1 | The following changes since commit b11365867568ba954de667a0bfe0945b8f78d6bd: | 1 | The following changes since commit f1d33f55c47dfdaf8daacd618588ad3ae4c452d1: |
---|---|---|---|
2 | 2 | ||
3 | Merge remote-tracking branch 'remotes/borntraeger/tags/s390x-20170706' into staging (2017-07-06 11:42:59 +0100) | 3 | Merge tag 'pull-testing-gdbstub-plugins-gitdm-061022-3' of https://github.com/stsquad/qemu into staging (2022-10-06 07:11:56 -0400) |
4 | 4 | ||
5 | are available in the git repository at: | 5 | are available in the Git repository at: |
6 | |||
7 | 6 | ||
8 | git://repo.or.cz/qemu/kevin.git tags/for-upstream | 7 | git://repo.or.cz/qemu/kevin.git tags/for-upstream |
9 | 8 | ||
10 | for you to fetch changes up to 7d982302db173616d011e07ee43be3b0aae872b1: | 9 | for you to fetch changes up to a7ca2eb488ff149c898f43abe103f8bd8e3ca3c4: |
11 | 10 | ||
12 | Merge remote-tracking branch 'mreitz/tags/pull-block-2017-07-07' into queue-block (2017-07-07 18:11:41 +0200) | 11 | file-posix: Remove unused s->discard_zeroes (2022-10-07 12:11:41 +0200) |
13 | 12 | ||
14 | ---------------------------------------------------------------- | 13 | ---------------------------------------------------------------- |
15 | |||
16 | Block layer patches | 14 | Block layer patches |
17 | 15 | ||
16 | - job: replace AioContext lock with job_mutex | ||
17 | - Fixes to make coroutine_fn annotations more accurate | ||
18 | - QAPI schema: Fix incorrect example | ||
19 | - Code cleanup | ||
20 | |||
18 | ---------------------------------------------------------------- | 21 | ---------------------------------------------------------------- |
19 | Daniel P. Berrange (26): | 22 | Alberto Faria (1): |
20 | qemu-img: drop -e and -6 options from the 'create' & 'convert' commands | 23 | coroutine: Drop coroutine_fn annotation from qemu_coroutine_self() |
21 | block: expose crypto option names / defs to other drivers | ||
22 | block: add ability to set a prefix for opt names | ||
23 | qcow: document another weakness of qcow AES encryption | ||
24 | qcow: require image size to be > 1 for new images | ||
25 | iotests: skip 042 with qcow which dosn't support zero sized images | ||
26 | iotests: skip 048 with qcow which doesn't support resize | ||
27 | block: deprecate "encryption=on" in favor of "encrypt.format=aes" | ||
28 | qcow: make encrypt_sectors encrypt in place | ||
29 | qcow: convert QCow to use QCryptoBlock for encryption | ||
30 | qcow2: make qcow2_encrypt_sectors encrypt in place | ||
31 | qcow2: convert QCow2 to use QCryptoBlock for encryption | ||
32 | qcow2: extend specification to cover LUKS encryption | ||
33 | qcow2: add support for LUKS encryption format | ||
34 | qcow2: add iotests to cover LUKS encryption support | ||
35 | iotests: enable tests 134 and 158 to work with qcow (v1) | ||
36 | block: rip out all traces of password prompting | ||
37 | block: remove all encryption handling APIs | ||
38 | block: pass option prefix down to crypto layer | ||
39 | qcow2: report encryption specific image information | ||
40 | docs: document encryption options for qcow, qcow2 and luks | ||
41 | iotests: skip 159 & 170 with luks format | ||
42 | iotests: fix remainining tests to work with LUKS | ||
43 | iotests: reduce PBKDF iterations when testing LUKS | ||
44 | iotests: add more LUKS hash combination tests | ||
45 | iotests: chown LUKS device before qemu-io launches | ||
46 | 24 | ||
47 | Eric Blake (26): | 25 | Emanuele Giuseppe Esposito (20): |
48 | qemu-io: Don't die on second open | 26 | job.c: make job_mutex and job_lock/unlock() public |
49 | block: Guarantee that *file is set on bdrv_get_block_status() | 27 | job.h: categorize fields in struct Job |
50 | block: Simplify use of BDRV_BLOCK_RAW | 28 | job.c: API functions not used outside should be static |
51 | blkdebug: Support .bdrv_co_get_block_status | 29 | aio-wait.h: introduce AIO_WAIT_WHILE_UNLOCKED |
52 | blockjob: Track job ratelimits via bytes, not sectors | 30 | job.c: add job_lock/unlock while keeping job.h intact |
53 | trace: Show blockjob actions via bytes, not sectors | 31 | job: move and update comments from blockjob.c |
54 | stream: Switch stream_populate() to byte-based | 32 | blockjob: introduce block_job _locked() APIs |
55 | stream: Drop reached_end for stream_complete() | 33 | jobs: add job lock in find_* functions |
56 | stream: Switch stream_run() to byte-based | 34 | jobs: use job locks also in the unit tests |
57 | commit: Switch commit_populate() to byte-based | 35 | block/mirror.c: use of job helpers in drivers |
58 | commit: Switch commit_run() to byte-based | 36 | jobs: group together API calls under the same job lock |
59 | mirror: Switch MirrorBlockJob to byte-based | 37 | jobs: protect job.aio_context with BQL and job_mutex |
60 | mirror: Switch mirror_do_zero_or_discard() to byte-based | 38 | blockjob.h: categorize fields in struct BlockJob |
61 | mirror: Update signature of mirror_clip_sectors() | 39 | blockjob: rename notifier callbacks as _locked |
62 | mirror: Switch mirror_cow_align() to byte-based | 40 | blockjob: protect iostatus field in BlockJob struct |
63 | mirror: Switch mirror_do_read() to byte-based | 41 | job.h: categorize JobDriver callbacks that need the AioContext lock |
64 | mirror: Switch mirror_iteration() to byte-based | 42 | job.c: enable job lock/unlock and remove Aiocontext locks |
65 | block: Drop unused bdrv_round_sectors_to_clusters() | 43 | block_job_query: remove atomic read |
66 | backup: Switch BackupBlockJob to byte-based | 44 | blockjob: remove unused functions |
67 | backup: Switch block_backup.h to byte-based | 45 | job: remove unused functions |
68 | backup: Switch backup_do_cow() to byte-based | ||
69 | backup: Switch backup_run() to byte-based | ||
70 | block: Make bdrv_is_allocated() byte-based | ||
71 | block: Minimize raw use of bds->total_sectors | ||
72 | block: Make bdrv_is_allocated_above() byte-based | ||
73 | tests: Avoid non-portable 'echo -ARG' | ||
74 | 46 | ||
75 | Hervé Poussineau (13): | 47 | Kevin Wolf (2): |
76 | vvfat: fix qemu-img map and qemu-img convert | 48 | quorum: Remove unnecessary forward declaration |
77 | vvfat: replace tabs by 8 spaces | 49 | file-posix: Remove unused s->discard_zeroes |
78 | vvfat: fix typos | ||
79 | vvfat: rename useless enumeration values | ||
80 | vvfat: introduce offset_to_bootsector, offset_to_fat and offset_to_root_dir | ||
81 | vvfat: fix field names in FAT12/FAT16 and FAT32 boot sectors | ||
82 | vvfat: always create . and .. entries at first and in that order | ||
83 | vvfat: correctly create long names for non-ASCII filenames | ||
84 | vvfat: correctly create base short names for non-ASCII filenames | ||
85 | vvfat: correctly generate numeric-tail of short file names | ||
86 | vvfat: limit number of entries in root directory in FAT12/FAT16 | ||
87 | vvfat: handle KANJI lead byte 0xe5 | ||
88 | vvfat: change OEM name to 'MSWIN4.1' | ||
89 | 50 | ||
90 | Kevin Wolf (1): | 51 | Marc-André Lureau (3): |
91 | Merge remote-tracking branch 'mreitz/tags/pull-block-2017-07-07' into queue-block | 52 | 9p: add missing coroutine_fn annotations |
53 | migration: add missing coroutine_fn annotations | ||
54 | test-coroutine: add missing coroutine_fn annotations | ||
92 | 55 | ||
93 | Max Reitz (3): | 56 | Markus Armbruster (1): |
94 | iotests: 181 does not work for all formats | 57 | Revert "qapi: fix examples of blockdev-add with qcow2" |
95 | iotests: Use absolute paths for executables | ||
96 | iotests: Add test for colon handling | ||
97 | 58 | ||
98 | Thomas Huth (1): | 59 | Paolo Bonzini (23): |
99 | blockdev: Print a warning for legacy drive options that belong to -device | 60 | block/nvme: separate nvme_get_free_req cases for coroutine/non-coroutine context |
61 | block: add missing coroutine_fn annotations | ||
62 | qcow2: remove incorrect coroutine_fn annotations | ||
63 | nbd: remove incorrect coroutine_fn annotations | ||
64 | coroutine: remove incorrect coroutine_fn annotations | ||
65 | blkverify: add missing coroutine_fn annotations | ||
66 | file-posix: add missing coroutine_fn annotations | ||
67 | iscsi: add missing coroutine_fn annotations | ||
68 | nbd: add missing coroutine_fn annotations | ||
69 | nfs: add missing coroutine_fn annotations | ||
70 | nvme: add missing coroutine_fn annotations | ||
71 | parallels: add missing coroutine_fn annotations | ||
72 | qcow2: add missing coroutine_fn annotations | ||
73 | copy-before-write: add missing coroutine_fn annotations | ||
74 | curl: add missing coroutine_fn annotations | ||
75 | qed: add missing coroutine_fn annotations | ||
76 | quorum: add missing coroutine_fn annotations | ||
77 | throttle: add missing coroutine_fn annotations | ||
78 | vmdk: add missing coroutine_fn annotations | ||
79 | job: add missing coroutine_fn annotations | ||
80 | coroutine-lock: add missing coroutine_fn annotations | ||
81 | raw-format: add missing coroutine_fn annotations | ||
82 | job: detect change of aiocontext within job coroutine | ||
100 | 83 | ||
101 | Vladimir Sementsov-Ogievskiy (30): | 84 | qapi/block-core.json | 10 +- |
102 | specs/qcow2: fix bitmap granularity qemu-specific note | 85 | block/qcow2.h | 19 +- |
103 | specs/qcow2: do not use wording 'bitmap header' | 86 | hw/9pfs/9p.h | 9 +- |
104 | hbitmap: improve dirty iter | 87 | include/block/aio-wait.h | 17 +- |
105 | tests: add hbitmap iter test | 88 | include/block/blockjob.h | 59 +++- |
106 | block: fix bdrv_dirty_bitmap_granularity signature | 89 | include/block/nbd.h | 2 +- |
107 | block/dirty-bitmap: add deserialize_ones func | 90 | include/qemu/coroutine.h | 4 +- |
108 | qcow2-refcount: rename inc_refcounts() and make it public | 91 | include/qemu/job.h | 306 +++++++++++++----- |
109 | qcow2: add bitmaps extension | 92 | block.c | 24 +- |
110 | block/dirty-bitmap: fix comment for BlockDirtyBitmap.disabled field | 93 | block/blkverify.c | 2 +- |
111 | block/dirty-bitmap: add readonly field to BdrvDirtyBitmap | 94 | block/block-backend.c | 10 +- |
112 | qcow2: autoloading dirty bitmaps | 95 | block/copy-before-write.c | 9 +- |
113 | block: refactor bdrv_reopen_commit | 96 | block/curl.c | 2 +- |
114 | block: new bdrv_reopen_bitmaps_rw interface | 97 | block/file-posix.c | 11 +- |
115 | qcow2: support .bdrv_reopen_bitmaps_rw | 98 | block/io.c | 22 +- |
116 | block/dirty-bitmap: add autoload field to BdrvDirtyBitmap | 99 | block/iscsi.c | 3 +- |
117 | block: bdrv_close: release bitmaps after drv->bdrv_close | 100 | block/mirror.c | 19 +- |
118 | block: introduce persistent dirty bitmaps | 101 | block/nbd.c | 11 +- |
119 | block/dirty-bitmap: add bdrv_dirty_bitmap_next() | 102 | block/nfs.c | 2 +- |
120 | qcow2: add persistent dirty bitmaps support | 103 | block/nvme.c | 54 ++-- |
121 | qcow2: store bitmaps on reopening image as read-only | 104 | block/parallels.c | 5 +- |
122 | block: add bdrv_can_store_new_dirty_bitmap | 105 | block/qcow2-cluster.c | 21 +- |
123 | qcow2: add .bdrv_can_store_new_dirty_bitmap | 106 | block/qcow2-refcount.c | 6 +- |
124 | qmp: add persistent flag to block-dirty-bitmap-add | 107 | block/qcow2.c | 5 +- |
125 | qmp: add autoload parameter to block-dirty-bitmap-add | 108 | block/qed.c | 4 +- |
126 | qmp: add x-debug-block-dirty-bitmap-sha256 | 109 | block/quorum.c | 38 +-- |
127 | iotests: test qcow2 persistent dirty bitmap | 110 | block/raw-format.c | 3 +- |
128 | block/dirty-bitmap: add bdrv_remove_persistent_dirty_bitmap | 111 | block/replication.c | 3 + |
129 | qcow2: add .bdrv_remove_persistent_dirty_bitmap | 112 | block/throttle.c | 2 +- |
130 | qmp: block-dirty-bitmap-remove: remove persistent | 113 | block/vmdk.c | 22 +- |
131 | block: release persistent bitmaps on inactivate | 114 | blockdev.c | 129 ++++---- |
115 | blockjob.c | 132 ++++---- | ||
116 | job-qmp.c | 92 +++--- | ||
117 | job.c | 674 +++++++++++++++++++++++++-------------- | ||
118 | migration/migration.c | 3 +- | ||
119 | monitor/qmp-cmds.c | 7 +- | ||
120 | qemu-img.c | 17 +- | ||
121 | tests/unit/test-bdrv-drain.c | 80 +++-- | ||
122 | tests/unit/test-block-iothread.c | 8 +- | ||
123 | tests/unit/test-blockjob-txn.c | 24 +- | ||
124 | tests/unit/test-blockjob.c | 136 ++++---- | ||
125 | tests/unit/test-coroutine.c | 2 +- | ||
126 | util/qemu-coroutine-lock.c | 14 +- | ||
127 | util/qemu-coroutine.c | 2 +- | ||
128 | 44 files changed, 1237 insertions(+), 787 deletions(-) | ||
132 | 129 | ||
133 | sochin.jiang (1): | ||
134 | mirror: Fix inconsistent backing AioContext for after mirroring | ||
135 | 130 | ||
136 | block.c | 143 +-- | ||
137 | block/Makefile.objs | 2 +- | ||
138 | block/backup.c | 128 +-- | ||
139 | block/blkdebug.c | 11 + | ||
140 | block/commit.c | 56 +- | ||
141 | block/crypto.c | 97 +- | ||
142 | block/crypto.h | 101 ++ | ||
143 | block/dirty-bitmap.c | 154 ++- | ||
144 | block/io.c | 110 +- | ||
145 | block/mirror.c | 310 ++--- | ||
146 | block/qapi.c | 2 +- | ||
147 | block/qcow.c | 269 ++--- | ||
148 | block/qcow2-bitmap.c | 1481 ++++++++++++++++++++++++ | ||
149 | block/qcow2-cluster.c | 66 +- | ||
150 | block/qcow2-refcount.c | 69 +- | ||
151 | block/qcow2.c | 653 +++++++++-- | ||
152 | block/qcow2.h | 60 +- | ||
153 | block/raw-format.c | 2 +- | ||
154 | block/replication.c | 29 +- | ||
155 | block/stream.c | 37 +- | ||
156 | block/trace-events | 14 +- | ||
157 | block/vpc.c | 2 +- | ||
158 | block/vvfat.c | 2336 ++++++++++++++++++++------------------ | ||
159 | blockdev.c | 124 +- | ||
160 | crypto/block-luks.c | 8 +- | ||
161 | crypto/block-qcow.c | 8 +- | ||
162 | crypto/block.c | 6 +- | ||
163 | crypto/blockpriv.h | 2 + | ||
164 | docs/interop/qcow2.txt | 111 +- | ||
165 | hmp-commands.hx | 2 + | ||
166 | hmp.c | 31 - | ||
167 | include/block/block.h | 22 +- | ||
168 | include/block/block_backup.h | 11 +- | ||
169 | include/block/block_int.h | 17 +- | ||
170 | include/block/dirty-bitmap.h | 22 +- | ||
171 | include/crypto/block.h | 6 +- | ||
172 | include/monitor/monitor.h | 7 - | ||
173 | include/qapi/error.h | 1 - | ||
174 | include/qemu/hbitmap.h | 49 +- | ||
175 | include/qemu/osdep.h | 2 - | ||
176 | include/qemu/ratelimit.h | 3 +- | ||
177 | migration/block.c | 16 +- | ||
178 | monitor.c | 68 -- | ||
179 | qapi-schema.json | 10 +- | ||
180 | qapi/block-core.json | 172 ++- | ||
181 | qapi/common.json | 5 +- | ||
182 | qemu-doc.texi | 123 +- | ||
183 | qemu-img.c | 76 +- | ||
184 | qemu-img.texi | 19 +- | ||
185 | qemu-io-cmds.c | 70 +- | ||
186 | qemu-io.c | 27 +- | ||
187 | qemu-options.hx | 13 +- | ||
188 | qmp.c | 12 +- | ||
189 | tests/Makefile.include | 2 +- | ||
190 | tests/multiboot/run_test.sh | 10 +- | ||
191 | tests/qemu-iotests/033 | 12 +- | ||
192 | tests/qemu-iotests/042 | 2 +- | ||
193 | tests/qemu-iotests/048 | 2 +- | ||
194 | tests/qemu-iotests/049 | 2 +- | ||
195 | tests/qemu-iotests/049.out | 102 +- | ||
196 | tests/qemu-iotests/051 | 7 +- | ||
197 | tests/qemu-iotests/060.out | 1 + | ||
198 | tests/qemu-iotests/068 | 2 +- | ||
199 | tests/qemu-iotests/082.out | 284 ++++- | ||
200 | tests/qemu-iotests/085.out | 38 +- | ||
201 | tests/qemu-iotests/087 | 39 +- | ||
202 | tests/qemu-iotests/087.out | 16 +- | ||
203 | tests/qemu-iotests/114.out | 5 +- | ||
204 | tests/qemu-iotests/120 | 1 + | ||
205 | tests/qemu-iotests/126 | 105 ++ | ||
206 | tests/qemu-iotests/126.out | 23 + | ||
207 | tests/qemu-iotests/134 | 20 +- | ||
208 | tests/qemu-iotests/134.out | 10 +- | ||
209 | tests/qemu-iotests/140 | 9 +- | ||
210 | tests/qemu-iotests/142 | 48 +- | ||
211 | tests/qemu-iotests/144.out | 4 +- | ||
212 | tests/qemu-iotests/145 | 19 +- | ||
213 | tests/qemu-iotests/149 | 25 +- | ||
214 | tests/qemu-iotests/149.out | 1002 +++++++++++----- | ||
215 | tests/qemu-iotests/153.out | 6 + | ||
216 | tests/qemu-iotests/157 | 17 +- | ||
217 | tests/qemu-iotests/157.out | 16 +- | ||
218 | tests/qemu-iotests/158 | 21 +- | ||
219 | tests/qemu-iotests/158.out | 14 +- | ||
220 | tests/qemu-iotests/159 | 1 + | ||
221 | tests/qemu-iotests/165 | 105 ++ | ||
222 | tests/qemu-iotests/165.out | 5 + | ||
223 | tests/qemu-iotests/170 | 1 + | ||
224 | tests/qemu-iotests/171 | 14 +- | ||
225 | tests/qemu-iotests/174 | 2 +- | ||
226 | tests/qemu-iotests/177 | 3 + | ||
227 | tests/qemu-iotests/177.out | 5 + | ||
228 | tests/qemu-iotests/181 | 23 +- | ||
229 | tests/qemu-iotests/185.out | 8 +- | ||
230 | tests/qemu-iotests/188 | 76 ++ | ||
231 | tests/qemu-iotests/188.out | 18 + | ||
232 | tests/qemu-iotests/189 | 86 ++ | ||
233 | tests/qemu-iotests/189.out | 26 + | ||
234 | tests/qemu-iotests/check | 18 +- | ||
235 | tests/qemu-iotests/common | 10 +- | ||
236 | tests/qemu-iotests/common.config | 11 + | ||
237 | tests/qemu-iotests/common.filter | 3 +- | ||
238 | tests/qemu-iotests/common.qemu | 9 +- | ||
239 | tests/qemu-iotests/common.rc | 3 + | ||
240 | tests/qemu-iotests/group | 4 + | ||
241 | tests/rocker/all | 10 +- | ||
242 | tests/tcg/cris/Makefile | 8 +- | ||
243 | tests/test-crypto-block.c | 8 +- | ||
244 | tests/test-hbitmap.c | 19 + | ||
245 | util/hbitmap.c | 51 +- | ||
246 | util/oslib-posix.c | 66 -- | ||
247 | util/oslib-win32.c | 24 - | ||
248 | 112 files changed, 6714 insertions(+), 2942 deletions(-) | ||
249 | create mode 100644 block/crypto.h | ||
250 | create mode 100644 block/qcow2-bitmap.c | ||
251 | create mode 100755 tests/qemu-iotests/126 | ||
252 | create mode 100644 tests/qemu-iotests/126.out | ||
253 | create mode 100755 tests/qemu-iotests/165 | ||
254 | create mode 100644 tests/qemu-iotests/165.out | ||
255 | create mode 100755 tests/qemu-iotests/188 | ||
256 | create mode 100644 tests/qemu-iotests/188.out | ||
257 | create mode 100755 tests/qemu-iotests/189 | ||
258 | create mode 100644 tests/qemu-iotests/189.out | ||
259 | diff view generated by jsdifflib |
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 1 | From: Markus Armbruster <armbru@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Remove persistent bitmap from the storage on block-dirty-bitmap-remove. | 3 | This reverts commit b6522938327141235b97ab38e40c6c4512587373. |
4 | 4 | ||
5 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 5 | Kevin Wolf NAKed this patch, because: |
6 | Reviewed-by: Max Reitz <mreitz@redhat.com> | 6 | |
7 | Reviewed-by: John Snow <jsnow@redhat.com> | 7 | 'file' is a required member (defined in BlockdevOptionsGenericFormat), |
8 | Message-id: 20170628120530.31251-30-vsementsov@virtuozzo.com | 8 | removing it makes the example invalid. 'data-file' is only an additional |
9 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 9 | optional member to be used for external data files (i.e. when the guest |
10 | data is kept separate from the metadata in the .qcow2 file). | ||
11 | |||
12 | However, it had already been merged then. Revert. | ||
13 | |||
14 | Signed-off-by: Markus Armbruster <armbru@redhat.com> | ||
15 | Message-Id: <20220930171908.846769-1-armbru@redhat.com> | ||
16 | Reviewed-by: Victor Toso <victortoso@redhat.com> | ||
17 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
18 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
10 | --- | 19 | --- |
11 | blockdev.c | 10 ++++++++++ | 20 | qapi/block-core.json | 10 +++++----- |
12 | qapi/block-core.json | 3 ++- | 21 | 1 file changed, 5 insertions(+), 5 deletions(-) |
13 | 2 files changed, 12 insertions(+), 1 deletion(-) | ||
14 | 22 | ||
15 | diff --git a/blockdev.c b/blockdev.c | ||
16 | index XXXXXXX..XXXXXXX 100644 | ||
17 | --- a/blockdev.c | ||
18 | +++ b/blockdev.c | ||
19 | @@ -XXX,XX +XXX,XX @@ void qmp_block_dirty_bitmap_remove(const char *node, const char *name, | ||
20 | { | ||
21 | BlockDriverState *bs; | ||
22 | BdrvDirtyBitmap *bitmap; | ||
23 | + Error *local_err = NULL; | ||
24 | |||
25 | bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp); | ||
26 | if (!bitmap || !bs) { | ||
27 | @@ -XXX,XX +XXX,XX @@ void qmp_block_dirty_bitmap_remove(const char *node, const char *name, | ||
28 | name); | ||
29 | return; | ||
30 | } | ||
31 | + | ||
32 | + if (bdrv_dirty_bitmap_get_persistance(bitmap)) { | ||
33 | + bdrv_remove_persistent_dirty_bitmap(bs, name, &local_err); | ||
34 | + if (local_err != NULL) { | ||
35 | + error_propagate(errp, local_err); | ||
36 | + return; | ||
37 | + } | ||
38 | + } | ||
39 | + | ||
40 | bdrv_dirty_bitmap_make_anon(bitmap); | ||
41 | bdrv_release_dirty_bitmap(bs, bitmap); | ||
42 | } | ||
43 | diff --git a/qapi/block-core.json b/qapi/block-core.json | 23 | diff --git a/qapi/block-core.json b/qapi/block-core.json |
44 | index XXXXXXX..XXXXXXX 100644 | 24 | index XXXXXXX..XXXXXXX 100644 |
45 | --- a/qapi/block-core.json | 25 | --- a/qapi/block-core.json |
46 | +++ b/qapi/block-core.json | 26 | +++ b/qapi/block-core.json |
47 | @@ -XXX,XX +XXX,XX @@ | 27 | @@ -XXX,XX +XXX,XX @@ |
48 | # @block-dirty-bitmap-remove: | 28 | # -> { "execute": "blockdev-add", |
29 | # "arguments": { "driver": "qcow2", | ||
30 | # "node-name": "node1534", | ||
31 | -# "data-file": { "driver": "file", | ||
32 | -# "filename": "hd1.qcow2" }, | ||
33 | +# "file": { "driver": "file", | ||
34 | +# "filename": "hd1.qcow2" }, | ||
35 | # "backing": null } } | ||
49 | # | 36 | # |
50 | # Stop write tracking and remove the dirty bitmap that was created | 37 | # <- { "return": {} } |
51 | -# with block-dirty-bitmap-add. | 38 | @@ -XXX,XX +XXX,XX @@ |
52 | +# with block-dirty-bitmap-add. If the bitmap is persistent, remove it from its | 39 | # "arguments": { |
53 | +# storage too. | 40 | # "driver": "qcow2", |
54 | # | 41 | # "node-name": "test1", |
55 | # Returns: nothing on success | 42 | -# "data-file": { |
56 | # If @node is not a valid block device or node, DeviceNotFound | 43 | +# "file": { |
44 | # "driver": "file", | ||
45 | # "filename": "test.qcow2" | ||
46 | # } | ||
47 | @@ -XXX,XX +XXX,XX @@ | ||
48 | # "cache": { | ||
49 | # "direct": true | ||
50 | # }, | ||
51 | -# "data-file": { | ||
52 | +# "file": { | ||
53 | # "driver": "file", | ||
54 | # "filename": "/tmp/test.qcow2" | ||
55 | # }, | ||
56 | @@ -XXX,XX +XXX,XX @@ | ||
57 | # "arguments": { | ||
58 | # "driver": "qcow2", | ||
59 | # "node-name": "node0", | ||
60 | -# "data-file": { | ||
61 | +# "file": { | ||
62 | # "driver": "file", | ||
63 | # "filename": "test.qcow2" | ||
64 | # } | ||
57 | -- | 65 | -- |
58 | 1.8.3.1 | 66 | 2.37.3 |
59 | |||
60 | diff view generated by jsdifflib |
1 | From: Hervé Poussineau <hpoussin@reactos.org> | 1 | From: Alberto Faria <afaria@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | MODE_FAKED and MODE_RENAMED are not and were never used. | 3 | qemu_coroutine_self() can be called from outside coroutine context, |
4 | returning the leader coroutine, and several such invocations currently | ||
5 | exist (mostly in qcow2 tracing calls). | ||
4 | 6 | ||
5 | Signed-off-by: Hervé Poussineau <hpoussin@reactos.org> | 7 | Signed-off-by: Alberto Faria <afaria@redhat.com> |
8 | Message-Id: <20221005175209.975797-1-afaria@redhat.com> | ||
9 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
10 | Reviewed-by: Paolo Bonzini <pbonzini@redhat.com> | ||
6 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
7 | --- | 12 | --- |
8 | block/vvfat.c | 13 ++++++++----- | 13 | include/qemu/coroutine.h | 2 +- |
9 | 1 file changed, 8 insertions(+), 5 deletions(-) | 14 | 1 file changed, 1 insertion(+), 1 deletion(-) |
10 | 15 | ||
11 | diff --git a/block/vvfat.c b/block/vvfat.c | 16 | diff --git a/include/qemu/coroutine.h b/include/qemu/coroutine.h |
12 | index XXXXXXX..XXXXXXX 100644 | 17 | index XXXXXXX..XXXXXXX 100644 |
13 | --- a/block/vvfat.c | 18 | --- a/include/qemu/coroutine.h |
14 | +++ b/block/vvfat.c | 19 | +++ b/include/qemu/coroutine.h |
15 | @@ -XXX,XX +XXX,XX @@ typedef struct mapping_t { | 20 | @@ -XXX,XX +XXX,XX @@ AioContext *coroutine_fn qemu_coroutine_get_aio_context(Coroutine *co); |
16 | union { | 21 | /** |
17 | /* offset is | 22 | * Get the currently executing coroutine |
18 | * - the offset in the file (in clusters) for a file, or | 23 | */ |
19 | - * - the next cluster of the directory for a directory, and | 24 | -Coroutine *coroutine_fn qemu_coroutine_self(void); |
20 | - * - the address of the buffer for a faked entry | 25 | +Coroutine *qemu_coroutine_self(void); |
21 | + * - the next cluster of the directory for a directory | 26 | |
22 | */ | 27 | /** |
23 | struct { | 28 | * Return whether or not currently inside a coroutine |
24 | uint32_t offset; | ||
25 | @@ -XXX,XX +XXX,XX @@ typedef struct mapping_t { | ||
26 | /* path contains the full path, i.e. it always starts with s->path */ | ||
27 | char* path; | ||
28 | |||
29 | - enum { MODE_UNDEFINED = 0, MODE_NORMAL = 1, MODE_MODIFIED = 2, | ||
30 | - MODE_DIRECTORY = 4, MODE_FAKED = 8, | ||
31 | - MODE_DELETED = 16, MODE_RENAMED = 32 } mode; | ||
32 | + enum { | ||
33 | + MODE_UNDEFINED = 0, | ||
34 | + MODE_NORMAL = 1, | ||
35 | + MODE_MODIFIED = 2, | ||
36 | + MODE_DIRECTORY = 4, | ||
37 | + MODE_DELETED = 8, | ||
38 | + } mode; | ||
39 | int read_only; | ||
40 | } mapping_t; | ||
41 | |||
42 | -- | 29 | -- |
43 | 1.8.3.1 | 30 | 2.37.3 |
44 | |||
45 | diff view generated by jsdifflib |
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 1 | From: Paolo Bonzini <pbonzini@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Make dirty iter resistant to resetting bits in corresponding HBitmap. | 3 | nvme_get_free_req has very difference semantics when called in |
4 | coroutine context (where it waits) and in non-coroutine context | ||
5 | (where it doesn't). Split the two cases to make it clear what | ||
6 | is being requested. | ||
4 | 7 | ||
5 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 8 | Cc: qemu-block@nongnu.org |
6 | Reviewed-by: Max Reitz <mreitz@redhat.com> | 9 | Reviewed-by: Alberto Faria <afaria@redhat.com> |
7 | Reviewed-by: John Snow <jsnow@redhat.com> | 10 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
8 | Message-id: 20170628120530.31251-4-vsementsov@virtuozzo.com | 11 | Message-Id: <20220922084924.201610-2-pbonzini@redhat.com> |
9 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 12 | [kwolf: Fixed up coding style] |
13 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
14 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
10 | --- | 15 | --- |
11 | include/qemu/hbitmap.h | 26 ++++---------------------- | 16 | block/nvme.c | 48 ++++++++++++++++++++++++++++-------------------- |
12 | util/hbitmap.c | 23 ++++++++++++++++++++++- | 17 | 1 file changed, 28 insertions(+), 20 deletions(-) |
13 | 2 files changed, 26 insertions(+), 23 deletions(-) | ||
14 | 18 | ||
15 | diff --git a/include/qemu/hbitmap.h b/include/qemu/hbitmap.h | 19 | diff --git a/block/nvme.c b/block/nvme.c |
16 | index XXXXXXX..XXXXXXX 100644 | 20 | index XXXXXXX..XXXXXXX 100644 |
17 | --- a/include/qemu/hbitmap.h | 21 | --- a/block/nvme.c |
18 | +++ b/include/qemu/hbitmap.h | 22 | +++ b/block/nvme.c |
19 | @@ -XXX,XX +XXX,XX @@ void hbitmap_free(HBitmap *hb); | 23 | @@ -XXX,XX +XXX,XX @@ static void nvme_kick(NVMeQueuePair *q) |
20 | * the lowest-numbered bit that is set in @hb, starting at @first. | 24 | q->need_kick = 0; |
21 | * | 25 | } |
22 | * Concurrent setting of bits is acceptable, and will at worst cause the | 26 | |
23 | - * iteration to miss some of those bits. Resetting bits before the current | 27 | -/* Find a free request element if any, otherwise: |
24 | - * position of the iterator is also okay. However, concurrent resetting of | 28 | - * a) if in coroutine context, try to wait for one to become available; |
25 | - * bits can lead to unexpected behavior if the iterator has not yet reached | 29 | - * b) if not in coroutine, return NULL; |
26 | - * those bits. | 30 | - */ |
27 | + * iteration to miss some of those bits. | 31 | -static NVMeRequest *nvme_get_free_req(NVMeQueuePair *q) |
28 | + * | 32 | +static NVMeRequest *nvme_get_free_req_nofail_locked(NVMeQueuePair *q) |
29 | + * The concurrent resetting of bits is OK. | 33 | { |
30 | */ | 34 | NVMeRequest *req; |
31 | void hbitmap_iter_init(HBitmapIter *hbi, const HBitmap *hb, uint64_t first); | 35 | |
32 | 36 | - qemu_mutex_lock(&q->lock); | |
33 | @@ -XXX,XX +XXX,XX @@ void hbitmap_free_meta(HBitmap *hb); | ||
34 | * Return the next bit that is set in @hbi's associated HBitmap, | ||
35 | * or -1 if all remaining bits are zero. | ||
36 | */ | ||
37 | -static inline int64_t hbitmap_iter_next(HBitmapIter *hbi) | ||
38 | -{ | ||
39 | - unsigned long cur = hbi->cur[HBITMAP_LEVELS - 1]; | ||
40 | - int64_t item; | ||
41 | - | 37 | - |
42 | - if (cur == 0) { | 38 | - while (q->free_req_head == -1) { |
43 | - cur = hbitmap_iter_skip_words(hbi); | 39 | - if (qemu_in_coroutine()) { |
44 | - if (cur == 0) { | 40 | - trace_nvme_free_req_queue_wait(q->s, q->index); |
45 | - return -1; | 41 | - qemu_co_queue_wait(&q->free_req_queue, &q->lock); |
42 | - } else { | ||
43 | - qemu_mutex_unlock(&q->lock); | ||
44 | - return NULL; | ||
46 | - } | 45 | - } |
47 | - } | 46 | - } |
48 | - | 47 | - |
49 | - /* The next call will resume work from the next bit. */ | 48 | req = &q->reqs[q->free_req_head]; |
50 | - hbi->cur[HBITMAP_LEVELS - 1] = cur & (cur - 1); | 49 | q->free_req_head = req->free_req_next; |
51 | - item = ((uint64_t)hbi->pos << BITS_PER_LEVEL) + ctzl(cur); | 50 | req->free_req_next = -1; |
52 | - | 51 | - |
53 | - return item << hbi->granularity; | 52 | - qemu_mutex_unlock(&q->lock); |
54 | -} | 53 | return req; |
55 | +int64_t hbitmap_iter_next(HBitmapIter *hbi); | ||
56 | |||
57 | /** | ||
58 | * hbitmap_iter_next_word: | ||
59 | diff --git a/util/hbitmap.c b/util/hbitmap.c | ||
60 | index XXXXXXX..XXXXXXX 100644 | ||
61 | --- a/util/hbitmap.c | ||
62 | +++ b/util/hbitmap.c | ||
63 | @@ -XXX,XX +XXX,XX @@ unsigned long hbitmap_iter_skip_words(HBitmapIter *hbi) | ||
64 | |||
65 | unsigned long cur; | ||
66 | do { | ||
67 | - cur = hbi->cur[--i]; | ||
68 | + i--; | ||
69 | pos >>= BITS_PER_LEVEL; | ||
70 | + cur = hbi->cur[i] & hb->levels[i][pos]; | ||
71 | } while (cur == 0); | ||
72 | |||
73 | /* Check for end of iteration. We always use fewer than BITS_PER_LONG | ||
74 | @@ -XXX,XX +XXX,XX @@ unsigned long hbitmap_iter_skip_words(HBitmapIter *hbi) | ||
75 | return cur; | ||
76 | } | 54 | } |
77 | 55 | ||
78 | +int64_t hbitmap_iter_next(HBitmapIter *hbi) | 56 | +/* Return a free request element if any, otherwise return NULL. */ |
57 | +static NVMeRequest *nvme_get_free_req_nowait(NVMeQueuePair *q) | ||
79 | +{ | 58 | +{ |
80 | + unsigned long cur = hbi->cur[HBITMAP_LEVELS - 1] & | 59 | + QEMU_LOCK_GUARD(&q->lock); |
81 | + hbi->hb->levels[HBITMAP_LEVELS - 1][hbi->pos]; | 60 | + if (q->free_req_head == -1) { |
82 | + int64_t item; | 61 | + return NULL; |
62 | + } | ||
63 | + return nvme_get_free_req_nofail_locked(q); | ||
64 | +} | ||
83 | + | 65 | + |
84 | + if (cur == 0) { | 66 | +/* |
85 | + cur = hbitmap_iter_skip_words(hbi); | 67 | + * Wait for a free request to become available if necessary, then |
86 | + if (cur == 0) { | 68 | + * return it. |
87 | + return -1; | 69 | + */ |
88 | + } | 70 | +static coroutine_fn NVMeRequest *nvme_get_free_req(NVMeQueuePair *q) |
71 | +{ | ||
72 | + QEMU_LOCK_GUARD(&q->lock); | ||
73 | + | ||
74 | + while (q->free_req_head == -1) { | ||
75 | + trace_nvme_free_req_queue_wait(q->s, q->index); | ||
76 | + qemu_co_queue_wait(&q->free_req_queue, &q->lock); | ||
89 | + } | 77 | + } |
90 | + | 78 | + |
91 | + /* The next call will resume work from the next bit. */ | 79 | + return nvme_get_free_req_nofail_locked(q); |
92 | + hbi->cur[HBITMAP_LEVELS - 1] = cur & (cur - 1); | ||
93 | + item = ((uint64_t)hbi->pos << BITS_PER_LEVEL) + ctzl(cur); | ||
94 | + | ||
95 | + return item << hbi->granularity; | ||
96 | +} | 80 | +} |
97 | + | 81 | + |
98 | void hbitmap_iter_init(HBitmapIter *hbi, const HBitmap *hb, uint64_t first) | 82 | /* With q->lock */ |
83 | static void nvme_put_free_req_locked(NVMeQueuePair *q, NVMeRequest *req) | ||
99 | { | 84 | { |
100 | unsigned i, bit; | 85 | @@ -XXX,XX +XXX,XX @@ static int nvme_admin_cmd_sync(BlockDriverState *bs, NvmeCmd *cmd) |
86 | AioContext *aio_context = bdrv_get_aio_context(bs); | ||
87 | NVMeRequest *req; | ||
88 | int ret = -EINPROGRESS; | ||
89 | - req = nvme_get_free_req(q); | ||
90 | + req = nvme_get_free_req_nowait(q); | ||
91 | if (!req) { | ||
92 | return -EBUSY; | ||
93 | } | ||
101 | -- | 94 | -- |
102 | 1.8.3.1 | 95 | 2.37.3 |
103 | |||
104 | diff view generated by jsdifflib |
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 1 | From: Paolo Bonzini <pbonzini@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | We should release them here to reload on invalidate cache. | 3 | Callers of coroutine_fn must be coroutine_fn themselves, or the call |
4 | must be within "if (qemu_in_coroutine())". Apply coroutine_fn to | ||
5 | functions where this holds. | ||
4 | 6 | ||
5 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 7 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
6 | Reviewed-by: Max Reitz <mreitz@redhat.com> | 8 | Message-Id: <20220922084924.201610-3-pbonzini@redhat.com> |
7 | Message-id: 20170628120530.31251-31-vsementsov@virtuozzo.com | 9 | [kwolf: Fixed up coding style] |
8 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 10 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> |
11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
9 | --- | 12 | --- |
10 | block.c | 4 ++++ | 13 | block.c | 7 ++++--- |
11 | block/dirty-bitmap.c | 29 +++++++++++++++++++++++------ | 14 | block/block-backend.c | 10 +++++----- |
12 | include/block/dirty-bitmap.h | 1 + | 15 | block/io.c | 22 +++++++++++----------- |
13 | 3 files changed, 28 insertions(+), 6 deletions(-) | 16 | 3 files changed, 20 insertions(+), 19 deletions(-) |
14 | 17 | ||
15 | diff --git a/block.c b/block.c | 18 | diff --git a/block.c b/block.c |
16 | index XXXXXXX..XXXXXXX 100644 | 19 | index XXXXXXX..XXXXXXX 100644 |
17 | --- a/block.c | 20 | --- a/block.c |
18 | +++ b/block.c | 21 | +++ b/block.c |
19 | @@ -XXX,XX +XXX,XX @@ static int bdrv_inactivate_recurse(BlockDriverState *bs, | 22 | @@ -XXX,XX +XXX,XX @@ static int64_t create_file_fallback_truncate(BlockBackend *blk, |
20 | } | 23 | * Helper function for bdrv_create_file_fallback(): Zero the first |
21 | } | 24 | * sector to remove any potentially pre-existing image header. |
22 | 25 | */ | |
23 | + /* At this point persistent bitmaps should be already stored by the format | 26 | -static int create_file_fallback_zero_first_sector(BlockBackend *blk, |
24 | + * driver */ | 27 | - int64_t current_size, |
25 | + bdrv_release_persistent_dirty_bitmaps(bs); | 28 | - Error **errp) |
26 | + | 29 | +static int coroutine_fn |
27 | return 0; | 30 | +create_file_fallback_zero_first_sector(BlockBackend *blk, |
31 | + int64_t current_size, | ||
32 | + Error **errp) | ||
33 | { | ||
34 | int64_t bytes_to_clear; | ||
35 | int ret; | ||
36 | diff --git a/block/block-backend.c b/block/block-backend.c | ||
37 | index XXXXXXX..XXXXXXX 100644 | ||
38 | --- a/block/block-backend.c | ||
39 | +++ b/block/block-backend.c | ||
40 | @@ -XXX,XX +XXX,XX @@ static BlockAIOCB *blk_aio_prwv(BlockBackend *blk, int64_t offset, | ||
41 | return &acb->common; | ||
28 | } | 42 | } |
29 | 43 | ||
30 | diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c | 44 | -static void blk_aio_read_entry(void *opaque) |
45 | +static void coroutine_fn blk_aio_read_entry(void *opaque) | ||
46 | { | ||
47 | BlkAioEmAIOCB *acb = opaque; | ||
48 | BlkRwCo *rwco = &acb->rwco; | ||
49 | @@ -XXX,XX +XXX,XX @@ static void blk_aio_read_entry(void *opaque) | ||
50 | blk_aio_complete(acb); | ||
51 | } | ||
52 | |||
53 | -static void blk_aio_write_entry(void *opaque) | ||
54 | +static void coroutine_fn blk_aio_write_entry(void *opaque) | ||
55 | { | ||
56 | BlkAioEmAIOCB *acb = opaque; | ||
57 | BlkRwCo *rwco = &acb->rwco; | ||
58 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn blk_co_ioctl(BlockBackend *blk, unsigned long int req, | ||
59 | return ret; | ||
60 | } | ||
61 | |||
62 | -static void blk_aio_ioctl_entry(void *opaque) | ||
63 | +static void coroutine_fn blk_aio_ioctl_entry(void *opaque) | ||
64 | { | ||
65 | BlkAioEmAIOCB *acb = opaque; | ||
66 | BlkRwCo *rwco = &acb->rwco; | ||
67 | @@ -XXX,XX +XXX,XX @@ blk_co_do_pdiscard(BlockBackend *blk, int64_t offset, int64_t bytes) | ||
68 | return bdrv_co_pdiscard(blk->root, offset, bytes); | ||
69 | } | ||
70 | |||
71 | -static void blk_aio_pdiscard_entry(void *opaque) | ||
72 | +static void coroutine_fn blk_aio_pdiscard_entry(void *opaque) | ||
73 | { | ||
74 | BlkAioEmAIOCB *acb = opaque; | ||
75 | BlkRwCo *rwco = &acb->rwco; | ||
76 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn blk_co_do_flush(BlockBackend *blk) | ||
77 | return bdrv_co_flush(blk_bs(blk)); | ||
78 | } | ||
79 | |||
80 | -static void blk_aio_flush_entry(void *opaque) | ||
81 | +static void coroutine_fn blk_aio_flush_entry(void *opaque) | ||
82 | { | ||
83 | BlkAioEmAIOCB *acb = opaque; | ||
84 | BlkRwCo *rwco = &acb->rwco; | ||
85 | diff --git a/block/io.c b/block/io.c | ||
31 | index XXXXXXX..XXXXXXX 100644 | 86 | index XXXXXXX..XXXXXXX 100644 |
32 | --- a/block/dirty-bitmap.c | 87 | --- a/block/io.c |
33 | +++ b/block/dirty-bitmap.c | 88 | +++ b/block/io.c |
34 | @@ -XXX,XX +XXX,XX @@ void bdrv_dirty_bitmap_truncate(BlockDriverState *bs) | 89 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn tracked_request_end(BdrvTrackedRequest *req) |
35 | bdrv_dirty_bitmaps_unlock(bs); | 90 | /** |
91 | * Add an active request to the tracked requests list | ||
92 | */ | ||
93 | -static void tracked_request_begin(BdrvTrackedRequest *req, | ||
94 | - BlockDriverState *bs, | ||
95 | - int64_t offset, | ||
96 | - int64_t bytes, | ||
97 | - enum BdrvTrackedRequestType type) | ||
98 | +static void coroutine_fn tracked_request_begin(BdrvTrackedRequest *req, | ||
99 | + BlockDriverState *bs, | ||
100 | + int64_t offset, | ||
101 | + int64_t bytes, | ||
102 | + enum BdrvTrackedRequestType type) | ||
103 | { | ||
104 | bdrv_check_request(offset, bytes, &error_abort); | ||
105 | |||
106 | @@ -XXX,XX +XXX,XX @@ static bool tracked_request_overlaps(BdrvTrackedRequest *req, | ||
36 | } | 107 | } |
37 | 108 | ||
38 | +static bool bdrv_dirty_bitmap_has_name(BdrvDirtyBitmap *bitmap) | 109 | /* Called with self->bs->reqs_lock held */ |
39 | +{ | 110 | -static BdrvTrackedRequest * |
40 | + return !!bdrv_dirty_bitmap_name(bitmap); | 111 | +static coroutine_fn BdrvTrackedRequest * |
41 | +} | 112 | bdrv_find_conflicting_request(BdrvTrackedRequest *self) |
42 | + | ||
43 | /* Called with BQL taken. */ | ||
44 | -static void bdrv_do_release_matching_dirty_bitmap(BlockDriverState *bs, | ||
45 | - BdrvDirtyBitmap *bitmap, | ||
46 | - bool only_named) | ||
47 | +static void bdrv_do_release_matching_dirty_bitmap( | ||
48 | + BlockDriverState *bs, BdrvDirtyBitmap *bitmap, | ||
49 | + bool (*cond)(BdrvDirtyBitmap *bitmap)) | ||
50 | { | 113 | { |
51 | BdrvDirtyBitmap *bm, *next; | 114 | BdrvTrackedRequest *req; |
52 | bdrv_dirty_bitmaps_lock(bs); | 115 | @@ -XXX,XX +XXX,XX @@ static bool bdrv_init_padding(BlockDriverState *bs, |
53 | QLIST_FOREACH_SAFE(bm, &bs->dirty_bitmaps, list, next) { | 116 | return true; |
54 | - if ((!bitmap || bm == bitmap) && (!only_named || bm->name)) { | 117 | } |
55 | + if ((!bitmap || bm == bitmap) && (!cond || cond(bm))) { | 118 | |
56 | assert(!bm->active_iterators); | 119 | -static int bdrv_padding_rmw_read(BdrvChild *child, |
57 | assert(!bdrv_dirty_bitmap_frozen(bm)); | 120 | - BdrvTrackedRequest *req, |
58 | assert(!bm->meta); | 121 | - BdrvRequestPadding *pad, |
122 | - bool zero_middle) | ||
123 | +static coroutine_fn int bdrv_padding_rmw_read(BdrvChild *child, | ||
124 | + BdrvTrackedRequest *req, | ||
125 | + BdrvRequestPadding *pad, | ||
126 | + bool zero_middle) | ||
127 | { | ||
128 | QEMUIOVector local_qiov; | ||
129 | BlockDriverState *bs = child->bs; | ||
59 | @@ -XXX,XX +XXX,XX @@ out: | 130 | @@ -XXX,XX +XXX,XX @@ out: |
60 | /* Called with BQL taken. */ | 131 | return ret; |
61 | void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap) | 132 | } |
133 | |||
134 | -int bdrv_co_ioctl(BlockDriverState *bs, int req, void *buf) | ||
135 | +int coroutine_fn bdrv_co_ioctl(BlockDriverState *bs, int req, void *buf) | ||
62 | { | 136 | { |
63 | - bdrv_do_release_matching_dirty_bitmap(bs, bitmap, false); | 137 | BlockDriver *drv = bs->drv; |
64 | + bdrv_do_release_matching_dirty_bitmap(bs, bitmap, NULL); | 138 | CoroutineIOCompletion co = { |
65 | } | ||
66 | |||
67 | /** | ||
68 | @@ -XXX,XX +XXX,XX @@ void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap) | ||
69 | */ | ||
70 | void bdrv_release_named_dirty_bitmaps(BlockDriverState *bs) | ||
71 | { | ||
72 | - bdrv_do_release_matching_dirty_bitmap(bs, NULL, true); | ||
73 | + bdrv_do_release_matching_dirty_bitmap(bs, NULL, bdrv_dirty_bitmap_has_name); | ||
74 | +} | ||
75 | + | ||
76 | +/** | ||
77 | + * Release all persistent dirty bitmaps attached to a BDS (for use in | ||
78 | + * bdrv_inactivate_recurse()). | ||
79 | + * There must not be any frozen bitmaps attached. | ||
80 | + * This function does not remove persistent bitmaps from the storage. | ||
81 | + */ | ||
82 | +void bdrv_release_persistent_dirty_bitmaps(BlockDriverState *bs) | ||
83 | +{ | ||
84 | + bdrv_do_release_matching_dirty_bitmap(bs, NULL, | ||
85 | + bdrv_dirty_bitmap_get_persistance); | ||
86 | } | ||
87 | |||
88 | /** | ||
89 | diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h | ||
90 | index XXXXXXX..XXXXXXX 100644 | ||
91 | --- a/include/block/dirty-bitmap.h | ||
92 | +++ b/include/block/dirty-bitmap.h | ||
93 | @@ -XXX,XX +XXX,XX @@ BdrvDirtyBitmap *bdrv_find_dirty_bitmap(BlockDriverState *bs, | ||
94 | void bdrv_dirty_bitmap_make_anon(BdrvDirtyBitmap *bitmap); | ||
95 | void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap); | ||
96 | void bdrv_release_named_dirty_bitmaps(BlockDriverState *bs); | ||
97 | +void bdrv_release_persistent_dirty_bitmaps(BlockDriverState *bs); | ||
98 | void bdrv_remove_persistent_dirty_bitmap(BlockDriverState *bs, | ||
99 | const char *name, | ||
100 | Error **errp); | ||
101 | -- | 139 | -- |
102 | 1.8.3.1 | 140 | 2.37.3 |
103 | |||
104 | diff view generated by jsdifflib |
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 1 | From: Paolo Bonzini <pbonzini@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Add bitmap extension as specified in docs/specs/qcow2.txt. | 3 | This is incorrect because qcow2_mark_clean() calls qcow2_flush_caches(). |
4 | For now, just mirror extension header into Qcow2 state and check | 4 | qcow2_mark_clean() is called from non-coroutine context in |
5 | constraints. Also, calculate refcounts for qcow2 bitmaps, to not break | 5 | qcow2_inactivate() and qcow2_amend_options(). |
6 | qemu-img check. | ||
7 | 6 | ||
8 | For now, disable image resize if it has bitmaps. It will be fixed later. | 7 | Reviewed-by: Alberto Faria <afaria@redhat.com> |
8 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
9 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> | ||
10 | Message-Id: <20220922084924.201610-4-pbonzini@redhat.com> | ||
11 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
13 | --- | ||
14 | block/qcow2.h | 4 ++-- | ||
15 | block/qcow2-refcount.c | 4 ++-- | ||
16 | 2 files changed, 4 insertions(+), 4 deletions(-) | ||
9 | 17 | ||
10 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 18 | diff --git a/block/qcow2.h b/block/qcow2.h |
11 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
12 | Reviewed-by: John Snow <jsnow@redhat.com> | ||
13 | Message-id: 20170628120530.31251-9-vsementsov@virtuozzo.com | ||
14 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
15 | --- | ||
16 | block/Makefile.objs | 2 +- | ||
17 | block/qcow2-bitmap.c | 439 +++++++++++++++++++++++++++++++++++++++++++++++++ | ||
18 | block/qcow2-refcount.c | 6 + | ||
19 | block/qcow2.c | 125 +++++++++++++- | ||
20 | block/qcow2.h | 27 +++ | ||
21 | 5 files changed, 593 insertions(+), 6 deletions(-) | ||
22 | create mode 100644 block/qcow2-bitmap.c | ||
23 | |||
24 | diff --git a/block/Makefile.objs b/block/Makefile.objs | ||
25 | index XXXXXXX..XXXXXXX 100644 | 19 | index XXXXXXX..XXXXXXX 100644 |
26 | --- a/block/Makefile.objs | 20 | --- a/block/qcow2.h |
27 | +++ b/block/Makefile.objs | 21 | +++ b/block/qcow2.h |
28 | @@ -XXX,XX +XXX,XX @@ | 22 | @@ -XXX,XX +XXX,XX @@ void qcow2_free_any_cluster(BlockDriverState *bs, uint64_t l2_entry, |
29 | block-obj-y += raw-format.o qcow.o vdi.o vmdk.o cloop.o bochs.o vpc.o vvfat.o dmg.o | 23 | int qcow2_update_snapshot_refcount(BlockDriverState *bs, |
30 | -block-obj-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o qcow2-cache.o | 24 | int64_t l1_table_offset, int l1_size, int addend); |
31 | +block-obj-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o qcow2-cache.o qcow2-bitmap.o | 25 | |
32 | block-obj-y += qed.o qed-l2-cache.o qed-table.o qed-cluster.o | 26 | -int coroutine_fn qcow2_flush_caches(BlockDriverState *bs); |
33 | block-obj-y += qed-check.o | 27 | -int coroutine_fn qcow2_write_caches(BlockDriverState *bs); |
34 | block-obj-y += vhdx.o vhdx-endian.o vhdx-log.o | 28 | +int qcow2_flush_caches(BlockDriverState *bs); |
35 | diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c | 29 | +int qcow2_write_caches(BlockDriverState *bs); |
36 | new file mode 100644 | 30 | int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res, |
37 | index XXXXXXX..XXXXXXX | 31 | BdrvCheckMode fix); |
38 | --- /dev/null | 32 | |
39 | +++ b/block/qcow2-bitmap.c | ||
40 | @@ -XXX,XX +XXX,XX @@ | ||
41 | +/* | ||
42 | + * Bitmaps for the QCOW version 2 format | ||
43 | + * | ||
44 | + * Copyright (c) 2014-2017 Vladimir Sementsov-Ogievskiy | ||
45 | + * | ||
46 | + * This file is derived from qcow2-snapshot.c, original copyright: | ||
47 | + * Copyright (c) 2004-2006 Fabrice Bellard | ||
48 | + * | ||
49 | + * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
50 | + * of this software and associated documentation files (the "Software"), to deal | ||
51 | + * in the Software without restriction, including without limitation the rights | ||
52 | + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
53 | + * copies of the Software, and to permit persons to whom the Software is | ||
54 | + * furnished to do so, subject to the following conditions: | ||
55 | + * | ||
56 | + * The above copyright notice and this permission notice shall be included in | ||
57 | + * all copies or substantial portions of the Software. | ||
58 | + * | ||
59 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
60 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
61 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
62 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
63 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
64 | + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
65 | + * THE SOFTWARE. | ||
66 | + */ | ||
67 | + | ||
68 | +#include "qemu/osdep.h" | ||
69 | +#include "qapi/error.h" | ||
70 | + | ||
71 | +#include "block/block_int.h" | ||
72 | +#include "block/qcow2.h" | ||
73 | + | ||
74 | +/* NOTICE: BME here means Bitmaps Extension and used as a namespace for | ||
75 | + * _internal_ constants. Please do not use this _internal_ abbreviation for | ||
76 | + * other needs and/or outside of this file. */ | ||
77 | + | ||
78 | +/* Bitmap directory entry constraints */ | ||
79 | +#define BME_MAX_TABLE_SIZE 0x8000000 | ||
80 | +#define BME_MAX_PHYS_SIZE 0x20000000 /* restrict BdrvDirtyBitmap size in RAM */ | ||
81 | +#define BME_MAX_GRANULARITY_BITS 31 | ||
82 | +#define BME_MIN_GRANULARITY_BITS 9 | ||
83 | +#define BME_MAX_NAME_SIZE 1023 | ||
84 | + | ||
85 | +/* Bitmap directory entry flags */ | ||
86 | +#define BME_RESERVED_FLAGS 0xfffffffcU | ||
87 | + | ||
88 | +/* bits [1, 8] U [56, 63] are reserved */ | ||
89 | +#define BME_TABLE_ENTRY_RESERVED_MASK 0xff000000000001feULL | ||
90 | +#define BME_TABLE_ENTRY_OFFSET_MASK 0x00fffffffffffe00ULL | ||
91 | +#define BME_TABLE_ENTRY_FLAG_ALL_ONES (1ULL << 0) | ||
92 | + | ||
93 | +typedef struct QEMU_PACKED Qcow2BitmapDirEntry { | ||
94 | + /* header is 8 byte aligned */ | ||
95 | + uint64_t bitmap_table_offset; | ||
96 | + | ||
97 | + uint32_t bitmap_table_size; | ||
98 | + uint32_t flags; | ||
99 | + | ||
100 | + uint8_t type; | ||
101 | + uint8_t granularity_bits; | ||
102 | + uint16_t name_size; | ||
103 | + uint32_t extra_data_size; | ||
104 | + /* extra data follows */ | ||
105 | + /* name follows */ | ||
106 | +} Qcow2BitmapDirEntry; | ||
107 | + | ||
108 | +typedef struct Qcow2BitmapTable { | ||
109 | + uint64_t offset; | ||
110 | + uint32_t size; /* number of 64bit entries */ | ||
111 | + QSIMPLEQ_ENTRY(Qcow2BitmapTable) entry; | ||
112 | +} Qcow2BitmapTable; | ||
113 | + | ||
114 | +typedef struct Qcow2Bitmap { | ||
115 | + Qcow2BitmapTable table; | ||
116 | + uint32_t flags; | ||
117 | + uint8_t granularity_bits; | ||
118 | + char *name; | ||
119 | + | ||
120 | + QSIMPLEQ_ENTRY(Qcow2Bitmap) entry; | ||
121 | +} Qcow2Bitmap; | ||
122 | +typedef QSIMPLEQ_HEAD(Qcow2BitmapList, Qcow2Bitmap) Qcow2BitmapList; | ||
123 | + | ||
124 | +typedef enum BitmapType { | ||
125 | + BT_DIRTY_TRACKING_BITMAP = 1 | ||
126 | +} BitmapType; | ||
127 | + | ||
128 | +static int check_table_entry(uint64_t entry, int cluster_size) | ||
129 | +{ | ||
130 | + uint64_t offset; | ||
131 | + | ||
132 | + if (entry & BME_TABLE_ENTRY_RESERVED_MASK) { | ||
133 | + return -EINVAL; | ||
134 | + } | ||
135 | + | ||
136 | + offset = entry & BME_TABLE_ENTRY_OFFSET_MASK; | ||
137 | + if (offset != 0) { | ||
138 | + /* if offset specified, bit 0 is reserved */ | ||
139 | + if (entry & BME_TABLE_ENTRY_FLAG_ALL_ONES) { | ||
140 | + return -EINVAL; | ||
141 | + } | ||
142 | + | ||
143 | + if (offset % cluster_size != 0) { | ||
144 | + return -EINVAL; | ||
145 | + } | ||
146 | + } | ||
147 | + | ||
148 | + return 0; | ||
149 | +} | ||
150 | + | ||
151 | +static int bitmap_table_load(BlockDriverState *bs, Qcow2BitmapTable *tb, | ||
152 | + uint64_t **bitmap_table) | ||
153 | +{ | ||
154 | + int ret; | ||
155 | + BDRVQcow2State *s = bs->opaque; | ||
156 | + uint32_t i; | ||
157 | + uint64_t *table; | ||
158 | + | ||
159 | + assert(tb->size != 0); | ||
160 | + table = g_try_new(uint64_t, tb->size); | ||
161 | + if (table == NULL) { | ||
162 | + return -ENOMEM; | ||
163 | + } | ||
164 | + | ||
165 | + assert(tb->size <= BME_MAX_TABLE_SIZE); | ||
166 | + ret = bdrv_pread(bs->file, tb->offset, | ||
167 | + table, tb->size * sizeof(uint64_t)); | ||
168 | + if (ret < 0) { | ||
169 | + goto fail; | ||
170 | + } | ||
171 | + | ||
172 | + for (i = 0; i < tb->size; ++i) { | ||
173 | + be64_to_cpus(&table[i]); | ||
174 | + ret = check_table_entry(table[i], s->cluster_size); | ||
175 | + if (ret < 0) { | ||
176 | + goto fail; | ||
177 | + } | ||
178 | + } | ||
179 | + | ||
180 | + *bitmap_table = table; | ||
181 | + return 0; | ||
182 | + | ||
183 | +fail: | ||
184 | + g_free(table); | ||
185 | + | ||
186 | + return ret; | ||
187 | +} | ||
188 | + | ||
189 | +/* | ||
190 | + * Bitmap List | ||
191 | + */ | ||
192 | + | ||
193 | +/* | ||
194 | + * Bitmap List private functions | ||
195 | + * Only Bitmap List knows about bitmap directory structure in Qcow2. | ||
196 | + */ | ||
197 | + | ||
198 | +static inline void bitmap_dir_entry_to_cpu(Qcow2BitmapDirEntry *entry) | ||
199 | +{ | ||
200 | + be64_to_cpus(&entry->bitmap_table_offset); | ||
201 | + be32_to_cpus(&entry->bitmap_table_size); | ||
202 | + be32_to_cpus(&entry->flags); | ||
203 | + be16_to_cpus(&entry->name_size); | ||
204 | + be32_to_cpus(&entry->extra_data_size); | ||
205 | +} | ||
206 | + | ||
207 | +static inline int calc_dir_entry_size(size_t name_size, size_t extra_data_size) | ||
208 | +{ | ||
209 | + return align_offset(sizeof(Qcow2BitmapDirEntry) + | ||
210 | + name_size + extra_data_size, 8); | ||
211 | +} | ||
212 | + | ||
213 | +static inline int dir_entry_size(Qcow2BitmapDirEntry *entry) | ||
214 | +{ | ||
215 | + return calc_dir_entry_size(entry->name_size, entry->extra_data_size); | ||
216 | +} | ||
217 | + | ||
218 | +static inline const char *dir_entry_name_field(Qcow2BitmapDirEntry *entry) | ||
219 | +{ | ||
220 | + return (const char *)(entry + 1) + entry->extra_data_size; | ||
221 | +} | ||
222 | + | ||
223 | +static inline char *dir_entry_copy_name(Qcow2BitmapDirEntry *entry) | ||
224 | +{ | ||
225 | + const char *name_field = dir_entry_name_field(entry); | ||
226 | + return g_strndup(name_field, entry->name_size); | ||
227 | +} | ||
228 | + | ||
229 | +static inline Qcow2BitmapDirEntry *next_dir_entry(Qcow2BitmapDirEntry *entry) | ||
230 | +{ | ||
231 | + return (Qcow2BitmapDirEntry *)((uint8_t *)entry + dir_entry_size(entry)); | ||
232 | +} | ||
233 | + | ||
234 | +static int check_dir_entry(BlockDriverState *bs, Qcow2BitmapDirEntry *entry) | ||
235 | +{ | ||
236 | + BDRVQcow2State *s = bs->opaque; | ||
237 | + uint64_t phys_bitmap_bytes; | ||
238 | + int64_t len; | ||
239 | + | ||
240 | + bool fail = (entry->bitmap_table_size == 0) || | ||
241 | + (entry->bitmap_table_offset == 0) || | ||
242 | + (entry->bitmap_table_offset % s->cluster_size) || | ||
243 | + (entry->bitmap_table_size > BME_MAX_TABLE_SIZE) || | ||
244 | + (entry->granularity_bits > BME_MAX_GRANULARITY_BITS) || | ||
245 | + (entry->granularity_bits < BME_MIN_GRANULARITY_BITS) || | ||
246 | + (entry->flags & BME_RESERVED_FLAGS) || | ||
247 | + (entry->name_size > BME_MAX_NAME_SIZE) || | ||
248 | + (entry->type != BT_DIRTY_TRACKING_BITMAP); | ||
249 | + | ||
250 | + if (fail) { | ||
251 | + return -EINVAL; | ||
252 | + } | ||
253 | + | ||
254 | + phys_bitmap_bytes = (uint64_t)entry->bitmap_table_size * s->cluster_size; | ||
255 | + len = bdrv_getlength(bs); | ||
256 | + | ||
257 | + if (len < 0) { | ||
258 | + return len; | ||
259 | + } | ||
260 | + | ||
261 | + fail = (phys_bitmap_bytes > BME_MAX_PHYS_SIZE) || | ||
262 | + (len > ((phys_bitmap_bytes * 8) << entry->granularity_bits)); | ||
263 | + | ||
264 | + return fail ? -EINVAL : 0; | ||
265 | +} | ||
266 | + | ||
267 | +/* | ||
268 | + * Bitmap List public functions | ||
269 | + */ | ||
270 | + | ||
271 | +static void bitmap_free(Qcow2Bitmap *bm) | ||
272 | +{ | ||
273 | + g_free(bm->name); | ||
274 | + g_free(bm); | ||
275 | +} | ||
276 | + | ||
277 | +static void bitmap_list_free(Qcow2BitmapList *bm_list) | ||
278 | +{ | ||
279 | + Qcow2Bitmap *bm; | ||
280 | + | ||
281 | + if (bm_list == NULL) { | ||
282 | + return; | ||
283 | + } | ||
284 | + | ||
285 | + while ((bm = QSIMPLEQ_FIRST(bm_list)) != NULL) { | ||
286 | + QSIMPLEQ_REMOVE_HEAD(bm_list, entry); | ||
287 | + bitmap_free(bm); | ||
288 | + } | ||
289 | + | ||
290 | + g_free(bm_list); | ||
291 | +} | ||
292 | + | ||
293 | +static Qcow2BitmapList *bitmap_list_new(void) | ||
294 | +{ | ||
295 | + Qcow2BitmapList *bm_list = g_new(Qcow2BitmapList, 1); | ||
296 | + QSIMPLEQ_INIT(bm_list); | ||
297 | + | ||
298 | + return bm_list; | ||
299 | +} | ||
300 | + | ||
301 | +/* bitmap_list_load | ||
302 | + * Get bitmap list from qcow2 image. Actually reads bitmap directory, | ||
303 | + * checks it and convert to bitmap list. | ||
304 | + */ | ||
305 | +static Qcow2BitmapList *bitmap_list_load(BlockDriverState *bs, uint64_t offset, | ||
306 | + uint64_t size, Error **errp) | ||
307 | +{ | ||
308 | + int ret; | ||
309 | + BDRVQcow2State *s = bs->opaque; | ||
310 | + uint8_t *dir, *dir_end; | ||
311 | + Qcow2BitmapDirEntry *e; | ||
312 | + uint32_t nb_dir_entries = 0; | ||
313 | + Qcow2BitmapList *bm_list = NULL; | ||
314 | + | ||
315 | + if (size == 0) { | ||
316 | + error_setg(errp, "Requested bitmap directory size is zero"); | ||
317 | + return NULL; | ||
318 | + } | ||
319 | + | ||
320 | + if (size > QCOW2_MAX_BITMAP_DIRECTORY_SIZE) { | ||
321 | + error_setg(errp, "Requested bitmap directory size is too big"); | ||
322 | + return NULL; | ||
323 | + } | ||
324 | + | ||
325 | + dir = g_try_malloc(size); | ||
326 | + if (dir == NULL) { | ||
327 | + error_setg(errp, "Failed to allocate space for bitmap directory"); | ||
328 | + return NULL; | ||
329 | + } | ||
330 | + dir_end = dir + size; | ||
331 | + | ||
332 | + ret = bdrv_pread(bs->file, offset, dir, size); | ||
333 | + if (ret < 0) { | ||
334 | + error_setg_errno(errp, -ret, "Failed to read bitmap directory"); | ||
335 | + goto fail; | ||
336 | + } | ||
337 | + | ||
338 | + bm_list = bitmap_list_new(); | ||
339 | + for (e = (Qcow2BitmapDirEntry *)dir; | ||
340 | + e < (Qcow2BitmapDirEntry *)dir_end; | ||
341 | + e = next_dir_entry(e)) | ||
342 | + { | ||
343 | + Qcow2Bitmap *bm; | ||
344 | + | ||
345 | + if ((uint8_t *)(e + 1) > dir_end) { | ||
346 | + goto broken_dir; | ||
347 | + } | ||
348 | + | ||
349 | + if (++nb_dir_entries > s->nb_bitmaps) { | ||
350 | + error_setg(errp, "More bitmaps found than specified in header" | ||
351 | + " extension"); | ||
352 | + goto fail; | ||
353 | + } | ||
354 | + bitmap_dir_entry_to_cpu(e); | ||
355 | + | ||
356 | + if ((uint8_t *)next_dir_entry(e) > dir_end) { | ||
357 | + goto broken_dir; | ||
358 | + } | ||
359 | + | ||
360 | + if (e->extra_data_size != 0) { | ||
361 | + error_setg(errp, "Bitmap extra data is not supported"); | ||
362 | + goto fail; | ||
363 | + } | ||
364 | + | ||
365 | + ret = check_dir_entry(bs, e); | ||
366 | + if (ret < 0) { | ||
367 | + error_setg(errp, "Bitmap '%.*s' doesn't satisfy the constraints", | ||
368 | + e->name_size, dir_entry_name_field(e)); | ||
369 | + goto fail; | ||
370 | + } | ||
371 | + | ||
372 | + bm = g_new(Qcow2Bitmap, 1); | ||
373 | + bm->table.offset = e->bitmap_table_offset; | ||
374 | + bm->table.size = e->bitmap_table_size; | ||
375 | + bm->flags = e->flags; | ||
376 | + bm->granularity_bits = e->granularity_bits; | ||
377 | + bm->name = dir_entry_copy_name(e); | ||
378 | + QSIMPLEQ_INSERT_TAIL(bm_list, bm, entry); | ||
379 | + } | ||
380 | + | ||
381 | + if (nb_dir_entries != s->nb_bitmaps) { | ||
382 | + error_setg(errp, "Less bitmaps found than specified in header" | ||
383 | + " extension"); | ||
384 | + goto fail; | ||
385 | + } | ||
386 | + | ||
387 | + if ((uint8_t *)e != dir_end) { | ||
388 | + goto broken_dir; | ||
389 | + } | ||
390 | + | ||
391 | + g_free(dir); | ||
392 | + return bm_list; | ||
393 | + | ||
394 | +broken_dir: | ||
395 | + ret = -EINVAL; | ||
396 | + error_setg(errp, "Broken bitmap directory"); | ||
397 | + | ||
398 | +fail: | ||
399 | + g_free(dir); | ||
400 | + bitmap_list_free(bm_list); | ||
401 | + | ||
402 | + return NULL; | ||
403 | +} | ||
404 | + | ||
405 | +int qcow2_check_bitmaps_refcounts(BlockDriverState *bs, BdrvCheckResult *res, | ||
406 | + void **refcount_table, | ||
407 | + int64_t *refcount_table_size) | ||
408 | +{ | ||
409 | + int ret; | ||
410 | + BDRVQcow2State *s = bs->opaque; | ||
411 | + Qcow2BitmapList *bm_list; | ||
412 | + Qcow2Bitmap *bm; | ||
413 | + | ||
414 | + if (s->nb_bitmaps == 0) { | ||
415 | + return 0; | ||
416 | + } | ||
417 | + | ||
418 | + ret = qcow2_inc_refcounts_imrt(bs, res, refcount_table, refcount_table_size, | ||
419 | + s->bitmap_directory_offset, | ||
420 | + s->bitmap_directory_size); | ||
421 | + if (ret < 0) { | ||
422 | + return ret; | ||
423 | + } | ||
424 | + | ||
425 | + bm_list = bitmap_list_load(bs, s->bitmap_directory_offset, | ||
426 | + s->bitmap_directory_size, NULL); | ||
427 | + if (bm_list == NULL) { | ||
428 | + res->corruptions++; | ||
429 | + return -EINVAL; | ||
430 | + } | ||
431 | + | ||
432 | + QSIMPLEQ_FOREACH(bm, bm_list, entry) { | ||
433 | + uint64_t *bitmap_table = NULL; | ||
434 | + int i; | ||
435 | + | ||
436 | + ret = qcow2_inc_refcounts_imrt(bs, res, | ||
437 | + refcount_table, refcount_table_size, | ||
438 | + bm->table.offset, | ||
439 | + bm->table.size * sizeof(uint64_t)); | ||
440 | + if (ret < 0) { | ||
441 | + goto out; | ||
442 | + } | ||
443 | + | ||
444 | + ret = bitmap_table_load(bs, &bm->table, &bitmap_table); | ||
445 | + if (ret < 0) { | ||
446 | + res->corruptions++; | ||
447 | + goto out; | ||
448 | + } | ||
449 | + | ||
450 | + for (i = 0; i < bm->table.size; ++i) { | ||
451 | + uint64_t entry = bitmap_table[i]; | ||
452 | + uint64_t offset = entry & BME_TABLE_ENTRY_OFFSET_MASK; | ||
453 | + | ||
454 | + if (check_table_entry(entry, s->cluster_size) < 0) { | ||
455 | + res->corruptions++; | ||
456 | + continue; | ||
457 | + } | ||
458 | + | ||
459 | + if (offset == 0) { | ||
460 | + continue; | ||
461 | + } | ||
462 | + | ||
463 | + ret = qcow2_inc_refcounts_imrt(bs, res, | ||
464 | + refcount_table, refcount_table_size, | ||
465 | + offset, s->cluster_size); | ||
466 | + if (ret < 0) { | ||
467 | + g_free(bitmap_table); | ||
468 | + goto out; | ||
469 | + } | ||
470 | + } | ||
471 | + | ||
472 | + g_free(bitmap_table); | ||
473 | + } | ||
474 | + | ||
475 | +out: | ||
476 | + bitmap_list_free(bm_list); | ||
477 | + | ||
478 | + return ret; | ||
479 | +} | ||
480 | diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c | 33 | diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c |
481 | index XXXXXXX..XXXXXXX 100644 | 34 | index XXXXXXX..XXXXXXX 100644 |
482 | --- a/block/qcow2-refcount.c | 35 | --- a/block/qcow2-refcount.c |
483 | +++ b/block/qcow2-refcount.c | 36 | +++ b/block/qcow2-refcount.c |
484 | @@ -XXX,XX +XXX,XX @@ static int calculate_refcounts(BlockDriverState *bs, BdrvCheckResult *res, | 37 | @@ -XXX,XX +XXX,XX @@ void qcow2_free_any_cluster(BlockDriverState *bs, uint64_t l2_entry, |
485 | } | ||
486 | } | 38 | } |
487 | |||
488 | + /* bitmaps */ | ||
489 | + ret = qcow2_check_bitmaps_refcounts(bs, res, refcount_table, nb_clusters); | ||
490 | + if (ret < 0) { | ||
491 | + return ret; | ||
492 | + } | ||
493 | + | ||
494 | return check_refblocks(bs, res, fix, rebuild, refcount_table, nb_clusters); | ||
495 | } | 39 | } |
496 | 40 | ||
497 | diff --git a/block/qcow2.c b/block/qcow2.c | 41 | -int coroutine_fn qcow2_write_caches(BlockDriverState *bs) |
498 | index XXXXXXX..XXXXXXX 100644 | 42 | +int qcow2_write_caches(BlockDriverState *bs) |
499 | --- a/block/qcow2.c | ||
500 | +++ b/block/qcow2.c | ||
501 | @@ -XXX,XX +XXX,XX @@ typedef struct { | ||
502 | #define QCOW2_EXT_MAGIC_BACKING_FORMAT 0xE2792ACA | ||
503 | #define QCOW2_EXT_MAGIC_FEATURE_TABLE 0x6803f857 | ||
504 | #define QCOW2_EXT_MAGIC_CRYPTO_HEADER 0x0537be77 | ||
505 | +#define QCOW2_EXT_MAGIC_BITMAPS 0x23852875 | ||
506 | |||
507 | static int qcow2_probe(const uint8_t *buf, int buf_size, const char *filename) | ||
508 | { | ||
509 | @@ -XXX,XX +XXX,XX @@ static ssize_t qcow2_crypto_hdr_write_func(QCryptoBlock *block, size_t offset, | ||
510 | */ | ||
511 | static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset, | ||
512 | uint64_t end_offset, void **p_feature_table, | ||
513 | - int flags, Error **errp) | ||
514 | + int flags, bool *need_update_header, | ||
515 | + Error **errp) | ||
516 | { | 43 | { |
517 | BDRVQcow2State *s = bs->opaque; | 44 | BDRVQcow2State *s = bs->opaque; |
518 | QCowExtension ext; | ||
519 | uint64_t offset; | ||
520 | int ret; | 45 | int ret; |
521 | + Qcow2BitmapHeaderExt bitmaps_ext; | 46 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn qcow2_write_caches(BlockDriverState *bs) |
522 | + | 47 | return 0; |
523 | + if (need_update_header != NULL) { | 48 | } |
524 | + *need_update_header = false; | 49 | |
525 | + } | 50 | -int coroutine_fn qcow2_flush_caches(BlockDriverState *bs) |
526 | 51 | +int qcow2_flush_caches(BlockDriverState *bs) | |
527 | #ifdef DEBUG_EXT | 52 | { |
528 | printf("qcow2_read_extensions: start=%ld end=%ld\n", start_offset, end_offset); | 53 | int ret = qcow2_write_caches(bs); |
529 | @@ -XXX,XX +XXX,XX @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset, | ||
530 | } | ||
531 | } break; | ||
532 | |||
533 | + case QCOW2_EXT_MAGIC_BITMAPS: | ||
534 | + if (ext.len != sizeof(bitmaps_ext)) { | ||
535 | + error_setg_errno(errp, -ret, "bitmaps_ext: " | ||
536 | + "Invalid extension length"); | ||
537 | + return -EINVAL; | ||
538 | + } | ||
539 | + | ||
540 | + if (!(s->autoclear_features & QCOW2_AUTOCLEAR_BITMAPS)) { | ||
541 | + error_report("WARNING: a program lacking bitmap support " | ||
542 | + "modified this file, so all bitmaps are now " | ||
543 | + "considered inconsistent. Some clusters may be " | ||
544 | + "leaked, run 'qemu-img check -r' on the image " | ||
545 | + "file to fix."); | ||
546 | + if (need_update_header != NULL) { | ||
547 | + /* Updating is needed to drop invalid bitmap extension. */ | ||
548 | + *need_update_header = true; | ||
549 | + } | ||
550 | + break; | ||
551 | + } | ||
552 | + | ||
553 | + ret = bdrv_pread(bs->file, offset, &bitmaps_ext, ext.len); | ||
554 | + if (ret < 0) { | ||
555 | + error_setg_errno(errp, -ret, "bitmaps_ext: " | ||
556 | + "Could not read ext header"); | ||
557 | + return ret; | ||
558 | + } | ||
559 | + | ||
560 | + if (bitmaps_ext.reserved32 != 0) { | ||
561 | + error_setg_errno(errp, -ret, "bitmaps_ext: " | ||
562 | + "Reserved field is not zero"); | ||
563 | + return -EINVAL; | ||
564 | + } | ||
565 | + | ||
566 | + be32_to_cpus(&bitmaps_ext.nb_bitmaps); | ||
567 | + be64_to_cpus(&bitmaps_ext.bitmap_directory_size); | ||
568 | + be64_to_cpus(&bitmaps_ext.bitmap_directory_offset); | ||
569 | + | ||
570 | + if (bitmaps_ext.nb_bitmaps > QCOW2_MAX_BITMAPS) { | ||
571 | + error_setg(errp, | ||
572 | + "bitmaps_ext: Image has %" PRIu32 " bitmaps, " | ||
573 | + "exceeding the QEMU supported maximum of %d", | ||
574 | + bitmaps_ext.nb_bitmaps, QCOW2_MAX_BITMAPS); | ||
575 | + return -EINVAL; | ||
576 | + } | ||
577 | + | ||
578 | + if (bitmaps_ext.nb_bitmaps == 0) { | ||
579 | + error_setg(errp, "found bitmaps extension with zero bitmaps"); | ||
580 | + return -EINVAL; | ||
581 | + } | ||
582 | + | ||
583 | + if (bitmaps_ext.bitmap_directory_offset & (s->cluster_size - 1)) { | ||
584 | + error_setg(errp, "bitmaps_ext: " | ||
585 | + "invalid bitmap directory offset"); | ||
586 | + return -EINVAL; | ||
587 | + } | ||
588 | + | ||
589 | + if (bitmaps_ext.bitmap_directory_size > | ||
590 | + QCOW2_MAX_BITMAP_DIRECTORY_SIZE) { | ||
591 | + error_setg(errp, "bitmaps_ext: " | ||
592 | + "bitmap directory size (%" PRIu64 ") exceeds " | ||
593 | + "the maximum supported size (%d)", | ||
594 | + bitmaps_ext.bitmap_directory_size, | ||
595 | + QCOW2_MAX_BITMAP_DIRECTORY_SIZE); | ||
596 | + return -EINVAL; | ||
597 | + } | ||
598 | + | ||
599 | + s->nb_bitmaps = bitmaps_ext.nb_bitmaps; | ||
600 | + s->bitmap_directory_offset = | ||
601 | + bitmaps_ext.bitmap_directory_offset; | ||
602 | + s->bitmap_directory_size = | ||
603 | + bitmaps_ext.bitmap_directory_size; | ||
604 | + | ||
605 | +#ifdef DEBUG_EXT | ||
606 | + printf("Qcow2: Got bitmaps extension: " | ||
607 | + "offset=%" PRIu64 " nb_bitmaps=%" PRIu32 "\n", | ||
608 | + s->bitmap_directory_offset, s->nb_bitmaps); | ||
609 | +#endif | ||
610 | + break; | ||
611 | + | ||
612 | default: | ||
613 | /* unknown magic - save it in case we need to rewrite the header */ | ||
614 | { | ||
615 | @@ -XXX,XX +XXX,XX @@ static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags, | ||
616 | Error *local_err = NULL; | ||
617 | uint64_t ext_end; | ||
618 | uint64_t l1_vm_state_index; | ||
619 | + bool update_header = false; | ||
620 | |||
621 | ret = bdrv_pread(bs->file, 0, &header, sizeof(header)); | ||
622 | if (ret < 0) { | 54 | if (ret < 0) { |
623 | @@ -XXX,XX +XXX,XX @@ static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags, | ||
624 | if (s->incompatible_features & ~QCOW2_INCOMPAT_MASK) { | ||
625 | void *feature_table = NULL; | ||
626 | qcow2_read_extensions(bs, header.header_length, ext_end, | ||
627 | - &feature_table, flags, NULL); | ||
628 | + &feature_table, flags, NULL, NULL); | ||
629 | report_unsupported_feature(errp, feature_table, | ||
630 | s->incompatible_features & | ||
631 | ~QCOW2_INCOMPAT_MASK); | ||
632 | @@ -XXX,XX +XXX,XX @@ static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags, | ||
633 | |||
634 | /* read qcow2 extensions */ | ||
635 | if (qcow2_read_extensions(bs, header.header_length, ext_end, NULL, | ||
636 | - flags, &local_err)) { | ||
637 | + flags, &update_header, &local_err)) { | ||
638 | error_propagate(errp, local_err); | ||
639 | ret = -EINVAL; | ||
640 | goto fail; | ||
641 | @@ -XXX,XX +XXX,XX @@ static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags, | ||
642 | } | ||
643 | |||
644 | /* Clear unknown autoclear feature bits */ | ||
645 | - if (!bs->read_only && !(flags & BDRV_O_INACTIVE) && s->autoclear_features) { | ||
646 | - s->autoclear_features = 0; | ||
647 | + update_header |= s->autoclear_features & ~QCOW2_AUTOCLEAR_MASK; | ||
648 | + | ||
649 | + if (update_header && !bs->read_only && !(flags & BDRV_O_INACTIVE)) { | ||
650 | + s->autoclear_features &= QCOW2_AUTOCLEAR_MASK; | ||
651 | ret = qcow2_update_header(bs); | ||
652 | if (ret < 0) { | ||
653 | error_setg_errno(errp, -ret, "Could not update qcow2 header"); | ||
654 | @@ -XXX,XX +XXX,XX @@ int qcow2_update_header(BlockDriverState *bs) | ||
655 | buflen -= ret; | ||
656 | } | ||
657 | |||
658 | + /* Bitmap extension */ | ||
659 | + if (s->nb_bitmaps > 0) { | ||
660 | + Qcow2BitmapHeaderExt bitmaps_header = { | ||
661 | + .nb_bitmaps = cpu_to_be32(s->nb_bitmaps), | ||
662 | + .bitmap_directory_size = | ||
663 | + cpu_to_be64(s->bitmap_directory_size), | ||
664 | + .bitmap_directory_offset = | ||
665 | + cpu_to_be64(s->bitmap_directory_offset) | ||
666 | + }; | ||
667 | + ret = header_ext_add(buf, QCOW2_EXT_MAGIC_BITMAPS, | ||
668 | + &bitmaps_header, sizeof(bitmaps_header), | ||
669 | + buflen); | ||
670 | + if (ret < 0) { | ||
671 | + goto fail; | ||
672 | + } | ||
673 | + buf += ret; | ||
674 | + buflen -= ret; | ||
675 | + } | ||
676 | + | ||
677 | /* Keep unknown header extensions */ | ||
678 | QLIST_FOREACH(uext, &s->unknown_header_ext, next) { | ||
679 | ret = header_ext_add(buf, uext->magic, uext->data, uext->len, buflen); | ||
680 | @@ -XXX,XX +XXX,XX @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset, Error **errp) | ||
681 | return -ENOTSUP; | ||
682 | } | ||
683 | |||
684 | + /* cannot proceed if image has bitmaps */ | ||
685 | + if (s->nb_bitmaps) { | ||
686 | + /* TODO: resize bitmaps in the image */ | ||
687 | + error_setg(errp, "Can't resize an image which has bitmaps"); | ||
688 | + return -ENOTSUP; | ||
689 | + } | ||
690 | + | ||
691 | /* shrinking is currently not supported */ | ||
692 | if (offset < bs->total_sectors * 512) { | ||
693 | error_setg(errp, "qcow2 doesn't support shrinking images yet"); | ||
694 | diff --git a/block/qcow2.h b/block/qcow2.h | ||
695 | index XXXXXXX..XXXXXXX 100644 | ||
696 | --- a/block/qcow2.h | ||
697 | +++ b/block/qcow2.h | ||
698 | @@ -XXX,XX +XXX,XX @@ | ||
699 | * space for snapshot names and IDs */ | ||
700 | #define QCOW_MAX_SNAPSHOTS_SIZE (1024 * QCOW_MAX_SNAPSHOTS) | ||
701 | |||
702 | +/* Bitmap header extension constraints */ | ||
703 | +#define QCOW2_MAX_BITMAPS 65535 | ||
704 | +#define QCOW2_MAX_BITMAP_DIRECTORY_SIZE (1024 * QCOW2_MAX_BITMAPS) | ||
705 | + | ||
706 | /* indicate that the refcount of the referenced cluster is exactly one. */ | ||
707 | #define QCOW_OFLAG_COPIED (1ULL << 63) | ||
708 | /* indicate that the cluster is compressed (they never have the copied flag) */ | ||
709 | @@ -XXX,XX +XXX,XX @@ enum { | ||
710 | QCOW2_COMPAT_FEAT_MASK = QCOW2_COMPAT_LAZY_REFCOUNTS, | ||
711 | }; | ||
712 | |||
713 | +/* Autoclear feature bits */ | ||
714 | +enum { | ||
715 | + QCOW2_AUTOCLEAR_BITMAPS_BITNR = 0, | ||
716 | + QCOW2_AUTOCLEAR_BITMAPS = 1 << QCOW2_AUTOCLEAR_BITMAPS_BITNR, | ||
717 | + | ||
718 | + QCOW2_AUTOCLEAR_MASK = QCOW2_AUTOCLEAR_BITMAPS, | ||
719 | +}; | ||
720 | + | ||
721 | enum qcow2_discard_type { | ||
722 | QCOW2_DISCARD_NEVER = 0, | ||
723 | QCOW2_DISCARD_ALWAYS, | ||
724 | @@ -XXX,XX +XXX,XX @@ typedef uint64_t Qcow2GetRefcountFunc(const void *refcount_array, | ||
725 | typedef void Qcow2SetRefcountFunc(void *refcount_array, | ||
726 | uint64_t index, uint64_t value); | ||
727 | |||
728 | +typedef struct Qcow2BitmapHeaderExt { | ||
729 | + uint32_t nb_bitmaps; | ||
730 | + uint32_t reserved32; | ||
731 | + uint64_t bitmap_directory_size; | ||
732 | + uint64_t bitmap_directory_offset; | ||
733 | +} QEMU_PACKED Qcow2BitmapHeaderExt; | ||
734 | + | ||
735 | typedef struct BDRVQcow2State { | ||
736 | int cluster_bits; | ||
737 | int cluster_size; | ||
738 | @@ -XXX,XX +XXX,XX @@ typedef struct BDRVQcow2State { | ||
739 | unsigned int nb_snapshots; | ||
740 | QCowSnapshot *snapshots; | ||
741 | |||
742 | + uint32_t nb_bitmaps; | ||
743 | + uint64_t bitmap_directory_size; | ||
744 | + uint64_t bitmap_directory_offset; | ||
745 | + | ||
746 | int flags; | ||
747 | int qcow_version; | ||
748 | bool use_lazy_refcounts; | ||
749 | @@ -XXX,XX +XXX,XX @@ int qcow2_cache_get_empty(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset, | ||
750 | void **table); | ||
751 | void qcow2_cache_put(BlockDriverState *bs, Qcow2Cache *c, void **table); | ||
752 | |||
753 | +/* qcow2-bitmap.c functions */ | ||
754 | +int qcow2_check_bitmaps_refcounts(BlockDriverState *bs, BdrvCheckResult *res, | ||
755 | + void **refcount_table, | ||
756 | + int64_t *refcount_table_size); | ||
757 | #endif | ||
758 | -- | 55 | -- |
759 | 1.8.3.1 | 56 | 2.37.3 |
760 | |||
761 | diff view generated by jsdifflib |
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 1 | From: Paolo Bonzini <pbonzini@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Realize .bdrv_can_store_new_dirty_bitmap interface. | 3 | nbd_co_establish_connection_cancel() cancels a coroutine but is not called |
4 | from coroutine context itself, for example in nbd_cancel_in_flight() | ||
5 | and in timer callbacks reconnect_delay_timer_cb() and open_timer_cb(). | ||
4 | 6 | ||
5 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 7 | Reviewed-by: Alberto Faria <afaria@redhat.com> |
6 | Reviewed-by: John Snow <jsnow@redhat.com> | 8 | Reviewed-by: Eric Blake <eblake@redhat.com> |
7 | Reviewed-by: Max Reitz <mreitz@redhat.com> | 9 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
8 | Message-id: 20170628120530.31251-23-vsementsov@virtuozzo.com | 10 | Message-Id: <20220922084924.201610-5-pbonzini@redhat.com> |
9 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 11 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> |
12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
10 | --- | 13 | --- |
11 | block/qcow2-bitmap.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ | 14 | include/block/nbd.h | 2 +- |
12 | block/qcow2.c | 1 + | 15 | 1 file changed, 1 insertion(+), 1 deletion(-) |
13 | block/qcow2.h | 4 ++++ | ||
14 | 3 files changed, 56 insertions(+) | ||
15 | 16 | ||
16 | diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c | 17 | diff --git a/include/block/nbd.h b/include/block/nbd.h |
17 | index XXXXXXX..XXXXXXX 100644 | 18 | index XXXXXXX..XXXXXXX 100644 |
18 | --- a/block/qcow2-bitmap.c | 19 | --- a/include/block/nbd.h |
19 | +++ b/block/qcow2-bitmap.c | 20 | +++ b/include/block/nbd.h |
20 | @@ -XXX,XX +XXX,XX @@ int qcow2_reopen_bitmaps_ro(BlockDriverState *bs, Error **errp) | 21 | @@ -XXX,XX +XXX,XX @@ QIOChannel *coroutine_fn |
21 | 22 | nbd_co_establish_connection(NBDClientConnection *conn, NBDExportInfo *info, | |
22 | return 0; | 23 | bool blocking, Error **errp); |
23 | } | 24 | |
24 | + | 25 | -void coroutine_fn nbd_co_establish_connection_cancel(NBDClientConnection *conn); |
25 | +bool qcow2_can_store_new_dirty_bitmap(BlockDriverState *bs, | 26 | +void nbd_co_establish_connection_cancel(NBDClientConnection *conn); |
26 | + const char *name, | ||
27 | + uint32_t granularity, | ||
28 | + Error **errp) | ||
29 | +{ | ||
30 | + BDRVQcow2State *s = bs->opaque; | ||
31 | + bool found; | ||
32 | + Qcow2BitmapList *bm_list; | ||
33 | + | ||
34 | + if (check_constraints_on_bitmap(bs, name, granularity, errp) != 0) { | ||
35 | + goto fail; | ||
36 | + } | ||
37 | + | ||
38 | + if (s->nb_bitmaps == 0) { | ||
39 | + return true; | ||
40 | + } | ||
41 | + | ||
42 | + if (s->nb_bitmaps >= QCOW2_MAX_BITMAPS) { | ||
43 | + error_setg(errp, | ||
44 | + "Maximum number of persistent bitmaps is already reached"); | ||
45 | + goto fail; | ||
46 | + } | ||
47 | + | ||
48 | + if (s->bitmap_directory_size + calc_dir_entry_size(strlen(name), 0) > | ||
49 | + QCOW2_MAX_BITMAP_DIRECTORY_SIZE) | ||
50 | + { | ||
51 | + error_setg(errp, "Not enough space in the bitmap directory"); | ||
52 | + goto fail; | ||
53 | + } | ||
54 | + | ||
55 | + bm_list = bitmap_list_load(bs, s->bitmap_directory_offset, | ||
56 | + s->bitmap_directory_size, errp); | ||
57 | + if (bm_list == NULL) { | ||
58 | + goto fail; | ||
59 | + } | ||
60 | + | ||
61 | + found = find_bitmap_by_name(bm_list, name); | ||
62 | + bitmap_list_free(bm_list); | ||
63 | + if (found) { | ||
64 | + error_setg(errp, "Bitmap with the same name is already stored"); | ||
65 | + goto fail; | ||
66 | + } | ||
67 | + | ||
68 | + return true; | ||
69 | + | ||
70 | +fail: | ||
71 | + error_prepend(errp, "Can't make bitmap '%s' persistent in '%s': ", | ||
72 | + name, bdrv_get_device_or_node_name(bs)); | ||
73 | + return false; | ||
74 | +} | ||
75 | diff --git a/block/qcow2.c b/block/qcow2.c | ||
76 | index XXXXXXX..XXXXXXX 100644 | ||
77 | --- a/block/qcow2.c | ||
78 | +++ b/block/qcow2.c | ||
79 | @@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_qcow2 = { | ||
80 | .bdrv_attach_aio_context = qcow2_attach_aio_context, | ||
81 | |||
82 | .bdrv_reopen_bitmaps_rw = qcow2_reopen_bitmaps_rw, | ||
83 | + .bdrv_can_store_new_dirty_bitmap = qcow2_can_store_new_dirty_bitmap, | ||
84 | }; | ||
85 | |||
86 | static void bdrv_qcow2_init(void) | ||
87 | diff --git a/block/qcow2.h b/block/qcow2.h | ||
88 | index XXXXXXX..XXXXXXX 100644 | ||
89 | --- a/block/qcow2.h | ||
90 | +++ b/block/qcow2.h | ||
91 | @@ -XXX,XX +XXX,XX @@ bool qcow2_load_autoloading_dirty_bitmaps(BlockDriverState *bs, Error **errp); | ||
92 | int qcow2_reopen_bitmaps_rw(BlockDriverState *bs, Error **errp); | ||
93 | void qcow2_store_persistent_dirty_bitmaps(BlockDriverState *bs, Error **errp); | ||
94 | int qcow2_reopen_bitmaps_ro(BlockDriverState *bs, Error **errp); | ||
95 | +bool qcow2_can_store_new_dirty_bitmap(BlockDriverState *bs, | ||
96 | + const char *name, | ||
97 | + uint32_t granularity, | ||
98 | + Error **errp); | ||
99 | 27 | ||
100 | #endif | 28 | #endif |
101 | -- | 29 | -- |
102 | 1.8.3.1 | 30 | 2.37.3 |
103 | |||
104 | diff view generated by jsdifflib |
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 1 | From: Paolo Bonzini <pbonzini@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Make getter signature const-correct. This allows other functions with | 3 | qemu_coroutine_get_aio_context inspects a coroutine, but it does |
4 | const dirty bitmap parameter use bdrv_dirty_bitmap_granularity(). | 4 | not have to be called from the coroutine itself (or from any |
5 | coroutine). | ||
5 | 6 | ||
6 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 7 | Reviewed-by: Alberto Faria <afaria@redhat.com> |
7 | Reviewed-by: Eric Blake <eblake@redhat.com> | 8 | Reviewed-by: Eric Blake <eblake@redhat.com> |
8 | Reviewed-by: John Snow <jsnow@redhat.com> | 9 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
10 | Message-Id: <20220922084924.201610-6-pbonzini@redhat.com> | ||
9 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | 11 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> |
10 | Message-id: 20170628120530.31251-6-vsementsov@virtuozzo.com | 12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
11 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
12 | --- | 13 | --- |
13 | block/dirty-bitmap.c | 2 +- | 14 | include/qemu/coroutine.h | 2 +- |
14 | include/block/dirty-bitmap.h | 2 +- | 15 | util/qemu-coroutine.c | 2 +- |
15 | 2 files changed, 2 insertions(+), 2 deletions(-) | 16 | 2 files changed, 2 insertions(+), 2 deletions(-) |
16 | 17 | ||
17 | diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c | 18 | diff --git a/include/qemu/coroutine.h b/include/qemu/coroutine.h |
18 | index XXXXXXX..XXXXXXX 100644 | 19 | index XXXXXXX..XXXXXXX 100644 |
19 | --- a/block/dirty-bitmap.c | 20 | --- a/include/qemu/coroutine.h |
20 | +++ b/block/dirty-bitmap.c | 21 | +++ b/include/qemu/coroutine.h |
21 | @@ -XXX,XX +XXX,XX @@ uint32_t bdrv_get_default_bitmap_granularity(BlockDriverState *bs) | 22 | @@ -XXX,XX +XXX,XX @@ void coroutine_fn qemu_coroutine_yield(void); |
22 | return granularity; | 23 | /** |
24 | * Get the AioContext of the given coroutine | ||
25 | */ | ||
26 | -AioContext *coroutine_fn qemu_coroutine_get_aio_context(Coroutine *co); | ||
27 | +AioContext *qemu_coroutine_get_aio_context(Coroutine *co); | ||
28 | |||
29 | /** | ||
30 | * Get the currently executing coroutine | ||
31 | diff --git a/util/qemu-coroutine.c b/util/qemu-coroutine.c | ||
32 | index XXXXXXX..XXXXXXX 100644 | ||
33 | --- a/util/qemu-coroutine.c | ||
34 | +++ b/util/qemu-coroutine.c | ||
35 | @@ -XXX,XX +XXX,XX @@ bool qemu_coroutine_entered(Coroutine *co) | ||
36 | return co->caller; | ||
23 | } | 37 | } |
24 | 38 | ||
25 | -uint32_t bdrv_dirty_bitmap_granularity(BdrvDirtyBitmap *bitmap) | 39 | -AioContext *coroutine_fn qemu_coroutine_get_aio_context(Coroutine *co) |
26 | +uint32_t bdrv_dirty_bitmap_granularity(const BdrvDirtyBitmap *bitmap) | 40 | +AioContext *qemu_coroutine_get_aio_context(Coroutine *co) |
27 | { | 41 | { |
28 | return BDRV_SECTOR_SIZE << hbitmap_granularity(bitmap->bitmap); | 42 | return co->ctx; |
29 | } | 43 | } |
30 | diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h | ||
31 | index XXXXXXX..XXXXXXX 100644 | ||
32 | --- a/include/block/dirty-bitmap.h | ||
33 | +++ b/include/block/dirty-bitmap.h | ||
34 | @@ -XXX,XX +XXX,XX @@ void bdrv_disable_dirty_bitmap(BdrvDirtyBitmap *bitmap); | ||
35 | void bdrv_enable_dirty_bitmap(BdrvDirtyBitmap *bitmap); | ||
36 | BlockDirtyInfoList *bdrv_query_dirty_bitmaps(BlockDriverState *bs); | ||
37 | uint32_t bdrv_get_default_bitmap_granularity(BlockDriverState *bs); | ||
38 | -uint32_t bdrv_dirty_bitmap_granularity(BdrvDirtyBitmap *bitmap); | ||
39 | +uint32_t bdrv_dirty_bitmap_granularity(const BdrvDirtyBitmap *bitmap); | ||
40 | uint32_t bdrv_dirty_bitmap_meta_granularity(BdrvDirtyBitmap *bitmap); | ||
41 | bool bdrv_dirty_bitmap_enabled(BdrvDirtyBitmap *bitmap); | ||
42 | bool bdrv_dirty_bitmap_frozen(BdrvDirtyBitmap *bitmap); | ||
43 | -- | 44 | -- |
44 | 1.8.3.1 | 45 | 2.37.3 |
45 | |||
46 | diff view generated by jsdifflib |
1 | From: Eric Blake <eblake@redhat.com> | 1 | From: Paolo Bonzini <pbonzini@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | POSIX says that backslashes in the arguments to 'echo', as well as | 3 | Callers of coroutine_fn must be coroutine_fn themselves, or the call |
4 | any use of 'echo -n' and 'echo -e', are non-portable; it recommends | 4 | must be within "if (qemu_in_coroutine())". Apply coroutine_fn to |
5 | people should favor 'printf' instead. This is definitely true where | 5 | functions where this holds. |
6 | we do not control which shell is running (such as in makefile snippets | ||
7 | or in documentation examples). But even for scripts where we | ||
8 | require bash (and therefore, where echo does what we want by default), | ||
9 | it is still possible to use 'shopt -s xpg_echo' to change bash's | ||
10 | behavior of echo. And setting a good example never hurts when we are | ||
11 | not sure if a snippet will be copied from a bash-only script to a | ||
12 | general shell script (although I don't change the use of non-portable | ||
13 | \e for ESC when we know the running shell is bash). | ||
14 | 6 | ||
15 | Replace 'echo -n "..."' with 'printf %s "..."', and 'echo -e "..."' | 7 | Reviewed-by: Alberto Faria <afaria@redhat.com> |
16 | with 'printf %b "...\n"', with the optimization that the %s/%b | 8 | Reviewed-by: Eric Blake <eblake@redhat.com> |
17 | argument can be omitted if the string being printed is a strict | 9 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
18 | literal with no '%', '$', or '`' (we could technically also make | 10 | Message-Id: <20220922084924.201610-8-pbonzini@redhat.com> |
19 | this optimization when there are $ or `` substitutions but where | 11 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> |
20 | we can prove their results will not be problematic, but proving | 12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
21 | that such substitutions are safe makes the patch less trivial | 13 | --- |
22 | compared to just being consistent). | 14 | block/blkverify.c | 2 +- |
15 | 1 file changed, 1 insertion(+), 1 deletion(-) | ||
23 | 16 | ||
24 | In the qemu-iotests check script, fix unusual shell quoting | 17 | diff --git a/block/blkverify.c b/block/blkverify.c |
25 | that would result in word-splitting if 'date' outputs a space. | ||
26 | |||
27 | In test 051, take an opportunity to shorten the line. | ||
28 | |||
29 | In test 068, get rid of a pointless second invocation of bash. | ||
30 | |||
31 | CC: qemu-trivial@nongnu.org | ||
32 | Signed-off-by: Eric Blake <eblake@redhat.com> | ||
33 | Message-id: 20170703180950.9895-1-eblake@redhat.com | ||
34 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
35 | --- | ||
36 | qemu-options.hx | 4 ++-- | ||
37 | tests/multiboot/run_test.sh | 10 +++++----- | ||
38 | tests/qemu-iotests/051 | 7 ++++--- | ||
39 | tests/qemu-iotests/068 | 2 +- | ||
40 | tests/qemu-iotests/142 | 48 ++++++++++++++++++++++----------------------- | ||
41 | tests/qemu-iotests/171 | 14 ++++++------- | ||
42 | tests/qemu-iotests/check | 18 ++++++++--------- | ||
43 | tests/rocker/all | 10 +++++----- | ||
44 | tests/tcg/cris/Makefile | 8 ++++---- | ||
45 | 9 files changed, 61 insertions(+), 60 deletions(-) | ||
46 | |||
47 | diff --git a/qemu-options.hx b/qemu-options.hx | ||
48 | index XXXXXXX..XXXXXXX 100644 | 18 | index XXXXXXX..XXXXXXX 100644 |
49 | --- a/qemu-options.hx | 19 | --- a/block/blkverify.c |
50 | +++ b/qemu-options.hx | 20 | +++ b/block/blkverify.c |
51 | @@ -XXX,XX +XXX,XX @@ The simplest (insecure) usage is to provide the secret inline | 21 | @@ -XXX,XX +XXX,XX @@ blkverify_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes, |
52 | 22 | return blkverify_co_prwv(bs, &r, offset, bytes, qiov, qiov, flags, true); | |
53 | The simplest secure usage is to provide the secret via a file | ||
54 | |||
55 | - # echo -n "letmein" > mypasswd.txt | ||
56 | + # printf "letmein" > mypasswd.txt | ||
57 | # $QEMU -object secret,id=sec0,file=mypasswd.txt,format=raw | ||
58 | |||
59 | For greater security, AES-256-CBC should be used. To illustrate usage, | ||
60 | @@ -XXX,XX +XXX,XX @@ telling openssl to base64 encode the result, but it could be left | ||
61 | as raw bytes if desired. | ||
62 | |||
63 | @example | ||
64 | - # SECRET=$(echo -n "letmein" | | ||
65 | + # SECRET=$(printf "letmein" | | ||
66 | openssl enc -aes-256-cbc -a -K $KEY -iv $IV) | ||
67 | @end example | ||
68 | |||
69 | diff --git a/tests/multiboot/run_test.sh b/tests/multiboot/run_test.sh | ||
70 | index XXXXXXX..XXXXXXX 100755 | ||
71 | --- a/tests/multiboot/run_test.sh | ||
72 | +++ b/tests/multiboot/run_test.sh | ||
73 | @@ -XXX,XX +XXX,XX @@ run_qemu() { | ||
74 | local kernel=$1 | ||
75 | shift | ||
76 | |||
77 | - echo -e "\n\n=== Running test case: $kernel $@ ===\n" >> test.log | ||
78 | + printf %b "\n\n=== Running test case: $kernel $@ ===\n\n" >> test.log | ||
79 | |||
80 | $QEMU \ | ||
81 | -kernel $kernel \ | ||
82 | @@ -XXX,XX +XXX,XX @@ for t in mmap modules; do | ||
83 | pass=1 | ||
84 | |||
85 | if [ $debugexit != 1 ]; then | ||
86 | - echo -e "\e[31m ?? \e[0m $t (no debugexit used, exit code $ret)" | ||
87 | + printf %b "\e[31m ?? \e[0m $t (no debugexit used, exit code $ret)\n" | ||
88 | pass=0 | ||
89 | elif [ $ret != 0 ]; then | ||
90 | - echo -e "\e[31mFAIL\e[0m $t (exit code $ret)" | ||
91 | + printf %b "\e[31mFAIL\e[0m $t (exit code $ret)\n" | ||
92 | pass=0 | ||
93 | fi | ||
94 | |||
95 | if ! diff $t.out test.log > /dev/null 2>&1; then | ||
96 | - echo -e "\e[31mFAIL\e[0m $t (output difference)" | ||
97 | + printf %b "\e[31mFAIL\e[0m $t (output difference)\n" | ||
98 | diff -u $t.out test.log | ||
99 | pass=0 | ||
100 | fi | ||
101 | |||
102 | if [ $pass == 1 ]; then | ||
103 | - echo -e "\e[32mPASS\e[0m $t" | ||
104 | + printf %b "\e[32mPASS\e[0m $t\n" | ||
105 | fi | ||
106 | |||
107 | done | ||
108 | diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051 | ||
109 | index XXXXXXX..XXXXXXX 100755 | ||
110 | --- a/tests/qemu-iotests/051 | ||
111 | +++ b/tests/qemu-iotests/051 | ||
112 | @@ -XXX,XX +XXX,XX @@ run_qemu -drive driver=null-co,cache=invalid_value | ||
113 | # Test 142 checks the direct=on cases | ||
114 | |||
115 | for cache in writeback writethrough unsafe invalid_value; do | ||
116 | - echo -e "info block\ninfo block file\ninfo block backing\ninfo block backing-file" | \ | ||
117 | + printf "info block %s\n" '' file backing backing-file | \ | ||
118 | run_qemu -drive file="$TEST_IMG",cache=$cache,backing.file.filename="$TEST_IMG.base",backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=$device_id -nodefaults | ||
119 | done | ||
120 | |||
121 | @@ -XXX,XX +XXX,XX @@ echo "qemu-io $device_id \"write -P 0x22 0 4k\"" | run_qemu -drive file="$TEST_I | ||
122 | |||
123 | $QEMU_IO -c "read -P 0x22 0 4k" "$TEST_IMG" | _filter_qemu_io | ||
124 | |||
125 | -echo -e "qemu-io $device_id \"write -P 0x33 0 4k\"\ncommit $device_id" | run_qemu -drive file="$TEST_IMG",snapshot=on,if=none,id=$device_id\ | ||
126 | - | _filter_qemu_io | ||
127 | +printf %b "qemu-io $device_id \"write -P 0x33 0 4k\"\ncommit $device_id\n" | | ||
128 | + run_qemu -drive file="$TEST_IMG",snapshot=on,if=none,id=$device_id | | ||
129 | + _filter_qemu_io | ||
130 | |||
131 | $QEMU_IO -c "read -P 0x33 0 4k" "$TEST_IMG" | _filter_qemu_io | ||
132 | |||
133 | diff --git a/tests/qemu-iotests/068 b/tests/qemu-iotests/068 | ||
134 | index XXXXXXX..XXXXXXX 100755 | ||
135 | --- a/tests/qemu-iotests/068 | ||
136 | +++ b/tests/qemu-iotests/068 | ||
137 | @@ -XXX,XX +XXX,XX @@ for extra_args in \ | ||
138 | _make_test_img $IMG_SIZE | ||
139 | |||
140 | # Give qemu some time to boot before saving the VM state | ||
141 | - bash -c 'sleep 1; echo -e "savevm 0\nquit"' | _qemu $extra_args | ||
142 | + { sleep 1; printf "savevm 0\nquit\n"; } | _qemu $extra_args | ||
143 | # Now try to continue from that VM state (this should just work) | ||
144 | echo quit | _qemu $extra_args -loadvm 0 | ||
145 | done | ||
146 | diff --git a/tests/qemu-iotests/142 b/tests/qemu-iotests/142 | ||
147 | index XXXXXXX..XXXXXXX 100755 | ||
148 | --- a/tests/qemu-iotests/142 | ||
149 | +++ b/tests/qemu-iotests/142 | ||
150 | @@ -XXX,XX +XXX,XX @@ function check_cache_all() | ||
151 | # cache.direct is supposed to be inherited by both bs->file and | ||
152 | # bs->backing | ||
153 | |||
154 | - echo -e "cache.direct=on on none0" | ||
155 | + printf "cache.direct=on on none0\n" | ||
156 | echo "$hmp_cmds" | run_qemu -drive "$files","$ids",cache.direct=on | grep -e "Cache" -e "[Cc]annot|[Cc]ould not|[Cc]an't" | ||
157 | - echo -e "\ncache.direct=on on file" | ||
158 | + printf "\ncache.direct=on on file\n" | ||
159 | echo "$hmp_cmds" | run_qemu -drive "$files","$ids",file.cache.direct=on | grep -e "Cache" -e "[Cc]annot|[Cc]ould not|[Cc]an't" | ||
160 | - echo -e "\ncache.direct=on on backing" | ||
161 | + printf "\ncache.direct=on on backing\n" | ||
162 | echo "$hmp_cmds" | run_qemu -drive "$files","$ids",backing.cache.direct=on | grep -e "Cache" -e "[Cc]annot|[Cc]ould not|[Cc]an't" | ||
163 | - echo -e "\ncache.direct=on on backing-file" | ||
164 | + printf "\ncache.direct=on on backing-file\n" | ||
165 | echo "$hmp_cmds" | run_qemu -drive "$files","$ids",backing.file.cache.direct=on | grep -e "Cache" -e "[Cc]annot|[Cc]ould not|[Cc]an't" | ||
166 | |||
167 | # cache.writeback is supposed to be inherited by bs->backing; bs->file | ||
168 | # always gets cache.writeback=on | ||
169 | |||
170 | - echo -e "\n\ncache.writeback=off on none0" | ||
171 | + printf "\n\ncache.writeback=off on none0\n" | ||
172 | echo "$hmp_cmds" | run_qemu -drive "$files","$ids",cache.writeback=off | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't" | ||
173 | - echo -e "\ncache.writeback=off on file" | ||
174 | + printf "\ncache.writeback=off on file\n" | ||
175 | echo "$hmp_cmds" | run_qemu -drive "$files","$ids",file.cache.writeback=off | grep -e "doesn't" -e "does not" | ||
176 | - echo -e "\ncache.writeback=off on backing" | ||
177 | + printf "\ncache.writeback=off on backing\n" | ||
178 | echo "$hmp_cmds" | run_qemu -drive "$files","$ids",backing.cache.writeback=off | grep -e "doesn't" -e "does not" | ||
179 | - echo -e "\ncache.writeback=off on backing-file" | ||
180 | + printf "\ncache.writeback=off on backing-file\n" | ||
181 | echo "$hmp_cmds" | run_qemu -drive "$files","$ids",backing.file.cache.writeback=off | grep -e "doesn't" -e "does not" | ||
182 | |||
183 | # cache.no-flush is supposed to be inherited by both bs->file and bs->backing | ||
184 | |||
185 | - echo -e "\n\ncache.no-flush=on on none0" | ||
186 | + printf "\n\ncache.no-flush=on on none0\n" | ||
187 | echo "$hmp_cmds" | run_qemu -drive "$files","$ids",cache.no-flush=on | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't" | ||
188 | - echo -e "\ncache.no-flush=on on file" | ||
189 | + printf "\ncache.no-flush=on on file\n" | ||
190 | echo "$hmp_cmds" | run_qemu -drive "$files","$ids",file.cache.no-flush=on | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't" | ||
191 | - echo -e "\ncache.no-flush=on on backing" | ||
192 | + printf "\ncache.no-flush=on on backing\n" | ||
193 | echo "$hmp_cmds" | run_qemu -drive "$files","$ids",backing.cache.no-flush=on | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't" | ||
194 | - echo -e "\ncache.no-flush=on on backing-file" | ||
195 | + printf "\ncache.no-flush=on on backing-file\n" | ||
196 | echo "$hmp_cmds" | run_qemu -drive "$files","$ids",backing.file.cache.no-flush=on | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't" | ||
197 | } | 23 | } |
198 | 24 | ||
199 | @@ -XXX,XX +XXX,XX @@ function check_cache_all_separate() | 25 | -static int blkverify_co_flush(BlockDriverState *bs) |
26 | +static int coroutine_fn blkverify_co_flush(BlockDriverState *bs) | ||
200 | { | 27 | { |
201 | # Check cache.direct | 28 | BDRVBlkverifyState *s = bs->opaque; |
202 | |||
203 | - echo -e "cache.direct=on on blk" | ||
204 | + printf "cache.direct=on on blk\n" | ||
205 | echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk" -drive "$drv_file" -drive "$drv_img",cache.direct=on | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't" | ||
206 | - echo -e "\ncache.direct=on on file" | ||
207 | + printf "\ncache.direct=on on file\n" | ||
208 | echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk" -drive "$drv_file",cache.direct=on -drive "$drv_img" | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't" | ||
209 | - echo -e "\ncache.direct=on on backing" | ||
210 | + printf "\ncache.direct=on on backing\n" | ||
211 | echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk",cache.direct=on -drive "$drv_file" -drive "$drv_img" | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't" | ||
212 | - echo -e "\ncache.direct=on on backing-file" | ||
213 | + printf "\ncache.direct=on on backing-file\n" | ||
214 | echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile",cache.direct=on -drive "$drv_bk" -drive "$drv_file" -drive "$drv_img" | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't" | ||
215 | |||
216 | # Check cache.writeback | ||
217 | |||
218 | - echo -e "\n\ncache.writeback=off on blk" | ||
219 | + printf "\n\ncache.writeback=off on blk\n" | ||
220 | echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk" -drive "$drv_file" -drive "$drv_img",cache.writeback=off | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't" | ||
221 | - echo -e "\ncache.writeback=off on file" | ||
222 | + printf "\ncache.writeback=off on file\n" | ||
223 | echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk" -drive "$drv_file",cache.writeback=off -drive "$drv_img" | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't" | ||
224 | - echo -e "\ncache.writeback=off on backing" | ||
225 | + printf "\ncache.writeback=off on backing\n" | ||
226 | echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk",cache.writeback=off -drive "$drv_file" -drive "$drv_img" | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't" | ||
227 | - echo -e "\ncache.writeback=off on backing-file" | ||
228 | + printf "\ncache.writeback=off on backing-file\n" | ||
229 | echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile",cache.writeback=off -drive "$drv_bk" -drive "$drv_file" -drive "$drv_img" | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't" | ||
230 | |||
231 | # Check cache.no-flush | ||
232 | |||
233 | - echo -e "\n\ncache.no-flush=on on blk" | ||
234 | + printf "\n\ncache.no-flush=on on blk\n" | ||
235 | echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk" -drive "$drv_file" -drive "$drv_img",cache.no-flush=on | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't" | ||
236 | - echo -e "\ncache.no-flush=on on file" | ||
237 | + printf "\ncache.no-flush=on on file\n" | ||
238 | echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk" -drive "$drv_file",cache.no-flush=on -drive "$drv_img" | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't" | ||
239 | - echo -e "\ncache.no-flush=on on backing" | ||
240 | + printf "\ncache.no-flush=on on backing\n" | ||
241 | echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk",cache.no-flush=on -drive "$drv_file" -drive "$drv_img" | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't" | ||
242 | - echo -e "\ncache.no-flush=on on backing-file" | ||
243 | + printf "\ncache.no-flush=on on backing-file\n" | ||
244 | echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile",cache.no-flush=on -drive "$drv_bk" -drive "$drv_file" -drive "$drv_img" | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't" | ||
245 | } | ||
246 | |||
247 | diff --git a/tests/qemu-iotests/171 b/tests/qemu-iotests/171 | ||
248 | index XXXXXXX..XXXXXXX 100755 | ||
249 | --- a/tests/qemu-iotests/171 | ||
250 | +++ b/tests/qemu-iotests/171 | ||
251 | @@ -XXX,XX +XXX,XX @@ _supported_os Linux | ||
252 | |||
253 | # Create JSON with options | ||
254 | img_json() { | ||
255 | - echo -n 'json:{"driver":"raw", ' | ||
256 | - echo -n "\"offset\":\"$img_offset\", " | ||
257 | + printf %s 'json:{"driver":"raw", ' | ||
258 | + printf %s "\"offset\":\"$img_offset\", " | ||
259 | if [ "$img_size" -ne -1 ] ; then | ||
260 | - echo -n "\"size\":\"$img_size\", " | ||
261 | + printf %s "\"size\":\"$img_size\", " | ||
262 | fi | ||
263 | - echo -n '"file": {' | ||
264 | - echo -n '"driver":"file", ' | ||
265 | - echo -n "\"filename\":\"$TEST_IMG\" " | ||
266 | - echo -n "} }" | ||
267 | + printf %s '"file": {' | ||
268 | + printf %s '"driver":"file", ' | ||
269 | + printf %s "\"filename\":\"$TEST_IMG\" " | ||
270 | + printf %s "} }" | ||
271 | } | ||
272 | |||
273 | do_general_test() { | ||
274 | diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check | ||
275 | index XXXXXXX..XXXXXXX 100755 | ||
276 | --- a/tests/qemu-iotests/check | ||
277 | +++ b/tests/qemu-iotests/check | ||
278 | @@ -XXX,XX +XXX,XX @@ _wallclock() | ||
279 | _timestamp() | ||
280 | { | ||
281 | now=`date "+%T"` | ||
282 | - echo -n " [$now]" | ||
283 | + printf %s " [$now]" | ||
284 | } | ||
285 | |||
286 | _wrapup() | ||
287 | @@ -XXX,XX +XXX,XX @@ seq="check" | ||
288 | for seq in $list | ||
289 | do | ||
290 | err=false | ||
291 | - echo -n "$seq" | ||
292 | + printf %s "$seq" | ||
293 | if [ -n "$TESTS_REMAINING_LOG" ] ; then | ||
294 | sed -e "s/$seq//" -e 's/ / /' -e 's/^ *//' $TESTS_REMAINING_LOG > $TESTS_REMAINING_LOG.tmp | ||
295 | mv $TESTS_REMAINING_LOG.tmp $TESTS_REMAINING_LOG | ||
296 | @@ -XXX,XX +XXX,XX @@ do | ||
297 | rm -f $seq.out.bad | ||
298 | lasttime=`sed -n -e "/^$seq /s/.* //p" <$TIMESTAMP_FILE` | ||
299 | if [ "X$lasttime" != X ]; then | ||
300 | - echo -n " ${lasttime}s ..." | ||
301 | + printf %s " ${lasttime}s ..." | ||
302 | else | ||
303 | - echo -n " " # prettier output with timestamps. | ||
304 | + printf " " # prettier output with timestamps. | ||
305 | fi | ||
306 | rm -f core $seq.notrun | ||
307 | |||
308 | @@ -XXX,XX +XXX,XX @@ do | ||
309 | echo "$seq" > "${TEST_DIR}"/check.sts | ||
310 | |||
311 | start=`_wallclock` | ||
312 | - $timestamp && echo -n " ["`date "+%T"`"]" | ||
313 | + $timestamp && printf %s " [$(date "+%T")]" | ||
314 | |||
315 | if [ "$(head -n 1 "$source_iotests/$seq")" == "#!/usr/bin/env python" ]; then | ||
316 | run_command="$PYTHON $seq" | ||
317 | @@ -XXX,XX +XXX,XX @@ do | ||
318 | |||
319 | if [ -f core ] | ||
320 | then | ||
321 | - echo -n " [dumped core]" | ||
322 | + printf " [dumped core]" | ||
323 | mv core $seq.core | ||
324 | err=true | ||
325 | fi | ||
326 | |||
327 | if [ -f $seq.notrun ] | ||
328 | then | ||
329 | - $timestamp || echo -n " [not run] " | ||
330 | - $timestamp && echo " [not run]" && echo -n " $seq -- " | ||
331 | + $timestamp || printf " [not run] " | ||
332 | + $timestamp && echo " [not run]" && printf %s " $seq -- " | ||
333 | cat $seq.notrun | ||
334 | notrun="$notrun $seq" | ||
335 | else | ||
336 | if [ $sts -ne 0 ] | ||
337 | then | ||
338 | - echo -n " [failed, exit status $sts]" | ||
339 | + printf %s " [failed, exit status $sts]" | ||
340 | err=true | ||
341 | fi | ||
342 | |||
343 | diff --git a/tests/rocker/all b/tests/rocker/all | ||
344 | index XXXXXXX..XXXXXXX 100755 | ||
345 | --- a/tests/rocker/all | ||
346 | +++ b/tests/rocker/all | ||
347 | @@ -XXX,XX +XXX,XX @@ | ||
348 | -echo -n "Running port test... " | ||
349 | +printf "Running port test... " | ||
350 | ./port | ||
351 | if [ $? -eq 0 ]; then echo "pass"; else echo "FAILED"; exit 1; fi | ||
352 | |||
353 | -echo -n "Running bridge test... " | ||
354 | +printf "Running bridge test... " | ||
355 | ./bridge | ||
356 | if [ $? -eq 0 ]; then echo "pass"; else echo "FAILED"; exit 1; fi | ||
357 | |||
358 | -echo -n "Running bridge STP test... " | ||
359 | +printf "Running bridge STP test... " | ||
360 | ./bridge-stp | ||
361 | if [ $? -eq 0 ]; then echo "pass"; else echo "FAILED"; exit 1; fi | ||
362 | |||
363 | -echo -n "Running bridge VLAN test... " | ||
364 | +printf "Running bridge VLAN test... " | ||
365 | ./bridge-vlan | ||
366 | if [ $? -eq 0 ]; then echo "pass"; else echo "FAILED"; exit 1; fi | ||
367 | |||
368 | -echo -n "Running bridge VLAN STP test... " | ||
369 | +printf "Running bridge VLAN STP test... " | ||
370 | ./bridge-vlan-stp | ||
371 | if [ $? -eq 0 ]; then echo "pass"; else echo "FAILED"; exit 1; fi | ||
372 | diff --git a/tests/tcg/cris/Makefile b/tests/tcg/cris/Makefile | ||
373 | index XXXXXXX..XXXXXXX 100644 | ||
374 | --- a/tests/tcg/cris/Makefile | ||
375 | +++ b/tests/tcg/cris/Makefile | ||
376 | @@ -XXX,XX +XXX,XX @@ check_addcv17.tst: crtv10.o sysv10.o | ||
377 | build: $(CRT) $(SYS) $(TESTCASES) | ||
378 | |||
379 | check: $(CRT) $(SYS) $(TESTCASES) | ||
380 | - @echo -e "\nQEMU simulator." | ||
381 | + @printf "\nQEMU simulator.\n" | ||
382 | for case in $(TESTCASES); do \ | ||
383 | - echo -n "$$case "; \ | ||
384 | + printf %s "$$case "; \ | ||
385 | SIMARGS=; \ | ||
386 | case $$case in *v17*) SIMARGS="-cpu crisv17";; esac; \ | ||
387 | $(SIM) $$SIMARGS ./$$case; \ | ||
388 | done | ||
389 | check-g: $(CRT) $(SYS) $(TESTCASES) | ||
390 | - @echo -e "\nGDB simulator." | ||
391 | + @printf "\nGDB simulator.\n" | ||
392 | @for case in $(TESTCASES); do \ | ||
393 | - echo -n "$$case "; \ | ||
394 | + printf %s "$$case "; \ | ||
395 | $(SIMG) $$case; \ | ||
396 | done | ||
397 | 29 | ||
398 | -- | 30 | -- |
399 | 1.8.3.1 | 31 | 2.37.3 |
400 | |||
401 | diff view generated by jsdifflib |
1 | From: Eric Blake <eblake@redhat.com> | 1 | From: Paolo Bonzini <pbonzini@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | We are gradually converting to byte-based interfaces, as they are | 3 | Callers of coroutine_fn must be coroutine_fn themselves, or the call |
4 | easier to reason about than sector-based. Change the internal | 4 | must be within "if (qemu_in_coroutine())". Apply coroutine_fn to |
5 | loop iteration of committing to track by bytes instead of sectors | 5 | functions where this holds. |
6 | (although we are still guaranteed that we iterate by steps that | ||
7 | are sector-aligned). | ||
8 | 6 | ||
9 | Signed-off-by: Eric Blake <eblake@redhat.com> | 7 | Reviewed-by: Alberto Faria <afaria@redhat.com> |
10 | Reviewed-by: John Snow <jsnow@redhat.com> | 8 | Reviewed-by: Eric Blake <eblake@redhat.com> |
11 | Reviewed-by: Jeff Cody <jcody@redhat.com> | 9 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
10 | Message-Id: <20220922084924.201610-9-pbonzini@redhat.com> | ||
12 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | 11 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> |
13 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
14 | --- | 13 | --- |
15 | block/commit.c | 16 ++++++---------- | 14 | block/file-posix.c | 2 +- |
16 | 1 file changed, 6 insertions(+), 10 deletions(-) | 15 | 1 file changed, 1 insertion(+), 1 deletion(-) |
17 | 16 | ||
18 | diff --git a/block/commit.c b/block/commit.c | 17 | diff --git a/block/file-posix.c b/block/file-posix.c |
19 | index XXXXXXX..XXXXXXX 100644 | 18 | index XXXXXXX..XXXXXXX 100644 |
20 | --- a/block/commit.c | 19 | --- a/block/file-posix.c |
21 | +++ b/block/commit.c | 20 | +++ b/block/file-posix.c |
22 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn commit_run(void *opaque) | 21 | @@ -XXX,XX +XXX,XX @@ static void raw_aio_unplug(BlockDriverState *bs) |
22 | #endif | ||
23 | } | ||
24 | |||
25 | -static int raw_co_flush_to_disk(BlockDriverState *bs) | ||
26 | +static int coroutine_fn raw_co_flush_to_disk(BlockDriverState *bs) | ||
23 | { | 27 | { |
24 | CommitBlockJob *s = opaque; | 28 | BDRVRawState *s = bs->opaque; |
25 | CommitCompleteData *data; | 29 | RawPosixAIOData acb; |
26 | - int64_t sector_num, end; | ||
27 | + int64_t offset; | ||
28 | uint64_t delay_ns = 0; | ||
29 | int ret = 0; | ||
30 | - int n = 0; | ||
31 | + int n = 0; /* sectors */ | ||
32 | void *buf = NULL; | ||
33 | int bytes_written = 0; | ||
34 | int64_t base_len; | ||
35 | |||
36 | ret = s->common.len = blk_getlength(s->top); | ||
37 | |||
38 | - | ||
39 | if (s->common.len < 0) { | ||
40 | goto out; | ||
41 | } | ||
42 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn commit_run(void *opaque) | ||
43 | } | ||
44 | } | ||
45 | |||
46 | - end = s->common.len >> BDRV_SECTOR_BITS; | ||
47 | buf = blk_blockalign(s->top, COMMIT_BUFFER_SIZE); | ||
48 | |||
49 | - for (sector_num = 0; sector_num < end; sector_num += n) { | ||
50 | + for (offset = 0; offset < s->common.len; offset += n * BDRV_SECTOR_SIZE) { | ||
51 | bool copy; | ||
52 | |||
53 | /* Note that even when no rate limit is applied we need to yield | ||
54 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn commit_run(void *opaque) | ||
55 | } | ||
56 | /* Copy if allocated above the base */ | ||
57 | ret = bdrv_is_allocated_above(blk_bs(s->top), blk_bs(s->base), | ||
58 | - sector_num, | ||
59 | + offset / BDRV_SECTOR_SIZE, | ||
60 | COMMIT_BUFFER_SIZE / BDRV_SECTOR_SIZE, | ||
61 | &n); | ||
62 | copy = (ret == 1); | ||
63 | - trace_commit_one_iteration(s, sector_num * BDRV_SECTOR_SIZE, | ||
64 | - n * BDRV_SECTOR_SIZE, ret); | ||
65 | + trace_commit_one_iteration(s, offset, n * BDRV_SECTOR_SIZE, ret); | ||
66 | if (copy) { | ||
67 | - ret = commit_populate(s->top, s->base, | ||
68 | - sector_num * BDRV_SECTOR_SIZE, | ||
69 | + ret = commit_populate(s->top, s->base, offset, | ||
70 | n * BDRV_SECTOR_SIZE, buf); | ||
71 | bytes_written += n * BDRV_SECTOR_SIZE; | ||
72 | } | ||
73 | -- | 30 | -- |
74 | 1.8.3.1 | 31 | 2.37.3 |
75 | |||
76 | diff view generated by jsdifflib |
1 | From: Eric Blake <eblake@redhat.com> | 1 | From: Paolo Bonzini <pbonzini@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | We are gradually converting to byte-based interfaces, as they are | 3 | Callers of coroutine_fn must be coroutine_fn themselves, or the call |
4 | easier to reason about than sector-based. Continue by converting an | 4 | must be within "if (qemu_in_coroutine())". Apply coroutine_fn to |
5 | internal structure (no semantic change), and all references to the | 5 | functions where this holds. |
6 | buffer size. | ||
7 | 6 | ||
8 | Add an assertion that our use of s->granularity >> BDRV_SECTOR_BITS | 7 | Reviewed-by: Alberto Faria <afaria@redhat.com> |
9 | (necessary for interaction with sector-based dirty bitmaps, until | 8 | Reviewed-by: Eric Blake <eblake@redhat.com> |
10 | a later patch converts those to be byte-based) does not suffer from | 9 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
11 | truncation problems. | 10 | Message-Id: <20220922084924.201610-10-pbonzini@redhat.com> |
12 | 11 | [kwolf: Fixed up coding style] | |
13 | [checkpatch has a false positive on use of MIN() in this patch] | ||
14 | |||
15 | Signed-off-by: Eric Blake <eblake@redhat.com> | ||
16 | Reviewed-by: John Snow <jsnow@redhat.com> | ||
17 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | 12 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> |
18 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 13 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
19 | --- | 14 | --- |
20 | block/mirror.c | 84 +++++++++++++++++++++++++++++----------------------------- | 15 | block/iscsi.c | 3 ++- |
21 | 1 file changed, 42 insertions(+), 42 deletions(-) | 16 | 1 file changed, 2 insertions(+), 1 deletion(-) |
22 | 17 | ||
23 | diff --git a/block/mirror.c b/block/mirror.c | 18 | diff --git a/block/iscsi.c b/block/iscsi.c |
24 | index XXXXXXX..XXXXXXX 100644 | 19 | index XXXXXXX..XXXXXXX 100644 |
25 | --- a/block/mirror.c | 20 | --- a/block/iscsi.c |
26 | +++ b/block/mirror.c | 21 | +++ b/block/iscsi.c |
27 | @@ -XXX,XX +XXX,XX @@ | 22 | @@ -XXX,XX +XXX,XX @@ iscsi_co_generic_cb(struct iscsi_context *iscsi, int status, |
28 | |||
29 | #define SLICE_TIME 100000000ULL /* ns */ | ||
30 | #define MAX_IN_FLIGHT 16 | ||
31 | -#define MAX_IO_SECTORS ((1 << 20) >> BDRV_SECTOR_BITS) /* 1 Mb */ | ||
32 | -#define DEFAULT_MIRROR_BUF_SIZE \ | ||
33 | - (MAX_IN_FLIGHT * MAX_IO_SECTORS * BDRV_SECTOR_SIZE) | ||
34 | +#define MAX_IO_BYTES (1 << 20) /* 1 Mb */ | ||
35 | +#define DEFAULT_MIRROR_BUF_SIZE (MAX_IN_FLIGHT * MAX_IO_BYTES) | ||
36 | |||
37 | /* The mirroring buffer is a list of granularity-sized chunks. | ||
38 | * Free chunks are organized in a list. | ||
39 | @@ -XXX,XX +XXX,XX @@ typedef struct MirrorBlockJob { | ||
40 | uint64_t last_pause_ns; | ||
41 | unsigned long *in_flight_bitmap; | ||
42 | int in_flight; | ||
43 | - int64_t sectors_in_flight; | ||
44 | + int64_t bytes_in_flight; | ||
45 | int ret; | ||
46 | bool unmap; | ||
47 | bool waiting_for_io; | ||
48 | - int target_cluster_sectors; | ||
49 | + int target_cluster_size; | ||
50 | int max_iov; | ||
51 | bool initial_zeroing_ongoing; | ||
52 | } MirrorBlockJob; | ||
53 | @@ -XXX,XX +XXX,XX @@ typedef struct MirrorBlockJob { | ||
54 | typedef struct MirrorOp { | ||
55 | MirrorBlockJob *s; | ||
56 | QEMUIOVector qiov; | ||
57 | - int64_t sector_num; | ||
58 | - int nb_sectors; | ||
59 | + int64_t offset; | ||
60 | + uint64_t bytes; | ||
61 | } MirrorOp; | ||
62 | |||
63 | static BlockErrorAction mirror_error_action(MirrorBlockJob *s, bool read, | ||
64 | @@ -XXX,XX +XXX,XX @@ static void mirror_iteration_done(MirrorOp *op, int ret) | ||
65 | MirrorBlockJob *s = op->s; | ||
66 | struct iovec *iov; | ||
67 | int64_t chunk_num; | ||
68 | - int i, nb_chunks, sectors_per_chunk; | ||
69 | + int i, nb_chunks; | ||
70 | |||
71 | - trace_mirror_iteration_done(s, op->sector_num * BDRV_SECTOR_SIZE, | ||
72 | - op->nb_sectors * BDRV_SECTOR_SIZE, ret); | ||
73 | + trace_mirror_iteration_done(s, op->offset, op->bytes, ret); | ||
74 | |||
75 | s->in_flight--; | ||
76 | - s->sectors_in_flight -= op->nb_sectors; | ||
77 | + s->bytes_in_flight -= op->bytes; | ||
78 | iov = op->qiov.iov; | ||
79 | for (i = 0; i < op->qiov.niov; i++) { | ||
80 | MirrorBuffer *buf = (MirrorBuffer *) iov[i].iov_base; | ||
81 | @@ -XXX,XX +XXX,XX @@ static void mirror_iteration_done(MirrorOp *op, int ret) | ||
82 | s->buf_free_count++; | ||
83 | } | ||
84 | |||
85 | - sectors_per_chunk = s->granularity >> BDRV_SECTOR_BITS; | ||
86 | - chunk_num = op->sector_num / sectors_per_chunk; | ||
87 | - nb_chunks = DIV_ROUND_UP(op->nb_sectors, sectors_per_chunk); | ||
88 | + chunk_num = op->offset / s->granularity; | ||
89 | + nb_chunks = DIV_ROUND_UP(op->bytes, s->granularity); | ||
90 | bitmap_clear(s->in_flight_bitmap, chunk_num, nb_chunks); | ||
91 | if (ret >= 0) { | ||
92 | if (s->cow_bitmap) { | ||
93 | bitmap_set(s->cow_bitmap, chunk_num, nb_chunks); | ||
94 | } | ||
95 | if (!s->initial_zeroing_ongoing) { | ||
96 | - s->common.offset += (uint64_t)op->nb_sectors * BDRV_SECTOR_SIZE; | ||
97 | + s->common.offset += op->bytes; | ||
98 | } | ||
99 | } | ||
100 | qemu_iovec_destroy(&op->qiov); | ||
101 | @@ -XXX,XX +XXX,XX @@ static void mirror_write_complete(void *opaque, int ret) | ||
102 | if (ret < 0) { | ||
103 | BlockErrorAction action; | ||
104 | |||
105 | - bdrv_set_dirty_bitmap(s->dirty_bitmap, op->sector_num, op->nb_sectors); | ||
106 | + bdrv_set_dirty_bitmap(s->dirty_bitmap, op->offset >> BDRV_SECTOR_BITS, | ||
107 | + op->bytes >> BDRV_SECTOR_BITS); | ||
108 | action = mirror_error_action(s, false, -ret); | ||
109 | if (action == BLOCK_ERROR_ACTION_REPORT && s->ret >= 0) { | ||
110 | s->ret = ret; | ||
111 | @@ -XXX,XX +XXX,XX @@ static void mirror_read_complete(void *opaque, int ret) | ||
112 | if (ret < 0) { | ||
113 | BlockErrorAction action; | ||
114 | |||
115 | - bdrv_set_dirty_bitmap(s->dirty_bitmap, op->sector_num, op->nb_sectors); | ||
116 | + bdrv_set_dirty_bitmap(s->dirty_bitmap, op->offset >> BDRV_SECTOR_BITS, | ||
117 | + op->bytes >> BDRV_SECTOR_BITS); | ||
118 | action = mirror_error_action(s, true, -ret); | ||
119 | if (action == BLOCK_ERROR_ACTION_REPORT && s->ret >= 0) { | ||
120 | s->ret = ret; | ||
121 | @@ -XXX,XX +XXX,XX @@ static void mirror_read_complete(void *opaque, int ret) | ||
122 | |||
123 | mirror_iteration_done(op, ret); | ||
124 | } else { | ||
125 | - blk_aio_pwritev(s->target, op->sector_num * BDRV_SECTOR_SIZE, &op->qiov, | ||
126 | + blk_aio_pwritev(s->target, op->offset, &op->qiov, | ||
127 | 0, mirror_write_complete, op); | ||
128 | } | ||
129 | aio_context_release(blk_get_aio_context(s->common.blk)); | ||
130 | @@ -XXX,XX +XXX,XX @@ static int mirror_cow_align(MirrorBlockJob *s, | ||
131 | align_nb_sectors = max_sectors; | ||
132 | if (need_cow) { | ||
133 | align_nb_sectors = QEMU_ALIGN_DOWN(align_nb_sectors, | ||
134 | - s->target_cluster_sectors); | ||
135 | + s->target_cluster_size >> | ||
136 | + BDRV_SECTOR_BITS); | ||
137 | } | ||
138 | } | ||
139 | /* Clipping may result in align_nb_sectors unaligned to chunk boundary, but | ||
140 | @@ -XXX,XX +XXX,XX @@ static int mirror_do_read(MirrorBlockJob *s, int64_t sector_num, | ||
141 | /* Allocate a MirrorOp that is used as an AIO callback. */ | ||
142 | op = g_new(MirrorOp, 1); | ||
143 | op->s = s; | ||
144 | - op->sector_num = sector_num; | ||
145 | - op->nb_sectors = nb_sectors; | ||
146 | + op->offset = sector_num * BDRV_SECTOR_SIZE; | ||
147 | + op->bytes = nb_sectors * BDRV_SECTOR_SIZE; | ||
148 | |||
149 | /* Now make a QEMUIOVector taking enough granularity-sized chunks | ||
150 | * from s->buf_free. | ||
151 | @@ -XXX,XX +XXX,XX @@ static int mirror_do_read(MirrorBlockJob *s, int64_t sector_num, | ||
152 | |||
153 | /* Copy the dirty cluster. */ | ||
154 | s->in_flight++; | ||
155 | - s->sectors_in_flight += nb_sectors; | ||
156 | + s->bytes_in_flight += nb_sectors * BDRV_SECTOR_SIZE; | ||
157 | trace_mirror_one_iteration(s, sector_num * BDRV_SECTOR_SIZE, | ||
158 | nb_sectors * BDRV_SECTOR_SIZE); | ||
159 | |||
160 | @@ -XXX,XX +XXX,XX @@ static void mirror_do_zero_or_discard(MirrorBlockJob *s, | ||
161 | * so the freeing in mirror_iteration_done is nop. */ | ||
162 | op = g_new0(MirrorOp, 1); | ||
163 | op->s = s; | ||
164 | - op->sector_num = sector_num; | ||
165 | - op->nb_sectors = nb_sectors; | ||
166 | + op->offset = sector_num * BDRV_SECTOR_SIZE; | ||
167 | + op->bytes = nb_sectors * BDRV_SECTOR_SIZE; | ||
168 | |||
169 | s->in_flight++; | ||
170 | - s->sectors_in_flight += nb_sectors; | ||
171 | + s->bytes_in_flight += nb_sectors * BDRV_SECTOR_SIZE; | ||
172 | if (is_discard) { | ||
173 | blk_aio_pdiscard(s->target, sector_num << BDRV_SECTOR_BITS, | ||
174 | - op->nb_sectors << BDRV_SECTOR_BITS, | ||
175 | - mirror_write_complete, op); | ||
176 | + op->bytes, mirror_write_complete, op); | ||
177 | } else { | ||
178 | blk_aio_pwrite_zeroes(s->target, sector_num * BDRV_SECTOR_SIZE, | ||
179 | - op->nb_sectors * BDRV_SECTOR_SIZE, | ||
180 | - s->unmap ? BDRV_REQ_MAY_UNMAP : 0, | ||
181 | + op->bytes, s->unmap ? BDRV_REQ_MAY_UNMAP : 0, | ||
182 | mirror_write_complete, op); | ||
183 | } | 23 | } |
184 | } | 24 | } |
185 | @@ -XXX,XX +XXX,XX @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s) | 25 | |
186 | int64_t end = s->bdev_length / BDRV_SECTOR_SIZE; | 26 | -static void iscsi_co_init_iscsitask(IscsiLun *iscsilun, struct IscsiTask *iTask) |
187 | int sectors_per_chunk = s->granularity >> BDRV_SECTOR_BITS; | 27 | +static void coroutine_fn |
188 | bool write_zeroes_ok = bdrv_can_write_zeroes_with_unmap(blk_bs(s->target)); | 28 | +iscsi_co_init_iscsitask(IscsiLun *iscsilun, struct IscsiTask *iTask) |
189 | - int max_io_sectors = MAX((s->buf_size >> BDRV_SECTOR_BITS) / MAX_IN_FLIGHT, | 29 | { |
190 | - MAX_IO_SECTORS); | 30 | *iTask = (struct IscsiTask) { |
191 | + int max_io_bytes = MAX(s->buf_size / MAX_IN_FLIGHT, MAX_IO_BYTES); | 31 | .co = qemu_coroutine_self(), |
192 | |||
193 | bdrv_dirty_bitmap_lock(s->dirty_bitmap); | ||
194 | sector_num = bdrv_dirty_iter_next(s->dbi); | ||
195 | @@ -XXX,XX +XXX,XX @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s) | ||
196 | nb_chunks * sectors_per_chunk, | ||
197 | &io_sectors, &file); | ||
198 | if (ret < 0) { | ||
199 | - io_sectors = MIN(nb_chunks * sectors_per_chunk, max_io_sectors); | ||
200 | + io_sectors = MIN(nb_chunks * sectors_per_chunk, | ||
201 | + max_io_bytes >> BDRV_SECTOR_BITS); | ||
202 | } else if (ret & BDRV_BLOCK_DATA) { | ||
203 | - io_sectors = MIN(io_sectors, max_io_sectors); | ||
204 | + io_sectors = MIN(io_sectors, max_io_bytes >> BDRV_SECTOR_BITS); | ||
205 | } | ||
206 | |||
207 | io_sectors -= io_sectors % sectors_per_chunk; | ||
208 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn mirror_run(void *opaque) | ||
209 | char backing_filename[2]; /* we only need 2 characters because we are only | ||
210 | checking for a NULL string */ | ||
211 | int ret = 0; | ||
212 | - int target_cluster_size = BDRV_SECTOR_SIZE; | ||
213 | |||
214 | if (block_job_is_cancelled(&s->common)) { | ||
215 | goto immediate_exit; | ||
216 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn mirror_run(void *opaque) | ||
217 | bdrv_get_backing_filename(target_bs, backing_filename, | ||
218 | sizeof(backing_filename)); | ||
219 | if (!bdrv_get_info(target_bs, &bdi) && bdi.cluster_size) { | ||
220 | - target_cluster_size = bdi.cluster_size; | ||
221 | + s->target_cluster_size = bdi.cluster_size; | ||
222 | + } else { | ||
223 | + s->target_cluster_size = BDRV_SECTOR_SIZE; | ||
224 | } | ||
225 | - if (backing_filename[0] && !target_bs->backing | ||
226 | - && s->granularity < target_cluster_size) { | ||
227 | - s->buf_size = MAX(s->buf_size, target_cluster_size); | ||
228 | + if (backing_filename[0] && !target_bs->backing && | ||
229 | + s->granularity < s->target_cluster_size) { | ||
230 | + s->buf_size = MAX(s->buf_size, s->target_cluster_size); | ||
231 | s->cow_bitmap = bitmap_new(length); | ||
232 | } | ||
233 | - s->target_cluster_sectors = target_cluster_size >> BDRV_SECTOR_BITS; | ||
234 | s->max_iov = MIN(bs->bl.max_iov, target_bs->bl.max_iov); | ||
235 | |||
236 | s->buf = qemu_try_blockalign(bs, s->buf_size); | ||
237 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn mirror_run(void *opaque) | ||
238 | cnt = bdrv_get_dirty_count(s->dirty_bitmap); | ||
239 | /* s->common.offset contains the number of bytes already processed so | ||
240 | * far, cnt is the number of dirty sectors remaining and | ||
241 | - * s->sectors_in_flight is the number of sectors currently being | ||
242 | + * s->bytes_in_flight is the number of bytes currently being | ||
243 | * processed; together those are the current total operation length */ | ||
244 | - s->common.len = s->common.offset + | ||
245 | - (cnt + s->sectors_in_flight) * BDRV_SECTOR_SIZE; | ||
246 | + s->common.len = s->common.offset + s->bytes_in_flight + | ||
247 | + cnt * BDRV_SECTOR_SIZE; | ||
248 | |||
249 | /* Note that even when no rate limit is applied we need to yield | ||
250 | * periodically with no pending I/O so that bdrv_drain_all() returns. | ||
251 | @@ -XXX,XX +XXX,XX @@ static void mirror_start_job(const char *job_id, BlockDriverState *bs, | ||
252 | } | ||
253 | |||
254 | assert ((granularity & (granularity - 1)) == 0); | ||
255 | + /* Granularity must be large enough for sector-based dirty bitmap */ | ||
256 | + assert(granularity >= BDRV_SECTOR_SIZE); | ||
257 | |||
258 | if (buf_size < 0) { | ||
259 | error_setg(errp, "Invalid parameter 'buf-size'"); | ||
260 | -- | 32 | -- |
261 | 1.8.3.1 | 33 | 2.37.3 |
262 | |||
263 | diff view generated by jsdifflib |
1 | From: Eric Blake <eblake@redhat.com> | 1 | From: Paolo Bonzini <pbonzini@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | We are gradually converting to byte-based interfaces, as they are | 3 | Callers of coroutine_fn must be coroutine_fn themselves, or the call |
4 | easier to reason about than sector-based. Start by converting an | 4 | must be within "if (qemu_in_coroutine())". Apply coroutine_fn to |
5 | internal function (no semantic change). | 5 | functions where this holds. |
6 | 6 | ||
7 | Signed-off-by: Eric Blake <eblake@redhat.com> | 7 | Reviewed-by: Alberto Faria <afaria@redhat.com> |
8 | Reviewed-by: John Snow <jsnow@redhat.com> | 8 | Reviewed-by: Eric Blake <eblake@redhat.com> |
9 | Reviewed-by: Jeff Cody <jcody@redhat.com> | 9 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
10 | Message-Id: <20220922084924.201610-11-pbonzini@redhat.com> | ||
11 | [kwolf: Fixed up coding style] | ||
10 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | 12 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> |
11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 13 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
12 | --- | 14 | --- |
13 | block/stream.c | 11 ++++++----- | 15 | block/nbd.c | 11 ++++++----- |
14 | 1 file changed, 6 insertions(+), 5 deletions(-) | 16 | 1 file changed, 6 insertions(+), 5 deletions(-) |
15 | 17 | ||
16 | diff --git a/block/stream.c b/block/stream.c | 18 | diff --git a/block/nbd.c b/block/nbd.c |
17 | index XXXXXXX..XXXXXXX 100644 | 19 | index XXXXXXX..XXXXXXX 100644 |
18 | --- a/block/stream.c | 20 | --- a/block/nbd.c |
19 | +++ b/block/stream.c | 21 | +++ b/block/nbd.c |
20 | @@ -XXX,XX +XXX,XX @@ typedef struct StreamBlockJob { | 22 | @@ -XXX,XX +XXX,XX @@ static void nbd_iter_request_error(NBDReplyChunkIter *iter, int ret) |
21 | } StreamBlockJob; | 23 | * nbd_reply_chunk_iter_receive |
22 | 24 | * The pointer stored in @payload requires g_free() to free it. | |
23 | static int coroutine_fn stream_populate(BlockBackend *blk, | 25 | */ |
24 | - int64_t sector_num, int nb_sectors, | 26 | -static bool nbd_reply_chunk_iter_receive(BDRVNBDState *s, |
25 | + int64_t offset, uint64_t bytes, | 27 | - NBDReplyChunkIter *iter, |
26 | void *buf) | 28 | - uint64_t handle, |
29 | - QEMUIOVector *qiov, NBDReply *reply, | ||
30 | - void **payload) | ||
31 | +static bool coroutine_fn nbd_reply_chunk_iter_receive(BDRVNBDState *s, | ||
32 | + NBDReplyChunkIter *iter, | ||
33 | + uint64_t handle, | ||
34 | + QEMUIOVector *qiov, | ||
35 | + NBDReply *reply, | ||
36 | + void **payload) | ||
27 | { | 37 | { |
28 | struct iovec iov = { | 38 | int ret, request_ret; |
29 | .iov_base = buf, | 39 | NBDReply local_reply; |
30 | - .iov_len = nb_sectors * BDRV_SECTOR_SIZE, | ||
31 | + .iov_len = bytes, | ||
32 | }; | ||
33 | QEMUIOVector qiov; | ||
34 | |||
35 | + assert(bytes < SIZE_MAX); | ||
36 | qemu_iovec_init_external(&qiov, &iov, 1); | ||
37 | |||
38 | /* Copy-on-read the unallocated clusters */ | ||
39 | - return blk_co_preadv(blk, sector_num * BDRV_SECTOR_SIZE, qiov.size, &qiov, | ||
40 | - BDRV_REQ_COPY_ON_READ); | ||
41 | + return blk_co_preadv(blk, offset, qiov.size, &qiov, BDRV_REQ_COPY_ON_READ); | ||
42 | } | ||
43 | |||
44 | typedef struct { | ||
45 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn stream_run(void *opaque) | ||
46 | trace_stream_one_iteration(s, sector_num * BDRV_SECTOR_SIZE, | ||
47 | n * BDRV_SECTOR_SIZE, ret); | ||
48 | if (copy) { | ||
49 | - ret = stream_populate(blk, sector_num, n, buf); | ||
50 | + ret = stream_populate(blk, sector_num * BDRV_SECTOR_SIZE, | ||
51 | + n * BDRV_SECTOR_SIZE, buf); | ||
52 | } | ||
53 | if (ret < 0) { | ||
54 | BlockErrorAction action = | ||
55 | -- | 40 | -- |
56 | 1.8.3.1 | 41 | 2.37.3 |
57 | |||
58 | diff view generated by jsdifflib |
1 | From: Eric Blake <eblake@redhat.com> | 1 | From: Paolo Bonzini <pbonzini@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | We are gradually converting to byte-based interfaces, as they are | 3 | Callers of coroutine_fn must be coroutine_fn themselves, or the call |
4 | easier to reason about than sector-based. Convert another internal | 4 | must be within "if (qemu_in_coroutine())". Apply coroutine_fn to |
5 | function (no semantic change). | 5 | functions where this holds. |
6 | 6 | ||
7 | Signed-off-by: Eric Blake <eblake@redhat.com> | 7 | Reviewed-by: Alberto Faria <afaria@redhat.com> |
8 | Reviewed-by: John Snow <jsnow@redhat.com> | 8 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
9 | Reviewed-by: Jeff Cody <jcody@redhat.com> | 9 | Message-Id: <20220922084924.201610-12-pbonzini@redhat.com> |
10 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | 10 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> |
11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
12 | --- | 12 | --- |
13 | block/backup.c | 62 ++++++++++++++++++++++++---------------------------------- | 13 | block/nfs.c | 2 +- |
14 | 1 file changed, 26 insertions(+), 36 deletions(-) | 14 | 1 file changed, 1 insertion(+), 1 deletion(-) |
15 | 15 | ||
16 | diff --git a/block/backup.c b/block/backup.c | 16 | diff --git a/block/nfs.c b/block/nfs.c |
17 | index XXXXXXX..XXXXXXX 100644 | 17 | index XXXXXXX..XXXXXXX 100644 |
18 | --- a/block/backup.c | 18 | --- a/block/nfs.c |
19 | +++ b/block/backup.c | 19 | +++ b/block/nfs.c |
20 | @@ -XXX,XX +XXX,XX @@ static void cow_request_end(CowRequest *req) | 20 | @@ -XXX,XX +XXX,XX @@ static void nfs_process_write(void *arg) |
21 | qemu_mutex_unlock(&client->mutex); | ||
21 | } | 22 | } |
22 | 23 | ||
23 | static int coroutine_fn backup_do_cow(BackupBlockJob *job, | 24 | -static void nfs_co_init_task(BlockDriverState *bs, NFSRPC *task) |
24 | - int64_t sector_num, int nb_sectors, | 25 | +static void coroutine_fn nfs_co_init_task(BlockDriverState *bs, NFSRPC *task) |
25 | + int64_t offset, uint64_t bytes, | ||
26 | bool *error_is_read, | ||
27 | bool is_write_notifier) | ||
28 | { | 26 | { |
29 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_do_cow(BackupBlockJob *job, | 27 | *task = (NFSRPC) { |
30 | QEMUIOVector bounce_qiov; | 28 | .co = qemu_coroutine_self(), |
31 | void *bounce_buffer = NULL; | ||
32 | int ret = 0; | ||
33 | - int64_t sectors_per_cluster = cluster_size_sectors(job); | ||
34 | - int64_t start, end; /* clusters */ | ||
35 | + int64_t start, end; /* bytes */ | ||
36 | int n; /* bytes */ | ||
37 | |||
38 | qemu_co_rwlock_rdlock(&job->flush_rwlock); | ||
39 | |||
40 | - start = sector_num / sectors_per_cluster; | ||
41 | - end = DIV_ROUND_UP(sector_num + nb_sectors, sectors_per_cluster); | ||
42 | + start = QEMU_ALIGN_DOWN(offset, job->cluster_size); | ||
43 | + end = QEMU_ALIGN_UP(bytes + offset, job->cluster_size); | ||
44 | |||
45 | - trace_backup_do_cow_enter(job, start * job->cluster_size, | ||
46 | - sector_num * BDRV_SECTOR_SIZE, | ||
47 | - nb_sectors * BDRV_SECTOR_SIZE); | ||
48 | + trace_backup_do_cow_enter(job, start, offset, bytes); | ||
49 | |||
50 | - wait_for_overlapping_requests(job, start * job->cluster_size, | ||
51 | - end * job->cluster_size); | ||
52 | - cow_request_begin(&cow_request, job, start * job->cluster_size, | ||
53 | - end * job->cluster_size); | ||
54 | + wait_for_overlapping_requests(job, start, end); | ||
55 | + cow_request_begin(&cow_request, job, start, end); | ||
56 | |||
57 | - for (; start < end; start++) { | ||
58 | - if (test_bit(start, job->done_bitmap)) { | ||
59 | - trace_backup_do_cow_skip(job, start * job->cluster_size); | ||
60 | + for (; start < end; start += job->cluster_size) { | ||
61 | + if (test_bit(start / job->cluster_size, job->done_bitmap)) { | ||
62 | + trace_backup_do_cow_skip(job, start); | ||
63 | continue; /* already copied */ | ||
64 | } | ||
65 | |||
66 | - trace_backup_do_cow_process(job, start * job->cluster_size); | ||
67 | + trace_backup_do_cow_process(job, start); | ||
68 | |||
69 | - n = MIN(job->cluster_size, | ||
70 | - job->common.len - start * job->cluster_size); | ||
71 | + n = MIN(job->cluster_size, job->common.len - start); | ||
72 | |||
73 | if (!bounce_buffer) { | ||
74 | bounce_buffer = blk_blockalign(blk, job->cluster_size); | ||
75 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_do_cow(BackupBlockJob *job, | ||
76 | iov.iov_len = n; | ||
77 | qemu_iovec_init_external(&bounce_qiov, &iov, 1); | ||
78 | |||
79 | - ret = blk_co_preadv(blk, start * job->cluster_size, | ||
80 | - bounce_qiov.size, &bounce_qiov, | ||
81 | + ret = blk_co_preadv(blk, start, bounce_qiov.size, &bounce_qiov, | ||
82 | is_write_notifier ? BDRV_REQ_NO_SERIALISING : 0); | ||
83 | if (ret < 0) { | ||
84 | - trace_backup_do_cow_read_fail(job, start * job->cluster_size, ret); | ||
85 | + trace_backup_do_cow_read_fail(job, start, ret); | ||
86 | if (error_is_read) { | ||
87 | *error_is_read = true; | ||
88 | } | ||
89 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_do_cow(BackupBlockJob *job, | ||
90 | } | ||
91 | |||
92 | if (buffer_is_zero(iov.iov_base, iov.iov_len)) { | ||
93 | - ret = blk_co_pwrite_zeroes(job->target, start * job->cluster_size, | ||
94 | + ret = blk_co_pwrite_zeroes(job->target, start, | ||
95 | bounce_qiov.size, BDRV_REQ_MAY_UNMAP); | ||
96 | } else { | ||
97 | - ret = blk_co_pwritev(job->target, start * job->cluster_size, | ||
98 | + ret = blk_co_pwritev(job->target, start, | ||
99 | bounce_qiov.size, &bounce_qiov, | ||
100 | job->compress ? BDRV_REQ_WRITE_COMPRESSED : 0); | ||
101 | } | ||
102 | if (ret < 0) { | ||
103 | - trace_backup_do_cow_write_fail(job, start * job->cluster_size, ret); | ||
104 | + trace_backup_do_cow_write_fail(job, start, ret); | ||
105 | if (error_is_read) { | ||
106 | *error_is_read = false; | ||
107 | } | ||
108 | goto out; | ||
109 | } | ||
110 | |||
111 | - set_bit(start, job->done_bitmap); | ||
112 | + set_bit(start / job->cluster_size, job->done_bitmap); | ||
113 | |||
114 | /* Publish progress, guest I/O counts as progress too. Note that the | ||
115 | * offset field is an opaque progress value, it is not a disk offset. | ||
116 | @@ -XXX,XX +XXX,XX @@ out: | ||
117 | |||
118 | cow_request_end(&cow_request); | ||
119 | |||
120 | - trace_backup_do_cow_return(job, sector_num * BDRV_SECTOR_SIZE, | ||
121 | - nb_sectors * BDRV_SECTOR_SIZE, ret); | ||
122 | + trace_backup_do_cow_return(job, offset, bytes, ret); | ||
123 | |||
124 | qemu_co_rwlock_unlock(&job->flush_rwlock); | ||
125 | |||
126 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_before_write_notify( | ||
127 | { | ||
128 | BackupBlockJob *job = container_of(notifier, BackupBlockJob, before_write); | ||
129 | BdrvTrackedRequest *req = opaque; | ||
130 | - int64_t sector_num = req->offset >> BDRV_SECTOR_BITS; | ||
131 | - int nb_sectors = req->bytes >> BDRV_SECTOR_BITS; | ||
132 | |||
133 | assert(req->bs == blk_bs(job->common.blk)); | ||
134 | - assert((req->offset & (BDRV_SECTOR_SIZE - 1)) == 0); | ||
135 | - assert((req->bytes & (BDRV_SECTOR_SIZE - 1)) == 0); | ||
136 | + assert(QEMU_IS_ALIGNED(req->offset, BDRV_SECTOR_SIZE)); | ||
137 | + assert(QEMU_IS_ALIGNED(req->bytes, BDRV_SECTOR_SIZE)); | ||
138 | |||
139 | - return backup_do_cow(job, sector_num, nb_sectors, NULL, true); | ||
140 | + return backup_do_cow(job, req->offset, req->bytes, NULL, true); | ||
141 | } | ||
142 | |||
143 | static void backup_set_speed(BlockJob *job, int64_t speed, Error **errp) | ||
144 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_run_incremental(BackupBlockJob *job) | ||
145 | if (yield_and_check(job)) { | ||
146 | goto out; | ||
147 | } | ||
148 | - ret = backup_do_cow(job, cluster * sectors_per_cluster, | ||
149 | - sectors_per_cluster, &error_is_read, | ||
150 | + ret = backup_do_cow(job, cluster * job->cluster_size, | ||
151 | + job->cluster_size, &error_is_read, | ||
152 | false); | ||
153 | if ((ret < 0) && | ||
154 | backup_error_action(job, error_is_read, -ret) == | ||
155 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn backup_run(void *opaque) | ||
156 | if (alloced < 0) { | ||
157 | ret = alloced; | ||
158 | } else { | ||
159 | - ret = backup_do_cow(job, start * sectors_per_cluster, | ||
160 | - sectors_per_cluster, &error_is_read, | ||
161 | + ret = backup_do_cow(job, start * job->cluster_size, | ||
162 | + job->cluster_size, &error_is_read, | ||
163 | false); | ||
164 | } | ||
165 | if (ret < 0) { | ||
166 | -- | 29 | -- |
167 | 1.8.3.1 | 30 | 2.37.3 |
168 | |||
169 | diff view generated by jsdifflib |
1 | From: Eric Blake <eblake@redhat.com> | 1 | From: Paolo Bonzini <pbonzini@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Now that the last user [mirror_iteration()] has converted to using | 3 | Callers of coroutine_fn must be coroutine_fn themselves, or the call |
4 | bytes, we no longer need a function to round sectors to clusters. | 4 | must be within "if (qemu_in_coroutine())". Apply coroutine_fn to |
5 | functions where this holds. | ||
5 | 6 | ||
6 | Signed-off-by: Eric Blake <eblake@redhat.com> | 7 | Reviewed-by: Alberto Faria <afaria@redhat.com> |
7 | Reviewed-by: John Snow <jsnow@redhat.com> | 8 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
8 | Reviewed-by: Jeff Cody <jcody@redhat.com> | 9 | Message-Id: <20220922084924.201610-13-pbonzini@redhat.com> |
10 | [kwolf: Fixed up coding style] | ||
9 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | 11 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> |
10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
11 | --- | 13 | --- |
12 | block/io.c | 21 --------------------- | 14 | block/nvme.c | 6 ++++-- |
13 | include/block/block.h | 4 ---- | 15 | 1 file changed, 4 insertions(+), 2 deletions(-) |
14 | 2 files changed, 25 deletions(-) | ||
15 | 16 | ||
16 | diff --git a/block/io.c b/block/io.c | 17 | diff --git a/block/nvme.c b/block/nvme.c |
17 | index XXXXXXX..XXXXXXX 100644 | 18 | index XXXXXXX..XXXXXXX 100644 |
18 | --- a/block/io.c | 19 | --- a/block/nvme.c |
19 | +++ b/block/io.c | 20 | +++ b/block/nvme.c |
20 | @@ -XXX,XX +XXX,XX @@ static void mark_request_serialising(BdrvTrackedRequest *req, uint64_t align) | 21 | @@ -XXX,XX +XXX,XX @@ static inline bool nvme_qiov_aligned(BlockDriverState *bs, |
22 | return true; | ||
21 | } | 23 | } |
22 | 24 | ||
23 | /** | 25 | -static int nvme_co_prw(BlockDriverState *bs, uint64_t offset, uint64_t bytes, |
24 | - * Round a region to cluster boundaries (sector-based) | 26 | - QEMUIOVector *qiov, bool is_write, int flags) |
25 | - */ | 27 | +static coroutine_fn int nvme_co_prw(BlockDriverState *bs, |
26 | -void bdrv_round_sectors_to_clusters(BlockDriverState *bs, | 28 | + uint64_t offset, uint64_t bytes, |
27 | - int64_t sector_num, int nb_sectors, | 29 | + QEMUIOVector *qiov, bool is_write, |
28 | - int64_t *cluster_sector_num, | 30 | + int flags) |
29 | - int *cluster_nb_sectors) | 31 | { |
30 | -{ | 32 | BDRVNVMeState *s = bs->opaque; |
31 | - BlockDriverInfo bdi; | 33 | int r; |
32 | - | ||
33 | - if (bdrv_get_info(bs, &bdi) < 0 || bdi.cluster_size == 0) { | ||
34 | - *cluster_sector_num = sector_num; | ||
35 | - *cluster_nb_sectors = nb_sectors; | ||
36 | - } else { | ||
37 | - int64_t c = bdi.cluster_size / BDRV_SECTOR_SIZE; | ||
38 | - *cluster_sector_num = QEMU_ALIGN_DOWN(sector_num, c); | ||
39 | - *cluster_nb_sectors = QEMU_ALIGN_UP(sector_num - *cluster_sector_num + | ||
40 | - nb_sectors, c); | ||
41 | - } | ||
42 | -} | ||
43 | - | ||
44 | -/** | ||
45 | * Round a region to cluster boundaries | ||
46 | */ | ||
47 | void bdrv_round_to_clusters(BlockDriverState *bs, | ||
48 | diff --git a/include/block/block.h b/include/block/block.h | ||
49 | index XXXXXXX..XXXXXXX 100644 | ||
50 | --- a/include/block/block.h | ||
51 | +++ b/include/block/block.h | ||
52 | @@ -XXX,XX +XXX,XX @@ const char *bdrv_get_device_or_node_name(const BlockDriverState *bs); | ||
53 | int bdrv_get_flags(BlockDriverState *bs); | ||
54 | int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi); | ||
55 | ImageInfoSpecific *bdrv_get_specific_info(BlockDriverState *bs); | ||
56 | -void bdrv_round_sectors_to_clusters(BlockDriverState *bs, | ||
57 | - int64_t sector_num, int nb_sectors, | ||
58 | - int64_t *cluster_sector_num, | ||
59 | - int *cluster_nb_sectors); | ||
60 | void bdrv_round_to_clusters(BlockDriverState *bs, | ||
61 | int64_t offset, unsigned int bytes, | ||
62 | int64_t *cluster_offset, | ||
63 | -- | 34 | -- |
64 | 1.8.3.1 | 35 | 2.37.3 |
65 | |||
66 | diff view generated by jsdifflib |
1 | From: Eric Blake <eblake@redhat.com> | 1 | From: Paolo Bonzini <pbonzini@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | We are gradually converting to byte-based interfaces, as they are | 3 | Callers of coroutine_fn must be coroutine_fn themselves, or the call |
4 | easier to reason about than sector-based. Start by converting an | 4 | must be within "if (qemu_in_coroutine())". Apply coroutine_fn to |
5 | internal function (no semantic change). | 5 | functions where this holds. |
6 | 6 | ||
7 | Signed-off-by: Eric Blake <eblake@redhat.com> | 7 | Reviewed-by: Alberto Faria <afaria@redhat.com> |
8 | Reviewed-by: John Snow <jsnow@redhat.com> | 8 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
9 | Reviewed-by: Jeff Cody <jcody@redhat.com> | 9 | Message-Id: <20220922084924.201610-14-pbonzini@redhat.com> |
10 | [kwolf: Fixed up coding style] | ||
10 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | 11 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> |
11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
12 | --- | 13 | --- |
13 | block/commit.c | 15 ++++++++------- | 14 | block/parallels.c | 5 +++-- |
14 | 1 file changed, 8 insertions(+), 7 deletions(-) | 15 | 1 file changed, 3 insertions(+), 2 deletions(-) |
15 | 16 | ||
16 | diff --git a/block/commit.c b/block/commit.c | 17 | diff --git a/block/parallels.c b/block/parallels.c |
17 | index XXXXXXX..XXXXXXX 100644 | 18 | index XXXXXXX..XXXXXXX 100644 |
18 | --- a/block/commit.c | 19 | --- a/block/parallels.c |
19 | +++ b/block/commit.c | 20 | +++ b/block/parallels.c |
20 | @@ -XXX,XX +XXX,XX @@ typedef struct CommitBlockJob { | 21 | @@ -XXX,XX +XXX,XX @@ static int64_t block_status(BDRVParallelsState *s, int64_t sector_num, |
21 | } CommitBlockJob; | 22 | return start_off; |
22 | 23 | } | |
23 | static int coroutine_fn commit_populate(BlockBackend *bs, BlockBackend *base, | 24 | |
24 | - int64_t sector_num, int nb_sectors, | 25 | -static int64_t allocate_clusters(BlockDriverState *bs, int64_t sector_num, |
25 | + int64_t offset, uint64_t bytes, | 26 | - int nb_sectors, int *pnum) |
26 | void *buf) | 27 | +static coroutine_fn int64_t allocate_clusters(BlockDriverState *bs, |
28 | + int64_t sector_num, | ||
29 | + int nb_sectors, int *pnum) | ||
27 | { | 30 | { |
28 | int ret = 0; | 31 | int ret = 0; |
29 | QEMUIOVector qiov; | 32 | BDRVParallelsState *s = bs->opaque; |
30 | struct iovec iov = { | ||
31 | .iov_base = buf, | ||
32 | - .iov_len = nb_sectors * BDRV_SECTOR_SIZE, | ||
33 | + .iov_len = bytes, | ||
34 | }; | ||
35 | |||
36 | + assert(bytes < SIZE_MAX); | ||
37 | qemu_iovec_init_external(&qiov, &iov, 1); | ||
38 | |||
39 | - ret = blk_co_preadv(bs, sector_num * BDRV_SECTOR_SIZE, | ||
40 | - qiov.size, &qiov, 0); | ||
41 | + ret = blk_co_preadv(bs, offset, qiov.size, &qiov, 0); | ||
42 | if (ret < 0) { | ||
43 | return ret; | ||
44 | } | ||
45 | |||
46 | - ret = blk_co_pwritev(base, sector_num * BDRV_SECTOR_SIZE, | ||
47 | - qiov.size, &qiov, 0); | ||
48 | + ret = blk_co_pwritev(base, offset, qiov.size, &qiov, 0); | ||
49 | if (ret < 0) { | ||
50 | return ret; | ||
51 | } | ||
52 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn commit_run(void *opaque) | ||
53 | trace_commit_one_iteration(s, sector_num * BDRV_SECTOR_SIZE, | ||
54 | n * BDRV_SECTOR_SIZE, ret); | ||
55 | if (copy) { | ||
56 | - ret = commit_populate(s->top, s->base, sector_num, n, buf); | ||
57 | + ret = commit_populate(s->top, s->base, | ||
58 | + sector_num * BDRV_SECTOR_SIZE, | ||
59 | + n * BDRV_SECTOR_SIZE, buf); | ||
60 | bytes_written += n * BDRV_SECTOR_SIZE; | ||
61 | } | ||
62 | if (ret < 0) { | ||
63 | -- | 33 | -- |
64 | 1.8.3.1 | 34 | 2.37.3 |
65 | |||
66 | diff view generated by jsdifflib |
1 | From: "Daniel P. Berrange" <berrange@redhat.com> | 1 | From: Paolo Bonzini <pbonzini@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | This adds support for using LUKS as an encryption format | 3 | Callers of coroutine_fn must be coroutine_fn themselves, or the call |
4 | with the qcow2 file, using the new encrypt.format parameter | 4 | must be within "if (qemu_in_coroutine())". Apply coroutine_fn to |
5 | to request "luks" format. e.g. | 5 | functions where this holds. |
6 | 6 | ||
7 | # qemu-img create --object secret,data=123456,id=sec0 \ | 7 | Reviewed-by: Alberto Faria <afaria@redhat.com> |
8 | -f qcow2 -o encrypt.format=luks,encrypt.key-secret=sec0 \ | 8 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
9 | test.qcow2 10G | 9 | Message-Id: <20220922084924.201610-15-pbonzini@redhat.com> |
10 | [kwolf: Fixed up coding style] | ||
11 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
13 | --- | ||
14 | block/qcow2.h | 15 ++++++++------- | ||
15 | block/qcow2-cluster.c | 21 ++++++++++++--------- | ||
16 | block/qcow2-refcount.c | 2 +- | ||
17 | block/qcow2.c | 5 +++-- | ||
18 | 4 files changed, 24 insertions(+), 19 deletions(-) | ||
10 | 19 | ||
11 | The legacy "encryption=on" parameter still results in | 20 | diff --git a/block/qcow2.h b/block/qcow2.h |
12 | creation of the old qcow2 AES format (and is equivalent | 21 | index XXXXXXX..XXXXXXX 100644 |
13 | to the new 'encryption-format=aes'). e.g. the following are | 22 | --- a/block/qcow2.h |
14 | equivalent: | 23 | +++ b/block/qcow2.h |
15 | 24 | @@ -XXX,XX +XXX,XX @@ int qcow2_change_refcount_order(BlockDriverState *bs, int refcount_order, | |
16 | # qemu-img create --object secret,data=123456,id=sec0 \ | 25 | void *cb_opaque, Error **errp); |
17 | -f qcow2 -o encryption=on,encrypt.key-secret=sec0 \ | 26 | int qcow2_shrink_reftable(BlockDriverState *bs); |
18 | test.qcow2 10G | 27 | int64_t qcow2_get_last_cluster(BlockDriverState *bs, int64_t size); |
19 | 28 | -int qcow2_detect_metadata_preallocation(BlockDriverState *bs); | |
20 | # qemu-img create --object secret,data=123456,id=sec0 \ | 29 | +int coroutine_fn qcow2_detect_metadata_preallocation(BlockDriverState *bs); |
21 | -f qcow2 -o encryption-format=aes,encrypt.key-secret=sec0 \ | 30 | |
22 | test.qcow2 10G | 31 | /* qcow2-cluster.c functions */ |
23 | 32 | int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size, | |
24 | With the LUKS format it is necessary to store the LUKS | 33 | @@ -XXX,XX +XXX,XX @@ int qcow2_encrypt_sectors(BDRVQcow2State *s, int64_t sector_num, |
25 | partition header and key material in the QCow2 file. This | 34 | int qcow2_get_host_offset(BlockDriverState *bs, uint64_t offset, |
26 | data can be many MB in size, so cannot go into the QCow2 | 35 | unsigned int *bytes, uint64_t *host_offset, |
27 | header region directly. Thus the spec defines a FDE | 36 | QCow2SubclusterType *subcluster_type); |
28 | (Full Disk Encryption) header extension that specifies | 37 | -int qcow2_alloc_host_offset(BlockDriverState *bs, uint64_t offset, |
29 | the offset of a set of clusters to hold the FDE headers, | 38 | - unsigned int *bytes, uint64_t *host_offset, |
30 | as well as the length of that region. The LUKS header is | 39 | - QCowL2Meta **m); |
31 | thus stored in these extra allocated clusters before the | 40 | +int coroutine_fn qcow2_alloc_host_offset(BlockDriverState *bs, uint64_t offset, |
32 | main image payload. | 41 | + unsigned int *bytes, |
33 | 42 | + uint64_t *host_offset, QCowL2Meta **m); | |
34 | Aside from all the cryptographic differences implied by | 43 | int qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs, |
35 | use of the LUKS format, there is one further key difference | 44 | uint64_t offset, |
36 | between the use of legacy AES and LUKS encryption in qcow2. | 45 | int compressed_size, |
37 | For LUKS, the initialiazation vectors are generated using | 46 | @@ -XXX,XX +XXX,XX @@ int qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs, |
38 | the host physical sector as the input, rather than the | 47 | void qcow2_parse_compressed_l2_entry(BlockDriverState *bs, uint64_t l2_entry, |
39 | guest virtual sector. This guarantees unique initialization | 48 | uint64_t *coffset, int *csize); |
40 | vectors for all sectors when qcow2 internal snapshots are | 49 | |
41 | used, thus giving stronger protection against watermarking | 50 | -int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m); |
42 | attacks. | 51 | +int coroutine_fn qcow2_alloc_cluster_link_l2(BlockDriverState *bs, |
43 | 52 | + QCowL2Meta *m); | |
44 | Signed-off-by: Daniel P. Berrange <berrange@redhat.com> | 53 | void qcow2_alloc_cluster_abort(BlockDriverState *bs, QCowL2Meta *m); |
45 | Message-id: 20170623162419.26068-14-berrange@redhat.com | 54 | int qcow2_cluster_discard(BlockDriverState *bs, uint64_t offset, |
46 | Reviewed-by: Alberto Garcia <berto@igalia.com> | 55 | uint64_t bytes, enum qcow2_discard_type type, |
47 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 56 | bool full_discard); |
48 | --- | 57 | -int qcow2_subcluster_zeroize(BlockDriverState *bs, uint64_t offset, |
49 | block/qcow2-cluster.c | 14 ++- | 58 | - uint64_t bytes, int flags); |
50 | block/qcow2-refcount.c | 10 ++ | 59 | +int coroutine_fn qcow2_subcluster_zeroize(BlockDriverState *bs, uint64_t offset, |
51 | block/qcow2.c | 268 ++++++++++++++++++++++++++++++++++++++------ | 60 | + uint64_t bytes, int flags); |
52 | block/qcow2.h | 9 ++ | 61 | |
53 | qapi/block-core.json | 5 +- | 62 | int qcow2_expand_zero_clusters(BlockDriverState *bs, |
54 | tests/qemu-iotests/082.out | 270 ++++++++++++++++++++++++++++++++++++--------- | 63 | BlockDriverAmendStatusCB *status_cb, |
55 | 6 files changed, 484 insertions(+), 92 deletions(-) | ||
56 | |||
57 | diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c | 64 | diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c |
58 | index XXXXXXX..XXXXXXX 100644 | 65 | index XXXXXXX..XXXXXXX 100644 |
59 | --- a/block/qcow2-cluster.c | 66 | --- a/block/qcow2-cluster.c |
60 | +++ b/block/qcow2-cluster.c | 67 | +++ b/block/qcow2-cluster.c |
61 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn do_perform_cow_read(BlockDriverState *bs, | 68 | @@ -XXX,XX +XXX,XX @@ int qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs, |
62 | 69 | return 0; | |
63 | static bool coroutine_fn do_perform_cow_encrypt(BlockDriverState *bs, | 70 | } |
64 | uint64_t src_cluster_offset, | 71 | |
65 | + uint64_t cluster_offset, | 72 | -static int perform_cow(BlockDriverState *bs, QCowL2Meta *m) |
66 | unsigned offset_in_cluster, | 73 | +static int coroutine_fn perform_cow(BlockDriverState *bs, QCowL2Meta *m) |
67 | uint8_t *buffer, | ||
68 | unsigned bytes) | ||
69 | { | 74 | { |
70 | if (bytes && bs->encrypted) { | 75 | BDRVQcow2State *s = bs->opaque; |
71 | BDRVQcow2State *s = bs->opaque; | 76 | Qcow2COWRegion *start = &m->cow_start; |
72 | - int64_t sector = (src_cluster_offset + offset_in_cluster) | 77 | @@ -XXX,XX +XXX,XX @@ fail: |
73 | + int64_t sector = (s->crypt_physical_offset ? | 78 | return ret; |
74 | + (cluster_offset + offset_in_cluster) : | 79 | } |
75 | + (src_cluster_offset + offset_in_cluster)) | 80 | |
76 | >> BDRV_SECTOR_BITS; | 81 | -int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m) |
77 | assert((offset_in_cluster & ~BDRV_SECTOR_MASK) == 0); | 82 | +int coroutine_fn qcow2_alloc_cluster_link_l2(BlockDriverState *bs, |
78 | assert((bytes & ~BDRV_SECTOR_MASK) == 0); | 83 | + QCowL2Meta *m) |
79 | @@ -XXX,XX +XXX,XX @@ static int perform_cow(BlockDriverState *bs, QCowL2Meta *m) | 84 | { |
80 | 85 | BDRVQcow2State *s = bs->opaque; | |
81 | /* Encrypt the data if necessary before writing it */ | 86 | int i, j = 0, l2_index, ret; |
82 | if (bs->encrypted) { | 87 | @@ -XXX,XX +XXX,XX @@ static int count_single_write_clusters(BlockDriverState *bs, int nb_clusters, |
83 | - if (!do_perform_cow_encrypt(bs, m->offset, start->offset, | 88 | * information on cluster allocation may be invalid now. The caller |
84 | - start_buffer, start->nb_bytes) || | 89 | * must start over anyway, so consider *cur_bytes undefined. |
85 | - !do_perform_cow_encrypt(bs, m->offset, end->offset, | 90 | */ |
86 | - end_buffer, end->nb_bytes)) { | 91 | -static int handle_dependencies(BlockDriverState *bs, uint64_t guest_offset, |
87 | + if (!do_perform_cow_encrypt(bs, m->offset, m->alloc_offset, | 92 | - uint64_t *cur_bytes, QCowL2Meta **m) |
88 | + start->offset, start_buffer, | 93 | +static int coroutine_fn handle_dependencies(BlockDriverState *bs, |
89 | + start->nb_bytes) || | 94 | + uint64_t guest_offset, |
90 | + !do_perform_cow_encrypt(bs, m->offset, m->alloc_offset, | 95 | + uint64_t *cur_bytes, QCowL2Meta **m) |
91 | + end->offset, end_buffer, end->nb_bytes)) { | 96 | { |
92 | ret = -EIO; | 97 | BDRVQcow2State *s = bs->opaque; |
93 | goto fail; | 98 | QCowL2Meta *old_alloc; |
94 | } | 99 | @@ -XXX,XX +XXX,XX @@ out: |
100 | * | ||
101 | * Return 0 on success and -errno in error cases | ||
102 | */ | ||
103 | -int qcow2_alloc_host_offset(BlockDriverState *bs, uint64_t offset, | ||
104 | - unsigned int *bytes, uint64_t *host_offset, | ||
105 | - QCowL2Meta **m) | ||
106 | +int coroutine_fn qcow2_alloc_host_offset(BlockDriverState *bs, uint64_t offset, | ||
107 | + unsigned int *bytes, | ||
108 | + uint64_t *host_offset, | ||
109 | + QCowL2Meta **m) | ||
110 | { | ||
111 | BDRVQcow2State *s = bs->opaque; | ||
112 | uint64_t start, remaining; | ||
113 | @@ -XXX,XX +XXX,XX @@ out: | ||
114 | return ret; | ||
115 | } | ||
116 | |||
117 | -int qcow2_subcluster_zeroize(BlockDriverState *bs, uint64_t offset, | ||
118 | - uint64_t bytes, int flags) | ||
119 | +int coroutine_fn qcow2_subcluster_zeroize(BlockDriverState *bs, uint64_t offset, | ||
120 | + uint64_t bytes, int flags) | ||
121 | { | ||
122 | BDRVQcow2State *s = bs->opaque; | ||
123 | uint64_t end_offset = offset + bytes; | ||
95 | diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c | 124 | diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c |
96 | index XXXXXXX..XXXXXXX 100644 | 125 | index XXXXXXX..XXXXXXX 100644 |
97 | --- a/block/qcow2-refcount.c | 126 | --- a/block/qcow2-refcount.c |
98 | +++ b/block/qcow2-refcount.c | 127 | +++ b/block/qcow2-refcount.c |
99 | @@ -XXX,XX +XXX,XX @@ static int calculate_refcounts(BlockDriverState *bs, BdrvCheckResult *res, | 128 | @@ -XXX,XX +XXX,XX @@ int64_t qcow2_get_last_cluster(BlockDriverState *bs, int64_t size) |
100 | return ret; | 129 | return -EIO; |
101 | } | ||
102 | |||
103 | + /* encryption */ | ||
104 | + if (s->crypto_header.length) { | ||
105 | + ret = inc_refcounts(bs, res, refcount_table, nb_clusters, | ||
106 | + s->crypto_header.offset, | ||
107 | + s->crypto_header.length); | ||
108 | + if (ret < 0) { | ||
109 | + return ret; | ||
110 | + } | ||
111 | + } | ||
112 | + | ||
113 | return check_refblocks(bs, res, fix, rebuild, refcount_table, nb_clusters); | ||
114 | } | 130 | } |
115 | 131 | ||
132 | -int qcow2_detect_metadata_preallocation(BlockDriverState *bs) | ||
133 | +int coroutine_fn qcow2_detect_metadata_preallocation(BlockDriverState *bs) | ||
134 | { | ||
135 | BDRVQcow2State *s = bs->opaque; | ||
136 | int64_t i, end_cluster, cluster_count = 0, threshold; | ||
116 | diff --git a/block/qcow2.c b/block/qcow2.c | 137 | diff --git a/block/qcow2.c b/block/qcow2.c |
117 | index XXXXXXX..XXXXXXX 100644 | 138 | index XXXXXXX..XXXXXXX 100644 |
118 | --- a/block/qcow2.c | 139 | --- a/block/qcow2.c |
119 | +++ b/block/qcow2.c | 140 | +++ b/block/qcow2.c |
120 | @@ -XXX,XX +XXX,XX @@ typedef struct { | 141 | @@ -XXX,XX +XXX,XX @@ static bool merge_cow(uint64_t offset, unsigned bytes, |
121 | #define QCOW2_EXT_MAGIC_END 0 | 142 | * Return 1 if the COW regions read as zeroes, 0 if not, < 0 on error. |
122 | #define QCOW2_EXT_MAGIC_BACKING_FORMAT 0xE2792ACA | 143 | * Note that returning 0 does not guarantee non-zero data. |
123 | #define QCOW2_EXT_MAGIC_FEATURE_TABLE 0x6803f857 | 144 | */ |
124 | +#define QCOW2_EXT_MAGIC_CRYPTO_HEADER 0x0537be77 | 145 | -static int is_zero_cow(BlockDriverState *bs, QCowL2Meta *m) |
125 | 146 | +static int coroutine_fn is_zero_cow(BlockDriverState *bs, QCowL2Meta *m) | |
126 | static int qcow2_probe(const uint8_t *buf, int buf_size, const char *filename) | ||
127 | { | 147 | { |
128 | @@ -XXX,XX +XXX,XX @@ static int qcow2_probe(const uint8_t *buf, int buf_size, const char *filename) | 148 | /* |
149 | * This check is designed for optimization shortcut so it must be | ||
150 | @@ -XXX,XX +XXX,XX @@ static int is_zero_cow(BlockDriverState *bs, QCowL2Meta *m) | ||
151 | m->cow_end.nb_bytes); | ||
129 | } | 152 | } |
130 | 153 | ||
131 | 154 | -static int handle_alloc_space(BlockDriverState *bs, QCowL2Meta *l2meta) | |
132 | +static ssize_t qcow2_crypto_hdr_read_func(QCryptoBlock *block, size_t offset, | 155 | +static int coroutine_fn handle_alloc_space(BlockDriverState *bs, |
133 | + uint8_t *buf, size_t buflen, | 156 | + QCowL2Meta *l2meta) |
134 | + void *opaque, Error **errp) | ||
135 | +{ | ||
136 | + BlockDriverState *bs = opaque; | ||
137 | + BDRVQcow2State *s = bs->opaque; | ||
138 | + ssize_t ret; | ||
139 | + | ||
140 | + if ((offset + buflen) > s->crypto_header.length) { | ||
141 | + error_setg(errp, "Request for data outside of extension header"); | ||
142 | + return -1; | ||
143 | + } | ||
144 | + | ||
145 | + ret = bdrv_pread(bs->file, | ||
146 | + s->crypto_header.offset + offset, buf, buflen); | ||
147 | + if (ret < 0) { | ||
148 | + error_setg_errno(errp, -ret, "Could not read encryption header"); | ||
149 | + return -1; | ||
150 | + } | ||
151 | + return ret; | ||
152 | +} | ||
153 | + | ||
154 | + | ||
155 | +static ssize_t qcow2_crypto_hdr_init_func(QCryptoBlock *block, size_t headerlen, | ||
156 | + void *opaque, Error **errp) | ||
157 | +{ | ||
158 | + BlockDriverState *bs = opaque; | ||
159 | + BDRVQcow2State *s = bs->opaque; | ||
160 | + int64_t ret; | ||
161 | + int64_t clusterlen; | ||
162 | + | ||
163 | + ret = qcow2_alloc_clusters(bs, headerlen); | ||
164 | + if (ret < 0) { | ||
165 | + error_setg_errno(errp, -ret, | ||
166 | + "Cannot allocate cluster for LUKS header size %zu", | ||
167 | + headerlen); | ||
168 | + return -1; | ||
169 | + } | ||
170 | + | ||
171 | + s->crypto_header.length = headerlen; | ||
172 | + s->crypto_header.offset = ret; | ||
173 | + | ||
174 | + /* Zero fill remaining space in cluster so it has predictable | ||
175 | + * content in case of future spec changes */ | ||
176 | + clusterlen = size_to_clusters(s, headerlen) * s->cluster_size; | ||
177 | + ret = bdrv_pwrite_zeroes(bs->file, | ||
178 | + ret + headerlen, | ||
179 | + clusterlen - headerlen, 0); | ||
180 | + if (ret < 0) { | ||
181 | + error_setg_errno(errp, -ret, "Could not zero fill encryption header"); | ||
182 | + return -1; | ||
183 | + } | ||
184 | + | ||
185 | + return ret; | ||
186 | +} | ||
187 | + | ||
188 | + | ||
189 | +static ssize_t qcow2_crypto_hdr_write_func(QCryptoBlock *block, size_t offset, | ||
190 | + const uint8_t *buf, size_t buflen, | ||
191 | + void *opaque, Error **errp) | ||
192 | +{ | ||
193 | + BlockDriverState *bs = opaque; | ||
194 | + BDRVQcow2State *s = bs->opaque; | ||
195 | + ssize_t ret; | ||
196 | + | ||
197 | + if ((offset + buflen) > s->crypto_header.length) { | ||
198 | + error_setg(errp, "Request for data outside of extension header"); | ||
199 | + return -1; | ||
200 | + } | ||
201 | + | ||
202 | + ret = bdrv_pwrite(bs->file, | ||
203 | + s->crypto_header.offset + offset, buf, buflen); | ||
204 | + if (ret < 0) { | ||
205 | + error_setg_errno(errp, -ret, "Could not read encryption header"); | ||
206 | + return -1; | ||
207 | + } | ||
208 | + return ret; | ||
209 | +} | ||
210 | + | ||
211 | + | ||
212 | /* | ||
213 | * read qcow2 extension and fill bs | ||
214 | * start reading from start_offset | ||
215 | @@ -XXX,XX +XXX,XX @@ static int qcow2_probe(const uint8_t *buf, int buf_size, const char *filename) | ||
216 | */ | ||
217 | static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset, | ||
218 | uint64_t end_offset, void **p_feature_table, | ||
219 | - Error **errp) | ||
220 | + int flags, Error **errp) | ||
221 | { | 157 | { |
222 | BDRVQcow2State *s = bs->opaque; | 158 | BDRVQcow2State *s = bs->opaque; |
223 | QCowExtension ext; | 159 | QCowL2Meta *m; |
224 | @@ -XXX,XX +XXX,XX @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset, | ||
225 | } | ||
226 | break; | ||
227 | |||
228 | + case QCOW2_EXT_MAGIC_CRYPTO_HEADER: { | ||
229 | + unsigned int cflags = 0; | ||
230 | + if (s->crypt_method_header != QCOW_CRYPT_LUKS) { | ||
231 | + error_setg(errp, "CRYPTO header extension only " | ||
232 | + "expected with LUKS encryption method"); | ||
233 | + return -EINVAL; | ||
234 | + } | ||
235 | + if (ext.len != sizeof(Qcow2CryptoHeaderExtension)) { | ||
236 | + error_setg(errp, "CRYPTO header extension size %u, " | ||
237 | + "but expected size %zu", ext.len, | ||
238 | + sizeof(Qcow2CryptoHeaderExtension)); | ||
239 | + return -EINVAL; | ||
240 | + } | ||
241 | + | ||
242 | + ret = bdrv_pread(bs->file, offset, &s->crypto_header, ext.len); | ||
243 | + if (ret < 0) { | ||
244 | + error_setg_errno(errp, -ret, | ||
245 | + "Unable to read CRYPTO header extension"); | ||
246 | + return ret; | ||
247 | + } | ||
248 | + be64_to_cpus(&s->crypto_header.offset); | ||
249 | + be64_to_cpus(&s->crypto_header.length); | ||
250 | + | ||
251 | + if ((s->crypto_header.offset % s->cluster_size) != 0) { | ||
252 | + error_setg(errp, "Encryption header offset '%" PRIu64 "' is " | ||
253 | + "not a multiple of cluster size '%u'", | ||
254 | + s->crypto_header.offset, s->cluster_size); | ||
255 | + return -EINVAL; | ||
256 | + } | ||
257 | + | ||
258 | + if (flags & BDRV_O_NO_IO) { | ||
259 | + cflags |= QCRYPTO_BLOCK_OPEN_NO_IO; | ||
260 | + } | ||
261 | + s->crypto = qcrypto_block_open(s->crypto_opts, | ||
262 | + qcow2_crypto_hdr_read_func, | ||
263 | + bs, cflags, errp); | ||
264 | + if (!s->crypto) { | ||
265 | + return -EINVAL; | ||
266 | + } | ||
267 | + } break; | ||
268 | + | ||
269 | default: | ||
270 | /* unknown magic - save it in case we need to rewrite the header */ | ||
271 | { | ||
272 | @@ -XXX,XX +XXX,XX @@ static QemuOptsList qcow2_runtime_opts = { | ||
273 | .type = QEMU_OPT_NUMBER, | ||
274 | .help = "Clean unused cache entries after this time (in seconds)", | ||
275 | }, | ||
276 | - BLOCK_CRYPTO_OPT_DEF_QCOW_KEY_SECRET("encrypt."), | ||
277 | + BLOCK_CRYPTO_OPT_DEF_KEY_SECRET("encrypt.", | ||
278 | + "ID of secret providing qcow2 AES key or LUKS passphrase"), | ||
279 | { /* end of list */ } | ||
280 | }, | ||
281 | }; | ||
282 | @@ -XXX,XX +XXX,XX @@ static int qcow2_update_options_prepare(BlockDriverState *bs, | ||
283 | Q_CRYPTO_BLOCK_FORMAT_QCOW, encryptopts, errp); | ||
284 | break; | ||
285 | |||
286 | + case QCOW_CRYPT_LUKS: | ||
287 | + if (encryptfmt && !g_str_equal(encryptfmt, "luks")) { | ||
288 | + error_setg(errp, | ||
289 | + "Header reported 'luks' encryption format but " | ||
290 | + "options specify '%s'", encryptfmt); | ||
291 | + ret = -EINVAL; | ||
292 | + goto fail; | ||
293 | + } | ||
294 | + qdict_del(encryptopts, "format"); | ||
295 | + r->crypto_opts = block_crypto_open_opts_init( | ||
296 | + Q_CRYPTO_BLOCK_FORMAT_LUKS, encryptopts, errp); | ||
297 | + break; | ||
298 | + | ||
299 | default: | ||
300 | error_setg(errp, "Unsupported encryption method %d", | ||
301 | s->crypt_method_header); | ||
302 | @@ -XXX,XX +XXX,XX @@ static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags, | ||
303 | if (s->incompatible_features & ~QCOW2_INCOMPAT_MASK) { | ||
304 | void *feature_table = NULL; | ||
305 | qcow2_read_extensions(bs, header.header_length, ext_end, | ||
306 | - &feature_table, NULL); | ||
307 | + &feature_table, flags, NULL); | ||
308 | report_unsupported_feature(errp, feature_table, | ||
309 | s->incompatible_features & | ||
310 | ~QCOW2_INCOMPAT_MASK); | ||
311 | @@ -XXX,XX +XXX,XX @@ static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags, | ||
312 | s->refcount_max = UINT64_C(1) << (s->refcount_bits - 1); | ||
313 | s->refcount_max += s->refcount_max - 1; | ||
314 | |||
315 | - if (header.crypt_method > QCOW_CRYPT_AES) { | ||
316 | - error_setg(errp, "Unsupported encryption method: %" PRIu32, | ||
317 | - header.crypt_method); | ||
318 | - ret = -EINVAL; | ||
319 | - goto fail; | ||
320 | - } | ||
321 | s->crypt_method_header = header.crypt_method; | ||
322 | if (s->crypt_method_header) { | ||
323 | if (bdrv_uses_whitelist() && | ||
324 | @@ -XXX,XX +XXX,XX @@ static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags, | ||
325 | goto fail; | ||
326 | } | ||
327 | |||
328 | + if (s->crypt_method_header == QCOW_CRYPT_AES) { | ||
329 | + s->crypt_physical_offset = false; | ||
330 | + } else { | ||
331 | + /* Assuming LUKS and any future crypt methods we | ||
332 | + * add will all use physical offsets, due to the | ||
333 | + * fact that the alternative is insecure... */ | ||
334 | + s->crypt_physical_offset = true; | ||
335 | + } | ||
336 | + | ||
337 | bs->encrypted = true; | ||
338 | bs->valid_key = true; | ||
339 | } | ||
340 | @@ -XXX,XX +XXX,XX @@ static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags, | ||
341 | |||
342 | /* read qcow2 extensions */ | ||
343 | if (qcow2_read_extensions(bs, header.header_length, ext_end, NULL, | ||
344 | - &local_err)) { | ||
345 | + flags, &local_err)) { | ||
346 | error_propagate(errp, local_err); | ||
347 | ret = -EINVAL; | ||
348 | goto fail; | ||
349 | } | ||
350 | |||
351 | - if (s->crypt_method_header == QCOW_CRYPT_AES) { | ||
352 | - unsigned int cflags = 0; | ||
353 | - if (flags & BDRV_O_NO_IO) { | ||
354 | - cflags |= QCRYPTO_BLOCK_OPEN_NO_IO; | ||
355 | - } | ||
356 | - s->crypto = qcrypto_block_open(s->crypto_opts, NULL, NULL, | ||
357 | - cflags, errp); | ||
358 | - if (!s->crypto) { | ||
359 | + /* qcow2_read_extension may have set up the crypto context | ||
360 | + * if the crypt method needs a header region, some methods | ||
361 | + * don't need header extensions, so must check here | ||
362 | + */ | ||
363 | + if (s->crypt_method_header && !s->crypto) { | ||
364 | + if (s->crypt_method_header == QCOW_CRYPT_AES) { | ||
365 | + unsigned int cflags = 0; | ||
366 | + if (flags & BDRV_O_NO_IO) { | ||
367 | + cflags |= QCRYPTO_BLOCK_OPEN_NO_IO; | ||
368 | + } | ||
369 | + s->crypto = qcrypto_block_open(s->crypto_opts, NULL, NULL, | ||
370 | + cflags, errp); | ||
371 | + if (!s->crypto) { | ||
372 | + ret = -EINVAL; | ||
373 | + goto fail; | ||
374 | + } | ||
375 | + } else if (!(flags & BDRV_O_NO_IO)) { | ||
376 | + error_setg(errp, "Missing CRYPTO header for crypt method %d", | ||
377 | + s->crypt_method_header); | ||
378 | ret = -EINVAL; | ||
379 | goto fail; | ||
380 | } | ||
381 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset, | ||
382 | assert((cur_bytes & (BDRV_SECTOR_SIZE - 1)) == 0); | ||
383 | Error *err = NULL; | ||
384 | if (qcrypto_block_decrypt(s->crypto, | ||
385 | - offset >> BDRV_SECTOR_BITS, | ||
386 | + (s->crypt_physical_offset ? | ||
387 | + cluster_offset + offset_in_cluster : | ||
388 | + offset) >> BDRV_SECTOR_BITS, | ||
389 | cluster_data, | ||
390 | cur_bytes, | ||
391 | &err) < 0) { | ||
392 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_pwritev(BlockDriverState *bs, uint64_t offset, | ||
393 | QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size); | ||
394 | qemu_iovec_to_buf(&hd_qiov, 0, cluster_data, hd_qiov.size); | ||
395 | |||
396 | - if (qcrypto_block_encrypt(s->crypto, offset >> BDRV_SECTOR_BITS, | ||
397 | + if (qcrypto_block_encrypt(s->crypto, | ||
398 | + (s->crypt_physical_offset ? | ||
399 | + cluster_offset + offset_in_cluster : | ||
400 | + offset) >> BDRV_SECTOR_BITS, | ||
401 | cluster_data, | ||
402 | cur_bytes, &err) < 0) { | ||
403 | error_free(err); | ||
404 | @@ -XXX,XX +XXX,XX @@ int qcow2_update_header(BlockDriverState *bs) | ||
405 | buflen -= ret; | ||
406 | } | ||
407 | |||
408 | + /* Full disk encryption header pointer extension */ | ||
409 | + if (s->crypto_header.offset != 0) { | ||
410 | + cpu_to_be64s(&s->crypto_header.offset); | ||
411 | + cpu_to_be64s(&s->crypto_header.length); | ||
412 | + ret = header_ext_add(buf, QCOW2_EXT_MAGIC_CRYPTO_HEADER, | ||
413 | + &s->crypto_header, sizeof(s->crypto_header), | ||
414 | + buflen); | ||
415 | + be64_to_cpus(&s->crypto_header.offset); | ||
416 | + be64_to_cpus(&s->crypto_header.length); | ||
417 | + if (ret < 0) { | ||
418 | + goto fail; | ||
419 | + } | ||
420 | + buf += ret; | ||
421 | + buflen -= ret; | ||
422 | + } | ||
423 | + | ||
424 | /* Feature table */ | ||
425 | if (s->qcow_version >= 3) { | ||
426 | Qcow2Feature features[] = { | ||
427 | @@ -XXX,XX +XXX,XX @@ static int qcow2_change_backing_file(BlockDriverState *bs, | ||
428 | return qcow2_update_header(bs); | ||
429 | } | ||
430 | |||
431 | +static int qcow2_crypt_method_from_format(const char *encryptfmt) | ||
432 | +{ | ||
433 | + if (g_str_equal(encryptfmt, "luks")) { | ||
434 | + return QCOW_CRYPT_LUKS; | ||
435 | + } else if (g_str_equal(encryptfmt, "aes")) { | ||
436 | + return QCOW_CRYPT_AES; | ||
437 | + } else { | ||
438 | + return -EINVAL; | ||
439 | + } | ||
440 | +} | ||
441 | |||
442 | static int qcow2_set_up_encryption(BlockDriverState *bs, const char *encryptfmt, | ||
443 | QemuOpts *opts, Error **errp) | ||
444 | @@ -XXX,XX +XXX,XX @@ static int qcow2_set_up_encryption(BlockDriverState *bs, const char *encryptfmt, | ||
445 | QCryptoBlock *crypto = NULL; | ||
446 | int ret = -EINVAL; | ||
447 | QDict *options, *encryptopts; | ||
448 | + int fmt; | ||
449 | |||
450 | options = qemu_opts_to_qdict(opts, NULL); | ||
451 | qdict_extract_subqdict(options, &encryptopts, "encrypt."); | ||
452 | QDECREF(options); | ||
453 | |||
454 | - if (!g_str_equal(encryptfmt, "aes")) { | ||
455 | - error_setg(errp, "Unknown encryption format '%s', expected 'aes'", | ||
456 | - encryptfmt); | ||
457 | - ret = -EINVAL; | ||
458 | - goto out; | ||
459 | + fmt = qcow2_crypt_method_from_format(encryptfmt); | ||
460 | + | ||
461 | + switch (fmt) { | ||
462 | + case QCOW_CRYPT_LUKS: | ||
463 | + cryptoopts = block_crypto_create_opts_init( | ||
464 | + Q_CRYPTO_BLOCK_FORMAT_LUKS, encryptopts, errp); | ||
465 | + break; | ||
466 | + case QCOW_CRYPT_AES: | ||
467 | + cryptoopts = block_crypto_create_opts_init( | ||
468 | + Q_CRYPTO_BLOCK_FORMAT_QCOW, encryptopts, errp); | ||
469 | + break; | ||
470 | + default: | ||
471 | + error_setg(errp, "Unknown encryption format '%s'", encryptfmt); | ||
472 | + break; | ||
473 | } | ||
474 | - cryptoopts = block_crypto_create_opts_init( | ||
475 | - Q_CRYPTO_BLOCK_FORMAT_QCOW, encryptopts, errp); | ||
476 | if (!cryptoopts) { | ||
477 | ret = -EINVAL; | ||
478 | goto out; | ||
479 | } | ||
480 | - s->crypt_method_header = QCOW_CRYPT_AES; | ||
481 | + s->crypt_method_header = fmt; | ||
482 | |||
483 | crypto = qcrypto_block_create(cryptoopts, | ||
484 | - NULL, NULL, | ||
485 | + qcow2_crypto_hdr_init_func, | ||
486 | + qcow2_crypto_hdr_write_func, | ||
487 | bs, errp); | ||
488 | if (!crypto) { | ||
489 | ret = -EINVAL; | ||
490 | @@ -XXX,XX +XXX,XX @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, | ||
491 | const char *compat = NULL; | ||
492 | uint64_t cluster_size = s->cluster_size; | ||
493 | bool encrypt; | ||
494 | + int encformat; | ||
495 | int refcount_bits = s->refcount_bits; | ||
496 | Error *local_err = NULL; | ||
497 | int ret; | ||
498 | @@ -XXX,XX +XXX,XX @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, | ||
499 | error_report("Changing the encryption flag is not supported"); | ||
500 | return -ENOTSUP; | ||
501 | } | ||
502 | + } else if (!strcmp(desc->name, BLOCK_OPT_ENCRYPT_FORMAT)) { | ||
503 | + encformat = qcow2_crypt_method_from_format( | ||
504 | + qemu_opt_get(opts, BLOCK_OPT_ENCRYPT_FORMAT)); | ||
505 | + | ||
506 | + if (encformat != s->crypt_method_header) { | ||
507 | + error_report("Changing the encryption format is not supported"); | ||
508 | + return -ENOTSUP; | ||
509 | + } | ||
510 | } else if (!strcmp(desc->name, BLOCK_OPT_CLUSTER_SIZE)) { | ||
511 | cluster_size = qemu_opt_get_size(opts, BLOCK_OPT_CLUSTER_SIZE, | ||
512 | cluster_size); | ||
513 | @@ -XXX,XX +XXX,XX @@ static QemuOptsList qcow2_create_opts = { | ||
514 | { | ||
515 | .name = BLOCK_OPT_ENCRYPT_FORMAT, | ||
516 | .type = QEMU_OPT_STRING, | ||
517 | - .help = "Encrypt the image, format choices: 'aes'", | ||
518 | + .help = "Encrypt the image, format choices: 'aes', 'luks'", | ||
519 | }, | ||
520 | - BLOCK_CRYPTO_OPT_DEF_QCOW_KEY_SECRET("encrypt."), | ||
521 | + BLOCK_CRYPTO_OPT_DEF_KEY_SECRET("encrypt.", | ||
522 | + "ID of secret providing qcow AES key or LUKS passphrase"), | ||
523 | + BLOCK_CRYPTO_OPT_DEF_LUKS_CIPHER_ALG("encrypt."), | ||
524 | + BLOCK_CRYPTO_OPT_DEF_LUKS_CIPHER_MODE("encrypt."), | ||
525 | + BLOCK_CRYPTO_OPT_DEF_LUKS_IVGEN_ALG("encrypt."), | ||
526 | + BLOCK_CRYPTO_OPT_DEF_LUKS_IVGEN_HASH_ALG("encrypt."), | ||
527 | + BLOCK_CRYPTO_OPT_DEF_LUKS_HASH_ALG("encrypt."), | ||
528 | + BLOCK_CRYPTO_OPT_DEF_LUKS_ITER_TIME("encrypt."), | ||
529 | { | ||
530 | .name = BLOCK_OPT_CLUSTER_SIZE, | ||
531 | .type = QEMU_OPT_SIZE, | ||
532 | diff --git a/block/qcow2.h b/block/qcow2.h | ||
533 | index XXXXXXX..XXXXXXX 100644 | ||
534 | --- a/block/qcow2.h | ||
535 | +++ b/block/qcow2.h | ||
536 | @@ -XXX,XX +XXX,XX @@ | ||
537 | |||
538 | #define QCOW_CRYPT_NONE 0 | ||
539 | #define QCOW_CRYPT_AES 1 | ||
540 | +#define QCOW_CRYPT_LUKS 2 | ||
541 | |||
542 | #define QCOW_MAX_CRYPT_CLUSTERS 32 | ||
543 | #define QCOW_MAX_SNAPSHOTS 65536 | ||
544 | @@ -XXX,XX +XXX,XX @@ typedef struct QCowSnapshot { | ||
545 | struct Qcow2Cache; | ||
546 | typedef struct Qcow2Cache Qcow2Cache; | ||
547 | |||
548 | +typedef struct Qcow2CryptoHeaderExtension { | ||
549 | + uint64_t offset; | ||
550 | + uint64_t length; | ||
551 | +} QEMU_PACKED Qcow2CryptoHeaderExtension; | ||
552 | + | ||
553 | typedef struct Qcow2UnknownHeaderExtension { | ||
554 | uint32_t magic; | ||
555 | uint32_t len; | ||
556 | @@ -XXX,XX +XXX,XX @@ typedef struct BDRVQcow2State { | ||
557 | |||
558 | CoMutex lock; | ||
559 | |||
560 | + Qcow2CryptoHeaderExtension crypto_header; /* QCow2 header extension */ | ||
561 | QCryptoBlockOpenOptions *crypto_opts; /* Disk encryption runtime options */ | ||
562 | QCryptoBlock *crypto; /* Disk encryption format driver */ | ||
563 | + bool crypt_physical_offset; /* Whether to use virtual or physical offset | ||
564 | + for encryption initialization vector tweak */ | ||
565 | uint32_t crypt_method_header; | ||
566 | uint64_t snapshots_offset; | ||
567 | int snapshots_size; | ||
568 | diff --git a/qapi/block-core.json b/qapi/block-core.json | ||
569 | index XXXXXXX..XXXXXXX 100644 | ||
570 | --- a/qapi/block-core.json | ||
571 | +++ b/qapi/block-core.json | ||
572 | @@ -XXX,XX +XXX,XX @@ | ||
573 | # Since: 2.10 | ||
574 | ## | ||
575 | { 'enum': 'BlockdevQcow2EncryptionFormat', | ||
576 | - 'data': [ 'aes' ] } | ||
577 | + 'data': [ 'aes', 'luks' ] } | ||
578 | |||
579 | ## | ||
580 | # @BlockdevQcow2Encryption: | ||
581 | @@ -XXX,XX +XXX,XX @@ | ||
582 | { 'union': 'BlockdevQcow2Encryption', | ||
583 | 'base': { 'format': 'BlockdevQcow2EncryptionFormat' }, | ||
584 | 'discriminator': 'format', | ||
585 | - 'data': { 'aes': 'QCryptoBlockOptionsQCow' } } | ||
586 | + 'data': { 'aes': 'QCryptoBlockOptionsQCow', | ||
587 | + 'luks': 'QCryptoBlockOptionsLUKS'} } | ||
588 | |||
589 | ## | ||
590 | # @BlockdevOptionsQcow2: | ||
591 | diff --git a/tests/qemu-iotests/082.out b/tests/qemu-iotests/082.out | ||
592 | index XXXXXXX..XXXXXXX 100644 | ||
593 | --- a/tests/qemu-iotests/082.out | ||
594 | +++ b/tests/qemu-iotests/082.out | ||
595 | @@ -XXX,XX +XXX,XX @@ compat Compatibility level (0.10 or 1.1) | ||
596 | backing_file File name of a base image | ||
597 | backing_fmt Image format of the base image | ||
598 | encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
599 | -encrypt.format Encrypt the image, format choices: 'aes' | ||
600 | -encrypt.key-secret ID of the secret that provides the AES encryption key | ||
601 | +encrypt.format Encrypt the image, format choices: 'aes', 'luks' | ||
602 | +encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase | ||
603 | +encrypt.cipher-alg Name of encryption cipher algorithm | ||
604 | +encrypt.cipher-mode Name of encryption cipher mode | ||
605 | +encrypt.ivgen-alg Name of IV generator algorithm | ||
606 | +encrypt.ivgen-hash-alg Name of IV generator hash algorithm | ||
607 | +encrypt.hash-alg Name of encryption hash algorithm | ||
608 | +encrypt.iter-time Time to spend in PBKDF in milliseconds | ||
609 | cluster_size qcow2 cluster size | ||
610 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
611 | lazy_refcounts Postpone refcount updates | ||
612 | @@ -XXX,XX +XXX,XX @@ compat Compatibility level (0.10 or 1.1) | ||
613 | backing_file File name of a base image | ||
614 | backing_fmt Image format of the base image | ||
615 | encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
616 | -encrypt.format Encrypt the image, format choices: 'aes' | ||
617 | -encrypt.key-secret ID of the secret that provides the AES encryption key | ||
618 | +encrypt.format Encrypt the image, format choices: 'aes', 'luks' | ||
619 | +encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase | ||
620 | +encrypt.cipher-alg Name of encryption cipher algorithm | ||
621 | +encrypt.cipher-mode Name of encryption cipher mode | ||
622 | +encrypt.ivgen-alg Name of IV generator algorithm | ||
623 | +encrypt.ivgen-hash-alg Name of IV generator hash algorithm | ||
624 | +encrypt.hash-alg Name of encryption hash algorithm | ||
625 | +encrypt.iter-time Time to spend in PBKDF in milliseconds | ||
626 | cluster_size qcow2 cluster size | ||
627 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
628 | lazy_refcounts Postpone refcount updates | ||
629 | @@ -XXX,XX +XXX,XX @@ compat Compatibility level (0.10 or 1.1) | ||
630 | backing_file File name of a base image | ||
631 | backing_fmt Image format of the base image | ||
632 | encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
633 | -encrypt.format Encrypt the image, format choices: 'aes' | ||
634 | -encrypt.key-secret ID of the secret that provides the AES encryption key | ||
635 | +encrypt.format Encrypt the image, format choices: 'aes', 'luks' | ||
636 | +encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase | ||
637 | +encrypt.cipher-alg Name of encryption cipher algorithm | ||
638 | +encrypt.cipher-mode Name of encryption cipher mode | ||
639 | +encrypt.ivgen-alg Name of IV generator algorithm | ||
640 | +encrypt.ivgen-hash-alg Name of IV generator hash algorithm | ||
641 | +encrypt.hash-alg Name of encryption hash algorithm | ||
642 | +encrypt.iter-time Time to spend in PBKDF in milliseconds | ||
643 | cluster_size qcow2 cluster size | ||
644 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
645 | lazy_refcounts Postpone refcount updates | ||
646 | @@ -XXX,XX +XXX,XX @@ compat Compatibility level (0.10 or 1.1) | ||
647 | backing_file File name of a base image | ||
648 | backing_fmt Image format of the base image | ||
649 | encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
650 | -encrypt.format Encrypt the image, format choices: 'aes' | ||
651 | -encrypt.key-secret ID of the secret that provides the AES encryption key | ||
652 | +encrypt.format Encrypt the image, format choices: 'aes', 'luks' | ||
653 | +encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase | ||
654 | +encrypt.cipher-alg Name of encryption cipher algorithm | ||
655 | +encrypt.cipher-mode Name of encryption cipher mode | ||
656 | +encrypt.ivgen-alg Name of IV generator algorithm | ||
657 | +encrypt.ivgen-hash-alg Name of IV generator hash algorithm | ||
658 | +encrypt.hash-alg Name of encryption hash algorithm | ||
659 | +encrypt.iter-time Time to spend in PBKDF in milliseconds | ||
660 | cluster_size qcow2 cluster size | ||
661 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
662 | lazy_refcounts Postpone refcount updates | ||
663 | @@ -XXX,XX +XXX,XX @@ compat Compatibility level (0.10 or 1.1) | ||
664 | backing_file File name of a base image | ||
665 | backing_fmt Image format of the base image | ||
666 | encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
667 | -encrypt.format Encrypt the image, format choices: 'aes' | ||
668 | -encrypt.key-secret ID of the secret that provides the AES encryption key | ||
669 | +encrypt.format Encrypt the image, format choices: 'aes', 'luks' | ||
670 | +encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase | ||
671 | +encrypt.cipher-alg Name of encryption cipher algorithm | ||
672 | +encrypt.cipher-mode Name of encryption cipher mode | ||
673 | +encrypt.ivgen-alg Name of IV generator algorithm | ||
674 | +encrypt.ivgen-hash-alg Name of IV generator hash algorithm | ||
675 | +encrypt.hash-alg Name of encryption hash algorithm | ||
676 | +encrypt.iter-time Time to spend in PBKDF in milliseconds | ||
677 | cluster_size qcow2 cluster size | ||
678 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
679 | lazy_refcounts Postpone refcount updates | ||
680 | @@ -XXX,XX +XXX,XX @@ compat Compatibility level (0.10 or 1.1) | ||
681 | backing_file File name of a base image | ||
682 | backing_fmt Image format of the base image | ||
683 | encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
684 | -encrypt.format Encrypt the image, format choices: 'aes' | ||
685 | -encrypt.key-secret ID of the secret that provides the AES encryption key | ||
686 | +encrypt.format Encrypt the image, format choices: 'aes', 'luks' | ||
687 | +encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase | ||
688 | +encrypt.cipher-alg Name of encryption cipher algorithm | ||
689 | +encrypt.cipher-mode Name of encryption cipher mode | ||
690 | +encrypt.ivgen-alg Name of IV generator algorithm | ||
691 | +encrypt.ivgen-hash-alg Name of IV generator hash algorithm | ||
692 | +encrypt.hash-alg Name of encryption hash algorithm | ||
693 | +encrypt.iter-time Time to spend in PBKDF in milliseconds | ||
694 | cluster_size qcow2 cluster size | ||
695 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
696 | lazy_refcounts Postpone refcount updates | ||
697 | @@ -XXX,XX +XXX,XX @@ compat Compatibility level (0.10 or 1.1) | ||
698 | backing_file File name of a base image | ||
699 | backing_fmt Image format of the base image | ||
700 | encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
701 | -encrypt.format Encrypt the image, format choices: 'aes' | ||
702 | -encrypt.key-secret ID of the secret that provides the AES encryption key | ||
703 | +encrypt.format Encrypt the image, format choices: 'aes', 'luks' | ||
704 | +encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase | ||
705 | +encrypt.cipher-alg Name of encryption cipher algorithm | ||
706 | +encrypt.cipher-mode Name of encryption cipher mode | ||
707 | +encrypt.ivgen-alg Name of IV generator algorithm | ||
708 | +encrypt.ivgen-hash-alg Name of IV generator hash algorithm | ||
709 | +encrypt.hash-alg Name of encryption hash algorithm | ||
710 | +encrypt.iter-time Time to spend in PBKDF in milliseconds | ||
711 | cluster_size qcow2 cluster size | ||
712 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
713 | lazy_refcounts Postpone refcount updates | ||
714 | @@ -XXX,XX +XXX,XX @@ compat Compatibility level (0.10 or 1.1) | ||
715 | backing_file File name of a base image | ||
716 | backing_fmt Image format of the base image | ||
717 | encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
718 | -encrypt.format Encrypt the image, format choices: 'aes' | ||
719 | -encrypt.key-secret ID of the secret that provides the AES encryption key | ||
720 | +encrypt.format Encrypt the image, format choices: 'aes', 'luks' | ||
721 | +encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase | ||
722 | +encrypt.cipher-alg Name of encryption cipher algorithm | ||
723 | +encrypt.cipher-mode Name of encryption cipher mode | ||
724 | +encrypt.ivgen-alg Name of IV generator algorithm | ||
725 | +encrypt.ivgen-hash-alg Name of IV generator hash algorithm | ||
726 | +encrypt.hash-alg Name of encryption hash algorithm | ||
727 | +encrypt.iter-time Time to spend in PBKDF in milliseconds | ||
728 | cluster_size qcow2 cluster size | ||
729 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
730 | lazy_refcounts Postpone refcount updates | ||
731 | @@ -XXX,XX +XXX,XX @@ compat Compatibility level (0.10 or 1.1) | ||
732 | backing_file File name of a base image | ||
733 | backing_fmt Image format of the base image | ||
734 | encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
735 | -encrypt.format Encrypt the image, format choices: 'aes' | ||
736 | -encrypt.key-secret ID of the secret that provides the AES encryption key | ||
737 | +encrypt.format Encrypt the image, format choices: 'aes', 'luks' | ||
738 | +encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase | ||
739 | +encrypt.cipher-alg Name of encryption cipher algorithm | ||
740 | +encrypt.cipher-mode Name of encryption cipher mode | ||
741 | +encrypt.ivgen-alg Name of IV generator algorithm | ||
742 | +encrypt.ivgen-hash-alg Name of IV generator hash algorithm | ||
743 | +encrypt.hash-alg Name of encryption hash algorithm | ||
744 | +encrypt.iter-time Time to spend in PBKDF in milliseconds | ||
745 | cluster_size qcow2 cluster size | ||
746 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
747 | lazy_refcounts Postpone refcount updates | ||
748 | @@ -XXX,XX +XXX,XX @@ compat Compatibility level (0.10 or 1.1) | ||
749 | backing_file File name of a base image | ||
750 | backing_fmt Image format of the base image | ||
751 | encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
752 | -encrypt.format Encrypt the image, format choices: 'aes' | ||
753 | -encrypt.key-secret ID of the secret that provides the AES encryption key | ||
754 | +encrypt.format Encrypt the image, format choices: 'aes', 'luks' | ||
755 | +encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase | ||
756 | +encrypt.cipher-alg Name of encryption cipher algorithm | ||
757 | +encrypt.cipher-mode Name of encryption cipher mode | ||
758 | +encrypt.ivgen-alg Name of IV generator algorithm | ||
759 | +encrypt.ivgen-hash-alg Name of IV generator hash algorithm | ||
760 | +encrypt.hash-alg Name of encryption hash algorithm | ||
761 | +encrypt.iter-time Time to spend in PBKDF in milliseconds | ||
762 | cluster_size qcow2 cluster size | ||
763 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
764 | lazy_refcounts Postpone refcount updates | ||
765 | @@ -XXX,XX +XXX,XX @@ compat Compatibility level (0.10 or 1.1) | ||
766 | backing_file File name of a base image | ||
767 | backing_fmt Image format of the base image | ||
768 | encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
769 | -encrypt.format Encrypt the image, format choices: 'aes' | ||
770 | -encrypt.key-secret ID of the secret that provides the AES encryption key | ||
771 | +encrypt.format Encrypt the image, format choices: 'aes', 'luks' | ||
772 | +encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase | ||
773 | +encrypt.cipher-alg Name of encryption cipher algorithm | ||
774 | +encrypt.cipher-mode Name of encryption cipher mode | ||
775 | +encrypt.ivgen-alg Name of IV generator algorithm | ||
776 | +encrypt.ivgen-hash-alg Name of IV generator hash algorithm | ||
777 | +encrypt.hash-alg Name of encryption hash algorithm | ||
778 | +encrypt.iter-time Time to spend in PBKDF in milliseconds | ||
779 | cluster_size qcow2 cluster size | ||
780 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
781 | lazy_refcounts Postpone refcount updates | ||
782 | @@ -XXX,XX +XXX,XX @@ compat Compatibility level (0.10 or 1.1) | ||
783 | backing_file File name of a base image | ||
784 | backing_fmt Image format of the base image | ||
785 | encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
786 | -encrypt.format Encrypt the image, format choices: 'aes' | ||
787 | -encrypt.key-secret ID of the secret that provides the AES encryption key | ||
788 | +encrypt.format Encrypt the image, format choices: 'aes', 'luks' | ||
789 | +encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase | ||
790 | +encrypt.cipher-alg Name of encryption cipher algorithm | ||
791 | +encrypt.cipher-mode Name of encryption cipher mode | ||
792 | +encrypt.ivgen-alg Name of IV generator algorithm | ||
793 | +encrypt.ivgen-hash-alg Name of IV generator hash algorithm | ||
794 | +encrypt.hash-alg Name of encryption hash algorithm | ||
795 | +encrypt.iter-time Time to spend in PBKDF in milliseconds | ||
796 | cluster_size qcow2 cluster size | ||
797 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
798 | lazy_refcounts Postpone refcount updates | ||
799 | @@ -XXX,XX +XXX,XX @@ compat Compatibility level (0.10 or 1.1) | ||
800 | backing_file File name of a base image | ||
801 | backing_fmt Image format of the base image | ||
802 | encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
803 | -encrypt.format Encrypt the image, format choices: 'aes' | ||
804 | -encrypt.key-secret ID of the secret that provides the AES encryption key | ||
805 | +encrypt.format Encrypt the image, format choices: 'aes', 'luks' | ||
806 | +encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase | ||
807 | +encrypt.cipher-alg Name of encryption cipher algorithm | ||
808 | +encrypt.cipher-mode Name of encryption cipher mode | ||
809 | +encrypt.ivgen-alg Name of IV generator algorithm | ||
810 | +encrypt.ivgen-hash-alg Name of IV generator hash algorithm | ||
811 | +encrypt.hash-alg Name of encryption hash algorithm | ||
812 | +encrypt.iter-time Time to spend in PBKDF in milliseconds | ||
813 | cluster_size qcow2 cluster size | ||
814 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
815 | lazy_refcounts Postpone refcount updates | ||
816 | @@ -XXX,XX +XXX,XX @@ compat Compatibility level (0.10 or 1.1) | ||
817 | backing_file File name of a base image | ||
818 | backing_fmt Image format of the base image | ||
819 | encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
820 | -encrypt.format Encrypt the image, format choices: 'aes' | ||
821 | -encrypt.key-secret ID of the secret that provides the AES encryption key | ||
822 | +encrypt.format Encrypt the image, format choices: 'aes', 'luks' | ||
823 | +encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase | ||
824 | +encrypt.cipher-alg Name of encryption cipher algorithm | ||
825 | +encrypt.cipher-mode Name of encryption cipher mode | ||
826 | +encrypt.ivgen-alg Name of IV generator algorithm | ||
827 | +encrypt.ivgen-hash-alg Name of IV generator hash algorithm | ||
828 | +encrypt.hash-alg Name of encryption hash algorithm | ||
829 | +encrypt.iter-time Time to spend in PBKDF in milliseconds | ||
830 | cluster_size qcow2 cluster size | ||
831 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
832 | lazy_refcounts Postpone refcount updates | ||
833 | @@ -XXX,XX +XXX,XX @@ compat Compatibility level (0.10 or 1.1) | ||
834 | backing_file File name of a base image | ||
835 | backing_fmt Image format of the base image | ||
836 | encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
837 | -encrypt.format Encrypt the image, format choices: 'aes' | ||
838 | -encrypt.key-secret ID of the secret that provides the AES encryption key | ||
839 | +encrypt.format Encrypt the image, format choices: 'aes', 'luks' | ||
840 | +encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase | ||
841 | +encrypt.cipher-alg Name of encryption cipher algorithm | ||
842 | +encrypt.cipher-mode Name of encryption cipher mode | ||
843 | +encrypt.ivgen-alg Name of IV generator algorithm | ||
844 | +encrypt.ivgen-hash-alg Name of IV generator hash algorithm | ||
845 | +encrypt.hash-alg Name of encryption hash algorithm | ||
846 | +encrypt.iter-time Time to spend in PBKDF in milliseconds | ||
847 | cluster_size qcow2 cluster size | ||
848 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
849 | lazy_refcounts Postpone refcount updates | ||
850 | @@ -XXX,XX +XXX,XX @@ compat Compatibility level (0.10 or 1.1) | ||
851 | backing_file File name of a base image | ||
852 | backing_fmt Image format of the base image | ||
853 | encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
854 | -encrypt.format Encrypt the image, format choices: 'aes' | ||
855 | -encrypt.key-secret ID of the secret that provides the AES encryption key | ||
856 | +encrypt.format Encrypt the image, format choices: 'aes', 'luks' | ||
857 | +encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase | ||
858 | +encrypt.cipher-alg Name of encryption cipher algorithm | ||
859 | +encrypt.cipher-mode Name of encryption cipher mode | ||
860 | +encrypt.ivgen-alg Name of IV generator algorithm | ||
861 | +encrypt.ivgen-hash-alg Name of IV generator hash algorithm | ||
862 | +encrypt.hash-alg Name of encryption hash algorithm | ||
863 | +encrypt.iter-time Time to spend in PBKDF in milliseconds | ||
864 | cluster_size qcow2 cluster size | ||
865 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
866 | lazy_refcounts Postpone refcount updates | ||
867 | @@ -XXX,XX +XXX,XX @@ compat Compatibility level (0.10 or 1.1) | ||
868 | backing_file File name of a base image | ||
869 | backing_fmt Image format of the base image | ||
870 | encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
871 | -encrypt.format Encrypt the image, format choices: 'aes' | ||
872 | -encrypt.key-secret ID of the secret that provides the AES encryption key | ||
873 | +encrypt.format Encrypt the image, format choices: 'aes', 'luks' | ||
874 | +encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase | ||
875 | +encrypt.cipher-alg Name of encryption cipher algorithm | ||
876 | +encrypt.cipher-mode Name of encryption cipher mode | ||
877 | +encrypt.ivgen-alg Name of IV generator algorithm | ||
878 | +encrypt.ivgen-hash-alg Name of IV generator hash algorithm | ||
879 | +encrypt.hash-alg Name of encryption hash algorithm | ||
880 | +encrypt.iter-time Time to spend in PBKDF in milliseconds | ||
881 | cluster_size qcow2 cluster size | ||
882 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
883 | lazy_refcounts Postpone refcount updates | ||
884 | @@ -XXX,XX +XXX,XX @@ compat Compatibility level (0.10 or 1.1) | ||
885 | backing_file File name of a base image | ||
886 | backing_fmt Image format of the base image | ||
887 | encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
888 | -encrypt.format Encrypt the image, format choices: 'aes' | ||
889 | -encrypt.key-secret ID of the secret that provides the AES encryption key | ||
890 | +encrypt.format Encrypt the image, format choices: 'aes', 'luks' | ||
891 | +encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase | ||
892 | +encrypt.cipher-alg Name of encryption cipher algorithm | ||
893 | +encrypt.cipher-mode Name of encryption cipher mode | ||
894 | +encrypt.ivgen-alg Name of IV generator algorithm | ||
895 | +encrypt.ivgen-hash-alg Name of IV generator hash algorithm | ||
896 | +encrypt.hash-alg Name of encryption hash algorithm | ||
897 | +encrypt.iter-time Time to spend in PBKDF in milliseconds | ||
898 | cluster_size qcow2 cluster size | ||
899 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
900 | lazy_refcounts Postpone refcount updates | ||
901 | @@ -XXX,XX +XXX,XX @@ compat Compatibility level (0.10 or 1.1) | ||
902 | backing_file File name of a base image | ||
903 | backing_fmt Image format of the base image | ||
904 | encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
905 | -encrypt.format Encrypt the image, format choices: 'aes' | ||
906 | -encrypt.key-secret ID of the secret that provides the AES encryption key | ||
907 | +encrypt.format Encrypt the image, format choices: 'aes', 'luks' | ||
908 | +encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase | ||
909 | +encrypt.cipher-alg Name of encryption cipher algorithm | ||
910 | +encrypt.cipher-mode Name of encryption cipher mode | ||
911 | +encrypt.ivgen-alg Name of IV generator algorithm | ||
912 | +encrypt.ivgen-hash-alg Name of IV generator hash algorithm | ||
913 | +encrypt.hash-alg Name of encryption hash algorithm | ||
914 | +encrypt.iter-time Time to spend in PBKDF in milliseconds | ||
915 | cluster_size qcow2 cluster size | ||
916 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
917 | lazy_refcounts Postpone refcount updates | ||
918 | @@ -XXX,XX +XXX,XX @@ compat Compatibility level (0.10 or 1.1) | ||
919 | backing_file File name of a base image | ||
920 | backing_fmt Image format of the base image | ||
921 | encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
922 | -encrypt.format Encrypt the image, format choices: 'aes' | ||
923 | -encrypt.key-secret ID of the secret that provides the AES encryption key | ||
924 | +encrypt.format Encrypt the image, format choices: 'aes', 'luks' | ||
925 | +encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase | ||
926 | +encrypt.cipher-alg Name of encryption cipher algorithm | ||
927 | +encrypt.cipher-mode Name of encryption cipher mode | ||
928 | +encrypt.ivgen-alg Name of IV generator algorithm | ||
929 | +encrypt.ivgen-hash-alg Name of IV generator hash algorithm | ||
930 | +encrypt.hash-alg Name of encryption hash algorithm | ||
931 | +encrypt.iter-time Time to spend in PBKDF in milliseconds | ||
932 | cluster_size qcow2 cluster size | ||
933 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
934 | lazy_refcounts Postpone refcount updates | ||
935 | @@ -XXX,XX +XXX,XX @@ compat Compatibility level (0.10 or 1.1) | ||
936 | backing_file File name of a base image | ||
937 | backing_fmt Image format of the base image | ||
938 | encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
939 | -encrypt.format Encrypt the image, format choices: 'aes' | ||
940 | -encrypt.key-secret ID of the secret that provides the AES encryption key | ||
941 | +encrypt.format Encrypt the image, format choices: 'aes', 'luks' | ||
942 | +encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase | ||
943 | +encrypt.cipher-alg Name of encryption cipher algorithm | ||
944 | +encrypt.cipher-mode Name of encryption cipher mode | ||
945 | +encrypt.ivgen-alg Name of IV generator algorithm | ||
946 | +encrypt.ivgen-hash-alg Name of IV generator hash algorithm | ||
947 | +encrypt.hash-alg Name of encryption hash algorithm | ||
948 | +encrypt.iter-time Time to spend in PBKDF in milliseconds | ||
949 | cluster_size qcow2 cluster size | ||
950 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
951 | lazy_refcounts Postpone refcount updates | ||
952 | @@ -XXX,XX +XXX,XX @@ compat Compatibility level (0.10 or 1.1) | ||
953 | backing_file File name of a base image | ||
954 | backing_fmt Image format of the base image | ||
955 | encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
956 | -encrypt.format Encrypt the image, format choices: 'aes' | ||
957 | -encrypt.key-secret ID of the secret that provides the AES encryption key | ||
958 | +encrypt.format Encrypt the image, format choices: 'aes', 'luks' | ||
959 | +encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase | ||
960 | +encrypt.cipher-alg Name of encryption cipher algorithm | ||
961 | +encrypt.cipher-mode Name of encryption cipher mode | ||
962 | +encrypt.ivgen-alg Name of IV generator algorithm | ||
963 | +encrypt.ivgen-hash-alg Name of IV generator hash algorithm | ||
964 | +encrypt.hash-alg Name of encryption hash algorithm | ||
965 | +encrypt.iter-time Time to spend in PBKDF in milliseconds | ||
966 | cluster_size qcow2 cluster size | ||
967 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
968 | lazy_refcounts Postpone refcount updates | ||
969 | @@ -XXX,XX +XXX,XX @@ compat Compatibility level (0.10 or 1.1) | ||
970 | backing_file File name of a base image | ||
971 | backing_fmt Image format of the base image | ||
972 | encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
973 | -encrypt.format Encrypt the image, format choices: 'aes' | ||
974 | -encrypt.key-secret ID of the secret that provides the AES encryption key | ||
975 | +encrypt.format Encrypt the image, format choices: 'aes', 'luks' | ||
976 | +encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase | ||
977 | +encrypt.cipher-alg Name of encryption cipher algorithm | ||
978 | +encrypt.cipher-mode Name of encryption cipher mode | ||
979 | +encrypt.ivgen-alg Name of IV generator algorithm | ||
980 | +encrypt.ivgen-hash-alg Name of IV generator hash algorithm | ||
981 | +encrypt.hash-alg Name of encryption hash algorithm | ||
982 | +encrypt.iter-time Time to spend in PBKDF in milliseconds | ||
983 | cluster_size qcow2 cluster size | ||
984 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
985 | lazy_refcounts Postpone refcount updates | ||
986 | @@ -XXX,XX +XXX,XX @@ compat Compatibility level (0.10 or 1.1) | ||
987 | backing_file File name of a base image | ||
988 | backing_fmt Image format of the base image | ||
989 | encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
990 | -encrypt.format Encrypt the image, format choices: 'aes' | ||
991 | -encrypt.key-secret ID of the secret that provides the AES encryption key | ||
992 | +encrypt.format Encrypt the image, format choices: 'aes', 'luks' | ||
993 | +encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase | ||
994 | +encrypt.cipher-alg Name of encryption cipher algorithm | ||
995 | +encrypt.cipher-mode Name of encryption cipher mode | ||
996 | +encrypt.ivgen-alg Name of IV generator algorithm | ||
997 | +encrypt.ivgen-hash-alg Name of IV generator hash algorithm | ||
998 | +encrypt.hash-alg Name of encryption hash algorithm | ||
999 | +encrypt.iter-time Time to spend in PBKDF in milliseconds | ||
1000 | cluster_size qcow2 cluster size | ||
1001 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
1002 | lazy_refcounts Postpone refcount updates | ||
1003 | @@ -XXX,XX +XXX,XX @@ compat Compatibility level (0.10 or 1.1) | ||
1004 | backing_file File name of a base image | ||
1005 | backing_fmt Image format of the base image | ||
1006 | encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
1007 | -encrypt.format Encrypt the image, format choices: 'aes' | ||
1008 | -encrypt.key-secret ID of the secret that provides the AES encryption key | ||
1009 | +encrypt.format Encrypt the image, format choices: 'aes', 'luks' | ||
1010 | +encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase | ||
1011 | +encrypt.cipher-alg Name of encryption cipher algorithm | ||
1012 | +encrypt.cipher-mode Name of encryption cipher mode | ||
1013 | +encrypt.ivgen-alg Name of IV generator algorithm | ||
1014 | +encrypt.ivgen-hash-alg Name of IV generator hash algorithm | ||
1015 | +encrypt.hash-alg Name of encryption hash algorithm | ||
1016 | +encrypt.iter-time Time to spend in PBKDF in milliseconds | ||
1017 | cluster_size qcow2 cluster size | ||
1018 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
1019 | lazy_refcounts Postpone refcount updates | ||
1020 | @@ -XXX,XX +XXX,XX @@ compat Compatibility level (0.10 or 1.1) | ||
1021 | backing_file File name of a base image | ||
1022 | backing_fmt Image format of the base image | ||
1023 | encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
1024 | -encrypt.format Encrypt the image, format choices: 'aes' | ||
1025 | -encrypt.key-secret ID of the secret that provides the AES encryption key | ||
1026 | +encrypt.format Encrypt the image, format choices: 'aes', 'luks' | ||
1027 | +encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase | ||
1028 | +encrypt.cipher-alg Name of encryption cipher algorithm | ||
1029 | +encrypt.cipher-mode Name of encryption cipher mode | ||
1030 | +encrypt.ivgen-alg Name of IV generator algorithm | ||
1031 | +encrypt.ivgen-hash-alg Name of IV generator hash algorithm | ||
1032 | +encrypt.hash-alg Name of encryption hash algorithm | ||
1033 | +encrypt.iter-time Time to spend in PBKDF in milliseconds | ||
1034 | cluster_size qcow2 cluster size | ||
1035 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
1036 | lazy_refcounts Postpone refcount updates | ||
1037 | @@ -XXX,XX +XXX,XX @@ compat Compatibility level (0.10 or 1.1) | ||
1038 | backing_file File name of a base image | ||
1039 | backing_fmt Image format of the base image | ||
1040 | encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
1041 | -encrypt.format Encrypt the image, format choices: 'aes' | ||
1042 | -encrypt.key-secret ID of the secret that provides the AES encryption key | ||
1043 | +encrypt.format Encrypt the image, format choices: 'aes', 'luks' | ||
1044 | +encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase | ||
1045 | +encrypt.cipher-alg Name of encryption cipher algorithm | ||
1046 | +encrypt.cipher-mode Name of encryption cipher mode | ||
1047 | +encrypt.ivgen-alg Name of IV generator algorithm | ||
1048 | +encrypt.ivgen-hash-alg Name of IV generator hash algorithm | ||
1049 | +encrypt.hash-alg Name of encryption hash algorithm | ||
1050 | +encrypt.iter-time Time to spend in PBKDF in milliseconds | ||
1051 | cluster_size qcow2 cluster size | ||
1052 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
1053 | lazy_refcounts Postpone refcount updates | ||
1054 | -- | 160 | -- |
1055 | 1.8.3.1 | 161 | 2.37.3 |
1056 | |||
1057 | diff view generated by jsdifflib |
1 | From: Eric Blake <eblake@redhat.com> | 1 | From: Paolo Bonzini <pbonzini@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | We are gradually converting to byte-based interfaces, as they are | 3 | Callers of coroutine_fn must be coroutine_fn themselves, or the call |
4 | easier to reason about than sector-based. Convert another internal | 4 | must be within "if (qemu_in_coroutine())". Apply coroutine_fn to |
5 | function (no semantic change). | 5 | functions where this holds. |
6 | 6 | ||
7 | Signed-off-by: Eric Blake <eblake@redhat.com> | 7 | Reviewed-by: Alberto Faria <afaria@redhat.com> |
8 | Reviewed-by: John Snow <jsnow@redhat.com> | 8 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
9 | Reviewed-by: Jeff Cody <jcody@redhat.com> | 9 | Message-Id: <20220922084924.201610-16-pbonzini@redhat.com> |
10 | [kwolf: Fixed up coding style] | ||
10 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | 11 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> |
11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
12 | --- | 13 | --- |
13 | block/mirror.c | 20 +++++++++++--------- | 14 | block/copy-before-write.c | 9 +++++---- |
14 | 1 file changed, 11 insertions(+), 9 deletions(-) | 15 | 1 file changed, 5 insertions(+), 4 deletions(-) |
15 | 16 | ||
16 | diff --git a/block/mirror.c b/block/mirror.c | 17 | diff --git a/block/copy-before-write.c b/block/copy-before-write.c |
17 | index XXXXXXX..XXXXXXX 100644 | 18 | index XXXXXXX..XXXXXXX 100644 |
18 | --- a/block/mirror.c | 19 | --- a/block/copy-before-write.c |
19 | +++ b/block/mirror.c | 20 | +++ b/block/copy-before-write.c |
20 | @@ -XXX,XX +XXX,XX @@ static int mirror_do_read(MirrorBlockJob *s, int64_t sector_num, | 21 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn cbw_co_flush(BlockDriverState *bs) |
22 | * It's guaranteed that guest writes will not interact in the region until | ||
23 | * cbw_snapshot_read_unlock() called. | ||
24 | */ | ||
25 | -static BlockReq *cbw_snapshot_read_lock(BlockDriverState *bs, | ||
26 | - int64_t offset, int64_t bytes, | ||
27 | - int64_t *pnum, BdrvChild **file) | ||
28 | +static coroutine_fn BlockReq * | ||
29 | +cbw_snapshot_read_lock(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
30 | + int64_t *pnum, BdrvChild **file) | ||
31 | { | ||
32 | BDRVCopyBeforeWriteState *s = bs->opaque; | ||
33 | BlockReq *req = g_new(BlockReq, 1); | ||
34 | @@ -XXX,XX +XXX,XX @@ static BlockReq *cbw_snapshot_read_lock(BlockDriverState *bs, | ||
35 | return req; | ||
21 | } | 36 | } |
22 | 37 | ||
23 | static void mirror_do_zero_or_discard(MirrorBlockJob *s, | 38 | -static void cbw_snapshot_read_unlock(BlockDriverState *bs, BlockReq *req) |
24 | - int64_t sector_num, | 39 | +static coroutine_fn void |
25 | - int nb_sectors, | 40 | +cbw_snapshot_read_unlock(BlockDriverState *bs, BlockReq *req) |
26 | + int64_t offset, | ||
27 | + uint64_t bytes, | ||
28 | bool is_discard) | ||
29 | { | 41 | { |
30 | MirrorOp *op; | 42 | BDRVCopyBeforeWriteState *s = bs->opaque; |
31 | @@ -XXX,XX +XXX,XX @@ static void mirror_do_zero_or_discard(MirrorBlockJob *s, | ||
32 | * so the freeing in mirror_iteration_done is nop. */ | ||
33 | op = g_new0(MirrorOp, 1); | ||
34 | op->s = s; | ||
35 | - op->offset = sector_num * BDRV_SECTOR_SIZE; | ||
36 | - op->bytes = nb_sectors * BDRV_SECTOR_SIZE; | ||
37 | + op->offset = offset; | ||
38 | + op->bytes = bytes; | ||
39 | |||
40 | s->in_flight++; | ||
41 | - s->bytes_in_flight += nb_sectors * BDRV_SECTOR_SIZE; | ||
42 | + s->bytes_in_flight += bytes; | ||
43 | if (is_discard) { | ||
44 | - blk_aio_pdiscard(s->target, sector_num << BDRV_SECTOR_BITS, | ||
45 | + blk_aio_pdiscard(s->target, offset, | ||
46 | op->bytes, mirror_write_complete, op); | ||
47 | } else { | ||
48 | - blk_aio_pwrite_zeroes(s->target, sector_num * BDRV_SECTOR_SIZE, | ||
49 | + blk_aio_pwrite_zeroes(s->target, offset, | ||
50 | op->bytes, s->unmap ? BDRV_REQ_MAY_UNMAP : 0, | ||
51 | mirror_write_complete, op); | ||
52 | } | ||
53 | @@ -XXX,XX +XXX,XX @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s) | ||
54 | break; | ||
55 | case MIRROR_METHOD_ZERO: | ||
56 | case MIRROR_METHOD_DISCARD: | ||
57 | - mirror_do_zero_or_discard(s, sector_num, io_sectors, | ||
58 | + mirror_do_zero_or_discard(s, sector_num * BDRV_SECTOR_SIZE, | ||
59 | + io_sectors * BDRV_SECTOR_SIZE, | ||
60 | mirror_method == MIRROR_METHOD_DISCARD); | ||
61 | if (write_zeroes_ok) { | ||
62 | io_bytes_acct = 0; | ||
63 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn mirror_dirty_init(MirrorBlockJob *s) | ||
64 | continue; | ||
65 | } | ||
66 | |||
67 | - mirror_do_zero_or_discard(s, sector_num, nb_sectors, false); | ||
68 | + mirror_do_zero_or_discard(s, sector_num * BDRV_SECTOR_SIZE, | ||
69 | + nb_sectors * BDRV_SECTOR_SIZE, false); | ||
70 | sector_num += nb_sectors; | ||
71 | } | ||
72 | 43 | ||
73 | -- | 44 | -- |
74 | 1.8.3.1 | 45 | 2.37.3 |
75 | |||
76 | diff view generated by jsdifflib |
1 | From: Eric Blake <eblake@redhat.com> | 1 | From: Paolo Bonzini <pbonzini@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | We are gradually converting to byte-based interfaces, as they are | 3 | Callers of coroutine_fn must be coroutine_fn themselves, or the call |
4 | easier to reason about than sector-based. Change the internal | 4 | must be within "if (qemu_in_coroutine())". Apply coroutine_fn to |
5 | loop iteration of mirroring to track by bytes instead of sectors | 5 | functions where this holds. |
6 | (although we are still guaranteed that we iterate by steps that | ||
7 | are both sector-aligned and multiples of the granularity). Drop | ||
8 | the now-unused mirror_clip_sectors(). | ||
9 | 6 | ||
10 | Signed-off-by: Eric Blake <eblake@redhat.com> | 7 | Reviewed-by: Alberto Faria <afaria@redhat.com> |
11 | Reviewed-by: John Snow <jsnow@redhat.com> | 8 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
12 | Reviewed-by: Jeff Cody <jcody@redhat.com> | 9 | Message-Id: <20220922084924.201610-17-pbonzini@redhat.com> |
13 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | 10 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> |
14 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
15 | --- | 12 | --- |
16 | block/mirror.c | 105 +++++++++++++++++++++++++-------------------------------- | 13 | block/curl.c | 2 +- |
17 | 1 file changed, 46 insertions(+), 59 deletions(-) | 14 | 1 file changed, 1 insertion(+), 1 deletion(-) |
18 | 15 | ||
19 | diff --git a/block/mirror.c b/block/mirror.c | 16 | diff --git a/block/curl.c b/block/curl.c |
20 | index XXXXXXX..XXXXXXX 100644 | 17 | index XXXXXXX..XXXXXXX 100644 |
21 | --- a/block/mirror.c | 18 | --- a/block/curl.c |
22 | +++ b/block/mirror.c | 19 | +++ b/block/curl.c |
23 | @@ -XXX,XX +XXX,XX @@ static inline int64_t mirror_clip_bytes(MirrorBlockJob *s, | 20 | @@ -XXX,XX +XXX,XX @@ out_noclean: |
24 | return MIN(bytes, s->bdev_length - offset); | 21 | return -EINVAL; |
25 | } | 22 | } |
26 | 23 | ||
27 | -/* Clip nb_sectors relative to sector_num to not exceed end-of-file */ | 24 | -static void curl_setup_preadv(BlockDriverState *bs, CURLAIOCB *acb) |
28 | -static inline int mirror_clip_sectors(MirrorBlockJob *s, | 25 | +static void coroutine_fn curl_setup_preadv(BlockDriverState *bs, CURLAIOCB *acb) |
29 | - int64_t sector_num, | ||
30 | - int nb_sectors) | ||
31 | -{ | ||
32 | - return MIN(nb_sectors, | ||
33 | - s->bdev_length / BDRV_SECTOR_SIZE - sector_num); | ||
34 | -} | ||
35 | - | ||
36 | /* Round offset and/or bytes to target cluster if COW is needed, and | ||
37 | * return the offset of the adjusted tail against original. */ | ||
38 | static int mirror_cow_align(MirrorBlockJob *s, int64_t *offset, | ||
39 | @@ -XXX,XX +XXX,XX @@ static void mirror_do_zero_or_discard(MirrorBlockJob *s, | ||
40 | static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s) | ||
41 | { | 26 | { |
42 | BlockDriverState *source = s->source; | 27 | CURLState *state; |
43 | - int64_t sector_num, first_chunk; | 28 | int running; |
44 | + int64_t offset, first_chunk; | ||
45 | uint64_t delay_ns = 0; | ||
46 | /* At least the first dirty chunk is mirrored in one iteration. */ | ||
47 | int nb_chunks = 1; | ||
48 | - int64_t end = s->bdev_length / BDRV_SECTOR_SIZE; | ||
49 | int sectors_per_chunk = s->granularity >> BDRV_SECTOR_BITS; | ||
50 | bool write_zeroes_ok = bdrv_can_write_zeroes_with_unmap(blk_bs(s->target)); | ||
51 | int max_io_bytes = MAX(s->buf_size / MAX_IN_FLIGHT, MAX_IO_BYTES); | ||
52 | |||
53 | bdrv_dirty_bitmap_lock(s->dirty_bitmap); | ||
54 | - sector_num = bdrv_dirty_iter_next(s->dbi); | ||
55 | - if (sector_num < 0) { | ||
56 | + offset = bdrv_dirty_iter_next(s->dbi) * BDRV_SECTOR_SIZE; | ||
57 | + if (offset < 0) { | ||
58 | bdrv_set_dirty_iter(s->dbi, 0); | ||
59 | - sector_num = bdrv_dirty_iter_next(s->dbi); | ||
60 | + offset = bdrv_dirty_iter_next(s->dbi) * BDRV_SECTOR_SIZE; | ||
61 | trace_mirror_restart_iter(s, bdrv_get_dirty_count(s->dirty_bitmap) * | ||
62 | BDRV_SECTOR_SIZE); | ||
63 | - assert(sector_num >= 0); | ||
64 | + assert(offset >= 0); | ||
65 | } | ||
66 | bdrv_dirty_bitmap_unlock(s->dirty_bitmap); | ||
67 | |||
68 | - first_chunk = sector_num / sectors_per_chunk; | ||
69 | + first_chunk = offset / s->granularity; | ||
70 | while (test_bit(first_chunk, s->in_flight_bitmap)) { | ||
71 | - trace_mirror_yield_in_flight(s, sector_num * BDRV_SECTOR_SIZE, | ||
72 | - s->in_flight); | ||
73 | + trace_mirror_yield_in_flight(s, offset, s->in_flight); | ||
74 | mirror_wait_for_io(s); | ||
75 | } | ||
76 | |||
77 | @@ -XXX,XX +XXX,XX @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s) | ||
78 | /* Find the number of consective dirty chunks following the first dirty | ||
79 | * one, and wait for in flight requests in them. */ | ||
80 | bdrv_dirty_bitmap_lock(s->dirty_bitmap); | ||
81 | - while (nb_chunks * sectors_per_chunk < (s->buf_size >> BDRV_SECTOR_BITS)) { | ||
82 | + while (nb_chunks * s->granularity < s->buf_size) { | ||
83 | int64_t next_dirty; | ||
84 | - int64_t next_sector = sector_num + nb_chunks * sectors_per_chunk; | ||
85 | - int64_t next_chunk = next_sector / sectors_per_chunk; | ||
86 | - if (next_sector >= end || | ||
87 | - !bdrv_get_dirty_locked(source, s->dirty_bitmap, next_sector)) { | ||
88 | + int64_t next_offset = offset + nb_chunks * s->granularity; | ||
89 | + int64_t next_chunk = next_offset / s->granularity; | ||
90 | + if (next_offset >= s->bdev_length || | ||
91 | + !bdrv_get_dirty_locked(source, s->dirty_bitmap, | ||
92 | + next_offset >> BDRV_SECTOR_BITS)) { | ||
93 | break; | ||
94 | } | ||
95 | if (test_bit(next_chunk, s->in_flight_bitmap)) { | ||
96 | break; | ||
97 | } | ||
98 | |||
99 | - next_dirty = bdrv_dirty_iter_next(s->dbi); | ||
100 | - if (next_dirty > next_sector || next_dirty < 0) { | ||
101 | + next_dirty = bdrv_dirty_iter_next(s->dbi) * BDRV_SECTOR_SIZE; | ||
102 | + if (next_dirty > next_offset || next_dirty < 0) { | ||
103 | /* The bitmap iterator's cache is stale, refresh it */ | ||
104 | - bdrv_set_dirty_iter(s->dbi, next_sector); | ||
105 | - next_dirty = bdrv_dirty_iter_next(s->dbi); | ||
106 | + bdrv_set_dirty_iter(s->dbi, next_offset >> BDRV_SECTOR_BITS); | ||
107 | + next_dirty = bdrv_dirty_iter_next(s->dbi) * BDRV_SECTOR_SIZE; | ||
108 | } | ||
109 | - assert(next_dirty == next_sector); | ||
110 | + assert(next_dirty == next_offset); | ||
111 | nb_chunks++; | ||
112 | } | ||
113 | |||
114 | @@ -XXX,XX +XXX,XX @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s) | ||
115 | * calling bdrv_get_block_status_above could yield - if some blocks are | ||
116 | * marked dirty in this window, we need to know. | ||
117 | */ | ||
118 | - bdrv_reset_dirty_bitmap_locked(s->dirty_bitmap, sector_num, | ||
119 | - nb_chunks * sectors_per_chunk); | ||
120 | + bdrv_reset_dirty_bitmap_locked(s->dirty_bitmap, offset >> BDRV_SECTOR_BITS, | ||
121 | + nb_chunks * sectors_per_chunk); | ||
122 | bdrv_dirty_bitmap_unlock(s->dirty_bitmap); | ||
123 | |||
124 | - bitmap_set(s->in_flight_bitmap, sector_num / sectors_per_chunk, nb_chunks); | ||
125 | - while (nb_chunks > 0 && sector_num < end) { | ||
126 | + bitmap_set(s->in_flight_bitmap, offset / s->granularity, nb_chunks); | ||
127 | + while (nb_chunks > 0 && offset < s->bdev_length) { | ||
128 | int64_t ret; | ||
129 | int io_sectors; | ||
130 | + unsigned int io_bytes; | ||
131 | int64_t io_bytes_acct; | ||
132 | BlockDriverState *file; | ||
133 | enum MirrorMethod { | ||
134 | @@ -XXX,XX +XXX,XX @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s) | ||
135 | MIRROR_METHOD_DISCARD | ||
136 | } mirror_method = MIRROR_METHOD_COPY; | ||
137 | |||
138 | - assert(!(sector_num % sectors_per_chunk)); | ||
139 | - ret = bdrv_get_block_status_above(source, NULL, sector_num, | ||
140 | + assert(!(offset % s->granularity)); | ||
141 | + ret = bdrv_get_block_status_above(source, NULL, | ||
142 | + offset >> BDRV_SECTOR_BITS, | ||
143 | nb_chunks * sectors_per_chunk, | ||
144 | &io_sectors, &file); | ||
145 | + io_bytes = io_sectors * BDRV_SECTOR_SIZE; | ||
146 | if (ret < 0) { | ||
147 | - io_sectors = MIN(nb_chunks * sectors_per_chunk, | ||
148 | - max_io_bytes >> BDRV_SECTOR_BITS); | ||
149 | + io_bytes = MIN(nb_chunks * s->granularity, max_io_bytes); | ||
150 | } else if (ret & BDRV_BLOCK_DATA) { | ||
151 | - io_sectors = MIN(io_sectors, max_io_bytes >> BDRV_SECTOR_BITS); | ||
152 | + io_bytes = MIN(io_bytes, max_io_bytes); | ||
153 | } | ||
154 | |||
155 | - io_sectors -= io_sectors % sectors_per_chunk; | ||
156 | - if (io_sectors < sectors_per_chunk) { | ||
157 | - io_sectors = sectors_per_chunk; | ||
158 | + io_bytes -= io_bytes % s->granularity; | ||
159 | + if (io_bytes < s->granularity) { | ||
160 | + io_bytes = s->granularity; | ||
161 | } else if (ret >= 0 && !(ret & BDRV_BLOCK_DATA)) { | ||
162 | - int64_t target_sector_num; | ||
163 | - int target_nb_sectors; | ||
164 | - bdrv_round_sectors_to_clusters(blk_bs(s->target), sector_num, | ||
165 | - io_sectors, &target_sector_num, | ||
166 | - &target_nb_sectors); | ||
167 | - if (target_sector_num == sector_num && | ||
168 | - target_nb_sectors == io_sectors) { | ||
169 | + int64_t target_offset; | ||
170 | + unsigned int target_bytes; | ||
171 | + bdrv_round_to_clusters(blk_bs(s->target), offset, io_bytes, | ||
172 | + &target_offset, &target_bytes); | ||
173 | + if (target_offset == offset && | ||
174 | + target_bytes == io_bytes) { | ||
175 | mirror_method = ret & BDRV_BLOCK_ZERO ? | ||
176 | MIRROR_METHOD_ZERO : | ||
177 | MIRROR_METHOD_DISCARD; | ||
178 | @@ -XXX,XX +XXX,XX @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s) | ||
179 | } | ||
180 | |||
181 | while (s->in_flight >= MAX_IN_FLIGHT) { | ||
182 | - trace_mirror_yield_in_flight(s, sector_num * BDRV_SECTOR_SIZE, | ||
183 | - s->in_flight); | ||
184 | + trace_mirror_yield_in_flight(s, offset, s->in_flight); | ||
185 | mirror_wait_for_io(s); | ||
186 | } | ||
187 | |||
188 | @@ -XXX,XX +XXX,XX @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s) | ||
189 | return 0; | ||
190 | } | ||
191 | |||
192 | - io_sectors = mirror_clip_sectors(s, sector_num, io_sectors); | ||
193 | + io_bytes = mirror_clip_bytes(s, offset, io_bytes); | ||
194 | switch (mirror_method) { | ||
195 | case MIRROR_METHOD_COPY: | ||
196 | - io_bytes_acct = mirror_do_read(s, sector_num * BDRV_SECTOR_SIZE, | ||
197 | - io_sectors * BDRV_SECTOR_SIZE); | ||
198 | - io_sectors = io_bytes_acct / BDRV_SECTOR_SIZE; | ||
199 | + io_bytes = io_bytes_acct = mirror_do_read(s, offset, io_bytes); | ||
200 | break; | ||
201 | case MIRROR_METHOD_ZERO: | ||
202 | case MIRROR_METHOD_DISCARD: | ||
203 | - mirror_do_zero_or_discard(s, sector_num * BDRV_SECTOR_SIZE, | ||
204 | - io_sectors * BDRV_SECTOR_SIZE, | ||
205 | + mirror_do_zero_or_discard(s, offset, io_bytes, | ||
206 | mirror_method == MIRROR_METHOD_DISCARD); | ||
207 | if (write_zeroes_ok) { | ||
208 | io_bytes_acct = 0; | ||
209 | } else { | ||
210 | - io_bytes_acct = io_sectors * BDRV_SECTOR_SIZE; | ||
211 | + io_bytes_acct = io_bytes; | ||
212 | } | ||
213 | break; | ||
214 | default: | ||
215 | abort(); | ||
216 | } | ||
217 | - assert(io_sectors); | ||
218 | - sector_num += io_sectors; | ||
219 | - nb_chunks -= DIV_ROUND_UP(io_sectors, sectors_per_chunk); | ||
220 | + assert(io_bytes); | ||
221 | + offset += io_bytes; | ||
222 | + nb_chunks -= DIV_ROUND_UP(io_bytes, s->granularity); | ||
223 | if (s->common.speed) { | ||
224 | delay_ns = ratelimit_calculate_delay(&s->limit, io_bytes_acct); | ||
225 | } | ||
226 | -- | 29 | -- |
227 | 1.8.3.1 | 30 | 2.37.3 |
228 | |||
229 | diff view generated by jsdifflib |
1 | From: Eric Blake <eblake@redhat.com> | 1 | From: Paolo Bonzini <pbonzini@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Rather than having a void function that modifies its input | 3 | Callers of coroutine_fn must be coroutine_fn themselves, or the call |
4 | in-place as the output, change the signature to reduce a layer | 4 | must be within "if (qemu_in_coroutine())". Apply coroutine_fn to |
5 | of indirection and return the result. | 5 | functions where this holds. |
6 | 6 | ||
7 | Suggested-by: John Snow <jsnow@redhat.com> | 7 | Reviewed-by: Alberto Faria <afaria@redhat.com> |
8 | Signed-off-by: Eric Blake <eblake@redhat.com> | 8 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
9 | Reviewed-by: John Snow <jsnow@redhat.com> | 9 | Message-Id: <20220922084924.201610-18-pbonzini@redhat.com> |
10 | Reviewed-by: Jeff Cody <jcody@redhat.com> | ||
11 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | 10 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> |
12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
13 | --- | 12 | --- |
14 | block/mirror.c | 15 ++++++++------- | 13 | block/qed.c | 4 ++-- |
15 | 1 file changed, 8 insertions(+), 7 deletions(-) | 14 | 1 file changed, 2 insertions(+), 2 deletions(-) |
16 | 15 | ||
17 | diff --git a/block/mirror.c b/block/mirror.c | 16 | diff --git a/block/qed.c b/block/qed.c |
18 | index XXXXXXX..XXXXXXX 100644 | 17 | index XXXXXXX..XXXXXXX 100644 |
19 | --- a/block/mirror.c | 18 | --- a/block/qed.c |
20 | +++ b/block/mirror.c | 19 | +++ b/block/qed.c |
21 | @@ -XXX,XX +XXX,XX @@ static void mirror_read_complete(void *opaque, int ret) | 20 | @@ -XXX,XX +XXX,XX @@ static CachedL2Table *qed_new_l2_table(BDRVQEDState *s) |
22 | aio_context_release(blk_get_aio_context(s->common.blk)); | 21 | return l2_table; |
23 | } | 22 | } |
24 | 23 | ||
25 | -static inline void mirror_clip_sectors(MirrorBlockJob *s, | 24 | -static bool qed_plug_allocating_write_reqs(BDRVQEDState *s) |
26 | - int64_t sector_num, | 25 | +static bool coroutine_fn qed_plug_allocating_write_reqs(BDRVQEDState *s) |
27 | - int *nb_sectors) | ||
28 | +static inline int mirror_clip_sectors(MirrorBlockJob *s, | ||
29 | + int64_t sector_num, | ||
30 | + int nb_sectors) | ||
31 | { | 26 | { |
32 | - *nb_sectors = MIN(*nb_sectors, | 27 | qemu_co_mutex_lock(&s->table_lock); |
33 | - s->bdev_length / BDRV_SECTOR_SIZE - sector_num); | 28 | |
34 | + return MIN(nb_sectors, | 29 | @@ -XXX,XX +XXX,XX @@ static bool qed_plug_allocating_write_reqs(BDRVQEDState *s) |
35 | + s->bdev_length / BDRV_SECTOR_SIZE - sector_num); | 30 | return true; |
36 | } | 31 | } |
37 | 32 | ||
38 | /* Round sector_num and/or nb_sectors to target cluster if COW is needed, and | 33 | -static void qed_unplug_allocating_write_reqs(BDRVQEDState *s) |
39 | @@ -XXX,XX +XXX,XX @@ static int mirror_cow_align(MirrorBlockJob *s, | 34 | +static void coroutine_fn qed_unplug_allocating_write_reqs(BDRVQEDState *s) |
40 | } | 35 | { |
41 | /* Clipping may result in align_nb_sectors unaligned to chunk boundary, but | 36 | qemu_co_mutex_lock(&s->table_lock); |
42 | * that doesn't matter because it's already the end of source image. */ | 37 | assert(s->allocating_write_reqs_plugged); |
43 | - mirror_clip_sectors(s, align_sector_num, &align_nb_sectors); | ||
44 | + align_nb_sectors = mirror_clip_sectors(s, align_sector_num, | ||
45 | + align_nb_sectors); | ||
46 | |||
47 | ret = align_sector_num + align_nb_sectors - (*sector_num + *nb_sectors); | ||
48 | *sector_num = align_sector_num; | ||
49 | @@ -XXX,XX +XXX,XX @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s) | ||
50 | return 0; | ||
51 | } | ||
52 | |||
53 | - mirror_clip_sectors(s, sector_num, &io_sectors); | ||
54 | + io_sectors = mirror_clip_sectors(s, sector_num, io_sectors); | ||
55 | switch (mirror_method) { | ||
56 | case MIRROR_METHOD_COPY: | ||
57 | io_sectors = mirror_do_read(s, sector_num, io_sectors); | ||
58 | -- | 38 | -- |
59 | 1.8.3.1 | 39 | 2.37.3 |
60 | |||
61 | diff view generated by jsdifflib |
1 | From: Hervé Poussineau <hpoussin@reactos.org> | 1 | From: Paolo Bonzini <pbonzini@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | This was a complete mess. On 2299 indented lines: | 3 | Callers of coroutine_fn must be coroutine_fn themselves, or the call |
4 | - 1329 were with spaces only | 4 | must be within "if (qemu_in_coroutine())". Apply coroutine_fn to |
5 | - 617 with tabulations only | 5 | functions where this holds. |
6 | - 353 with spaces and tabulations | ||
7 | 6 | ||
8 | Signed-off-by: Hervé Poussineau <hpoussin@reactos.org> | 7 | Reviewed-by: Alberto Faria <afaria@redhat.com> |
8 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> | ||
9 | Message-Id: <20220922084924.201610-19-pbonzini@redhat.com> | ||
10 | [kwolf: Fixed up coding style] | ||
11 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
9 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
10 | --- | 13 | --- |
11 | block/vvfat.c | 2054 ++++++++++++++++++++++++++++----------------------------- | 14 | block/quorum.c | 36 +++++++++++++++++++----------------- |
12 | 1 file changed, 1027 insertions(+), 1027 deletions(-) | 15 | 1 file changed, 19 insertions(+), 17 deletions(-) |
13 | 16 | ||
14 | diff --git a/block/vvfat.c b/block/vvfat.c | 17 | diff --git a/block/quorum.c b/block/quorum.c |
15 | index XXXXXXX..XXXXXXX 100644 | 18 | index XXXXXXX..XXXXXXX 100644 |
16 | --- a/block/vvfat.c | 19 | --- a/block/quorum.c |
17 | +++ b/block/vvfat.c | 20 | +++ b/block/quorum.c |
18 | @@ -XXX,XX +XXX,XX @@ static inline void* array_get(array_t* array,unsigned int index) { | 21 | @@ -XXX,XX +XXX,XX @@ static bool quorum_64bits_compare(QuorumVoteValue *a, QuorumVoteValue *b) |
19 | static inline int array_ensure_allocated(array_t* array, int index) | 22 | return a->l == b->l; |
23 | } | ||
24 | |||
25 | -static QuorumAIOCB *quorum_aio_get(BlockDriverState *bs, | ||
26 | - QEMUIOVector *qiov, | ||
27 | - uint64_t offset, | ||
28 | - uint64_t bytes, | ||
29 | - int flags) | ||
30 | +static QuorumAIOCB *coroutine_fn quorum_aio_get(BlockDriverState *bs, | ||
31 | + QEMUIOVector *qiov, | ||
32 | + uint64_t offset, uint64_t bytes, | ||
33 | + int flags) | ||
20 | { | 34 | { |
21 | if((index + 1) * array->item_size > array->size) { | 35 | BDRVQuorumState *s = bs->opaque; |
22 | - int new_size = (index + 32) * array->item_size; | 36 | QuorumAIOCB *acb = g_new(QuorumAIOCB, 1); |
23 | - array->pointer = g_realloc(array->pointer, new_size); | 37 | @@ -XXX,XX +XXX,XX @@ static void quorum_report_bad_versions(BDRVQuorumState *s, |
24 | - if (!array->pointer) | ||
25 | - return -1; | ||
26 | - array->size = new_size; | ||
27 | - array->next = index + 1; | ||
28 | + int new_size = (index + 32) * array->item_size; | ||
29 | + array->pointer = g_realloc(array->pointer, new_size); | ||
30 | + if (!array->pointer) | ||
31 | + return -1; | ||
32 | + array->size = new_size; | ||
33 | + array->next = index + 1; | ||
34 | } | ||
35 | |||
36 | return 0; | ||
37 | @@ -XXX,XX +XXX,XX @@ static inline void* array_get_next(array_t* array) { | ||
38 | unsigned int next = array->next; | ||
39 | |||
40 | if (array_ensure_allocated(array, next) < 0) | ||
41 | - return NULL; | ||
42 | + return NULL; | ||
43 | |||
44 | array->next = next + 1; | ||
45 | return array_get(array, next); | ||
46 | @@ -XXX,XX +XXX,XX @@ static inline void* array_get_next(array_t* array) { | ||
47 | |||
48 | static inline void* array_insert(array_t* array,unsigned int index,unsigned int count) { | ||
49 | if((array->next+count)*array->item_size>array->size) { | ||
50 | - int increment=count*array->item_size; | ||
51 | - array->pointer=g_realloc(array->pointer,array->size+increment); | ||
52 | - if(!array->pointer) | ||
53 | + int increment=count*array->item_size; | ||
54 | + array->pointer=g_realloc(array->pointer,array->size+increment); | ||
55 | + if(!array->pointer) | ||
56 | return NULL; | ||
57 | - array->size+=increment; | ||
58 | + array->size+=increment; | ||
59 | } | ||
60 | memmove(array->pointer+(index+count)*array->item_size, | ||
61 | - array->pointer+index*array->item_size, | ||
62 | - (array->next-index)*array->item_size); | ||
63 | + array->pointer+index*array->item_size, | ||
64 | + (array->next-index)*array->item_size); | ||
65 | array->next+=count; | ||
66 | return array->pointer+index*array->item_size; | ||
67 | } | ||
68 | @@ -XXX,XX +XXX,XX @@ static inline int array_roll(array_t* array,int index_to,int index_from,int coun | ||
69 | int is; | ||
70 | |||
71 | if(!array || | ||
72 | - index_to<0 || index_to>=array->next || | ||
73 | - index_from<0 || index_from>=array->next) | ||
74 | - return -1; | ||
75 | + index_to<0 || index_to>=array->next || | ||
76 | + index_from<0 || index_from>=array->next) | ||
77 | + return -1; | ||
78 | |||
79 | if(index_to==index_from) | ||
80 | - return 0; | ||
81 | + return 0; | ||
82 | |||
83 | is=array->item_size; | ||
84 | from=array->pointer+index_from*is; | ||
85 | @@ -XXX,XX +XXX,XX @@ static inline int array_roll(array_t* array,int index_to,int index_from,int coun | ||
86 | memcpy(buf,from,is*count); | ||
87 | |||
88 | if(index_to<index_from) | ||
89 | - memmove(to+is*count,to,from-to); | ||
90 | + memmove(to+is*count,to,from-to); | ||
91 | else | ||
92 | - memmove(from,from+is*count,to-from); | ||
93 | + memmove(from,from+is*count,to-from); | ||
94 | |||
95 | memcpy(to,buf,is*count); | ||
96 | |||
97 | @@ -XXX,XX +XXX,XX @@ static inline int array_remove_slice(array_t* array,int index, int count) | ||
98 | assert(count > 0); | ||
99 | assert(index + count <= array->next); | ||
100 | if(array_roll(array,array->next-1,index,count)) | ||
101 | - return -1; | ||
102 | + return -1; | ||
103 | array->next -= count; | ||
104 | return 0; | ||
105 | } | ||
106 | @@ -XXX,XX +XXX,XX @@ typedef struct bootsector_t { | ||
107 | uint32_t total_sectors; | ||
108 | union { | ||
109 | struct { | ||
110 | - uint8_t drive_number; | ||
111 | - uint8_t current_head; | ||
112 | - uint8_t signature; | ||
113 | - uint32_t id; | ||
114 | - uint8_t volume_label[11]; | ||
115 | - } QEMU_PACKED fat16; | ||
116 | - struct { | ||
117 | - uint32_t sectors_per_fat; | ||
118 | - uint16_t flags; | ||
119 | - uint8_t major,minor; | ||
120 | - uint32_t first_cluster_of_root_directory; | ||
121 | - uint16_t info_sector; | ||
122 | - uint16_t backup_boot_sector; | ||
123 | - uint16_t ignored; | ||
124 | - } QEMU_PACKED fat32; | ||
125 | + uint8_t drive_number; | ||
126 | + uint8_t current_head; | ||
127 | + uint8_t signature; | ||
128 | + uint32_t id; | ||
129 | + uint8_t volume_label[11]; | ||
130 | + } QEMU_PACKED fat16; | ||
131 | + struct { | ||
132 | + uint32_t sectors_per_fat; | ||
133 | + uint16_t flags; | ||
134 | + uint8_t major,minor; | ||
135 | + uint32_t first_cluster_of_root_directory; | ||
136 | + uint16_t info_sector; | ||
137 | + uint16_t backup_boot_sector; | ||
138 | + uint16_t ignored; | ||
139 | + } QEMU_PACKED fat32; | ||
140 | } u; | ||
141 | uint8_t fat_type[8]; | ||
142 | uint8_t ignored[0x1c0]; | ||
143 | @@ -XXX,XX +XXX,XX @@ typedef struct mapping_t { | ||
144 | /* the clusters of a file may be in any order; this points to the first */ | ||
145 | int first_mapping_index; | ||
146 | union { | ||
147 | - /* offset is | ||
148 | - * - the offset in the file (in clusters) for a file, or | ||
149 | - * - the next cluster of the directory for a directory, and | ||
150 | - * - the address of the buffer for a faked entry | ||
151 | - */ | ||
152 | - struct { | ||
153 | - uint32_t offset; | ||
154 | - } file; | ||
155 | - struct { | ||
156 | - int parent_mapping_index; | ||
157 | - int first_dir_index; | ||
158 | - } dir; | ||
159 | + /* offset is | ||
160 | + * - the offset in the file (in clusters) for a file, or | ||
161 | + * - the next cluster of the directory for a directory, and | ||
162 | + * - the address of the buffer for a faked entry | ||
163 | + */ | ||
164 | + struct { | ||
165 | + uint32_t offset; | ||
166 | + } file; | ||
167 | + struct { | ||
168 | + int parent_mapping_index; | ||
169 | + int first_dir_index; | ||
170 | + } dir; | ||
171 | } info; | ||
172 | /* path contains the full path, i.e. it always starts with s->path */ | ||
173 | char* path; | ||
174 | |||
175 | enum { MODE_UNDEFINED = 0, MODE_NORMAL = 1, MODE_MODIFIED = 2, | ||
176 | - MODE_DIRECTORY = 4, MODE_FAKED = 8, | ||
177 | - MODE_DELETED = 16, MODE_RENAMED = 32 } mode; | ||
178 | + MODE_DIRECTORY = 4, MODE_FAKED = 8, | ||
179 | + MODE_DELETED = 16, MODE_RENAMED = 32 } mode; | ||
180 | int read_only; | ||
181 | } mapping_t; | ||
182 | |||
183 | @@ -XXX,XX +XXX,XX @@ static inline int short2long_name(char* dest,const char* src) | ||
184 | int len; | ||
185 | for(i=0;i<129 && src[i];i++) { | ||
186 | dest[2*i]=src[i]; | ||
187 | - dest[2*i+1]=0; | ||
188 | + dest[2*i+1]=0; | ||
189 | } | ||
190 | len=2*i; | ||
191 | dest[2*i]=dest[2*i+1]=0; | ||
192 | for(i=2*i+2;(i%26);i++) | ||
193 | - dest[i]=0xff; | ||
194 | + dest[i]=0xff; | ||
195 | return len; | ||
196 | } | ||
197 | |||
198 | @@ -XXX,XX +XXX,XX @@ static inline direntry_t* create_long_filename(BDRVVVFATState* s,const char* fil | ||
199 | direntry_t* entry; | ||
200 | |||
201 | for(i=0;i<number_of_entries;i++) { | ||
202 | - entry=array_get_next(&(s->directory)); | ||
203 | - entry->attributes=0xf; | ||
204 | - entry->reserved[0]=0; | ||
205 | - entry->begin=0; | ||
206 | - entry->name[0]=(number_of_entries-i)|(i==0?0x40:0); | ||
207 | + entry=array_get_next(&(s->directory)); | ||
208 | + entry->attributes=0xf; | ||
209 | + entry->reserved[0]=0; | ||
210 | + entry->begin=0; | ||
211 | + entry->name[0]=(number_of_entries-i)|(i==0?0x40:0); | ||
212 | } | ||
213 | for(i=0;i<26*number_of_entries;i++) { | ||
214 | - int offset=(i%26); | ||
215 | - if(offset<10) offset=1+offset; | ||
216 | - else if(offset<22) offset=14+offset-10; | ||
217 | - else offset=28+offset-22; | ||
218 | - entry=array_get(&(s->directory),s->directory.next-1-(i/26)); | ||
219 | - entry->name[offset]=buffer[i]; | ||
220 | + int offset=(i%26); | ||
221 | + if(offset<10) offset=1+offset; | ||
222 | + else if(offset<22) offset=14+offset-10; | ||
223 | + else offset=28+offset-22; | ||
224 | + entry=array_get(&(s->directory),s->directory.next-1-(i/26)); | ||
225 | + entry->name[offset]=buffer[i]; | ||
226 | } | ||
227 | return array_get(&(s->directory),s->directory.next-number_of_entries); | ||
228 | } | ||
229 | @@ -XXX,XX +XXX,XX @@ static char is_long_name(const direntry_t* direntry) | ||
230 | static char is_short_name(const direntry_t* direntry) | ||
231 | { | ||
232 | return !is_volume_label(direntry) && !is_long_name(direntry) | ||
233 | - && !is_free(direntry); | ||
234 | + && !is_free(direntry); | ||
235 | } | ||
236 | |||
237 | static char is_directory(const direntry_t* direntry) | ||
238 | @@ -XXX,XX +XXX,XX @@ static uint16_t fat_datetime(time_t time,int return_time) { | ||
239 | t = &t1; | ||
240 | localtime_r(&time,t); | ||
241 | if(return_time) | ||
242 | - return cpu_to_le16((t->tm_sec/2)|(t->tm_min<<5)|(t->tm_hour<<11)); | ||
243 | + return cpu_to_le16((t->tm_sec/2)|(t->tm_min<<5)|(t->tm_hour<<11)); | ||
244 | return cpu_to_le16((t->tm_mday)|((t->tm_mon+1)<<5)|((t->tm_year-80)<<9)); | ||
245 | } | ||
246 | |||
247 | static inline void fat_set(BDRVVVFATState* s,unsigned int cluster,uint32_t value) | ||
248 | { | ||
249 | if(s->fat_type==32) { | ||
250 | - uint32_t* entry=array_get(&(s->fat),cluster); | ||
251 | - *entry=cpu_to_le32(value); | ||
252 | + uint32_t* entry=array_get(&(s->fat),cluster); | ||
253 | + *entry=cpu_to_le32(value); | ||
254 | } else if(s->fat_type==16) { | ||
255 | - uint16_t* entry=array_get(&(s->fat),cluster); | ||
256 | - *entry=cpu_to_le16(value&0xffff); | ||
257 | + uint16_t* entry=array_get(&(s->fat),cluster); | ||
258 | + *entry=cpu_to_le16(value&0xffff); | ||
259 | } else { | ||
260 | - int offset = (cluster*3/2); | ||
261 | - unsigned char* p = array_get(&(s->fat), offset); | ||
262 | + int offset = (cluster*3/2); | ||
263 | + unsigned char* p = array_get(&(s->fat), offset); | ||
264 | switch (cluster&1) { | ||
265 | - case 0: | ||
266 | - p[0] = value&0xff; | ||
267 | - p[1] = (p[1]&0xf0) | ((value>>8)&0xf); | ||
268 | - break; | ||
269 | - case 1: | ||
270 | - p[0] = (p[0]&0xf) | ((value&0xf)<<4); | ||
271 | - p[1] = (value>>4); | ||
272 | - break; | ||
273 | - } | ||
274 | + case 0: | ||
275 | + p[0] = value&0xff; | ||
276 | + p[1] = (p[1]&0xf0) | ((value>>8)&0xf); | ||
277 | + break; | ||
278 | + case 1: | ||
279 | + p[0] = (p[0]&0xf) | ((value&0xf)<<4); | ||
280 | + p[1] = (value>>4); | ||
281 | + break; | ||
282 | + } | ||
283 | } | 38 | } |
284 | } | 39 | } |
285 | 40 | ||
286 | static inline uint32_t fat_get(BDRVVVFATState* s,unsigned int cluster) | 41 | -static void quorum_rewrite_entry(void *opaque) |
42 | +static void coroutine_fn quorum_rewrite_entry(void *opaque) | ||
287 | { | 43 | { |
288 | if(s->fat_type==32) { | 44 | QuorumCo *co = opaque; |
289 | - uint32_t* entry=array_get(&(s->fat),cluster); | 45 | QuorumAIOCB *acb = co->acb; |
290 | - return le32_to_cpu(*entry); | 46 | @@ -XXX,XX +XXX,XX @@ free_exit: |
291 | + uint32_t* entry=array_get(&(s->fat),cluster); | 47 | quorum_free_vote_list(&acb->votes); |
292 | + return le32_to_cpu(*entry); | 48 | } |
293 | } else if(s->fat_type==16) { | 49 | |
294 | - uint16_t* entry=array_get(&(s->fat),cluster); | 50 | -static void read_quorum_children_entry(void *opaque) |
295 | - return le16_to_cpu(*entry); | 51 | +static void coroutine_fn read_quorum_children_entry(void *opaque) |
296 | + uint16_t* entry=array_get(&(s->fat),cluster); | 52 | { |
297 | + return le16_to_cpu(*entry); | 53 | QuorumCo *co = opaque; |
298 | } else { | 54 | QuorumAIOCB *acb = co->acb; |
299 | - const uint8_t* x=(uint8_t*)(s->fat.pointer)+cluster*3/2; | 55 | @@ -XXX,XX +XXX,XX @@ static void read_quorum_children_entry(void *opaque) |
300 | - return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff; | ||
301 | + const uint8_t* x=(uint8_t*)(s->fat.pointer)+cluster*3/2; | ||
302 | + return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff; | ||
303 | } | 56 | } |
304 | } | 57 | } |
305 | 58 | ||
306 | static inline int fat_eof(BDRVVVFATState* s,uint32_t fat_entry) | 59 | -static int read_quorum_children(QuorumAIOCB *acb) |
60 | +static int coroutine_fn read_quorum_children(QuorumAIOCB *acb) | ||
307 | { | 61 | { |
308 | if(fat_entry>s->max_fat_value-8) | 62 | BDRVQuorumState *s = acb->bs->opaque; |
309 | - return -1; | 63 | int i; |
310 | + return -1; | 64 | @@ -XXX,XX +XXX,XX @@ static int read_quorum_children(QuorumAIOCB *acb) |
311 | return 0; | 65 | return acb->vote_ret; |
312 | } | 66 | } |
313 | 67 | ||
314 | static inline void init_fat(BDRVVVFATState* s) | 68 | -static int read_fifo_child(QuorumAIOCB *acb) |
69 | +static int coroutine_fn read_fifo_child(QuorumAIOCB *acb) | ||
315 | { | 70 | { |
316 | if (s->fat_type == 12) { | 71 | BDRVQuorumState *s = acb->bs->opaque; |
317 | - array_init(&(s->fat),1); | 72 | int n, ret; |
318 | - array_ensure_allocated(&(s->fat), | 73 | @@ -XXX,XX +XXX,XX @@ static int read_fifo_child(QuorumAIOCB *acb) |
319 | - s->sectors_per_fat * 0x200 * 3 / 2 - 1); | 74 | return ret; |
320 | + array_init(&(s->fat),1); | ||
321 | + array_ensure_allocated(&(s->fat), | ||
322 | + s->sectors_per_fat * 0x200 * 3 / 2 - 1); | ||
323 | } else { | ||
324 | - array_init(&(s->fat),(s->fat_type==32?4:2)); | ||
325 | - array_ensure_allocated(&(s->fat), | ||
326 | - s->sectors_per_fat * 0x200 / s->fat.item_size - 1); | ||
327 | + array_init(&(s->fat),(s->fat_type==32?4:2)); | ||
328 | + array_ensure_allocated(&(s->fat), | ||
329 | + s->sectors_per_fat * 0x200 / s->fat.item_size - 1); | ||
330 | } | ||
331 | memset(s->fat.pointer,0,s->fat.size); | ||
332 | |||
333 | switch(s->fat_type) { | ||
334 | - case 12: s->max_fat_value=0xfff; break; | ||
335 | - case 16: s->max_fat_value=0xffff; break; | ||
336 | - case 32: s->max_fat_value=0x0fffffff; break; | ||
337 | - default: s->max_fat_value=0; /* error... */ | ||
338 | + case 12: s->max_fat_value=0xfff; break; | ||
339 | + case 16: s->max_fat_value=0xffff; break; | ||
340 | + case 32: s->max_fat_value=0x0fffffff; break; | ||
341 | + default: s->max_fat_value=0; /* error... */ | ||
342 | } | ||
343 | |||
344 | } | 75 | } |
345 | @@ -XXX,XX +XXX,XX @@ static inline void init_fat(BDRVVVFATState* s) | 76 | |
346 | /* TODO: in create_short_filename, 0xe5->0x05 is not yet handled! */ | 77 | -static int quorum_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes, |
347 | /* TODO: in parse_short_filename, 0x05->0xe5 is not yet handled! */ | 78 | - QEMUIOVector *qiov, BdrvRequestFlags flags) |
348 | static inline direntry_t* create_short_and_long_name(BDRVVVFATState* s, | 79 | +static int coroutine_fn quorum_co_preadv(BlockDriverState *bs, |
349 | - unsigned int directory_start, const char* filename, int is_dot) | 80 | + int64_t offset, int64_t bytes, |
350 | + unsigned int directory_start, const char* filename, int is_dot) | 81 | + QEMUIOVector *qiov, |
82 | + BdrvRequestFlags flags) | ||
351 | { | 83 | { |
352 | int i,j,long_index=s->directory.next; | 84 | BDRVQuorumState *s = bs->opaque; |
353 | direntry_t* entry = NULL; | 85 | QuorumAIOCB *acb = quorum_aio_get(bs, qiov, offset, bytes, flags); |
354 | direntry_t* entry_long = NULL; | 86 | @@ -XXX,XX +XXX,XX @@ static int quorum_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes, |
355 | 87 | return ret; | |
356 | if(is_dot) { | 88 | } |
357 | - entry=array_get_next(&(s->directory)); | 89 | |
358 | + entry=array_get_next(&(s->directory)); | 90 | -static void write_quorum_entry(void *opaque) |
359 | memset(entry->name, 0x20, sizeof(entry->name)); | 91 | +static void coroutine_fn write_quorum_entry(void *opaque) |
360 | - memcpy(entry->name,filename,strlen(filename)); | ||
361 | - return entry; | ||
362 | + memcpy(entry->name,filename,strlen(filename)); | ||
363 | + return entry; | ||
364 | } | ||
365 | |||
366 | entry_long=create_long_filename(s,filename); | ||
367 | @@ -XXX,XX +XXX,XX @@ static inline direntry_t* create_short_and_long_name(BDRVVVFATState* s, | ||
368 | i = strlen(filename); | ||
369 | for(j = i - 1; j>0 && filename[j]!='.';j--); | ||
370 | if (j > 0) | ||
371 | - i = (j > 8 ? 8 : j); | ||
372 | + i = (j > 8 ? 8 : j); | ||
373 | else if (i > 8) | ||
374 | - i = 8; | ||
375 | + i = 8; | ||
376 | |||
377 | entry=array_get_next(&(s->directory)); | ||
378 | memset(entry->name, 0x20, sizeof(entry->name)); | ||
379 | @@ -XXX,XX +XXX,XX @@ static inline direntry_t* create_short_and_long_name(BDRVVVFATState* s, | ||
380 | |||
381 | /* upcase & remove unwanted characters */ | ||
382 | for(i=10;i>=0;i--) { | ||
383 | - if(i==10 || i==7) for(;i>0 && entry->name[i]==' ';i--); | ||
384 | - if(entry->name[i]<=' ' || entry->name[i]>0x7f | ||
385 | - || strchr(".*?<>|\":/\\[];,+='",entry->name[i])) | ||
386 | - entry->name[i]='_'; | ||
387 | + if(i==10 || i==7) for(;i>0 && entry->name[i]==' ';i--); | ||
388 | + if(entry->name[i]<=' ' || entry->name[i]>0x7f | ||
389 | + || strchr(".*?<>|\":/\\[];,+='",entry->name[i])) | ||
390 | + entry->name[i]='_'; | ||
391 | else if(entry->name[i]>='a' && entry->name[i]<='z') | ||
392 | entry->name[i]+='A'-'a'; | ||
393 | } | ||
394 | |||
395 | /* mangle duplicates */ | ||
396 | while(1) { | ||
397 | - direntry_t* entry1=array_get(&(s->directory),directory_start); | ||
398 | - int j; | ||
399 | - | ||
400 | - for(;entry1<entry;entry1++) | ||
401 | - if(!is_long_name(entry1) && !memcmp(entry1->name,entry->name,11)) | ||
402 | - break; /* found dupe */ | ||
403 | - if(entry1==entry) /* no dupe found */ | ||
404 | - break; | ||
405 | - | ||
406 | - /* use all 8 characters of name */ | ||
407 | - if(entry->name[7]==' ') { | ||
408 | - int j; | ||
409 | - for(j=6;j>0 && entry->name[j]==' ';j--) | ||
410 | - entry->name[j]='~'; | ||
411 | - } | ||
412 | - | ||
413 | - /* increment number */ | ||
414 | - for(j=7;j>0 && entry->name[j]=='9';j--) | ||
415 | - entry->name[j]='0'; | ||
416 | - if(j>0) { | ||
417 | - if(entry->name[j]<'0' || entry->name[j]>'9') | ||
418 | - entry->name[j]='0'; | ||
419 | - else | ||
420 | - entry->name[j]++; | ||
421 | - } | ||
422 | + direntry_t* entry1=array_get(&(s->directory),directory_start); | ||
423 | + int j; | ||
424 | + | ||
425 | + for(;entry1<entry;entry1++) | ||
426 | + if(!is_long_name(entry1) && !memcmp(entry1->name,entry->name,11)) | ||
427 | + break; /* found dupe */ | ||
428 | + if(entry1==entry) /* no dupe found */ | ||
429 | + break; | ||
430 | + | ||
431 | + /* use all 8 characters of name */ | ||
432 | + if(entry->name[7]==' ') { | ||
433 | + int j; | ||
434 | + for(j=6;j>0 && entry->name[j]==' ';j--) | ||
435 | + entry->name[j]='~'; | ||
436 | + } | ||
437 | + | ||
438 | + /* increment number */ | ||
439 | + for(j=7;j>0 && entry->name[j]=='9';j--) | ||
440 | + entry->name[j]='0'; | ||
441 | + if(j>0) { | ||
442 | + if(entry->name[j]<'0' || entry->name[j]>'9') | ||
443 | + entry->name[j]='0'; | ||
444 | + else | ||
445 | + entry->name[j]++; | ||
446 | + } | ||
447 | } | ||
448 | |||
449 | /* calculate checksum; propagate to long name */ | ||
450 | if(entry_long) { | ||
451 | uint8_t chksum=fat_chksum(entry); | ||
452 | |||
453 | - /* calculate anew, because realloc could have taken place */ | ||
454 | - entry_long=array_get(&(s->directory),long_index); | ||
455 | - while(entry_long<entry && is_long_name(entry_long)) { | ||
456 | - entry_long->reserved[1]=chksum; | ||
457 | - entry_long++; | ||
458 | - } | ||
459 | + /* calculate anew, because realloc could have taken place */ | ||
460 | + entry_long=array_get(&(s->directory),long_index); | ||
461 | + while(entry_long<entry && is_long_name(entry_long)) { | ||
462 | + entry_long->reserved[1]=chksum; | ||
463 | + entry_long++; | ||
464 | + } | ||
465 | } | ||
466 | |||
467 | return entry; | ||
468 | @@ -XXX,XX +XXX,XX @@ static int read_directory(BDRVVVFATState* s, int mapping_index) | ||
469 | assert(mapping->mode & MODE_DIRECTORY); | ||
470 | |||
471 | if(!dir) { | ||
472 | - mapping->end = mapping->begin; | ||
473 | - return -1; | ||
474 | + mapping->end = mapping->begin; | ||
475 | + return -1; | ||
476 | } | ||
477 | |||
478 | i = mapping->info.dir.first_dir_index = | ||
479 | - first_cluster == 0 ? 0 : s->directory.next; | ||
480 | + first_cluster == 0 ? 0 : s->directory.next; | ||
481 | |||
482 | /* actually read the directory, and allocate the mappings */ | ||
483 | while((entry=readdir(dir))) { | ||
484 | - unsigned int length=strlen(dirname)+2+strlen(entry->d_name); | ||
485 | + unsigned int length=strlen(dirname)+2+strlen(entry->d_name); | ||
486 | char* buffer; | ||
487 | - direntry_t* direntry; | ||
488 | + direntry_t* direntry; | ||
489 | struct stat st; | ||
490 | - int is_dot=!strcmp(entry->d_name,"."); | ||
491 | - int is_dotdot=!strcmp(entry->d_name,".."); | ||
492 | + int is_dot=!strcmp(entry->d_name,"."); | ||
493 | + int is_dotdot=!strcmp(entry->d_name,".."); | ||
494 | |||
495 | - if(first_cluster == 0 && (is_dotdot || is_dot)) | ||
496 | - continue; | ||
497 | + if(first_cluster == 0 && (is_dotdot || is_dot)) | ||
498 | + continue; | ||
499 | |||
500 | - buffer = g_malloc(length); | ||
501 | - snprintf(buffer,length,"%s/%s",dirname,entry->d_name); | ||
502 | + buffer = g_malloc(length); | ||
503 | + snprintf(buffer,length,"%s/%s",dirname,entry->d_name); | ||
504 | |||
505 | - if(stat(buffer,&st)<0) { | ||
506 | + if(stat(buffer,&st)<0) { | ||
507 | g_free(buffer); | ||
508 | continue; | ||
509 | - } | ||
510 | - | ||
511 | - /* create directory entry for this file */ | ||
512 | - direntry=create_short_and_long_name(s, i, entry->d_name, | ||
513 | - is_dot || is_dotdot); | ||
514 | - direntry->attributes=(S_ISDIR(st.st_mode)?0x10:0x20); | ||
515 | - direntry->reserved[0]=direntry->reserved[1]=0; | ||
516 | - direntry->ctime=fat_datetime(st.st_ctime,1); | ||
517 | - direntry->cdate=fat_datetime(st.st_ctime,0); | ||
518 | - direntry->adate=fat_datetime(st.st_atime,0); | ||
519 | - direntry->begin_hi=0; | ||
520 | - direntry->mtime=fat_datetime(st.st_mtime,1); | ||
521 | - direntry->mdate=fat_datetime(st.st_mtime,0); | ||
522 | - if(is_dotdot) | ||
523 | - set_begin_of_direntry(direntry, first_cluster_of_parent); | ||
524 | - else if(is_dot) | ||
525 | - set_begin_of_direntry(direntry, first_cluster); | ||
526 | - else | ||
527 | - direntry->begin=0; /* do that later */ | ||
528 | + } | ||
529 | + | ||
530 | + /* create directory entry for this file */ | ||
531 | + direntry=create_short_and_long_name(s, i, entry->d_name, | ||
532 | + is_dot || is_dotdot); | ||
533 | + direntry->attributes=(S_ISDIR(st.st_mode)?0x10:0x20); | ||
534 | + direntry->reserved[0]=direntry->reserved[1]=0; | ||
535 | + direntry->ctime=fat_datetime(st.st_ctime,1); | ||
536 | + direntry->cdate=fat_datetime(st.st_ctime,0); | ||
537 | + direntry->adate=fat_datetime(st.st_atime,0); | ||
538 | + direntry->begin_hi=0; | ||
539 | + direntry->mtime=fat_datetime(st.st_mtime,1); | ||
540 | + direntry->mdate=fat_datetime(st.st_mtime,0); | ||
541 | + if(is_dotdot) | ||
542 | + set_begin_of_direntry(direntry, first_cluster_of_parent); | ||
543 | + else if(is_dot) | ||
544 | + set_begin_of_direntry(direntry, first_cluster); | ||
545 | + else | ||
546 | + direntry->begin=0; /* do that later */ | ||
547 | if (st.st_size > 0x7fffffff) { | ||
548 | - fprintf(stderr, "File %s is larger than 2GB\n", buffer); | ||
549 | + fprintf(stderr, "File %s is larger than 2GB\n", buffer); | ||
550 | g_free(buffer); | ||
551 | closedir(dir); | ||
552 | - return -2; | ||
553 | + return -2; | ||
554 | } | ||
555 | - direntry->size=cpu_to_le32(S_ISDIR(st.st_mode)?0:st.st_size); | ||
556 | - | ||
557 | - /* create mapping for this file */ | ||
558 | - if(!is_dot && !is_dotdot && (S_ISDIR(st.st_mode) || st.st_size)) { | ||
559 | - s->current_mapping = array_get_next(&(s->mapping)); | ||
560 | - s->current_mapping->begin=0; | ||
561 | - s->current_mapping->end=st.st_size; | ||
562 | - /* | ||
563 | - * we get the direntry of the most recent direntry, which | ||
564 | - * contains the short name and all the relevant information. | ||
565 | - */ | ||
566 | - s->current_mapping->dir_index=s->directory.next-1; | ||
567 | - s->current_mapping->first_mapping_index = -1; | ||
568 | - if (S_ISDIR(st.st_mode)) { | ||
569 | - s->current_mapping->mode = MODE_DIRECTORY; | ||
570 | - s->current_mapping->info.dir.parent_mapping_index = | ||
571 | - mapping_index; | ||
572 | - } else { | ||
573 | - s->current_mapping->mode = MODE_UNDEFINED; | ||
574 | - s->current_mapping->info.file.offset = 0; | ||
575 | - } | ||
576 | - s->current_mapping->path=buffer; | ||
577 | - s->current_mapping->read_only = | ||
578 | - (st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) == 0; | ||
579 | + direntry->size=cpu_to_le32(S_ISDIR(st.st_mode)?0:st.st_size); | ||
580 | + | ||
581 | + /* create mapping for this file */ | ||
582 | + if(!is_dot && !is_dotdot && (S_ISDIR(st.st_mode) || st.st_size)) { | ||
583 | + s->current_mapping = array_get_next(&(s->mapping)); | ||
584 | + s->current_mapping->begin=0; | ||
585 | + s->current_mapping->end=st.st_size; | ||
586 | + /* | ||
587 | + * we get the direntry of the most recent direntry, which | ||
588 | + * contains the short name and all the relevant information. | ||
589 | + */ | ||
590 | + s->current_mapping->dir_index=s->directory.next-1; | ||
591 | + s->current_mapping->first_mapping_index = -1; | ||
592 | + if (S_ISDIR(st.st_mode)) { | ||
593 | + s->current_mapping->mode = MODE_DIRECTORY; | ||
594 | + s->current_mapping->info.dir.parent_mapping_index = | ||
595 | + mapping_index; | ||
596 | + } else { | ||
597 | + s->current_mapping->mode = MODE_UNDEFINED; | ||
598 | + s->current_mapping->info.file.offset = 0; | ||
599 | + } | ||
600 | + s->current_mapping->path=buffer; | ||
601 | + s->current_mapping->read_only = | ||
602 | + (st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) == 0; | ||
603 | } else { | ||
604 | g_free(buffer); | ||
605 | } | ||
606 | @@ -XXX,XX +XXX,XX @@ static int read_directory(BDRVVVFATState* s, int mapping_index) | ||
607 | |||
608 | /* fill with zeroes up to the end of the cluster */ | ||
609 | while(s->directory.next%(0x10*s->sectors_per_cluster)) { | ||
610 | - direntry_t* direntry=array_get_next(&(s->directory)); | ||
611 | - memset(direntry,0,sizeof(direntry_t)); | ||
612 | + direntry_t* direntry=array_get_next(&(s->directory)); | ||
613 | + memset(direntry,0,sizeof(direntry_t)); | ||
614 | } | ||
615 | |||
616 | /* TODO: if there are more entries, bootsector has to be adjusted! */ | ||
617 | #define ROOT_ENTRIES (0x02 * 0x10 * s->sectors_per_cluster) | ||
618 | if (mapping_index == 0 && s->directory.next < ROOT_ENTRIES) { | ||
619 | - /* root directory */ | ||
620 | - int cur = s->directory.next; | ||
621 | - array_ensure_allocated(&(s->directory), ROOT_ENTRIES - 1); | ||
622 | - s->directory.next = ROOT_ENTRIES; | ||
623 | - memset(array_get(&(s->directory), cur), 0, | ||
624 | - (ROOT_ENTRIES - cur) * sizeof(direntry_t)); | ||
625 | + /* root directory */ | ||
626 | + int cur = s->directory.next; | ||
627 | + array_ensure_allocated(&(s->directory), ROOT_ENTRIES - 1); | ||
628 | + s->directory.next = ROOT_ENTRIES; | ||
629 | + memset(array_get(&(s->directory), cur), 0, | ||
630 | + (ROOT_ENTRIES - cur) * sizeof(direntry_t)); | ||
631 | } | ||
632 | |||
633 | /* reget the mapping, since s->mapping was possibly realloc()ed */ | ||
634 | mapping = array_get(&(s->mapping), mapping_index); | ||
635 | first_cluster += (s->directory.next - mapping->info.dir.first_dir_index) | ||
636 | - * 0x20 / s->cluster_size; | ||
637 | + * 0x20 / s->cluster_size; | ||
638 | mapping->end = first_cluster; | ||
639 | |||
640 | direntry = array_get(&(s->directory), mapping->dir_index); | ||
641 | @@ -XXX,XX +XXX,XX @@ static int init_directories(BDRVVVFATState* s, | ||
642 | |||
643 | /* add volume label */ | ||
644 | { | ||
645 | - direntry_t* entry=array_get_next(&(s->directory)); | ||
646 | - entry->attributes=0x28; /* archive | volume label */ | ||
647 | + direntry_t* entry=array_get_next(&(s->directory)); | ||
648 | + entry->attributes=0x28; /* archive | volume label */ | ||
649 | memcpy(entry->name, s->volume_label, sizeof(entry->name)); | ||
650 | } | ||
651 | |||
652 | @@ -XXX,XX +XXX,XX @@ static int init_directories(BDRVVVFATState* s, | ||
653 | mapping->path = g_strdup(dirname); | ||
654 | i = strlen(mapping->path); | ||
655 | if (i > 0 && mapping->path[i - 1] == '/') | ||
656 | - mapping->path[i - 1] = '\0'; | ||
657 | + mapping->path[i - 1] = '\0'; | ||
658 | mapping->mode = MODE_DIRECTORY; | ||
659 | mapping->read_only = 0; | ||
660 | s->path = mapping->path; | ||
661 | |||
662 | for (i = 0, cluster = 0; i < s->mapping.next; i++) { | ||
663 | - /* MS-DOS expects the FAT to be 0 for the root directory | ||
664 | - * (except for the media byte). */ | ||
665 | - /* LATER TODO: still true for FAT32? */ | ||
666 | - int fix_fat = (i != 0); | ||
667 | - mapping = array_get(&(s->mapping), i); | ||
668 | + /* MS-DOS expects the FAT to be 0 for the root directory | ||
669 | + * (except for the media byte). */ | ||
670 | + /* LATER TODO: still true for FAT32? */ | ||
671 | + int fix_fat = (i != 0); | ||
672 | + mapping = array_get(&(s->mapping), i); | ||
673 | |||
674 | if (mapping->mode & MODE_DIRECTORY) { | ||
675 | - mapping->begin = cluster; | ||
676 | - if(read_directory(s, i)) { | ||
677 | + mapping->begin = cluster; | ||
678 | + if(read_directory(s, i)) { | ||
679 | error_setg(errp, "Could not read directory %s", | ||
680 | mapping->path); | ||
681 | - return -1; | ||
682 | - } | ||
683 | - mapping = array_get(&(s->mapping), i); | ||
684 | - } else { | ||
685 | - assert(mapping->mode == MODE_UNDEFINED); | ||
686 | - mapping->mode=MODE_NORMAL; | ||
687 | - mapping->begin = cluster; | ||
688 | - if (mapping->end > 0) { | ||
689 | - direntry_t* direntry = array_get(&(s->directory), | ||
690 | - mapping->dir_index); | ||
691 | - | ||
692 | - mapping->end = cluster + 1 + (mapping->end-1)/s->cluster_size; | ||
693 | - set_begin_of_direntry(direntry, mapping->begin); | ||
694 | - } else { | ||
695 | - mapping->end = cluster + 1; | ||
696 | - fix_fat = 0; | ||
697 | - } | ||
698 | - } | ||
699 | - | ||
700 | - assert(mapping->begin < mapping->end); | ||
701 | - | ||
702 | - /* next free cluster */ | ||
703 | - cluster = mapping->end; | ||
704 | - | ||
705 | - if(cluster > s->cluster_count) { | ||
706 | + return -1; | ||
707 | + } | ||
708 | + mapping = array_get(&(s->mapping), i); | ||
709 | + } else { | ||
710 | + assert(mapping->mode == MODE_UNDEFINED); | ||
711 | + mapping->mode=MODE_NORMAL; | ||
712 | + mapping->begin = cluster; | ||
713 | + if (mapping->end > 0) { | ||
714 | + direntry_t* direntry = array_get(&(s->directory), | ||
715 | + mapping->dir_index); | ||
716 | + | ||
717 | + mapping->end = cluster + 1 + (mapping->end-1)/s->cluster_size; | ||
718 | + set_begin_of_direntry(direntry, mapping->begin); | ||
719 | + } else { | ||
720 | + mapping->end = cluster + 1; | ||
721 | + fix_fat = 0; | ||
722 | + } | ||
723 | + } | ||
724 | + | ||
725 | + assert(mapping->begin < mapping->end); | ||
726 | + | ||
727 | + /* next free cluster */ | ||
728 | + cluster = mapping->end; | ||
729 | + | ||
730 | + if(cluster > s->cluster_count) { | ||
731 | error_setg(errp, | ||
732 | "Directory does not fit in FAT%d (capacity %.2f MB)", | ||
733 | s->fat_type, s->sector_count / 2000.0); | ||
734 | return -1; | ||
735 | - } | ||
736 | + } | ||
737 | |||
738 | - /* fix fat for entry */ | ||
739 | - if (fix_fat) { | ||
740 | - int j; | ||
741 | - for(j = mapping->begin; j < mapping->end - 1; j++) | ||
742 | - fat_set(s, j, j+1); | ||
743 | - fat_set(s, mapping->end - 1, s->max_fat_value); | ||
744 | - } | ||
745 | + /* fix fat for entry */ | ||
746 | + if (fix_fat) { | ||
747 | + int j; | ||
748 | + for(j = mapping->begin; j < mapping->end - 1; j++) | ||
749 | + fat_set(s, j, j+1); | ||
750 | + fat_set(s, mapping->end - 1, s->max_fat_value); | ||
751 | + } | ||
752 | } | ||
753 | |||
754 | mapping = array_get(&(s->mapping), 0); | ||
755 | @@ -XXX,XX +XXX,XX @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags, | ||
756 | |||
757 | switch (s->fat_type) { | ||
758 | case 32: | ||
759 | - fprintf(stderr, "Big fat greek warning: FAT32 has not been tested. " | ||
760 | + fprintf(stderr, "Big fat greek warning: FAT32 has not been tested. " | ||
761 | "You are welcome to do so!\n"); | ||
762 | break; | ||
763 | case 16: | ||
764 | @@ -XXX,XX +XXX,XX @@ static void vvfat_refresh_limits(BlockDriverState *bs, Error **errp) | ||
765 | static inline void vvfat_close_current_file(BDRVVVFATState *s) | ||
766 | { | 92 | { |
767 | if(s->current_mapping) { | 93 | QuorumCo *co = opaque; |
768 | - s->current_mapping = NULL; | 94 | QuorumAIOCB *acb = co->acb; |
769 | - if (s->current_fd) { | 95 | @@ -XXX,XX +XXX,XX @@ static void write_quorum_entry(void *opaque) |
770 | - qemu_close(s->current_fd); | ||
771 | - s->current_fd = 0; | ||
772 | - } | ||
773 | + s->current_mapping = NULL; | ||
774 | + if (s->current_fd) { | ||
775 | + qemu_close(s->current_fd); | ||
776 | + s->current_fd = 0; | ||
777 | + } | ||
778 | } | ||
779 | s->current_cluster = -1; | ||
780 | } | ||
781 | @@ -XXX,XX +XXX,XX @@ static inline int find_mapping_for_cluster_aux(BDRVVVFATState* s,int cluster_num | ||
782 | { | ||
783 | while(1) { | ||
784 | int index3; | ||
785 | - mapping_t* mapping; | ||
786 | - index3=(index1+index2)/2; | ||
787 | - mapping=array_get(&(s->mapping),index3); | ||
788 | - assert(mapping->begin < mapping->end); | ||
789 | - if(mapping->begin>=cluster_num) { | ||
790 | - assert(index2!=index3 || index2==0); | ||
791 | - if(index2==index3) | ||
792 | - return index1; | ||
793 | - index2=index3; | ||
794 | - } else { | ||
795 | - if(index1==index3) | ||
796 | - return mapping->end<=cluster_num ? index2 : index1; | ||
797 | - index1=index3; | ||
798 | - } | ||
799 | - assert(index1<=index2); | ||
800 | - DLOG(mapping=array_get(&(s->mapping),index1); | ||
801 | - assert(mapping->begin<=cluster_num); | ||
802 | - assert(index2 >= s->mapping.next || | ||
803 | - ((mapping = array_get(&(s->mapping),index2)) && | ||
804 | - mapping->end>cluster_num))); | ||
805 | + mapping_t* mapping; | ||
806 | + index3=(index1+index2)/2; | ||
807 | + mapping=array_get(&(s->mapping),index3); | ||
808 | + assert(mapping->begin < mapping->end); | ||
809 | + if(mapping->begin>=cluster_num) { | ||
810 | + assert(index2!=index3 || index2==0); | ||
811 | + if(index2==index3) | ||
812 | + return index1; | ||
813 | + index2=index3; | ||
814 | + } else { | ||
815 | + if(index1==index3) | ||
816 | + return mapping->end<=cluster_num ? index2 : index1; | ||
817 | + index1=index3; | ||
818 | + } | ||
819 | + assert(index1<=index2); | ||
820 | + DLOG(mapping=array_get(&(s->mapping),index1); | ||
821 | + assert(mapping->begin<=cluster_num); | ||
822 | + assert(index2 >= s->mapping.next || | ||
823 | + ((mapping = array_get(&(s->mapping),index2)) && | ||
824 | + mapping->end>cluster_num))); | ||
825 | } | 96 | } |
826 | } | 97 | } |
827 | 98 | ||
828 | @@ -XXX,XX +XXX,XX @@ static inline mapping_t* find_mapping_for_cluster(BDRVVVFATState* s,int cluster_ | 99 | -static int quorum_co_pwritev(BlockDriverState *bs, int64_t offset, |
829 | static int open_file(BDRVVVFATState* s,mapping_t* mapping) | 100 | - int64_t bytes, QEMUIOVector *qiov, |
101 | - BdrvRequestFlags flags) | ||
102 | +static int coroutine_fn quorum_co_pwritev(BlockDriverState *bs, int64_t offset, | ||
103 | + int64_t bytes, QEMUIOVector *qiov, | ||
104 | + BdrvRequestFlags flags) | ||
830 | { | 105 | { |
831 | if(!mapping) | 106 | BDRVQuorumState *s = bs->opaque; |
832 | - return -1; | 107 | QuorumAIOCB *acb = quorum_aio_get(bs, qiov, offset, bytes, flags); |
833 | + return -1; | 108 | @@ -XXX,XX +XXX,XX @@ static int quorum_co_pwritev(BlockDriverState *bs, int64_t offset, |
834 | if(!s->current_mapping || | 109 | return ret; |
835 | - strcmp(s->current_mapping->path,mapping->path)) { | ||
836 | - /* open file */ | ||
837 | - int fd = qemu_open(mapping->path, O_RDONLY | O_BINARY | O_LARGEFILE); | ||
838 | - if(fd<0) | ||
839 | - return -1; | ||
840 | - vvfat_close_current_file(s); | ||
841 | - s->current_fd = fd; | ||
842 | - s->current_mapping = mapping; | ||
843 | + strcmp(s->current_mapping->path,mapping->path)) { | ||
844 | + /* open file */ | ||
845 | + int fd = qemu_open(mapping->path, O_RDONLY | O_BINARY | O_LARGEFILE); | ||
846 | + if(fd<0) | ||
847 | + return -1; | ||
848 | + vvfat_close_current_file(s); | ||
849 | + s->current_fd = fd; | ||
850 | + s->current_mapping = mapping; | ||
851 | } | ||
852 | return 0; | ||
853 | } | 110 | } |
854 | @@ -XXX,XX +XXX,XX @@ static int open_file(BDRVVVFATState* s,mapping_t* mapping) | 111 | |
855 | static inline int read_cluster(BDRVVVFATState *s,int cluster_num) | 112 | -static int quorum_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, |
113 | - int64_t bytes, BdrvRequestFlags flags) | ||
114 | +static int coroutine_fn quorum_co_pwrite_zeroes(BlockDriverState *bs, | ||
115 | + int64_t offset, int64_t bytes, | ||
116 | + BdrvRequestFlags flags) | ||
117 | |||
856 | { | 118 | { |
857 | if(s->current_cluster != cluster_num) { | 119 | return quorum_co_pwritev(bs, offset, bytes, NULL, |
858 | - int result=0; | ||
859 | - off_t offset; | ||
860 | - assert(!s->current_mapping || s->current_fd || (s->current_mapping->mode & MODE_DIRECTORY)); | ||
861 | - if(!s->current_mapping | ||
862 | - || s->current_mapping->begin>cluster_num | ||
863 | - || s->current_mapping->end<=cluster_num) { | ||
864 | - /* binary search of mappings for file */ | ||
865 | - mapping_t* mapping=find_mapping_for_cluster(s,cluster_num); | ||
866 | - | ||
867 | - assert(!mapping || (cluster_num>=mapping->begin && cluster_num<mapping->end)); | ||
868 | - | ||
869 | - if (mapping && mapping->mode & MODE_DIRECTORY) { | ||
870 | - vvfat_close_current_file(s); | ||
871 | - s->current_mapping = mapping; | ||
872 | + int result=0; | ||
873 | + off_t offset; | ||
874 | + assert(!s->current_mapping || s->current_fd || (s->current_mapping->mode & MODE_DIRECTORY)); | ||
875 | + if(!s->current_mapping | ||
876 | + || s->current_mapping->begin>cluster_num | ||
877 | + || s->current_mapping->end<=cluster_num) { | ||
878 | + /* binary search of mappings for file */ | ||
879 | + mapping_t* mapping=find_mapping_for_cluster(s,cluster_num); | ||
880 | + | ||
881 | + assert(!mapping || (cluster_num>=mapping->begin && cluster_num<mapping->end)); | ||
882 | + | ||
883 | + if (mapping && mapping->mode & MODE_DIRECTORY) { | ||
884 | + vvfat_close_current_file(s); | ||
885 | + s->current_mapping = mapping; | ||
886 | read_cluster_directory: | ||
887 | - offset = s->cluster_size*(cluster_num-s->current_mapping->begin); | ||
888 | - s->cluster = (unsigned char*)s->directory.pointer+offset | ||
889 | - + 0x20*s->current_mapping->info.dir.first_dir_index; | ||
890 | - assert(((s->cluster-(unsigned char*)s->directory.pointer)%s->cluster_size)==0); | ||
891 | - assert((char*)s->cluster+s->cluster_size <= s->directory.pointer+s->directory.next*s->directory.item_size); | ||
892 | - s->current_cluster = cluster_num; | ||
893 | - return 0; | ||
894 | - } | ||
895 | - | ||
896 | - if(open_file(s,mapping)) | ||
897 | - return -2; | ||
898 | - } else if (s->current_mapping->mode & MODE_DIRECTORY) | ||
899 | - goto read_cluster_directory; | ||
900 | - | ||
901 | - assert(s->current_fd); | ||
902 | - | ||
903 | - offset=s->cluster_size*(cluster_num-s->current_mapping->begin)+s->current_mapping->info.file.offset; | ||
904 | - if(lseek(s->current_fd, offset, SEEK_SET)!=offset) | ||
905 | - return -3; | ||
906 | - s->cluster=s->cluster_buffer; | ||
907 | - result=read(s->current_fd,s->cluster,s->cluster_size); | ||
908 | - if(result<0) { | ||
909 | - s->current_cluster = -1; | ||
910 | - return -1; | ||
911 | - } | ||
912 | - s->current_cluster = cluster_num; | ||
913 | + offset = s->cluster_size*(cluster_num-s->current_mapping->begin); | ||
914 | + s->cluster = (unsigned char*)s->directory.pointer+offset | ||
915 | + + 0x20*s->current_mapping->info.dir.first_dir_index; | ||
916 | + assert(((s->cluster-(unsigned char*)s->directory.pointer)%s->cluster_size)==0); | ||
917 | + assert((char*)s->cluster+s->cluster_size <= s->directory.pointer+s->directory.next*s->directory.item_size); | ||
918 | + s->current_cluster = cluster_num; | ||
919 | + return 0; | ||
920 | + } | ||
921 | + | ||
922 | + if(open_file(s,mapping)) | ||
923 | + return -2; | ||
924 | + } else if (s->current_mapping->mode & MODE_DIRECTORY) | ||
925 | + goto read_cluster_directory; | ||
926 | + | ||
927 | + assert(s->current_fd); | ||
928 | + | ||
929 | + offset=s->cluster_size*(cluster_num-s->current_mapping->begin)+s->current_mapping->info.file.offset; | ||
930 | + if(lseek(s->current_fd, offset, SEEK_SET)!=offset) | ||
931 | + return -3; | ||
932 | + s->cluster=s->cluster_buffer; | ||
933 | + result=read(s->current_fd,s->cluster,s->cluster_size); | ||
934 | + if(result<0) { | ||
935 | + s->current_cluster = -1; | ||
936 | + return -1; | ||
937 | + } | ||
938 | + s->current_cluster = cluster_num; | ||
939 | } | ||
940 | return 0; | ||
941 | } | ||
942 | @@ -XXX,XX +XXX,XX @@ static void print_direntry(const direntry_t* direntry) | ||
943 | |||
944 | fprintf(stderr, "direntry %p: ", direntry); | ||
945 | if(!direntry) | ||
946 | - return; | ||
947 | + return; | ||
948 | if(is_long_name(direntry)) { | ||
949 | - unsigned char* c=(unsigned char*)direntry; | ||
950 | - int i; | ||
951 | - for(i=1;i<11 && c[i] && c[i]!=0xff;i+=2) | ||
952 | + unsigned char* c=(unsigned char*)direntry; | ||
953 | + int i; | ||
954 | + for(i=1;i<11 && c[i] && c[i]!=0xff;i+=2) | ||
955 | #define ADD_CHAR(c) {buffer[j] = (c); if (buffer[j] < ' ') buffer[j] = 0xb0; j++;} | ||
956 | - ADD_CHAR(c[i]); | ||
957 | - for(i=14;i<26 && c[i] && c[i]!=0xff;i+=2) | ||
958 | - ADD_CHAR(c[i]); | ||
959 | - for(i=28;i<32 && c[i] && c[i]!=0xff;i+=2) | ||
960 | - ADD_CHAR(c[i]); | ||
961 | - buffer[j] = 0; | ||
962 | - fprintf(stderr, "%s\n", buffer); | ||
963 | + ADD_CHAR(c[i]); | ||
964 | + for(i=14;i<26 && c[i] && c[i]!=0xff;i+=2) | ||
965 | + ADD_CHAR(c[i]); | ||
966 | + for(i=28;i<32 && c[i] && c[i]!=0xff;i+=2) | ||
967 | + ADD_CHAR(c[i]); | ||
968 | + buffer[j] = 0; | ||
969 | + fprintf(stderr, "%s\n", buffer); | ||
970 | } else { | ||
971 | - int i; | ||
972 | - for(i=0;i<11;i++) | ||
973 | - ADD_CHAR(direntry->name[i]); | ||
974 | - buffer[j] = 0; | ||
975 | - fprintf(stderr,"%s attributes=0x%02x begin=%d size=%d\n", | ||
976 | - buffer, | ||
977 | - direntry->attributes, | ||
978 | - begin_of_direntry(direntry),le32_to_cpu(direntry->size)); | ||
979 | + int i; | ||
980 | + for(i=0;i<11;i++) | ||
981 | + ADD_CHAR(direntry->name[i]); | ||
982 | + buffer[j] = 0; | ||
983 | + fprintf(stderr,"%s attributes=0x%02x begin=%d size=%d\n", | ||
984 | + buffer, | ||
985 | + direntry->attributes, | ||
986 | + begin_of_direntry(direntry),le32_to_cpu(direntry->size)); | ||
987 | } | ||
988 | } | ||
989 | |||
990 | @@ -XXX,XX +XXX,XX @@ static void print_mapping(const mapping_t* mapping) | ||
991 | mapping->first_mapping_index, mapping->path, mapping->mode); | ||
992 | |||
993 | if (mapping->mode & MODE_DIRECTORY) | ||
994 | - fprintf(stderr, "parent_mapping_index = %d, first_dir_index = %d\n", mapping->info.dir.parent_mapping_index, mapping->info.dir.first_dir_index); | ||
995 | + fprintf(stderr, "parent_mapping_index = %d, first_dir_index = %d\n", mapping->info.dir.parent_mapping_index, mapping->info.dir.first_dir_index); | ||
996 | else | ||
997 | - fprintf(stderr, "offset = %d\n", mapping->info.file.offset); | ||
998 | + fprintf(stderr, "offset = %d\n", mapping->info.file.offset); | ||
999 | } | ||
1000 | #endif | ||
1001 | |||
1002 | @@ -XXX,XX +XXX,XX @@ static int vvfat_read(BlockDriverState *bs, int64_t sector_num, | ||
1003 | int i; | ||
1004 | |||
1005 | for(i=0;i<nb_sectors;i++,sector_num++) { | ||
1006 | - if (sector_num >= bs->total_sectors) | ||
1007 | - return -1; | ||
1008 | - if (s->qcow) { | ||
1009 | - int n; | ||
1010 | + if (sector_num >= bs->total_sectors) | ||
1011 | + return -1; | ||
1012 | + if (s->qcow) { | ||
1013 | + int n; | ||
1014 | int ret; | ||
1015 | ret = bdrv_is_allocated(s->qcow->bs, sector_num, | ||
1016 | nb_sectors - i, &n); | ||
1017 | @@ -XXX,XX +XXX,XX @@ static int vvfat_read(BlockDriverState *bs, int64_t sector_num, | ||
1018 | continue; | ||
1019 | } | ||
1020 | DLOG(fprintf(stderr, "sector %d not allocated\n", (int)sector_num)); | ||
1021 | - } | ||
1022 | - if(sector_num<s->faked_sectors) { | ||
1023 | - if(sector_num<s->first_sectors_number) | ||
1024 | - memcpy(buf+i*0x200,&(s->first_sectors[sector_num*0x200]),0x200); | ||
1025 | - else if(sector_num-s->first_sectors_number<s->sectors_per_fat) | ||
1026 | - memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number)*0x200]),0x200); | ||
1027 | - else if(sector_num-s->first_sectors_number-s->sectors_per_fat<s->sectors_per_fat) | ||
1028 | - memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number-s->sectors_per_fat)*0x200]),0x200); | ||
1029 | - } else { | ||
1030 | - uint32_t sector=sector_num-s->faked_sectors, | ||
1031 | - sector_offset_in_cluster=(sector%s->sectors_per_cluster), | ||
1032 | - cluster_num=sector/s->sectors_per_cluster; | ||
1033 | - if(cluster_num > s->cluster_count || read_cluster(s, cluster_num) != 0) { | ||
1034 | - /* LATER TODO: strict: return -1; */ | ||
1035 | - memset(buf+i*0x200,0,0x200); | ||
1036 | - continue; | ||
1037 | - } | ||
1038 | - memcpy(buf+i*0x200,s->cluster+sector_offset_in_cluster*0x200,0x200); | ||
1039 | - } | ||
1040 | + } | ||
1041 | + if(sector_num<s->faked_sectors) { | ||
1042 | + if(sector_num<s->first_sectors_number) | ||
1043 | + memcpy(buf+i*0x200,&(s->first_sectors[sector_num*0x200]),0x200); | ||
1044 | + else if(sector_num-s->first_sectors_number<s->sectors_per_fat) | ||
1045 | + memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number)*0x200]),0x200); | ||
1046 | + else if(sector_num-s->first_sectors_number-s->sectors_per_fat<s->sectors_per_fat) | ||
1047 | + memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number-s->sectors_per_fat)*0x200]),0x200); | ||
1048 | + } else { | ||
1049 | + uint32_t sector=sector_num-s->faked_sectors, | ||
1050 | + sector_offset_in_cluster=(sector%s->sectors_per_cluster), | ||
1051 | + cluster_num=sector/s->sectors_per_cluster; | ||
1052 | + if(cluster_num > s->cluster_count || read_cluster(s, cluster_num) != 0) { | ||
1053 | + /* LATER TODO: strict: return -1; */ | ||
1054 | + memset(buf+i*0x200,0,0x200); | ||
1055 | + continue; | ||
1056 | + } | ||
1057 | + memcpy(buf+i*0x200,s->cluster+sector_offset_in_cluster*0x200,0x200); | ||
1058 | + } | ||
1059 | } | ||
1060 | return 0; | ||
1061 | } | ||
1062 | @@ -XXX,XX +XXX,XX @@ vvfat_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes, | ||
1063 | typedef struct commit_t { | ||
1064 | char* path; | ||
1065 | union { | ||
1066 | - struct { uint32_t cluster; } rename; | ||
1067 | - struct { int dir_index; uint32_t modified_offset; } writeout; | ||
1068 | - struct { uint32_t first_cluster; } new_file; | ||
1069 | - struct { uint32_t cluster; } mkdir; | ||
1070 | + struct { uint32_t cluster; } rename; | ||
1071 | + struct { int dir_index; uint32_t modified_offset; } writeout; | ||
1072 | + struct { uint32_t first_cluster; } new_file; | ||
1073 | + struct { uint32_t cluster; } mkdir; | ||
1074 | } param; | ||
1075 | /* DELETEs and RMDIRs are handled differently: see handle_deletes() */ | ||
1076 | enum { | ||
1077 | - ACTION_RENAME, ACTION_WRITEOUT, ACTION_NEW_FILE, ACTION_MKDIR | ||
1078 | + ACTION_RENAME, ACTION_WRITEOUT, ACTION_NEW_FILE, ACTION_MKDIR | ||
1079 | } action; | ||
1080 | } commit_t; | ||
1081 | |||
1082 | @@ -XXX,XX +XXX,XX @@ static void clear_commits(BDRVVVFATState* s) | ||
1083 | int i; | ||
1084 | DLOG(fprintf(stderr, "clear_commits (%d commits)\n", s->commits.next)); | ||
1085 | for (i = 0; i < s->commits.next; i++) { | ||
1086 | - commit_t* commit = array_get(&(s->commits), i); | ||
1087 | - assert(commit->path || commit->action == ACTION_WRITEOUT); | ||
1088 | - if (commit->action != ACTION_WRITEOUT) { | ||
1089 | - assert(commit->path); | ||
1090 | + commit_t* commit = array_get(&(s->commits), i); | ||
1091 | + assert(commit->path || commit->action == ACTION_WRITEOUT); | ||
1092 | + if (commit->action != ACTION_WRITEOUT) { | ||
1093 | + assert(commit->path); | ||
1094 | g_free(commit->path); | ||
1095 | - } else | ||
1096 | - assert(commit->path == NULL); | ||
1097 | + } else | ||
1098 | + assert(commit->path == NULL); | ||
1099 | } | ||
1100 | s->commits.next = 0; | ||
1101 | } | ||
1102 | |||
1103 | static void schedule_rename(BDRVVVFATState* s, | ||
1104 | - uint32_t cluster, char* new_path) | ||
1105 | + uint32_t cluster, char* new_path) | ||
1106 | { | ||
1107 | commit_t* commit = array_get_next(&(s->commits)); | ||
1108 | commit->path = new_path; | ||
1109 | @@ -XXX,XX +XXX,XX @@ static void schedule_rename(BDRVVVFATState* s, | ||
1110 | } | ||
1111 | |||
1112 | static void schedule_writeout(BDRVVVFATState* s, | ||
1113 | - int dir_index, uint32_t modified_offset) | ||
1114 | + int dir_index, uint32_t modified_offset) | ||
1115 | { | ||
1116 | commit_t* commit = array_get_next(&(s->commits)); | ||
1117 | commit->path = NULL; | ||
1118 | @@ -XXX,XX +XXX,XX @@ static void schedule_writeout(BDRVVVFATState* s, | ||
1119 | } | ||
1120 | |||
1121 | static void schedule_new_file(BDRVVVFATState* s, | ||
1122 | - char* path, uint32_t first_cluster) | ||
1123 | + char* path, uint32_t first_cluster) | ||
1124 | { | ||
1125 | commit_t* commit = array_get_next(&(s->commits)); | ||
1126 | commit->path = path; | ||
1127 | @@ -XXX,XX +XXX,XX @@ static void lfn_init(long_file_name* lfn) | ||
1128 | |||
1129 | /* return 0 if parsed successfully, > 0 if no long name, < 0 if error */ | ||
1130 | static int parse_long_name(long_file_name* lfn, | ||
1131 | - const direntry_t* direntry) | ||
1132 | + const direntry_t* direntry) | ||
1133 | { | ||
1134 | int i, j, offset; | ||
1135 | const unsigned char* pointer = (const unsigned char*)direntry; | ||
1136 | |||
1137 | if (!is_long_name(direntry)) | ||
1138 | - return 1; | ||
1139 | + return 1; | ||
1140 | |||
1141 | if (pointer[0] & 0x40) { | ||
1142 | - lfn->sequence_number = pointer[0] & 0x3f; | ||
1143 | - lfn->checksum = pointer[13]; | ||
1144 | - lfn->name[0] = 0; | ||
1145 | - lfn->name[lfn->sequence_number * 13] = 0; | ||
1146 | + lfn->sequence_number = pointer[0] & 0x3f; | ||
1147 | + lfn->checksum = pointer[13]; | ||
1148 | + lfn->name[0] = 0; | ||
1149 | + lfn->name[lfn->sequence_number * 13] = 0; | ||
1150 | } else if ((pointer[0] & 0x3f) != --lfn->sequence_number) | ||
1151 | - return -1; | ||
1152 | + return -1; | ||
1153 | else if (pointer[13] != lfn->checksum) | ||
1154 | - return -2; | ||
1155 | + return -2; | ||
1156 | else if (pointer[12] || pointer[26] || pointer[27]) | ||
1157 | - return -3; | ||
1158 | + return -3; | ||
1159 | |||
1160 | offset = 13 * (lfn->sequence_number - 1); | ||
1161 | for (i = 0, j = 1; i < 13; i++, j+=2) { | ||
1162 | - if (j == 11) | ||
1163 | - j = 14; | ||
1164 | - else if (j == 26) | ||
1165 | - j = 28; | ||
1166 | + if (j == 11) | ||
1167 | + j = 14; | ||
1168 | + else if (j == 26) | ||
1169 | + j = 28; | ||
1170 | |||
1171 | - if (pointer[j+1] == 0) | ||
1172 | - lfn->name[offset + i] = pointer[j]; | ||
1173 | - else if (pointer[j+1] != 0xff || (pointer[0] & 0x40) == 0) | ||
1174 | - return -4; | ||
1175 | - else | ||
1176 | - lfn->name[offset + i] = 0; | ||
1177 | + if (pointer[j+1] == 0) | ||
1178 | + lfn->name[offset + i] = pointer[j]; | ||
1179 | + else if (pointer[j+1] != 0xff || (pointer[0] & 0x40) == 0) | ||
1180 | + return -4; | ||
1181 | + else | ||
1182 | + lfn->name[offset + i] = 0; | ||
1183 | } | ||
1184 | |||
1185 | if (pointer[0] & 0x40) | ||
1186 | - lfn->len = offset + strlen((char*)lfn->name + offset); | ||
1187 | + lfn->len = offset + strlen((char*)lfn->name + offset); | ||
1188 | |||
1189 | return 0; | ||
1190 | } | ||
1191 | |||
1192 | /* returns 0 if successful, >0 if no short_name, and <0 on error */ | ||
1193 | static int parse_short_name(BDRVVVFATState* s, | ||
1194 | - long_file_name* lfn, direntry_t* direntry) | ||
1195 | + long_file_name* lfn, direntry_t* direntry) | ||
1196 | { | ||
1197 | int i, j; | ||
1198 | |||
1199 | if (!is_short_name(direntry)) | ||
1200 | - return 1; | ||
1201 | + return 1; | ||
1202 | |||
1203 | for (j = 7; j >= 0 && direntry->name[j] == ' '; j--); | ||
1204 | for (i = 0; i <= j; i++) { | ||
1205 | - if (direntry->name[i] <= ' ' || direntry->name[i] > 0x7f) | ||
1206 | - return -1; | ||
1207 | - else if (s->downcase_short_names) | ||
1208 | - lfn->name[i] = qemu_tolower(direntry->name[i]); | ||
1209 | - else | ||
1210 | - lfn->name[i] = direntry->name[i]; | ||
1211 | + if (direntry->name[i] <= ' ' || direntry->name[i] > 0x7f) | ||
1212 | + return -1; | ||
1213 | + else if (s->downcase_short_names) | ||
1214 | + lfn->name[i] = qemu_tolower(direntry->name[i]); | ||
1215 | + else | ||
1216 | + lfn->name[i] = direntry->name[i]; | ||
1217 | } | ||
1218 | |||
1219 | for (j = 2; j >= 0 && direntry->name[8 + j] == ' '; j--) { | ||
1220 | } | ||
1221 | if (j >= 0) { | ||
1222 | - lfn->name[i++] = '.'; | ||
1223 | - lfn->name[i + j + 1] = '\0'; | ||
1224 | - for (;j >= 0; j--) { | ||
1225 | + lfn->name[i++] = '.'; | ||
1226 | + lfn->name[i + j + 1] = '\0'; | ||
1227 | + for (;j >= 0; j--) { | ||
1228 | uint8_t c = direntry->name[8 + j]; | ||
1229 | if (c <= ' ' || c > 0x7f) { | ||
1230 | return -2; | ||
1231 | @@ -XXX,XX +XXX,XX @@ static int parse_short_name(BDRVVVFATState* s, | ||
1232 | } else { | ||
1233 | lfn->name[i + j] = c; | ||
1234 | } | ||
1235 | - } | ||
1236 | + } | ||
1237 | } else | ||
1238 | - lfn->name[i + j + 1] = '\0'; | ||
1239 | + lfn->name[i + j + 1] = '\0'; | ||
1240 | |||
1241 | lfn->len = strlen((char*)lfn->name); | ||
1242 | |||
1243 | @@ -XXX,XX +XXX,XX @@ static int parse_short_name(BDRVVVFATState* s, | ||
1244 | } | ||
1245 | |||
1246 | static inline uint32_t modified_fat_get(BDRVVVFATState* s, | ||
1247 | - unsigned int cluster) | ||
1248 | + unsigned int cluster) | ||
1249 | { | ||
1250 | if (cluster < s->last_cluster_of_root_directory) { | ||
1251 | - if (cluster + 1 == s->last_cluster_of_root_directory) | ||
1252 | - return s->max_fat_value; | ||
1253 | - else | ||
1254 | - return cluster + 1; | ||
1255 | + if (cluster + 1 == s->last_cluster_of_root_directory) | ||
1256 | + return s->max_fat_value; | ||
1257 | + else | ||
1258 | + return cluster + 1; | ||
1259 | } | ||
1260 | |||
1261 | if (s->fat_type==32) { | ||
1262 | @@ -XXX,XX +XXX,XX @@ static const char* get_basename(const char* path) | ||
1263 | { | ||
1264 | char* basename = strrchr(path, '/'); | ||
1265 | if (basename == NULL) | ||
1266 | - return path; | ||
1267 | + return path; | ||
1268 | else | ||
1269 | - return basename + 1; /* strip '/' */ | ||
1270 | + return basename + 1; /* strip '/' */ | ||
1271 | } | ||
1272 | |||
1273 | /* | ||
1274 | @@ -XXX,XX +XXX,XX @@ typedef enum { | ||
1275 | * assumed to be *not* deleted (and *only* those). | ||
1276 | */ | ||
1277 | static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s, | ||
1278 | - direntry_t* direntry, const char* path) | ||
1279 | + direntry_t* direntry, const char* path) | ||
1280 | { | ||
1281 | /* | ||
1282 | * This is a little bit tricky: | ||
1283 | @@ -XXX,XX +XXX,XX @@ static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s, | ||
1284 | |||
1285 | /* the root directory */ | ||
1286 | if (cluster_num == 0) | ||
1287 | - return 0; | ||
1288 | + return 0; | ||
1289 | |||
1290 | /* write support */ | ||
1291 | if (s->qcow) { | ||
1292 | - basename2 = get_basename(path); | ||
1293 | + basename2 = get_basename(path); | ||
1294 | |||
1295 | - mapping = find_mapping_for_cluster(s, cluster_num); | ||
1296 | + mapping = find_mapping_for_cluster(s, cluster_num); | ||
1297 | |||
1298 | - if (mapping) { | ||
1299 | - const char* basename; | ||
1300 | + if (mapping) { | ||
1301 | + const char* basename; | ||
1302 | |||
1303 | - assert(mapping->mode & MODE_DELETED); | ||
1304 | - mapping->mode &= ~MODE_DELETED; | ||
1305 | + assert(mapping->mode & MODE_DELETED); | ||
1306 | + mapping->mode &= ~MODE_DELETED; | ||
1307 | |||
1308 | - basename = get_basename(mapping->path); | ||
1309 | + basename = get_basename(mapping->path); | ||
1310 | |||
1311 | - assert(mapping->mode & MODE_NORMAL); | ||
1312 | + assert(mapping->mode & MODE_NORMAL); | ||
1313 | |||
1314 | - /* rename */ | ||
1315 | - if (strcmp(basename, basename2)) | ||
1316 | - schedule_rename(s, cluster_num, g_strdup(path)); | ||
1317 | - } else if (is_file(direntry)) | ||
1318 | - /* new file */ | ||
1319 | - schedule_new_file(s, g_strdup(path), cluster_num); | ||
1320 | - else { | ||
1321 | + /* rename */ | ||
1322 | + if (strcmp(basename, basename2)) | ||
1323 | + schedule_rename(s, cluster_num, g_strdup(path)); | ||
1324 | + } else if (is_file(direntry)) | ||
1325 | + /* new file */ | ||
1326 | + schedule_new_file(s, g_strdup(path), cluster_num); | ||
1327 | + else { | ||
1328 | abort(); | ||
1329 | - return 0; | ||
1330 | - } | ||
1331 | + return 0; | ||
1332 | + } | ||
1333 | } | ||
1334 | |||
1335 | while(1) { | ||
1336 | - if (s->qcow) { | ||
1337 | - if (!copy_it && cluster_was_modified(s, cluster_num)) { | ||
1338 | - if (mapping == NULL || | ||
1339 | - mapping->begin > cluster_num || | ||
1340 | - mapping->end <= cluster_num) | ||
1341 | - mapping = find_mapping_for_cluster(s, cluster_num); | ||
1342 | + if (s->qcow) { | ||
1343 | + if (!copy_it && cluster_was_modified(s, cluster_num)) { | ||
1344 | + if (mapping == NULL || | ||
1345 | + mapping->begin > cluster_num || | ||
1346 | + mapping->end <= cluster_num) | ||
1347 | + mapping = find_mapping_for_cluster(s, cluster_num); | ||
1348 | |||
1349 | |||
1350 | - if (mapping && | ||
1351 | - (mapping->mode & MODE_DIRECTORY) == 0) { | ||
1352 | + if (mapping && | ||
1353 | + (mapping->mode & MODE_DIRECTORY) == 0) { | ||
1354 | |||
1355 | - /* was modified in qcow */ | ||
1356 | - if (offset != mapping->info.file.offset + s->cluster_size | ||
1357 | - * (cluster_num - mapping->begin)) { | ||
1358 | - /* offset of this cluster in file chain has changed */ | ||
1359 | + /* was modified in qcow */ | ||
1360 | + if (offset != mapping->info.file.offset + s->cluster_size | ||
1361 | + * (cluster_num - mapping->begin)) { | ||
1362 | + /* offset of this cluster in file chain has changed */ | ||
1363 | abort(); | ||
1364 | - copy_it = 1; | ||
1365 | - } else if (offset == 0) { | ||
1366 | - const char* basename = get_basename(mapping->path); | ||
1367 | + copy_it = 1; | ||
1368 | + } else if (offset == 0) { | ||
1369 | + const char* basename = get_basename(mapping->path); | ||
1370 | |||
1371 | - if (strcmp(basename, basename2)) | ||
1372 | - copy_it = 1; | ||
1373 | - first_mapping_index = array_index(&(s->mapping), mapping); | ||
1374 | - } | ||
1375 | + if (strcmp(basename, basename2)) | ||
1376 | + copy_it = 1; | ||
1377 | + first_mapping_index = array_index(&(s->mapping), mapping); | ||
1378 | + } | ||
1379 | |||
1380 | - if (mapping->first_mapping_index != first_mapping_index | ||
1381 | - && mapping->info.file.offset > 0) { | ||
1382 | + if (mapping->first_mapping_index != first_mapping_index | ||
1383 | + && mapping->info.file.offset > 0) { | ||
1384 | abort(); | ||
1385 | - copy_it = 1; | ||
1386 | - } | ||
1387 | - | ||
1388 | - /* need to write out? */ | ||
1389 | - if (!was_modified && is_file(direntry)) { | ||
1390 | - was_modified = 1; | ||
1391 | - schedule_writeout(s, mapping->dir_index, offset); | ||
1392 | - } | ||
1393 | - } | ||
1394 | - } | ||
1395 | - | ||
1396 | - if (copy_it) { | ||
1397 | - int i, dummy; | ||
1398 | - /* | ||
1399 | - * This is horribly inefficient, but that is okay, since | ||
1400 | - * it is rarely executed, if at all. | ||
1401 | - */ | ||
1402 | - int64_t offset = cluster2sector(s, cluster_num); | ||
1403 | - | ||
1404 | - vvfat_close_current_file(s); | ||
1405 | + copy_it = 1; | ||
1406 | + } | ||
1407 | + | ||
1408 | + /* need to write out? */ | ||
1409 | + if (!was_modified && is_file(direntry)) { | ||
1410 | + was_modified = 1; | ||
1411 | + schedule_writeout(s, mapping->dir_index, offset); | ||
1412 | + } | ||
1413 | + } | ||
1414 | + } | ||
1415 | + | ||
1416 | + if (copy_it) { | ||
1417 | + int i, dummy; | ||
1418 | + /* | ||
1419 | + * This is horribly inefficient, but that is okay, since | ||
1420 | + * it is rarely executed, if at all. | ||
1421 | + */ | ||
1422 | + int64_t offset = cluster2sector(s, cluster_num); | ||
1423 | + | ||
1424 | + vvfat_close_current_file(s); | ||
1425 | for (i = 0; i < s->sectors_per_cluster; i++) { | ||
1426 | int res; | ||
1427 | |||
1428 | @@ -XXX,XX +XXX,XX @@ static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s, | ||
1429 | } | ||
1430 | } | ||
1431 | } | ||
1432 | - } | ||
1433 | - } | ||
1434 | + } | ||
1435 | + } | ||
1436 | |||
1437 | - ret++; | ||
1438 | - if (s->used_clusters[cluster_num] & USED_ANY) | ||
1439 | - return 0; | ||
1440 | - s->used_clusters[cluster_num] = USED_FILE; | ||
1441 | + ret++; | ||
1442 | + if (s->used_clusters[cluster_num] & USED_ANY) | ||
1443 | + return 0; | ||
1444 | + s->used_clusters[cluster_num] = USED_FILE; | ||
1445 | |||
1446 | - cluster_num = modified_fat_get(s, cluster_num); | ||
1447 | + cluster_num = modified_fat_get(s, cluster_num); | ||
1448 | |||
1449 | - if (fat_eof(s, cluster_num)) | ||
1450 | - return ret; | ||
1451 | - else if (cluster_num < 2 || cluster_num > s->max_fat_value - 16) | ||
1452 | - return -1; | ||
1453 | + if (fat_eof(s, cluster_num)) | ||
1454 | + return ret; | ||
1455 | + else if (cluster_num < 2 || cluster_num > s->max_fat_value - 16) | ||
1456 | + return -1; | ||
1457 | |||
1458 | - offset += s->cluster_size; | ||
1459 | + offset += s->cluster_size; | ||
1460 | } | ||
1461 | } | ||
1462 | |||
1463 | @@ -XXX,XX +XXX,XX @@ static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s, | ||
1464 | * used by the directory, its subdirectories and their files. | ||
1465 | */ | ||
1466 | static int check_directory_consistency(BDRVVVFATState *s, | ||
1467 | - int cluster_num, const char* path) | ||
1468 | + int cluster_num, const char* path) | ||
1469 | { | ||
1470 | int ret = 0; | ||
1471 | unsigned char* cluster = g_malloc(s->cluster_size); | ||
1472 | @@ -XXX,XX +XXX,XX @@ static int check_directory_consistency(BDRVVVFATState *s, | ||
1473 | path2[path_len + 1] = '\0'; | ||
1474 | |||
1475 | if (mapping) { | ||
1476 | - const char* basename = get_basename(mapping->path); | ||
1477 | - const char* basename2 = get_basename(path); | ||
1478 | + const char* basename = get_basename(mapping->path); | ||
1479 | + const char* basename2 = get_basename(path); | ||
1480 | |||
1481 | - assert(mapping->mode & MODE_DIRECTORY); | ||
1482 | + assert(mapping->mode & MODE_DIRECTORY); | ||
1483 | |||
1484 | - assert(mapping->mode & MODE_DELETED); | ||
1485 | - mapping->mode &= ~MODE_DELETED; | ||
1486 | + assert(mapping->mode & MODE_DELETED); | ||
1487 | + mapping->mode &= ~MODE_DELETED; | ||
1488 | |||
1489 | - if (strcmp(basename, basename2)) | ||
1490 | - schedule_rename(s, cluster_num, g_strdup(path)); | ||
1491 | + if (strcmp(basename, basename2)) | ||
1492 | + schedule_rename(s, cluster_num, g_strdup(path)); | ||
1493 | } else | ||
1494 | - /* new directory */ | ||
1495 | - schedule_mkdir(s, cluster_num, g_strdup(path)); | ||
1496 | + /* new directory */ | ||
1497 | + schedule_mkdir(s, cluster_num, g_strdup(path)); | ||
1498 | |||
1499 | lfn_init(&lfn); | ||
1500 | do { | ||
1501 | - int i; | ||
1502 | - int subret = 0; | ||
1503 | + int i; | ||
1504 | + int subret = 0; | ||
1505 | |||
1506 | - ret++; | ||
1507 | + ret++; | ||
1508 | |||
1509 | - if (s->used_clusters[cluster_num] & USED_ANY) { | ||
1510 | - fprintf(stderr, "cluster %d used more than once\n", (int)cluster_num); | ||
1511 | + if (s->used_clusters[cluster_num] & USED_ANY) { | ||
1512 | + fprintf(stderr, "cluster %d used more than once\n", (int)cluster_num); | ||
1513 | goto fail; | ||
1514 | - } | ||
1515 | - s->used_clusters[cluster_num] = USED_DIRECTORY; | ||
1516 | + } | ||
1517 | + s->used_clusters[cluster_num] = USED_DIRECTORY; | ||
1518 | |||
1519 | DLOG(fprintf(stderr, "read cluster %d (sector %d)\n", (int)cluster_num, (int)cluster2sector(s, cluster_num))); | ||
1520 | - subret = vvfat_read(s->bs, cluster2sector(s, cluster_num), cluster, | ||
1521 | - s->sectors_per_cluster); | ||
1522 | - if (subret) { | ||
1523 | - fprintf(stderr, "Error fetching direntries\n"); | ||
1524 | - fail: | ||
1525 | + subret = vvfat_read(s->bs, cluster2sector(s, cluster_num), cluster, | ||
1526 | + s->sectors_per_cluster); | ||
1527 | + if (subret) { | ||
1528 | + fprintf(stderr, "Error fetching direntries\n"); | ||
1529 | + fail: | ||
1530 | g_free(cluster); | ||
1531 | - return 0; | ||
1532 | - } | ||
1533 | + return 0; | ||
1534 | + } | ||
1535 | |||
1536 | - for (i = 0; i < 0x10 * s->sectors_per_cluster; i++) { | ||
1537 | - int cluster_count = 0; | ||
1538 | + for (i = 0; i < 0x10 * s->sectors_per_cluster; i++) { | ||
1539 | + int cluster_count = 0; | ||
1540 | |||
1541 | DLOG(fprintf(stderr, "check direntry %d:\n", i); print_direntry(direntries + i)); | ||
1542 | - if (is_volume_label(direntries + i) || is_dot(direntries + i) || | ||
1543 | - is_free(direntries + i)) | ||
1544 | - continue; | ||
1545 | - | ||
1546 | - subret = parse_long_name(&lfn, direntries + i); | ||
1547 | - if (subret < 0) { | ||
1548 | - fprintf(stderr, "Error in long name\n"); | ||
1549 | - goto fail; | ||
1550 | - } | ||
1551 | - if (subret == 0 || is_free(direntries + i)) | ||
1552 | - continue; | ||
1553 | - | ||
1554 | - if (fat_chksum(direntries+i) != lfn.checksum) { | ||
1555 | - subret = parse_short_name(s, &lfn, direntries + i); | ||
1556 | - if (subret < 0) { | ||
1557 | - fprintf(stderr, "Error in short name (%d)\n", subret); | ||
1558 | - goto fail; | ||
1559 | - } | ||
1560 | - if (subret > 0 || !strcmp((char*)lfn.name, ".") | ||
1561 | - || !strcmp((char*)lfn.name, "..")) | ||
1562 | - continue; | ||
1563 | - } | ||
1564 | - lfn.checksum = 0x100; /* cannot use long name twice */ | ||
1565 | - | ||
1566 | - if (path_len + 1 + lfn.len >= PATH_MAX) { | ||
1567 | - fprintf(stderr, "Name too long: %s/%s\n", path, lfn.name); | ||
1568 | - goto fail; | ||
1569 | - } | ||
1570 | + if (is_volume_label(direntries + i) || is_dot(direntries + i) || | ||
1571 | + is_free(direntries + i)) | ||
1572 | + continue; | ||
1573 | + | ||
1574 | + subret = parse_long_name(&lfn, direntries + i); | ||
1575 | + if (subret < 0) { | ||
1576 | + fprintf(stderr, "Error in long name\n"); | ||
1577 | + goto fail; | ||
1578 | + } | ||
1579 | + if (subret == 0 || is_free(direntries + i)) | ||
1580 | + continue; | ||
1581 | + | ||
1582 | + if (fat_chksum(direntries+i) != lfn.checksum) { | ||
1583 | + subret = parse_short_name(s, &lfn, direntries + i); | ||
1584 | + if (subret < 0) { | ||
1585 | + fprintf(stderr, "Error in short name (%d)\n", subret); | ||
1586 | + goto fail; | ||
1587 | + } | ||
1588 | + if (subret > 0 || !strcmp((char*)lfn.name, ".") | ||
1589 | + || !strcmp((char*)lfn.name, "..")) | ||
1590 | + continue; | ||
1591 | + } | ||
1592 | + lfn.checksum = 0x100; /* cannot use long name twice */ | ||
1593 | + | ||
1594 | + if (path_len + 1 + lfn.len >= PATH_MAX) { | ||
1595 | + fprintf(stderr, "Name too long: %s/%s\n", path, lfn.name); | ||
1596 | + goto fail; | ||
1597 | + } | ||
1598 | pstrcpy(path2 + path_len + 1, sizeof(path2) - path_len - 1, | ||
1599 | (char*)lfn.name); | ||
1600 | |||
1601 | - if (is_directory(direntries + i)) { | ||
1602 | - if (begin_of_direntry(direntries + i) == 0) { | ||
1603 | - DLOG(fprintf(stderr, "invalid begin for directory: %s\n", path2); print_direntry(direntries + i)); | ||
1604 | - goto fail; | ||
1605 | - } | ||
1606 | - cluster_count = check_directory_consistency(s, | ||
1607 | - begin_of_direntry(direntries + i), path2); | ||
1608 | - if (cluster_count == 0) { | ||
1609 | - DLOG(fprintf(stderr, "problem in directory %s:\n", path2); print_direntry(direntries + i)); | ||
1610 | - goto fail; | ||
1611 | - } | ||
1612 | - } else if (is_file(direntries + i)) { | ||
1613 | - /* check file size with FAT */ | ||
1614 | - cluster_count = get_cluster_count_for_direntry(s, direntries + i, path2); | ||
1615 | - if (cluster_count != | ||
1616 | + if (is_directory(direntries + i)) { | ||
1617 | + if (begin_of_direntry(direntries + i) == 0) { | ||
1618 | + DLOG(fprintf(stderr, "invalid begin for directory: %s\n", path2); print_direntry(direntries + i)); | ||
1619 | + goto fail; | ||
1620 | + } | ||
1621 | + cluster_count = check_directory_consistency(s, | ||
1622 | + begin_of_direntry(direntries + i), path2); | ||
1623 | + if (cluster_count == 0) { | ||
1624 | + DLOG(fprintf(stderr, "problem in directory %s:\n", path2); print_direntry(direntries + i)); | ||
1625 | + goto fail; | ||
1626 | + } | ||
1627 | + } else if (is_file(direntries + i)) { | ||
1628 | + /* check file size with FAT */ | ||
1629 | + cluster_count = get_cluster_count_for_direntry(s, direntries + i, path2); | ||
1630 | + if (cluster_count != | ||
1631 | DIV_ROUND_UP(le32_to_cpu(direntries[i].size), s->cluster_size)) { | ||
1632 | - DLOG(fprintf(stderr, "Cluster count mismatch\n")); | ||
1633 | - goto fail; | ||
1634 | - } | ||
1635 | - } else | ||
1636 | + DLOG(fprintf(stderr, "Cluster count mismatch\n")); | ||
1637 | + goto fail; | ||
1638 | + } | ||
1639 | + } else | ||
1640 | abort(); /* cluster_count = 0; */ | ||
1641 | |||
1642 | - ret += cluster_count; | ||
1643 | - } | ||
1644 | + ret += cluster_count; | ||
1645 | + } | ||
1646 | |||
1647 | - cluster_num = modified_fat_get(s, cluster_num); | ||
1648 | + cluster_num = modified_fat_get(s, cluster_num); | ||
1649 | } while(!fat_eof(s, cluster_num)); | ||
1650 | |||
1651 | g_free(cluster); | ||
1652 | @@ -XXX,XX +XXX,XX @@ DLOG(checkpoint()); | ||
1653 | * - if all is fine, return number of used clusters | ||
1654 | */ | ||
1655 | if (s->fat2 == NULL) { | ||
1656 | - int size = 0x200 * s->sectors_per_fat; | ||
1657 | - s->fat2 = g_malloc(size); | ||
1658 | - memcpy(s->fat2, s->fat.pointer, size); | ||
1659 | + int size = 0x200 * s->sectors_per_fat; | ||
1660 | + s->fat2 = g_malloc(size); | ||
1661 | + memcpy(s->fat2, s->fat.pointer, size); | ||
1662 | } | ||
1663 | check = vvfat_read(s->bs, | ||
1664 | - s->first_sectors_number, s->fat2, s->sectors_per_fat); | ||
1665 | + s->first_sectors_number, s->fat2, s->sectors_per_fat); | ||
1666 | if (check) { | ||
1667 | - fprintf(stderr, "Could not copy fat\n"); | ||
1668 | - return 0; | ||
1669 | + fprintf(stderr, "Could not copy fat\n"); | ||
1670 | + return 0; | ||
1671 | } | ||
1672 | assert (s->used_clusters); | ||
1673 | for (i = 0; i < sector2cluster(s, s->sector_count); i++) | ||
1674 | - s->used_clusters[i] &= ~USED_ANY; | ||
1675 | + s->used_clusters[i] &= ~USED_ANY; | ||
1676 | |||
1677 | clear_commits(s); | ||
1678 | |||
1679 | /* mark every mapped file/directory as deleted. | ||
1680 | * (check_directory_consistency() will unmark those still present). */ | ||
1681 | if (s->qcow) | ||
1682 | - for (i = 0; i < s->mapping.next; i++) { | ||
1683 | - mapping_t* mapping = array_get(&(s->mapping), i); | ||
1684 | - if (mapping->first_mapping_index < 0) | ||
1685 | - mapping->mode |= MODE_DELETED; | ||
1686 | - } | ||
1687 | + for (i = 0; i < s->mapping.next; i++) { | ||
1688 | + mapping_t* mapping = array_get(&(s->mapping), i); | ||
1689 | + if (mapping->first_mapping_index < 0) | ||
1690 | + mapping->mode |= MODE_DELETED; | ||
1691 | + } | ||
1692 | |||
1693 | used_clusters_count = check_directory_consistency(s, 0, s->path); | ||
1694 | if (used_clusters_count <= 0) { | ||
1695 | - DLOG(fprintf(stderr, "problem in directory\n")); | ||
1696 | - return 0; | ||
1697 | + DLOG(fprintf(stderr, "problem in directory\n")); | ||
1698 | + return 0; | ||
1699 | } | ||
1700 | |||
1701 | check = s->last_cluster_of_root_directory; | ||
1702 | for (i = check; i < sector2cluster(s, s->sector_count); i++) { | ||
1703 | - if (modified_fat_get(s, i)) { | ||
1704 | - if(!s->used_clusters[i]) { | ||
1705 | - DLOG(fprintf(stderr, "FAT was modified (%d), but cluster is not used?\n", i)); | ||
1706 | - return 0; | ||
1707 | - } | ||
1708 | - check++; | ||
1709 | - } | ||
1710 | + if (modified_fat_get(s, i)) { | ||
1711 | + if(!s->used_clusters[i]) { | ||
1712 | + DLOG(fprintf(stderr, "FAT was modified (%d), but cluster is not used?\n", i)); | ||
1713 | + return 0; | ||
1714 | + } | ||
1715 | + check++; | ||
1716 | + } | ||
1717 | |||
1718 | - if (s->used_clusters[i] == USED_ALLOCATED) { | ||
1719 | - /* allocated, but not used... */ | ||
1720 | - DLOG(fprintf(stderr, "unused, modified cluster: %d\n", i)); | ||
1721 | - return 0; | ||
1722 | - } | ||
1723 | + if (s->used_clusters[i] == USED_ALLOCATED) { | ||
1724 | + /* allocated, but not used... */ | ||
1725 | + DLOG(fprintf(stderr, "unused, modified cluster: %d\n", i)); | ||
1726 | + return 0; | ||
1727 | + } | ||
1728 | } | ||
1729 | |||
1730 | if (check != used_clusters_count) | ||
1731 | - return 0; | ||
1732 | + return 0; | ||
1733 | |||
1734 | return used_clusters_count; | ||
1735 | } | ||
1736 | |||
1737 | static inline void adjust_mapping_indices(BDRVVVFATState* s, | ||
1738 | - int offset, int adjust) | ||
1739 | + int offset, int adjust) | ||
1740 | { | ||
1741 | int i; | ||
1742 | |||
1743 | for (i = 0; i < s->mapping.next; i++) { | ||
1744 | - mapping_t* mapping = array_get(&(s->mapping), i); | ||
1745 | + mapping_t* mapping = array_get(&(s->mapping), i); | ||
1746 | |||
1747 | #define ADJUST_MAPPING_INDEX(name) \ | ||
1748 | - if (mapping->name >= offset) \ | ||
1749 | - mapping->name += adjust | ||
1750 | + if (mapping->name >= offset) \ | ||
1751 | + mapping->name += adjust | ||
1752 | |||
1753 | - ADJUST_MAPPING_INDEX(first_mapping_index); | ||
1754 | - if (mapping->mode & MODE_DIRECTORY) | ||
1755 | - ADJUST_MAPPING_INDEX(info.dir.parent_mapping_index); | ||
1756 | + ADJUST_MAPPING_INDEX(first_mapping_index); | ||
1757 | + if (mapping->mode & MODE_DIRECTORY) | ||
1758 | + ADJUST_MAPPING_INDEX(info.dir.parent_mapping_index); | ||
1759 | } | ||
1760 | } | ||
1761 | |||
1762 | /* insert or update mapping */ | ||
1763 | static mapping_t* insert_mapping(BDRVVVFATState* s, | ||
1764 | - uint32_t begin, uint32_t end) | ||
1765 | + uint32_t begin, uint32_t end) | ||
1766 | { | ||
1767 | /* | ||
1768 | * - find mapping where mapping->begin >= begin, | ||
1769 | @@ -XXX,XX +XXX,XX @@ static mapping_t* insert_mapping(BDRVVVFATState* s, | ||
1770 | mapping_t* first_mapping = array_get(&(s->mapping), 0); | ||
1771 | |||
1772 | if (index < s->mapping.next && (mapping = array_get(&(s->mapping), index)) | ||
1773 | - && mapping->begin < begin) { | ||
1774 | - mapping->end = begin; | ||
1775 | - index++; | ||
1776 | - mapping = array_get(&(s->mapping), index); | ||
1777 | + && mapping->begin < begin) { | ||
1778 | + mapping->end = begin; | ||
1779 | + index++; | ||
1780 | + mapping = array_get(&(s->mapping), index); | ||
1781 | } | ||
1782 | if (index >= s->mapping.next || mapping->begin > begin) { | ||
1783 | - mapping = array_insert(&(s->mapping), index, 1); | ||
1784 | - mapping->path = NULL; | ||
1785 | - adjust_mapping_indices(s, index, +1); | ||
1786 | + mapping = array_insert(&(s->mapping), index, 1); | ||
1787 | + mapping->path = NULL; | ||
1788 | + adjust_mapping_indices(s, index, +1); | ||
1789 | } | ||
1790 | |||
1791 | mapping->begin = begin; | ||
1792 | @@ -XXX,XX +XXX,XX @@ assert(index + 1 >= s->mapping.next || | ||
1793 | next_mapping->begin >= end))); | ||
1794 | |||
1795 | if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer) | ||
1796 | - s->current_mapping = array_get(&(s->mapping), | ||
1797 | - s->current_mapping - first_mapping); | ||
1798 | + s->current_mapping = array_get(&(s->mapping), | ||
1799 | + s->current_mapping - first_mapping); | ||
1800 | |||
1801 | return mapping; | ||
1802 | } | ||
1803 | @@ -XXX,XX +XXX,XX @@ static int remove_mapping(BDRVVVFATState* s, int mapping_index) | ||
1804 | adjust_mapping_indices(s, mapping_index, -1); | ||
1805 | |||
1806 | if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer) | ||
1807 | - s->current_mapping = array_get(&(s->mapping), | ||
1808 | - s->current_mapping - first_mapping); | ||
1809 | + s->current_mapping = array_get(&(s->mapping), | ||
1810 | + s->current_mapping - first_mapping); | ||
1811 | |||
1812 | return 0; | ||
1813 | } | ||
1814 | @@ -XXX,XX +XXX,XX @@ static void adjust_dirindices(BDRVVVFATState* s, int offset, int adjust) | ||
1815 | { | ||
1816 | int i; | ||
1817 | for (i = 0; i < s->mapping.next; i++) { | ||
1818 | - mapping_t* mapping = array_get(&(s->mapping), i); | ||
1819 | - if (mapping->dir_index >= offset) | ||
1820 | - mapping->dir_index += adjust; | ||
1821 | - if ((mapping->mode & MODE_DIRECTORY) && | ||
1822 | - mapping->info.dir.first_dir_index >= offset) | ||
1823 | - mapping->info.dir.first_dir_index += adjust; | ||
1824 | + mapping_t* mapping = array_get(&(s->mapping), i); | ||
1825 | + if (mapping->dir_index >= offset) | ||
1826 | + mapping->dir_index += adjust; | ||
1827 | + if ((mapping->mode & MODE_DIRECTORY) && | ||
1828 | + mapping->info.dir.first_dir_index >= offset) | ||
1829 | + mapping->info.dir.first_dir_index += adjust; | ||
1830 | } | ||
1831 | } | ||
1832 | |||
1833 | static direntry_t* insert_direntries(BDRVVVFATState* s, | ||
1834 | - int dir_index, int count) | ||
1835 | + int dir_index, int count) | ||
1836 | { | ||
1837 | /* | ||
1838 | * make room in s->directory, | ||
1839 | @@ -XXX,XX +XXX,XX @@ static direntry_t* insert_direntries(BDRVVVFATState* s, | ||
1840 | */ | ||
1841 | direntry_t* result = array_insert(&(s->directory), dir_index, count); | ||
1842 | if (result == NULL) | ||
1843 | - return NULL; | ||
1844 | + return NULL; | ||
1845 | adjust_dirindices(s, dir_index, count); | ||
1846 | return result; | ||
1847 | } | ||
1848 | @@ -XXX,XX +XXX,XX @@ static int remove_direntries(BDRVVVFATState* s, int dir_index, int count) | ||
1849 | { | ||
1850 | int ret = array_remove_slice(&(s->directory), dir_index, count); | ||
1851 | if (ret) | ||
1852 | - return ret; | ||
1853 | + return ret; | ||
1854 | adjust_dirindices(s, dir_index, -count); | ||
1855 | return 0; | ||
1856 | } | ||
1857 | @@ -XXX,XX +XXX,XX @@ static int remove_direntries(BDRVVVFATState* s, int dir_index, int count) | ||
1858 | * adjusted) | ||
1859 | */ | ||
1860 | static int commit_mappings(BDRVVVFATState* s, | ||
1861 | - uint32_t first_cluster, int dir_index) | ||
1862 | + uint32_t first_cluster, int dir_index) | ||
1863 | { | ||
1864 | mapping_t* mapping = find_mapping_for_cluster(s, first_cluster); | ||
1865 | direntry_t* direntry = array_get(&(s->directory), dir_index); | ||
1866 | @@ -XXX,XX +XXX,XX @@ static int commit_mappings(BDRVVVFATState* s, | ||
1867 | mapping->first_mapping_index = -1; | ||
1868 | mapping->dir_index = dir_index; | ||
1869 | mapping->mode = (dir_index <= 0 || is_directory(direntry)) ? | ||
1870 | - MODE_DIRECTORY : MODE_NORMAL; | ||
1871 | + MODE_DIRECTORY : MODE_NORMAL; | ||
1872 | |||
1873 | while (!fat_eof(s, cluster)) { | ||
1874 | - uint32_t c, c1; | ||
1875 | - | ||
1876 | - for (c = cluster, c1 = modified_fat_get(s, c); c + 1 == c1; | ||
1877 | - c = c1, c1 = modified_fat_get(s, c1)); | ||
1878 | - | ||
1879 | - c++; | ||
1880 | - if (c > mapping->end) { | ||
1881 | - int index = array_index(&(s->mapping), mapping); | ||
1882 | - int i, max_i = s->mapping.next - index; | ||
1883 | - for (i = 1; i < max_i && mapping[i].begin < c; i++); | ||
1884 | - while (--i > 0) | ||
1885 | - remove_mapping(s, index + 1); | ||
1886 | - } | ||
1887 | - assert(mapping == array_get(&(s->mapping), s->mapping.next - 1) | ||
1888 | - || mapping[1].begin >= c); | ||
1889 | - mapping->end = c; | ||
1890 | - | ||
1891 | - if (!fat_eof(s, c1)) { | ||
1892 | - int i = find_mapping_for_cluster_aux(s, c1, 0, s->mapping.next); | ||
1893 | - mapping_t* next_mapping = i >= s->mapping.next ? NULL : | ||
1894 | - array_get(&(s->mapping), i); | ||
1895 | - | ||
1896 | - if (next_mapping == NULL || next_mapping->begin > c1) { | ||
1897 | - int i1 = array_index(&(s->mapping), mapping); | ||
1898 | - | ||
1899 | - next_mapping = insert_mapping(s, c1, c1+1); | ||
1900 | - | ||
1901 | - if (c1 < c) | ||
1902 | - i1++; | ||
1903 | - mapping = array_get(&(s->mapping), i1); | ||
1904 | - } | ||
1905 | - | ||
1906 | - next_mapping->dir_index = mapping->dir_index; | ||
1907 | - next_mapping->first_mapping_index = | ||
1908 | - mapping->first_mapping_index < 0 ? | ||
1909 | - array_index(&(s->mapping), mapping) : | ||
1910 | - mapping->first_mapping_index; | ||
1911 | - next_mapping->path = mapping->path; | ||
1912 | - next_mapping->mode = mapping->mode; | ||
1913 | - next_mapping->read_only = mapping->read_only; | ||
1914 | - if (mapping->mode & MODE_DIRECTORY) { | ||
1915 | - next_mapping->info.dir.parent_mapping_index = | ||
1916 | - mapping->info.dir.parent_mapping_index; | ||
1917 | - next_mapping->info.dir.first_dir_index = | ||
1918 | - mapping->info.dir.first_dir_index + | ||
1919 | - 0x10 * s->sectors_per_cluster * | ||
1920 | - (mapping->end - mapping->begin); | ||
1921 | - } else | ||
1922 | - next_mapping->info.file.offset = mapping->info.file.offset + | ||
1923 | - mapping->end - mapping->begin; | ||
1924 | - | ||
1925 | - mapping = next_mapping; | ||
1926 | - } | ||
1927 | - | ||
1928 | - cluster = c1; | ||
1929 | + uint32_t c, c1; | ||
1930 | + | ||
1931 | + for (c = cluster, c1 = modified_fat_get(s, c); c + 1 == c1; | ||
1932 | + c = c1, c1 = modified_fat_get(s, c1)); | ||
1933 | + | ||
1934 | + c++; | ||
1935 | + if (c > mapping->end) { | ||
1936 | + int index = array_index(&(s->mapping), mapping); | ||
1937 | + int i, max_i = s->mapping.next - index; | ||
1938 | + for (i = 1; i < max_i && mapping[i].begin < c; i++); | ||
1939 | + while (--i > 0) | ||
1940 | + remove_mapping(s, index + 1); | ||
1941 | + } | ||
1942 | + assert(mapping == array_get(&(s->mapping), s->mapping.next - 1) | ||
1943 | + || mapping[1].begin >= c); | ||
1944 | + mapping->end = c; | ||
1945 | + | ||
1946 | + if (!fat_eof(s, c1)) { | ||
1947 | + int i = find_mapping_for_cluster_aux(s, c1, 0, s->mapping.next); | ||
1948 | + mapping_t* next_mapping = i >= s->mapping.next ? NULL : | ||
1949 | + array_get(&(s->mapping), i); | ||
1950 | + | ||
1951 | + if (next_mapping == NULL || next_mapping->begin > c1) { | ||
1952 | + int i1 = array_index(&(s->mapping), mapping); | ||
1953 | + | ||
1954 | + next_mapping = insert_mapping(s, c1, c1+1); | ||
1955 | + | ||
1956 | + if (c1 < c) | ||
1957 | + i1++; | ||
1958 | + mapping = array_get(&(s->mapping), i1); | ||
1959 | + } | ||
1960 | + | ||
1961 | + next_mapping->dir_index = mapping->dir_index; | ||
1962 | + next_mapping->first_mapping_index = | ||
1963 | + mapping->first_mapping_index < 0 ? | ||
1964 | + array_index(&(s->mapping), mapping) : | ||
1965 | + mapping->first_mapping_index; | ||
1966 | + next_mapping->path = mapping->path; | ||
1967 | + next_mapping->mode = mapping->mode; | ||
1968 | + next_mapping->read_only = mapping->read_only; | ||
1969 | + if (mapping->mode & MODE_DIRECTORY) { | ||
1970 | + next_mapping->info.dir.parent_mapping_index = | ||
1971 | + mapping->info.dir.parent_mapping_index; | ||
1972 | + next_mapping->info.dir.first_dir_index = | ||
1973 | + mapping->info.dir.first_dir_index + | ||
1974 | + 0x10 * s->sectors_per_cluster * | ||
1975 | + (mapping->end - mapping->begin); | ||
1976 | + } else | ||
1977 | + next_mapping->info.file.offset = mapping->info.file.offset + | ||
1978 | + mapping->end - mapping->begin; | ||
1979 | + | ||
1980 | + mapping = next_mapping; | ||
1981 | + } | ||
1982 | + | ||
1983 | + cluster = c1; | ||
1984 | } | ||
1985 | |||
1986 | return 0; | ||
1987 | } | ||
1988 | |||
1989 | static int commit_direntries(BDRVVVFATState* s, | ||
1990 | - int dir_index, int parent_mapping_index) | ||
1991 | + int dir_index, int parent_mapping_index) | ||
1992 | { | ||
1993 | direntry_t* direntry = array_get(&(s->directory), dir_index); | ||
1994 | uint32_t first_cluster = dir_index == 0 ? 0 : begin_of_direntry(direntry); | ||
1995 | @@ -XXX,XX +XXX,XX @@ DLOG(fprintf(stderr, "commit_direntries for %s, parent_mapping_index %d\n", mapp | ||
1996 | mapping->info.dir.parent_mapping_index = parent_mapping_index; | ||
1997 | |||
1998 | if (first_cluster == 0) { | ||
1999 | - old_cluster_count = new_cluster_count = | ||
2000 | - s->last_cluster_of_root_directory; | ||
2001 | + old_cluster_count = new_cluster_count = | ||
2002 | + s->last_cluster_of_root_directory; | ||
2003 | } else { | ||
2004 | - for (old_cluster_count = 0, c = first_cluster; !fat_eof(s, c); | ||
2005 | - c = fat_get(s, c)) | ||
2006 | - old_cluster_count++; | ||
2007 | + for (old_cluster_count = 0, c = first_cluster; !fat_eof(s, c); | ||
2008 | + c = fat_get(s, c)) | ||
2009 | + old_cluster_count++; | ||
2010 | |||
2011 | - for (new_cluster_count = 0, c = first_cluster; !fat_eof(s, c); | ||
2012 | - c = modified_fat_get(s, c)) | ||
2013 | - new_cluster_count++; | ||
2014 | + for (new_cluster_count = 0, c = first_cluster; !fat_eof(s, c); | ||
2015 | + c = modified_fat_get(s, c)) | ||
2016 | + new_cluster_count++; | ||
2017 | } | ||
2018 | |||
2019 | if (new_cluster_count > old_cluster_count) { | ||
2020 | - if (insert_direntries(s, | ||
2021 | - current_dir_index + factor * old_cluster_count, | ||
2022 | - factor * (new_cluster_count - old_cluster_count)) == NULL) | ||
2023 | - return -1; | ||
2024 | + if (insert_direntries(s, | ||
2025 | + current_dir_index + factor * old_cluster_count, | ||
2026 | + factor * (new_cluster_count - old_cluster_count)) == NULL) | ||
2027 | + return -1; | ||
2028 | } else if (new_cluster_count < old_cluster_count) | ||
2029 | - remove_direntries(s, | ||
2030 | - current_dir_index + factor * new_cluster_count, | ||
2031 | - factor * (old_cluster_count - new_cluster_count)); | ||
2032 | + remove_direntries(s, | ||
2033 | + current_dir_index + factor * new_cluster_count, | ||
2034 | + factor * (old_cluster_count - new_cluster_count)); | ||
2035 | |||
2036 | for (c = first_cluster; !fat_eof(s, c); c = modified_fat_get(s, c)) { | ||
2037 | direntry_t *first_direntry; | ||
2038 | - void* direntry = array_get(&(s->directory), current_dir_index); | ||
2039 | - int ret = vvfat_read(s->bs, cluster2sector(s, c), direntry, | ||
2040 | - s->sectors_per_cluster); | ||
2041 | - if (ret) | ||
2042 | - return ret; | ||
2043 | + void* direntry = array_get(&(s->directory), current_dir_index); | ||
2044 | + int ret = vvfat_read(s->bs, cluster2sector(s, c), direntry, | ||
2045 | + s->sectors_per_cluster); | ||
2046 | + if (ret) | ||
2047 | + return ret; | ||
2048 | |||
2049 | /* The first directory entry on the filesystem is the volume name */ | ||
2050 | first_direntry = (direntry_t*) s->directory.pointer; | ||
2051 | assert(!memcmp(first_direntry->name, s->volume_label, 11)); | ||
2052 | |||
2053 | - current_dir_index += factor; | ||
2054 | + current_dir_index += factor; | ||
2055 | } | ||
2056 | |||
2057 | ret = commit_mappings(s, first_cluster, dir_index); | ||
2058 | if (ret) | ||
2059 | - return ret; | ||
2060 | + return ret; | ||
2061 | |||
2062 | /* recurse */ | ||
2063 | for (i = 0; i < factor * new_cluster_count; i++) { | ||
2064 | - direntry = array_get(&(s->directory), first_dir_index + i); | ||
2065 | - if (is_directory(direntry) && !is_dot(direntry)) { | ||
2066 | - mapping = find_mapping_for_cluster(s, first_cluster); | ||
2067 | - assert(mapping->mode & MODE_DIRECTORY); | ||
2068 | - ret = commit_direntries(s, first_dir_index + i, | ||
2069 | - array_index(&(s->mapping), mapping)); | ||
2070 | - if (ret) | ||
2071 | - return ret; | ||
2072 | - } | ||
2073 | + direntry = array_get(&(s->directory), first_dir_index + i); | ||
2074 | + if (is_directory(direntry) && !is_dot(direntry)) { | ||
2075 | + mapping = find_mapping_for_cluster(s, first_cluster); | ||
2076 | + assert(mapping->mode & MODE_DIRECTORY); | ||
2077 | + ret = commit_direntries(s, first_dir_index + i, | ||
2078 | + array_index(&(s->mapping), mapping)); | ||
2079 | + if (ret) | ||
2080 | + return ret; | ||
2081 | + } | ||
2082 | } | ||
2083 | |||
2084 | return 0; | ||
2085 | @@ -XXX,XX +XXX,XX @@ DLOG(fprintf(stderr, "commit_direntries for %s, parent_mapping_index %d\n", mapp | ||
2086 | /* commit one file (adjust contents, adjust mapping), | ||
2087 | return first_mapping_index */ | ||
2088 | static int commit_one_file(BDRVVVFATState* s, | ||
2089 | - int dir_index, uint32_t offset) | ||
2090 | + int dir_index, uint32_t offset) | ||
2091 | { | ||
2092 | direntry_t* direntry = array_get(&(s->directory), dir_index); | ||
2093 | uint32_t c = begin_of_direntry(direntry); | ||
2094 | @@ -XXX,XX +XXX,XX @@ static int commit_one_file(BDRVVVFATState* s, | ||
2095 | assert((offset % s->cluster_size) == 0); | ||
2096 | |||
2097 | for (i = s->cluster_size; i < offset; i += s->cluster_size) | ||
2098 | - c = modified_fat_get(s, c); | ||
2099 | + c = modified_fat_get(s, c); | ||
2100 | |||
2101 | fd = qemu_open(mapping->path, O_RDWR | O_CREAT | O_BINARY, 0666); | ||
2102 | if (fd < 0) { | ||
2103 | - fprintf(stderr, "Could not open %s... (%s, %d)\n", mapping->path, | ||
2104 | - strerror(errno), errno); | ||
2105 | + fprintf(stderr, "Could not open %s... (%s, %d)\n", mapping->path, | ||
2106 | + strerror(errno), errno); | ||
2107 | g_free(cluster); | ||
2108 | - return fd; | ||
2109 | + return fd; | ||
2110 | } | ||
2111 | if (offset > 0) { | ||
2112 | if (lseek(fd, offset, SEEK_SET) != offset) { | ||
2113 | @@ -XXX,XX +XXX,XX @@ static int commit_one_file(BDRVVVFATState* s, | ||
2114 | } | ||
2115 | |||
2116 | while (offset < size) { | ||
2117 | - uint32_t c1; | ||
2118 | - int rest_size = (size - offset > s->cluster_size ? | ||
2119 | - s->cluster_size : size - offset); | ||
2120 | - int ret; | ||
2121 | + uint32_t c1; | ||
2122 | + int rest_size = (size - offset > s->cluster_size ? | ||
2123 | + s->cluster_size : size - offset); | ||
2124 | + int ret; | ||
2125 | |||
2126 | - c1 = modified_fat_get(s, c); | ||
2127 | + c1 = modified_fat_get(s, c); | ||
2128 | |||
2129 | - assert((size - offset == 0 && fat_eof(s, c)) || | ||
2130 | - (size > offset && c >=2 && !fat_eof(s, c))); | ||
2131 | + assert((size - offset == 0 && fat_eof(s, c)) || | ||
2132 | + (size > offset && c >=2 && !fat_eof(s, c))); | ||
2133 | |||
2134 | - ret = vvfat_read(s->bs, cluster2sector(s, c), | ||
2135 | - (uint8_t*)cluster, (rest_size + 0x1ff) / 0x200); | ||
2136 | + ret = vvfat_read(s->bs, cluster2sector(s, c), | ||
2137 | + (uint8_t*)cluster, (rest_size + 0x1ff) / 0x200); | ||
2138 | |||
2139 | if (ret < 0) { | ||
2140 | qemu_close(fd); | ||
2141 | @@ -XXX,XX +XXX,XX @@ static int commit_one_file(BDRVVVFATState* s, | ||
2142 | return -2; | ||
2143 | } | ||
2144 | |||
2145 | - offset += rest_size; | ||
2146 | - c = c1; | ||
2147 | + offset += rest_size; | ||
2148 | + c = c1; | ||
2149 | } | ||
2150 | |||
2151 | if (ftruncate(fd, size)) { | ||
2152 | @@ -XXX,XX +XXX,XX @@ static void check1(BDRVVVFATState* s) | ||
2153 | { | ||
2154 | int i; | ||
2155 | for (i = 0; i < s->mapping.next; i++) { | ||
2156 | - mapping_t* mapping = array_get(&(s->mapping), i); | ||
2157 | - if (mapping->mode & MODE_DELETED) { | ||
2158 | - fprintf(stderr, "deleted\n"); | ||
2159 | - continue; | ||
2160 | - } | ||
2161 | - assert(mapping->dir_index < s->directory.next); | ||
2162 | - direntry_t* direntry = array_get(&(s->directory), mapping->dir_index); | ||
2163 | - assert(mapping->begin == begin_of_direntry(direntry) || mapping->first_mapping_index >= 0); | ||
2164 | - if (mapping->mode & MODE_DIRECTORY) { | ||
2165 | - assert(mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster * (mapping->end - mapping->begin) <= s->directory.next); | ||
2166 | - assert((mapping->info.dir.first_dir_index % (0x10 * s->sectors_per_cluster)) == 0); | ||
2167 | - } | ||
2168 | + mapping_t* mapping = array_get(&(s->mapping), i); | ||
2169 | + if (mapping->mode & MODE_DELETED) { | ||
2170 | + fprintf(stderr, "deleted\n"); | ||
2171 | + continue; | ||
2172 | + } | ||
2173 | + assert(mapping->dir_index < s->directory.next); | ||
2174 | + direntry_t* direntry = array_get(&(s->directory), mapping->dir_index); | ||
2175 | + assert(mapping->begin == begin_of_direntry(direntry) || mapping->first_mapping_index >= 0); | ||
2176 | + if (mapping->mode & MODE_DIRECTORY) { | ||
2177 | + assert(mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster * (mapping->end - mapping->begin) <= s->directory.next); | ||
2178 | + assert((mapping->info.dir.first_dir_index % (0x10 * s->sectors_per_cluster)) == 0); | ||
2179 | + } | ||
2180 | } | ||
2181 | } | ||
2182 | |||
2183 | @@ -XXX,XX +XXX,XX @@ static void check2(BDRVVVFATState* s) | ||
2184 | int first_mapping = -1; | ||
2185 | |||
2186 | for (i = 0; i < s->directory.next; i++) { | ||
2187 | - direntry_t* direntry = array_get(&(s->directory), i); | ||
2188 | - | ||
2189 | - if (is_short_name(direntry) && begin_of_direntry(direntry)) { | ||
2190 | - mapping_t* mapping = find_mapping_for_cluster(s, begin_of_direntry(direntry)); | ||
2191 | - assert(mapping); | ||
2192 | - assert(mapping->dir_index == i || is_dot(direntry)); | ||
2193 | - assert(mapping->begin == begin_of_direntry(direntry) || is_dot(direntry)); | ||
2194 | - } | ||
2195 | - | ||
2196 | - if ((i % (0x10 * s->sectors_per_cluster)) == 0) { | ||
2197 | - /* cluster start */ | ||
2198 | - int j, count = 0; | ||
2199 | - | ||
2200 | - for (j = 0; j < s->mapping.next; j++) { | ||
2201 | - mapping_t* mapping = array_get(&(s->mapping), j); | ||
2202 | - if (mapping->mode & MODE_DELETED) | ||
2203 | - continue; | ||
2204 | - if (mapping->mode & MODE_DIRECTORY) { | ||
2205 | - if (mapping->info.dir.first_dir_index <= i && mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster > i) { | ||
2206 | - assert(++count == 1); | ||
2207 | - if (mapping->first_mapping_index == -1) | ||
2208 | - first_mapping = array_index(&(s->mapping), mapping); | ||
2209 | - else | ||
2210 | - assert(first_mapping == mapping->first_mapping_index); | ||
2211 | - if (mapping->info.dir.parent_mapping_index < 0) | ||
2212 | - assert(j == 0); | ||
2213 | - else { | ||
2214 | - mapping_t* parent = array_get(&(s->mapping), mapping->info.dir.parent_mapping_index); | ||
2215 | - assert(parent->mode & MODE_DIRECTORY); | ||
2216 | - assert(parent->info.dir.first_dir_index < mapping->info.dir.first_dir_index); | ||
2217 | - } | ||
2218 | - } | ||
2219 | - } | ||
2220 | - } | ||
2221 | - if (count == 0) | ||
2222 | - first_mapping = -1; | ||
2223 | - } | ||
2224 | + direntry_t* direntry = array_get(&(s->directory), i); | ||
2225 | + | ||
2226 | + if (is_short_name(direntry) && begin_of_direntry(direntry)) { | ||
2227 | + mapping_t* mapping = find_mapping_for_cluster(s, begin_of_direntry(direntry)); | ||
2228 | + assert(mapping); | ||
2229 | + assert(mapping->dir_index == i || is_dot(direntry)); | ||
2230 | + assert(mapping->begin == begin_of_direntry(direntry) || is_dot(direntry)); | ||
2231 | + } | ||
2232 | + | ||
2233 | + if ((i % (0x10 * s->sectors_per_cluster)) == 0) { | ||
2234 | + /* cluster start */ | ||
2235 | + int j, count = 0; | ||
2236 | + | ||
2237 | + for (j = 0; j < s->mapping.next; j++) { | ||
2238 | + mapping_t* mapping = array_get(&(s->mapping), j); | ||
2239 | + if (mapping->mode & MODE_DELETED) | ||
2240 | + continue; | ||
2241 | + if (mapping->mode & MODE_DIRECTORY) { | ||
2242 | + if (mapping->info.dir.first_dir_index <= i && mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster > i) { | ||
2243 | + assert(++count == 1); | ||
2244 | + if (mapping->first_mapping_index == -1) | ||
2245 | + first_mapping = array_index(&(s->mapping), mapping); | ||
2246 | + else | ||
2247 | + assert(first_mapping == mapping->first_mapping_index); | ||
2248 | + if (mapping->info.dir.parent_mapping_index < 0) | ||
2249 | + assert(j == 0); | ||
2250 | + else { | ||
2251 | + mapping_t* parent = array_get(&(s->mapping), mapping->info.dir.parent_mapping_index); | ||
2252 | + assert(parent->mode & MODE_DIRECTORY); | ||
2253 | + assert(parent->info.dir.first_dir_index < mapping->info.dir.first_dir_index); | ||
2254 | + } | ||
2255 | + } | ||
2256 | + } | ||
2257 | + } | ||
2258 | + if (count == 0) | ||
2259 | + first_mapping = -1; | ||
2260 | + } | ||
2261 | } | ||
2262 | } | ||
2263 | #endif | ||
2264 | @@ -XXX,XX +XXX,XX @@ static int handle_renames_and_mkdirs(BDRVVVFATState* s) | ||
2265 | #ifdef DEBUG | ||
2266 | fprintf(stderr, "handle_renames\n"); | ||
2267 | for (i = 0; i < s->commits.next; i++) { | ||
2268 | - commit_t* commit = array_get(&(s->commits), i); | ||
2269 | - fprintf(stderr, "%d, %s (%d, %d)\n", i, commit->path ? commit->path : "(null)", commit->param.rename.cluster, commit->action); | ||
2270 | + commit_t* commit = array_get(&(s->commits), i); | ||
2271 | + fprintf(stderr, "%d, %s (%d, %d)\n", i, commit->path ? commit->path : "(null)", commit->param.rename.cluster, commit->action); | ||
2272 | } | ||
2273 | #endif | ||
2274 | |||
2275 | for (i = 0; i < s->commits.next;) { | ||
2276 | - commit_t* commit = array_get(&(s->commits), i); | ||
2277 | - if (commit->action == ACTION_RENAME) { | ||
2278 | - mapping_t* mapping = find_mapping_for_cluster(s, | ||
2279 | - commit->param.rename.cluster); | ||
2280 | - char* old_path = mapping->path; | ||
2281 | - | ||
2282 | - assert(commit->path); | ||
2283 | - mapping->path = commit->path; | ||
2284 | - if (rename(old_path, mapping->path)) | ||
2285 | - return -2; | ||
2286 | - | ||
2287 | - if (mapping->mode & MODE_DIRECTORY) { | ||
2288 | - int l1 = strlen(mapping->path); | ||
2289 | - int l2 = strlen(old_path); | ||
2290 | - int diff = l1 - l2; | ||
2291 | - direntry_t* direntry = array_get(&(s->directory), | ||
2292 | - mapping->info.dir.first_dir_index); | ||
2293 | - uint32_t c = mapping->begin; | ||
2294 | - int i = 0; | ||
2295 | - | ||
2296 | - /* recurse */ | ||
2297 | - while (!fat_eof(s, c)) { | ||
2298 | - do { | ||
2299 | - direntry_t* d = direntry + i; | ||
2300 | - | ||
2301 | - if (is_file(d) || (is_directory(d) && !is_dot(d))) { | ||
2302 | - mapping_t* m = find_mapping_for_cluster(s, | ||
2303 | - begin_of_direntry(d)); | ||
2304 | - int l = strlen(m->path); | ||
2305 | - char* new_path = g_malloc(l + diff + 1); | ||
2306 | - | ||
2307 | - assert(!strncmp(m->path, mapping->path, l2)); | ||
2308 | + commit_t* commit = array_get(&(s->commits), i); | ||
2309 | + if (commit->action == ACTION_RENAME) { | ||
2310 | + mapping_t* mapping = find_mapping_for_cluster(s, | ||
2311 | + commit->param.rename.cluster); | ||
2312 | + char* old_path = mapping->path; | ||
2313 | + | ||
2314 | + assert(commit->path); | ||
2315 | + mapping->path = commit->path; | ||
2316 | + if (rename(old_path, mapping->path)) | ||
2317 | + return -2; | ||
2318 | + | ||
2319 | + if (mapping->mode & MODE_DIRECTORY) { | ||
2320 | + int l1 = strlen(mapping->path); | ||
2321 | + int l2 = strlen(old_path); | ||
2322 | + int diff = l1 - l2; | ||
2323 | + direntry_t* direntry = array_get(&(s->directory), | ||
2324 | + mapping->info.dir.first_dir_index); | ||
2325 | + uint32_t c = mapping->begin; | ||
2326 | + int i = 0; | ||
2327 | + | ||
2328 | + /* recurse */ | ||
2329 | + while (!fat_eof(s, c)) { | ||
2330 | + do { | ||
2331 | + direntry_t* d = direntry + i; | ||
2332 | + | ||
2333 | + if (is_file(d) || (is_directory(d) && !is_dot(d))) { | ||
2334 | + mapping_t* m = find_mapping_for_cluster(s, | ||
2335 | + begin_of_direntry(d)); | ||
2336 | + int l = strlen(m->path); | ||
2337 | + char* new_path = g_malloc(l + diff + 1); | ||
2338 | + | ||
2339 | + assert(!strncmp(m->path, mapping->path, l2)); | ||
2340 | |||
2341 | pstrcpy(new_path, l + diff + 1, mapping->path); | ||
2342 | pstrcpy(new_path + l1, l + diff + 1 - l1, | ||
2343 | m->path + l2); | ||
2344 | |||
2345 | - schedule_rename(s, m->begin, new_path); | ||
2346 | - } | ||
2347 | - i++; | ||
2348 | - } while((i % (0x10 * s->sectors_per_cluster)) != 0); | ||
2349 | - c = fat_get(s, c); | ||
2350 | - } | ||
2351 | - } | ||
2352 | + schedule_rename(s, m->begin, new_path); | ||
2353 | + } | ||
2354 | + i++; | ||
2355 | + } while((i % (0x10 * s->sectors_per_cluster)) != 0); | ||
2356 | + c = fat_get(s, c); | ||
2357 | + } | ||
2358 | + } | ||
2359 | |||
2360 | g_free(old_path); | ||
2361 | - array_remove(&(s->commits), i); | ||
2362 | - continue; | ||
2363 | - } else if (commit->action == ACTION_MKDIR) { | ||
2364 | - mapping_t* mapping; | ||
2365 | - int j, parent_path_len; | ||
2366 | + array_remove(&(s->commits), i); | ||
2367 | + continue; | ||
2368 | + } else if (commit->action == ACTION_MKDIR) { | ||
2369 | + mapping_t* mapping; | ||
2370 | + int j, parent_path_len; | ||
2371 | |||
2372 | #ifdef __MINGW32__ | ||
2373 | if (mkdir(commit->path)) | ||
2374 | @@ -XXX,XX +XXX,XX @@ static int handle_renames_and_mkdirs(BDRVVVFATState* s) | ||
2375 | return -5; | ||
2376 | #endif | ||
2377 | |||
2378 | - mapping = insert_mapping(s, commit->param.mkdir.cluster, | ||
2379 | - commit->param.mkdir.cluster + 1); | ||
2380 | - if (mapping == NULL) | ||
2381 | - return -6; | ||
2382 | - | ||
2383 | - mapping->mode = MODE_DIRECTORY; | ||
2384 | - mapping->read_only = 0; | ||
2385 | - mapping->path = commit->path; | ||
2386 | - j = s->directory.next; | ||
2387 | - assert(j); | ||
2388 | - insert_direntries(s, s->directory.next, | ||
2389 | - 0x10 * s->sectors_per_cluster); | ||
2390 | - mapping->info.dir.first_dir_index = j; | ||
2391 | - | ||
2392 | - parent_path_len = strlen(commit->path) | ||
2393 | - - strlen(get_basename(commit->path)) - 1; | ||
2394 | - for (j = 0; j < s->mapping.next; j++) { | ||
2395 | - mapping_t* m = array_get(&(s->mapping), j); | ||
2396 | - if (m->first_mapping_index < 0 && m != mapping && | ||
2397 | - !strncmp(m->path, mapping->path, parent_path_len) && | ||
2398 | - strlen(m->path) == parent_path_len) | ||
2399 | - break; | ||
2400 | - } | ||
2401 | - assert(j < s->mapping.next); | ||
2402 | - mapping->info.dir.parent_mapping_index = j; | ||
2403 | - | ||
2404 | - array_remove(&(s->commits), i); | ||
2405 | - continue; | ||
2406 | - } | ||
2407 | - | ||
2408 | - i++; | ||
2409 | + mapping = insert_mapping(s, commit->param.mkdir.cluster, | ||
2410 | + commit->param.mkdir.cluster + 1); | ||
2411 | + if (mapping == NULL) | ||
2412 | + return -6; | ||
2413 | + | ||
2414 | + mapping->mode = MODE_DIRECTORY; | ||
2415 | + mapping->read_only = 0; | ||
2416 | + mapping->path = commit->path; | ||
2417 | + j = s->directory.next; | ||
2418 | + assert(j); | ||
2419 | + insert_direntries(s, s->directory.next, | ||
2420 | + 0x10 * s->sectors_per_cluster); | ||
2421 | + mapping->info.dir.first_dir_index = j; | ||
2422 | + | ||
2423 | + parent_path_len = strlen(commit->path) | ||
2424 | + - strlen(get_basename(commit->path)) - 1; | ||
2425 | + for (j = 0; j < s->mapping.next; j++) { | ||
2426 | + mapping_t* m = array_get(&(s->mapping), j); | ||
2427 | + if (m->first_mapping_index < 0 && m != mapping && | ||
2428 | + !strncmp(m->path, mapping->path, parent_path_len) && | ||
2429 | + strlen(m->path) == parent_path_len) | ||
2430 | + break; | ||
2431 | + } | ||
2432 | + assert(j < s->mapping.next); | ||
2433 | + mapping->info.dir.parent_mapping_index = j; | ||
2434 | + | ||
2435 | + array_remove(&(s->commits), i); | ||
2436 | + continue; | ||
2437 | + } | ||
2438 | + | ||
2439 | + i++; | ||
2440 | } | ||
2441 | return 0; | ||
2442 | } | ||
2443 | @@ -XXX,XX +XXX,XX @@ static int handle_commits(BDRVVVFATState* s) | ||
2444 | vvfat_close_current_file(s); | ||
2445 | |||
2446 | for (i = 0; !fail && i < s->commits.next; i++) { | ||
2447 | - commit_t* commit = array_get(&(s->commits), i); | ||
2448 | - switch(commit->action) { | ||
2449 | - case ACTION_RENAME: case ACTION_MKDIR: | ||
2450 | + commit_t* commit = array_get(&(s->commits), i); | ||
2451 | + switch(commit->action) { | ||
2452 | + case ACTION_RENAME: case ACTION_MKDIR: | ||
2453 | abort(); | ||
2454 | - fail = -2; | ||
2455 | - break; | ||
2456 | - case ACTION_WRITEOUT: { | ||
2457 | + fail = -2; | ||
2458 | + break; | ||
2459 | + case ACTION_WRITEOUT: { | ||
2460 | #ifndef NDEBUG | ||
2461 | /* these variables are only used by assert() below */ | ||
2462 | - direntry_t* entry = array_get(&(s->directory), | ||
2463 | - commit->param.writeout.dir_index); | ||
2464 | - uint32_t begin = begin_of_direntry(entry); | ||
2465 | - mapping_t* mapping = find_mapping_for_cluster(s, begin); | ||
2466 | + direntry_t* entry = array_get(&(s->directory), | ||
2467 | + commit->param.writeout.dir_index); | ||
2468 | + uint32_t begin = begin_of_direntry(entry); | ||
2469 | + mapping_t* mapping = find_mapping_for_cluster(s, begin); | ||
2470 | #endif | ||
2471 | |||
2472 | - assert(mapping); | ||
2473 | - assert(mapping->begin == begin); | ||
2474 | - assert(commit->path == NULL); | ||
2475 | - | ||
2476 | - if (commit_one_file(s, commit->param.writeout.dir_index, | ||
2477 | - commit->param.writeout.modified_offset)) | ||
2478 | - fail = -3; | ||
2479 | - | ||
2480 | - break; | ||
2481 | - } | ||
2482 | - case ACTION_NEW_FILE: { | ||
2483 | - int begin = commit->param.new_file.first_cluster; | ||
2484 | - mapping_t* mapping = find_mapping_for_cluster(s, begin); | ||
2485 | - direntry_t* entry; | ||
2486 | - int i; | ||
2487 | - | ||
2488 | - /* find direntry */ | ||
2489 | - for (i = 0; i < s->directory.next; i++) { | ||
2490 | - entry = array_get(&(s->directory), i); | ||
2491 | - if (is_file(entry) && begin_of_direntry(entry) == begin) | ||
2492 | - break; | ||
2493 | - } | ||
2494 | - | ||
2495 | - if (i >= s->directory.next) { | ||
2496 | - fail = -6; | ||
2497 | - continue; | ||
2498 | - } | ||
2499 | - | ||
2500 | - /* make sure there exists an initial mapping */ | ||
2501 | - if (mapping && mapping->begin != begin) { | ||
2502 | - mapping->end = begin; | ||
2503 | - mapping = NULL; | ||
2504 | - } | ||
2505 | - if (mapping == NULL) { | ||
2506 | - mapping = insert_mapping(s, begin, begin+1); | ||
2507 | - } | ||
2508 | - /* most members will be fixed in commit_mappings() */ | ||
2509 | - assert(commit->path); | ||
2510 | - mapping->path = commit->path; | ||
2511 | - mapping->read_only = 0; | ||
2512 | - mapping->mode = MODE_NORMAL; | ||
2513 | - mapping->info.file.offset = 0; | ||
2514 | - | ||
2515 | - if (commit_one_file(s, i, 0)) | ||
2516 | - fail = -7; | ||
2517 | - | ||
2518 | - break; | ||
2519 | - } | ||
2520 | - default: | ||
2521 | + assert(mapping); | ||
2522 | + assert(mapping->begin == begin); | ||
2523 | + assert(commit->path == NULL); | ||
2524 | + | ||
2525 | + if (commit_one_file(s, commit->param.writeout.dir_index, | ||
2526 | + commit->param.writeout.modified_offset)) | ||
2527 | + fail = -3; | ||
2528 | + | ||
2529 | + break; | ||
2530 | + } | ||
2531 | + case ACTION_NEW_FILE: { | ||
2532 | + int begin = commit->param.new_file.first_cluster; | ||
2533 | + mapping_t* mapping = find_mapping_for_cluster(s, begin); | ||
2534 | + direntry_t* entry; | ||
2535 | + int i; | ||
2536 | + | ||
2537 | + /* find direntry */ | ||
2538 | + for (i = 0; i < s->directory.next; i++) { | ||
2539 | + entry = array_get(&(s->directory), i); | ||
2540 | + if (is_file(entry) && begin_of_direntry(entry) == begin) | ||
2541 | + break; | ||
2542 | + } | ||
2543 | + | ||
2544 | + if (i >= s->directory.next) { | ||
2545 | + fail = -6; | ||
2546 | + continue; | ||
2547 | + } | ||
2548 | + | ||
2549 | + /* make sure there exists an initial mapping */ | ||
2550 | + if (mapping && mapping->begin != begin) { | ||
2551 | + mapping->end = begin; | ||
2552 | + mapping = NULL; | ||
2553 | + } | ||
2554 | + if (mapping == NULL) { | ||
2555 | + mapping = insert_mapping(s, begin, begin+1); | ||
2556 | + } | ||
2557 | + /* most members will be fixed in commit_mappings() */ | ||
2558 | + assert(commit->path); | ||
2559 | + mapping->path = commit->path; | ||
2560 | + mapping->read_only = 0; | ||
2561 | + mapping->mode = MODE_NORMAL; | ||
2562 | + mapping->info.file.offset = 0; | ||
2563 | + | ||
2564 | + if (commit_one_file(s, i, 0)) | ||
2565 | + fail = -7; | ||
2566 | + | ||
2567 | + break; | ||
2568 | + } | ||
2569 | + default: | ||
2570 | abort(); | ||
2571 | - } | ||
2572 | + } | ||
2573 | } | ||
2574 | if (i > 0 && array_remove_slice(&(s->commits), 0, i)) | ||
2575 | - return -1; | ||
2576 | + return -1; | ||
2577 | return fail; | ||
2578 | } | ||
2579 | |||
2580 | @@ -XXX,XX +XXX,XX @@ static int handle_deletes(BDRVVVFATState* s) | ||
2581 | /* delete files corresponding to mappings marked as deleted */ | ||
2582 | /* handle DELETEs and unused mappings (modified_fat_get(s, mapping->begin) == 0) */ | ||
2583 | while (deferred && deleted) { | ||
2584 | - deferred = 0; | ||
2585 | - deleted = 0; | ||
2586 | - | ||
2587 | - for (i = 1; i < s->mapping.next; i++) { | ||
2588 | - mapping_t* mapping = array_get(&(s->mapping), i); | ||
2589 | - if (mapping->mode & MODE_DELETED) { | ||
2590 | - direntry_t* entry = array_get(&(s->directory), | ||
2591 | - mapping->dir_index); | ||
2592 | - | ||
2593 | - if (is_free(entry)) { | ||
2594 | - /* remove file/directory */ | ||
2595 | - if (mapping->mode & MODE_DIRECTORY) { | ||
2596 | - int j, next_dir_index = s->directory.next, | ||
2597 | - first_dir_index = mapping->info.dir.first_dir_index; | ||
2598 | - | ||
2599 | - if (rmdir(mapping->path) < 0) { | ||
2600 | - if (errno == ENOTEMPTY) { | ||
2601 | - deferred++; | ||
2602 | - continue; | ||
2603 | - } else | ||
2604 | - return -5; | ||
2605 | - } | ||
2606 | - | ||
2607 | - for (j = 1; j < s->mapping.next; j++) { | ||
2608 | - mapping_t* m = array_get(&(s->mapping), j); | ||
2609 | - if (m->mode & MODE_DIRECTORY && | ||
2610 | - m->info.dir.first_dir_index > | ||
2611 | - first_dir_index && | ||
2612 | - m->info.dir.first_dir_index < | ||
2613 | - next_dir_index) | ||
2614 | - next_dir_index = | ||
2615 | - m->info.dir.first_dir_index; | ||
2616 | - } | ||
2617 | - remove_direntries(s, first_dir_index, | ||
2618 | - next_dir_index - first_dir_index); | ||
2619 | - | ||
2620 | - deleted++; | ||
2621 | - } | ||
2622 | - } else { | ||
2623 | - if (unlink(mapping->path)) | ||
2624 | - return -4; | ||
2625 | - deleted++; | ||
2626 | - } | ||
2627 | - DLOG(fprintf(stderr, "DELETE (%d)\n", i); print_mapping(mapping); print_direntry(entry)); | ||
2628 | - remove_mapping(s, i); | ||
2629 | - } | ||
2630 | - } | ||
2631 | + deferred = 0; | ||
2632 | + deleted = 0; | ||
2633 | + | ||
2634 | + for (i = 1; i < s->mapping.next; i++) { | ||
2635 | + mapping_t* mapping = array_get(&(s->mapping), i); | ||
2636 | + if (mapping->mode & MODE_DELETED) { | ||
2637 | + direntry_t* entry = array_get(&(s->directory), | ||
2638 | + mapping->dir_index); | ||
2639 | + | ||
2640 | + if (is_free(entry)) { | ||
2641 | + /* remove file/directory */ | ||
2642 | + if (mapping->mode & MODE_DIRECTORY) { | ||
2643 | + int j, next_dir_index = s->directory.next, | ||
2644 | + first_dir_index = mapping->info.dir.first_dir_index; | ||
2645 | + | ||
2646 | + if (rmdir(mapping->path) < 0) { | ||
2647 | + if (errno == ENOTEMPTY) { | ||
2648 | + deferred++; | ||
2649 | + continue; | ||
2650 | + } else | ||
2651 | + return -5; | ||
2652 | + } | ||
2653 | + | ||
2654 | + for (j = 1; j < s->mapping.next; j++) { | ||
2655 | + mapping_t* m = array_get(&(s->mapping), j); | ||
2656 | + if (m->mode & MODE_DIRECTORY && | ||
2657 | + m->info.dir.first_dir_index > | ||
2658 | + first_dir_index && | ||
2659 | + m->info.dir.first_dir_index < | ||
2660 | + next_dir_index) | ||
2661 | + next_dir_index = | ||
2662 | + m->info.dir.first_dir_index; | ||
2663 | + } | ||
2664 | + remove_direntries(s, first_dir_index, | ||
2665 | + next_dir_index - first_dir_index); | ||
2666 | + | ||
2667 | + deleted++; | ||
2668 | + } | ||
2669 | + } else { | ||
2670 | + if (unlink(mapping->path)) | ||
2671 | + return -4; | ||
2672 | + deleted++; | ||
2673 | + } | ||
2674 | + DLOG(fprintf(stderr, "DELETE (%d)\n", i); print_mapping(mapping); print_direntry(entry)); | ||
2675 | + remove_mapping(s, i); | ||
2676 | + } | ||
2677 | + } | ||
2678 | } | ||
2679 | |||
2680 | return 0; | ||
2681 | @@ -XXX,XX +XXX,XX @@ static int do_commit(BDRVVVFATState* s) | ||
2682 | |||
2683 | /* the real meat are the commits. Nothing to do? Move along! */ | ||
2684 | if (s->commits.next == 0) | ||
2685 | - return 0; | ||
2686 | + return 0; | ||
2687 | |||
2688 | vvfat_close_current_file(s); | ||
2689 | |||
2690 | ret = handle_renames_and_mkdirs(s); | ||
2691 | if (ret) { | ||
2692 | - fprintf(stderr, "Error handling renames (%d)\n", ret); | ||
2693 | + fprintf(stderr, "Error handling renames (%d)\n", ret); | ||
2694 | abort(); | ||
2695 | - return ret; | ||
2696 | + return ret; | ||
2697 | } | ||
2698 | |||
2699 | /* copy FAT (with bdrv_read) */ | ||
2700 | @@ -XXX,XX +XXX,XX @@ static int do_commit(BDRVVVFATState* s) | ||
2701 | /* recurse direntries from root (using bs->bdrv_read) */ | ||
2702 | ret = commit_direntries(s, 0, -1); | ||
2703 | if (ret) { | ||
2704 | - fprintf(stderr, "Fatal: error while committing (%d)\n", ret); | ||
2705 | + fprintf(stderr, "Fatal: error while committing (%d)\n", ret); | ||
2706 | abort(); | ||
2707 | - return ret; | ||
2708 | + return ret; | ||
2709 | } | ||
2710 | |||
2711 | ret = handle_commits(s); | ||
2712 | if (ret) { | ||
2713 | - fprintf(stderr, "Error handling commits (%d)\n", ret); | ||
2714 | + fprintf(stderr, "Error handling commits (%d)\n", ret); | ||
2715 | abort(); | ||
2716 | - return ret; | ||
2717 | + return ret; | ||
2718 | } | ||
2719 | |||
2720 | ret = handle_deletes(s); | ||
2721 | if (ret) { | ||
2722 | - fprintf(stderr, "Error deleting\n"); | ||
2723 | + fprintf(stderr, "Error deleting\n"); | ||
2724 | abort(); | ||
2725 | - return ret; | ||
2726 | + return ret; | ||
2727 | } | ||
2728 | |||
2729 | if (s->qcow->bs->drv->bdrv_make_empty) { | ||
2730 | @@ -XXX,XX +XXX,XX @@ static int try_commit(BDRVVVFATState* s) | ||
2731 | vvfat_close_current_file(s); | ||
2732 | DLOG(checkpoint()); | ||
2733 | if(!is_consistent(s)) | ||
2734 | - return -1; | ||
2735 | + return -1; | ||
2736 | return do_commit(s); | ||
2737 | } | ||
2738 | |||
2739 | @@ -XXX,XX +XXX,XX @@ DLOG(checkpoint()); | ||
2740 | */ | ||
2741 | |||
2742 | if (sector_num < s->first_sectors_number) | ||
2743 | - return -1; | ||
2744 | + return -1; | ||
2745 | |||
2746 | for (i = sector2cluster(s, sector_num); | ||
2747 | - i <= sector2cluster(s, sector_num + nb_sectors - 1);) { | ||
2748 | - mapping_t* mapping = find_mapping_for_cluster(s, i); | ||
2749 | - if (mapping) { | ||
2750 | - if (mapping->read_only) { | ||
2751 | - fprintf(stderr, "Tried to write to write-protected file %s\n", | ||
2752 | - mapping->path); | ||
2753 | - return -1; | ||
2754 | - } | ||
2755 | - | ||
2756 | - if (mapping->mode & MODE_DIRECTORY) { | ||
2757 | - int begin = cluster2sector(s, i); | ||
2758 | - int end = begin + s->sectors_per_cluster, k; | ||
2759 | - int dir_index; | ||
2760 | - const direntry_t* direntries; | ||
2761 | - long_file_name lfn; | ||
2762 | - | ||
2763 | - lfn_init(&lfn); | ||
2764 | - | ||
2765 | - if (begin < sector_num) | ||
2766 | - begin = sector_num; | ||
2767 | - if (end > sector_num + nb_sectors) | ||
2768 | - end = sector_num + nb_sectors; | ||
2769 | - dir_index = mapping->dir_index + | ||
2770 | - 0x10 * (begin - mapping->begin * s->sectors_per_cluster); | ||
2771 | - direntries = (direntry_t*)(buf + 0x200 * (begin - sector_num)); | ||
2772 | - | ||
2773 | - for (k = 0; k < (end - begin) * 0x10; k++) { | ||
2774 | - /* do not allow non-ASCII filenames */ | ||
2775 | - if (parse_long_name(&lfn, direntries + k) < 0) { | ||
2776 | - fprintf(stderr, "Warning: non-ASCII filename\n"); | ||
2777 | - return -1; | ||
2778 | - } | ||
2779 | - /* no access to the direntry of a read-only file */ | ||
2780 | - else if (is_short_name(direntries+k) && | ||
2781 | - (direntries[k].attributes & 1)) { | ||
2782 | - if (memcmp(direntries + k, | ||
2783 | - array_get(&(s->directory), dir_index + k), | ||
2784 | - sizeof(direntry_t))) { | ||
2785 | - fprintf(stderr, "Warning: tried to write to write-protected file\n"); | ||
2786 | - return -1; | ||
2787 | - } | ||
2788 | - } | ||
2789 | - } | ||
2790 | - } | ||
2791 | - i = mapping->end; | ||
2792 | - } else | ||
2793 | - i++; | ||
2794 | + i <= sector2cluster(s, sector_num + nb_sectors - 1);) { | ||
2795 | + mapping_t* mapping = find_mapping_for_cluster(s, i); | ||
2796 | + if (mapping) { | ||
2797 | + if (mapping->read_only) { | ||
2798 | + fprintf(stderr, "Tried to write to write-protected file %s\n", | ||
2799 | + mapping->path); | ||
2800 | + return -1; | ||
2801 | + } | ||
2802 | + | ||
2803 | + if (mapping->mode & MODE_DIRECTORY) { | ||
2804 | + int begin = cluster2sector(s, i); | ||
2805 | + int end = begin + s->sectors_per_cluster, k; | ||
2806 | + int dir_index; | ||
2807 | + const direntry_t* direntries; | ||
2808 | + long_file_name lfn; | ||
2809 | + | ||
2810 | + lfn_init(&lfn); | ||
2811 | + | ||
2812 | + if (begin < sector_num) | ||
2813 | + begin = sector_num; | ||
2814 | + if (end > sector_num + nb_sectors) | ||
2815 | + end = sector_num + nb_sectors; | ||
2816 | + dir_index = mapping->dir_index + | ||
2817 | + 0x10 * (begin - mapping->begin * s->sectors_per_cluster); | ||
2818 | + direntries = (direntry_t*)(buf + 0x200 * (begin - sector_num)); | ||
2819 | + | ||
2820 | + for (k = 0; k < (end - begin) * 0x10; k++) { | ||
2821 | + /* do not allow non-ASCII filenames */ | ||
2822 | + if (parse_long_name(&lfn, direntries + k) < 0) { | ||
2823 | + fprintf(stderr, "Warning: non-ASCII filename\n"); | ||
2824 | + return -1; | ||
2825 | + } | ||
2826 | + /* no access to the direntry of a read-only file */ | ||
2827 | + else if (is_short_name(direntries+k) && | ||
2828 | + (direntries[k].attributes & 1)) { | ||
2829 | + if (memcmp(direntries + k, | ||
2830 | + array_get(&(s->directory), dir_index + k), | ||
2831 | + sizeof(direntry_t))) { | ||
2832 | + fprintf(stderr, "Warning: tried to write to write-protected file\n"); | ||
2833 | + return -1; | ||
2834 | + } | ||
2835 | + } | ||
2836 | + } | ||
2837 | + } | ||
2838 | + i = mapping->end; | ||
2839 | + } else | ||
2840 | + i++; | ||
2841 | } | ||
2842 | |||
2843 | /* | ||
2844 | @@ -XXX,XX +XXX,XX @@ DLOG(checkpoint()); | ||
2845 | DLOG(fprintf(stderr, "Write to qcow backend: %d + %d\n", (int)sector_num, nb_sectors)); | ||
2846 | ret = bdrv_write(s->qcow, sector_num, buf, nb_sectors); | ||
2847 | if (ret < 0) { | ||
2848 | - fprintf(stderr, "Error writing to qcow backend\n"); | ||
2849 | - return ret; | ||
2850 | + fprintf(stderr, "Error writing to qcow backend\n"); | ||
2851 | + return ret; | ||
2852 | } | ||
2853 | |||
2854 | for (i = sector2cluster(s, sector_num); | ||
2855 | - i <= sector2cluster(s, sector_num + nb_sectors - 1); i++) | ||
2856 | - if (i >= 0) | ||
2857 | - s->used_clusters[i] |= USED_ALLOCATED; | ||
2858 | + i <= sector2cluster(s, sector_num + nb_sectors - 1); i++) | ||
2859 | + if (i >= 0) | ||
2860 | + s->used_clusters[i] |= USED_ALLOCATED; | ||
2861 | |||
2862 | DLOG(checkpoint()); | ||
2863 | /* TODO: add timeout */ | ||
2864 | @@ -XXX,XX +XXX,XX @@ vvfat_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes, | ||
2865 | } | ||
2866 | |||
2867 | static int64_t coroutine_fn vvfat_co_get_block_status(BlockDriverState *bs, | ||
2868 | - int64_t sector_num, int nb_sectors, int *n, BlockDriverState **file) | ||
2869 | + int64_t sector_num, int nb_sectors, int *n, BlockDriverState **file) | ||
2870 | { | ||
2871 | *n = bs->total_sectors - sector_num; | ||
2872 | if (*n > nb_sectors) { | ||
2873 | @@ -XXX,XX +XXX,XX @@ static void checkpoint(void) { | ||
2874 | assert(!vvv->current_mapping || vvv->current_fd || (vvv->current_mapping->mode & MODE_DIRECTORY)); | ||
2875 | #if 0 | ||
2876 | if (((direntry_t*)vvv->directory.pointer)[1].attributes != 0xf) | ||
2877 | - fprintf(stderr, "Nonono!\n"); | ||
2878 | + fprintf(stderr, "Nonono!\n"); | ||
2879 | mapping_t* mapping; | ||
2880 | direntry_t* direntry; | ||
2881 | assert(vvv->mapping.size >= vvv->mapping.item_size * vvv->mapping.next); | ||
2882 | assert(vvv->directory.size >= vvv->directory.item_size * vvv->directory.next); | ||
2883 | if (vvv->mapping.next<47) | ||
2884 | - return; | ||
2885 | + return; | ||
2886 | assert((mapping = array_get(&(vvv->mapping), 47))); | ||
2887 | assert(mapping->dir_index < vvv->directory.next); | ||
2888 | direntry = array_get(&(vvv->directory), mapping->dir_index); | ||
2889 | -- | 120 | -- |
2890 | 1.8.3.1 | 121 | 2.37.3 |
2891 | |||
2892 | diff view generated by jsdifflib |
1 | From: Eric Blake <eblake@redhat.com> | 1 | From: Paolo Bonzini <pbonzini@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Upcoming patches are going to switch to byte-based interfaces | 3 | Callers of coroutine_fn must be coroutine_fn themselves, or the call |
4 | instead of sector-based. Even worse, trace_backup_do_cow_enter() | 4 | must be within "if (qemu_in_coroutine())". Apply coroutine_fn to |
5 | had a weird mix of cluster and sector indices. | 5 | functions where this holds. |
6 | 6 | ||
7 | The trace interface is low enough that there are no stability | 7 | Reviewed-by: Alberto Faria <afaria@redhat.com> |
8 | guarantees, and therefore nothing wrong with changing our units, | 8 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
9 | even in cases like trace_backup_do_cow_skip() where we are not | 9 | Message-Id: <20220922084924.201610-20-pbonzini@redhat.com> |
10 | changing the trace output. So make the tracing uniformly use | ||
11 | bytes. | ||
12 | |||
13 | Signed-off-by: Eric Blake <eblake@redhat.com> | ||
14 | Reviewed-by: John Snow <jsnow@redhat.com> | ||
15 | Reviewed-by: Jeff Cody <jcody@redhat.com> | ||
16 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | 10 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> |
17 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
18 | --- | 12 | --- |
19 | block/backup.c | 16 ++++++++++------ | 13 | block/throttle.c | 2 +- |
20 | block/commit.c | 3 ++- | 14 | 1 file changed, 1 insertion(+), 1 deletion(-) |
21 | block/mirror.c | 26 +++++++++++++++++--------- | ||
22 | block/stream.c | 3 ++- | ||
23 | block/trace-events | 14 +++++++------- | ||
24 | 5 files changed, 38 insertions(+), 24 deletions(-) | ||
25 | 15 | ||
26 | diff --git a/block/backup.c b/block/backup.c | 16 | diff --git a/block/throttle.c b/block/throttle.c |
27 | index XXXXXXX..XXXXXXX 100644 | 17 | index XXXXXXX..XXXXXXX 100644 |
28 | --- a/block/backup.c | 18 | --- a/block/throttle.c |
29 | +++ b/block/backup.c | 19 | +++ b/block/throttle.c |
30 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_do_cow(BackupBlockJob *job, | 20 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn throttle_co_pwritev_compressed(BlockDriverState *bs, |
31 | void *bounce_buffer = NULL; | 21 | BDRV_REQ_WRITE_COMPRESSED); |
32 | int ret = 0; | 22 | } |
33 | int64_t sectors_per_cluster = cluster_size_sectors(job); | 23 | |
34 | + int64_t bytes_per_cluster = sectors_per_cluster * BDRV_SECTOR_SIZE; | 24 | -static int throttle_co_flush(BlockDriverState *bs) |
35 | int64_t start, end; | 25 | +static int coroutine_fn throttle_co_flush(BlockDriverState *bs) |
36 | int n; | 26 | { |
37 | 27 | return bdrv_co_flush(bs->file->bs); | |
38 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_do_cow(BackupBlockJob *job, | 28 | } |
39 | start = sector_num / sectors_per_cluster; | ||
40 | end = DIV_ROUND_UP(sector_num + nb_sectors, sectors_per_cluster); | ||
41 | |||
42 | - trace_backup_do_cow_enter(job, start, sector_num, nb_sectors); | ||
43 | + trace_backup_do_cow_enter(job, start * bytes_per_cluster, | ||
44 | + sector_num * BDRV_SECTOR_SIZE, | ||
45 | + nb_sectors * BDRV_SECTOR_SIZE); | ||
46 | |||
47 | wait_for_overlapping_requests(job, start, end); | ||
48 | cow_request_begin(&cow_request, job, start, end); | ||
49 | |||
50 | for (; start < end; start++) { | ||
51 | if (test_bit(start, job->done_bitmap)) { | ||
52 | - trace_backup_do_cow_skip(job, start); | ||
53 | + trace_backup_do_cow_skip(job, start * bytes_per_cluster); | ||
54 | continue; /* already copied */ | ||
55 | } | ||
56 | |||
57 | - trace_backup_do_cow_process(job, start); | ||
58 | + trace_backup_do_cow_process(job, start * bytes_per_cluster); | ||
59 | |||
60 | n = MIN(sectors_per_cluster, | ||
61 | job->common.len / BDRV_SECTOR_SIZE - | ||
62 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_do_cow(BackupBlockJob *job, | ||
63 | bounce_qiov.size, &bounce_qiov, | ||
64 | is_write_notifier ? BDRV_REQ_NO_SERIALISING : 0); | ||
65 | if (ret < 0) { | ||
66 | - trace_backup_do_cow_read_fail(job, start, ret); | ||
67 | + trace_backup_do_cow_read_fail(job, start * bytes_per_cluster, ret); | ||
68 | if (error_is_read) { | ||
69 | *error_is_read = true; | ||
70 | } | ||
71 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_do_cow(BackupBlockJob *job, | ||
72 | job->compress ? BDRV_REQ_WRITE_COMPRESSED : 0); | ||
73 | } | ||
74 | if (ret < 0) { | ||
75 | - trace_backup_do_cow_write_fail(job, start, ret); | ||
76 | + trace_backup_do_cow_write_fail(job, start * bytes_per_cluster, ret); | ||
77 | if (error_is_read) { | ||
78 | *error_is_read = false; | ||
79 | } | ||
80 | @@ -XXX,XX +XXX,XX @@ out: | ||
81 | |||
82 | cow_request_end(&cow_request); | ||
83 | |||
84 | - trace_backup_do_cow_return(job, sector_num, nb_sectors, ret); | ||
85 | + trace_backup_do_cow_return(job, sector_num * BDRV_SECTOR_SIZE, | ||
86 | + nb_sectors * BDRV_SECTOR_SIZE, ret); | ||
87 | |||
88 | qemu_co_rwlock_unlock(&job->flush_rwlock); | ||
89 | |||
90 | diff --git a/block/commit.c b/block/commit.c | ||
91 | index XXXXXXX..XXXXXXX 100644 | ||
92 | --- a/block/commit.c | ||
93 | +++ b/block/commit.c | ||
94 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn commit_run(void *opaque) | ||
95 | COMMIT_BUFFER_SIZE / BDRV_SECTOR_SIZE, | ||
96 | &n); | ||
97 | copy = (ret == 1); | ||
98 | - trace_commit_one_iteration(s, sector_num, n, ret); | ||
99 | + trace_commit_one_iteration(s, sector_num * BDRV_SECTOR_SIZE, | ||
100 | + n * BDRV_SECTOR_SIZE, ret); | ||
101 | if (copy) { | ||
102 | ret = commit_populate(s->top, s->base, sector_num, n, buf); | ||
103 | bytes_written += n * BDRV_SECTOR_SIZE; | ||
104 | diff --git a/block/mirror.c b/block/mirror.c | ||
105 | index XXXXXXX..XXXXXXX 100644 | ||
106 | --- a/block/mirror.c | ||
107 | +++ b/block/mirror.c | ||
108 | @@ -XXX,XX +XXX,XX @@ static void mirror_iteration_done(MirrorOp *op, int ret) | ||
109 | int64_t chunk_num; | ||
110 | int i, nb_chunks, sectors_per_chunk; | ||
111 | |||
112 | - trace_mirror_iteration_done(s, op->sector_num, op->nb_sectors, ret); | ||
113 | + trace_mirror_iteration_done(s, op->sector_num * BDRV_SECTOR_SIZE, | ||
114 | + op->nb_sectors * BDRV_SECTOR_SIZE, ret); | ||
115 | |||
116 | s->in_flight--; | ||
117 | s->sectors_in_flight -= op->nb_sectors; | ||
118 | @@ -XXX,XX +XXX,XX @@ static int mirror_do_read(MirrorBlockJob *s, int64_t sector_num, | ||
119 | nb_chunks = DIV_ROUND_UP(nb_sectors, sectors_per_chunk); | ||
120 | |||
121 | while (s->buf_free_count < nb_chunks) { | ||
122 | - trace_mirror_yield_in_flight(s, sector_num, s->in_flight); | ||
123 | + trace_mirror_yield_in_flight(s, sector_num * BDRV_SECTOR_SIZE, | ||
124 | + s->in_flight); | ||
125 | mirror_wait_for_io(s); | ||
126 | } | ||
127 | |||
128 | @@ -XXX,XX +XXX,XX @@ static int mirror_do_read(MirrorBlockJob *s, int64_t sector_num, | ||
129 | /* Copy the dirty cluster. */ | ||
130 | s->in_flight++; | ||
131 | s->sectors_in_flight += nb_sectors; | ||
132 | - trace_mirror_one_iteration(s, sector_num, nb_sectors); | ||
133 | + trace_mirror_one_iteration(s, sector_num * BDRV_SECTOR_SIZE, | ||
134 | + nb_sectors * BDRV_SECTOR_SIZE); | ||
135 | |||
136 | blk_aio_preadv(source, sector_num * BDRV_SECTOR_SIZE, &op->qiov, 0, | ||
137 | mirror_read_complete, op); | ||
138 | @@ -XXX,XX +XXX,XX @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s) | ||
139 | if (sector_num < 0) { | ||
140 | bdrv_set_dirty_iter(s->dbi, 0); | ||
141 | sector_num = bdrv_dirty_iter_next(s->dbi); | ||
142 | - trace_mirror_restart_iter(s, bdrv_get_dirty_count(s->dirty_bitmap)); | ||
143 | + trace_mirror_restart_iter(s, bdrv_get_dirty_count(s->dirty_bitmap) * | ||
144 | + BDRV_SECTOR_SIZE); | ||
145 | assert(sector_num >= 0); | ||
146 | } | ||
147 | bdrv_dirty_bitmap_unlock(s->dirty_bitmap); | ||
148 | |||
149 | first_chunk = sector_num / sectors_per_chunk; | ||
150 | while (test_bit(first_chunk, s->in_flight_bitmap)) { | ||
151 | - trace_mirror_yield_in_flight(s, sector_num, s->in_flight); | ||
152 | + trace_mirror_yield_in_flight(s, sector_num * BDRV_SECTOR_SIZE, | ||
153 | + s->in_flight); | ||
154 | mirror_wait_for_io(s); | ||
155 | } | ||
156 | |||
157 | @@ -XXX,XX +XXX,XX @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s) | ||
158 | } | ||
159 | |||
160 | while (s->in_flight >= MAX_IN_FLIGHT) { | ||
161 | - trace_mirror_yield_in_flight(s, sector_num, s->in_flight); | ||
162 | + trace_mirror_yield_in_flight(s, sector_num * BDRV_SECTOR_SIZE, | ||
163 | + s->in_flight); | ||
164 | mirror_wait_for_io(s); | ||
165 | } | ||
166 | |||
167 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn mirror_run(void *opaque) | ||
168 | s->common.iostatus == BLOCK_DEVICE_IO_STATUS_OK) { | ||
169 | if (s->in_flight >= MAX_IN_FLIGHT || s->buf_free_count == 0 || | ||
170 | (cnt == 0 && s->in_flight > 0)) { | ||
171 | - trace_mirror_yield(s, cnt, s->buf_free_count, s->in_flight); | ||
172 | + trace_mirror_yield(s, cnt * BDRV_SECTOR_SIZE, | ||
173 | + s->buf_free_count, s->in_flight); | ||
174 | mirror_wait_for_io(s); | ||
175 | continue; | ||
176 | } else if (cnt != 0) { | ||
177 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn mirror_run(void *opaque) | ||
178 | * whether to switch to target check one last time if I/O has | ||
179 | * come in the meanwhile, and if not flush the data to disk. | ||
180 | */ | ||
181 | - trace_mirror_before_drain(s, cnt); | ||
182 | + trace_mirror_before_drain(s, cnt * BDRV_SECTOR_SIZE); | ||
183 | |||
184 | bdrv_drained_begin(bs); | ||
185 | cnt = bdrv_get_dirty_count(s->dirty_bitmap); | ||
186 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn mirror_run(void *opaque) | ||
187 | } | ||
188 | |||
189 | ret = 0; | ||
190 | - trace_mirror_before_sleep(s, cnt, s->synced, delay_ns); | ||
191 | + trace_mirror_before_sleep(s, cnt * BDRV_SECTOR_SIZE, | ||
192 | + s->synced, delay_ns); | ||
193 | if (!s->synced) { | ||
194 | block_job_sleep_ns(&s->common, QEMU_CLOCK_REALTIME, delay_ns); | ||
195 | if (block_job_is_cancelled(&s->common)) { | ||
196 | diff --git a/block/stream.c b/block/stream.c | ||
197 | index XXXXXXX..XXXXXXX 100644 | ||
198 | --- a/block/stream.c | ||
199 | +++ b/block/stream.c | ||
200 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn stream_run(void *opaque) | ||
201 | |||
202 | copy = (ret == 1); | ||
203 | } | ||
204 | - trace_stream_one_iteration(s, sector_num, n, ret); | ||
205 | + trace_stream_one_iteration(s, sector_num * BDRV_SECTOR_SIZE, | ||
206 | + n * BDRV_SECTOR_SIZE, ret); | ||
207 | if (copy) { | ||
208 | ret = stream_populate(blk, sector_num, n, buf); | ||
209 | } | ||
210 | diff --git a/block/trace-events b/block/trace-events | ||
211 | index XXXXXXX..XXXXXXX 100644 | ||
212 | --- a/block/trace-events | ||
213 | +++ b/block/trace-events | ||
214 | @@ -XXX,XX +XXX,XX @@ bdrv_co_pwrite_zeroes(void *bs, int64_t offset, int count, int flags) "bs %p off | ||
215 | bdrv_co_do_copy_on_readv(void *bs, int64_t offset, unsigned int bytes, int64_t cluster_offset, unsigned int cluster_bytes) "bs %p offset %"PRId64" bytes %u cluster_offset %"PRId64" cluster_bytes %u" | ||
216 | |||
217 | # block/stream.c | ||
218 | -stream_one_iteration(void *s, int64_t sector_num, int nb_sectors, int is_allocated) "s %p sector_num %"PRId64" nb_sectors %d is_allocated %d" | ||
219 | +stream_one_iteration(void *s, int64_t offset, uint64_t bytes, int is_allocated) "s %p offset %" PRId64 " bytes %" PRIu64 " is_allocated %d" | ||
220 | stream_start(void *bs, void *base, void *s) "bs %p base %p s %p" | ||
221 | |||
222 | # block/commit.c | ||
223 | -commit_one_iteration(void *s, int64_t sector_num, int nb_sectors, int is_allocated) "s %p sector_num %"PRId64" nb_sectors %d is_allocated %d" | ||
224 | +commit_one_iteration(void *s, int64_t offset, uint64_t bytes, int is_allocated) "s %p offset %" PRId64 " bytes %" PRIu64 " is_allocated %d" | ||
225 | commit_start(void *bs, void *base, void *top, void *s) "bs %p base %p top %p s %p" | ||
226 | |||
227 | # block/mirror.c | ||
228 | @@ -XXX,XX +XXX,XX @@ mirror_restart_iter(void *s, int64_t cnt) "s %p dirty count %"PRId64 | ||
229 | mirror_before_flush(void *s) "s %p" | ||
230 | mirror_before_drain(void *s, int64_t cnt) "s %p dirty count %"PRId64 | ||
231 | mirror_before_sleep(void *s, int64_t cnt, int synced, uint64_t delay_ns) "s %p dirty count %"PRId64" synced %d delay %"PRIu64"ns" | ||
232 | -mirror_one_iteration(void *s, int64_t sector_num, int nb_sectors) "s %p sector_num %"PRId64" nb_sectors %d" | ||
233 | -mirror_iteration_done(void *s, int64_t sector_num, int nb_sectors, int ret) "s %p sector_num %"PRId64" nb_sectors %d ret %d" | ||
234 | +mirror_one_iteration(void *s, int64_t offset, uint64_t bytes) "s %p offset %" PRId64 " bytes %" PRIu64 | ||
235 | +mirror_iteration_done(void *s, int64_t offset, uint64_t bytes, int ret) "s %p offset %" PRId64 " bytes %" PRIu64 " ret %d" | ||
236 | mirror_yield(void *s, int64_t cnt, int buf_free_count, int in_flight) "s %p dirty count %"PRId64" free buffers %d in_flight %d" | ||
237 | -mirror_yield_in_flight(void *s, int64_t sector_num, int in_flight) "s %p sector_num %"PRId64" in_flight %d" | ||
238 | +mirror_yield_in_flight(void *s, int64_t offset, int in_flight) "s %p offset %" PRId64 " in_flight %d" | ||
239 | |||
240 | # block/backup.c | ||
241 | -backup_do_cow_enter(void *job, int64_t start, int64_t sector_num, int nb_sectors) "job %p start %"PRId64" sector_num %"PRId64" nb_sectors %d" | ||
242 | -backup_do_cow_return(void *job, int64_t sector_num, int nb_sectors, int ret) "job %p sector_num %"PRId64" nb_sectors %d ret %d" | ||
243 | +backup_do_cow_enter(void *job, int64_t start, int64_t offset, uint64_t bytes) "job %p start %" PRId64 " offset %" PRId64 " bytes %" PRIu64 | ||
244 | +backup_do_cow_return(void *job, int64_t offset, uint64_t bytes, int ret) "job %p offset %" PRId64 " bytes %" PRIu64 " ret %d" | ||
245 | backup_do_cow_skip(void *job, int64_t start) "job %p start %"PRId64 | ||
246 | backup_do_cow_process(void *job, int64_t start) "job %p start %"PRId64 | ||
247 | backup_do_cow_read_fail(void *job, int64_t start, int ret) "job %p start %"PRId64" ret %d" | ||
248 | -- | 29 | -- |
249 | 1.8.3.1 | 30 | 2.37.3 |
250 | |||
251 | diff view generated by jsdifflib |
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 1 | From: Paolo Bonzini <pbonzini@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Auto loading bitmaps are bitmaps in Qcow2, with the AUTO flag set. They | 3 | Callers of coroutine_fn must be coroutine_fn themselves, or the call |
4 | are loaded when the image is opened and become BdrvDirtyBitmaps for the | 4 | must be within "if (qemu_in_coroutine())". Apply coroutine_fn to |
5 | corresponding drive. | 5 | functions where this holds. |
6 | 6 | ||
7 | Extra data in bitmaps is not supported for now. | 7 | Reviewed-by: Alberto Faria <afaria@redhat.com> |
8 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> | ||
9 | Message-Id: <20220922084924.201610-21-pbonzini@redhat.com> | ||
10 | [kwolf: Fixed up coding style] | ||
11 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
13 | --- | ||
14 | block/vmdk.c | 22 ++++++++++++---------- | ||
15 | 1 file changed, 12 insertions(+), 10 deletions(-) | ||
8 | 16 | ||
9 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 17 | diff --git a/block/vmdk.c b/block/vmdk.c |
10 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
11 | Reviewed-by: John Snow <jsnow@redhat.com> | ||
12 | Message-id: 20170628120530.31251-12-vsementsov@virtuozzo.com | ||
13 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
14 | --- | ||
15 | block/qcow2-bitmap.c | 389 +++++++++++++++++++++++++++++++++++++++++++++++++++ | ||
16 | block/qcow2.c | 17 ++- | ||
17 | block/qcow2.h | 2 + | ||
18 | 3 files changed, 406 insertions(+), 2 deletions(-) | ||
19 | |||
20 | diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c | ||
21 | index XXXXXXX..XXXXXXX 100644 | 18 | index XXXXXXX..XXXXXXX 100644 |
22 | --- a/block/qcow2-bitmap.c | 19 | --- a/block/vmdk.c |
23 | +++ b/block/qcow2-bitmap.c | 20 | +++ b/block/vmdk.c |
24 | @@ -XXX,XX +XXX,XX @@ | 21 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn vmdk_co_block_status(BlockDriverState *bs, |
25 | |||
26 | /* Bitmap directory entry flags */ | ||
27 | #define BME_RESERVED_FLAGS 0xfffffffcU | ||
28 | +#define BME_FLAG_IN_USE (1U << 0) | ||
29 | +#define BME_FLAG_AUTO (1U << 1) | ||
30 | |||
31 | /* bits [1, 8] U [56, 63] are reserved */ | ||
32 | #define BME_TABLE_ENTRY_RESERVED_MASK 0xff000000000001feULL | ||
33 | @@ -XXX,XX +XXX,XX @@ typedef enum BitmapType { | ||
34 | BT_DIRTY_TRACKING_BITMAP = 1 | ||
35 | } BitmapType; | ||
36 | |||
37 | +static inline bool can_write(BlockDriverState *bs) | ||
38 | +{ | ||
39 | + return !bdrv_is_read_only(bs) && !(bdrv_get_flags(bs) & BDRV_O_INACTIVE); | ||
40 | +} | ||
41 | + | ||
42 | +static int update_header_sync(BlockDriverState *bs) | ||
43 | +{ | ||
44 | + int ret; | ||
45 | + | ||
46 | + ret = qcow2_update_header(bs); | ||
47 | + if (ret < 0) { | ||
48 | + return ret; | ||
49 | + } | ||
50 | + | ||
51 | + return bdrv_flush(bs); | ||
52 | +} | ||
53 | + | ||
54 | static int check_table_entry(uint64_t entry, int cluster_size) | ||
55 | { | ||
56 | uint64_t offset; | ||
57 | @@ -XXX,XX +XXX,XX @@ fail: | ||
58 | return ret; | 22 | return ret; |
59 | } | 23 | } |
60 | 24 | ||
61 | +/* This function returns the number of disk sectors covered by a single qcow2 | 25 | -static int vmdk_write_extent(VmdkExtent *extent, int64_t cluster_offset, |
62 | + * cluster of bitmap data. */ | 26 | - int64_t offset_in_cluster, QEMUIOVector *qiov, |
63 | +static uint64_t sectors_covered_by_bitmap_cluster(const BDRVQcow2State *s, | 27 | - uint64_t qiov_offset, uint64_t n_bytes, |
64 | + const BdrvDirtyBitmap *bitmap) | 28 | - uint64_t offset) |
65 | +{ | 29 | +static int coroutine_fn |
66 | + uint32_t sector_granularity = | 30 | +vmdk_write_extent(VmdkExtent *extent, int64_t cluster_offset, |
67 | + bdrv_dirty_bitmap_granularity(bitmap) >> BDRV_SECTOR_BITS; | 31 | + int64_t offset_in_cluster, QEMUIOVector *qiov, |
68 | + | 32 | + uint64_t qiov_offset, uint64_t n_bytes, |
69 | + return (uint64_t)sector_granularity * (s->cluster_size << 3); | 33 | + uint64_t offset) |
70 | +} | ||
71 | + | ||
72 | +/* load_bitmap_data | ||
73 | + * @bitmap_table entries must satisfy specification constraints. | ||
74 | + * @bitmap must be cleared */ | ||
75 | +static int load_bitmap_data(BlockDriverState *bs, | ||
76 | + const uint64_t *bitmap_table, | ||
77 | + uint32_t bitmap_table_size, | ||
78 | + BdrvDirtyBitmap *bitmap) | ||
79 | +{ | ||
80 | + int ret = 0; | ||
81 | + BDRVQcow2State *s = bs->opaque; | ||
82 | + uint64_t sector, sbc; | ||
83 | + uint64_t bm_size = bdrv_dirty_bitmap_size(bitmap); | ||
84 | + uint8_t *buf = NULL; | ||
85 | + uint64_t i, tab_size = | ||
86 | + size_to_clusters(s, | ||
87 | + bdrv_dirty_bitmap_serialization_size(bitmap, 0, bm_size)); | ||
88 | + | ||
89 | + if (tab_size != bitmap_table_size || tab_size > BME_MAX_TABLE_SIZE) { | ||
90 | + return -EINVAL; | ||
91 | + } | ||
92 | + | ||
93 | + buf = g_malloc(s->cluster_size); | ||
94 | + sbc = sectors_covered_by_bitmap_cluster(s, bitmap); | ||
95 | + for (i = 0, sector = 0; i < tab_size; ++i, sector += sbc) { | ||
96 | + uint64_t count = MIN(bm_size - sector, sbc); | ||
97 | + uint64_t entry = bitmap_table[i]; | ||
98 | + uint64_t offset = entry & BME_TABLE_ENTRY_OFFSET_MASK; | ||
99 | + | ||
100 | + assert(check_table_entry(entry, s->cluster_size) == 0); | ||
101 | + | ||
102 | + if (offset == 0) { | ||
103 | + if (entry & BME_TABLE_ENTRY_FLAG_ALL_ONES) { | ||
104 | + bdrv_dirty_bitmap_deserialize_ones(bitmap, sector, count, | ||
105 | + false); | ||
106 | + } else { | ||
107 | + /* No need to deserialize zeros because the dirty bitmap is | ||
108 | + * already cleared */ | ||
109 | + } | ||
110 | + } else { | ||
111 | + ret = bdrv_pread(bs->file, offset, buf, s->cluster_size); | ||
112 | + if (ret < 0) { | ||
113 | + goto finish; | ||
114 | + } | ||
115 | + bdrv_dirty_bitmap_deserialize_part(bitmap, buf, sector, count, | ||
116 | + false); | ||
117 | + } | ||
118 | + } | ||
119 | + ret = 0; | ||
120 | + | ||
121 | + bdrv_dirty_bitmap_deserialize_finish(bitmap); | ||
122 | + | ||
123 | +finish: | ||
124 | + g_free(buf); | ||
125 | + | ||
126 | + return ret; | ||
127 | +} | ||
128 | + | ||
129 | +static BdrvDirtyBitmap *load_bitmap(BlockDriverState *bs, | ||
130 | + Qcow2Bitmap *bm, Error **errp) | ||
131 | +{ | ||
132 | + int ret; | ||
133 | + uint64_t *bitmap_table = NULL; | ||
134 | + uint32_t granularity; | ||
135 | + BdrvDirtyBitmap *bitmap = NULL; | ||
136 | + | ||
137 | + if (bm->flags & BME_FLAG_IN_USE) { | ||
138 | + error_setg(errp, "Bitmap '%s' is in use", bm->name); | ||
139 | + goto fail; | ||
140 | + } | ||
141 | + | ||
142 | + ret = bitmap_table_load(bs, &bm->table, &bitmap_table); | ||
143 | + if (ret < 0) { | ||
144 | + error_setg_errno(errp, -ret, | ||
145 | + "Could not read bitmap_table table from image for " | ||
146 | + "bitmap '%s'", bm->name); | ||
147 | + goto fail; | ||
148 | + } | ||
149 | + | ||
150 | + granularity = 1U << bm->granularity_bits; | ||
151 | + bitmap = bdrv_create_dirty_bitmap(bs, granularity, bm->name, errp); | ||
152 | + if (bitmap == NULL) { | ||
153 | + goto fail; | ||
154 | + } | ||
155 | + | ||
156 | + ret = load_bitmap_data(bs, bitmap_table, bm->table.size, bitmap); | ||
157 | + if (ret < 0) { | ||
158 | + error_setg_errno(errp, -ret, "Could not read bitmap '%s' from image", | ||
159 | + bm->name); | ||
160 | + goto fail; | ||
161 | + } | ||
162 | + | ||
163 | + g_free(bitmap_table); | ||
164 | + return bitmap; | ||
165 | + | ||
166 | +fail: | ||
167 | + g_free(bitmap_table); | ||
168 | + if (bitmap != NULL) { | ||
169 | + bdrv_release_dirty_bitmap(bs, bitmap); | ||
170 | + } | ||
171 | + | ||
172 | + return NULL; | ||
173 | +} | ||
174 | + | ||
175 | /* | ||
176 | * Bitmap List | ||
177 | */ | ||
178 | @@ -XXX,XX +XXX,XX @@ static inline void bitmap_dir_entry_to_cpu(Qcow2BitmapDirEntry *entry) | ||
179 | be32_to_cpus(&entry->extra_data_size); | ||
180 | } | ||
181 | |||
182 | +static inline void bitmap_dir_entry_to_be(Qcow2BitmapDirEntry *entry) | ||
183 | +{ | ||
184 | + cpu_to_be64s(&entry->bitmap_table_offset); | ||
185 | + cpu_to_be32s(&entry->bitmap_table_size); | ||
186 | + cpu_to_be32s(&entry->flags); | ||
187 | + cpu_to_be16s(&entry->name_size); | ||
188 | + cpu_to_be32s(&entry->extra_data_size); | ||
189 | +} | ||
190 | + | ||
191 | static inline int calc_dir_entry_size(size_t name_size, size_t extra_data_size) | ||
192 | { | 34 | { |
193 | return align_offset(sizeof(Qcow2BitmapDirEntry) + | 35 | int ret; |
194 | @@ -XXX,XX +XXX,XX @@ static int check_dir_entry(BlockDriverState *bs, Qcow2BitmapDirEntry *entry) | 36 | VmdkGrainMarker *data = NULL; |
195 | return fail ? -EINVAL : 0; | 37 | @@ -XXX,XX +XXX,XX @@ static int vmdk_write_extent(VmdkExtent *extent, int64_t cluster_offset, |
196 | } | ||
197 | |||
198 | +static inline void bitmap_directory_to_be(uint8_t *dir, size_t size) | ||
199 | +{ | ||
200 | + uint8_t *end = dir + size; | ||
201 | + while (dir < end) { | ||
202 | + Qcow2BitmapDirEntry *e = (Qcow2BitmapDirEntry *)dir; | ||
203 | + dir += dir_entry_size(e); | ||
204 | + | ||
205 | + bitmap_dir_entry_to_be(e); | ||
206 | + } | ||
207 | +} | ||
208 | + | ||
209 | /* | ||
210 | * Bitmap List public functions | ||
211 | */ | ||
212 | @@ -XXX,XX +XXX,XX @@ static Qcow2BitmapList *bitmap_list_new(void) | ||
213 | return bm_list; | ||
214 | } | ||
215 | |||
216 | +static uint32_t bitmap_list_count(Qcow2BitmapList *bm_list) | ||
217 | +{ | ||
218 | + Qcow2Bitmap *bm; | ||
219 | + uint32_t nb_bitmaps = 0; | ||
220 | + | ||
221 | + QSIMPLEQ_FOREACH(bm, bm_list, entry) { | ||
222 | + nb_bitmaps++; | ||
223 | + } | ||
224 | + | ||
225 | + return nb_bitmaps; | ||
226 | +} | ||
227 | + | ||
228 | /* bitmap_list_load | ||
229 | * Get bitmap list from qcow2 image. Actually reads bitmap directory, | ||
230 | * checks it and convert to bitmap list. | ||
231 | @@ -XXX,XX +XXX,XX @@ out: | ||
232 | |||
233 | return ret; | 38 | return ret; |
234 | } | 39 | } |
235 | + | 40 | |
236 | +/* bitmap_list_store | 41 | -static int vmdk_read_extent(VmdkExtent *extent, int64_t cluster_offset, |
237 | + * Store bitmap list to qcow2 image as a bitmap directory. | 42 | - int64_t offset_in_cluster, QEMUIOVector *qiov, |
238 | + * Everything is checked. | 43 | - int bytes) |
239 | + */ | 44 | +static int coroutine_fn |
240 | +static int bitmap_list_store(BlockDriverState *bs, Qcow2BitmapList *bm_list, | 45 | +vmdk_read_extent(VmdkExtent *extent, int64_t cluster_offset, |
241 | + uint64_t *offset, uint64_t *size, bool in_place) | 46 | + int64_t offset_in_cluster, QEMUIOVector *qiov, |
242 | +{ | 47 | + int bytes) |
243 | + int ret; | 48 | { |
244 | + uint8_t *dir; | 49 | int ret; |
245 | + int64_t dir_offset = 0; | 50 | int cluster_bytes, buf_bytes; |
246 | + uint64_t dir_size = 0; | 51 | @@ -XXX,XX +XXX,XX @@ fail: |
247 | + Qcow2Bitmap *bm; | 52 | * |
248 | + Qcow2BitmapDirEntry *e; | 53 | * Returns: error code with 0 for success. |
249 | + | 54 | */ |
250 | + QSIMPLEQ_FOREACH(bm, bm_list, entry) { | 55 | -static int vmdk_pwritev(BlockDriverState *bs, uint64_t offset, |
251 | + dir_size += calc_dir_entry_size(strlen(bm->name), 0); | 56 | - uint64_t bytes, QEMUIOVector *qiov, |
252 | + } | 57 | - bool zeroed, bool zero_dry_run) |
253 | + | 58 | +static int coroutine_fn vmdk_pwritev(BlockDriverState *bs, uint64_t offset, |
254 | + if (dir_size == 0 || dir_size > QCOW2_MAX_BITMAP_DIRECTORY_SIZE) { | 59 | + uint64_t bytes, QEMUIOVector *qiov, |
255 | + return -EINVAL; | 60 | + bool zeroed, bool zero_dry_run) |
256 | + } | 61 | { |
257 | + | 62 | BDRVVmdkState *s = bs->opaque; |
258 | + if (in_place) { | 63 | VmdkExtent *extent = NULL; |
259 | + if (*size != dir_size || *offset == 0) { | ||
260 | + return -EINVAL; | ||
261 | + } | ||
262 | + | ||
263 | + dir_offset = *offset; | ||
264 | + } | ||
265 | + | ||
266 | + dir = g_try_malloc(dir_size); | ||
267 | + if (dir == NULL) { | ||
268 | + return -ENOMEM; | ||
269 | + } | ||
270 | + | ||
271 | + e = (Qcow2BitmapDirEntry *)dir; | ||
272 | + QSIMPLEQ_FOREACH(bm, bm_list, entry) { | ||
273 | + e->bitmap_table_offset = bm->table.offset; | ||
274 | + e->bitmap_table_size = bm->table.size; | ||
275 | + e->flags = bm->flags; | ||
276 | + e->type = BT_DIRTY_TRACKING_BITMAP; | ||
277 | + e->granularity_bits = bm->granularity_bits; | ||
278 | + e->name_size = strlen(bm->name); | ||
279 | + e->extra_data_size = 0; | ||
280 | + memcpy(e + 1, bm->name, e->name_size); | ||
281 | + | ||
282 | + if (check_dir_entry(bs, e) < 0) { | ||
283 | + ret = -EINVAL; | ||
284 | + goto fail; | ||
285 | + } | ||
286 | + | ||
287 | + e = next_dir_entry(e); | ||
288 | + } | ||
289 | + | ||
290 | + bitmap_directory_to_be(dir, dir_size); | ||
291 | + | ||
292 | + if (!in_place) { | ||
293 | + dir_offset = qcow2_alloc_clusters(bs, dir_size); | ||
294 | + if (dir_offset < 0) { | ||
295 | + ret = dir_offset; | ||
296 | + goto fail; | ||
297 | + } | ||
298 | + } | ||
299 | + | ||
300 | + ret = qcow2_pre_write_overlap_check(bs, 0, dir_offset, dir_size); | ||
301 | + if (ret < 0) { | ||
302 | + goto fail; | ||
303 | + } | ||
304 | + | ||
305 | + ret = bdrv_pwrite(bs->file, dir_offset, dir, dir_size); | ||
306 | + if (ret < 0) { | ||
307 | + goto fail; | ||
308 | + } | ||
309 | + | ||
310 | + g_free(dir); | ||
311 | + | ||
312 | + if (!in_place) { | ||
313 | + *size = dir_size; | ||
314 | + *offset = dir_offset; | ||
315 | + } | ||
316 | + | ||
317 | + return 0; | ||
318 | + | ||
319 | +fail: | ||
320 | + g_free(dir); | ||
321 | + | ||
322 | + if (!in_place && dir_offset > 0) { | ||
323 | + qcow2_free_clusters(bs, dir_offset, dir_size, QCOW2_DISCARD_OTHER); | ||
324 | + } | ||
325 | + | ||
326 | + return ret; | ||
327 | +} | ||
328 | + | ||
329 | +/* | ||
330 | + * Bitmap List end | ||
331 | + */ | ||
332 | + | ||
333 | +static int update_ext_header_and_dir_in_place(BlockDriverState *bs, | ||
334 | + Qcow2BitmapList *bm_list) | ||
335 | +{ | ||
336 | + BDRVQcow2State *s = bs->opaque; | ||
337 | + int ret; | ||
338 | + | ||
339 | + if (!(s->autoclear_features & QCOW2_AUTOCLEAR_BITMAPS) || | ||
340 | + bm_list == NULL || QSIMPLEQ_EMPTY(bm_list) || | ||
341 | + bitmap_list_count(bm_list) != s->nb_bitmaps) | ||
342 | + { | ||
343 | + return -EINVAL; | ||
344 | + } | ||
345 | + | ||
346 | + s->autoclear_features &= ~(uint64_t)QCOW2_AUTOCLEAR_BITMAPS; | ||
347 | + ret = update_header_sync(bs); | ||
348 | + if (ret < 0) { | ||
349 | + /* Two variants are possible here: | ||
350 | + * 1. Autoclear flag is dropped, all bitmaps will be lost. | ||
351 | + * 2. Autoclear flag is not dropped, old state is left. | ||
352 | + */ | ||
353 | + return ret; | ||
354 | + } | ||
355 | + | ||
356 | + /* autoclear bit is not set, so we can safely update bitmap directory */ | ||
357 | + | ||
358 | + ret = bitmap_list_store(bs, bm_list, &s->bitmap_directory_offset, | ||
359 | + &s->bitmap_directory_size, true); | ||
360 | + if (ret < 0) { | ||
361 | + /* autoclear bit is cleared, so all leaked clusters would be removed on | ||
362 | + * qemu-img check */ | ||
363 | + return ret; | ||
364 | + } | ||
365 | + | ||
366 | + ret = update_header_sync(bs); | ||
367 | + if (ret < 0) { | ||
368 | + /* autoclear bit is cleared, so all leaked clusters would be removed on | ||
369 | + * qemu-img check */ | ||
370 | + return ret; | ||
371 | + } | ||
372 | + | ||
373 | + s->autoclear_features |= QCOW2_AUTOCLEAR_BITMAPS; | ||
374 | + return update_header_sync(bs); | ||
375 | + /* If final update_header_sync() fails, two variants are possible: | ||
376 | + * 1. Autoclear flag is not set, all bitmaps will be lost. | ||
377 | + * 2. Autoclear flag is set, header and directory are successfully updated. | ||
378 | + */ | ||
379 | +} | ||
380 | + | ||
381 | +/* for g_slist_foreach for GSList of BdrvDirtyBitmap* elements */ | ||
382 | +static void release_dirty_bitmap_helper(gpointer bitmap, | ||
383 | + gpointer bs) | ||
384 | +{ | ||
385 | + bdrv_release_dirty_bitmap(bs, bitmap); | ||
386 | +} | ||
387 | + | ||
388 | +/* for g_slist_foreach for GSList of BdrvDirtyBitmap* elements */ | ||
389 | +static void set_readonly_helper(gpointer bitmap, gpointer value) | ||
390 | +{ | ||
391 | + bdrv_dirty_bitmap_set_readonly(bitmap, (bool)value); | ||
392 | +} | ||
393 | + | ||
394 | +/* qcow2_load_autoloading_dirty_bitmaps() | ||
395 | + * Return value is a hint for caller: true means that the Qcow2 header was | ||
396 | + * updated. (false doesn't mean that the header should be updated by the | ||
397 | + * caller, it just means that updating was not needed or the image cannot be | ||
398 | + * written to). | ||
399 | + * On failure the function returns false. | ||
400 | + */ | ||
401 | +bool qcow2_load_autoloading_dirty_bitmaps(BlockDriverState *bs, Error **errp) | ||
402 | +{ | ||
403 | + BDRVQcow2State *s = bs->opaque; | ||
404 | + Qcow2BitmapList *bm_list; | ||
405 | + Qcow2Bitmap *bm; | ||
406 | + GSList *created_dirty_bitmaps = NULL; | ||
407 | + bool header_updated = false; | ||
408 | + | ||
409 | + if (s->nb_bitmaps == 0) { | ||
410 | + /* No bitmaps - nothing to do */ | ||
411 | + return false; | ||
412 | + } | ||
413 | + | ||
414 | + bm_list = bitmap_list_load(bs, s->bitmap_directory_offset, | ||
415 | + s->bitmap_directory_size, errp); | ||
416 | + if (bm_list == NULL) { | ||
417 | + return false; | ||
418 | + } | ||
419 | + | ||
420 | + QSIMPLEQ_FOREACH(bm, bm_list, entry) { | ||
421 | + if ((bm->flags & BME_FLAG_AUTO) && !(bm->flags & BME_FLAG_IN_USE)) { | ||
422 | + BdrvDirtyBitmap *bitmap = load_bitmap(bs, bm, errp); | ||
423 | + if (bitmap == NULL) { | ||
424 | + goto fail; | ||
425 | + } | ||
426 | + bm->flags |= BME_FLAG_IN_USE; | ||
427 | + created_dirty_bitmaps = | ||
428 | + g_slist_append(created_dirty_bitmaps, bitmap); | ||
429 | + } | ||
430 | + } | ||
431 | + | ||
432 | + if (created_dirty_bitmaps != NULL) { | ||
433 | + if (can_write(bs)) { | ||
434 | + /* in_use flags must be updated */ | ||
435 | + int ret = update_ext_header_and_dir_in_place(bs, bm_list); | ||
436 | + if (ret < 0) { | ||
437 | + error_setg_errno(errp, -ret, "Can't update bitmap directory"); | ||
438 | + goto fail; | ||
439 | + } | ||
440 | + header_updated = true; | ||
441 | + } else { | ||
442 | + g_slist_foreach(created_dirty_bitmaps, set_readonly_helper, | ||
443 | + (gpointer)true); | ||
444 | + } | ||
445 | + } | ||
446 | + | ||
447 | + g_slist_free(created_dirty_bitmaps); | ||
448 | + bitmap_list_free(bm_list); | ||
449 | + | ||
450 | + return header_updated; | ||
451 | + | ||
452 | +fail: | ||
453 | + g_slist_foreach(created_dirty_bitmaps, release_dirty_bitmap_helper, bs); | ||
454 | + g_slist_free(created_dirty_bitmaps); | ||
455 | + bitmap_list_free(bm_list); | ||
456 | + | ||
457 | + return false; | ||
458 | +} | ||
459 | diff --git a/block/qcow2.c b/block/qcow2.c | ||
460 | index XXXXXXX..XXXXXXX 100644 | ||
461 | --- a/block/qcow2.c | ||
462 | +++ b/block/qcow2.c | ||
463 | @@ -XXX,XX +XXX,XX @@ static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags, | ||
464 | |||
465 | /* Clear unknown autoclear feature bits */ | ||
466 | update_header |= s->autoclear_features & ~QCOW2_AUTOCLEAR_MASK; | ||
467 | - | ||
468 | - if (update_header && !bs->read_only && !(flags & BDRV_O_INACTIVE)) { | ||
469 | + update_header = | ||
470 | + update_header && !bs->read_only && !(flags & BDRV_O_INACTIVE); | ||
471 | + if (update_header) { | ||
472 | s->autoclear_features &= QCOW2_AUTOCLEAR_MASK; | ||
473 | + } | ||
474 | + | ||
475 | + if (qcow2_load_autoloading_dirty_bitmaps(bs, &local_err)) { | ||
476 | + update_header = false; | ||
477 | + } | ||
478 | + if (local_err != NULL) { | ||
479 | + error_propagate(errp, local_err); | ||
480 | + ret = -EINVAL; | ||
481 | + goto fail; | ||
482 | + } | ||
483 | + | ||
484 | + if (update_header) { | ||
485 | ret = qcow2_update_header(bs); | ||
486 | if (ret < 0) { | ||
487 | error_setg_errno(errp, -ret, "Could not update qcow2 header"); | ||
488 | diff --git a/block/qcow2.h b/block/qcow2.h | ||
489 | index XXXXXXX..XXXXXXX 100644 | ||
490 | --- a/block/qcow2.h | ||
491 | +++ b/block/qcow2.h | ||
492 | @@ -XXX,XX +XXX,XX @@ void qcow2_cache_put(BlockDriverState *bs, Qcow2Cache *c, void **table); | ||
493 | int qcow2_check_bitmaps_refcounts(BlockDriverState *bs, BdrvCheckResult *res, | ||
494 | void **refcount_table, | ||
495 | int64_t *refcount_table_size); | ||
496 | +bool qcow2_load_autoloading_dirty_bitmaps(BlockDriverState *bs, Error **errp); | ||
497 | + | ||
498 | #endif | ||
499 | -- | 64 | -- |
500 | 1.8.3.1 | 65 | 2.37.3 |
501 | |||
502 | diff view generated by jsdifflib |
1 | From: Eric Blake <eblake@redhat.com> | 1 | From: Paolo Bonzini <pbonzini@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Most callback commands in qemu-io return 0 to keep the interpreter | 3 | Callers of coroutine_fn must be coroutine_fn themselves, or the call |
4 | loop running, or 1 to quit immediately. However, open_f() just | 4 | must be within "if (qemu_in_coroutine())". Apply coroutine_fn to |
5 | passed through the return value of openfile(), which has different | 5 | functions where this holds. |
6 | semantics of returning 0 if a file was opened, or 1 on any failure. | ||
7 | 6 | ||
8 | As a result of mixing the return semantics, we are forcing the | 7 | Reviewed-by: Alberto Faria <afaria@redhat.com> |
9 | qemu-io interpreter to exit early on any failures, which is rather | 8 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
10 | annoying when some of the failures are obviously trying to give | 9 | Message-Id: <20220922084924.201610-22-pbonzini@redhat.com> |
11 | the user a hint of how to proceed (if we didn't then kill qemu-io | 10 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> |
12 | out from under the user's feet): | ||
13 | |||
14 | $ qemu-io | ||
15 | qemu-io> open foo | ||
16 | qemu-io> open foo | ||
17 | file open already, try 'help close' | ||
18 | $ echo $? | ||
19 | 0 | ||
20 | |||
21 | In general, we WANT openfile() to report failures, since it is the | ||
22 | function used in the form 'qemu-io -c "$something" no_such_file' | ||
23 | for performing one or more -c options on a single file, and it is | ||
24 | not worth attempting $something if the file itself cannot be opened. | ||
25 | So the solution is to fix open_f() to always return 0 (when we are | ||
26 | in interactive mode, even failure to open should not end the | ||
27 | session), and save the return value of openfile() for command line | ||
28 | use in main(). | ||
29 | |||
30 | Note, however, that we do have some qemu-iotests that do 'qemu-io | ||
31 | -c "open file" -c "$something"'; such tests will now proceed to | ||
32 | attempt $something whether or not the open succeeded, the same way | ||
33 | as if the two commands had been attempted in interactive mode. As | ||
34 | such, the expected output for those tests has to be modified. But it | ||
35 | also means that it is now possible to use -c close and have a single | ||
36 | qemu-io command line operate on more than one file even without | ||
37 | using interactive mode. Although the '-c open' action is a subtle | ||
38 | change in behavior, remember that qemu-io is for debugging purposes, | ||
39 | so as long as it serves the needs of qemu-iotests while still being | ||
40 | reasonable for interactive use, it should not be a problem that we | ||
41 | are changing tests to the new behavior. | ||
42 | |||
43 | This has been awkward since at least as far back as commit | ||
44 | e3aff4f, in 2009. | ||
45 | |||
46 | Signed-off-by: Eric Blake <eblake@redhat.com> | ||
47 | Reviewed-by: Fam Zheng <famz@redhat.com> | ||
48 | Reviewed-by: John Snow <jsnow@redhat.com> | ||
49 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
50 | --- | 12 | --- |
51 | qemu-io.c | 7 ++++--- | 13 | include/qemu/job.h | 2 +- |
52 | tests/qemu-iotests/060.out | 1 + | 14 | job.c | 2 +- |
53 | tests/qemu-iotests/114.out | 5 +++-- | 15 | 2 files changed, 2 insertions(+), 2 deletions(-) |
54 | tests/qemu-iotests/153.out | 6 ++++++ | ||
55 | 4 files changed, 14 insertions(+), 5 deletions(-) | ||
56 | 16 | ||
57 | diff --git a/qemu-io.c b/qemu-io.c | 17 | diff --git a/include/qemu/job.h b/include/qemu/job.h |
58 | index XXXXXXX..XXXXXXX 100644 | 18 | index XXXXXXX..XXXXXXX 100644 |
59 | --- a/qemu-io.c | 19 | --- a/include/qemu/job.h |
60 | +++ b/qemu-io.c | 20 | +++ b/include/qemu/job.h |
61 | @@ -XXX,XX +XXX,XX @@ static int open_f(BlockBackend *blk, int argc, char **argv) | 21 | @@ -XXX,XX +XXX,XX @@ void coroutine_fn job_pause_point(Job *job); |
62 | qemu_opts_reset(&empty_opts); | 22 | * |
63 | 23 | * Yield the job coroutine. | |
64 | if (optind == argc - 1) { | 24 | */ |
65 | - return openfile(argv[optind], flags, writethrough, force_share, opts); | 25 | -void job_yield(Job *job); |
66 | + openfile(argv[optind], flags, writethrough, force_share, opts); | 26 | +void coroutine_fn job_yield(Job *job); |
67 | } else if (optind == argc) { | 27 | |
68 | - return openfile(NULL, flags, writethrough, force_share, opts); | 28 | /** |
69 | + openfile(NULL, flags, writethrough, force_share, opts); | 29 | * @job: The job that calls the function. |
70 | } else { | 30 | diff --git a/job.c b/job.c |
71 | QDECREF(opts); | 31 | index XXXXXXX..XXXXXXX 100644 |
72 | - return qemuio_command_usage(&open_cmd); | 32 | --- a/job.c |
73 | + qemuio_command_usage(&open_cmd); | 33 | +++ b/job.c |
34 | @@ -XXX,XX +XXX,XX @@ void coroutine_fn job_pause_point(Job *job) | ||
74 | } | 35 | } |
75 | + return 0; | ||
76 | } | 36 | } |
77 | 37 | ||
78 | static int quit_f(BlockBackend *blk, int argc, char **argv) | 38 | -void job_yield(Job *job) |
79 | diff --git a/tests/qemu-iotests/060.out b/tests/qemu-iotests/060.out | 39 | +void coroutine_fn job_yield(Job *job) |
80 | index XXXXXXX..XXXXXXX 100644 | 40 | { |
81 | --- a/tests/qemu-iotests/060.out | 41 | assert(job->busy); |
82 | +++ b/tests/qemu-iotests/060.out | ||
83 | @@ -XXX,XX +XXX,XX @@ Format specific information: | ||
84 | refcount bits: 16 | ||
85 | corrupt: true | ||
86 | can't open device TEST_DIR/t.IMGFMT: IMGFMT: Image is corrupt; cannot be opened read/write | ||
87 | +no file open, try 'help open' | ||
88 | read 512/512 bytes at offset 0 | ||
89 | 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
90 | |||
91 | diff --git a/tests/qemu-iotests/114.out b/tests/qemu-iotests/114.out | ||
92 | index XXXXXXX..XXXXXXX 100644 | ||
93 | --- a/tests/qemu-iotests/114.out | ||
94 | +++ b/tests/qemu-iotests/114.out | ||
95 | @@ -XXX,XX +XXX,XX @@ | ||
96 | QA output created by 114 | ||
97 | -Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864 | ||
98 | -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base | ||
99 | +Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864 | ||
100 | +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base | ||
101 | image: TEST_DIR/t.IMGFMT | ||
102 | file format: IMGFMT | ||
103 | virtual size: 64M (67108864 bytes) | ||
104 | @@ -XXX,XX +XXX,XX @@ cluster_size: 65536 | ||
105 | backing file: TEST_DIR/t.IMGFMT.base | ||
106 | backing file format: foo | ||
107 | can't open device TEST_DIR/t.qcow2: Could not open backing file: Unknown driver 'foo' | ||
108 | +no file open, try 'help open' | ||
109 | read 4096/4096 bytes at offset 0 | ||
110 | 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
111 | *** done | ||
112 | diff --git a/tests/qemu-iotests/153.out b/tests/qemu-iotests/153.out | ||
113 | index XXXXXXX..XXXXXXX 100644 | ||
114 | --- a/tests/qemu-iotests/153.out | ||
115 | +++ b/tests/qemu-iotests/153.out | ||
116 | @@ -XXX,XX +XXX,XX @@ Is another process using the image? | ||
117 | _qemu_io_wrapper -c open TEST_DIR/t.qcow2 -c read 0 512 | ||
118 | can't open device TEST_DIR/t.qcow2: Failed to get "write" lock | ||
119 | Is another process using the image? | ||
120 | +no file open, try 'help open' | ||
121 | |||
122 | _qemu_io_wrapper -c open -r TEST_DIR/t.qcow2 -c read 0 512 | ||
123 | can't open device TEST_DIR/t.qcow2: Failed to get shared "write" lock | ||
124 | Is another process using the image? | ||
125 | +no file open, try 'help open' | ||
126 | |||
127 | _qemu_img_wrapper info TEST_DIR/t.qcow2 | ||
128 | qemu-img: Could not open 'TEST_DIR/t.qcow2': Failed to get shared "write" lock | ||
129 | @@ -XXX,XX +XXX,XX @@ _qemu_io_wrapper -U -r -c read 0 512 TEST_DIR/t.qcow2 | ||
130 | |||
131 | _qemu_io_wrapper -c open -U TEST_DIR/t.qcow2 -c read 0 512 | ||
132 | can't open device TEST_DIR/t.qcow2: force-share=on can only be used with read-only images | ||
133 | +no file open, try 'help open' | ||
134 | |||
135 | _qemu_io_wrapper -c open -r -U TEST_DIR/t.qcow2 -c read 0 512 | ||
136 | |||
137 | @@ -XXX,XX +XXX,XX @@ _qemu_io_wrapper -r -c read 0 512 TEST_DIR/t.qcow2 | ||
138 | _qemu_io_wrapper -c open TEST_DIR/t.qcow2 -c read 0 512 | ||
139 | can't open device TEST_DIR/t.qcow2: Failed to get "write" lock | ||
140 | Is another process using the image? | ||
141 | +no file open, try 'help open' | ||
142 | |||
143 | _qemu_io_wrapper -c open -r TEST_DIR/t.qcow2 -c read 0 512 | ||
144 | |||
145 | @@ -XXX,XX +XXX,XX @@ _qemu_io_wrapper -U -r -c read 0 512 TEST_DIR/t.qcow2 | ||
146 | |||
147 | _qemu_io_wrapper -c open -U TEST_DIR/t.qcow2 -c read 0 512 | ||
148 | can't open device TEST_DIR/t.qcow2: force-share=on can only be used with read-only images | ||
149 | +no file open, try 'help open' | ||
150 | |||
151 | _qemu_io_wrapper -c open -r -U TEST_DIR/t.qcow2 -c read 0 512 | ||
152 | |||
153 | @@ -XXX,XX +XXX,XX @@ _qemu_io_wrapper -U -r -c read 0 512 TEST_DIR/t.qcow2 | ||
154 | |||
155 | _qemu_io_wrapper -c open -U TEST_DIR/t.qcow2 -c read 0 512 | ||
156 | can't open device TEST_DIR/t.qcow2: force-share=on can only be used with read-only images | ||
157 | +no file open, try 'help open' | ||
158 | |||
159 | _qemu_io_wrapper -c open -r -U TEST_DIR/t.qcow2 -c read 0 512 | ||
160 | 42 | ||
161 | -- | 43 | -- |
162 | 1.8.3.1 | 44 | 2.37.3 |
163 | |||
164 | diff view generated by jsdifflib |
1 | From: "Daniel P. Berrange" <berrange@redhat.com> | 1 | From: Paolo Bonzini <pbonzini@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Now that qcow & qcow2 are wired up to get encryption keys | 3 | Callers of coroutine_fn must be coroutine_fn themselves, or the call |
4 | via the QCryptoSecret object, nothing is relying on the | 4 | must be within "if (qemu_in_coroutine())". Apply coroutine_fn to |
5 | interactive prompting for passwords. All the code related | 5 | functions where this holds. |
6 | to password prompting can thus be ripped out. | ||
7 | 6 | ||
8 | Reviewed-by: Alberto Garcia <berto@igalia.com> | 7 | Reviewed-by: Alberto Faria <afaria@redhat.com> |
9 | Reviewed-by: Max Reitz <mreitz@redhat.com> | 8 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
10 | Signed-off-by: Daniel P. Berrange <berrange@redhat.com> | 9 | Message-Id: <20220922084924.201610-23-pbonzini@redhat.com> |
11 | Message-id: 20170623162419.26068-17-berrange@redhat.com | 10 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> |
12 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
13 | --- | 12 | --- |
14 | hmp.c | 31 --------------------- | 13 | util/qemu-coroutine-lock.c | 14 +++++++------- |
15 | include/monitor/monitor.h | 7 ----- | 14 | 1 file changed, 7 insertions(+), 7 deletions(-) |
16 | include/qemu/osdep.h | 2 -- | ||
17 | monitor.c | 68 ----------------------------------------------- | ||
18 | qapi-schema.json | 10 +------ | ||
19 | qemu-img.c | 31 --------------------- | ||
20 | qemu-io.c | 20 -------------- | ||
21 | qmp.c | 12 +-------- | ||
22 | util/oslib-posix.c | 66 --------------------------------------------- | ||
23 | util/oslib-win32.c | 24 ----------------- | ||
24 | 10 files changed, 2 insertions(+), 269 deletions(-) | ||
25 | 15 | ||
26 | diff --git a/hmp.c b/hmp.c | 16 | diff --git a/util/qemu-coroutine-lock.c b/util/qemu-coroutine-lock.c |
27 | index XXXXXXX..XXXXXXX 100644 | 17 | index XXXXXXX..XXXXXXX 100644 |
28 | --- a/hmp.c | 18 | --- a/util/qemu-coroutine-lock.c |
29 | +++ b/hmp.c | 19 | +++ b/util/qemu-coroutine-lock.c |
30 | @@ -XXX,XX +XXX,XX @@ void hmp_ringbuf_read(Monitor *mon, const QDict *qdict) | 20 | @@ -XXX,XX +XXX,XX @@ typedef struct CoWaitRecord { |
31 | g_free(data); | 21 | QSLIST_ENTRY(CoWaitRecord) next; |
22 | } CoWaitRecord; | ||
23 | |||
24 | -static void push_waiter(CoMutex *mutex, CoWaitRecord *w) | ||
25 | +static void coroutine_fn push_waiter(CoMutex *mutex, CoWaitRecord *w) | ||
26 | { | ||
27 | w->co = qemu_coroutine_self(); | ||
28 | QSLIST_INSERT_HEAD_ATOMIC(&mutex->from_push, w, next); | ||
29 | @@ -XXX,XX +XXX,XX @@ void qemu_co_rwlock_init(CoRwlock *lock) | ||
32 | } | 30 | } |
33 | 31 | ||
34 | -static void hmp_cont_cb(void *opaque, int err) | 32 | /* Releases the internal CoMutex. */ |
35 | -{ | 33 | -static void qemu_co_rwlock_maybe_wake_one(CoRwlock *lock) |
36 | - if (!err) { | 34 | +static void coroutine_fn qemu_co_rwlock_maybe_wake_one(CoRwlock *lock) |
37 | - qmp_cont(NULL); | ||
38 | - } | ||
39 | -} | ||
40 | - | ||
41 | -static bool key_is_missing(const BlockInfo *bdev) | ||
42 | -{ | ||
43 | - return (bdev->inserted && bdev->inserted->encryption_key_missing); | ||
44 | -} | ||
45 | - | ||
46 | void hmp_cont(Monitor *mon, const QDict *qdict) | ||
47 | { | 35 | { |
48 | - BlockInfoList *bdev_list, *bdev; | 36 | CoRwTicket *tkt = QSIMPLEQ_FIRST(&lock->tickets); |
49 | Error *err = NULL; | 37 | Coroutine *co = NULL; |
50 | 38 | @@ -XXX,XX +XXX,XX @@ static void qemu_co_rwlock_maybe_wake_one(CoRwlock *lock) | |
51 | - bdev_list = qmp_query_block(NULL); | 39 | } |
52 | - for (bdev = bdev_list; bdev; bdev = bdev->next) { | ||
53 | - if (key_is_missing(bdev->value)) { | ||
54 | - monitor_read_block_device_key(mon, bdev->value->device, | ||
55 | - hmp_cont_cb, NULL); | ||
56 | - goto out; | ||
57 | - } | ||
58 | - } | ||
59 | - | ||
60 | qmp_cont(&err); | ||
61 | hmp_handle_error(mon, &err); | ||
62 | - | ||
63 | -out: | ||
64 | - qapi_free_BlockInfoList(bdev_list); | ||
65 | } | 40 | } |
66 | 41 | ||
67 | void hmp_system_wakeup(Monitor *mon, const QDict *qdict) | 42 | -void qemu_co_rwlock_rdlock(CoRwlock *lock) |
68 | @@ -XXX,XX +XXX,XX @@ void hmp_change(Monitor *mon, const QDict *qdict) | 43 | +void coroutine_fn qemu_co_rwlock_rdlock(CoRwlock *lock) |
69 | qmp_blockdev_change_medium(true, device, false, NULL, target, | 44 | { |
70 | !!arg, arg, !!read_only, read_only_mode, | 45 | Coroutine *self = qemu_coroutine_self(); |
71 | &err); | 46 | |
72 | - if (err && | 47 | @@ -XXX,XX +XXX,XX @@ void qemu_co_rwlock_rdlock(CoRwlock *lock) |
73 | - error_get_class(err) == ERROR_CLASS_DEVICE_ENCRYPTED) { | 48 | self->locks_held++; |
74 | - error_free(err); | ||
75 | - monitor_read_block_device_key(mon, device, NULL, NULL); | ||
76 | - return; | ||
77 | - } | ||
78 | } | ||
79 | |||
80 | hmp_handle_error(mon, &err); | ||
81 | diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h | ||
82 | index XXXXXXX..XXXXXXX 100644 | ||
83 | --- a/include/monitor/monitor.h | ||
84 | +++ b/include/monitor/monitor.h | ||
85 | @@ -XXX,XX +XXX,XX @@ void monitor_cleanup(void); | ||
86 | int monitor_suspend(Monitor *mon); | ||
87 | void monitor_resume(Monitor *mon); | ||
88 | |||
89 | -int monitor_read_bdrv_key_start(Monitor *mon, BlockDriverState *bs, | ||
90 | - BlockCompletionFunc *completion_cb, | ||
91 | - void *opaque); | ||
92 | -int monitor_read_block_device_key(Monitor *mon, const char *device, | ||
93 | - BlockCompletionFunc *completion_cb, | ||
94 | - void *opaque); | ||
95 | - | ||
96 | int monitor_get_fd(Monitor *mon, const char *fdname, Error **errp); | ||
97 | int monitor_fd_param(Monitor *mon, const char *fdname, Error **errp); | ||
98 | |||
99 | diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h | ||
100 | index XXXXXXX..XXXXXXX 100644 | ||
101 | --- a/include/qemu/osdep.h | ||
102 | +++ b/include/qemu/osdep.h | ||
103 | @@ -XXX,XX +XXX,XX @@ void qemu_set_tty_echo(int fd, bool echo); | ||
104 | void os_mem_prealloc(int fd, char *area, size_t sz, int smp_cpus, | ||
105 | Error **errp); | ||
106 | |||
107 | -int qemu_read_password(char *buf, int buf_size); | ||
108 | - | ||
109 | /** | ||
110 | * qemu_get_pid_name: | ||
111 | * @pid: pid of a process | ||
112 | diff --git a/monitor.c b/monitor.c | ||
113 | index XXXXXXX..XXXXXXX 100644 | ||
114 | --- a/monitor.c | ||
115 | +++ b/monitor.c | ||
116 | @@ -XXX,XX +XXX,XX @@ void monitor_cleanup(void) | ||
117 | qemu_mutex_unlock(&monitor_lock); | ||
118 | } | 49 | } |
119 | 50 | ||
120 | -static void bdrv_password_cb(void *opaque, const char *password, | 51 | -void qemu_co_rwlock_unlock(CoRwlock *lock) |
121 | - void *readline_opaque) | 52 | +void coroutine_fn qemu_co_rwlock_unlock(CoRwlock *lock) |
122 | -{ | 53 | { |
123 | - Monitor *mon = opaque; | 54 | Coroutine *self = qemu_coroutine_self(); |
124 | - BlockDriverState *bs = readline_opaque; | 55 | |
125 | - int ret = 0; | 56 | @@ -XXX,XX +XXX,XX @@ void qemu_co_rwlock_unlock(CoRwlock *lock) |
126 | - Error *local_err = NULL; | 57 | qemu_co_rwlock_maybe_wake_one(lock); |
127 | - | ||
128 | - bdrv_add_key(bs, password, &local_err); | ||
129 | - if (local_err) { | ||
130 | - error_report_err(local_err); | ||
131 | - ret = -EPERM; | ||
132 | - } | ||
133 | - if (mon->password_completion_cb) | ||
134 | - mon->password_completion_cb(mon->password_opaque, ret); | ||
135 | - | ||
136 | - monitor_read_command(mon, 1); | ||
137 | -} | ||
138 | - | ||
139 | -int monitor_read_bdrv_key_start(Monitor *mon, BlockDriverState *bs, | ||
140 | - BlockCompletionFunc *completion_cb, | ||
141 | - void *opaque) | ||
142 | -{ | ||
143 | - int err; | ||
144 | - | ||
145 | - monitor_printf(mon, "%s (%s) is encrypted.\n", bdrv_get_device_name(bs), | ||
146 | - bdrv_get_encrypted_filename(bs)); | ||
147 | - | ||
148 | - mon->password_completion_cb = completion_cb; | ||
149 | - mon->password_opaque = opaque; | ||
150 | - | ||
151 | - err = monitor_read_password(mon, bdrv_password_cb, bs); | ||
152 | - | ||
153 | - if (err && completion_cb) | ||
154 | - completion_cb(opaque, err); | ||
155 | - | ||
156 | - return err; | ||
157 | -} | ||
158 | - | ||
159 | -int monitor_read_block_device_key(Monitor *mon, const char *device, | ||
160 | - BlockCompletionFunc *completion_cb, | ||
161 | - void *opaque) | ||
162 | -{ | ||
163 | - Error *err = NULL; | ||
164 | - BlockBackend *blk; | ||
165 | - | ||
166 | - blk = blk_by_name(device); | ||
167 | - if (!blk) { | ||
168 | - monitor_printf(mon, "Device not found %s\n", device); | ||
169 | - return -1; | ||
170 | - } | ||
171 | - if (!blk_bs(blk)) { | ||
172 | - monitor_printf(mon, "Device '%s' has no medium\n", device); | ||
173 | - return -1; | ||
174 | - } | ||
175 | - | ||
176 | - bdrv_add_key(blk_bs(blk), NULL, &err); | ||
177 | - if (err) { | ||
178 | - error_free(err); | ||
179 | - return monitor_read_bdrv_key_start(mon, blk_bs(blk), completion_cb, opaque); | ||
180 | - } | ||
181 | - | ||
182 | - if (completion_cb) { | ||
183 | - completion_cb(opaque, 0); | ||
184 | - } | ||
185 | - return 0; | ||
186 | -} | ||
187 | - | ||
188 | QemuOptsList qemu_mon_opts = { | ||
189 | .name = "mon", | ||
190 | .implied_opt_name = "chardev", | ||
191 | diff --git a/qapi-schema.json b/qapi-schema.json | ||
192 | index XXXXXXX..XXXXXXX 100644 | ||
193 | --- a/qapi-schema.json | ||
194 | +++ b/qapi-schema.json | ||
195 | @@ -XXX,XX +XXX,XX @@ | ||
196 | # Since: 0.14.0 | ||
197 | # | ||
198 | # Returns: If successful, nothing | ||
199 | -# If QEMU was started with an encrypted block device and a key has | ||
200 | -# not yet been set, DeviceEncrypted. | ||
201 | # | ||
202 | # Notes: This command will succeed if the guest is currently running. It | ||
203 | # will also succeed if the guest is in the "inmigrate" state; in | ||
204 | @@ -XXX,XX +XXX,XX @@ | ||
205 | # * This command is stateless, this means that commands that depend | ||
206 | # on state information (such as getfd) might not work | ||
207 | # | ||
208 | -# * Commands that prompt the user for data (eg. 'cont' when the block | ||
209 | -# device is encrypted) don't currently work | ||
210 | +# * Commands that prompt the user for data don't currently work | ||
211 | # | ||
212 | # Example: | ||
213 | # | ||
214 | @@ -XXX,XX +XXX,XX @@ | ||
215 | # | ||
216 | # Returns: Nothing on success. | ||
217 | # If @device is not a valid block device, DeviceNotFound | ||
218 | -# If the new block device is encrypted, DeviceEncrypted. Note that | ||
219 | -# if this error is returned, the device has been opened successfully | ||
220 | -# and an additional call to @block_passwd is required to set the | ||
221 | -# device's password. The behavior of reads and writes to the block | ||
222 | -# device between when these calls are executed is undefined. | ||
223 | # | ||
224 | # Notes: This interface is deprecated, and it is strongly recommended that you | ||
225 | # avoid using it. For changing block devices, use | ||
226 | diff --git a/qemu-img.c b/qemu-img.c | ||
227 | index XXXXXXX..XXXXXXX 100644 | ||
228 | --- a/qemu-img.c | ||
229 | +++ b/qemu-img.c | ||
230 | @@ -XXX,XX +XXX,XX @@ static int print_block_option_help(const char *filename, const char *fmt) | ||
231 | } | 58 | } |
232 | 59 | ||
233 | 60 | -void qemu_co_rwlock_downgrade(CoRwlock *lock) | |
234 | -static int img_open_password(BlockBackend *blk, const char *filename, | 61 | +void coroutine_fn qemu_co_rwlock_downgrade(CoRwlock *lock) |
235 | - int flags, bool quiet) | 62 | { |
236 | -{ | 63 | qemu_co_mutex_lock(&lock->mutex); |
237 | - BlockDriverState *bs; | 64 | assert(lock->owners == -1); |
238 | - char password[256]; | 65 | @@ -XXX,XX +XXX,XX @@ void qemu_co_rwlock_downgrade(CoRwlock *lock) |
239 | - | 66 | qemu_co_rwlock_maybe_wake_one(lock); |
240 | - bs = blk_bs(blk); | ||
241 | - if (bdrv_is_encrypted(bs) && bdrv_key_required(bs) && | ||
242 | - !(flags & BDRV_O_NO_IO)) { | ||
243 | - qprintf(quiet, "Disk image '%s' is encrypted.\n", filename); | ||
244 | - if (qemu_read_password(password, sizeof(password)) < 0) { | ||
245 | - error_report("No password given"); | ||
246 | - return -1; | ||
247 | - } | ||
248 | - if (bdrv_set_key(bs, password) < 0) { | ||
249 | - error_report("invalid password"); | ||
250 | - return -1; | ||
251 | - } | ||
252 | - } | ||
253 | - return 0; | ||
254 | -} | ||
255 | - | ||
256 | - | ||
257 | static BlockBackend *img_open_opts(const char *optstr, | ||
258 | QemuOpts *opts, int flags, bool writethrough, | ||
259 | bool quiet, bool force_share) | ||
260 | @@ -XXX,XX +XXX,XX @@ static BlockBackend *img_open_opts(const char *optstr, | ||
261 | } | ||
262 | blk_set_enable_write_cache(blk, !writethrough); | ||
263 | |||
264 | - if (img_open_password(blk, optstr, flags, quiet) < 0) { | ||
265 | - blk_unref(blk); | ||
266 | - return NULL; | ||
267 | - } | ||
268 | return blk; | ||
269 | } | 67 | } |
270 | 68 | ||
271 | @@ -XXX,XX +XXX,XX @@ static BlockBackend *img_open_file(const char *filename, | 69 | -void qemu_co_rwlock_wrlock(CoRwlock *lock) |
272 | } | 70 | +void coroutine_fn qemu_co_rwlock_wrlock(CoRwlock *lock) |
273 | blk_set_enable_write_cache(blk, !writethrough); | 71 | { |
274 | 72 | Coroutine *self = qemu_coroutine_self(); | |
275 | - if (img_open_password(blk, filename, flags, quiet) < 0) { | 73 | |
276 | - blk_unref(blk); | 74 | @@ -XXX,XX +XXX,XX @@ void qemu_co_rwlock_wrlock(CoRwlock *lock) |
277 | - return NULL; | 75 | self->locks_held++; |
278 | - } | ||
279 | return blk; | ||
280 | } | 76 | } |
281 | 77 | ||
282 | diff --git a/qemu-io.c b/qemu-io.c | 78 | -void qemu_co_rwlock_upgrade(CoRwlock *lock) |
283 | index XXXXXXX..XXXXXXX 100644 | 79 | +void coroutine_fn qemu_co_rwlock_upgrade(CoRwlock *lock) |
284 | --- a/qemu-io.c | ||
285 | +++ b/qemu-io.c | ||
286 | @@ -XXX,XX +XXX,XX @@ static int openfile(char *name, int flags, bool writethrough, bool force_share, | ||
287 | QDict *opts) | ||
288 | { | 80 | { |
289 | Error *local_err = NULL; | 81 | qemu_co_mutex_lock(&lock->mutex); |
290 | - BlockDriverState *bs; | 82 | assert(lock->owners > 0); |
291 | |||
292 | if (qemuio_blk) { | ||
293 | error_report("file open already, try 'help close'"); | ||
294 | @@ -XXX,XX +XXX,XX @@ static int openfile(char *name, int flags, bool writethrough, bool force_share, | ||
295 | return 1; | ||
296 | } | ||
297 | |||
298 | - bs = blk_bs(qemuio_blk); | ||
299 | - if (bdrv_is_encrypted(bs) && bdrv_key_required(bs)) { | ||
300 | - char password[256]; | ||
301 | - printf("Disk image '%s' is encrypted.\n", name); | ||
302 | - if (qemu_read_password(password, sizeof(password)) < 0) { | ||
303 | - error_report("No password given"); | ||
304 | - goto error; | ||
305 | - } | ||
306 | - if (bdrv_set_key(bs, password) < 0) { | ||
307 | - error_report("invalid password"); | ||
308 | - goto error; | ||
309 | - } | ||
310 | - } | ||
311 | - | ||
312 | blk_set_enable_write_cache(qemuio_blk, !writethrough); | ||
313 | |||
314 | return 0; | ||
315 | - | ||
316 | - error: | ||
317 | - blk_unref(qemuio_blk); | ||
318 | - qemuio_blk = NULL; | ||
319 | - return 1; | ||
320 | } | ||
321 | |||
322 | static void open_help(void) | ||
323 | diff --git a/qmp.c b/qmp.c | ||
324 | index XXXXXXX..XXXXXXX 100644 | ||
325 | --- a/qmp.c | ||
326 | +++ b/qmp.c | ||
327 | @@ -XXX,XX +XXX,XX @@ SpiceInfo *qmp_query_spice(Error **errp) | ||
328 | |||
329 | void qmp_cont(Error **errp) | ||
330 | { | ||
331 | - Error *local_err = NULL; | ||
332 | BlockBackend *blk; | ||
333 | - BlockDriverState *bs; | ||
334 | - BdrvNextIterator it; | ||
335 | + Error *local_err = NULL; | ||
336 | |||
337 | /* if there is a dump in background, we should wait until the dump | ||
338 | * finished */ | ||
339 | @@ -XXX,XX +XXX,XX @@ void qmp_cont(Error **errp) | ||
340 | blk_iostatus_reset(blk); | ||
341 | } | ||
342 | |||
343 | - for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { | ||
344 | - bdrv_add_key(bs, NULL, &local_err); | ||
345 | - if (local_err) { | ||
346 | - error_propagate(errp, local_err); | ||
347 | - return; | ||
348 | - } | ||
349 | - } | ||
350 | - | ||
351 | /* Continuing after completed migration. Images have been inactivated to | ||
352 | * allow the destination to take control. Need to get control back now. | ||
353 | * | ||
354 | diff --git a/util/oslib-posix.c b/util/oslib-posix.c | ||
355 | index XXXXXXX..XXXXXXX 100644 | ||
356 | --- a/util/oslib-posix.c | ||
357 | +++ b/util/oslib-posix.c | ||
358 | @@ -XXX,XX +XXX,XX @@ void os_mem_prealloc(int fd, char *area, size_t memory, int smp_cpus, | ||
359 | } | ||
360 | |||
361 | |||
362 | -static struct termios oldtty; | ||
363 | - | ||
364 | -static void term_exit(void) | ||
365 | -{ | ||
366 | - tcsetattr(0, TCSANOW, &oldtty); | ||
367 | -} | ||
368 | - | ||
369 | -static void term_init(void) | ||
370 | -{ | ||
371 | - struct termios tty; | ||
372 | - | ||
373 | - tcgetattr(0, &tty); | ||
374 | - oldtty = tty; | ||
375 | - | ||
376 | - tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP | ||
377 | - |INLCR|IGNCR|ICRNL|IXON); | ||
378 | - tty.c_oflag |= OPOST; | ||
379 | - tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN); | ||
380 | - tty.c_cflag &= ~(CSIZE|PARENB); | ||
381 | - tty.c_cflag |= CS8; | ||
382 | - tty.c_cc[VMIN] = 1; | ||
383 | - tty.c_cc[VTIME] = 0; | ||
384 | - | ||
385 | - tcsetattr(0, TCSANOW, &tty); | ||
386 | - | ||
387 | - atexit(term_exit); | ||
388 | -} | ||
389 | - | ||
390 | -int qemu_read_password(char *buf, int buf_size) | ||
391 | -{ | ||
392 | - uint8_t ch; | ||
393 | - int i, ret; | ||
394 | - | ||
395 | - printf("password: "); | ||
396 | - fflush(stdout); | ||
397 | - term_init(); | ||
398 | - i = 0; | ||
399 | - for (;;) { | ||
400 | - ret = read(0, &ch, 1); | ||
401 | - if (ret == -1) { | ||
402 | - if (errno == EAGAIN || errno == EINTR) { | ||
403 | - continue; | ||
404 | - } else { | ||
405 | - break; | ||
406 | - } | ||
407 | - } else if (ret == 0) { | ||
408 | - ret = -1; | ||
409 | - break; | ||
410 | - } else { | ||
411 | - if (ch == '\r' || | ||
412 | - ch == '\n') { | ||
413 | - ret = 0; | ||
414 | - break; | ||
415 | - } | ||
416 | - if (i < (buf_size - 1)) { | ||
417 | - buf[i++] = ch; | ||
418 | - } | ||
419 | - } | ||
420 | - } | ||
421 | - term_exit(); | ||
422 | - buf[i] = '\0'; | ||
423 | - printf("\n"); | ||
424 | - return ret; | ||
425 | -} | ||
426 | - | ||
427 | - | ||
428 | char *qemu_get_pid_name(pid_t pid) | ||
429 | { | ||
430 | char *name = NULL; | ||
431 | diff --git a/util/oslib-win32.c b/util/oslib-win32.c | ||
432 | index XXXXXXX..XXXXXXX 100644 | ||
433 | --- a/util/oslib-win32.c | ||
434 | +++ b/util/oslib-win32.c | ||
435 | @@ -XXX,XX +XXX,XX @@ void os_mem_prealloc(int fd, char *area, size_t memory, int smp_cpus, | ||
436 | } | ||
437 | |||
438 | |||
439 | -/* XXX: put correct support for win32 */ | ||
440 | -int qemu_read_password(char *buf, int buf_size) | ||
441 | -{ | ||
442 | - int c, i; | ||
443 | - | ||
444 | - printf("Password: "); | ||
445 | - fflush(stdout); | ||
446 | - i = 0; | ||
447 | - for (;;) { | ||
448 | - c = getchar(); | ||
449 | - if (c < 0) { | ||
450 | - buf[i] = '\0'; | ||
451 | - return -1; | ||
452 | - } else if (c == '\n') { | ||
453 | - break; | ||
454 | - } else if (i < (buf_size - 1)) { | ||
455 | - buf[i++] = c; | ||
456 | - } | ||
457 | - } | ||
458 | - buf[i] = '\0'; | ||
459 | - return 0; | ||
460 | -} | ||
461 | - | ||
462 | - | ||
463 | char *qemu_get_pid_name(pid_t pid) | ||
464 | { | ||
465 | /* XXX Implement me */ | ||
466 | -- | 83 | -- |
467 | 1.8.3.1 | 84 | 2.37.3 |
468 | |||
469 | diff view generated by jsdifflib |
1 | From: Eric Blake <eblake@redhat.com> | 1 | From: Paolo Bonzini <pbonzini@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | The lone caller that cares about a return of BDRV_BLOCK_RAW | 3 | Callers of coroutine_fn must be coroutine_fn themselves, or the call |
4 | (namely, io.c:bdrv_co_get_block_status) completely replaces the | 4 | must be within "if (qemu_in_coroutine())". Apply coroutine_fn to |
5 | return value, so there is no point in passing BDRV_BLOCK_DATA. | 5 | functions where this holds. |
6 | 6 | ||
7 | Signed-off-by: Eric Blake <eblake@redhat.com> | 7 | Reviewed-by: Alberto Faria <afaria@redhat.com> |
8 | Reviewed-by: Fam Zheng <famz@redhat.com> | 8 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
9 | Reviewed-by: John Snow <jsnow@redhat.com> | 9 | Message-Id: <20220922084924.201610-24-pbonzini@redhat.com> |
10 | [kwolf: Fixed up coding style] | ||
11 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
11 | --- | 13 | --- |
12 | block/commit.c | 2 +- | 14 | block/raw-format.c | 3 ++- |
13 | block/mirror.c | 2 +- | 15 | 1 file changed, 2 insertions(+), 1 deletion(-) |
14 | block/raw-format.c | 2 +- | ||
15 | block/vpc.c | 2 +- | ||
16 | include/block/block.h | 6 +++--- | ||
17 | 5 files changed, 7 insertions(+), 7 deletions(-) | ||
18 | 16 | ||
19 | diff --git a/block/commit.c b/block/commit.c | ||
20 | index XXXXXXX..XXXXXXX 100644 | ||
21 | --- a/block/commit.c | ||
22 | +++ b/block/commit.c | ||
23 | @@ -XXX,XX +XXX,XX @@ static int64_t coroutine_fn bdrv_commit_top_get_block_status( | ||
24 | { | ||
25 | *pnum = nb_sectors; | ||
26 | *file = bs->backing->bs; | ||
27 | - return BDRV_BLOCK_RAW | BDRV_BLOCK_OFFSET_VALID | BDRV_BLOCK_DATA | | ||
28 | + return BDRV_BLOCK_RAW | BDRV_BLOCK_OFFSET_VALID | | ||
29 | (sector_num << BDRV_SECTOR_BITS); | ||
30 | } | ||
31 | |||
32 | diff --git a/block/mirror.c b/block/mirror.c | ||
33 | index XXXXXXX..XXXXXXX 100644 | ||
34 | --- a/block/mirror.c | ||
35 | +++ b/block/mirror.c | ||
36 | @@ -XXX,XX +XXX,XX @@ static int64_t coroutine_fn bdrv_mirror_top_get_block_status( | ||
37 | { | ||
38 | *pnum = nb_sectors; | ||
39 | *file = bs->backing->bs; | ||
40 | - return BDRV_BLOCK_RAW | BDRV_BLOCK_OFFSET_VALID | BDRV_BLOCK_DATA | | ||
41 | + return BDRV_BLOCK_RAW | BDRV_BLOCK_OFFSET_VALID | | ||
42 | (sector_num << BDRV_SECTOR_BITS); | ||
43 | } | ||
44 | |||
45 | diff --git a/block/raw-format.c b/block/raw-format.c | 17 | diff --git a/block/raw-format.c b/block/raw-format.c |
46 | index XXXXXXX..XXXXXXX 100644 | 18 | index XXXXXXX..XXXXXXX 100644 |
47 | --- a/block/raw-format.c | 19 | --- a/block/raw-format.c |
48 | +++ b/block/raw-format.c | 20 | +++ b/block/raw-format.c |
49 | @@ -XXX,XX +XXX,XX @@ static int64_t coroutine_fn raw_co_get_block_status(BlockDriverState *bs, | 21 | @@ -XXX,XX +XXX,XX @@ static void raw_lock_medium(BlockDriverState *bs, bool locked) |
50 | *pnum = nb_sectors; | 22 | bdrv_lock_medium(bs->file->bs, locked); |
51 | *file = bs->file->bs; | ||
52 | sector_num += s->offset / BDRV_SECTOR_SIZE; | ||
53 | - return BDRV_BLOCK_RAW | BDRV_BLOCK_OFFSET_VALID | BDRV_BLOCK_DATA | | ||
54 | + return BDRV_BLOCK_RAW | BDRV_BLOCK_OFFSET_VALID | | ||
55 | (sector_num << BDRV_SECTOR_BITS); | ||
56 | } | 23 | } |
57 | 24 | ||
58 | diff --git a/block/vpc.c b/block/vpc.c | 25 | -static int raw_co_ioctl(BlockDriverState *bs, unsigned long int req, void *buf) |
59 | index XXXXXXX..XXXXXXX 100644 | 26 | +static int coroutine_fn raw_co_ioctl(BlockDriverState *bs, |
60 | --- a/block/vpc.c | 27 | + unsigned long int req, void *buf) |
61 | +++ b/block/vpc.c | 28 | { |
62 | @@ -XXX,XX +XXX,XX @@ static int64_t coroutine_fn vpc_co_get_block_status(BlockDriverState *bs, | 29 | BDRVRawState *s = bs->opaque; |
63 | if (be32_to_cpu(footer->type) == VHD_FIXED) { | 30 | if (s->offset || s->has_size) { |
64 | *pnum = nb_sectors; | ||
65 | *file = bs->file->bs; | ||
66 | - return BDRV_BLOCK_RAW | BDRV_BLOCK_OFFSET_VALID | BDRV_BLOCK_DATA | | ||
67 | + return BDRV_BLOCK_RAW | BDRV_BLOCK_OFFSET_VALID | | ||
68 | (sector_num << BDRV_SECTOR_BITS); | ||
69 | } | ||
70 | |||
71 | diff --git a/include/block/block.h b/include/block/block.h | ||
72 | index XXXXXXX..XXXXXXX 100644 | ||
73 | --- a/include/block/block.h | ||
74 | +++ b/include/block/block.h | ||
75 | @@ -XXX,XX +XXX,XX @@ typedef struct HDGeometry { | ||
76 | * BDRV_BLOCK_EOF: the returned pnum covers through end of file for this layer | ||
77 | * | ||
78 | * Internal flag: | ||
79 | - * BDRV_BLOCK_RAW: used internally to indicate that the request was | ||
80 | - * answered by a passthrough driver such as raw and that the | ||
81 | - * block layer should recompute the answer from bs->file. | ||
82 | + * BDRV_BLOCK_RAW: for use by passthrough drivers, such as raw, to request | ||
83 | + * that the block layer recompute the answer from the returned | ||
84 | + * BDS; must be accompanied by just BDRV_BLOCK_OFFSET_VALID. | ||
85 | * | ||
86 | * If BDRV_BLOCK_OFFSET_VALID is set, bits 9-62 (BDRV_BLOCK_OFFSET_MASK) | ||
87 | * represent the offset in the returned BDS that is allocated for the | ||
88 | -- | 31 | -- |
89 | 1.8.3.1 | 32 | 2.37.3 |
90 | |||
91 | diff view generated by jsdifflib |
1 | From: Hervé Poussineau <hpoussin@reactos.org> | 1 | From: Marc-André Lureau <marcandre.lureau@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | - offset_to_bootsector is the number of sectors up to FAT bootsector | 3 | Callers of coroutine_fn must be coroutine_fn themselves, or the call |
4 | - offset_to_fat is the number of sectors up to first File Allocation Table | 4 | must be within "if (qemu_in_coroutine())". Apply coroutine_fn to |
5 | - offset_to_root_dir is the number of sectors up to root directory sector | 5 | functions where this holds. |
6 | 6 | ||
7 | Replace first_sectors_number - 1 by offset_to_bootsector. | 7 | Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> |
8 | Replace first_sectors_number by offset_to_fat. | 8 | Acked-by: Greg Kurz <groug@kaod.org> |
9 | Replace faked_sectors by offset_to_rootdir. | 9 | Reviewed-by: Alberto Faria <afaria@redhat.com> |
10 | 10 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> | |
11 | Signed-off-by: Hervé Poussineau <hpoussin@reactos.org> | 11 | Message-Id: <20220922084924.201610-25-pbonzini@redhat.com> |
12 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 13 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
13 | --- | 14 | --- |
14 | block/vvfat.c | 70 ++++++++++++++++++++++++++++++++++++----------------------- | 15 | hw/9pfs/9p.h | 9 ++++++--- |
15 | 1 file changed, 43 insertions(+), 27 deletions(-) | 16 | 1 file changed, 6 insertions(+), 3 deletions(-) |
16 | 17 | ||
17 | diff --git a/block/vvfat.c b/block/vvfat.c | 18 | diff --git a/hw/9pfs/9p.h b/hw/9pfs/9p.h |
18 | index XXXXXXX..XXXXXXX 100644 | 19 | index XXXXXXX..XXXXXXX 100644 |
19 | --- a/block/vvfat.c | 20 | --- a/hw/9pfs/9p.h |
20 | +++ b/block/vvfat.c | 21 | +++ b/hw/9pfs/9p.h |
21 | @@ -XXX,XX +XXX,XX @@ static void print_mapping(const struct mapping_t* mapping); | 22 | @@ -XXX,XX +XXX,XX @@ typedef struct V9fsGetlock |
22 | typedef struct BDRVVVFATState { | 23 | extern int open_fd_hw; |
23 | CoMutex lock; | 24 | extern int total_open_fd; |
24 | BlockDriverState* bs; /* pointer to parent */ | 25 | |
25 | - unsigned int first_sectors_number; /* 1 for a single partition, 0x40 for a disk with partition table */ | 26 | -static inline void v9fs_path_write_lock(V9fsState *s) |
26 | unsigned char first_sectors[0x40*0x200]; | 27 | +static inline void coroutine_fn |
27 | 28 | +v9fs_path_write_lock(V9fsState *s) | |
28 | int fat_type; /* 16 or 32 */ | ||
29 | array_t fat,directory,mapping; | ||
30 | char volume_label[11]; | ||
31 | |||
32 | + uint32_t offset_to_bootsector; /* 0 for floppy, 0x3f for disk */ | ||
33 | + | ||
34 | unsigned int cluster_size; | ||
35 | unsigned int sectors_per_cluster; | ||
36 | unsigned int sectors_per_fat; | ||
37 | unsigned int sectors_of_root_directory; | ||
38 | uint32_t last_cluster_of_root_directory; | ||
39 | - unsigned int faked_sectors; /* how many sectors are faked before file data */ | ||
40 | uint32_t sector_count; /* total number of sectors of the partition */ | ||
41 | uint32_t cluster_count; /* total number of clusters of this partition */ | ||
42 | uint32_t max_fat_value; | ||
43 | + uint32_t offset_to_fat; | ||
44 | + uint32_t offset_to_root_dir; | ||
45 | |||
46 | int current_fd; | ||
47 | mapping_t* current_mapping; | ||
48 | @@ -XXX,XX +XXX,XX @@ static void init_mbr(BDRVVVFATState *s, int cyls, int heads, int secs) | ||
49 | partition->attributes=0x80; /* bootable */ | ||
50 | |||
51 | /* LBA is used when partition is outside the CHS geometry */ | ||
52 | - lba = sector2CHS(&partition->start_CHS, s->first_sectors_number - 1, | ||
53 | + lba = sector2CHS(&partition->start_CHS, s->offset_to_bootsector, | ||
54 | cyls, heads, secs); | ||
55 | lba |= sector2CHS(&partition->end_CHS, s->bs->total_sectors - 1, | ||
56 | cyls, heads, secs); | ||
57 | |||
58 | /*LBA partitions are identified only by start/length_sector_long not by CHS*/ | ||
59 | - partition->start_sector_long = cpu_to_le32(s->first_sectors_number - 1); | ||
60 | + partition->start_sector_long = cpu_to_le32(s->offset_to_bootsector); | ||
61 | partition->length_sector_long = cpu_to_le32(s->bs->total_sectors | ||
62 | - - s->first_sectors_number + 1); | ||
63 | + - s->offset_to_bootsector); | ||
64 | |||
65 | /* FAT12/FAT16/FAT32 */ | ||
66 | /* DOS uses different types when partition is LBA, | ||
67 | @@ -XXX,XX +XXX,XX @@ static int read_directory(BDRVVVFATState* s, int mapping_index) | ||
68 | |||
69 | static inline uint32_t sector2cluster(BDRVVVFATState* s,off_t sector_num) | ||
70 | { | 29 | { |
71 | - return (sector_num-s->faked_sectors)/s->sectors_per_cluster; | 30 | if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) { |
72 | + return (sector_num - s->offset_to_root_dir) / s->sectors_per_cluster; | 31 | qemu_co_rwlock_wrlock(&s->rename_lock); |
32 | } | ||
73 | } | 33 | } |
74 | 34 | ||
75 | static inline off_t cluster2sector(BDRVVVFATState* s, uint32_t cluster_num) | 35 | -static inline void v9fs_path_read_lock(V9fsState *s) |
36 | +static inline void coroutine_fn | ||
37 | +v9fs_path_read_lock(V9fsState *s) | ||
76 | { | 38 | { |
77 | - return s->faked_sectors + s->sectors_per_cluster * cluster_num; | 39 | if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) { |
78 | + return s->offset_to_root_dir + s->sectors_per_cluster * cluster_num; | 40 | qemu_co_rwlock_rdlock(&s->rename_lock); |
41 | } | ||
79 | } | 42 | } |
80 | 43 | ||
81 | static int init_directories(BDRVVVFATState* s, | 44 | -static inline void v9fs_path_unlock(V9fsState *s) |
82 | @@ -XXX,XX +XXX,XX @@ static int init_directories(BDRVVVFATState* s, | 45 | +static inline void coroutine_fn |
83 | i = 1+s->sectors_per_cluster*0x200*8/s->fat_type; | 46 | +v9fs_path_unlock(V9fsState *s) |
84 | s->sectors_per_fat=(s->sector_count+i)/i; /* round up */ | 47 | { |
85 | 48 | if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) { | |
86 | + s->offset_to_fat = s->offset_to_bootsector + 1; | 49 | qemu_co_rwlock_unlock(&s->rename_lock); |
87 | + s->offset_to_root_dir = s->offset_to_fat + s->sectors_per_fat * 2; | ||
88 | + | ||
89 | array_init(&(s->mapping),sizeof(mapping_t)); | ||
90 | array_init(&(s->directory),sizeof(direntry_t)); | ||
91 | |||
92 | @@ -XXX,XX +XXX,XX @@ static int init_directories(BDRVVVFATState* s, | ||
93 | /* Now build FAT, and write back information into directory */ | ||
94 | init_fat(s); | ||
95 | |||
96 | - s->faked_sectors=s->first_sectors_number+s->sectors_per_fat*2; | ||
97 | s->cluster_count=sector2cluster(s, s->sector_count); | ||
98 | |||
99 | mapping = array_get_next(&(s->mapping)); | ||
100 | @@ -XXX,XX +XXX,XX @@ static int init_directories(BDRVVVFATState* s, | ||
101 | |||
102 | s->current_mapping = NULL; | ||
103 | |||
104 | - bootsector=(bootsector_t*)(s->first_sectors+(s->first_sectors_number-1)*0x200); | ||
105 | + bootsector = (bootsector_t *)(s->first_sectors | ||
106 | + + s->offset_to_bootsector * 0x200); | ||
107 | bootsector->jump[0]=0xeb; | ||
108 | bootsector->jump[1]=0x3e; | ||
109 | bootsector->jump[2]=0x90; | ||
110 | @@ -XXX,XX +XXX,XX @@ static int init_directories(BDRVVVFATState* s, | ||
111 | bootsector->number_of_fats=0x2; /* number of FATs */ | ||
112 | bootsector->root_entries=cpu_to_le16(s->sectors_of_root_directory*0x10); | ||
113 | bootsector->total_sectors16=s->sector_count>0xffff?0:cpu_to_le16(s->sector_count); | ||
114 | - bootsector->media_type=(s->first_sectors_number>1?0xf8:0xf0); /* media descriptor (f8=hd, f0=3.5 fd)*/ | ||
115 | + /* media descriptor: hard disk=0xf8, floppy=0xf0 */ | ||
116 | + bootsector->media_type = (s->offset_to_bootsector > 0 ? 0xf8 : 0xf0); | ||
117 | s->fat.pointer[0] = bootsector->media_type; | ||
118 | bootsector->sectors_per_fat=cpu_to_le16(s->sectors_per_fat); | ||
119 | bootsector->sectors_per_track = cpu_to_le16(secs); | ||
120 | bootsector->number_of_heads = cpu_to_le16(heads); | ||
121 | - bootsector->hidden_sectors=cpu_to_le32(s->first_sectors_number==1?0:0x3f); | ||
122 | + bootsector->hidden_sectors = cpu_to_le32(s->offset_to_bootsector); | ||
123 | bootsector->total_sectors=cpu_to_le32(s->sector_count>0xffff?s->sector_count:0); | ||
124 | |||
125 | /* LATER TODO: if FAT32, this is wrong */ | ||
126 | - bootsector->u.fat16.drive_number=s->first_sectors_number==1?0:0x80; /* fda=0, hda=0x80 */ | ||
127 | + /* drive_number: fda=0, hda=0x80 */ | ||
128 | + bootsector->u.fat16.drive_number = s->offset_to_bootsector == 0 ? 0 : 0x80; | ||
129 | bootsector->u.fat16.current_head=0; | ||
130 | bootsector->u.fat16.signature=0x29; | ||
131 | bootsector->u.fat16.id=cpu_to_le32(0xfabe1afd); | ||
132 | @@ -XXX,XX +XXX,XX @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags, | ||
133 | secs = s->fat_type == 12 ? 18 : 36; | ||
134 | s->sectors_per_cluster = 1; | ||
135 | } | ||
136 | - s->first_sectors_number = 1; | ||
137 | cyls = 80; | ||
138 | heads = 2; | ||
139 | } else { | ||
140 | @@ -XXX,XX +XXX,XX @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags, | ||
141 | if (!s->fat_type) { | ||
142 | s->fat_type = 16; | ||
143 | } | ||
144 | - s->first_sectors_number = 0x40; | ||
145 | + s->offset_to_bootsector = 0x3f; | ||
146 | cyls = s->fat_type == 12 ? 64 : 1024; | ||
147 | heads = 16; | ||
148 | secs = 63; | ||
149 | @@ -XXX,XX +XXX,XX @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags, | ||
150 | fprintf(stderr, "vvfat %s chs %d,%d,%d\n", | ||
151 | dirname, cyls, heads, secs); | ||
152 | |||
153 | - s->sector_count = cyls * heads * secs - (s->first_sectors_number - 1); | ||
154 | + s->sector_count = cyls * heads * secs - s->offset_to_bootsector; | ||
155 | |||
156 | if (qemu_opt_get_bool(opts, "rw", false)) { | ||
157 | if (!bdrv_is_read_only(bs)) { | ||
158 | @@ -XXX,XX +XXX,XX @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags, | ||
159 | goto fail; | ||
160 | } | ||
161 | |||
162 | - s->sector_count = s->faked_sectors + s->sectors_per_cluster*s->cluster_count; | ||
163 | + s->sector_count = s->offset_to_root_dir | ||
164 | + + s->sectors_per_cluster * s->cluster_count; | ||
165 | |||
166 | /* Disable migration when vvfat is used rw */ | ||
167 | if (s->qcow) { | ||
168 | @@ -XXX,XX +XXX,XX @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags, | ||
169 | } | ||
170 | } | ||
171 | |||
172 | - if (s->first_sectors_number == 0x40) { | ||
173 | + if (s->offset_to_bootsector > 0) { | ||
174 | init_mbr(s, cyls, heads, secs); | ||
175 | } | ||
176 | |||
177 | @@ -XXX,XX +XXX,XX @@ static int vvfat_read(BlockDriverState *bs, int64_t sector_num, | ||
178 | } | ||
179 | DLOG(fprintf(stderr, "sector %d not allocated\n", (int)sector_num)); | ||
180 | } | ||
181 | - if(sector_num<s->faked_sectors) { | ||
182 | - if(sector_num<s->first_sectors_number) | ||
183 | - memcpy(buf+i*0x200,&(s->first_sectors[sector_num*0x200]),0x200); | ||
184 | - else if(sector_num-s->first_sectors_number<s->sectors_per_fat) | ||
185 | - memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number)*0x200]),0x200); | ||
186 | - else if(sector_num-s->first_sectors_number-s->sectors_per_fat<s->sectors_per_fat) | ||
187 | - memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number-s->sectors_per_fat)*0x200]),0x200); | ||
188 | + if (sector_num < s->offset_to_root_dir) { | ||
189 | + if (sector_num < s->offset_to_fat) { | ||
190 | + memcpy(buf + i * 0x200, | ||
191 | + &(s->first_sectors[sector_num * 0x200]), | ||
192 | + 0x200); | ||
193 | + } else if (sector_num < s->offset_to_fat + s->sectors_per_fat) { | ||
194 | + memcpy(buf + i * 0x200, | ||
195 | + &(s->fat.pointer[(sector_num | ||
196 | + - s->offset_to_fat) * 0x200]), | ||
197 | + 0x200); | ||
198 | + } else if (sector_num < s->offset_to_root_dir) { | ||
199 | + memcpy(buf + i * 0x200, | ||
200 | + &(s->fat.pointer[(sector_num - s->offset_to_fat | ||
201 | + - s->sectors_per_fat) * 0x200]), | ||
202 | + 0x200); | ||
203 | + } | ||
204 | } else { | ||
205 | - uint32_t sector=sector_num-s->faked_sectors, | ||
206 | + uint32_t sector = sector_num - s->offset_to_root_dir, | ||
207 | sector_offset_in_cluster=(sector%s->sectors_per_cluster), | ||
208 | cluster_num=sector/s->sectors_per_cluster; | ||
209 | if(cluster_num > s->cluster_count || read_cluster(s, cluster_num) != 0) { | ||
210 | @@ -XXX,XX +XXX,XX @@ DLOG(checkpoint()); | ||
211 | memcpy(s->fat2, s->fat.pointer, size); | ||
212 | } | ||
213 | check = vvfat_read(s->bs, | ||
214 | - s->first_sectors_number, s->fat2, s->sectors_per_fat); | ||
215 | + s->offset_to_fat, s->fat2, s->sectors_per_fat); | ||
216 | if (check) { | ||
217 | fprintf(stderr, "Could not copy fat\n"); | ||
218 | return 0; | ||
219 | @@ -XXX,XX +XXX,XX @@ DLOG(checkpoint()); | ||
220 | * - do not allow to write non-ASCII filenames | ||
221 | */ | ||
222 | |||
223 | - if (sector_num < s->first_sectors_number) | ||
224 | + if (sector_num < s->offset_to_fat) | ||
225 | return -1; | ||
226 | |||
227 | for (i = sector2cluster(s, sector_num); | ||
228 | -- | 50 | -- |
229 | 1.8.3.1 | 51 | 2.37.3 |
230 | 52 | ||
231 | 53 | diff view generated by jsdifflib |
1 | From: Hervé Poussineau <hpoussin@reactos.org> | 1 | From: Marc-André Lureau <marcandre.lureau@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | More specifically: | 3 | Callers of coroutine_fn must be coroutine_fn themselves, or the call |
4 | - try without numeric-tail only if LFN didn't have invalid short chars | 4 | must be within "if (qemu_in_coroutine())". Apply coroutine_fn to |
5 | - start at ~1 (instead of ~0) | 5 | functions where this holds. |
6 | - handle case if numeric tail is more than one char (ie > 10) | ||
7 | 6 | ||
8 | Windows 9x Scandisk doesn't see anymore mismatches between short file names and | 7 | Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> |
9 | long file names for non-ASCII filenames. | 8 | Reviewed-by: Juan Quintela <quintela@redhat.com> |
10 | 9 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | |
11 | Specification: "FAT: General overview of on-disk format" v1.03, page 31 | 10 | Reviewed-by: Alberto Faria <afaria@redhat.com> |
12 | Signed-off-by: Hervé Poussineau <hpoussin@reactos.org> | 11 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
12 | Message-Id: <20220922084924.201610-26-pbonzini@redhat.com> | ||
13 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
13 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 14 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
14 | --- | 15 | --- |
15 | block/vvfat.c | 65 ++++++++++++++++++++++++++++------------------------------- | 16 | migration/migration.c | 3 ++- |
16 | 1 file changed, 31 insertions(+), 34 deletions(-) | 17 | 1 file changed, 2 insertions(+), 1 deletion(-) |
17 | 18 | ||
18 | diff --git a/block/vvfat.c b/block/vvfat.c | 19 | diff --git a/migration/migration.c b/migration/migration.c |
19 | index XXXXXXX..XXXXXXX 100644 | 20 | index XXXXXXX..XXXXXXX 100644 |
20 | --- a/block/vvfat.c | 21 | --- a/migration/migration.c |
21 | +++ b/block/vvfat.c | 22 | +++ b/migration/migration.c |
22 | @@ -XXX,XX +XXX,XX @@ static uint8_t to_valid_short_char(gunichar c) | 23 | @@ -XXX,XX +XXX,XX @@ static void process_incoming_migration_bh(void *opaque) |
24 | migration_incoming_state_destroy(); | ||
23 | } | 25 | } |
24 | 26 | ||
25 | static direntry_t *create_short_filename(BDRVVVFATState *s, | 27 | -static void process_incoming_migration_co(void *opaque) |
26 | - const char *filename) | 28 | +static void coroutine_fn |
27 | + const char *filename, | 29 | +process_incoming_migration_co(void *opaque) |
28 | + unsigned int directory_start) | ||
29 | { | 30 | { |
30 | - int j = 0; | 31 | MigrationIncomingState *mis = migration_incoming_get_current(); |
31 | + int i, j = 0; | 32 | PostcopyState ps; |
32 | direntry_t *entry = array_get_next(&(s->directory)); | ||
33 | const gchar *p, *last_dot = NULL; | ||
34 | gunichar c; | ||
35 | bool lossy_conversion = false; | ||
36 | + char tail[11]; | ||
37 | |||
38 | if (!entry) { | ||
39 | return NULL; | ||
40 | @@ -XXX,XX +XXX,XX @@ static direntry_t *create_short_filename(BDRVVVFATState *s, | ||
41 | } | ||
42 | } | ||
43 | } | ||
44 | - (void)lossy_conversion; | ||
45 | - return entry; | ||
46 | + | ||
47 | + /* numeric-tail generation */ | ||
48 | + for (j = 0; j < 8; j++) { | ||
49 | + if (entry->name[j] == ' ') { | ||
50 | + break; | ||
51 | + } | ||
52 | + } | ||
53 | + for (i = lossy_conversion ? 1 : 0; i < 999999; i++) { | ||
54 | + direntry_t *entry1; | ||
55 | + if (i > 0) { | ||
56 | + int len = sprintf(tail, "~%d", i); | ||
57 | + memcpy(entry->name + MIN(j, 8 - len), tail, len); | ||
58 | + } | ||
59 | + for (entry1 = array_get(&(s->directory), directory_start); | ||
60 | + entry1 < entry; entry1++) { | ||
61 | + if (!is_long_name(entry1) && | ||
62 | + !memcmp(entry1->name, entry->name, 11)) { | ||
63 | + break; /* found dupe */ | ||
64 | + } | ||
65 | + } | ||
66 | + if (entry1 == entry) { | ||
67 | + /* no dupe found */ | ||
68 | + return entry; | ||
69 | + } | ||
70 | + } | ||
71 | + return NULL; | ||
72 | } | ||
73 | |||
74 | /* fat functions */ | ||
75 | @@ -XXX,XX +XXX,XX @@ static inline direntry_t* create_short_and_long_name(BDRVVVFATState* s, | ||
76 | } | ||
77 | |||
78 | entry_long=create_long_filename(s,filename); | ||
79 | - entry = create_short_filename(s, filename); | ||
80 | - | ||
81 | - /* mangle duplicates */ | ||
82 | - while(1) { | ||
83 | - direntry_t* entry1=array_get(&(s->directory),directory_start); | ||
84 | - int j; | ||
85 | - | ||
86 | - for(;entry1<entry;entry1++) | ||
87 | - if(!is_long_name(entry1) && !memcmp(entry1->name,entry->name,11)) | ||
88 | - break; /* found dupe */ | ||
89 | - if(entry1==entry) /* no dupe found */ | ||
90 | - break; | ||
91 | - | ||
92 | - /* use all 8 characters of name */ | ||
93 | - if(entry->name[7]==' ') { | ||
94 | - int j; | ||
95 | - for(j=6;j>0 && entry->name[j]==' ';j--) | ||
96 | - entry->name[j]='~'; | ||
97 | - } | ||
98 | - | ||
99 | - /* increment number */ | ||
100 | - for(j=7;j>0 && entry->name[j]=='9';j--) | ||
101 | - entry->name[j]='0'; | ||
102 | - if(j>0) { | ||
103 | - if(entry->name[j]<'0' || entry->name[j]>'9') | ||
104 | - entry->name[j]='0'; | ||
105 | - else | ||
106 | - entry->name[j]++; | ||
107 | - } | ||
108 | - } | ||
109 | + entry = create_short_filename(s, filename, directory_start); | ||
110 | |||
111 | /* calculate checksum; propagate to long name */ | ||
112 | if(entry_long) { | ||
113 | -- | 33 | -- |
114 | 1.8.3.1 | 34 | 2.37.3 |
115 | 35 | ||
116 | 36 | diff view generated by jsdifflib |
1 | From: Eric Blake <eblake@redhat.com> | 1 | From: Marc-André Lureau <marcandre.lureau@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Without a passthrough status of BDRV_BLOCK_RAW, anything wrapped by | 3 | Callers of coroutine_fn must be coroutine_fn themselves, or the call |
4 | blkdebug appears 100% allocated as data. Better is treating it the | 4 | must be within "if (qemu_in_coroutine())". Apply coroutine_fn to |
5 | same as the underlying file being wrapped. | 5 | functions where this holds. |
6 | 6 | ||
7 | Update iotest 177 for the new expected output. | 7 | Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> |
8 | 8 | Reviewed-by: Alberto Faria <afaria@redhat.com> | |
9 | Signed-off-by: Eric Blake <eblake@redhat.com> | 9 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
10 | Reviewed-by: Fam Zheng <famz@redhat.com> | 10 | Message-Id: <20220922084924.201610-27-pbonzini@redhat.com> |
11 | Reviewed-by: Max Reitz <mreitz@redhat.com> | 11 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> |
12 | Reviewed-by: John Snow <jsnow@redhat.com> | ||
13 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
14 | --- | 13 | --- |
15 | block/blkdebug.c | 11 +++++++++++ | 14 | tests/unit/test-coroutine.c | 2 +- |
16 | tests/qemu-iotests/177.out | 5 ++++- | 15 | 1 file changed, 1 insertion(+), 1 deletion(-) |
17 | 2 files changed, 15 insertions(+), 1 deletion(-) | ||
18 | 16 | ||
19 | diff --git a/block/blkdebug.c b/block/blkdebug.c | 17 | diff --git a/tests/unit/test-coroutine.c b/tests/unit/test-coroutine.c |
20 | index XXXXXXX..XXXXXXX 100644 | 18 | index XXXXXXX..XXXXXXX 100644 |
21 | --- a/block/blkdebug.c | 19 | --- a/tests/unit/test-coroutine.c |
22 | +++ b/block/blkdebug.c | 20 | +++ b/tests/unit/test-coroutine.c |
23 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn blkdebug_co_pdiscard(BlockDriverState *bs, | 21 | @@ -XXX,XX +XXX,XX @@ static void perf_baseline(void) |
24 | return bdrv_co_pdiscard(bs->file->bs, offset, bytes); | 22 | g_test_message("Function call %u iterations: %f s", maxcycles, duration); |
25 | } | 23 | } |
26 | 24 | ||
27 | +static int64_t coroutine_fn blkdebug_co_get_block_status( | 25 | -static __attribute__((noinline)) void perf_cost_func(void *opaque) |
28 | + BlockDriverState *bs, int64_t sector_num, int nb_sectors, int *pnum, | 26 | +static __attribute__((noinline)) void coroutine_fn perf_cost_func(void *opaque) |
29 | + BlockDriverState **file) | ||
30 | +{ | ||
31 | + *pnum = nb_sectors; | ||
32 | + *file = bs->file->bs; | ||
33 | + return BDRV_BLOCK_RAW | BDRV_BLOCK_OFFSET_VALID | | ||
34 | + (sector_num << BDRV_SECTOR_BITS); | ||
35 | +} | ||
36 | + | ||
37 | static void blkdebug_close(BlockDriverState *bs) | ||
38 | { | 27 | { |
39 | BDRVBlkdebugState *s = bs->opaque; | 28 | qemu_coroutine_yield(); |
40 | @@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_blkdebug = { | 29 | } |
41 | .bdrv_co_flush_to_disk = blkdebug_co_flush, | ||
42 | .bdrv_co_pwrite_zeroes = blkdebug_co_pwrite_zeroes, | ||
43 | .bdrv_co_pdiscard = blkdebug_co_pdiscard, | ||
44 | + .bdrv_co_get_block_status = blkdebug_co_get_block_status, | ||
45 | |||
46 | .bdrv_debug_event = blkdebug_debug_event, | ||
47 | .bdrv_debug_breakpoint = blkdebug_debug_breakpoint, | ||
48 | diff --git a/tests/qemu-iotests/177.out b/tests/qemu-iotests/177.out | ||
49 | index XXXXXXX..XXXXXXX 100644 | ||
50 | --- a/tests/qemu-iotests/177.out | ||
51 | +++ b/tests/qemu-iotests/177.out | ||
52 | @@ -XXX,XX +XXX,XX @@ read 30408704/30408704 bytes at offset 80740352 | ||
53 | read 23068672/23068672 bytes at offset 111149056 | ||
54 | 22 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
55 | Offset Length File | ||
56 | -0 0x8000000 json:{"image": {"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/t.IMGFMT"}}, "driver": "blkdebug", "align": "4k"} | ||
57 | +0 0x800000 TEST_DIR/t.IMGFMT | ||
58 | +0x900000 0x2400000 TEST_DIR/t.IMGFMT | ||
59 | +0x3c00000 0x1100000 TEST_DIR/t.IMGFMT | ||
60 | +0x6a00000 0x1600000 TEST_DIR/t.IMGFMT | ||
61 | No errors were found on the image. | ||
62 | *** done | ||
63 | -- | 30 | -- |
64 | 1.8.3.1 | 31 | 2.37.3 |
65 | 32 | ||
66 | 33 | diff view generated by jsdifflib |
1 | From: Eric Blake <eblake@redhat.com> | 1 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
---|---|---|---|
2 | 2 | Message-Id: <20221006122607.162769-1-kwolf@redhat.com> | |
3 | We document that *file is valid if the return is not an error and | 3 | Reviewed-by: Peter Maydell <peter.maydell@linaro.org> |
4 | includes BDRV_BLOCK_OFFSET_VALID, but forgot to obey this contract | 4 | Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org> |
5 | when a driver (such as blkdebug) lacks a callback. Messed up in | ||
6 | commit 67a0fd2 (v2.6), when we added the file parameter. | ||
7 | |||
8 | Enhance qemu-iotest 177 to cover this, using a sequence that would | ||
9 | print garbage or even SEGV, because it was dererefencing through | ||
10 | uninitialized memory. [The resulting test output shows that we | ||
11 | have less-than-ideal block status from the blkdebug driver, but | ||
12 | that's a separate fix coming up soon.] | ||
13 | |||
14 | Setting *file on all paths that return BDRV_BLOCK_OFFSET_VALID is | ||
15 | enough to fix the crash, but we can go one step further: always | ||
16 | setting *file, even on error, means that a broken caller that | ||
17 | blindly dereferences file without checking for error is now more | ||
18 | likely to get a reliable SEGV instead of randomly acting on garbage, | ||
19 | making it easier to diagnose such buggy callers. Adding an | ||
20 | assertion that file is set where expected doesn't hurt either. | ||
21 | |||
22 | CC: qemu-stable@nongnu.org | ||
23 | Signed-off-by: Eric Blake <eblake@redhat.com> | ||
24 | Reviewed-by: Fam Zheng <famz@redhat.com> | ||
25 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
26 | Reviewed-by: John Snow <jsnow@redhat.com> | ||
27 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 5 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
28 | --- | 6 | --- |
29 | block/io.c | 5 +++-- | 7 | block/quorum.c | 2 -- |
30 | tests/qemu-iotests/177 | 3 +++ | 8 | 1 file changed, 2 deletions(-) |
31 | tests/qemu-iotests/177.out | 2 ++ | ||
32 | 3 files changed, 8 insertions(+), 2 deletions(-) | ||
33 | 9 | ||
34 | diff --git a/block/io.c b/block/io.c | 10 | diff --git a/block/quorum.c b/block/quorum.c |
35 | index XXXXXXX..XXXXXXX 100644 | 11 | index XXXXXXX..XXXXXXX 100644 |
36 | --- a/block/io.c | 12 | --- a/block/quorum.c |
37 | +++ b/block/io.c | 13 | +++ b/block/quorum.c |
38 | @@ -XXX,XX +XXX,XX @@ static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs, | 14 | @@ -XXX,XX +XXX,XX @@ static bool quorum_has_too_much_io_failed(QuorumAIOCB *acb) |
39 | int64_t n; | 15 | return false; |
40 | int64_t ret, ret2; | ||
41 | |||
42 | + *file = NULL; | ||
43 | total_sectors = bdrv_nb_sectors(bs); | ||
44 | if (total_sectors < 0) { | ||
45 | return total_sectors; | ||
46 | @@ -XXX,XX +XXX,XX @@ static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs, | ||
47 | } | ||
48 | if (bs->drv->protocol_name) { | ||
49 | ret |= BDRV_BLOCK_OFFSET_VALID | (sector_num * BDRV_SECTOR_SIZE); | ||
50 | + *file = bs; | ||
51 | } | ||
52 | return ret; | ||
53 | } | ||
54 | |||
55 | - *file = NULL; | ||
56 | bdrv_inc_in_flight(bs); | ||
57 | ret = bs->drv->bdrv_co_get_block_status(bs, sector_num, nb_sectors, pnum, | ||
58 | file); | ||
59 | @@ -XXX,XX +XXX,XX @@ static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs, | ||
60 | } | ||
61 | |||
62 | if (ret & BDRV_BLOCK_RAW) { | ||
63 | - assert(ret & BDRV_BLOCK_OFFSET_VALID); | ||
64 | + assert(ret & BDRV_BLOCK_OFFSET_VALID && *file); | ||
65 | ret = bdrv_co_get_block_status(*file, ret >> BDRV_SECTOR_BITS, | ||
66 | *pnum, pnum, file); | ||
67 | goto out; | ||
68 | diff --git a/tests/qemu-iotests/177 b/tests/qemu-iotests/177 | ||
69 | index XXXXXXX..XXXXXXX 100755 | ||
70 | --- a/tests/qemu-iotests/177 | ||
71 | +++ b/tests/qemu-iotests/177 | ||
72 | @@ -XXX,XX +XXX,XX @@ _supported_proto file | ||
73 | CLUSTER_SIZE=1M | ||
74 | size=128M | ||
75 | options=driver=blkdebug,image.driver=qcow2 | ||
76 | +nested_opts=image.file.driver=file,image.file.filename=$TEST_IMG | ||
77 | |||
78 | echo | ||
79 | echo "== setting up files ==" | ||
80 | @@ -XXX,XX +XXX,XX @@ function verify_io() | ||
81 | } | 16 | } |
82 | 17 | ||
83 | verify_io | $QEMU_IO -r "$TEST_IMG" | _filter_qemu_io | 18 | -static int read_fifo_child(QuorumAIOCB *acb); |
84 | +$QEMU_IMG map --image-opts "$options,$nested_opts,align=4k" \ | 19 | - |
85 | + | _filter_qemu_img_map | 20 | static void quorum_copy_qiov(QEMUIOVector *dest, QEMUIOVector *source) |
86 | 21 | { | |
87 | _check_test_img | 22 | int i; |
88 | |||
89 | diff --git a/tests/qemu-iotests/177.out b/tests/qemu-iotests/177.out | ||
90 | index XXXXXXX..XXXXXXX 100644 | ||
91 | --- a/tests/qemu-iotests/177.out | ||
92 | +++ b/tests/qemu-iotests/177.out | ||
93 | @@ -XXX,XX +XXX,XX @@ read 30408704/30408704 bytes at offset 80740352 | ||
94 | 29 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
95 | read 23068672/23068672 bytes at offset 111149056 | ||
96 | 22 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
97 | +Offset Length File | ||
98 | +0 0x8000000 json:{"image": {"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/t.IMGFMT"}}, "driver": "blkdebug", "align": "4k"} | ||
99 | No errors were found on the image. | ||
100 | *** done | ||
101 | -- | 23 | -- |
102 | 1.8.3.1 | 24 | 2.37.3 |
103 | 25 | ||
104 | 26 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Hervé Poussineau <hpoussin@reactos.org> | ||
2 | 1 | ||
3 | - bs->total_sectors is the number of sectors of the whole disk | ||
4 | - s->sector_count is the number of sectors of the FAT partition | ||
5 | |||
6 | This fixes the following assert in qemu-img map: | ||
7 | qemu-img.c:2641: get_block_status: Assertion `nb_sectors' failed. | ||
8 | |||
9 | This also fixes an infinite loop in qemu-img convert. | ||
10 | |||
11 | Fixes: 4480e0f924a42e1db8b8cfcac4d0634dd1bb27a0 | ||
12 | Fixes: https://bugs.launchpad.net/qemu/+bug/1599539 | ||
13 | Cc: qemu-stable@nongnu.org | ||
14 | Signed-off-by: Hervé Poussineau <hpoussin@reactos.org> | ||
15 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
16 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
17 | --- | ||
18 | block/vvfat.c | 3 +-- | ||
19 | 1 file changed, 1 insertion(+), 2 deletions(-) | ||
20 | |||
21 | diff --git a/block/vvfat.c b/block/vvfat.c | ||
22 | index XXXXXXX..XXXXXXX 100644 | ||
23 | --- a/block/vvfat.c | ||
24 | +++ b/block/vvfat.c | ||
25 | @@ -XXX,XX +XXX,XX @@ vvfat_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes, | ||
26 | static int64_t coroutine_fn vvfat_co_get_block_status(BlockDriverState *bs, | ||
27 | int64_t sector_num, int nb_sectors, int *n, BlockDriverState **file) | ||
28 | { | ||
29 | - BDRVVVFATState* s = bs->opaque; | ||
30 | - *n = s->sector_count - sector_num; | ||
31 | + *n = bs->total_sectors - sector_num; | ||
32 | if (*n > nb_sectors) { | ||
33 | *n = nb_sectors; | ||
34 | } else if (*n < 0) { | ||
35 | -- | ||
36 | 1.8.3.1 | ||
37 | |||
38 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Hervé Poussineau <hpoussin@reactos.org> | ||
2 | 1 | ||
3 | Signed-off-by: Hervé Poussineau <hpoussin@reactos.org> | ||
4 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
5 | --- | ||
6 | block/vvfat.c | 8 ++++---- | ||
7 | 1 file changed, 4 insertions(+), 4 deletions(-) | ||
8 | |||
9 | diff --git a/block/vvfat.c b/block/vvfat.c | ||
10 | index XXXXXXX..XXXXXXX 100644 | ||
11 | --- a/block/vvfat.c | ||
12 | +++ b/block/vvfat.c | ||
13 | @@ -XXX,XX +XXX,XX @@ static void init_mbr(BDRVVVFATState *s, int cyls, int heads, int secs) | ||
14 | /* FAT12/FAT16/FAT32 */ | ||
15 | /* DOS uses different types when partition is LBA, | ||
16 | probably to prevent older versions from using CHS on them */ | ||
17 | - partition->fs_type= s->fat_type==12 ? 0x1: | ||
18 | - s->fat_type==16 ? (lba?0xe:0x06): | ||
19 | - /*fat_tyoe==32*/ (lba?0xc:0x0b); | ||
20 | + partition->fs_type = s->fat_type == 12 ? 0x1 : | ||
21 | + s->fat_type == 16 ? (lba ? 0xe : 0x06) : | ||
22 | + /*s->fat_type == 32*/ (lba ? 0xc : 0x0b); | ||
23 | |||
24 | real_mbr->magic[0]=0x55; real_mbr->magic[1]=0xaa; | ||
25 | } | ||
26 | @@ -XXX,XX +XXX,XX @@ static int read_directory(BDRVVVFATState* s, int mapping_index) | ||
27 | (ROOT_ENTRIES - cur) * sizeof(direntry_t)); | ||
28 | } | ||
29 | |||
30 | - /* reget the mapping, since s->mapping was possibly realloc()ed */ | ||
31 | + /* re-get the mapping, since s->mapping was possibly realloc()ed */ | ||
32 | mapping = array_get(&(s->mapping), mapping_index); | ||
33 | first_cluster += (s->directory.next - mapping->info.dir.first_dir_index) | ||
34 | * 0x20 / s->cluster_size; | ||
35 | -- | ||
36 | 1.8.3.1 | ||
37 | |||
38 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Hervé Poussineau <hpoussin@reactos.org> | ||
2 | 1 | ||
3 | Specification: "FAT: General overview of on-disk format" v1.03, pages 11-13 | ||
4 | Signed-off-by: Hervé Poussineau <hpoussin@reactos.org> | ||
5 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
6 | --- | ||
7 | block/vvfat.c | 21 ++++++++++++++------- | ||
8 | 1 file changed, 14 insertions(+), 7 deletions(-) | ||
9 | |||
10 | diff --git a/block/vvfat.c b/block/vvfat.c | ||
11 | index XXXXXXX..XXXXXXX 100644 | ||
12 | --- a/block/vvfat.c | ||
13 | +++ b/block/vvfat.c | ||
14 | @@ -XXX,XX +XXX,XX @@ typedef struct bootsector_t { | ||
15 | union { | ||
16 | struct { | ||
17 | uint8_t drive_number; | ||
18 | - uint8_t current_head; | ||
19 | + uint8_t reserved1; | ||
20 | uint8_t signature; | ||
21 | uint32_t id; | ||
22 | uint8_t volume_label[11]; | ||
23 | + uint8_t fat_type[8]; | ||
24 | + uint8_t ignored[0x1c0]; | ||
25 | } QEMU_PACKED fat16; | ||
26 | struct { | ||
27 | uint32_t sectors_per_fat; | ||
28 | uint16_t flags; | ||
29 | uint8_t major,minor; | ||
30 | - uint32_t first_cluster_of_root_directory; | ||
31 | + uint32_t first_cluster_of_root_dir; | ||
32 | uint16_t info_sector; | ||
33 | uint16_t backup_boot_sector; | ||
34 | - uint16_t ignored; | ||
35 | + uint8_t reserved[12]; | ||
36 | + uint8_t drive_number; | ||
37 | + uint8_t reserved1; | ||
38 | + uint8_t signature; | ||
39 | + uint32_t id; | ||
40 | + uint8_t volume_label[11]; | ||
41 | + uint8_t fat_type[8]; | ||
42 | + uint8_t ignored[0x1a4]; | ||
43 | } QEMU_PACKED fat32; | ||
44 | } u; | ||
45 | - uint8_t fat_type[8]; | ||
46 | - uint8_t ignored[0x1c0]; | ||
47 | uint8_t magic[2]; | ||
48 | } QEMU_PACKED bootsector_t; | ||
49 | |||
50 | @@ -XXX,XX +XXX,XX @@ static int init_directories(BDRVVVFATState* s, | ||
51 | /* LATER TODO: if FAT32, this is wrong */ | ||
52 | /* drive_number: fda=0, hda=0x80 */ | ||
53 | bootsector->u.fat16.drive_number = s->offset_to_bootsector == 0 ? 0 : 0x80; | ||
54 | - bootsector->u.fat16.current_head=0; | ||
55 | bootsector->u.fat16.signature=0x29; | ||
56 | bootsector->u.fat16.id=cpu_to_le32(0xfabe1afd); | ||
57 | |||
58 | memcpy(bootsector->u.fat16.volume_label, s->volume_label, | ||
59 | sizeof(bootsector->u.fat16.volume_label)); | ||
60 | - memcpy(bootsector->fat_type,(s->fat_type==12?"FAT12 ":s->fat_type==16?"FAT16 ":"FAT32 "),8); | ||
61 | + memcpy(bootsector->u.fat16.fat_type, | ||
62 | + s->fat_type == 12 ? "FAT12 " : "FAT16 ", 8); | ||
63 | bootsector->magic[0]=0x55; bootsector->magic[1]=0xaa; | ||
64 | |||
65 | return 0; | ||
66 | -- | ||
67 | 1.8.3.1 | ||
68 | |||
69 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Hervé Poussineau <hpoussin@reactos.org> | ||
2 | 1 | ||
3 | readdir() doesn't always return . and .. entries at first and in that order. | ||
4 | This leads to not creating them at first in the directory, which raises some | ||
5 | errors on file system checking utilities like MS-DOS Scandisk. | ||
6 | |||
7 | Specification: "FAT: General overview of on-disk format" v1.03, page 25 | ||
8 | |||
9 | Fixes: https://bugs.launchpad.net/qemu/+bug/1599539 | ||
10 | Signed-off-by: Hervé Poussineau <hpoussin@reactos.org> | ||
11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
12 | --- | ||
13 | block/vvfat.c | 13 +++++++++++-- | ||
14 | 1 file changed, 11 insertions(+), 2 deletions(-) | ||
15 | |||
16 | diff --git a/block/vvfat.c b/block/vvfat.c | ||
17 | index XXXXXXX..XXXXXXX 100644 | ||
18 | --- a/block/vvfat.c | ||
19 | +++ b/block/vvfat.c | ||
20 | @@ -XXX,XX +XXX,XX @@ static int read_directory(BDRVVVFATState* s, int mapping_index) | ||
21 | i = mapping->info.dir.first_dir_index = | ||
22 | first_cluster == 0 ? 0 : s->directory.next; | ||
23 | |||
24 | + if (first_cluster != 0) { | ||
25 | + /* create the top entries of a subdirectory */ | ||
26 | + (void)create_short_and_long_name(s, i, ".", 1); | ||
27 | + (void)create_short_and_long_name(s, i, "..", 1); | ||
28 | + } | ||
29 | + | ||
30 | /* actually read the directory, and allocate the mappings */ | ||
31 | while((entry=readdir(dir))) { | ||
32 | unsigned int length=strlen(dirname)+2+strlen(entry->d_name); | ||
33 | @@ -XXX,XX +XXX,XX @@ static int read_directory(BDRVVVFATState* s, int mapping_index) | ||
34 | } | ||
35 | |||
36 | /* create directory entry for this file */ | ||
37 | - direntry=create_short_and_long_name(s, i, entry->d_name, | ||
38 | - is_dot || is_dotdot); | ||
39 | + if (!is_dot && !is_dotdot) { | ||
40 | + direntry = create_short_and_long_name(s, i, entry->d_name, 0); | ||
41 | + } else { | ||
42 | + direntry = array_get(&(s->directory), is_dot ? i : i + 1); | ||
43 | + } | ||
44 | direntry->attributes=(S_ISDIR(st.st_mode)?0x10:0x20); | ||
45 | direntry->reserved[0]=direntry->reserved[1]=0; | ||
46 | direntry->ctime=fat_datetime(st.st_ctime,1); | ||
47 | -- | ||
48 | 1.8.3.1 | ||
49 | |||
50 | diff view generated by jsdifflib |
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | It will be needed in following commits for persistent bitmaps. | 3 | job mutex will be used to protect the job struct elements and list, |
4 | If bitmap is loaded from read-only storage (and we can't mark it | 4 | replacing AioContext locks. |
5 | "in use" in this storage) corresponding BdrvDirtyBitmap should be | ||
6 | read-only. | ||
7 | 5 | ||
8 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 6 | Right now use a shared lock for all jobs, in order to keep things |
9 | Message-id: 20170628120530.31251-11-vsementsov@virtuozzo.com | 7 | simple. Once the AioContext lock is gone, we can introduce per-job |
10 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 8 | locks. |
9 | |||
10 | To simplify the switch from aiocontext to job lock, introduce | ||
11 | *nop* lock/unlock functions and macros. | ||
12 | We want to always call job_lock/unlock outside the AioContext locks, | ||
13 | and not vice-versa, otherwise we might get a deadlock. This is not | ||
14 | straightforward to do, and that's why we start with nop functions. | ||
15 | Once everything is protected by job_lock/unlock, we can change the nop into | ||
16 | an actual mutex and remove the aiocontext lock. | ||
17 | |||
18 | Since job_mutex is already being used, add static | ||
19 | real_job_{lock/unlock} for the existing usage. | ||
20 | |||
21 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
22 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
23 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> | ||
24 | Message-Id: <20220926093214.506243-2-eesposit@redhat.com> | ||
25 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
11 | --- | 26 | --- |
12 | block/dirty-bitmap.c | 36 ++++++++++++++++++++++++++++++++++++ | 27 | include/qemu/job.h | 24 ++++++++++++++++++++++++ |
13 | block/io.c | 8 ++++++++ | 28 | job.c | 35 +++++++++++++++++++++++------------ |
14 | blockdev.c | 6 ++++++ | 29 | 2 files changed, 47 insertions(+), 12 deletions(-) |
15 | include/block/dirty-bitmap.h | 4 ++++ | ||
16 | 4 files changed, 54 insertions(+) | ||
17 | 30 | ||
18 | diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c | 31 | diff --git a/include/qemu/job.h b/include/qemu/job.h |
19 | index XXXXXXX..XXXXXXX 100644 | 32 | index XXXXXXX..XXXXXXX 100644 |
20 | --- a/block/dirty-bitmap.c | 33 | --- a/include/qemu/job.h |
21 | +++ b/block/dirty-bitmap.c | 34 | +++ b/include/qemu/job.h |
22 | @@ -XXX,XX +XXX,XX @@ struct BdrvDirtyBitmap { | 35 | @@ -XXX,XX +XXX,XX @@ typedef enum JobCreateFlags { |
23 | bool disabled; /* Bitmap is disabled. It ignores all writes to | 36 | JOB_MANUAL_DISMISS = 0x04, |
24 | the device */ | 37 | } JobCreateFlags; |
25 | int active_iterators; /* How many iterators are active */ | 38 | |
26 | + bool readonly; /* Bitmap is read-only. This field also | 39 | +extern QemuMutex job_mutex; |
27 | + prevents the respective image from being | 40 | + |
28 | + modified (i.e. blocks writes and discards). | 41 | +#define JOB_LOCK_GUARD() /* QEMU_LOCK_GUARD(&job_mutex) */ |
29 | + Such operations must fail and both the image | 42 | + |
30 | + and this bitmap must remain unchanged while | 43 | +#define WITH_JOB_LOCK_GUARD() /* WITH_QEMU_LOCK_GUARD(&job_mutex) */ |
31 | + this flag is set. */ | 44 | + |
32 | QLIST_ENTRY(BdrvDirtyBitmap) list; | 45 | +/** |
46 | + * job_lock: | ||
47 | + * | ||
48 | + * Take the mutex protecting the list of jobs and their status. | ||
49 | + * Most functions called by the monitor need to call job_lock | ||
50 | + * and job_unlock manually. On the other hand, function called | ||
51 | + * by the block jobs themselves and by the block layer will take the | ||
52 | + * lock for you. | ||
53 | + */ | ||
54 | +void job_lock(void); | ||
55 | + | ||
56 | +/** | ||
57 | + * job_unlock: | ||
58 | + * | ||
59 | + * Release the mutex protecting the list of jobs and their status. | ||
60 | + */ | ||
61 | +void job_unlock(void); | ||
62 | + | ||
63 | /** | ||
64 | * Allocate and return a new job transaction. Jobs can be added to the | ||
65 | * transaction using job_txn_add_job(). | ||
66 | diff --git a/job.c b/job.c | ||
67 | index XXXXXXX..XXXXXXX 100644 | ||
68 | --- a/job.c | ||
69 | +++ b/job.c | ||
70 | @@ -XXX,XX +XXX,XX @@ | ||
71 | #include "trace/trace-root.h" | ||
72 | #include "qapi/qapi-events-job.h" | ||
73 | |||
74 | +/* | ||
75 | + * job_mutex protects the jobs list, but also makes the | ||
76 | + * struct job fields thread-safe. | ||
77 | + */ | ||
78 | +QemuMutex job_mutex; | ||
79 | + | ||
80 | static QLIST_HEAD(, Job) jobs = QLIST_HEAD_INITIALIZER(jobs); | ||
81 | |||
82 | /* Job State Transition Table */ | ||
83 | @@ -XXX,XX +XXX,XX @@ struct JobTxn { | ||
84 | int refcnt; | ||
33 | }; | 85 | }; |
34 | 86 | ||
35 | @@ -XXX,XX +XXX,XX @@ void bdrv_set_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap, | 87 | -/* Right now, this mutex is only needed to synchronize accesses to job->busy |
36 | int64_t cur_sector, int64_t nr_sectors) | 88 | - * and job->sleep_timer, such as concurrent calls to job_do_yield and |
37 | { | 89 | - * job_enter. */ |
38 | assert(bdrv_dirty_bitmap_enabled(bitmap)); | 90 | -static QemuMutex job_mutex; |
39 | + assert(!bdrv_dirty_bitmap_readonly(bitmap)); | 91 | +void job_lock(void) |
40 | hbitmap_set(bitmap->bitmap, cur_sector, nr_sectors); | ||
41 | } | ||
42 | |||
43 | @@ -XXX,XX +XXX,XX @@ void bdrv_reset_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap, | ||
44 | int64_t cur_sector, int64_t nr_sectors) | ||
45 | { | ||
46 | assert(bdrv_dirty_bitmap_enabled(bitmap)); | ||
47 | + assert(!bdrv_dirty_bitmap_readonly(bitmap)); | ||
48 | hbitmap_reset(bitmap->bitmap, cur_sector, nr_sectors); | ||
49 | } | ||
50 | |||
51 | @@ -XXX,XX +XXX,XX @@ void bdrv_reset_dirty_bitmap(BdrvDirtyBitmap *bitmap, | ||
52 | void bdrv_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap **out) | ||
53 | { | ||
54 | assert(bdrv_dirty_bitmap_enabled(bitmap)); | ||
55 | + assert(!bdrv_dirty_bitmap_readonly(bitmap)); | ||
56 | bdrv_dirty_bitmap_lock(bitmap); | ||
57 | if (!out) { | ||
58 | hbitmap_reset_all(bitmap->bitmap); | ||
59 | @@ -XXX,XX +XXX,XX @@ void bdrv_undo_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap *in) | ||
60 | { | ||
61 | HBitmap *tmp = bitmap->bitmap; | ||
62 | assert(bdrv_dirty_bitmap_enabled(bitmap)); | ||
63 | + assert(!bdrv_dirty_bitmap_readonly(bitmap)); | ||
64 | bitmap->bitmap = in; | ||
65 | hbitmap_free(tmp); | ||
66 | } | ||
67 | @@ -XXX,XX +XXX,XX @@ void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector, | ||
68 | if (!bdrv_dirty_bitmap_enabled(bitmap)) { | ||
69 | continue; | ||
70 | } | ||
71 | + assert(!bdrv_dirty_bitmap_readonly(bitmap)); | ||
72 | hbitmap_set(bitmap->bitmap, cur_sector, nr_sectors); | ||
73 | } | ||
74 | bdrv_dirty_bitmaps_unlock(bs); | ||
75 | @@ -XXX,XX +XXX,XX @@ int64_t bdrv_get_meta_dirty_count(BdrvDirtyBitmap *bitmap) | ||
76 | { | ||
77 | return hbitmap_count(bitmap->meta); | ||
78 | } | ||
79 | + | ||
80 | +bool bdrv_dirty_bitmap_readonly(const BdrvDirtyBitmap *bitmap) | ||
81 | +{ | 92 | +{ |
82 | + return bitmap->readonly; | 93 | + /* nop */ |
83 | +} | 94 | +} |
84 | + | 95 | + |
85 | +/* Called with BQL taken. */ | 96 | +void job_unlock(void) |
86 | +void bdrv_dirty_bitmap_set_readonly(BdrvDirtyBitmap *bitmap, bool value) | ||
87 | +{ | 97 | +{ |
88 | + qemu_mutex_lock(bitmap->mutex); | 98 | + /* nop */ |
89 | + bitmap->readonly = value; | ||
90 | + qemu_mutex_unlock(bitmap->mutex); | ||
91 | +} | 99 | +} |
92 | + | 100 | |
93 | +bool bdrv_has_readonly_bitmaps(BlockDriverState *bs) | 101 | -static void job_lock(void) |
94 | +{ | 102 | +static void real_job_lock(void) |
95 | + BdrvDirtyBitmap *bm; | 103 | { |
96 | + QLIST_FOREACH(bm, &bs->dirty_bitmaps, list) { | 104 | qemu_mutex_lock(&job_mutex); |
97 | + if (bm->readonly) { | 105 | } |
98 | + return true; | 106 | |
99 | + } | 107 | -static void job_unlock(void) |
100 | + } | 108 | +static void real_job_unlock(void) |
101 | + | 109 | { |
102 | + return false; | 110 | qemu_mutex_unlock(&job_mutex); |
103 | +} | 111 | } |
104 | diff --git a/block/io.c b/block/io.c | 112 | @@ -XXX,XX +XXX,XX @@ void job_enter_cond(Job *job, bool(*fn)(Job *job)) |
105 | index XXXXXXX..XXXXXXX 100644 | 113 | return; |
106 | --- a/block/io.c | ||
107 | +++ b/block/io.c | ||
108 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child, | ||
109 | uint64_t bytes_remaining = bytes; | ||
110 | int max_transfer; | ||
111 | |||
112 | + if (bdrv_has_readonly_bitmaps(bs)) { | ||
113 | + return -EPERM; | ||
114 | + } | ||
115 | + | ||
116 | assert(is_power_of_2(align)); | ||
117 | assert((offset & (align - 1)) == 0); | ||
118 | assert((bytes & (align - 1)) == 0); | ||
119 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_pdiscard(BlockDriverState *bs, int64_t offset, | ||
120 | return -ENOMEDIUM; | ||
121 | } | 114 | } |
122 | 115 | ||
123 | + if (bdrv_has_readonly_bitmaps(bs)) { | 116 | - job_lock(); |
124 | + return -EPERM; | 117 | + real_job_lock(); |
125 | + } | 118 | if (job->busy) { |
126 | + | 119 | - job_unlock(); |
127 | ret = bdrv_check_byte_request(bs, offset, bytes); | 120 | + real_job_unlock(); |
128 | if (ret < 0) { | ||
129 | return ret; | ||
130 | diff --git a/blockdev.c b/blockdev.c | ||
131 | index XXXXXXX..XXXXXXX 100644 | ||
132 | --- a/blockdev.c | ||
133 | +++ b/blockdev.c | ||
134 | @@ -XXX,XX +XXX,XX @@ static void block_dirty_bitmap_clear_prepare(BlkActionState *common, | ||
135 | } else if (!bdrv_dirty_bitmap_enabled(state->bitmap)) { | ||
136 | error_setg(errp, "Cannot clear a disabled bitmap"); | ||
137 | return; | 121 | return; |
138 | + } else if (bdrv_dirty_bitmap_readonly(state->bitmap)) { | ||
139 | + error_setg(errp, "Cannot clear a readonly bitmap"); | ||
140 | + return; | ||
141 | } | 122 | } |
142 | 123 | ||
143 | bdrv_clear_dirty_bitmap(state->bitmap, &state->backup); | 124 | if (fn && !fn(job)) { |
144 | @@ -XXX,XX +XXX,XX @@ void qmp_block_dirty_bitmap_clear(const char *node, const char *name, | 125 | - job_unlock(); |
145 | "Bitmap '%s' is currently disabled and cannot be cleared", | 126 | + real_job_unlock(); |
146 | name); | ||
147 | return; | 127 | return; |
148 | + } else if (bdrv_dirty_bitmap_readonly(bitmap)) { | ||
149 | + error_setg(errp, "Bitmap '%s' is readonly and cannot be cleared", name); | ||
150 | + return; | ||
151 | } | 128 | } |
152 | 129 | ||
153 | bdrv_clear_dirty_bitmap(bitmap, NULL); | 130 | assert(!job->deferred_to_main_loop); |
154 | diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h | 131 | timer_del(&job->sleep_timer); |
155 | index XXXXXXX..XXXXXXX 100644 | 132 | job->busy = true; |
156 | --- a/include/block/dirty-bitmap.h | 133 | - job_unlock(); |
157 | +++ b/include/block/dirty-bitmap.h | 134 | + real_job_unlock(); |
158 | @@ -XXX,XX +XXX,XX @@ void bdrv_dirty_bitmap_deserialize_ones(BdrvDirtyBitmap *bitmap, | 135 | aio_co_enter(job->aio_context, job->co); |
159 | bool finish); | 136 | } |
160 | void bdrv_dirty_bitmap_deserialize_finish(BdrvDirtyBitmap *bitmap); | 137 | |
161 | 138 | @@ -XXX,XX +XXX,XX @@ void job_enter(Job *job) | |
162 | +void bdrv_dirty_bitmap_set_readonly(BdrvDirtyBitmap *bitmap, bool value); | 139 | * called explicitly. */ |
163 | + | 140 | static void coroutine_fn job_do_yield(Job *job, uint64_t ns) |
164 | /* Functions that require manual locking. */ | 141 | { |
165 | void bdrv_dirty_bitmap_lock(BdrvDirtyBitmap *bitmap); | 142 | - job_lock(); |
166 | void bdrv_dirty_bitmap_unlock(BdrvDirtyBitmap *bitmap); | 143 | + real_job_lock(); |
167 | @@ -XXX,XX +XXX,XX @@ void bdrv_set_dirty_iter(BdrvDirtyBitmapIter *hbi, int64_t sector_num); | 144 | if (ns != -1) { |
168 | int64_t bdrv_get_dirty_count(BdrvDirtyBitmap *bitmap); | 145 | timer_mod(&job->sleep_timer, ns); |
169 | int64_t bdrv_get_meta_dirty_count(BdrvDirtyBitmap *bitmap); | 146 | } |
170 | void bdrv_dirty_bitmap_truncate(BlockDriverState *bs); | 147 | job->busy = false; |
171 | +bool bdrv_dirty_bitmap_readonly(const BdrvDirtyBitmap *bitmap); | 148 | job_event_idle(job); |
172 | +bool bdrv_has_readonly_bitmaps(BlockDriverState *bs); | 149 | - job_unlock(); |
173 | 150 | + real_job_unlock(); | |
174 | #endif | 151 | qemu_coroutine_yield(); |
152 | |||
153 | /* Set by job_enter_cond() before re-entering the coroutine. */ | ||
175 | -- | 154 | -- |
176 | 1.8.3.1 | 155 | 2.37.3 |
177 | |||
178 | diff view generated by jsdifflib |
1 | From: Hervé Poussineau <hpoussin@reactos.org> | 1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Assume that input filename is encoded as UTF-8, so correctly create UTF-16 encoding. | 3 | Categorize the fields in struct Job to understand which ones |
4 | need to be protected by the job mutex and which don't. | ||
4 | 5 | ||
5 | Signed-off-by: Hervé Poussineau <hpoussin@reactos.org> | 6 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
7 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> | ||
8 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
9 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
10 | Message-Id: <20220926093214.506243-3-eesposit@redhat.com> | ||
6 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
7 | --- | 12 | --- |
8 | block/vvfat.c | 38 ++++++++++++++++++-------------------- | 13 | include/qemu/job.h | 61 +++++++++++++++++++++++++++------------------- |
9 | 1 file changed, 18 insertions(+), 20 deletions(-) | 14 | 1 file changed, 36 insertions(+), 25 deletions(-) |
10 | 15 | ||
11 | diff --git a/block/vvfat.c b/block/vvfat.c | 16 | diff --git a/include/qemu/job.h b/include/qemu/job.h |
12 | index XXXXXXX..XXXXXXX 100644 | 17 | index XXXXXXX..XXXXXXX 100644 |
13 | --- a/block/vvfat.c | 18 | --- a/include/qemu/job.h |
14 | +++ b/block/vvfat.c | 19 | +++ b/include/qemu/job.h |
15 | @@ -XXX,XX +XXX,XX @@ static void init_mbr(BDRVVVFATState *s, int cyls, int heads, int secs) | 20 | @@ -XXX,XX +XXX,XX @@ typedef struct JobTxn JobTxn; |
16 | 21 | * Long-running operation. | |
17 | /* direntry functions */ | 22 | */ |
18 | 23 | typedef struct Job { | |
19 | -/* dest is assumed to hold 258 bytes, and pads with 0xffff up to next multiple of 26 */ | ||
20 | -static inline int short2long_name(char* dest,const char* src) | ||
21 | +static direntry_t *create_long_filename(BDRVVVFATState *s, const char *filename) | ||
22 | { | ||
23 | - int i; | ||
24 | - int len; | ||
25 | - for(i=0;i<129 && src[i];i++) { | ||
26 | - dest[2*i]=src[i]; | ||
27 | - dest[2*i+1]=0; | ||
28 | + int number_of_entries, i; | ||
29 | + glong length; | ||
30 | + direntry_t *entry; | ||
31 | + | 24 | + |
32 | + gunichar2 *longname = g_utf8_to_utf16(filename, -1, NULL, &length, NULL); | 25 | + /* Fields set at initialization (job_create), and never modified */ |
33 | + if (!longname) { | 26 | + |
34 | + fprintf(stderr, "vvfat: invalid UTF-8 name: %s\n", filename); | 27 | /** The ID of the job. May be NULL for internal jobs. */ |
35 | + return NULL; | 28 | char *id; |
36 | } | 29 | |
37 | - len=2*i; | 30 | - /** The type of this job. */ |
38 | - dest[2*i]=dest[2*i+1]=0; | 31 | + /** |
39 | - for(i=2*i+2;(i%26);i++) | 32 | + * The type of this job. |
40 | - dest[i]=0xff; | 33 | + * All callbacks are called with job_mutex *not* held. |
41 | - return len; | 34 | + */ |
42 | -} | 35 | const JobDriver *driver; |
43 | 36 | ||
44 | -static inline direntry_t* create_long_filename(BDRVVVFATState* s,const char* filename) | 37 | - /** Reference count of the block job */ |
45 | -{ | 38 | - int refcnt; |
46 | - char buffer[258]; | 39 | - |
47 | - int length=short2long_name(buffer,filename), | 40 | - /** Current state; See @JobStatus for details. */ |
48 | - number_of_entries=(length+25)/26,i; | 41 | - JobStatus status; |
49 | - direntry_t* entry; | 42 | - |
50 | + number_of_entries = (length * 2 + 25) / 26; | 43 | - /** AioContext to run the job coroutine in */ |
51 | 44 | - AioContext *aio_context; | |
52 | for(i=0;i<number_of_entries;i++) { | 45 | - |
53 | entry=array_get_next(&(s->directory)); | 46 | /** |
54 | @@ -XXX,XX +XXX,XX @@ static inline direntry_t* create_long_filename(BDRVVVFATState* s,const char* fil | 47 | * The coroutine that executes the job. If not NULL, it is reentered when |
55 | else if(offset<22) offset=14+offset-10; | 48 | * busy is false and the job is cancelled. |
56 | else offset=28+offset-22; | 49 | + * Initialized in job_start() |
57 | entry=array_get(&(s->directory),s->directory.next-1-(i/26)); | 50 | */ |
58 | - entry->name[offset]=buffer[i]; | 51 | Coroutine *co; |
59 | + if (i >= 2 * length + 2) { | 52 | |
60 | + entry->name[offset] = 0xff; | 53 | + /** True if this job should automatically finalize itself */ |
61 | + } else if (i % 2 == 0) { | 54 | + bool auto_finalize; |
62 | + entry->name[offset] = longname[i / 2] & 0xff; | 55 | + |
63 | + } else { | 56 | + /** True if this job should automatically dismiss itself */ |
64 | + entry->name[offset] = longname[i / 2] >> 8; | 57 | + bool auto_dismiss; |
65 | + } | 58 | + |
66 | } | 59 | + /** The completion function that will be called when the job completes. */ |
67 | + g_free(longname); | 60 | + BlockCompletionFunc *cb; |
68 | return array_get(&(s->directory),s->directory.next-number_of_entries); | 61 | + |
69 | } | 62 | + /** The opaque value that is passed to the completion function. */ |
63 | + void *opaque; | ||
64 | + | ||
65 | + /* ProgressMeter API is thread-safe */ | ||
66 | + ProgressMeter progress; | ||
67 | + | ||
68 | + | ||
69 | + /** Protected by AioContext lock */ | ||
70 | + | ||
71 | + /** AioContext to run the job coroutine in */ | ||
72 | + AioContext *aio_context; | ||
73 | + | ||
74 | + /** Reference count of the block job */ | ||
75 | + int refcnt; | ||
76 | + | ||
77 | + /** Current state; See @JobStatus for details. */ | ||
78 | + JobStatus status; | ||
79 | + | ||
80 | /** | ||
81 | * Timer that is used by @job_sleep_ns. Accessed under job_mutex (in | ||
82 | * job.c). | ||
83 | @@ -XXX,XX +XXX,XX @@ typedef struct Job { | ||
84 | /** Set to true when the job has deferred work to the main loop. */ | ||
85 | bool deferred_to_main_loop; | ||
86 | |||
87 | - /** True if this job should automatically finalize itself */ | ||
88 | - bool auto_finalize; | ||
89 | - | ||
90 | - /** True if this job should automatically dismiss itself */ | ||
91 | - bool auto_dismiss; | ||
92 | - | ||
93 | - ProgressMeter progress; | ||
94 | - | ||
95 | /** | ||
96 | * Return code from @run and/or @prepare callback(s). | ||
97 | * Not final until the job has reached the CONCLUDED status. | ||
98 | @@ -XXX,XX +XXX,XX @@ typedef struct Job { | ||
99 | */ | ||
100 | Error *err; | ||
101 | |||
102 | - /** The completion function that will be called when the job completes. */ | ||
103 | - BlockCompletionFunc *cb; | ||
104 | - | ||
105 | - /** The opaque value that is passed to the completion function. */ | ||
106 | - void *opaque; | ||
107 | - | ||
108 | /** Notifiers called when a cancelled job is finalised */ | ||
109 | NotifierList on_finalize_cancelled; | ||
110 | |||
111 | @@ -XXX,XX +XXX,XX @@ typedef struct Job { | ||
112 | |||
113 | /** | ||
114 | * Callbacks and other information about a Job driver. | ||
115 | + * All callbacks are invoked with job_mutex *not* held. | ||
116 | */ | ||
117 | struct JobDriver { | ||
118 | |||
119 | @@ -XXX,XX +XXX,XX @@ void coroutine_fn job_yield(Job *job); | ||
120 | */ | ||
121 | void coroutine_fn job_sleep_ns(Job *job, int64_t ns); | ||
122 | |||
123 | - | ||
124 | /** Returns the JobType of a given Job. */ | ||
125 | JobType job_type(const Job *job); | ||
70 | 126 | ||
71 | -- | 127 | -- |
72 | 1.8.3.1 | 128 | 2.37.3 |
73 | |||
74 | diff view generated by jsdifflib |
1 | From: Eric Blake <eblake@redhat.com> | 1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | We are gradually moving away from sector-based interfaces, towards | 3 | job_event_* functions can all be static, as they are not used |
4 | byte-based. In the common case, allocation is unlikely to ever use | 4 | outside job.c. |
5 | values that are not naturally sector-aligned, but it is possible | ||
6 | that byte-based values will let us be more precise about allocation | ||
7 | at the end of an unaligned file that can do byte-based access. | ||
8 | 5 | ||
9 | Changing the signature of the function to use int64_t *pnum ensures | 6 | Same applies for job_txn_add_job(). |
10 | that the compiler enforces that all callers are updated. For now, | ||
11 | the io.c layer still assert()s that all callers are sector-aligned | ||
12 | on input and that *pnum is sector-aligned on return to the caller, | ||
13 | but that can be relaxed when a later patch implements byte-based | ||
14 | block status. Therefore, this code adds usages like | ||
15 | DIV_ROUND_UP(,BDRV_SECTOR_SIZE) to callers that still want aligned | ||
16 | values, where the call might reasonbly give non-aligned results | ||
17 | in the future; on the other hand, no rounding is needed for callers | ||
18 | that should just continue to work with byte alignment. | ||
19 | 7 | ||
20 | For the most part this patch is just the addition of scaling at the | 8 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
21 | callers followed by inverse scaling at bdrv_is_allocated(). But | 9 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> |
22 | some code, particularly bdrv_commit(), gets a lot simpler because it | 10 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> |
23 | no longer has to mess with sectors; also, it is now possible to pass | 11 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> |
24 | NULL if the caller does not care how much of the image is allocated | 12 | Message-Id: <20220926093214.506243-4-eesposit@redhat.com> |
25 | beyond the initial offset. Leave comments where we can further | ||
26 | simplify once a later patch eliminates the need for sector-aligned | ||
27 | requests through bdrv_is_allocated(). | ||
28 | |||
29 | For ease of review, bdrv_is_allocated_above() will be tackled | ||
30 | separately. | ||
31 | |||
32 | Signed-off-by: Eric Blake <eblake@redhat.com> | ||
33 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 13 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
34 | --- | 14 | --- |
35 | block/backup.c | 17 ++++--------- | 15 | include/qemu/job.h | 18 ------------------ |
36 | block/commit.c | 21 +++++++--------- | 16 | job.c | 22 +++++++++++++++++++--- |
37 | block/io.c | 54 ++++++++++++++++++++++++++------------- | 17 | 2 files changed, 19 insertions(+), 21 deletions(-) |
38 | block/stream.c | 7 ++++-- | ||
39 | block/vvfat.c | 34 ++++++++++++++----------- | ||
40 | include/block/block.h | 4 +-- | ||
41 | migration/block.c | 16 +++++++----- | ||
42 | qemu-img.c | 8 +++++- | ||
43 | qemu-io-cmds.c | 70 +++++++++++++++++++++++---------------------------- | ||
44 | 9 files changed, 126 insertions(+), 105 deletions(-) | ||
45 | 18 | ||
46 | diff --git a/block/backup.c b/block/backup.c | 19 | diff --git a/include/qemu/job.h b/include/qemu/job.h |
47 | index XXXXXXX..XXXXXXX 100644 | 20 | index XXXXXXX..XXXXXXX 100644 |
48 | --- a/block/backup.c | 21 | --- a/include/qemu/job.h |
49 | +++ b/block/backup.c | 22 | +++ b/include/qemu/job.h |
50 | @@ -XXX,XX +XXX,XX @@ typedef struct BackupBlockJob { | 23 | @@ -XXX,XX +XXX,XX @@ JobTxn *job_txn_new(void); |
51 | QLIST_HEAD(, CowRequest) inflight_reqs; | 24 | */ |
52 | } BackupBlockJob; | 25 | void job_txn_unref(JobTxn *txn); |
53 | 26 | ||
54 | -/* Size of a cluster in sectors, instead of bytes. */ | 27 | -/** |
55 | -static inline int64_t cluster_size_sectors(BackupBlockJob *job) | 28 | - * @txn: The transaction (may be NULL) |
56 | -{ | 29 | - * @job: Job to add to the transaction |
57 | - return job->cluster_size / BDRV_SECTOR_SIZE; | 30 | - * |
58 | -} | 31 | - * Add @job to the transaction. The @job must not already be in a transaction. |
32 | - * The caller must call either job_txn_unref() or job_completed() to release | ||
33 | - * the reference that is automatically grabbed here. | ||
34 | - * | ||
35 | - * If @txn is NULL, the function does nothing. | ||
36 | - */ | ||
37 | -void job_txn_add_job(JobTxn *txn, Job *job); | ||
59 | - | 38 | - |
60 | /* See if in-flight requests overlap and wait for them to complete */ | 39 | /** |
61 | static void coroutine_fn wait_for_overlapping_requests(BackupBlockJob *job, | 40 | * Create a new long-running job and return it. |
62 | int64_t start, | 41 | * |
63 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn backup_run(void *opaque) | 42 | @@ -XXX,XX +XXX,XX @@ void job_progress_set_remaining(Job *job, uint64_t remaining); |
64 | BackupCompleteData *data; | 43 | */ |
65 | BlockDriverState *bs = blk_bs(job->common.blk); | 44 | void job_progress_increase_remaining(Job *job, uint64_t delta); |
66 | int64_t offset; | 45 | |
67 | - int64_t sectors_per_cluster = cluster_size_sectors(job); | 46 | -/** To be called when a cancelled job is finalised. */ |
68 | int ret = 0; | 47 | -void job_event_cancelled(Job *job); |
69 | 48 | - | |
70 | QLIST_INIT(&job->inflight_reqs); | 49 | -/** To be called when a successfully completed job is finalised. */ |
71 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn backup_run(void *opaque) | 50 | -void job_event_completed(Job *job); |
72 | } | 51 | - |
73 | 52 | /** | |
74 | if (job->sync_mode == MIRROR_SYNC_MODE_TOP) { | 53 | * Conditionally enter the job coroutine if the job is ready to run, not |
75 | - int i, n; | 54 | * already busy and fn() returns true. fn() is called while under the job_lock |
76 | + int i; | 55 | diff --git a/job.c b/job.c |
77 | + int64_t n; | ||
78 | |||
79 | /* Check to see if these blocks are already in the | ||
80 | * backing file. */ | ||
81 | |||
82 | - for (i = 0; i < sectors_per_cluster;) { | ||
83 | + for (i = 0; i < job->cluster_size;) { | ||
84 | /* bdrv_is_allocated() only returns true/false based | ||
85 | * on the first set of sectors it comes across that | ||
86 | * are are all in the same state. | ||
87 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn backup_run(void *opaque) | ||
88 | * backup cluster length. We end up copying more than | ||
89 | * needed but at some point that is always the case. */ | ||
90 | alloced = | ||
91 | - bdrv_is_allocated(bs, | ||
92 | - (offset >> BDRV_SECTOR_BITS) + i, | ||
93 | - sectors_per_cluster - i, &n); | ||
94 | + bdrv_is_allocated(bs, offset + i, | ||
95 | + job->cluster_size - i, &n); | ||
96 | i += n; | ||
97 | |||
98 | if (alloced || n == 0) { | ||
99 | diff --git a/block/commit.c b/block/commit.c | ||
100 | index XXXXXXX..XXXXXXX 100644 | 56 | index XXXXXXX..XXXXXXX 100644 |
101 | --- a/block/commit.c | 57 | --- a/job.c |
102 | +++ b/block/commit.c | 58 | +++ b/job.c |
103 | @@ -XXX,XX +XXX,XX @@ fail: | 59 | @@ -XXX,XX +XXX,XX @@ void job_txn_unref(JobTxn *txn) |
60 | } | ||
104 | } | 61 | } |
105 | 62 | ||
106 | 63 | -void job_txn_add_job(JobTxn *txn, Job *job) | |
107 | -#define COMMIT_BUF_SECTORS 2048 | 64 | +/** |
108 | +#define COMMIT_BUF_SIZE (2048 * BDRV_SECTOR_SIZE) | 65 | + * @txn: The transaction (may be NULL) |
109 | 66 | + * @job: Job to add to the transaction | |
110 | /* commit COW file into the raw image */ | 67 | + * |
111 | int bdrv_commit(BlockDriverState *bs) | 68 | + * Add @job to the transaction. The @job must not already be in a transaction. |
112 | @@ -XXX,XX +XXX,XX @@ int bdrv_commit(BlockDriverState *bs) | 69 | + * The caller must call either job_txn_unref() or job_completed() to release |
113 | BlockDriverState *backing_file_bs = NULL; | 70 | + * the reference that is automatically grabbed here. |
114 | BlockDriverState *commit_top_bs = NULL; | 71 | + * |
115 | BlockDriver *drv = bs->drv; | 72 | + * If @txn is NULL, the function does nothing. |
116 | - int64_t sector, total_sectors, length, backing_length; | 73 | + */ |
117 | - int n, ro, open_flags; | 74 | +static void job_txn_add_job(JobTxn *txn, Job *job) |
118 | + int64_t offset, length, backing_length; | 75 | { |
119 | + int ro, open_flags; | 76 | if (!txn) { |
120 | + int64_t n; | 77 | return; |
121 | int ret = 0; | 78 | @@ -XXX,XX +XXX,XX @@ void job_progress_increase_remaining(Job *job, uint64_t delta) |
122 | uint8_t *buf = NULL; | 79 | progress_increase_remaining(&job->progress, delta); |
123 | Error *local_err = NULL; | ||
124 | @@ -XXX,XX +XXX,XX @@ int bdrv_commit(BlockDriverState *bs) | ||
125 | } | ||
126 | } | ||
127 | |||
128 | - total_sectors = length >> BDRV_SECTOR_BITS; | ||
129 | - | ||
130 | /* blk_try_blockalign() for src will choose an alignment that works for | ||
131 | * backing as well, so no need to compare the alignment manually. */ | ||
132 | - buf = blk_try_blockalign(src, COMMIT_BUF_SECTORS * BDRV_SECTOR_SIZE); | ||
133 | + buf = blk_try_blockalign(src, COMMIT_BUF_SIZE); | ||
134 | if (buf == NULL) { | ||
135 | ret = -ENOMEM; | ||
136 | goto ro_cleanup; | ||
137 | } | ||
138 | |||
139 | - for (sector = 0; sector < total_sectors; sector += n) { | ||
140 | - ret = bdrv_is_allocated(bs, sector, COMMIT_BUF_SECTORS, &n); | ||
141 | + for (offset = 0; offset < length; offset += n) { | ||
142 | + ret = bdrv_is_allocated(bs, offset, COMMIT_BUF_SIZE, &n); | ||
143 | if (ret < 0) { | ||
144 | goto ro_cleanup; | ||
145 | } | ||
146 | if (ret) { | ||
147 | - ret = blk_pread(src, sector * BDRV_SECTOR_SIZE, buf, | ||
148 | - n * BDRV_SECTOR_SIZE); | ||
149 | + ret = blk_pread(src, offset, buf, n); | ||
150 | if (ret < 0) { | ||
151 | goto ro_cleanup; | ||
152 | } | ||
153 | |||
154 | - ret = blk_pwrite(backing, sector * BDRV_SECTOR_SIZE, buf, | ||
155 | - n * BDRV_SECTOR_SIZE, 0); | ||
156 | + ret = blk_pwrite(backing, offset, buf, n, 0); | ||
157 | if (ret < 0) { | ||
158 | goto ro_cleanup; | ||
159 | } | ||
160 | diff --git a/block/io.c b/block/io.c | ||
161 | index XXXXXXX..XXXXXXX 100644 | ||
162 | --- a/block/io.c | ||
163 | +++ b/block/io.c | ||
164 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_aligned_preadv(BdrvChild *child, | ||
165 | } | ||
166 | |||
167 | if (flags & BDRV_REQ_COPY_ON_READ) { | ||
168 | - int64_t start_sector = offset >> BDRV_SECTOR_BITS; | ||
169 | - int64_t end_sector = DIV_ROUND_UP(offset + bytes, BDRV_SECTOR_SIZE); | ||
170 | - unsigned int nb_sectors = end_sector - start_sector; | ||
171 | - int pnum; | ||
172 | + /* TODO: Simplify further once bdrv_is_allocated no longer | ||
173 | + * requires sector alignment */ | ||
174 | + int64_t start = QEMU_ALIGN_DOWN(offset, BDRV_SECTOR_SIZE); | ||
175 | + int64_t end = QEMU_ALIGN_UP(offset + bytes, BDRV_SECTOR_SIZE); | ||
176 | + int64_t pnum; | ||
177 | |||
178 | - ret = bdrv_is_allocated(bs, start_sector, nb_sectors, &pnum); | ||
179 | + ret = bdrv_is_allocated(bs, start, end - start, &pnum); | ||
180 | if (ret < 0) { | ||
181 | goto out; | ||
182 | } | ||
183 | |||
184 | - if (!ret || pnum != nb_sectors) { | ||
185 | + if (!ret || pnum != end - start) { | ||
186 | ret = bdrv_co_do_copy_on_readv(child, offset, bytes, qiov); | ||
187 | goto out; | ||
188 | } | ||
189 | @@ -XXX,XX +XXX,XX @@ int64_t bdrv_get_block_status(BlockDriverState *bs, | ||
190 | sector_num, nb_sectors, pnum, file); | ||
191 | } | 80 | } |
192 | 81 | ||
193 | -int coroutine_fn bdrv_is_allocated(BlockDriverState *bs, int64_t sector_num, | 82 | -void job_event_cancelled(Job *job) |
194 | - int nb_sectors, int *pnum) | 83 | +/** |
195 | +int coroutine_fn bdrv_is_allocated(BlockDriverState *bs, int64_t offset, | 84 | + * To be called when a cancelled job is finalised. |
196 | + int64_t bytes, int64_t *pnum) | 85 | + */ |
86 | +static void job_event_cancelled(Job *job) | ||
197 | { | 87 | { |
198 | BlockDriverState *file; | 88 | notifier_list_notify(&job->on_finalize_cancelled, job); |
199 | - int64_t ret = bdrv_get_block_status(bs, sector_num, nb_sectors, pnum, | ||
200 | - &file); | ||
201 | + int64_t sector_num = offset >> BDRV_SECTOR_BITS; | ||
202 | + int nb_sectors = bytes >> BDRV_SECTOR_BITS; | ||
203 | + int64_t ret; | ||
204 | + int psectors; | ||
205 | + | ||
206 | + assert(QEMU_IS_ALIGNED(offset, BDRV_SECTOR_SIZE)); | ||
207 | + assert(QEMU_IS_ALIGNED(bytes, BDRV_SECTOR_SIZE) && bytes < INT_MAX); | ||
208 | + ret = bdrv_get_block_status(bs, sector_num, nb_sectors, &psectors, | ||
209 | + &file); | ||
210 | if (ret < 0) { | ||
211 | return ret; | ||
212 | } | ||
213 | + if (pnum) { | ||
214 | + *pnum = psectors * BDRV_SECTOR_SIZE; | ||
215 | + } | ||
216 | return !!(ret & BDRV_BLOCK_ALLOCATED); | ||
217 | } | 89 | } |
218 | 90 | ||
219 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_is_allocated(BlockDriverState *bs, int64_t sector_num, | 91 | -void job_event_completed(Job *job) |
220 | * | 92 | +/** |
221 | * Return true if the given sector is allocated in any image between | 93 | + * To be called when a successfully completed job is finalised. |
222 | * BASE and TOP (inclusive). BASE can be NULL to check if the given | 94 | + */ |
223 | - * sector is allocated in any image of the chain. Return false otherwise. | 95 | +static void job_event_completed(Job *job) |
224 | + * sector is allocated in any image of the chain. Return false otherwise, | ||
225 | + * or negative errno on failure. | ||
226 | * | ||
227 | * 'pnum' is set to the number of sectors (including and immediately following | ||
228 | * the specified sector) that are known to be in the same | ||
229 | @@ -XXX,XX +XXX,XX @@ int bdrv_is_allocated_above(BlockDriverState *top, | ||
230 | |||
231 | intermediate = top; | ||
232 | while (intermediate && intermediate != base) { | ||
233 | - int pnum_inter; | ||
234 | - ret = bdrv_is_allocated(intermediate, sector_num, nb_sectors, | ||
235 | + int64_t pnum_inter; | ||
236 | + int psectors_inter; | ||
237 | + | ||
238 | + ret = bdrv_is_allocated(intermediate, sector_num * BDRV_SECTOR_SIZE, | ||
239 | + nb_sectors * BDRV_SECTOR_SIZE, | ||
240 | &pnum_inter); | ||
241 | if (ret < 0) { | ||
242 | return ret; | ||
243 | - } else if (ret) { | ||
244 | - *pnum = pnum_inter; | ||
245 | + } | ||
246 | + assert(pnum_inter < INT_MAX * BDRV_SECTOR_SIZE); | ||
247 | + psectors_inter = pnum_inter >> BDRV_SECTOR_BITS; | ||
248 | + if (ret) { | ||
249 | + *pnum = psectors_inter; | ||
250 | return 1; | ||
251 | } | ||
252 | |||
253 | @@ -XXX,XX +XXX,XX @@ int bdrv_is_allocated_above(BlockDriverState *top, | ||
254 | * | ||
255 | * [sector_num+x, nr_sectors] allocated. | ||
256 | */ | ||
257 | - if (n > pnum_inter && | ||
258 | + if (n > psectors_inter && | ||
259 | (intermediate == top || | ||
260 | - sector_num + pnum_inter < intermediate->total_sectors)) { | ||
261 | - n = pnum_inter; | ||
262 | + sector_num + psectors_inter < intermediate->total_sectors)) { | ||
263 | + n = psectors_inter; | ||
264 | } | ||
265 | |||
266 | intermediate = backing_bs(intermediate); | ||
267 | diff --git a/block/stream.c b/block/stream.c | ||
268 | index XXXXXXX..XXXXXXX 100644 | ||
269 | --- a/block/stream.c | ||
270 | +++ b/block/stream.c | ||
271 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn stream_run(void *opaque) | ||
272 | |||
273 | for ( ; offset < s->common.len; offset += n * BDRV_SECTOR_SIZE) { | ||
274 | bool copy; | ||
275 | + int64_t count = 0; | ||
276 | |||
277 | /* Note that even when no rate limit is applied we need to yield | ||
278 | * with no pending I/O here so that bdrv_drain_all() returns. | ||
279 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn stream_run(void *opaque) | ||
280 | |||
281 | copy = false; | ||
282 | |||
283 | - ret = bdrv_is_allocated(bs, offset / BDRV_SECTOR_SIZE, | ||
284 | - STREAM_BUFFER_SIZE / BDRV_SECTOR_SIZE, &n); | ||
285 | + ret = bdrv_is_allocated(bs, offset, STREAM_BUFFER_SIZE, &count); | ||
286 | + /* TODO relax this once bdrv_is_allocated does not enforce sectors */ | ||
287 | + assert(QEMU_IS_ALIGNED(count, BDRV_SECTOR_SIZE)); | ||
288 | + n = count >> BDRV_SECTOR_BITS; | ||
289 | if (ret == 1) { | ||
290 | /* Allocated in the top, no need to copy. */ | ||
291 | } else if (ret >= 0) { | ||
292 | diff --git a/block/vvfat.c b/block/vvfat.c | ||
293 | index XXXXXXX..XXXXXXX 100644 | ||
294 | --- a/block/vvfat.c | ||
295 | +++ b/block/vvfat.c | ||
296 | @@ -XXX,XX +XXX,XX @@ static int vvfat_read(BlockDriverState *bs, int64_t sector_num, | ||
297 | if (sector_num >= bs->total_sectors) | ||
298 | return -1; | ||
299 | if (s->qcow) { | ||
300 | - int n; | ||
301 | + int64_t n; | ||
302 | int ret; | ||
303 | - ret = bdrv_is_allocated(s->qcow->bs, sector_num, | ||
304 | - nb_sectors - i, &n); | ||
305 | + ret = bdrv_is_allocated(s->qcow->bs, sector_num * BDRV_SECTOR_SIZE, | ||
306 | + (nb_sectors - i) * BDRV_SECTOR_SIZE, &n); | ||
307 | if (ret < 0) { | ||
308 | return ret; | ||
309 | } | ||
310 | if (ret) { | ||
311 | - DLOG(fprintf(stderr, "sectors %d+%d allocated\n", | ||
312 | - (int)sector_num, n)); | ||
313 | - if (bdrv_read(s->qcow, sector_num, buf + i * 0x200, n)) { | ||
314 | + DLOG(fprintf(stderr, "sectors %" PRId64 "+%" PRId64 | ||
315 | + " allocated\n", sector_num, | ||
316 | + n >> BDRV_SECTOR_BITS)); | ||
317 | + if (bdrv_read(s->qcow, sector_num, buf + i * 0x200, | ||
318 | + n >> BDRV_SECTOR_BITS)) { | ||
319 | return -1; | ||
320 | } | ||
321 | - i += n - 1; | ||
322 | - sector_num += n - 1; | ||
323 | + i += (n >> BDRV_SECTOR_BITS) - 1; | ||
324 | + sector_num += (n >> BDRV_SECTOR_BITS) - 1; | ||
325 | continue; | ||
326 | } | ||
327 | -DLOG(fprintf(stderr, "sector %d not allocated\n", (int)sector_num)); | ||
328 | + DLOG(fprintf(stderr, "sector %" PRId64 " not allocated\n", | ||
329 | + sector_num)); | ||
330 | } | ||
331 | if (sector_num < s->offset_to_root_dir) { | ||
332 | if (sector_num < s->offset_to_fat) { | ||
333 | @@ -XXX,XX +XXX,XX @@ static inline bool cluster_was_modified(BDRVVVFATState *s, | ||
334 | uint32_t cluster_num) | ||
335 | { | 96 | { |
336 | int was_modified = 0; | 97 | notifier_list_notify(&job->on_finalize_completed, job); |
337 | - int i, dummy; | ||
338 | + int i; | ||
339 | |||
340 | if (s->qcow == NULL) { | ||
341 | return 0; | ||
342 | @@ -XXX,XX +XXX,XX @@ static inline bool cluster_was_modified(BDRVVVFATState *s, | ||
343 | |||
344 | for (i = 0; !was_modified && i < s->sectors_per_cluster; i++) { | ||
345 | was_modified = bdrv_is_allocated(s->qcow->bs, | ||
346 | - cluster2sector(s, cluster_num) + i, | ||
347 | - 1, &dummy); | ||
348 | + (cluster2sector(s, cluster_num) + | ||
349 | + i) * BDRV_SECTOR_SIZE, | ||
350 | + BDRV_SECTOR_SIZE, NULL); | ||
351 | } | ||
352 | |||
353 | /* | ||
354 | @@ -XXX,XX +XXX,XX @@ static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s, | ||
355 | } | ||
356 | |||
357 | if (copy_it) { | ||
358 | - int i, dummy; | ||
359 | + int i; | ||
360 | /* | ||
361 | * This is horribly inefficient, but that is okay, since | ||
362 | * it is rarely executed, if at all. | ||
363 | @@ -XXX,XX +XXX,XX @@ static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s, | ||
364 | for (i = 0; i < s->sectors_per_cluster; i++) { | ||
365 | int res; | ||
366 | |||
367 | - res = bdrv_is_allocated(s->qcow->bs, offset + i, 1, &dummy); | ||
368 | + res = bdrv_is_allocated(s->qcow->bs, | ||
369 | + (offset + i) * BDRV_SECTOR_SIZE, | ||
370 | + BDRV_SECTOR_SIZE, NULL); | ||
371 | if (res < 0) { | ||
372 | return -1; | ||
373 | } | ||
374 | diff --git a/include/block/block.h b/include/block/block.h | ||
375 | index XXXXXXX..XXXXXXX 100644 | ||
376 | --- a/include/block/block.h | ||
377 | +++ b/include/block/block.h | ||
378 | @@ -XXX,XX +XXX,XX @@ int64_t bdrv_get_block_status_above(BlockDriverState *bs, | ||
379 | int64_t sector_num, | ||
380 | int nb_sectors, int *pnum, | ||
381 | BlockDriverState **file); | ||
382 | -int bdrv_is_allocated(BlockDriverState *bs, int64_t sector_num, int nb_sectors, | ||
383 | - int *pnum); | ||
384 | +int bdrv_is_allocated(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
385 | + int64_t *pnum); | ||
386 | int bdrv_is_allocated_above(BlockDriverState *top, BlockDriverState *base, | ||
387 | int64_t sector_num, int nb_sectors, int *pnum); | ||
388 | |||
389 | diff --git a/migration/block.c b/migration/block.c | ||
390 | index XXXXXXX..XXXXXXX 100644 | ||
391 | --- a/migration/block.c | ||
392 | +++ b/migration/block.c | ||
393 | @@ -XXX,XX +XXX,XX @@ | ||
394 | #define BLK_MIG_FLAG_PROGRESS 0x04 | ||
395 | #define BLK_MIG_FLAG_ZERO_BLOCK 0x08 | ||
396 | |||
397 | -#define MAX_IS_ALLOCATED_SEARCH 65536 | ||
398 | +#define MAX_IS_ALLOCATED_SEARCH (65536 * BDRV_SECTOR_SIZE) | ||
399 | |||
400 | #define MAX_INFLIGHT_IO 512 | ||
401 | |||
402 | @@ -XXX,XX +XXX,XX @@ static int mig_save_device_bulk(QEMUFile *f, BlkMigDevState *bmds) | ||
403 | BlockBackend *bb = bmds->blk; | ||
404 | BlkMigBlock *blk; | ||
405 | int nr_sectors; | ||
406 | + int64_t count; | ||
407 | |||
408 | if (bmds->shared_base) { | ||
409 | qemu_mutex_lock_iothread(); | ||
410 | aio_context_acquire(blk_get_aio_context(bb)); | ||
411 | - /* Skip unallocated sectors; intentionally treats failure as | ||
412 | - * an allocated sector */ | ||
413 | + /* Skip unallocated sectors; intentionally treats failure or | ||
414 | + * partial sector as an allocated sector */ | ||
415 | while (cur_sector < total_sectors && | ||
416 | - !bdrv_is_allocated(blk_bs(bb), cur_sector, | ||
417 | - MAX_IS_ALLOCATED_SEARCH, &nr_sectors)) { | ||
418 | - cur_sector += nr_sectors; | ||
419 | + !bdrv_is_allocated(blk_bs(bb), cur_sector * BDRV_SECTOR_SIZE, | ||
420 | + MAX_IS_ALLOCATED_SEARCH, &count)) { | ||
421 | + if (count < BDRV_SECTOR_SIZE) { | ||
422 | + break; | ||
423 | + } | ||
424 | + cur_sector += count >> BDRV_SECTOR_BITS; | ||
425 | } | ||
426 | aio_context_release(blk_get_aio_context(bb)); | ||
427 | qemu_mutex_unlock_iothread(); | ||
428 | diff --git a/qemu-img.c b/qemu-img.c | ||
429 | index XXXXXXX..XXXXXXX 100644 | ||
430 | --- a/qemu-img.c | ||
431 | +++ b/qemu-img.c | ||
432 | @@ -XXX,XX +XXX,XX @@ static int img_rebase(int argc, char **argv) | ||
433 | int64_t new_backing_num_sectors = 0; | ||
434 | uint64_t sector; | ||
435 | int n; | ||
436 | + int64_t count; | ||
437 | float local_progress = 0; | ||
438 | |||
439 | buf_old = blk_blockalign(blk, IO_BUF_SIZE); | ||
440 | @@ -XXX,XX +XXX,XX @@ static int img_rebase(int argc, char **argv) | ||
441 | } | ||
442 | |||
443 | /* If the cluster is allocated, we don't need to take action */ | ||
444 | - ret = bdrv_is_allocated(bs, sector, n, &n); | ||
445 | + ret = bdrv_is_allocated(bs, sector << BDRV_SECTOR_BITS, | ||
446 | + n << BDRV_SECTOR_BITS, &count); | ||
447 | if (ret < 0) { | ||
448 | error_report("error while reading image metadata: %s", | ||
449 | strerror(-ret)); | ||
450 | goto out; | ||
451 | } | ||
452 | + /* TODO relax this once bdrv_is_allocated does not enforce | ||
453 | + * sector alignment */ | ||
454 | + assert(QEMU_IS_ALIGNED(count, BDRV_SECTOR_SIZE)); | ||
455 | + n = count >> BDRV_SECTOR_BITS; | ||
456 | if (ret) { | ||
457 | continue; | ||
458 | } | ||
459 | diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c | ||
460 | index XXXXXXX..XXXXXXX 100644 | ||
461 | --- a/qemu-io-cmds.c | ||
462 | +++ b/qemu-io-cmds.c | ||
463 | @@ -XXX,XX +XXX,XX @@ out: | ||
464 | static int alloc_f(BlockBackend *blk, int argc, char **argv) | ||
465 | { | ||
466 | BlockDriverState *bs = blk_bs(blk); | ||
467 | - int64_t offset, sector_num, nb_sectors, remaining, count; | ||
468 | + int64_t offset, start, remaining, count; | ||
469 | char s1[64]; | ||
470 | - int num, ret; | ||
471 | - int64_t sum_alloc; | ||
472 | + int ret; | ||
473 | + int64_t num, sum_alloc; | ||
474 | |||
475 | - offset = cvtnum(argv[1]); | ||
476 | + start = offset = cvtnum(argv[1]); | ||
477 | if (offset < 0) { | ||
478 | print_cvtnum_err(offset, argv[1]); | ||
479 | return 0; | ||
480 | @@ -XXX,XX +XXX,XX @@ static int alloc_f(BlockBackend *blk, int argc, char **argv) | ||
481 | count); | ||
482 | return 0; | ||
483 | } | ||
484 | - nb_sectors = count >> BDRV_SECTOR_BITS; | ||
485 | |||
486 | - remaining = nb_sectors; | ||
487 | + remaining = count; | ||
488 | sum_alloc = 0; | ||
489 | - sector_num = offset >> 9; | ||
490 | while (remaining) { | ||
491 | - ret = bdrv_is_allocated(bs, sector_num, remaining, &num); | ||
492 | + ret = bdrv_is_allocated(bs, offset, remaining, &num); | ||
493 | if (ret < 0) { | ||
494 | printf("is_allocated failed: %s\n", strerror(-ret)); | ||
495 | return 0; | ||
496 | } | ||
497 | - sector_num += num; | ||
498 | + offset += num; | ||
499 | remaining -= num; | ||
500 | if (ret) { | ||
501 | sum_alloc += num; | ||
502 | } | ||
503 | if (num == 0) { | ||
504 | - nb_sectors -= remaining; | ||
505 | + count -= remaining; | ||
506 | remaining = 0; | ||
507 | } | ||
508 | } | ||
509 | |||
510 | - cvtstr(offset, s1, sizeof(s1)); | ||
511 | + cvtstr(start, s1, sizeof(s1)); | ||
512 | |||
513 | printf("%"PRId64"/%"PRId64" bytes allocated at offset %s\n", | ||
514 | - sum_alloc << BDRV_SECTOR_BITS, nb_sectors << BDRV_SECTOR_BITS, s1); | ||
515 | + sum_alloc, count, s1); | ||
516 | return 0; | ||
517 | } | ||
518 | |||
519 | @@ -XXX,XX +XXX,XX @@ static const cmdinfo_t alloc_cmd = { | ||
520 | }; | ||
521 | |||
522 | |||
523 | -static int map_is_allocated(BlockDriverState *bs, int64_t sector_num, | ||
524 | - int64_t nb_sectors, int64_t *pnum) | ||
525 | +static int map_is_allocated(BlockDriverState *bs, int64_t offset, | ||
526 | + int64_t bytes, int64_t *pnum) | ||
527 | { | ||
528 | - int num, num_checked; | ||
529 | + int64_t num; | ||
530 | + int num_checked; | ||
531 | int ret, firstret; | ||
532 | |||
533 | - num_checked = MIN(nb_sectors, INT_MAX); | ||
534 | - ret = bdrv_is_allocated(bs, sector_num, num_checked, &num); | ||
535 | + num_checked = MIN(bytes, BDRV_REQUEST_MAX_BYTES); | ||
536 | + ret = bdrv_is_allocated(bs, offset, num_checked, &num); | ||
537 | if (ret < 0) { | ||
538 | return ret; | ||
539 | } | ||
540 | @@ -XXX,XX +XXX,XX @@ static int map_is_allocated(BlockDriverState *bs, int64_t sector_num, | ||
541 | firstret = ret; | ||
542 | *pnum = num; | ||
543 | |||
544 | - while (nb_sectors > 0 && ret == firstret) { | ||
545 | - sector_num += num; | ||
546 | - nb_sectors -= num; | ||
547 | + while (bytes > 0 && ret == firstret) { | ||
548 | + offset += num; | ||
549 | + bytes -= num; | ||
550 | |||
551 | - num_checked = MIN(nb_sectors, INT_MAX); | ||
552 | - ret = bdrv_is_allocated(bs, sector_num, num_checked, &num); | ||
553 | + num_checked = MIN(bytes, BDRV_REQUEST_MAX_BYTES); | ||
554 | + ret = bdrv_is_allocated(bs, offset, num_checked, &num); | ||
555 | if (ret == firstret && num) { | ||
556 | *pnum += num; | ||
557 | } else { | ||
558 | @@ -XXX,XX +XXX,XX @@ static int map_is_allocated(BlockDriverState *bs, int64_t sector_num, | ||
559 | |||
560 | static int map_f(BlockBackend *blk, int argc, char **argv) | ||
561 | { | ||
562 | - int64_t offset; | ||
563 | - int64_t nb_sectors, total_sectors; | ||
564 | + int64_t offset, bytes; | ||
565 | char s1[64], s2[64]; | ||
566 | int64_t num; | ||
567 | int ret; | ||
568 | const char *retstr; | ||
569 | |||
570 | offset = 0; | ||
571 | - total_sectors = blk_nb_sectors(blk); | ||
572 | - if (total_sectors < 0) { | ||
573 | - error_report("Failed to query image length: %s", | ||
574 | - strerror(-total_sectors)); | ||
575 | + bytes = blk_getlength(blk); | ||
576 | + if (bytes < 0) { | ||
577 | + error_report("Failed to query image length: %s", strerror(-bytes)); | ||
578 | return 0; | ||
579 | } | ||
580 | |||
581 | - nb_sectors = total_sectors; | ||
582 | - | ||
583 | - do { | ||
584 | - ret = map_is_allocated(blk_bs(blk), offset, nb_sectors, &num); | ||
585 | + while (bytes) { | ||
586 | + ret = map_is_allocated(blk_bs(blk), offset, bytes, &num); | ||
587 | if (ret < 0) { | ||
588 | error_report("Failed to get allocation status: %s", strerror(-ret)); | ||
589 | return 0; | ||
590 | @@ -XXX,XX +XXX,XX @@ static int map_f(BlockBackend *blk, int argc, char **argv) | ||
591 | } | ||
592 | |||
593 | retstr = ret ? " allocated" : "not allocated"; | ||
594 | - cvtstr(num << BDRV_SECTOR_BITS, s1, sizeof(s1)); | ||
595 | - cvtstr(offset << BDRV_SECTOR_BITS, s2, sizeof(s2)); | ||
596 | + cvtstr(num, s1, sizeof(s1)); | ||
597 | + cvtstr(offset, s2, sizeof(s2)); | ||
598 | printf("%s (0x%" PRIx64 ") bytes %s at offset %s (0x%" PRIx64 ")\n", | ||
599 | - s1, num << BDRV_SECTOR_BITS, retstr, | ||
600 | - s2, offset << BDRV_SECTOR_BITS); | ||
601 | + s1, num, retstr, s2, offset); | ||
602 | |||
603 | offset += num; | ||
604 | - nb_sectors -= num; | ||
605 | - } while (offset < total_sectors); | ||
606 | + bytes -= num; | ||
607 | + } | ||
608 | |||
609 | return 0; | ||
610 | } | 98 | } |
611 | -- | 99 | -- |
612 | 1.8.3.1 | 100 | 2.37.3 |
613 | |||
614 | diff view generated by jsdifflib |
1 | From: Eric Blake <eblake@redhat.com> | 1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | We are gradually converting to byte-based interfaces, as they are | 3 | Same as AIO_WAIT_WHILE macro, but if we are in the Main loop |
4 | easier to reason about than sector-based. Change the internal | 4 | do not release and then acquire ctx_ 's aiocontext. |
5 | loop iteration of streaming to track by bytes instead of sectors | ||
6 | (although we are still guaranteed that we iterate by steps that | ||
7 | are sector-aligned). | ||
8 | 5 | ||
9 | Signed-off-by: Eric Blake <eblake@redhat.com> | 6 | Once all Aiocontext locks go away, this macro will replace |
10 | Reviewed-by: John Snow <jsnow@redhat.com> | 7 | AIO_WAIT_WHILE. |
11 | Reviewed-by: Jeff Cody <jcody@redhat.com> | 8 | |
9 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
10 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
11 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> | ||
12 | Message-Id: <20220926093214.506243-5-eesposit@redhat.com> | ||
12 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | 13 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> |
13 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 14 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
14 | --- | 15 | --- |
15 | block/stream.c | 22 +++++++++------------- | 16 | include/block/aio-wait.h | 17 +++++++++++++---- |
16 | 1 file changed, 9 insertions(+), 13 deletions(-) | 17 | 1 file changed, 13 insertions(+), 4 deletions(-) |
17 | 18 | ||
18 | diff --git a/block/stream.c b/block/stream.c | 19 | diff --git a/include/block/aio-wait.h b/include/block/aio-wait.h |
19 | index XXXXXXX..XXXXXXX 100644 | 20 | index XXXXXXX..XXXXXXX 100644 |
20 | --- a/block/stream.c | 21 | --- a/include/block/aio-wait.h |
21 | +++ b/block/stream.c | 22 | +++ b/include/block/aio-wait.h |
22 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn stream_run(void *opaque) | 23 | @@ -XXX,XX +XXX,XX @@ typedef struct { |
23 | BlockBackend *blk = s->common.blk; | 24 | extern AioWait global_aio_wait; |
24 | BlockDriverState *bs = blk_bs(blk); | 25 | |
25 | BlockDriverState *base = s->base; | 26 | /** |
26 | - int64_t sector_num = 0; | 27 | - * AIO_WAIT_WHILE: |
27 | - int64_t end = -1; | 28 | + * AIO_WAIT_WHILE_INTERNAL: |
28 | + int64_t offset = 0; | 29 | * @ctx: the aio context, or NULL if multiple aio contexts (for which the |
29 | uint64_t delay_ns = 0; | 30 | * caller does not hold a lock) are involved in the polling condition. |
30 | int error = 0; | 31 | * @cond: wait while this conditional expression is true |
31 | int ret = 0; | 32 | + * @unlock: whether to unlock and then lock again @ctx. This apples |
32 | - int n = 0; | 33 | + * only when waiting for another AioContext from the main loop. |
33 | + int n = 0; /* sectors */ | 34 | + * Otherwise it's ignored. |
34 | void *buf; | 35 | * |
35 | 36 | * Wait while a condition is true. Use this to implement synchronous | |
36 | if (!bs->backing) { | 37 | * operations that require event loop activity. |
37 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn stream_run(void *opaque) | 38 | @@ -XXX,XX +XXX,XX @@ extern AioWait global_aio_wait; |
38 | goto out; | 39 | * wait on conditions between two IOThreads since that could lead to deadlock, |
39 | } | 40 | * go via the main loop instead. |
40 | 41 | */ | |
41 | - end = s->common.len >> BDRV_SECTOR_BITS; | 42 | -#define AIO_WAIT_WHILE(ctx, cond) ({ \ |
42 | buf = qemu_blockalign(bs, STREAM_BUFFER_SIZE); | 43 | +#define AIO_WAIT_WHILE_INTERNAL(ctx, cond, unlock) ({ \ |
43 | 44 | bool waited_ = false; \ | |
44 | /* Turn on copy-on-read for the whole block device so that guest read | 45 | AioWait *wait_ = &global_aio_wait; \ |
45 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn stream_run(void *opaque) | 46 | AioContext *ctx_ = (ctx); \ |
46 | bdrv_enable_copy_on_read(bs); | 47 | @@ -XXX,XX +XXX,XX @@ extern AioWait global_aio_wait; |
47 | } | 48 | assert(qemu_get_current_aio_context() == \ |
48 | 49 | qemu_get_aio_context()); \ | |
49 | - for (sector_num = 0; sector_num < end; sector_num += n) { | 50 | while ((cond)) { \ |
50 | + for ( ; offset < s->common.len; offset += n * BDRV_SECTOR_SIZE) { | 51 | - if (ctx_) { \ |
51 | bool copy; | 52 | + if (unlock && ctx_) { \ |
52 | 53 | aio_context_release(ctx_); \ | |
53 | /* Note that even when no rate limit is applied we need to yield | 54 | } \ |
54 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn stream_run(void *opaque) | 55 | aio_poll(qemu_get_aio_context(), true); \ |
55 | 56 | - if (ctx_) { \ | |
56 | copy = false; | 57 | + if (unlock && ctx_) { \ |
57 | 58 | aio_context_acquire(ctx_); \ | |
58 | - ret = bdrv_is_allocated(bs, sector_num, | 59 | } \ |
59 | + ret = bdrv_is_allocated(bs, offset / BDRV_SECTOR_SIZE, | 60 | waited_ = true; \ |
60 | STREAM_BUFFER_SIZE / BDRV_SECTOR_SIZE, &n); | 61 | @@ -XXX,XX +XXX,XX @@ extern AioWait global_aio_wait; |
61 | if (ret == 1) { | 62 | qatomic_dec(&wait_->num_waiters); \ |
62 | /* Allocated in the top, no need to copy. */ | 63 | waited_; }) |
63 | } else if (ret >= 0) { | 64 | |
64 | /* Copy if allocated in the intermediate images. Limit to the | 65 | +#define AIO_WAIT_WHILE(ctx, cond) \ |
65 | - * known-unallocated area [sector_num, sector_num+n). */ | 66 | + AIO_WAIT_WHILE_INTERNAL(ctx, cond, true) |
66 | + * known-unallocated area [offset, offset+n*BDRV_SECTOR_SIZE). */ | 67 | + |
67 | ret = bdrv_is_allocated_above(backing_bs(bs), base, | 68 | +#define AIO_WAIT_WHILE_UNLOCKED(ctx, cond) \ |
68 | - sector_num, n, &n); | 69 | + AIO_WAIT_WHILE_INTERNAL(ctx, cond, false) |
69 | + offset / BDRV_SECTOR_SIZE, n, &n); | 70 | + |
70 | 71 | /** | |
71 | /* Finish early if end of backing file has been reached */ | 72 | * aio_wait_kick: |
72 | if (ret == 0 && n == 0) { | 73 | * Wake up the main thread if it is waiting on AIO_WAIT_WHILE(). During |
73 | - n = end - sector_num; | ||
74 | + n = (s->common.len - offset) / BDRV_SECTOR_SIZE; | ||
75 | } | ||
76 | |||
77 | copy = (ret == 1); | ||
78 | } | ||
79 | - trace_stream_one_iteration(s, sector_num * BDRV_SECTOR_SIZE, | ||
80 | - n * BDRV_SECTOR_SIZE, ret); | ||
81 | + trace_stream_one_iteration(s, offset, n * BDRV_SECTOR_SIZE, ret); | ||
82 | if (copy) { | ||
83 | - ret = stream_populate(blk, sector_num * BDRV_SECTOR_SIZE, | ||
84 | - n * BDRV_SECTOR_SIZE, buf); | ||
85 | + ret = stream_populate(blk, offset, n * BDRV_SECTOR_SIZE, buf); | ||
86 | } | ||
87 | if (ret < 0) { | ||
88 | BlockErrorAction action = | ||
89 | -- | 74 | -- |
90 | 1.8.3.1 | 75 | 2.37.3 |
91 | |||
92 | diff view generated by jsdifflib |
1 | From: Eric Blake <eblake@redhat.com> | 1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | The user interface specifies job rate limits in bytes/second. | 3 | With "intact" we mean that all job.h functions implicitly |
4 | It's pointless to have our internal representation track things | 4 | take the lock. Therefore API callers are unmodified. |
5 | in sectors/second, particularly since we want to move away from | ||
6 | sector-based interfaces. | ||
7 | 5 | ||
8 | Fix up a doc typo found while verifying that the ratelimit | 6 | This means that: |
9 | code handles the scaling difference. | 7 | - many static functions that will be always called with job lock held |
8 | become _locked, and call _locked functions | ||
9 | - all public functions take the lock internally if needed, and call _locked | ||
10 | functions | ||
11 | - all public functions called internally by other functions in job.c will have a | ||
12 | _locked counterpart (sometimes public), to avoid deadlocks (job lock already taken). | ||
13 | These functions are not used for now. | ||
14 | - some public functions called only from exernal files (not job.c) do not | ||
15 | have _locked() counterpart and take the lock inside. Others won't need | ||
16 | the lock at all because use fields only set at initialization and | ||
17 | never modified. | ||
10 | 18 | ||
11 | Repetition of expressions like 'n * BDRV_SECTOR_SIZE' will be | 19 | job_{lock/unlock} is independent from real_job_{lock/unlock}. |
12 | cleaned up later when functions are converted to iterate over | ||
13 | images by bytes rather than by sectors. | ||
14 | 20 | ||
15 | Signed-off-by: Eric Blake <eblake@redhat.com> | 21 | Note: at this stage, job_{lock/unlock} and job lock guard macros |
16 | Reviewed-by: John Snow <jsnow@redhat.com> | 22 | are *nop* |
17 | Reviewed-by: Jeff Cody <jcody@redhat.com> | 23 | |
24 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
18 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | 25 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> |
26 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
27 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> | ||
28 | Message-Id: <20220926093214.506243-6-eesposit@redhat.com> | ||
19 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 29 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
20 | --- | 30 | --- |
21 | block/backup.c | 5 +++-- | 31 | include/qemu/job.h | 138 +++++++++- |
22 | block/commit.c | 5 +++-- | 32 | job.c | 610 ++++++++++++++++++++++++++++++++------------- |
23 | block/mirror.c | 13 +++++++------ | 33 | 2 files changed, 561 insertions(+), 187 deletions(-) |
24 | block/stream.c | 5 +++-- | ||
25 | include/qemu/ratelimit.h | 3 ++- | ||
26 | 5 files changed, 18 insertions(+), 13 deletions(-) | ||
27 | 34 | ||
28 | diff --git a/block/backup.c b/block/backup.c | 35 | diff --git a/include/qemu/job.h b/include/qemu/job.h |
29 | index XXXXXXX..XXXXXXX 100644 | 36 | index XXXXXXX..XXXXXXX 100644 |
30 | --- a/block/backup.c | 37 | --- a/include/qemu/job.h |
31 | +++ b/block/backup.c | 38 | +++ b/include/qemu/job.h |
32 | @@ -XXX,XX +XXX,XX @@ static void backup_set_speed(BlockJob *job, int64_t speed, Error **errp) | 39 | @@ -XXX,XX +XXX,XX @@ JobTxn *job_txn_new(void); |
33 | error_setg(errp, QERR_INVALID_PARAMETER, "speed"); | 40 | */ |
41 | void job_txn_unref(JobTxn *txn); | ||
42 | |||
43 | +/* | ||
44 | + * Same as job_txn_unref(), but called with job lock held. | ||
45 | + * Might release the lock temporarily. | ||
46 | + */ | ||
47 | +void job_txn_unref_locked(JobTxn *txn); | ||
48 | + | ||
49 | /** | ||
50 | * Create a new long-running job and return it. | ||
51 | + * Called with job_mutex *not* held. | ||
52 | * | ||
53 | * @job_id: The id of the newly-created job, or %NULL for internal jobs | ||
54 | * @driver: The class object for the newly-created job. | ||
55 | @@ -XXX,XX +XXX,XX @@ void *job_create(const char *job_id, const JobDriver *driver, JobTxn *txn, | ||
56 | */ | ||
57 | void job_ref(Job *job); | ||
58 | |||
59 | +/* Same as job_ref(), but called with job lock held. */ | ||
60 | +void job_ref_locked(Job *job); | ||
61 | + | ||
62 | /** | ||
63 | * Release a reference that was previously acquired with job_ref() or | ||
64 | * job_create(). If it's the last reference to the object, it will be freed. | ||
65 | */ | ||
66 | void job_unref(Job *job); | ||
67 | |||
68 | +/* Same as job_unref(), but called with job lock held. */ | ||
69 | +void job_unref_locked(Job *job); | ||
70 | + | ||
71 | /** | ||
72 | * @job: The job that has made progress | ||
73 | * @done: How much progress the job made since the last call | ||
74 | * | ||
75 | * Updates the progress counter of the job. | ||
76 | + * | ||
77 | + * May be called with mutex held or not held. | ||
78 | */ | ||
79 | void job_progress_update(Job *job, uint64_t done); | ||
80 | |||
81 | @@ -XXX,XX +XXX,XX @@ void job_progress_update(Job *job, uint64_t done); | ||
82 | * | ||
83 | * Sets the expected end value of the progress counter of a job so that a | ||
84 | * completion percentage can be calculated when the progress is updated. | ||
85 | + * | ||
86 | + * May be called with mutex held or not held. | ||
87 | */ | ||
88 | void job_progress_set_remaining(Job *job, uint64_t remaining); | ||
89 | |||
90 | @@ -XXX,XX +XXX,XX @@ void job_progress_set_remaining(Job *job, uint64_t remaining); | ||
91 | * length before, and job_progress_update() afterwards. | ||
92 | * (So the operation acts as a parenthesis in regards to the main job | ||
93 | * operation running in background.) | ||
94 | + * | ||
95 | + * May be called with mutex held or not held. | ||
96 | */ | ||
97 | void job_progress_increase_remaining(Job *job, uint64_t delta); | ||
98 | |||
99 | @@ -XXX,XX +XXX,XX @@ void job_progress_increase_remaining(Job *job, uint64_t delta); | ||
100 | */ | ||
101 | void job_enter_cond(Job *job, bool(*fn)(Job *job)); | ||
102 | |||
103 | +/* | ||
104 | + * Same as job_enter_cond(), but called with job lock held. | ||
105 | + * Might release the lock temporarily. | ||
106 | + */ | ||
107 | +void job_enter_cond_locked(Job *job, bool(*fn)(Job *job)); | ||
108 | + | ||
109 | /** | ||
110 | * @job: A job that has not yet been started. | ||
111 | * | ||
112 | * Begins execution of a job. | ||
113 | * Takes ownership of one reference to the job object. | ||
114 | + * | ||
115 | + * Called with job_mutex *not* held. | ||
116 | */ | ||
117 | void job_start(Job *job); | ||
118 | |||
119 | @@ -XXX,XX +XXX,XX @@ void job_start(Job *job); | ||
120 | * @job: The job to enter. | ||
121 | * | ||
122 | * Continue the specified job by entering the coroutine. | ||
123 | + * Called with job_mutex *not* held. | ||
124 | */ | ||
125 | void job_enter(Job *job); | ||
126 | |||
127 | @@ -XXX,XX +XXX,XX @@ void job_enter(Job *job); | ||
128 | * | ||
129 | * Pause now if job_pause() has been called. Jobs that perform lots of I/O | ||
130 | * must call this between requests so that the job can be paused. | ||
131 | + * | ||
132 | + * Called with job_mutex *not* held. | ||
133 | */ | ||
134 | void coroutine_fn job_pause_point(Job *job); | ||
135 | |||
136 | @@ -XXX,XX +XXX,XX @@ void coroutine_fn job_pause_point(Job *job); | ||
137 | * @job: The job that calls the function. | ||
138 | * | ||
139 | * Yield the job coroutine. | ||
140 | + * Called with job_mutex *not* held. | ||
141 | */ | ||
142 | void coroutine_fn job_yield(Job *job); | ||
143 | |||
144 | @@ -XXX,XX +XXX,XX @@ void coroutine_fn job_yield(Job *job); | ||
145 | * Put the job to sleep (assuming that it wasn't canceled) for @ns | ||
146 | * %QEMU_CLOCK_REALTIME nanoseconds. Canceling the job will immediately | ||
147 | * interrupt the wait. | ||
148 | + * | ||
149 | + * Called with job_mutex *not* held. | ||
150 | */ | ||
151 | void coroutine_fn job_sleep_ns(Job *job, int64_t ns); | ||
152 | |||
153 | @@ -XXX,XX +XXX,XX @@ const char *job_type_str(const Job *job); | ||
154 | /** Returns true if the job should not be visible to the management layer. */ | ||
155 | bool job_is_internal(Job *job); | ||
156 | |||
157 | -/** Returns whether the job is being cancelled. */ | ||
158 | +/** | ||
159 | + * Returns whether the job is being cancelled. | ||
160 | + * Called with job_mutex *not* held. | ||
161 | + */ | ||
162 | bool job_is_cancelled(Job *job); | ||
163 | |||
164 | +/* Same as job_is_cancelled(), but called with job lock held. */ | ||
165 | +bool job_is_cancelled_locked(Job *job); | ||
166 | + | ||
167 | /** | ||
168 | * Returns whether the job is scheduled for cancellation (at an | ||
169 | * indefinite point). | ||
170 | + * Called with job_mutex *not* held. | ||
171 | */ | ||
172 | bool job_cancel_requested(Job *job); | ||
173 | |||
174 | -/** Returns whether the job is in a completed state. */ | ||
175 | +/** | ||
176 | + * Returns whether the job is in a completed state. | ||
177 | + * Called with job_mutex *not* held. | ||
178 | + */ | ||
179 | bool job_is_completed(Job *job); | ||
180 | |||
181 | -/** Returns whether the job is ready to be completed. */ | ||
182 | +/* Same as job_is_completed(), but called with job lock held. */ | ||
183 | +bool job_is_completed_locked(Job *job); | ||
184 | + | ||
185 | +/** | ||
186 | + * Returns whether the job is ready to be completed. | ||
187 | + * Called with job_mutex *not* held. | ||
188 | + */ | ||
189 | bool job_is_ready(Job *job); | ||
190 | |||
191 | +/* Same as job_is_ready(), but called with job lock held. */ | ||
192 | +bool job_is_ready_locked(Job *job); | ||
193 | + | ||
194 | /** | ||
195 | * Request @job to pause at the next pause point. Must be paired with | ||
196 | * job_resume(). If the job is supposed to be resumed by user action, call | ||
197 | @@ -XXX,XX +XXX,XX @@ bool job_is_ready(Job *job); | ||
198 | */ | ||
199 | void job_pause(Job *job); | ||
200 | |||
201 | +/* Same as job_pause(), but called with job lock held. */ | ||
202 | +void job_pause_locked(Job *job); | ||
203 | + | ||
204 | /** Resumes a @job paused with job_pause. */ | ||
205 | void job_resume(Job *job); | ||
206 | |||
207 | +/* | ||
208 | + * Same as job_resume(), but called with job lock held. | ||
209 | + * Might release the lock temporarily. | ||
210 | + */ | ||
211 | +void job_resume_locked(Job *job); | ||
212 | + | ||
213 | /** | ||
214 | * Asynchronously pause the specified @job. | ||
215 | * Do not allow a resume until a matching call to job_user_resume. | ||
216 | */ | ||
217 | void job_user_pause(Job *job, Error **errp); | ||
218 | |||
219 | +/* Same as job_user_pause(), but called with job lock held. */ | ||
220 | +void job_user_pause_locked(Job *job, Error **errp); | ||
221 | + | ||
222 | /** Returns true if the job is user-paused. */ | ||
223 | bool job_user_paused(Job *job); | ||
224 | |||
225 | +/* Same as job_user_paused(), but called with job lock held. */ | ||
226 | +bool job_user_paused_locked(Job *job); | ||
227 | + | ||
228 | /** | ||
229 | * Resume the specified @job. | ||
230 | * Must be paired with a preceding job_user_pause. | ||
231 | */ | ||
232 | void job_user_resume(Job *job, Error **errp); | ||
233 | |||
234 | +/* | ||
235 | + * Same as job_user_resume(), but called with job lock held. | ||
236 | + * Might release the lock temporarily. | ||
237 | + */ | ||
238 | +void job_user_resume_locked(Job *job, Error **errp); | ||
239 | + | ||
240 | /** | ||
241 | * Get the next element from the list of block jobs after @job, or the | ||
242 | * first one if @job is %NULL. | ||
243 | @@ -XXX,XX +XXX,XX @@ void job_user_resume(Job *job, Error **errp); | ||
244 | */ | ||
245 | Job *job_next(Job *job); | ||
246 | |||
247 | +/* Same as job_next(), but called with job lock held. */ | ||
248 | +Job *job_next_locked(Job *job); | ||
249 | + | ||
250 | /** | ||
251 | * Get the job identified by @id (which must not be %NULL). | ||
252 | * | ||
253 | @@ -XXX,XX +XXX,XX @@ Job *job_next(Job *job); | ||
254 | */ | ||
255 | Job *job_get(const char *id); | ||
256 | |||
257 | +/* Same as job_get(), but called with job lock held. */ | ||
258 | +Job *job_get_locked(const char *id); | ||
259 | + | ||
260 | /** | ||
261 | * Check whether the verb @verb can be applied to @job in its current state. | ||
262 | * Returns 0 if the verb can be applied; otherwise errp is set and -EPERM | ||
263 | @@ -XXX,XX +XXX,XX @@ Job *job_get(const char *id); | ||
264 | */ | ||
265 | int job_apply_verb(Job *job, JobVerb verb, Error **errp); | ||
266 | |||
267 | -/** The @job could not be started, free it. */ | ||
268 | +/* Same as job_apply_verb, but called with job lock held. */ | ||
269 | +int job_apply_verb_locked(Job *job, JobVerb verb, Error **errp); | ||
270 | + | ||
271 | +/** | ||
272 | + * The @job could not be started, free it. | ||
273 | + * Called with job_mutex *not* held. | ||
274 | + */ | ||
275 | void job_early_fail(Job *job); | ||
276 | |||
277 | -/** Moves the @job from RUNNING to READY */ | ||
278 | +/** | ||
279 | + * Moves the @job from RUNNING to READY. | ||
280 | + * Called with job_mutex *not* held. | ||
281 | + */ | ||
282 | void job_transition_to_ready(Job *job); | ||
283 | |||
284 | /** Asynchronously complete the specified @job. */ | ||
285 | void job_complete(Job *job, Error **errp); | ||
286 | |||
287 | +/* | ||
288 | + * Same as job_complete(), but called with job lock held. | ||
289 | + * Might release the lock temporarily. | ||
290 | + */ | ||
291 | +void job_complete_locked(Job *job, Error **errp); | ||
292 | + | ||
293 | /** | ||
294 | * Asynchronously cancel the specified @job. If @force is true, the job should | ||
295 | * be cancelled immediately without waiting for a consistent state. | ||
296 | */ | ||
297 | void job_cancel(Job *job, bool force); | ||
298 | |||
299 | +/* Same as job_cancel(), but called with job lock held. */ | ||
300 | +void job_cancel_locked(Job *job, bool force); | ||
301 | + | ||
302 | /** | ||
303 | * Cancels the specified job like job_cancel(), but may refuse to do so if the | ||
304 | * operation isn't meaningful in the current state of the job. | ||
305 | */ | ||
306 | void job_user_cancel(Job *job, bool force, Error **errp); | ||
307 | |||
308 | +/* Same as job_user_cancel(), but called with job lock held. */ | ||
309 | +void job_user_cancel_locked(Job *job, bool force, Error **errp); | ||
310 | + | ||
311 | /** | ||
312 | * Synchronously cancel the @job. The completion callback is called | ||
313 | * before the function returns. If @force is false, the job may | ||
314 | @@ -XXX,XX +XXX,XX @@ void job_user_cancel(Job *job, bool force, Error **errp); | ||
315 | */ | ||
316 | int job_cancel_sync(Job *job, bool force); | ||
317 | |||
318 | -/** Synchronously force-cancels all jobs using job_cancel_sync(). */ | ||
319 | +/* Same as job_cancel_sync, but called with job lock held. */ | ||
320 | +int job_cancel_sync_locked(Job *job, bool force); | ||
321 | + | ||
322 | +/** | ||
323 | + * Synchronously force-cancels all jobs using job_cancel_sync_locked(). | ||
324 | + * | ||
325 | + * Called with job_lock *not* held. | ||
326 | + */ | ||
327 | void job_cancel_sync_all(void); | ||
328 | |||
329 | /** | ||
330 | @@ -XXX,XX +XXX,XX @@ void job_cancel_sync_all(void); | ||
331 | */ | ||
332 | int job_complete_sync(Job *job, Error **errp); | ||
333 | |||
334 | +/* Same as job_complete_sync, but called with job lock held. */ | ||
335 | +int job_complete_sync_locked(Job *job, Error **errp); | ||
336 | + | ||
337 | /** | ||
338 | * For a @job that has finished its work and is pending awaiting explicit | ||
339 | * acknowledgement to commit its work, this will commit that work. | ||
340 | @@ -XXX,XX +XXX,XX @@ int job_complete_sync(Job *job, Error **errp); | ||
341 | */ | ||
342 | void job_finalize(Job *job, Error **errp); | ||
343 | |||
344 | +/* Same as job_finalize(), but called with job lock held. */ | ||
345 | +void job_finalize_locked(Job *job, Error **errp); | ||
346 | + | ||
347 | /** | ||
348 | * Remove the concluded @job from the query list and resets the passed pointer | ||
349 | * to %NULL. Returns an error if the job is not actually concluded. | ||
350 | */ | ||
351 | void job_dismiss(Job **job, Error **errp); | ||
352 | |||
353 | +/* Same as job_dismiss(), but called with job lock held. */ | ||
354 | +void job_dismiss_locked(Job **job, Error **errp); | ||
355 | + | ||
356 | /** | ||
357 | * Synchronously finishes the given @job. If @finish is given, it is called to | ||
358 | * trigger completion or cancellation of the job. | ||
359 | @@ -XXX,XX +XXX,XX @@ void job_dismiss(Job **job, Error **errp); | ||
360 | * | ||
361 | * Callers must hold the AioContext lock of job->aio_context. | ||
362 | */ | ||
363 | -int job_finish_sync(Job *job, void (*finish)(Job *, Error **errp), Error **errp); | ||
364 | +int job_finish_sync(Job *job, void (*finish)(Job *, Error **errp), | ||
365 | + Error **errp); | ||
366 | + | ||
367 | +/* | ||
368 | + * Same as job_finish_sync(), but called with job lock held. | ||
369 | + * Might release the lock temporarily. | ||
370 | + */ | ||
371 | +int job_finish_sync_locked(Job *job, void (*finish)(Job *, Error **errp), | ||
372 | + Error **errp); | ||
373 | |||
374 | #endif | ||
375 | diff --git a/job.c b/job.c | ||
376 | index XXXXXXX..XXXXXXX 100644 | ||
377 | --- a/job.c | ||
378 | +++ b/job.c | ||
379 | @@ -XXX,XX +XXX,XX @@ | ||
380 | */ | ||
381 | QemuMutex job_mutex; | ||
382 | |||
383 | +/* Protected by job_mutex */ | ||
384 | static QLIST_HEAD(, Job) jobs = QLIST_HEAD_INITIALIZER(jobs); | ||
385 | |||
386 | /* Job State Transition Table */ | ||
387 | @@ -XXX,XX +XXX,XX @@ JobTxn *job_txn_new(void) | ||
388 | return txn; | ||
389 | } | ||
390 | |||
391 | -static void job_txn_ref(JobTxn *txn) | ||
392 | +/* Called with job_mutex held. */ | ||
393 | +static void job_txn_ref_locked(JobTxn *txn) | ||
394 | { | ||
395 | txn->refcnt++; | ||
396 | } | ||
397 | |||
398 | -void job_txn_unref(JobTxn *txn) | ||
399 | +void job_txn_unref_locked(JobTxn *txn) | ||
400 | { | ||
401 | if (txn && --txn->refcnt == 0) { | ||
402 | g_free(txn); | ||
403 | } | ||
404 | } | ||
405 | |||
406 | +void job_txn_unref(JobTxn *txn) | ||
407 | +{ | ||
408 | + JOB_LOCK_GUARD(); | ||
409 | + job_txn_unref_locked(txn); | ||
410 | +} | ||
411 | + | ||
412 | /** | ||
413 | * @txn: The transaction (may be NULL) | ||
414 | * @job: Job to add to the transaction | ||
415 | @@ -XXX,XX +XXX,XX @@ void job_txn_unref(JobTxn *txn) | ||
416 | * the reference that is automatically grabbed here. | ||
417 | * | ||
418 | * If @txn is NULL, the function does nothing. | ||
419 | + * | ||
420 | + * Called with job_mutex held. | ||
421 | */ | ||
422 | -static void job_txn_add_job(JobTxn *txn, Job *job) | ||
423 | +static void job_txn_add_job_locked(JobTxn *txn, Job *job) | ||
424 | { | ||
425 | if (!txn) { | ||
34 | return; | 426 | return; |
35 | } | 427 | @@ -XXX,XX +XXX,XX @@ static void job_txn_add_job(JobTxn *txn, Job *job) |
36 | - ratelimit_set_speed(&s->limit, speed / BDRV_SECTOR_SIZE, SLICE_TIME); | 428 | job->txn = txn; |
37 | + ratelimit_set_speed(&s->limit, speed, SLICE_TIME); | 429 | |
38 | } | 430 | QLIST_INSERT_HEAD(&txn->jobs, job, txn_list); |
39 | 431 | - job_txn_ref(txn); | |
40 | static void backup_cleanup_sync_bitmap(BackupBlockJob *job, int ret) | 432 | + job_txn_ref_locked(txn); |
41 | @@ -XXX,XX +XXX,XX @@ static bool coroutine_fn yield_and_check(BackupBlockJob *job) | 433 | } |
434 | |||
435 | -static void job_txn_del_job(Job *job) | ||
436 | +/* Called with job_mutex held. */ | ||
437 | +static void job_txn_del_job_locked(Job *job) | ||
438 | { | ||
439 | if (job->txn) { | ||
440 | QLIST_REMOVE(job, txn_list); | ||
441 | - job_txn_unref(job->txn); | ||
442 | + job_txn_unref_locked(job->txn); | ||
443 | job->txn = NULL; | ||
444 | } | ||
445 | } | ||
446 | |||
447 | -static int job_txn_apply(Job *job, int fn(Job *)) | ||
448 | +/* Called with job_mutex held, but releases it temporarily. */ | ||
449 | +static int job_txn_apply_locked(Job *job, int fn(Job *)) | ||
450 | { | ||
451 | AioContext *inner_ctx; | ||
452 | Job *other_job, *next; | ||
453 | @@ -XXX,XX +XXX,XX @@ static int job_txn_apply(Job *job, int fn(Job *)) | ||
454 | * we need to release it here to avoid holding the lock twice - which would | ||
455 | * break AIO_WAIT_WHILE from within fn. | ||
42 | */ | 456 | */ |
43 | if (job->common.speed) { | 457 | - job_ref(job); |
44 | uint64_t delay_ns = ratelimit_calculate_delay(&job->limit, | 458 | + job_ref_locked(job); |
45 | - job->sectors_read); | 459 | aio_context_release(job->aio_context); |
46 | + job->sectors_read * | 460 | |
47 | + BDRV_SECTOR_SIZE); | 461 | QLIST_FOREACH_SAFE(other_job, &txn->jobs, txn_list, next) { |
48 | job->sectors_read = 0; | 462 | @@ -XXX,XX +XXX,XX @@ static int job_txn_apply(Job *job, int fn(Job *)) |
49 | block_job_sleep_ns(&job->common, QEMU_CLOCK_REALTIME, delay_ns); | 463 | * can't use a local variable to cache it. |
464 | */ | ||
465 | aio_context_acquire(job->aio_context); | ||
466 | - job_unref(job); | ||
467 | + job_unref_locked(job); | ||
468 | return rc; | ||
469 | } | ||
470 | |||
471 | @@ -XXX,XX +XXX,XX @@ bool job_is_internal(Job *job) | ||
472 | return (job->id == NULL); | ||
473 | } | ||
474 | |||
475 | -static void job_state_transition(Job *job, JobStatus s1) | ||
476 | +/* Called with job_mutex held. */ | ||
477 | +static void job_state_transition_locked(Job *job, JobStatus s1) | ||
478 | { | ||
479 | JobStatus s0 = job->status; | ||
480 | assert(s1 >= 0 && s1 < JOB_STATUS__MAX); | ||
481 | @@ -XXX,XX +XXX,XX @@ static void job_state_transition(Job *job, JobStatus s1) | ||
482 | } | ||
483 | } | ||
484 | |||
485 | -int job_apply_verb(Job *job, JobVerb verb, Error **errp) | ||
486 | +int job_apply_verb_locked(Job *job, JobVerb verb, Error **errp) | ||
487 | { | ||
488 | JobStatus s0 = job->status; | ||
489 | assert(verb >= 0 && verb < JOB_VERB__MAX); | ||
490 | @@ -XXX,XX +XXX,XX @@ int job_apply_verb(Job *job, JobVerb verb, Error **errp) | ||
491 | return -EPERM; | ||
492 | } | ||
493 | |||
494 | +int job_apply_verb(Job *job, JobVerb verb, Error **errp) | ||
495 | +{ | ||
496 | + JOB_LOCK_GUARD(); | ||
497 | + return job_apply_verb_locked(job, verb, errp); | ||
498 | +} | ||
499 | + | ||
500 | JobType job_type(const Job *job) | ||
501 | { | ||
502 | return job->driver->job_type; | ||
503 | @@ -XXX,XX +XXX,XX @@ const char *job_type_str(const Job *job) | ||
504 | return JobType_str(job_type(job)); | ||
505 | } | ||
506 | |||
507 | -bool job_is_cancelled(Job *job) | ||
508 | +bool job_is_cancelled_locked(Job *job) | ||
509 | { | ||
510 | /* force_cancel may be true only if cancelled is true, too */ | ||
511 | assert(job->cancelled || !job->force_cancel); | ||
512 | return job->force_cancel; | ||
513 | } | ||
514 | |||
515 | -bool job_cancel_requested(Job *job) | ||
516 | +bool job_is_cancelled(Job *job) | ||
517 | +{ | ||
518 | + JOB_LOCK_GUARD(); | ||
519 | + return job_is_cancelled_locked(job); | ||
520 | +} | ||
521 | + | ||
522 | +/* Called with job_mutex held. */ | ||
523 | +static bool job_cancel_requested_locked(Job *job) | ||
524 | { | ||
525 | return job->cancelled; | ||
526 | } | ||
527 | |||
528 | -bool job_is_ready(Job *job) | ||
529 | +bool job_cancel_requested(Job *job) | ||
530 | +{ | ||
531 | + JOB_LOCK_GUARD(); | ||
532 | + return job_cancel_requested_locked(job); | ||
533 | +} | ||
534 | + | ||
535 | +bool job_is_ready_locked(Job *job) | ||
536 | { | ||
537 | switch (job->status) { | ||
538 | case JOB_STATUS_UNDEFINED: | ||
539 | @@ -XXX,XX +XXX,XX @@ bool job_is_ready(Job *job) | ||
540 | return false; | ||
541 | } | ||
542 | |||
543 | -bool job_is_completed(Job *job) | ||
544 | +bool job_is_ready(Job *job) | ||
545 | +{ | ||
546 | + JOB_LOCK_GUARD(); | ||
547 | + return job_is_ready_locked(job); | ||
548 | +} | ||
549 | + | ||
550 | +bool job_is_completed_locked(Job *job) | ||
551 | { | ||
552 | switch (job->status) { | ||
553 | case JOB_STATUS_UNDEFINED: | ||
554 | @@ -XXX,XX +XXX,XX @@ bool job_is_completed(Job *job) | ||
555 | return false; | ||
556 | } | ||
557 | |||
558 | -static bool job_started(Job *job) | ||
559 | +bool job_is_completed(Job *job) | ||
560 | +{ | ||
561 | + JOB_LOCK_GUARD(); | ||
562 | + return job_is_completed_locked(job); | ||
563 | +} | ||
564 | + | ||
565 | +static bool job_started_locked(Job *job) | ||
566 | { | ||
567 | return job->co; | ||
568 | } | ||
569 | |||
570 | -static bool job_should_pause(Job *job) | ||
571 | +/* Called with job_mutex held. */ | ||
572 | +static bool job_should_pause_locked(Job *job) | ||
573 | { | ||
574 | return job->pause_count > 0; | ||
575 | } | ||
576 | |||
577 | -Job *job_next(Job *job) | ||
578 | +Job *job_next_locked(Job *job) | ||
579 | { | ||
580 | if (!job) { | ||
581 | return QLIST_FIRST(&jobs); | ||
582 | @@ -XXX,XX +XXX,XX @@ Job *job_next(Job *job) | ||
583 | return QLIST_NEXT(job, job_list); | ||
584 | } | ||
585 | |||
586 | -Job *job_get(const char *id) | ||
587 | +Job *job_next(Job *job) | ||
588 | +{ | ||
589 | + JOB_LOCK_GUARD(); | ||
590 | + return job_next_locked(job); | ||
591 | +} | ||
592 | + | ||
593 | +Job *job_get_locked(const char *id) | ||
594 | { | ||
595 | Job *job; | ||
596 | |||
597 | @@ -XXX,XX +XXX,XX @@ Job *job_get(const char *id) | ||
598 | return NULL; | ||
599 | } | ||
600 | |||
601 | +Job *job_get(const char *id) | ||
602 | +{ | ||
603 | + JOB_LOCK_GUARD(); | ||
604 | + return job_get_locked(id); | ||
605 | +} | ||
606 | + | ||
607 | +/* Called with job_mutex *not* held. */ | ||
608 | static void job_sleep_timer_cb(void *opaque) | ||
609 | { | ||
610 | Job *job = opaque; | ||
611 | @@ -XXX,XX +XXX,XX @@ void *job_create(const char *job_id, const JobDriver *driver, JobTxn *txn, | ||
612 | { | ||
613 | Job *job; | ||
614 | |||
615 | + JOB_LOCK_GUARD(); | ||
616 | + | ||
617 | if (job_id) { | ||
618 | if (flags & JOB_INTERNAL) { | ||
619 | error_setg(errp, "Cannot specify job ID for internal job"); | ||
620 | @@ -XXX,XX +XXX,XX @@ void *job_create(const char *job_id, const JobDriver *driver, JobTxn *txn, | ||
621 | error_setg(errp, "Invalid job ID '%s'", job_id); | ||
622 | return NULL; | ||
623 | } | ||
624 | - if (job_get(job_id)) { | ||
625 | + if (job_get_locked(job_id)) { | ||
626 | error_setg(errp, "Job ID '%s' already in use", job_id); | ||
627 | return NULL; | ||
628 | } | ||
629 | @@ -XXX,XX +XXX,XX @@ void *job_create(const char *job_id, const JobDriver *driver, JobTxn *txn, | ||
630 | notifier_list_init(&job->on_ready); | ||
631 | notifier_list_init(&job->on_idle); | ||
632 | |||
633 | - job_state_transition(job, JOB_STATUS_CREATED); | ||
634 | + job_state_transition_locked(job, JOB_STATUS_CREATED); | ||
635 | aio_timer_init(qemu_get_aio_context(), &job->sleep_timer, | ||
636 | QEMU_CLOCK_REALTIME, SCALE_NS, | ||
637 | job_sleep_timer_cb, job); | ||
638 | @@ -XXX,XX +XXX,XX @@ void *job_create(const char *job_id, const JobDriver *driver, JobTxn *txn, | ||
639 | * consolidating the job management logic */ | ||
640 | if (!txn) { | ||
641 | txn = job_txn_new(); | ||
642 | - job_txn_add_job(txn, job); | ||
643 | - job_txn_unref(txn); | ||
644 | + job_txn_add_job_locked(txn, job); | ||
645 | + job_txn_unref_locked(txn); | ||
50 | } else { | 646 | } else { |
51 | diff --git a/block/commit.c b/block/commit.c | 647 | - job_txn_add_job(txn, job); |
52 | index XXXXXXX..XXXXXXX 100644 | 648 | + job_txn_add_job_locked(txn, job); |
53 | --- a/block/commit.c | 649 | } |
54 | +++ b/block/commit.c | 650 | |
55 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn commit_run(void *opaque) | 651 | return job; |
56 | s->common.offset += n * BDRV_SECTOR_SIZE; | 652 | } |
57 | 653 | ||
58 | if (copy && s->common.speed) { | 654 | -void job_ref(Job *job) |
59 | - delay_ns = ratelimit_calculate_delay(&s->limit, n); | 655 | +void job_ref_locked(Job *job) |
60 | + delay_ns = ratelimit_calculate_delay(&s->limit, | 656 | { |
61 | + n * BDRV_SECTOR_SIZE); | 657 | ++job->refcnt; |
658 | } | ||
659 | |||
660 | -void job_unref(Job *job) | ||
661 | +void job_ref(Job *job) | ||
662 | +{ | ||
663 | + JOB_LOCK_GUARD(); | ||
664 | + job_ref_locked(job); | ||
665 | +} | ||
666 | + | ||
667 | +void job_unref_locked(Job *job) | ||
668 | { | ||
669 | GLOBAL_STATE_CODE(); | ||
670 | |||
671 | @@ -XXX,XX +XXX,XX @@ void job_unref(Job *job) | ||
672 | assert(!job->txn); | ||
673 | |||
674 | if (job->driver->free) { | ||
675 | + job_unlock(); | ||
676 | job->driver->free(job); | ||
677 | + job_lock(); | ||
62 | } | 678 | } |
63 | } | 679 | |
64 | 680 | QLIST_REMOVE(job, job_list); | |
65 | @@ -XXX,XX +XXX,XX @@ static void commit_set_speed(BlockJob *job, int64_t speed, Error **errp) | 681 | @@ -XXX,XX +XXX,XX @@ void job_unref(Job *job) |
66 | error_setg(errp, QERR_INVALID_PARAMETER, "speed"); | 682 | } |
683 | } | ||
684 | |||
685 | +void job_unref(Job *job) | ||
686 | +{ | ||
687 | + JOB_LOCK_GUARD(); | ||
688 | + job_unref_locked(job); | ||
689 | +} | ||
690 | + | ||
691 | void job_progress_update(Job *job, uint64_t done) | ||
692 | { | ||
693 | progress_work_done(&job->progress, done); | ||
694 | @@ -XXX,XX +XXX,XX @@ void job_progress_increase_remaining(Job *job, uint64_t delta) | ||
695 | |||
696 | /** | ||
697 | * To be called when a cancelled job is finalised. | ||
698 | + * Called with job_mutex held. | ||
699 | */ | ||
700 | -static void job_event_cancelled(Job *job) | ||
701 | +static void job_event_cancelled_locked(Job *job) | ||
702 | { | ||
703 | notifier_list_notify(&job->on_finalize_cancelled, job); | ||
704 | } | ||
705 | |||
706 | /** | ||
707 | * To be called when a successfully completed job is finalised. | ||
708 | + * Called with job_mutex held. | ||
709 | */ | ||
710 | -static void job_event_completed(Job *job) | ||
711 | +static void job_event_completed_locked(Job *job) | ||
712 | { | ||
713 | notifier_list_notify(&job->on_finalize_completed, job); | ||
714 | } | ||
715 | |||
716 | -static void job_event_pending(Job *job) | ||
717 | +/* Called with job_mutex held. */ | ||
718 | +static void job_event_pending_locked(Job *job) | ||
719 | { | ||
720 | notifier_list_notify(&job->on_pending, job); | ||
721 | } | ||
722 | |||
723 | -static void job_event_ready(Job *job) | ||
724 | +/* Called with job_mutex held. */ | ||
725 | +static void job_event_ready_locked(Job *job) | ||
726 | { | ||
727 | notifier_list_notify(&job->on_ready, job); | ||
728 | } | ||
729 | |||
730 | -static void job_event_idle(Job *job) | ||
731 | +/* Called with job_mutex held. */ | ||
732 | +static void job_event_idle_locked(Job *job) | ||
733 | { | ||
734 | notifier_list_notify(&job->on_idle, job); | ||
735 | } | ||
736 | |||
737 | -void job_enter_cond(Job *job, bool(*fn)(Job *job)) | ||
738 | +void job_enter_cond_locked(Job *job, bool(*fn)(Job *job)) | ||
739 | { | ||
740 | - if (!job_started(job)) { | ||
741 | + if (!job_started_locked(job)) { | ||
67 | return; | 742 | return; |
68 | } | 743 | } |
69 | - ratelimit_set_speed(&s->limit, speed / BDRV_SECTOR_SIZE, SLICE_TIME); | 744 | if (job->deferred_to_main_loop) { |
70 | + ratelimit_set_speed(&s->limit, speed, SLICE_TIME); | 745 | @@ -XXX,XX +XXX,XX @@ void job_enter_cond(Job *job, bool(*fn)(Job *job)) |
71 | } | 746 | timer_del(&job->sleep_timer); |
72 | 747 | job->busy = true; | |
73 | static const BlockJobDriver commit_job_driver = { | 748 | real_job_unlock(); |
74 | diff --git a/block/mirror.c b/block/mirror.c | 749 | + job_unlock(); |
75 | index XXXXXXX..XXXXXXX 100644 | 750 | aio_co_enter(job->aio_context, job->co); |
76 | --- a/block/mirror.c | 751 | + job_lock(); |
77 | +++ b/block/mirror.c | 752 | +} |
78 | @@ -XXX,XX +XXX,XX @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s) | 753 | + |
79 | bitmap_set(s->in_flight_bitmap, sector_num / sectors_per_chunk, nb_chunks); | 754 | +void job_enter_cond(Job *job, bool(*fn)(Job *job)) |
80 | while (nb_chunks > 0 && sector_num < end) { | 755 | +{ |
81 | int64_t ret; | 756 | + JOB_LOCK_GUARD(); |
82 | - int io_sectors, io_sectors_acct; | 757 | + job_enter_cond_locked(job, fn); |
83 | + int io_sectors; | 758 | } |
84 | + int64_t io_bytes_acct; | 759 | |
85 | BlockDriverState *file; | 760 | void job_enter(Job *job) |
86 | enum MirrorMethod { | 761 | { |
87 | MIRROR_METHOD_COPY, | 762 | - job_enter_cond(job, NULL); |
88 | @@ -XXX,XX +XXX,XX @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s) | 763 | + JOB_LOCK_GUARD(); |
89 | switch (mirror_method) { | 764 | + job_enter_cond_locked(job, NULL); |
90 | case MIRROR_METHOD_COPY: | 765 | } |
91 | io_sectors = mirror_do_read(s, sector_num, io_sectors); | 766 | |
92 | - io_sectors_acct = io_sectors; | 767 | /* Yield, and schedule a timer to reenter the coroutine after @ns nanoseconds. |
93 | + io_bytes_acct = io_sectors * BDRV_SECTOR_SIZE; | 768 | @@ -XXX,XX +XXX,XX @@ void job_enter(Job *job) |
94 | break; | 769 | * is allowed and cancels the timer. |
95 | case MIRROR_METHOD_ZERO: | 770 | * |
96 | case MIRROR_METHOD_DISCARD: | 771 | * If @ns is (uint64_t) -1, no timer is scheduled and job_enter() must be |
97 | mirror_do_zero_or_discard(s, sector_num, io_sectors, | 772 | - * called explicitly. */ |
98 | mirror_method == MIRROR_METHOD_DISCARD); | 773 | -static void coroutine_fn job_do_yield(Job *job, uint64_t ns) |
99 | if (write_zeroes_ok) { | 774 | + * called explicitly. |
100 | - io_sectors_acct = 0; | 775 | + * |
101 | + io_bytes_acct = 0; | 776 | + * Called with job_mutex held, but releases it temporarily. |
102 | } else { | 777 | + */ |
103 | - io_sectors_acct = io_sectors; | 778 | +static void coroutine_fn job_do_yield_locked(Job *job, uint64_t ns) |
104 | + io_bytes_acct = io_sectors * BDRV_SECTOR_SIZE; | 779 | { |
105 | } | 780 | real_job_lock(); |
106 | break; | 781 | if (ns != -1) { |
107 | default: | 782 | timer_mod(&job->sleep_timer, ns); |
108 | @@ -XXX,XX +XXX,XX @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s) | 783 | } |
109 | sector_num += io_sectors; | 784 | job->busy = false; |
110 | nb_chunks -= DIV_ROUND_UP(io_sectors, sectors_per_chunk); | 785 | - job_event_idle(job); |
111 | if (s->common.speed) { | 786 | + job_event_idle_locked(job); |
112 | - delay_ns = ratelimit_calculate_delay(&s->limit, io_sectors_acct); | 787 | real_job_unlock(); |
113 | + delay_ns = ratelimit_calculate_delay(&s->limit, io_bytes_acct); | 788 | + job_unlock(); |
789 | qemu_coroutine_yield(); | ||
790 | + job_lock(); | ||
791 | |||
792 | /* Set by job_enter_cond() before re-entering the coroutine. */ | ||
793 | assert(job->busy); | ||
794 | } | ||
795 | |||
796 | -void coroutine_fn job_pause_point(Job *job) | ||
797 | +/* Called with job_mutex held, but releases it temporarily. */ | ||
798 | +static void coroutine_fn job_pause_point_locked(Job *job) | ||
799 | { | ||
800 | - assert(job && job_started(job)); | ||
801 | + assert(job && job_started_locked(job)); | ||
802 | |||
803 | - if (!job_should_pause(job)) { | ||
804 | + if (!job_should_pause_locked(job)) { | ||
805 | return; | ||
806 | } | ||
807 | - if (job_is_cancelled(job)) { | ||
808 | + if (job_is_cancelled_locked(job)) { | ||
809 | return; | ||
810 | } | ||
811 | |||
812 | if (job->driver->pause) { | ||
813 | + job_unlock(); | ||
814 | job->driver->pause(job); | ||
815 | + job_lock(); | ||
816 | } | ||
817 | |||
818 | - if (job_should_pause(job) && !job_is_cancelled(job)) { | ||
819 | + if (job_should_pause_locked(job) && !job_is_cancelled_locked(job)) { | ||
820 | JobStatus status = job->status; | ||
821 | - job_state_transition(job, status == JOB_STATUS_READY | ||
822 | - ? JOB_STATUS_STANDBY | ||
823 | - : JOB_STATUS_PAUSED); | ||
824 | + job_state_transition_locked(job, status == JOB_STATUS_READY | ||
825 | + ? JOB_STATUS_STANDBY | ||
826 | + : JOB_STATUS_PAUSED); | ||
827 | job->paused = true; | ||
828 | - job_do_yield(job, -1); | ||
829 | + job_do_yield_locked(job, -1); | ||
830 | job->paused = false; | ||
831 | - job_state_transition(job, status); | ||
832 | + job_state_transition_locked(job, status); | ||
833 | } | ||
834 | |||
835 | if (job->driver->resume) { | ||
836 | + job_unlock(); | ||
837 | job->driver->resume(job); | ||
838 | + job_lock(); | ||
839 | } | ||
840 | } | ||
841 | |||
842 | -void coroutine_fn job_yield(Job *job) | ||
843 | +void coroutine_fn job_pause_point(Job *job) | ||
844 | +{ | ||
845 | + JOB_LOCK_GUARD(); | ||
846 | + job_pause_point_locked(job); | ||
847 | +} | ||
848 | + | ||
849 | +static void coroutine_fn job_yield_locked(Job *job) | ||
850 | { | ||
851 | assert(job->busy); | ||
852 | |||
853 | /* Check cancellation *before* setting busy = false, too! */ | ||
854 | - if (job_is_cancelled(job)) { | ||
855 | + if (job_is_cancelled_locked(job)) { | ||
856 | return; | ||
857 | } | ||
858 | |||
859 | - if (!job_should_pause(job)) { | ||
860 | - job_do_yield(job, -1); | ||
861 | + if (!job_should_pause_locked(job)) { | ||
862 | + job_do_yield_locked(job, -1); | ||
863 | } | ||
864 | |||
865 | - job_pause_point(job); | ||
866 | + job_pause_point_locked(job); | ||
867 | +} | ||
868 | + | ||
869 | +void coroutine_fn job_yield(Job *job) | ||
870 | +{ | ||
871 | + JOB_LOCK_GUARD(); | ||
872 | + job_yield_locked(job); | ||
873 | } | ||
874 | |||
875 | void coroutine_fn job_sleep_ns(Job *job, int64_t ns) | ||
876 | { | ||
877 | + JOB_LOCK_GUARD(); | ||
878 | assert(job->busy); | ||
879 | |||
880 | /* Check cancellation *before* setting busy = false, too! */ | ||
881 | - if (job_is_cancelled(job)) { | ||
882 | + if (job_is_cancelled_locked(job)) { | ||
883 | return; | ||
884 | } | ||
885 | |||
886 | - if (!job_should_pause(job)) { | ||
887 | - job_do_yield(job, qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + ns); | ||
888 | + if (!job_should_pause_locked(job)) { | ||
889 | + job_do_yield_locked(job, qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + ns); | ||
890 | } | ||
891 | |||
892 | - job_pause_point(job); | ||
893 | + job_pause_point_locked(job); | ||
894 | } | ||
895 | |||
896 | -/* Assumes the block_job_mutex is held */ | ||
897 | -static bool job_timer_not_pending(Job *job) | ||
898 | +/* Assumes the job_mutex is held */ | ||
899 | +static bool job_timer_not_pending_locked(Job *job) | ||
900 | { | ||
901 | return !timer_pending(&job->sleep_timer); | ||
902 | } | ||
903 | |||
904 | -void job_pause(Job *job) | ||
905 | +void job_pause_locked(Job *job) | ||
906 | { | ||
907 | job->pause_count++; | ||
908 | if (!job->paused) { | ||
909 | - job_enter(job); | ||
910 | + job_enter_cond_locked(job, NULL); | ||
911 | } | ||
912 | } | ||
913 | |||
914 | -void job_resume(Job *job) | ||
915 | +void job_pause(Job *job) | ||
916 | +{ | ||
917 | + JOB_LOCK_GUARD(); | ||
918 | + job_pause_locked(job); | ||
919 | +} | ||
920 | + | ||
921 | +void job_resume_locked(Job *job) | ||
922 | { | ||
923 | assert(job->pause_count > 0); | ||
924 | job->pause_count--; | ||
925 | @@ -XXX,XX +XXX,XX @@ void job_resume(Job *job) | ||
926 | } | ||
927 | |||
928 | /* kick only if no timer is pending */ | ||
929 | - job_enter_cond(job, job_timer_not_pending); | ||
930 | + job_enter_cond_locked(job, job_timer_not_pending_locked); | ||
931 | } | ||
932 | |||
933 | -void job_user_pause(Job *job, Error **errp) | ||
934 | +void job_resume(Job *job) | ||
935 | { | ||
936 | - if (job_apply_verb(job, JOB_VERB_PAUSE, errp)) { | ||
937 | + JOB_LOCK_GUARD(); | ||
938 | + job_resume_locked(job); | ||
939 | +} | ||
940 | + | ||
941 | +void job_user_pause_locked(Job *job, Error **errp) | ||
942 | +{ | ||
943 | + if (job_apply_verb_locked(job, JOB_VERB_PAUSE, errp)) { | ||
944 | return; | ||
945 | } | ||
946 | if (job->user_paused) { | ||
947 | @@ -XXX,XX +XXX,XX @@ void job_user_pause(Job *job, Error **errp) | ||
948 | return; | ||
949 | } | ||
950 | job->user_paused = true; | ||
951 | - job_pause(job); | ||
952 | + job_pause_locked(job); | ||
953 | } | ||
954 | |||
955 | -bool job_user_paused(Job *job) | ||
956 | +void job_user_pause(Job *job, Error **errp) | ||
957 | +{ | ||
958 | + JOB_LOCK_GUARD(); | ||
959 | + job_user_pause_locked(job, errp); | ||
960 | +} | ||
961 | + | ||
962 | +bool job_user_paused_locked(Job *job) | ||
963 | { | ||
964 | return job->user_paused; | ||
965 | } | ||
966 | |||
967 | -void job_user_resume(Job *job, Error **errp) | ||
968 | +bool job_user_paused(Job *job) | ||
969 | +{ | ||
970 | + JOB_LOCK_GUARD(); | ||
971 | + return job_user_paused_locked(job); | ||
972 | +} | ||
973 | + | ||
974 | +void job_user_resume_locked(Job *job, Error **errp) | ||
975 | { | ||
976 | assert(job); | ||
977 | GLOBAL_STATE_CODE(); | ||
978 | @@ -XXX,XX +XXX,XX @@ void job_user_resume(Job *job, Error **errp) | ||
979 | error_setg(errp, "Can't resume a job that was not paused"); | ||
980 | return; | ||
981 | } | ||
982 | - if (job_apply_verb(job, JOB_VERB_RESUME, errp)) { | ||
983 | + if (job_apply_verb_locked(job, JOB_VERB_RESUME, errp)) { | ||
984 | return; | ||
985 | } | ||
986 | if (job->driver->user_resume) { | ||
987 | + job_unlock(); | ||
988 | job->driver->user_resume(job); | ||
989 | + job_lock(); | ||
990 | } | ||
991 | job->user_paused = false; | ||
992 | - job_resume(job); | ||
993 | + job_resume_locked(job); | ||
994 | } | ||
995 | |||
996 | -static void job_do_dismiss(Job *job) | ||
997 | +void job_user_resume(Job *job, Error **errp) | ||
998 | +{ | ||
999 | + JOB_LOCK_GUARD(); | ||
1000 | + job_user_resume_locked(job, errp); | ||
1001 | +} | ||
1002 | + | ||
1003 | +/* Called with job_mutex held, but releases it temporarily. */ | ||
1004 | +static void job_do_dismiss_locked(Job *job) | ||
1005 | { | ||
1006 | assert(job); | ||
1007 | job->busy = false; | ||
1008 | job->paused = false; | ||
1009 | job->deferred_to_main_loop = true; | ||
1010 | |||
1011 | - job_txn_del_job(job); | ||
1012 | + job_txn_del_job_locked(job); | ||
1013 | |||
1014 | - job_state_transition(job, JOB_STATUS_NULL); | ||
1015 | - job_unref(job); | ||
1016 | + job_state_transition_locked(job, JOB_STATUS_NULL); | ||
1017 | + job_unref_locked(job); | ||
1018 | } | ||
1019 | |||
1020 | -void job_dismiss(Job **jobptr, Error **errp) | ||
1021 | +void job_dismiss_locked(Job **jobptr, Error **errp) | ||
1022 | { | ||
1023 | Job *job = *jobptr; | ||
1024 | /* similarly to _complete, this is QMP-interface only. */ | ||
1025 | assert(job->id); | ||
1026 | - if (job_apply_verb(job, JOB_VERB_DISMISS, errp)) { | ||
1027 | + if (job_apply_verb_locked(job, JOB_VERB_DISMISS, errp)) { | ||
1028 | return; | ||
1029 | } | ||
1030 | |||
1031 | - job_do_dismiss(job); | ||
1032 | + job_do_dismiss_locked(job); | ||
1033 | *jobptr = NULL; | ||
1034 | } | ||
1035 | |||
1036 | +void job_dismiss(Job **jobptr, Error **errp) | ||
1037 | +{ | ||
1038 | + JOB_LOCK_GUARD(); | ||
1039 | + job_dismiss_locked(jobptr, errp); | ||
1040 | +} | ||
1041 | + | ||
1042 | void job_early_fail(Job *job) | ||
1043 | { | ||
1044 | + JOB_LOCK_GUARD(); | ||
1045 | assert(job->status == JOB_STATUS_CREATED); | ||
1046 | - job_do_dismiss(job); | ||
1047 | + job_do_dismiss_locked(job); | ||
1048 | } | ||
1049 | |||
1050 | -static void job_conclude(Job *job) | ||
1051 | +/* Called with job_mutex held. */ | ||
1052 | +static void job_conclude_locked(Job *job) | ||
1053 | { | ||
1054 | - job_state_transition(job, JOB_STATUS_CONCLUDED); | ||
1055 | - if (job->auto_dismiss || !job_started(job)) { | ||
1056 | - job_do_dismiss(job); | ||
1057 | + job_state_transition_locked(job, JOB_STATUS_CONCLUDED); | ||
1058 | + if (job->auto_dismiss || !job_started_locked(job)) { | ||
1059 | + job_do_dismiss_locked(job); | ||
1060 | } | ||
1061 | } | ||
1062 | |||
1063 | -static void job_update_rc(Job *job) | ||
1064 | +/* Called with job_mutex held. */ | ||
1065 | +static void job_update_rc_locked(Job *job) | ||
1066 | { | ||
1067 | - if (!job->ret && job_is_cancelled(job)) { | ||
1068 | + if (!job->ret && job_is_cancelled_locked(job)) { | ||
1069 | job->ret = -ECANCELED; | ||
1070 | } | ||
1071 | if (job->ret) { | ||
1072 | if (!job->err) { | ||
1073 | error_setg(&job->err, "%s", strerror(-job->ret)); | ||
114 | } | 1074 | } |
115 | } | 1075 | - job_state_transition(job, JOB_STATUS_ABORTING); |
116 | return delay_ns; | 1076 | + job_state_transition_locked(job, JOB_STATUS_ABORTING); |
117 | @@ -XXX,XX +XXX,XX @@ static void mirror_set_speed(BlockJob *job, int64_t speed, Error **errp) | 1077 | } |
118 | error_setg(errp, QERR_INVALID_PARAMETER, "speed"); | 1078 | } |
1079 | |||
1080 | @@ -XXX,XX +XXX,XX @@ static void job_clean(Job *job) | ||
1081 | } | ||
1082 | } | ||
1083 | |||
1084 | -static int job_finalize_single(Job *job) | ||
1085 | +/* Called with job_mutex held, but releases it temporarily */ | ||
1086 | +static int job_finalize_single_locked(Job *job) | ||
1087 | { | ||
1088 | - assert(job_is_completed(job)); | ||
1089 | + int job_ret; | ||
1090 | + | ||
1091 | + assert(job_is_completed_locked(job)); | ||
1092 | |||
1093 | /* Ensure abort is called for late-transactional failures */ | ||
1094 | - job_update_rc(job); | ||
1095 | + job_update_rc_locked(job); | ||
1096 | + | ||
1097 | + job_ret = job->ret; | ||
1098 | + job_unlock(); | ||
1099 | |||
1100 | - if (!job->ret) { | ||
1101 | + if (!job_ret) { | ||
1102 | job_commit(job); | ||
1103 | } else { | ||
1104 | job_abort(job); | ||
1105 | } | ||
1106 | job_clean(job); | ||
1107 | |||
1108 | + job_lock(); | ||
1109 | + | ||
1110 | if (job->cb) { | ||
1111 | - job->cb(job->opaque, job->ret); | ||
1112 | + job_ret = job->ret; | ||
1113 | + job_unlock(); | ||
1114 | + job->cb(job->opaque, job_ret); | ||
1115 | + job_lock(); | ||
1116 | } | ||
1117 | |||
1118 | /* Emit events only if we actually started */ | ||
1119 | - if (job_started(job)) { | ||
1120 | - if (job_is_cancelled(job)) { | ||
1121 | - job_event_cancelled(job); | ||
1122 | + if (job_started_locked(job)) { | ||
1123 | + if (job_is_cancelled_locked(job)) { | ||
1124 | + job_event_cancelled_locked(job); | ||
1125 | } else { | ||
1126 | - job_event_completed(job); | ||
1127 | + job_event_completed_locked(job); | ||
1128 | } | ||
1129 | } | ||
1130 | |||
1131 | - job_txn_del_job(job); | ||
1132 | - job_conclude(job); | ||
1133 | + job_txn_del_job_locked(job); | ||
1134 | + job_conclude_locked(job); | ||
1135 | return 0; | ||
1136 | } | ||
1137 | |||
1138 | -static void job_cancel_async(Job *job, bool force) | ||
1139 | +/* Called with job_mutex held, but releases it temporarily */ | ||
1140 | +static void job_cancel_async_locked(Job *job, bool force) | ||
1141 | { | ||
1142 | GLOBAL_STATE_CODE(); | ||
1143 | if (job->driver->cancel) { | ||
1144 | + job_unlock(); | ||
1145 | force = job->driver->cancel(job, force); | ||
1146 | + job_lock(); | ||
1147 | } else { | ||
1148 | /* No .cancel() means the job will behave as if force-cancelled */ | ||
1149 | force = true; | ||
1150 | @@ -XXX,XX +XXX,XX @@ static void job_cancel_async(Job *job, bool force) | ||
1151 | if (job->user_paused) { | ||
1152 | /* Do not call job_enter here, the caller will handle it. */ | ||
1153 | if (job->driver->user_resume) { | ||
1154 | + job_unlock(); | ||
1155 | job->driver->user_resume(job); | ||
1156 | + job_lock(); | ||
1157 | } | ||
1158 | job->user_paused = false; | ||
1159 | assert(job->pause_count > 0); | ||
1160 | @@ -XXX,XX +XXX,XX @@ static void job_cancel_async(Job *job, bool force) | ||
1161 | } | ||
1162 | } | ||
1163 | |||
1164 | -static void job_completed_txn_abort(Job *job) | ||
1165 | +/* Called with job_mutex held, but releases it temporarily. */ | ||
1166 | +static void job_completed_txn_abort_locked(Job *job) | ||
1167 | { | ||
1168 | AioContext *ctx; | ||
1169 | JobTxn *txn = job->txn; | ||
1170 | @@ -XXX,XX +XXX,XX @@ static void job_completed_txn_abort(Job *job) | ||
119 | return; | 1171 | return; |
120 | } | 1172 | } |
121 | - ratelimit_set_speed(&s->limit, speed / BDRV_SECTOR_SIZE, SLICE_TIME); | 1173 | txn->aborting = true; |
122 | + ratelimit_set_speed(&s->limit, speed, SLICE_TIME); | 1174 | - job_txn_ref(txn); |
123 | } | 1175 | + job_txn_ref_locked(txn); |
124 | 1176 | ||
125 | static void mirror_complete(BlockJob *job, Error **errp) | 1177 | /* |
126 | diff --git a/block/stream.c b/block/stream.c | 1178 | * We can only hold the single job's AioContext lock while calling |
127 | index XXXXXXX..XXXXXXX 100644 | 1179 | @@ -XXX,XX +XXX,XX @@ static void job_completed_txn_abort(Job *job) |
128 | --- a/block/stream.c | 1180 | * calls of AIO_WAIT_WHILE(), which could deadlock otherwise. |
129 | +++ b/block/stream.c | 1181 | * Note that the job's AioContext may change when it is finalized. |
130 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn stream_run(void *opaque) | 1182 | */ |
131 | /* Publish progress */ | 1183 | - job_ref(job); |
132 | s->common.offset += n * BDRV_SECTOR_SIZE; | 1184 | + job_ref_locked(job); |
133 | if (copy && s->common.speed) { | 1185 | aio_context_release(job->aio_context); |
134 | - delay_ns = ratelimit_calculate_delay(&s->limit, n); | 1186 | |
135 | + delay_ns = ratelimit_calculate_delay(&s->limit, | 1187 | /* Other jobs are effectively cancelled by us, set the status for |
136 | + n * BDRV_SECTOR_SIZE); | 1188 | @@ -XXX,XX +XXX,XX @@ static void job_completed_txn_abort(Job *job) |
1189 | * Therefore, pass force=true to terminate all other jobs as quickly | ||
1190 | * as possible. | ||
1191 | */ | ||
1192 | - job_cancel_async(other_job, true); | ||
1193 | + job_cancel_async_locked(other_job, true); | ||
1194 | aio_context_release(ctx); | ||
137 | } | 1195 | } |
138 | } | 1196 | } |
139 | 1197 | @@ -XXX,XX +XXX,XX @@ static void job_completed_txn_abort(Job *job) | |
140 | @@ -XXX,XX +XXX,XX @@ static void stream_set_speed(BlockJob *job, int64_t speed, Error **errp) | 1198 | */ |
141 | error_setg(errp, QERR_INVALID_PARAMETER, "speed"); | 1199 | ctx = other_job->aio_context; |
1200 | aio_context_acquire(ctx); | ||
1201 | - if (!job_is_completed(other_job)) { | ||
1202 | - assert(job_cancel_requested(other_job)); | ||
1203 | - job_finish_sync(other_job, NULL, NULL); | ||
1204 | + if (!job_is_completed_locked(other_job)) { | ||
1205 | + assert(job_cancel_requested_locked(other_job)); | ||
1206 | + job_finish_sync_locked(other_job, NULL, NULL); | ||
1207 | } | ||
1208 | - job_finalize_single(other_job); | ||
1209 | + job_finalize_single_locked(other_job); | ||
1210 | aio_context_release(ctx); | ||
1211 | } | ||
1212 | |||
1213 | @@ -XXX,XX +XXX,XX @@ static void job_completed_txn_abort(Job *job) | ||
1214 | * even if the job went away during job_finalize_single(). | ||
1215 | */ | ||
1216 | aio_context_acquire(job->aio_context); | ||
1217 | - job_unref(job); | ||
1218 | + job_unref_locked(job); | ||
1219 | |||
1220 | - job_txn_unref(txn); | ||
1221 | + job_txn_unref_locked(txn); | ||
1222 | } | ||
1223 | |||
1224 | -static int job_prepare(Job *job) | ||
1225 | +/* Called with job_mutex held, but releases it temporarily */ | ||
1226 | +static int job_prepare_locked(Job *job) | ||
1227 | { | ||
1228 | + int ret; | ||
1229 | + | ||
1230 | GLOBAL_STATE_CODE(); | ||
1231 | if (job->ret == 0 && job->driver->prepare) { | ||
1232 | - job->ret = job->driver->prepare(job); | ||
1233 | - job_update_rc(job); | ||
1234 | + job_unlock(); | ||
1235 | + ret = job->driver->prepare(job); | ||
1236 | + job_lock(); | ||
1237 | + job->ret = ret; | ||
1238 | + job_update_rc_locked(job); | ||
1239 | } | ||
1240 | return job->ret; | ||
1241 | } | ||
1242 | |||
1243 | -static int job_needs_finalize(Job *job) | ||
1244 | +/* Called with job_mutex held */ | ||
1245 | +static int job_needs_finalize_locked(Job *job) | ||
1246 | { | ||
1247 | return !job->auto_finalize; | ||
1248 | } | ||
1249 | |||
1250 | -static void job_do_finalize(Job *job) | ||
1251 | +/* Called with job_mutex held */ | ||
1252 | +static void job_do_finalize_locked(Job *job) | ||
1253 | { | ||
1254 | int rc; | ||
1255 | assert(job && job->txn); | ||
1256 | |||
1257 | /* prepare the transaction to complete */ | ||
1258 | - rc = job_txn_apply(job, job_prepare); | ||
1259 | + rc = job_txn_apply_locked(job, job_prepare_locked); | ||
1260 | if (rc) { | ||
1261 | - job_completed_txn_abort(job); | ||
1262 | + job_completed_txn_abort_locked(job); | ||
1263 | } else { | ||
1264 | - job_txn_apply(job, job_finalize_single); | ||
1265 | + job_txn_apply_locked(job, job_finalize_single_locked); | ||
1266 | } | ||
1267 | } | ||
1268 | |||
1269 | -void job_finalize(Job *job, Error **errp) | ||
1270 | +void job_finalize_locked(Job *job, Error **errp) | ||
1271 | { | ||
1272 | assert(job && job->id); | ||
1273 | - if (job_apply_verb(job, JOB_VERB_FINALIZE, errp)) { | ||
1274 | + if (job_apply_verb_locked(job, JOB_VERB_FINALIZE, errp)) { | ||
142 | return; | 1275 | return; |
143 | } | 1276 | } |
144 | - ratelimit_set_speed(&s->limit, speed / BDRV_SECTOR_SIZE, SLICE_TIME); | 1277 | - job_do_finalize(job); |
145 | + ratelimit_set_speed(&s->limit, speed, SLICE_TIME); | 1278 | + job_do_finalize_locked(job); |
146 | } | 1279 | } |
147 | 1280 | ||
148 | static const BlockJobDriver stream_job_driver = { | 1281 | -static int job_transition_to_pending(Job *job) |
149 | diff --git a/include/qemu/ratelimit.h b/include/qemu/ratelimit.h | 1282 | +void job_finalize(Job *job, Error **errp) |
150 | index XXXXXXX..XXXXXXX 100644 | 1283 | { |
151 | --- a/include/qemu/ratelimit.h | 1284 | - job_state_transition(job, JOB_STATUS_PENDING); |
152 | +++ b/include/qemu/ratelimit.h | 1285 | + JOB_LOCK_GUARD(); |
153 | @@ -XXX,XX +XXX,XX @@ typedef struct { | 1286 | + job_finalize_locked(job, errp); |
154 | 1287 | +} | |
155 | /** Calculate and return delay for next request in ns | 1288 | + |
156 | * | 1289 | +/* Called with job_mutex held. */ |
157 | - * Record that we sent @p n data units. If we may send more data units | 1290 | +static int job_transition_to_pending_locked(Job *job) |
158 | + * Record that we sent @n data units (where @n matches the scale chosen | 1291 | +{ |
159 | + * during ratelimit_set_speed). If we may send more data units | 1292 | + job_state_transition_locked(job, JOB_STATUS_PENDING); |
160 | * in the current time slice, return 0 (i.e. no delay). Otherwise | 1293 | if (!job->auto_finalize) { |
161 | * return the amount of time (in ns) until the start of the next time | 1294 | - job_event_pending(job); |
162 | * slice that will permit sending the next chunk of data. | 1295 | + job_event_pending_locked(job); |
1296 | } | ||
1297 | return 0; | ||
1298 | } | ||
1299 | |||
1300 | void job_transition_to_ready(Job *job) | ||
1301 | { | ||
1302 | - job_state_transition(job, JOB_STATUS_READY); | ||
1303 | - job_event_ready(job); | ||
1304 | + JOB_LOCK_GUARD(); | ||
1305 | + job_state_transition_locked(job, JOB_STATUS_READY); | ||
1306 | + job_event_ready_locked(job); | ||
1307 | } | ||
1308 | |||
1309 | -static void job_completed_txn_success(Job *job) | ||
1310 | +/* Called with job_mutex held. */ | ||
1311 | +static void job_completed_txn_success_locked(Job *job) | ||
1312 | { | ||
1313 | JobTxn *txn = job->txn; | ||
1314 | Job *other_job; | ||
1315 | |||
1316 | - job_state_transition(job, JOB_STATUS_WAITING); | ||
1317 | + job_state_transition_locked(job, JOB_STATUS_WAITING); | ||
1318 | |||
1319 | /* | ||
1320 | * Successful completion, see if there are other running jobs in this | ||
1321 | * txn. | ||
1322 | */ | ||
1323 | QLIST_FOREACH(other_job, &txn->jobs, txn_list) { | ||
1324 | - if (!job_is_completed(other_job)) { | ||
1325 | + if (!job_is_completed_locked(other_job)) { | ||
1326 | return; | ||
1327 | } | ||
1328 | assert(other_job->ret == 0); | ||
1329 | } | ||
1330 | |||
1331 | - job_txn_apply(job, job_transition_to_pending); | ||
1332 | + job_txn_apply_locked(job, job_transition_to_pending_locked); | ||
1333 | |||
1334 | /* If no jobs need manual finalization, automatically do so */ | ||
1335 | - if (job_txn_apply(job, job_needs_finalize) == 0) { | ||
1336 | - job_do_finalize(job); | ||
1337 | + if (job_txn_apply_locked(job, job_needs_finalize_locked) == 0) { | ||
1338 | + job_do_finalize_locked(job); | ||
1339 | } | ||
1340 | } | ||
1341 | |||
1342 | -static void job_completed(Job *job) | ||
1343 | +/* Called with job_mutex held. */ | ||
1344 | +static void job_completed_locked(Job *job) | ||
1345 | { | ||
1346 | - assert(job && job->txn && !job_is_completed(job)); | ||
1347 | + assert(job && job->txn && !job_is_completed_locked(job)); | ||
1348 | |||
1349 | - job_update_rc(job); | ||
1350 | + job_update_rc_locked(job); | ||
1351 | trace_job_completed(job, job->ret); | ||
1352 | if (job->ret) { | ||
1353 | - job_completed_txn_abort(job); | ||
1354 | + job_completed_txn_abort_locked(job); | ||
1355 | } else { | ||
1356 | - job_completed_txn_success(job); | ||
1357 | + job_completed_txn_success_locked(job); | ||
1358 | } | ||
1359 | } | ||
1360 | |||
1361 | -/** Useful only as a type shim for aio_bh_schedule_oneshot. */ | ||
1362 | +/** | ||
1363 | + * Useful only as a type shim for aio_bh_schedule_oneshot. | ||
1364 | + * Called with job_mutex *not* held. | ||
1365 | + */ | ||
1366 | static void job_exit(void *opaque) | ||
1367 | { | ||
1368 | Job *job = (Job *)opaque; | ||
1369 | AioContext *ctx; | ||
1370 | + JOB_LOCK_GUARD(); | ||
1371 | |||
1372 | - job_ref(job); | ||
1373 | + job_ref_locked(job); | ||
1374 | aio_context_acquire(job->aio_context); | ||
1375 | |||
1376 | /* This is a lie, we're not quiescent, but still doing the completion | ||
1377 | @@ -XXX,XX +XXX,XX @@ static void job_exit(void *opaque) | ||
1378 | * drain block nodes, and if .drained_poll still returned true, we would | ||
1379 | * deadlock. */ | ||
1380 | job->busy = false; | ||
1381 | - job_event_idle(job); | ||
1382 | + job_event_idle_locked(job); | ||
1383 | |||
1384 | - job_completed(job); | ||
1385 | + job_completed_locked(job); | ||
1386 | |||
1387 | /* | ||
1388 | * Note that calling job_completed can move the job to a different | ||
1389 | @@ -XXX,XX +XXX,XX @@ static void job_exit(void *opaque) | ||
1390 | * the job underneath us. | ||
1391 | */ | ||
1392 | ctx = job->aio_context; | ||
1393 | - job_unref(job); | ||
1394 | + job_unref_locked(job); | ||
1395 | aio_context_release(ctx); | ||
1396 | } | ||
1397 | |||
1398 | @@ -XXX,XX +XXX,XX @@ static void job_exit(void *opaque) | ||
1399 | static void coroutine_fn job_co_entry(void *opaque) | ||
1400 | { | ||
1401 | Job *job = opaque; | ||
1402 | + int ret; | ||
1403 | |||
1404 | assert(job && job->driver && job->driver->run); | ||
1405 | - assert(job->aio_context == qemu_get_current_aio_context()); | ||
1406 | - job_pause_point(job); | ||
1407 | - job->ret = job->driver->run(job, &job->err); | ||
1408 | - job->deferred_to_main_loop = true; | ||
1409 | - job->busy = true; | ||
1410 | + WITH_JOB_LOCK_GUARD() { | ||
1411 | + assert(job->aio_context == qemu_get_current_aio_context()); | ||
1412 | + job_pause_point_locked(job); | ||
1413 | + } | ||
1414 | + ret = job->driver->run(job, &job->err); | ||
1415 | + WITH_JOB_LOCK_GUARD() { | ||
1416 | + job->ret = ret; | ||
1417 | + job->deferred_to_main_loop = true; | ||
1418 | + job->busy = true; | ||
1419 | + } | ||
1420 | aio_bh_schedule_oneshot(qemu_get_aio_context(), job_exit, job); | ||
1421 | } | ||
1422 | |||
1423 | void job_start(Job *job) | ||
1424 | { | ||
1425 | - assert(job && !job_started(job) && job->paused && | ||
1426 | - job->driver && job->driver->run); | ||
1427 | - job->co = qemu_coroutine_create(job_co_entry, job); | ||
1428 | - job->pause_count--; | ||
1429 | - job->busy = true; | ||
1430 | - job->paused = false; | ||
1431 | - job_state_transition(job, JOB_STATUS_RUNNING); | ||
1432 | + assert(qemu_in_main_thread()); | ||
1433 | + | ||
1434 | + WITH_JOB_LOCK_GUARD() { | ||
1435 | + assert(job && !job_started_locked(job) && job->paused && | ||
1436 | + job->driver && job->driver->run); | ||
1437 | + job->co = qemu_coroutine_create(job_co_entry, job); | ||
1438 | + job->pause_count--; | ||
1439 | + job->busy = true; | ||
1440 | + job->paused = false; | ||
1441 | + job_state_transition_locked(job, JOB_STATUS_RUNNING); | ||
1442 | + } | ||
1443 | aio_co_enter(job->aio_context, job->co); | ||
1444 | } | ||
1445 | |||
1446 | -void job_cancel(Job *job, bool force) | ||
1447 | +void job_cancel_locked(Job *job, bool force) | ||
1448 | { | ||
1449 | if (job->status == JOB_STATUS_CONCLUDED) { | ||
1450 | - job_do_dismiss(job); | ||
1451 | + job_do_dismiss_locked(job); | ||
1452 | return; | ||
1453 | } | ||
1454 | - job_cancel_async(job, force); | ||
1455 | - if (!job_started(job)) { | ||
1456 | - job_completed(job); | ||
1457 | + job_cancel_async_locked(job, force); | ||
1458 | + if (!job_started_locked(job)) { | ||
1459 | + job_completed_locked(job); | ||
1460 | } else if (job->deferred_to_main_loop) { | ||
1461 | /* | ||
1462 | * job_cancel_async() ignores soft-cancel requests for jobs | ||
1463 | @@ -XXX,XX +XXX,XX @@ void job_cancel(Job *job, bool force) | ||
1464 | * choose to call job_is_cancelled() to show that we invoke | ||
1465 | * job_completed_txn_abort() only for force-cancelled jobs.) | ||
1466 | */ | ||
1467 | - if (job_is_cancelled(job)) { | ||
1468 | - job_completed_txn_abort(job); | ||
1469 | + if (job_is_cancelled_locked(job)) { | ||
1470 | + job_completed_txn_abort_locked(job); | ||
1471 | } | ||
1472 | } else { | ||
1473 | - job_enter(job); | ||
1474 | + job_enter_cond_locked(job, NULL); | ||
1475 | } | ||
1476 | } | ||
1477 | |||
1478 | -void job_user_cancel(Job *job, bool force, Error **errp) | ||
1479 | +void job_cancel(Job *job, bool force) | ||
1480 | { | ||
1481 | - if (job_apply_verb(job, JOB_VERB_CANCEL, errp)) { | ||
1482 | + JOB_LOCK_GUARD(); | ||
1483 | + job_cancel_locked(job, force); | ||
1484 | +} | ||
1485 | + | ||
1486 | +void job_user_cancel_locked(Job *job, bool force, Error **errp) | ||
1487 | +{ | ||
1488 | + if (job_apply_verb_locked(job, JOB_VERB_CANCEL, errp)) { | ||
1489 | return; | ||
1490 | } | ||
1491 | - job_cancel(job, force); | ||
1492 | + job_cancel_locked(job, force); | ||
1493 | +} | ||
1494 | + | ||
1495 | +void job_user_cancel(Job *job, bool force, Error **errp) | ||
1496 | +{ | ||
1497 | + JOB_LOCK_GUARD(); | ||
1498 | + job_user_cancel_locked(job, force, errp); | ||
1499 | } | ||
1500 | |||
1501 | /* A wrapper around job_cancel() taking an Error ** parameter so it may be | ||
1502 | * used with job_finish_sync() without the need for (rather nasty) function | ||
1503 | - * pointer casts there. */ | ||
1504 | -static void job_cancel_err(Job *job, Error **errp) | ||
1505 | + * pointer casts there. | ||
1506 | + * | ||
1507 | + * Called with job_mutex held. | ||
1508 | + */ | ||
1509 | +static void job_cancel_err_locked(Job *job, Error **errp) | ||
1510 | { | ||
1511 | - job_cancel(job, false); | ||
1512 | + job_cancel_locked(job, false); | ||
1513 | } | ||
1514 | |||
1515 | /** | ||
1516 | * Same as job_cancel_err(), but force-cancel. | ||
1517 | + * Called with job_mutex held. | ||
1518 | */ | ||
1519 | -static void job_force_cancel_err(Job *job, Error **errp) | ||
1520 | +static void job_force_cancel_err_locked(Job *job, Error **errp) | ||
1521 | { | ||
1522 | - job_cancel(job, true); | ||
1523 | + job_cancel_locked(job, true); | ||
1524 | } | ||
1525 | |||
1526 | -int job_cancel_sync(Job *job, bool force) | ||
1527 | +int job_cancel_sync_locked(Job *job, bool force) | ||
1528 | { | ||
1529 | if (force) { | ||
1530 | - return job_finish_sync(job, &job_force_cancel_err, NULL); | ||
1531 | + return job_finish_sync_locked(job, &job_force_cancel_err_locked, NULL); | ||
1532 | } else { | ||
1533 | - return job_finish_sync(job, &job_cancel_err, NULL); | ||
1534 | + return job_finish_sync_locked(job, &job_cancel_err_locked, NULL); | ||
1535 | } | ||
1536 | } | ||
1537 | |||
1538 | +int job_cancel_sync(Job *job, bool force) | ||
1539 | +{ | ||
1540 | + JOB_LOCK_GUARD(); | ||
1541 | + return job_cancel_sync_locked(job, force); | ||
1542 | +} | ||
1543 | + | ||
1544 | void job_cancel_sync_all(void) | ||
1545 | { | ||
1546 | Job *job; | ||
1547 | AioContext *aio_context; | ||
1548 | + JOB_LOCK_GUARD(); | ||
1549 | |||
1550 | - while ((job = job_next(NULL))) { | ||
1551 | + while ((job = job_next_locked(NULL))) { | ||
1552 | aio_context = job->aio_context; | ||
1553 | aio_context_acquire(aio_context); | ||
1554 | - job_cancel_sync(job, true); | ||
1555 | + job_cancel_sync_locked(job, true); | ||
1556 | aio_context_release(aio_context); | ||
1557 | } | ||
1558 | } | ||
1559 | |||
1560 | +int job_complete_sync_locked(Job *job, Error **errp) | ||
1561 | +{ | ||
1562 | + return job_finish_sync_locked(job, job_complete_locked, errp); | ||
1563 | +} | ||
1564 | + | ||
1565 | int job_complete_sync(Job *job, Error **errp) | ||
1566 | { | ||
1567 | - return job_finish_sync(job, job_complete, errp); | ||
1568 | + JOB_LOCK_GUARD(); | ||
1569 | + return job_complete_sync_locked(job, errp); | ||
1570 | } | ||
1571 | |||
1572 | -void job_complete(Job *job, Error **errp) | ||
1573 | +void job_complete_locked(Job *job, Error **errp) | ||
1574 | { | ||
1575 | /* Should not be reachable via external interface for internal jobs */ | ||
1576 | assert(job->id); | ||
1577 | GLOBAL_STATE_CODE(); | ||
1578 | - if (job_apply_verb(job, JOB_VERB_COMPLETE, errp)) { | ||
1579 | + if (job_apply_verb_locked(job, JOB_VERB_COMPLETE, errp)) { | ||
1580 | return; | ||
1581 | } | ||
1582 | - if (job_cancel_requested(job) || !job->driver->complete) { | ||
1583 | + if (job_cancel_requested_locked(job) || !job->driver->complete) { | ||
1584 | error_setg(errp, "The active block job '%s' cannot be completed", | ||
1585 | job->id); | ||
1586 | return; | ||
1587 | } | ||
1588 | |||
1589 | + job_unlock(); | ||
1590 | job->driver->complete(job, errp); | ||
1591 | + job_lock(); | ||
1592 | } | ||
1593 | |||
1594 | -int job_finish_sync(Job *job, void (*finish)(Job *, Error **errp), Error **errp) | ||
1595 | +void job_complete(Job *job, Error **errp) | ||
1596 | +{ | ||
1597 | + JOB_LOCK_GUARD(); | ||
1598 | + job_complete_locked(job, errp); | ||
1599 | +} | ||
1600 | + | ||
1601 | +int job_finish_sync_locked(Job *job, | ||
1602 | + void (*finish)(Job *, Error **errp), | ||
1603 | + Error **errp) | ||
1604 | { | ||
1605 | Error *local_err = NULL; | ||
1606 | int ret; | ||
1607 | |||
1608 | - job_ref(job); | ||
1609 | + job_ref_locked(job); | ||
1610 | |||
1611 | if (finish) { | ||
1612 | finish(job, &local_err); | ||
1613 | } | ||
1614 | if (local_err) { | ||
1615 | error_propagate(errp, local_err); | ||
1616 | - job_unref(job); | ||
1617 | + job_unref_locked(job); | ||
1618 | return -EBUSY; | ||
1619 | } | ||
1620 | |||
1621 | + job_unlock(); | ||
1622 | AIO_WAIT_WHILE(job->aio_context, | ||
1623 | (job_enter(job), !job_is_completed(job))); | ||
1624 | + job_lock(); | ||
1625 | |||
1626 | - ret = (job_is_cancelled(job) && job->ret == 0) ? -ECANCELED : job->ret; | ||
1627 | - job_unref(job); | ||
1628 | + ret = (job_is_cancelled_locked(job) && job->ret == 0) | ||
1629 | + ? -ECANCELED : job->ret; | ||
1630 | + job_unref_locked(job); | ||
1631 | return ret; | ||
1632 | } | ||
1633 | + | ||
1634 | +int job_finish_sync(Job *job, void (*finish)(Job *, Error **errp), Error **errp) | ||
1635 | +{ | ||
1636 | + JOB_LOCK_GUARD(); | ||
1637 | + return job_finish_sync_locked(job, finish, errp); | ||
1638 | +} | ||
163 | -- | 1639 | -- |
164 | 1.8.3.1 | 1640 | 2.37.3 |
165 | |||
166 | diff view generated by jsdifflib |
1 | From: "Daniel P. Berrange" <berrange@redhat.com> | 1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | The block/crypto.c defines a set of QemuOpts that provide | 3 | This comment applies more on job, it was left in blockjob as in the past |
4 | parameters for encryption. This will also be needed by | 4 | the whole job logic was implemented there. |
5 | the qcow/qcow2 integration, so expose the relevant pieces | ||
6 | in a new block/crypto.h header. Some helper methods taking | ||
7 | QemuOpts are changed to take QDict to simplify usage in | ||
8 | other places. | ||
9 | 5 | ||
10 | Reviewed-by: Max Reitz <mreitz@redhat.com> | 6 | Note: at this stage, job_{lock/unlock} and job lock guard macros |
11 | Reviewed-by: Eric Blake <eblake@redhat.com> | 7 | are *nop*. |
12 | Reviewed-by: Alberto Garcia <berto@igalia.com> | 8 | |
13 | Signed-off-by: Daniel P. Berrange <berrange@redhat.com> | 9 | No functional change intended. |
14 | Message-id: 20170623162419.26068-2-berrange@redhat.com | 10 | |
15 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 11 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
12 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> | ||
13 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
14 | Message-Id: <20220926093214.506243-7-eesposit@redhat.com> | ||
15 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
16 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
16 | --- | 17 | --- |
17 | block/crypto.c | 82 +++++++++++++++++----------------------------------- | 18 | blockjob.c | 20 -------------------- |
18 | block/crypto.h | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | 19 | job.c | 16 ++++++++++++++++ |
19 | 2 files changed, 117 insertions(+), 56 deletions(-) | 20 | 2 files changed, 16 insertions(+), 20 deletions(-) |
20 | create mode 100644 block/crypto.h | ||
21 | 21 | ||
22 | diff --git a/block/crypto.c b/block/crypto.c | 22 | diff --git a/blockjob.c b/blockjob.c |
23 | index XXXXXXX..XXXXXXX 100644 | 23 | index XXXXXXX..XXXXXXX 100644 |
24 | --- a/block/crypto.c | 24 | --- a/blockjob.c |
25 | +++ b/block/crypto.c | 25 | +++ b/blockjob.c |
26 | @@ -XXX,XX +XXX,XX @@ | 26 | @@ -XXX,XX +XXX,XX @@ |
27 | #include "sysemu/block-backend.h" | 27 | #include "qemu/main-loop.h" |
28 | #include "crypto/block.h" | 28 | #include "qemu/timer.h" |
29 | #include "qapi/opts-visitor.h" | 29 | |
30 | +#include "qapi/qobject-input-visitor.h" | 30 | -/* |
31 | #include "qapi-visit.h" | 31 | - * The block job API is composed of two categories of functions. |
32 | #include "qapi/error.h" | 32 | - * |
33 | - * The first includes functions used by the monitor. The monitor is | ||
34 | - * peculiar in that it accesses the block job list with block_job_get, and | ||
35 | - * therefore needs consistency across block_job_get and the actual operation | ||
36 | - * (e.g. block_job_set_speed). The consistency is achieved with | ||
37 | - * aio_context_acquire/release. These functions are declared in blockjob.h. | ||
38 | - * | ||
39 | - * The second includes functions used by the block job drivers and sometimes | ||
40 | - * by the core block layer. These do not care about locking, because the | ||
41 | - * whole coroutine runs under the AioContext lock, and are declared in | ||
42 | - * blockjob_int.h. | ||
43 | - */ | ||
33 | - | 44 | - |
34 | -#define BLOCK_CRYPTO_OPT_LUKS_KEY_SECRET "key-secret" | 45 | static bool is_block_job(Job *job) |
35 | -#define BLOCK_CRYPTO_OPT_LUKS_CIPHER_ALG "cipher-alg" | ||
36 | -#define BLOCK_CRYPTO_OPT_LUKS_CIPHER_MODE "cipher-mode" | ||
37 | -#define BLOCK_CRYPTO_OPT_LUKS_IVGEN_ALG "ivgen-alg" | ||
38 | -#define BLOCK_CRYPTO_OPT_LUKS_IVGEN_HASH_ALG "ivgen-hash-alg" | ||
39 | -#define BLOCK_CRYPTO_OPT_LUKS_HASH_ALG "hash-alg" | ||
40 | -#define BLOCK_CRYPTO_OPT_LUKS_ITER_TIME "iter-time" | ||
41 | +#include "block/crypto.h" | ||
42 | |||
43 | typedef struct BlockCrypto BlockCrypto; | ||
44 | |||
45 | @@ -XXX,XX +XXX,XX @@ static QemuOptsList block_crypto_runtime_opts_luks = { | ||
46 | .name = "crypto", | ||
47 | .head = QTAILQ_HEAD_INITIALIZER(block_crypto_runtime_opts_luks.head), | ||
48 | .desc = { | ||
49 | - { | ||
50 | - .name = BLOCK_CRYPTO_OPT_LUKS_KEY_SECRET, | ||
51 | - .type = QEMU_OPT_STRING, | ||
52 | - .help = "ID of the secret that provides the encryption key", | ||
53 | - }, | ||
54 | + BLOCK_CRYPTO_OPT_DEF_LUKS_KEY_SECRET, | ||
55 | { /* end of list */ } | ||
56 | }, | ||
57 | }; | ||
58 | @@ -XXX,XX +XXX,XX @@ static QemuOptsList block_crypto_create_opts_luks = { | ||
59 | .type = QEMU_OPT_SIZE, | ||
60 | .help = "Virtual disk size" | ||
61 | }, | ||
62 | - { | ||
63 | - .name = BLOCK_CRYPTO_OPT_LUKS_KEY_SECRET, | ||
64 | - .type = QEMU_OPT_STRING, | ||
65 | - .help = "ID of the secret that provides the encryption key", | ||
66 | - }, | ||
67 | - { | ||
68 | - .name = BLOCK_CRYPTO_OPT_LUKS_CIPHER_ALG, | ||
69 | - .type = QEMU_OPT_STRING, | ||
70 | - .help = "Name of encryption cipher algorithm", | ||
71 | - }, | ||
72 | - { | ||
73 | - .name = BLOCK_CRYPTO_OPT_LUKS_CIPHER_MODE, | ||
74 | - .type = QEMU_OPT_STRING, | ||
75 | - .help = "Name of encryption cipher mode", | ||
76 | - }, | ||
77 | - { | ||
78 | - .name = BLOCK_CRYPTO_OPT_LUKS_IVGEN_ALG, | ||
79 | - .type = QEMU_OPT_STRING, | ||
80 | - .help = "Name of IV generator algorithm", | ||
81 | - }, | ||
82 | - { | ||
83 | - .name = BLOCK_CRYPTO_OPT_LUKS_IVGEN_HASH_ALG, | ||
84 | - .type = QEMU_OPT_STRING, | ||
85 | - .help = "Name of IV generator hash algorithm", | ||
86 | - }, | ||
87 | - { | ||
88 | - .name = BLOCK_CRYPTO_OPT_LUKS_HASH_ALG, | ||
89 | - .type = QEMU_OPT_STRING, | ||
90 | - .help = "Name of encryption hash algorithm", | ||
91 | - }, | ||
92 | - { | ||
93 | - .name = BLOCK_CRYPTO_OPT_LUKS_ITER_TIME, | ||
94 | - .type = QEMU_OPT_NUMBER, | ||
95 | - .help = "Time to spend in PBKDF in milliseconds", | ||
96 | - }, | ||
97 | + BLOCK_CRYPTO_OPT_DEF_LUKS_KEY_SECRET, | ||
98 | + BLOCK_CRYPTO_OPT_DEF_LUKS_CIPHER_ALG, | ||
99 | + BLOCK_CRYPTO_OPT_DEF_LUKS_CIPHER_MODE, | ||
100 | + BLOCK_CRYPTO_OPT_DEF_LUKS_IVGEN_ALG, | ||
101 | + BLOCK_CRYPTO_OPT_DEF_LUKS_IVGEN_HASH_ALG, | ||
102 | + BLOCK_CRYPTO_OPT_DEF_LUKS_HASH_ALG, | ||
103 | + BLOCK_CRYPTO_OPT_DEF_LUKS_ITER_TIME, | ||
104 | { /* end of list */ } | ||
105 | }, | ||
106 | }; | ||
107 | |||
108 | |||
109 | -static QCryptoBlockOpenOptions * | ||
110 | +QCryptoBlockOpenOptions * | ||
111 | block_crypto_open_opts_init(QCryptoBlockFormat format, | ||
112 | - QemuOpts *opts, | ||
113 | + QDict *opts, | ||
114 | Error **errp) | ||
115 | { | 46 | { |
116 | Visitor *v; | 47 | return job_type(job) == JOB_TYPE_BACKUP || |
117 | @@ -XXX,XX +XXX,XX @@ block_crypto_open_opts_init(QCryptoBlockFormat format, | 48 | @@ -XXX,XX +XXX,XX @@ static void block_job_event_ready(Notifier *n, void *opaque) |
118 | ret = g_new0(QCryptoBlockOpenOptions, 1); | ||
119 | ret->format = format; | ||
120 | |||
121 | - v = opts_visitor_new(opts); | ||
122 | + v = qobject_input_visitor_new_keyval(QOBJECT(opts)); | ||
123 | |||
124 | visit_start_struct(v, NULL, NULL, 0, &local_err); | ||
125 | if (local_err) { | ||
126 | @@ -XXX,XX +XXX,XX @@ block_crypto_open_opts_init(QCryptoBlockFormat format, | ||
127 | } | 49 | } |
128 | 50 | ||
129 | 51 | ||
130 | -static QCryptoBlockCreateOptions * | 52 | -/* |
131 | +QCryptoBlockCreateOptions * | 53 | - * API for block job drivers and the block layer. These functions are |
132 | block_crypto_create_opts_init(QCryptoBlockFormat format, | 54 | - * declared in blockjob_int.h. |
133 | - QemuOpts *opts, | 55 | - */ |
134 | + QDict *opts, | 56 | - |
135 | Error **errp) | 57 | void *block_job_create(const char *job_id, const BlockJobDriver *driver, |
136 | { | 58 | JobTxn *txn, BlockDriverState *bs, uint64_t perm, |
137 | Visitor *v; | 59 | uint64_t shared_perm, int64_t speed, int flags, |
138 | @@ -XXX,XX +XXX,XX @@ block_crypto_create_opts_init(QCryptoBlockFormat format, | 60 | diff --git a/job.c b/job.c |
139 | ret = g_new0(QCryptoBlockCreateOptions, 1); | 61 | index XXXXXXX..XXXXXXX 100644 |
140 | ret->format = format; | 62 | --- a/job.c |
141 | 63 | +++ b/job.c | |
142 | - v = opts_visitor_new(opts); | ||
143 | + v = qobject_input_visitor_new_keyval(QOBJECT(opts)); | ||
144 | |||
145 | visit_start_struct(v, NULL, NULL, 0, &local_err); | ||
146 | if (local_err) { | ||
147 | @@ -XXX,XX +XXX,XX @@ static int block_crypto_open_generic(QCryptoBlockFormat format, | ||
148 | int ret = -EINVAL; | ||
149 | QCryptoBlockOpenOptions *open_opts = NULL; | ||
150 | unsigned int cflags = 0; | ||
151 | + QDict *cryptoopts = NULL; | ||
152 | |||
153 | bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, | ||
154 | false, errp); | ||
155 | @@ -XXX,XX +XXX,XX @@ static int block_crypto_open_generic(QCryptoBlockFormat format, | ||
156 | goto cleanup; | ||
157 | } | ||
158 | |||
159 | - open_opts = block_crypto_open_opts_init(format, opts, errp); | ||
160 | + cryptoopts = qemu_opts_to_qdict(opts, NULL); | ||
161 | + | ||
162 | + open_opts = block_crypto_open_opts_init(format, cryptoopts, errp); | ||
163 | if (!open_opts) { | ||
164 | goto cleanup; | ||
165 | } | ||
166 | @@ -XXX,XX +XXX,XX @@ static int block_crypto_open_generic(QCryptoBlockFormat format, | ||
167 | |||
168 | ret = 0; | ||
169 | cleanup: | ||
170 | + QDECREF(cryptoopts); | ||
171 | qapi_free_QCryptoBlockOpenOptions(open_opts); | ||
172 | return ret; | ||
173 | } | ||
174 | @@ -XXX,XX +XXX,XX @@ static int block_crypto_create_generic(QCryptoBlockFormat format, | ||
175 | .opts = opts, | ||
176 | .filename = filename, | ||
177 | }; | ||
178 | + QDict *cryptoopts; | ||
179 | + | ||
180 | + cryptoopts = qemu_opts_to_qdict(opts, NULL); | ||
181 | |||
182 | - create_opts = block_crypto_create_opts_init(format, opts, errp); | ||
183 | + create_opts = block_crypto_create_opts_init(format, cryptoopts, errp); | ||
184 | if (!create_opts) { | ||
185 | return -1; | ||
186 | } | ||
187 | @@ -XXX,XX +XXX,XX @@ static int block_crypto_create_generic(QCryptoBlockFormat format, | ||
188 | |||
189 | ret = 0; | ||
190 | cleanup: | ||
191 | + QDECREF(cryptoopts); | ||
192 | qcrypto_block_free(crypto); | ||
193 | blk_unref(data.blk); | ||
194 | qapi_free_QCryptoBlockCreateOptions(create_opts); | ||
195 | diff --git a/block/crypto.h b/block/crypto.h | ||
196 | new file mode 100644 | ||
197 | index XXXXXXX..XXXXXXX | ||
198 | --- /dev/null | ||
199 | +++ b/block/crypto.h | ||
200 | @@ -XXX,XX +XXX,XX @@ | 64 | @@ -XXX,XX +XXX,XX @@ |
65 | #include "trace/trace-root.h" | ||
66 | #include "qapi/qapi-events-job.h" | ||
67 | |||
201 | +/* | 68 | +/* |
202 | + * QEMU block full disk encryption | 69 | + * The job API is composed of two categories of functions. |
203 | + * | 70 | + * |
204 | + * Copyright (c) 2015-2017 Red Hat, Inc. | 71 | + * The first includes functions used by the monitor. The monitor is |
72 | + * peculiar in that it accesses the job list with job_get, and | ||
73 | + * therefore needs consistency across job_get and the actual operation | ||
74 | + * (e.g. job_user_cancel). To achieve this consistency, the caller | ||
75 | + * calls job_lock/job_unlock itself around the whole operation. | ||
205 | + * | 76 | + * |
206 | + * This library is free software; you can redistribute it and/or | ||
207 | + * modify it under the terms of the GNU Lesser General Public | ||
208 | + * License as published by the Free Software Foundation; either | ||
209 | + * version 2 of the License, or (at your option) any later version. | ||
210 | + * | 77 | + * |
211 | + * This library is distributed in the hope that it will be useful, | 78 | + * The second includes functions used by the job drivers and sometimes |
212 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | 79 | + * by the core block layer. These delegate the locking to the callee instead. |
213 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
214 | + * Lesser General Public License for more details. | ||
215 | + * | 80 | + * |
216 | + * You should have received a copy of the GNU Lesser General Public | 81 | + * TODO Actually make this true |
217 | + * License along with this library; if not, see <http://www.gnu.org/licenses/>. | ||
218 | + * | ||
219 | + */ | 82 | + */ |
220 | + | 83 | + |
221 | +#ifndef BLOCK_CRYPTO_H__ | 84 | /* |
222 | +#define BLOCK_CRYPTO_H__ | 85 | * job_mutex protects the jobs list, but also makes the |
223 | + | 86 | * struct job fields thread-safe. |
224 | +#define BLOCK_CRYPTO_OPT_LUKS_KEY_SECRET "key-secret" | ||
225 | +#define BLOCK_CRYPTO_OPT_LUKS_CIPHER_ALG "cipher-alg" | ||
226 | +#define BLOCK_CRYPTO_OPT_LUKS_CIPHER_MODE "cipher-mode" | ||
227 | +#define BLOCK_CRYPTO_OPT_LUKS_IVGEN_ALG "ivgen-alg" | ||
228 | +#define BLOCK_CRYPTO_OPT_LUKS_IVGEN_HASH_ALG "ivgen-hash-alg" | ||
229 | +#define BLOCK_CRYPTO_OPT_LUKS_HASH_ALG "hash-alg" | ||
230 | +#define BLOCK_CRYPTO_OPT_LUKS_ITER_TIME "iter-time" | ||
231 | + | ||
232 | +#define BLOCK_CRYPTO_OPT_DEF_LUKS_KEY_SECRET \ | ||
233 | + { \ | ||
234 | + .name = BLOCK_CRYPTO_OPT_LUKS_KEY_SECRET, \ | ||
235 | + .type = QEMU_OPT_STRING, \ | ||
236 | + .help = "ID of the secret that provides the keyslot passphrase", \ | ||
237 | + } | ||
238 | + | ||
239 | +#define BLOCK_CRYPTO_OPT_DEF_LUKS_CIPHER_ALG \ | ||
240 | + { \ | ||
241 | + .name = BLOCK_CRYPTO_OPT_LUKS_CIPHER_ALG, \ | ||
242 | + .type = QEMU_OPT_STRING, \ | ||
243 | + .help = "Name of encryption cipher algorithm", \ | ||
244 | + } | ||
245 | + | ||
246 | +#define BLOCK_CRYPTO_OPT_DEF_LUKS_CIPHER_MODE \ | ||
247 | + { \ | ||
248 | + .name = BLOCK_CRYPTO_OPT_LUKS_CIPHER_MODE, \ | ||
249 | + .type = QEMU_OPT_STRING, \ | ||
250 | + .help = "Name of encryption cipher mode", \ | ||
251 | + } | ||
252 | + | ||
253 | +#define BLOCK_CRYPTO_OPT_DEF_LUKS_IVGEN_ALG \ | ||
254 | + { \ | ||
255 | + .name = BLOCK_CRYPTO_OPT_LUKS_IVGEN_ALG, \ | ||
256 | + .type = QEMU_OPT_STRING, \ | ||
257 | + .help = "Name of IV generator algorithm", \ | ||
258 | + } | ||
259 | + | ||
260 | +#define BLOCK_CRYPTO_OPT_DEF_LUKS_IVGEN_HASH_ALG \ | ||
261 | + { \ | ||
262 | + .name = BLOCK_CRYPTO_OPT_LUKS_IVGEN_HASH_ALG, \ | ||
263 | + .type = QEMU_OPT_STRING, \ | ||
264 | + .help = "Name of IV generator hash algorithm", \ | ||
265 | + } | ||
266 | + | ||
267 | +#define BLOCK_CRYPTO_OPT_DEF_LUKS_HASH_ALG \ | ||
268 | + { \ | ||
269 | + .name = BLOCK_CRYPTO_OPT_LUKS_HASH_ALG, \ | ||
270 | + .type = QEMU_OPT_STRING, \ | ||
271 | + .help = "Name of encryption hash algorithm", \ | ||
272 | + } | ||
273 | + | ||
274 | +#define BLOCK_CRYPTO_OPT_DEF_LUKS_ITER_TIME \ | ||
275 | + { \ | ||
276 | + .name = BLOCK_CRYPTO_OPT_LUKS_ITER_TIME, \ | ||
277 | + .type = QEMU_OPT_NUMBER, \ | ||
278 | + .help = "Time to spend in PBKDF in milliseconds", \ | ||
279 | + } | ||
280 | + | ||
281 | +QCryptoBlockCreateOptions * | ||
282 | +block_crypto_create_opts_init(QCryptoBlockFormat format, | ||
283 | + QDict *opts, | ||
284 | + Error **errp); | ||
285 | + | ||
286 | +QCryptoBlockOpenOptions * | ||
287 | +block_crypto_open_opts_init(QCryptoBlockFormat format, | ||
288 | + QDict *opts, | ||
289 | + Error **errp); | ||
290 | + | ||
291 | +#endif /* BLOCK_CRYPTO_H__ */ | ||
292 | -- | 87 | -- |
293 | 1.8.3.1 | 88 | 2.37.3 |
294 | |||
295 | diff view generated by jsdifflib |
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Realize .bdrv_remove_persistent_dirty_bitmap interface. | 3 | Just as done with job.h, create _locked() functions in blockjob.h |
4 | 4 | ||
5 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 5 | These functions will be later useful when caller has already taken |
6 | Reviewed-by: Max Reitz <mreitz@redhat.com> | 6 | the lock. All blockjob _locked functions call job _locked functions. |
7 | Reviewed-by: John Snow <jsnow@redhat.com> | 7 | |
8 | Message-id: 20170628120530.31251-29-vsementsov@virtuozzo.com | 8 | Note: at this stage, job_{lock/unlock} and job lock guard macros |
9 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 9 | are *nop*. |
10 | |||
11 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
12 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> | ||
13 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
14 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
15 | Message-Id: <20220926093214.506243-8-eesposit@redhat.com> | ||
16 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
10 | --- | 17 | --- |
11 | block/qcow2-bitmap.c | 41 +++++++++++++++++++++++++++++++++++++++++ | 18 | include/block/blockjob.h | 18 ++++++++++++++ |
12 | block/qcow2.c | 1 + | 19 | blockjob.c | 52 ++++++++++++++++++++++++++++++++-------- |
13 | block/qcow2.h | 3 +++ | 20 | 2 files changed, 60 insertions(+), 10 deletions(-) |
14 | 3 files changed, 45 insertions(+) | 21 | |
15 | 22 | diff --git a/include/block/blockjob.h b/include/block/blockjob.h | |
16 | diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c | ||
17 | index XXXXXXX..XXXXXXX 100644 | 23 | index XXXXXXX..XXXXXXX 100644 |
18 | --- a/block/qcow2-bitmap.c | 24 | --- a/include/block/blockjob.h |
19 | +++ b/block/qcow2-bitmap.c | 25 | +++ b/include/block/blockjob.h |
20 | @@ -XXX,XX +XXX,XX @@ static Qcow2Bitmap *find_bitmap_by_name(Qcow2BitmapList *bm_list, | 26 | @@ -XXX,XX +XXX,XX @@ typedef struct BlockJob { |
27 | */ | ||
28 | BlockJob *block_job_next(BlockJob *job); | ||
29 | |||
30 | +/* Same as block_job_next(), but called with job lock held. */ | ||
31 | +BlockJob *block_job_next_locked(BlockJob *job); | ||
32 | + | ||
33 | /** | ||
34 | * block_job_get: | ||
35 | * @id: The id of the block job. | ||
36 | @@ -XXX,XX +XXX,XX @@ BlockJob *block_job_next(BlockJob *job); | ||
37 | */ | ||
38 | BlockJob *block_job_get(const char *id); | ||
39 | |||
40 | +/* Same as block_job_get(), but called with job lock held. */ | ||
41 | +BlockJob *block_job_get_locked(const char *id); | ||
42 | + | ||
43 | /** | ||
44 | * block_job_add_bdrv: | ||
45 | * @job: A block job | ||
46 | @@ -XXX,XX +XXX,XX @@ bool block_job_has_bdrv(BlockJob *job, BlockDriverState *bs); | ||
47 | */ | ||
48 | bool block_job_set_speed(BlockJob *job, int64_t speed, Error **errp); | ||
49 | |||
50 | +/* | ||
51 | + * Same as block_job_set_speed(), but called with job lock held. | ||
52 | + * Might release the lock temporarily. | ||
53 | + */ | ||
54 | +bool block_job_set_speed_locked(BlockJob *job, int64_t speed, Error **errp); | ||
55 | + | ||
56 | /** | ||
57 | * block_job_query: | ||
58 | * @job: The job to get information about. | ||
59 | @@ -XXX,XX +XXX,XX @@ bool block_job_set_speed(BlockJob *job, int64_t speed, Error **errp); | ||
60 | */ | ||
61 | BlockJobInfo *block_job_query(BlockJob *job, Error **errp); | ||
62 | |||
63 | +/* Same as block_job_query(), but called with job lock held. */ | ||
64 | +BlockJobInfo *block_job_query_locked(BlockJob *job, Error **errp); | ||
65 | + | ||
66 | /** | ||
67 | * block_job_iostatus_reset: | ||
68 | * @job: The job whose I/O status should be reset. | ||
69 | @@ -XXX,XX +XXX,XX @@ BlockJobInfo *block_job_query(BlockJob *job, Error **errp); | ||
70 | */ | ||
71 | void block_job_iostatus_reset(BlockJob *job); | ||
72 | |||
73 | +/* Same as block_job_iostatus_reset(), but called with job lock held. */ | ||
74 | +void block_job_iostatus_reset_locked(BlockJob *job); | ||
75 | + | ||
76 | /* | ||
77 | * block_job_get_aio_context: | ||
78 | * | ||
79 | diff --git a/blockjob.c b/blockjob.c | ||
80 | index XXXXXXX..XXXXXXX 100644 | ||
81 | --- a/blockjob.c | ||
82 | +++ b/blockjob.c | ||
83 | @@ -XXX,XX +XXX,XX @@ static bool is_block_job(Job *job) | ||
84 | job_type(job) == JOB_TYPE_STREAM; | ||
85 | } | ||
86 | |||
87 | -BlockJob *block_job_next(BlockJob *bjob) | ||
88 | +BlockJob *block_job_next_locked(BlockJob *bjob) | ||
89 | { | ||
90 | Job *job = bjob ? &bjob->job : NULL; | ||
91 | GLOBAL_STATE_CODE(); | ||
92 | |||
93 | do { | ||
94 | - job = job_next(job); | ||
95 | + job = job_next_locked(job); | ||
96 | } while (job && !is_block_job(job)); | ||
97 | |||
98 | return job ? container_of(job, BlockJob, job) : NULL; | ||
99 | } | ||
100 | |||
101 | -BlockJob *block_job_get(const char *id) | ||
102 | +BlockJob *block_job_next(BlockJob *bjob) | ||
103 | { | ||
104 | - Job *job = job_get(id); | ||
105 | + JOB_LOCK_GUARD(); | ||
106 | + return block_job_next_locked(bjob); | ||
107 | +} | ||
108 | + | ||
109 | +BlockJob *block_job_get_locked(const char *id) | ||
110 | +{ | ||
111 | + Job *job = job_get_locked(id); | ||
112 | GLOBAL_STATE_CODE(); | ||
113 | |||
114 | if (job && is_block_job(job)) { | ||
115 | @@ -XXX,XX +XXX,XX @@ BlockJob *block_job_get(const char *id) | ||
116 | } | ||
117 | } | ||
118 | |||
119 | +BlockJob *block_job_get(const char *id) | ||
120 | +{ | ||
121 | + JOB_LOCK_GUARD(); | ||
122 | + return block_job_get_locked(id); | ||
123 | +} | ||
124 | + | ||
125 | void block_job_free(Job *job) | ||
126 | { | ||
127 | BlockJob *bjob = container_of(job, BlockJob, job); | ||
128 | @@ -XXX,XX +XXX,XX @@ static bool job_timer_pending(Job *job) | ||
129 | return timer_pending(&job->sleep_timer); | ||
130 | } | ||
131 | |||
132 | -bool block_job_set_speed(BlockJob *job, int64_t speed, Error **errp) | ||
133 | +bool block_job_set_speed_locked(BlockJob *job, int64_t speed, Error **errp) | ||
134 | { | ||
135 | const BlockJobDriver *drv = block_job_driver(job); | ||
136 | int64_t old_speed = job->speed; | ||
137 | |||
138 | GLOBAL_STATE_CODE(); | ||
139 | |||
140 | - if (job_apply_verb(&job->job, JOB_VERB_SET_SPEED, errp) < 0) { | ||
141 | + if (job_apply_verb_locked(&job->job, JOB_VERB_SET_SPEED, errp) < 0) { | ||
142 | return false; | ||
143 | } | ||
144 | if (speed < 0) { | ||
145 | @@ -XXX,XX +XXX,XX @@ bool block_job_set_speed(BlockJob *job, int64_t speed, Error **errp) | ||
146 | job->speed = speed; | ||
147 | |||
148 | if (drv->set_speed) { | ||
149 | + job_unlock(); | ||
150 | drv->set_speed(job, speed); | ||
151 | + job_lock(); | ||
152 | } | ||
153 | |||
154 | if (speed && speed <= old_speed) { | ||
155 | @@ -XXX,XX +XXX,XX @@ bool block_job_set_speed(BlockJob *job, int64_t speed, Error **errp) | ||
156 | } | ||
157 | |||
158 | /* kick only if a timer is pending */ | ||
159 | - job_enter_cond(&job->job, job_timer_pending); | ||
160 | + job_enter_cond_locked(&job->job, job_timer_pending); | ||
161 | |||
162 | return true; | ||
163 | } | ||
164 | |||
165 | +bool block_job_set_speed(BlockJob *job, int64_t speed, Error **errp) | ||
166 | +{ | ||
167 | + JOB_LOCK_GUARD(); | ||
168 | + return block_job_set_speed_locked(job, speed, errp); | ||
169 | +} | ||
170 | + | ||
171 | int64_t block_job_ratelimit_get_delay(BlockJob *job, uint64_t n) | ||
172 | { | ||
173 | IO_CODE(); | ||
174 | return ratelimit_calculate_delay(&job->limit, n); | ||
175 | } | ||
176 | |||
177 | -BlockJobInfo *block_job_query(BlockJob *job, Error **errp) | ||
178 | +BlockJobInfo *block_job_query_locked(BlockJob *job, Error **errp) | ||
179 | { | ||
180 | BlockJobInfo *info; | ||
181 | uint64_t progress_current, progress_total; | ||
182 | @@ -XXX,XX +XXX,XX @@ BlockJobInfo *block_job_query(BlockJob *job, Error **errp) | ||
183 | info->len = progress_total; | ||
184 | info->speed = job->speed; | ||
185 | info->io_status = job->iostatus; | ||
186 | - info->ready = job_is_ready(&job->job), | ||
187 | + info->ready = job_is_ready_locked(&job->job), | ||
188 | info->status = job->job.status; | ||
189 | info->auto_finalize = job->job.auto_finalize; | ||
190 | info->auto_dismiss = job->job.auto_dismiss; | ||
191 | @@ -XXX,XX +XXX,XX @@ BlockJobInfo *block_job_query(BlockJob *job, Error **errp) | ||
192 | return info; | ||
193 | } | ||
194 | |||
195 | +BlockJobInfo *block_job_query(BlockJob *job, Error **errp) | ||
196 | +{ | ||
197 | + JOB_LOCK_GUARD(); | ||
198 | + return block_job_query_locked(job, errp); | ||
199 | +} | ||
200 | + | ||
201 | static void block_job_iostatus_set_err(BlockJob *job, int error) | ||
202 | { | ||
203 | if (job->iostatus == BLOCK_DEVICE_IO_STATUS_OK) { | ||
204 | @@ -XXX,XX +XXX,XX @@ fail: | ||
21 | return NULL; | 205 | return NULL; |
22 | } | 206 | } |
23 | 207 | ||
24 | +void qcow2_remove_persistent_dirty_bitmap(BlockDriverState *bs, | 208 | -void block_job_iostatus_reset(BlockJob *job) |
25 | + const char *name, | 209 | +void block_job_iostatus_reset_locked(BlockJob *job) |
26 | + Error **errp) | 210 | { |
27 | +{ | 211 | GLOBAL_STATE_CODE(); |
28 | + int ret; | 212 | if (job->iostatus == BLOCK_DEVICE_IO_STATUS_OK) { |
29 | + BDRVQcow2State *s = bs->opaque; | 213 | @@ -XXX,XX +XXX,XX @@ void block_job_iostatus_reset(BlockJob *job) |
30 | + Qcow2Bitmap *bm; | 214 | job->iostatus = BLOCK_DEVICE_IO_STATUS_OK; |
31 | + Qcow2BitmapList *bm_list; | 215 | } |
32 | + | 216 | |
33 | + if (s->nb_bitmaps == 0) { | 217 | +void block_job_iostatus_reset(BlockJob *job) |
34 | + /* Absence of the bitmap is not an error: see explanation above | 218 | +{ |
35 | + * bdrv_remove_persistent_dirty_bitmap() definition. */ | 219 | + JOB_LOCK_GUARD(); |
36 | + return; | 220 | + block_job_iostatus_reset_locked(job); |
37 | + } | 221 | +} |
38 | + | 222 | + |
39 | + bm_list = bitmap_list_load(bs, s->bitmap_directory_offset, | 223 | void block_job_user_resume(Job *job) |
40 | + s->bitmap_directory_size, errp); | 224 | { |
41 | + if (bm_list == NULL) { | 225 | BlockJob *bjob = container_of(job, BlockJob, job); |
42 | + return; | ||
43 | + } | ||
44 | + | ||
45 | + bm = find_bitmap_by_name(bm_list, name); | ||
46 | + if (bm == NULL) { | ||
47 | + goto fail; | ||
48 | + } | ||
49 | + | ||
50 | + QSIMPLEQ_REMOVE(bm_list, bm, Qcow2Bitmap, entry); | ||
51 | + | ||
52 | + ret = update_ext_header_and_dir(bs, bm_list); | ||
53 | + if (ret < 0) { | ||
54 | + error_setg_errno(errp, -ret, "Failed to update bitmap extension"); | ||
55 | + goto fail; | ||
56 | + } | ||
57 | + | ||
58 | + free_bitmap_clusters(bs, &bm->table); | ||
59 | + | ||
60 | +fail: | ||
61 | + bitmap_free(bm); | ||
62 | + bitmap_list_free(bm_list); | ||
63 | +} | ||
64 | + | ||
65 | void qcow2_store_persistent_dirty_bitmaps(BlockDriverState *bs, Error **errp) | ||
66 | { | ||
67 | BdrvDirtyBitmap *bitmap; | ||
68 | diff --git a/block/qcow2.c b/block/qcow2.c | ||
69 | index XXXXXXX..XXXXXXX 100644 | ||
70 | --- a/block/qcow2.c | ||
71 | +++ b/block/qcow2.c | ||
72 | @@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_qcow2 = { | ||
73 | |||
74 | .bdrv_reopen_bitmaps_rw = qcow2_reopen_bitmaps_rw, | ||
75 | .bdrv_can_store_new_dirty_bitmap = qcow2_can_store_new_dirty_bitmap, | ||
76 | + .bdrv_remove_persistent_dirty_bitmap = qcow2_remove_persistent_dirty_bitmap, | ||
77 | }; | ||
78 | |||
79 | static void bdrv_qcow2_init(void) | ||
80 | diff --git a/block/qcow2.h b/block/qcow2.h | ||
81 | index XXXXXXX..XXXXXXX 100644 | ||
82 | --- a/block/qcow2.h | ||
83 | +++ b/block/qcow2.h | ||
84 | @@ -XXX,XX +XXX,XX @@ bool qcow2_can_store_new_dirty_bitmap(BlockDriverState *bs, | ||
85 | const char *name, | ||
86 | uint32_t granularity, | ||
87 | Error **errp); | ||
88 | +void qcow2_remove_persistent_dirty_bitmap(BlockDriverState *bs, | ||
89 | + const char *name, | ||
90 | + Error **errp); | ||
91 | |||
92 | #endif | ||
93 | -- | 226 | -- |
94 | 1.8.3.1 | 227 | 2.37.3 |
95 | |||
96 | diff view generated by jsdifflib |
1 | From: Thomas Huth <thuth@redhat.com> | 1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | We likely do not want to carry these legacy -drive options along forever. | 3 | Both blockdev.c and job-qmp.c have TOC/TOU conditions, because |
4 | Let's emit a deprecation warning for the -drive options that have a | 4 | they first search for the job and then perform an action on it. |
5 | replacement with the -device option, so that the (hopefully few) remaining | 5 | Therefore, we need to do the search + action under the same |
6 | users are aware of this and can adapt their scripts / behaviour accordingly. | 6 | job mutex critical section. |
7 | 7 | ||
8 | Signed-off-by: Thomas Huth <thuth@redhat.com> | 8 | Note: at this stage, job_{lock/unlock} and job lock guard macros |
9 | Reviewed-by: Markus Armbruster <armbru@redhat.com> | 9 | are *nop*. |
10 | |||
11 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
12 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> | ||
13 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
14 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
15 | Message-Id: <20220926093214.506243-9-eesposit@redhat.com> | ||
10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 16 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
11 | --- | 17 | --- |
12 | blockdev.c | 14 ++++++++++++++ | 18 | blockdev.c | 67 +++++++++++++++++++++++++++++++++++++----------------- |
13 | qemu-options.hx | 9 +++++++-- | 19 | job-qmp.c | 57 ++++++++++++++++++++++++++++++++-------------- |
14 | 2 files changed, 21 insertions(+), 2 deletions(-) | 20 | 2 files changed, 86 insertions(+), 38 deletions(-) |
15 | 21 | ||
16 | diff --git a/blockdev.c b/blockdev.c | 22 | diff --git a/blockdev.c b/blockdev.c |
17 | index XXXXXXX..XXXXXXX 100644 | 23 | index XXXXXXX..XXXXXXX 100644 |
18 | --- a/blockdev.c | 24 | --- a/blockdev.c |
19 | +++ b/blockdev.c | 25 | +++ b/blockdev.c |
26 | @@ -XXX,XX +XXX,XX @@ out: | ||
27 | aio_context_release(aio_context); | ||
28 | } | ||
29 | |||
30 | -/* Get a block job using its ID and acquire its AioContext */ | ||
31 | -static BlockJob *find_block_job(const char *id, AioContext **aio_context, | ||
32 | - Error **errp) | ||
33 | +/* | ||
34 | + * Get a block job using its ID and acquire its AioContext. | ||
35 | + * Called with job_mutex held. | ||
36 | + */ | ||
37 | +static BlockJob *find_block_job_locked(const char *id, | ||
38 | + AioContext **aio_context, | ||
39 | + Error **errp) | ||
40 | { | ||
41 | BlockJob *job; | ||
42 | |||
43 | @@ -XXX,XX +XXX,XX @@ static BlockJob *find_block_job(const char *id, AioContext **aio_context, | ||
44 | |||
45 | *aio_context = NULL; | ||
46 | |||
47 | - job = block_job_get(id); | ||
48 | + job = block_job_get_locked(id); | ||
49 | |||
50 | if (!job) { | ||
51 | error_set(errp, ERROR_CLASS_DEVICE_NOT_ACTIVE, | ||
52 | @@ -XXX,XX +XXX,XX @@ static BlockJob *find_block_job(const char *id, AioContext **aio_context, | ||
53 | void qmp_block_job_set_speed(const char *device, int64_t speed, Error **errp) | ||
54 | { | ||
55 | AioContext *aio_context; | ||
56 | - BlockJob *job = find_block_job(device, &aio_context, errp); | ||
57 | + BlockJob *job; | ||
58 | + | ||
59 | + JOB_LOCK_GUARD(); | ||
60 | + job = find_block_job_locked(device, &aio_context, errp); | ||
61 | |||
62 | if (!job) { | ||
63 | return; | ||
64 | } | ||
65 | |||
66 | - block_job_set_speed(job, speed, errp); | ||
67 | + block_job_set_speed_locked(job, speed, errp); | ||
68 | aio_context_release(aio_context); | ||
69 | } | ||
70 | |||
71 | @@ -XXX,XX +XXX,XX @@ void qmp_block_job_cancel(const char *device, | ||
72 | bool has_force, bool force, Error **errp) | ||
73 | { | ||
74 | AioContext *aio_context; | ||
75 | - BlockJob *job = find_block_job(device, &aio_context, errp); | ||
76 | + BlockJob *job; | ||
77 | + | ||
78 | + JOB_LOCK_GUARD(); | ||
79 | + job = find_block_job_locked(device, &aio_context, errp); | ||
80 | |||
81 | if (!job) { | ||
82 | return; | ||
83 | @@ -XXX,XX +XXX,XX @@ void qmp_block_job_cancel(const char *device, | ||
84 | force = false; | ||
85 | } | ||
86 | |||
87 | - if (job_user_paused(&job->job) && !force) { | ||
88 | + if (job_user_paused_locked(&job->job) && !force) { | ||
89 | error_setg(errp, "The block job for device '%s' is currently paused", | ||
90 | device); | ||
91 | goto out; | ||
92 | } | ||
93 | |||
94 | trace_qmp_block_job_cancel(job); | ||
95 | - job_user_cancel(&job->job, force, errp); | ||
96 | + job_user_cancel_locked(&job->job, force, errp); | ||
97 | out: | ||
98 | aio_context_release(aio_context); | ||
99 | } | ||
100 | @@ -XXX,XX +XXX,XX @@ out: | ||
101 | void qmp_block_job_pause(const char *device, Error **errp) | ||
102 | { | ||
103 | AioContext *aio_context; | ||
104 | - BlockJob *job = find_block_job(device, &aio_context, errp); | ||
105 | + BlockJob *job; | ||
106 | + | ||
107 | + JOB_LOCK_GUARD(); | ||
108 | + job = find_block_job_locked(device, &aio_context, errp); | ||
109 | |||
110 | if (!job) { | ||
111 | return; | ||
112 | } | ||
113 | |||
114 | trace_qmp_block_job_pause(job); | ||
115 | - job_user_pause(&job->job, errp); | ||
116 | + job_user_pause_locked(&job->job, errp); | ||
117 | aio_context_release(aio_context); | ||
118 | } | ||
119 | |||
120 | void qmp_block_job_resume(const char *device, Error **errp) | ||
121 | { | ||
122 | AioContext *aio_context; | ||
123 | - BlockJob *job = find_block_job(device, &aio_context, errp); | ||
124 | + BlockJob *job; | ||
125 | + | ||
126 | + JOB_LOCK_GUARD(); | ||
127 | + job = find_block_job_locked(device, &aio_context, errp); | ||
128 | |||
129 | if (!job) { | ||
130 | return; | ||
131 | } | ||
132 | |||
133 | trace_qmp_block_job_resume(job); | ||
134 | - job_user_resume(&job->job, errp); | ||
135 | + job_user_resume_locked(&job->job, errp); | ||
136 | aio_context_release(aio_context); | ||
137 | } | ||
138 | |||
139 | void qmp_block_job_complete(const char *device, Error **errp) | ||
140 | { | ||
141 | AioContext *aio_context; | ||
142 | - BlockJob *job = find_block_job(device, &aio_context, errp); | ||
143 | + BlockJob *job; | ||
144 | + | ||
145 | + JOB_LOCK_GUARD(); | ||
146 | + job = find_block_job_locked(device, &aio_context, errp); | ||
147 | |||
148 | if (!job) { | ||
149 | return; | ||
150 | } | ||
151 | |||
152 | trace_qmp_block_job_complete(job); | ||
153 | - job_complete(&job->job, errp); | ||
154 | + job_complete_locked(&job->job, errp); | ||
155 | aio_context_release(aio_context); | ||
156 | } | ||
157 | |||
158 | void qmp_block_job_finalize(const char *id, Error **errp) | ||
159 | { | ||
160 | AioContext *aio_context; | ||
161 | - BlockJob *job = find_block_job(id, &aio_context, errp); | ||
162 | + BlockJob *job; | ||
163 | + | ||
164 | + JOB_LOCK_GUARD(); | ||
165 | + job = find_block_job_locked(id, &aio_context, errp); | ||
166 | |||
167 | if (!job) { | ||
168 | return; | ||
169 | } | ||
170 | |||
171 | trace_qmp_block_job_finalize(job); | ||
172 | - job_ref(&job->job); | ||
173 | - job_finalize(&job->job, errp); | ||
174 | + job_ref_locked(&job->job); | ||
175 | + job_finalize_locked(&job->job, errp); | ||
176 | |||
177 | /* | ||
178 | * Job's context might have changed via job_finalize (and job_txn_apply | ||
179 | @@ -XXX,XX +XXX,XX @@ void qmp_block_job_finalize(const char *id, Error **errp) | ||
180 | * one. | ||
181 | */ | ||
182 | aio_context = block_job_get_aio_context(job); | ||
183 | - job_unref(&job->job); | ||
184 | + job_unref_locked(&job->job); | ||
185 | aio_context_release(aio_context); | ||
186 | } | ||
187 | |||
188 | void qmp_block_job_dismiss(const char *id, Error **errp) | ||
189 | { | ||
190 | AioContext *aio_context; | ||
191 | - BlockJob *bjob = find_block_job(id, &aio_context, errp); | ||
192 | + BlockJob *bjob; | ||
193 | Job *job; | ||
194 | |||
195 | + JOB_LOCK_GUARD(); | ||
196 | + bjob = find_block_job_locked(id, &aio_context, errp); | ||
197 | + | ||
198 | if (!bjob) { | ||
199 | return; | ||
200 | } | ||
201 | |||
202 | trace_qmp_block_job_dismiss(bjob); | ||
203 | job = &bjob->job; | ||
204 | - job_dismiss(&job, errp); | ||
205 | + job_dismiss_locked(&job, errp); | ||
206 | aio_context_release(aio_context); | ||
207 | } | ||
208 | |||
209 | diff --git a/job-qmp.c b/job-qmp.c | ||
210 | index XXXXXXX..XXXXXXX 100644 | ||
211 | --- a/job-qmp.c | ||
212 | +++ b/job-qmp.c | ||
20 | @@ -XXX,XX +XXX,XX @@ | 213 | @@ -XXX,XX +XXX,XX @@ |
21 | #include "qmp-commands.h" | 214 | #include "qapi/error.h" |
22 | #include "block/trace.h" | 215 | #include "trace/trace-root.h" |
23 | #include "sysemu/arch_init.h" | 216 | |
24 | +#include "sysemu/qtest.h" | 217 | -/* Get a job using its ID and acquire its AioContext */ |
25 | #include "qemu/cutils.h" | 218 | -static Job *find_job(const char *id, AioContext **aio_context, Error **errp) |
26 | #include "qemu/help_option.h" | 219 | +/* |
27 | #include "qemu/throttle-options.h" | 220 | + * Get a job using its ID and acquire its AioContext. |
28 | @@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type) | 221 | + * Called with job_mutex held. |
29 | const char *filename; | 222 | + */ |
30 | Error *local_err = NULL; | 223 | +static Job *find_job_locked(const char *id, |
31 | int i; | 224 | + AioContext **aio_context, |
32 | + const char *deprecated[] = { | 225 | + Error **errp) |
33 | + "serial", "trans", "secs", "heads", "cyls", "addr" | 226 | { |
34 | + }; | 227 | Job *job; |
35 | 228 | ||
36 | /* Change legacy command line options into QMP ones */ | 229 | *aio_context = NULL; |
37 | static const struct { | 230 | |
38 | @@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type) | 231 | - job = job_get(id); |
39 | "update your scripts.\n"); | 232 | + job = job_get_locked(id); |
40 | } | 233 | if (!job) { |
41 | 234 | error_setg(errp, "Job not found"); | |
42 | + /* Other deprecated options */ | 235 | return NULL; |
43 | + if (!qtest_enabled()) { | 236 | @@ -XXX,XX +XXX,XX @@ static Job *find_job(const char *id, AioContext **aio_context, Error **errp) |
44 | + for (i = 0; i < ARRAY_SIZE(deprecated); i++) { | 237 | void qmp_job_cancel(const char *id, Error **errp) |
45 | + if (qemu_opt_get(legacy_opts, deprecated[i]) != NULL) { | 238 | { |
46 | + error_report("'%s' is deprecated, please use the corresponding " | 239 | AioContext *aio_context; |
47 | + "option of '-device' instead", deprecated[i]); | 240 | - Job *job = find_job(id, &aio_context, errp); |
48 | + } | 241 | + Job *job; |
49 | + } | 242 | + |
50 | + } | 243 | + JOB_LOCK_GUARD(); |
51 | + | 244 | + job = find_job_locked(id, &aio_context, errp); |
52 | /* Media type */ | 245 | |
53 | value = qemu_opt_get(legacy_opts, "media"); | 246 | if (!job) { |
54 | if (value) { | 247 | return; |
55 | diff --git a/qemu-options.hx b/qemu-options.hx | 248 | } |
56 | index XXXXXXX..XXXXXXX 100644 | 249 | |
57 | --- a/qemu-options.hx | 250 | trace_qmp_job_cancel(job); |
58 | +++ b/qemu-options.hx | 251 | - job_user_cancel(job, true, errp); |
59 | @@ -XXX,XX +XXX,XX @@ of available connectors of a given interface type. | 252 | + job_user_cancel_locked(job, true, errp); |
60 | This option defines the type of the media: disk or cdrom. | 253 | aio_context_release(aio_context); |
61 | @item cyls=@var{c},heads=@var{h},secs=@var{s}[,trans=@var{t}] | 254 | } |
62 | These options have the same definition as they have in @option{-hdachs}. | 255 | |
63 | +These parameters are deprecated, use the corresponding parameters | 256 | void qmp_job_pause(const char *id, Error **errp) |
64 | +of @code{-device} instead. | 257 | { |
65 | @item snapshot=@var{snapshot} | 258 | AioContext *aio_context; |
66 | @var{snapshot} is "on" or "off" and controls snapshot mode for the given drive | 259 | - Job *job = find_job(id, &aio_context, errp); |
67 | (see @option{-snapshot}). | 260 | + Job *job; |
68 | @@ -XXX,XX +XXX,XX @@ Specify which disk @var{format} will be used rather than detecting | 261 | + |
69 | the format. Can be used to specify format=raw to avoid interpreting | 262 | + JOB_LOCK_GUARD(); |
70 | an untrusted format header. | 263 | + job = find_job_locked(id, &aio_context, errp); |
71 | @item serial=@var{serial} | 264 | |
72 | -This option specifies the serial number to assign to the device. | 265 | if (!job) { |
73 | +This option specifies the serial number to assign to the device. This | 266 | return; |
74 | +parameter is deprecated, use the corresponding parameter of @code{-device} | 267 | } |
75 | +instead. | 268 | |
76 | @item addr=@var{addr} | 269 | trace_qmp_job_pause(job); |
77 | -Specify the controller's PCI address (if=virtio only). | 270 | - job_user_pause(job, errp); |
78 | +Specify the controller's PCI address (if=virtio only). This parameter is | 271 | + job_user_pause_locked(job, errp); |
79 | +deprecated, use the corresponding parameter of @code{-device} instead. | 272 | aio_context_release(aio_context); |
80 | @item werror=@var{action},rerror=@var{action} | 273 | } |
81 | Specify which @var{action} to take on write and read errors. Valid actions are: | 274 | |
82 | "ignore" (ignore the error and try to continue), "stop" (pause QEMU), | 275 | void qmp_job_resume(const char *id, Error **errp) |
276 | { | ||
277 | AioContext *aio_context; | ||
278 | - Job *job = find_job(id, &aio_context, errp); | ||
279 | + Job *job; | ||
280 | + | ||
281 | + JOB_LOCK_GUARD(); | ||
282 | + job = find_job_locked(id, &aio_context, errp); | ||
283 | |||
284 | if (!job) { | ||
285 | return; | ||
286 | } | ||
287 | |||
288 | trace_qmp_job_resume(job); | ||
289 | - job_user_resume(job, errp); | ||
290 | + job_user_resume_locked(job, errp); | ||
291 | aio_context_release(aio_context); | ||
292 | } | ||
293 | |||
294 | void qmp_job_complete(const char *id, Error **errp) | ||
295 | { | ||
296 | AioContext *aio_context; | ||
297 | - Job *job = find_job(id, &aio_context, errp); | ||
298 | + Job *job; | ||
299 | + | ||
300 | + JOB_LOCK_GUARD(); | ||
301 | + job = find_job_locked(id, &aio_context, errp); | ||
302 | |||
303 | if (!job) { | ||
304 | return; | ||
305 | } | ||
306 | |||
307 | trace_qmp_job_complete(job); | ||
308 | - job_complete(job, errp); | ||
309 | + job_complete_locked(job, errp); | ||
310 | aio_context_release(aio_context); | ||
311 | } | ||
312 | |||
313 | void qmp_job_finalize(const char *id, Error **errp) | ||
314 | { | ||
315 | AioContext *aio_context; | ||
316 | - Job *job = find_job(id, &aio_context, errp); | ||
317 | + Job *job; | ||
318 | + | ||
319 | + JOB_LOCK_GUARD(); | ||
320 | + job = find_job_locked(id, &aio_context, errp); | ||
321 | |||
322 | if (!job) { | ||
323 | return; | ||
324 | } | ||
325 | |||
326 | trace_qmp_job_finalize(job); | ||
327 | - job_ref(job); | ||
328 | - job_finalize(job, errp); | ||
329 | + job_ref_locked(job); | ||
330 | + job_finalize_locked(job, errp); | ||
331 | |||
332 | /* | ||
333 | * Job's context might have changed via job_finalize (and job_txn_apply | ||
334 | @@ -XXX,XX +XXX,XX @@ void qmp_job_finalize(const char *id, Error **errp) | ||
335 | * one. | ||
336 | */ | ||
337 | aio_context = job->aio_context; | ||
338 | - job_unref(job); | ||
339 | + job_unref_locked(job); | ||
340 | aio_context_release(aio_context); | ||
341 | } | ||
342 | |||
343 | void qmp_job_dismiss(const char *id, Error **errp) | ||
344 | { | ||
345 | AioContext *aio_context; | ||
346 | - Job *job = find_job(id, &aio_context, errp); | ||
347 | + Job *job; | ||
348 | + | ||
349 | + JOB_LOCK_GUARD(); | ||
350 | + job = find_job_locked(id, &aio_context, errp); | ||
351 | |||
352 | if (!job) { | ||
353 | return; | ||
354 | } | ||
355 | |||
356 | trace_qmp_job_dismiss(job); | ||
357 | - job_dismiss(&job, errp); | ||
358 | + job_dismiss_locked(&job, errp); | ||
359 | aio_context_release(aio_context); | ||
360 | } | ||
361 | |||
83 | -- | 362 | -- |
84 | 1.8.3.1 | 363 | 2.37.3 |
85 | |||
86 | diff view generated by jsdifflib |
1 | From: Hervé Poussineau <hpoussin@reactos.org> | 1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Specification: "FAT: General overview of on-disk format" v1.03, page 23 | 3 | Add missing job synchronization in the unit tests, with |
4 | Signed-off-by: Hervé Poussineau <hpoussin@reactos.org> | 4 | explicit locks. |
5 | |||
6 | We are deliberately using _locked functions wrapped by a guard | ||
7 | instead of a normal call because the normal call will be removed | ||
8 | in future, as the only usage is limited to the tests. | ||
9 | |||
10 | In other words, if a function like job_pause() is/will be only used | ||
11 | in tests to avoid: | ||
12 | |||
13 | WITH_JOB_LOCK_GUARD(){ | ||
14 | job_pause_locked(); | ||
15 | } | ||
16 | |||
17 | then it is not worth keeping job_pause(), and just use the guard. | ||
18 | |||
19 | Note: at this stage, job_{lock/unlock} and job lock guard macros | ||
20 | are *nop*. | ||
21 | |||
22 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
23 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> | ||
24 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
25 | Message-Id: <20220926093214.506243-10-eesposit@redhat.com> | ||
5 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 26 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
6 | --- | 27 | --- |
7 | block/vvfat.c | 9 +++++++-- | 28 | tests/unit/test-bdrv-drain.c | 76 ++++++++++++-------- |
8 | 1 file changed, 7 insertions(+), 2 deletions(-) | 29 | tests/unit/test-block-iothread.c | 8 ++- |
9 | 30 | tests/unit/test-blockjob-txn.c | 24 ++++--- | |
10 | diff --git a/block/vvfat.c b/block/vvfat.c | 31 | tests/unit/test-blockjob.c | 115 +++++++++++++++++++------------ |
32 | 4 files changed, 140 insertions(+), 83 deletions(-) | ||
33 | |||
34 | diff --git a/tests/unit/test-bdrv-drain.c b/tests/unit/test-bdrv-drain.c | ||
11 | index XXXXXXX..XXXXXXX 100644 | 35 | index XXXXXXX..XXXXXXX 100644 |
12 | --- a/block/vvfat.c | 36 | --- a/tests/unit/test-bdrv-drain.c |
13 | +++ b/block/vvfat.c | 37 | +++ b/tests/unit/test-bdrv-drain.c |
14 | @@ -XXX,XX +XXX,XX @@ static direntry_t *create_short_filename(BDRVVVFATState *s, | 38 | @@ -XXX,XX +XXX,XX @@ static void test_blockjob_common_drain_node(enum drain_type drain_type, |
15 | } | 39 | } |
16 | } | 40 | } |
17 | 41 | ||
18 | + if (entry->name[0] == 0xe5) { | 42 | - g_assert_cmpint(job->job.pause_count, ==, 0); |
19 | + entry->name[0] = 0x05; | 43 | - g_assert_false(job->job.paused); |
44 | - g_assert_true(tjob->running); | ||
45 | - g_assert_true(job->job.busy); /* We're in qemu_co_sleep_ns() */ | ||
46 | + WITH_JOB_LOCK_GUARD() { | ||
47 | + g_assert_cmpint(job->job.pause_count, ==, 0); | ||
48 | + g_assert_false(job->job.paused); | ||
49 | + g_assert_true(tjob->running); | ||
50 | + g_assert_true(job->job.busy); /* We're in qemu_co_sleep_ns() */ | ||
51 | + } | ||
52 | |||
53 | do_drain_begin_unlocked(drain_type, drain_bs); | ||
54 | |||
55 | - if (drain_type == BDRV_DRAIN_ALL) { | ||
56 | - /* bdrv_drain_all() drains both src and target */ | ||
57 | - g_assert_cmpint(job->job.pause_count, ==, 2); | ||
58 | - } else { | ||
59 | - g_assert_cmpint(job->job.pause_count, ==, 1); | ||
60 | + WITH_JOB_LOCK_GUARD() { | ||
61 | + if (drain_type == BDRV_DRAIN_ALL) { | ||
62 | + /* bdrv_drain_all() drains both src and target */ | ||
63 | + g_assert_cmpint(job->job.pause_count, ==, 2); | ||
64 | + } else { | ||
65 | + g_assert_cmpint(job->job.pause_count, ==, 1); | ||
66 | + } | ||
67 | + g_assert_true(job->job.paused); | ||
68 | + g_assert_false(job->job.busy); /* The job is paused */ | ||
69 | } | ||
70 | - g_assert_true(job->job.paused); | ||
71 | - g_assert_false(job->job.busy); /* The job is paused */ | ||
72 | |||
73 | do_drain_end_unlocked(drain_type, drain_bs); | ||
74 | |||
75 | if (use_iothread) { | ||
76 | - /* paused is reset in the I/O thread, wait for it */ | ||
77 | + /* | ||
78 | + * Here we are waiting for the paused status to change, | ||
79 | + * so don't bother protecting the read every time. | ||
80 | + * | ||
81 | + * paused is reset in the I/O thread, wait for it | ||
82 | + */ | ||
83 | while (job->job.paused) { | ||
84 | aio_poll(qemu_get_aio_context(), false); | ||
85 | } | ||
86 | } | ||
87 | |||
88 | - g_assert_cmpint(job->job.pause_count, ==, 0); | ||
89 | - g_assert_false(job->job.paused); | ||
90 | - g_assert_true(job->job.busy); /* We're in qemu_co_sleep_ns() */ | ||
91 | + WITH_JOB_LOCK_GUARD() { | ||
92 | + g_assert_cmpint(job->job.pause_count, ==, 0); | ||
93 | + g_assert_false(job->job.paused); | ||
94 | + g_assert_true(job->job.busy); /* We're in qemu_co_sleep_ns() */ | ||
95 | + } | ||
96 | |||
97 | do_drain_begin_unlocked(drain_type, target); | ||
98 | |||
99 | - if (drain_type == BDRV_DRAIN_ALL) { | ||
100 | - /* bdrv_drain_all() drains both src and target */ | ||
101 | - g_assert_cmpint(job->job.pause_count, ==, 2); | ||
102 | - } else { | ||
103 | - g_assert_cmpint(job->job.pause_count, ==, 1); | ||
104 | + WITH_JOB_LOCK_GUARD() { | ||
105 | + if (drain_type == BDRV_DRAIN_ALL) { | ||
106 | + /* bdrv_drain_all() drains both src and target */ | ||
107 | + g_assert_cmpint(job->job.pause_count, ==, 2); | ||
108 | + } else { | ||
109 | + g_assert_cmpint(job->job.pause_count, ==, 1); | ||
110 | + } | ||
111 | + g_assert_true(job->job.paused); | ||
112 | + g_assert_false(job->job.busy); /* The job is paused */ | ||
113 | } | ||
114 | - g_assert_true(job->job.paused); | ||
115 | - g_assert_false(job->job.busy); /* The job is paused */ | ||
116 | |||
117 | do_drain_end_unlocked(drain_type, target); | ||
118 | |||
119 | if (use_iothread) { | ||
120 | - /* paused is reset in the I/O thread, wait for it */ | ||
121 | + /* | ||
122 | + * Here we are waiting for the paused status to change, | ||
123 | + * so don't bother protecting the read every time. | ||
124 | + * | ||
125 | + * paused is reset in the I/O thread, wait for it | ||
126 | + */ | ||
127 | while (job->job.paused) { | ||
128 | aio_poll(qemu_get_aio_context(), false); | ||
129 | } | ||
130 | } | ||
131 | |||
132 | - g_assert_cmpint(job->job.pause_count, ==, 0); | ||
133 | - g_assert_false(job->job.paused); | ||
134 | - g_assert_true(job->job.busy); /* We're in qemu_co_sleep_ns() */ | ||
135 | + WITH_JOB_LOCK_GUARD() { | ||
136 | + g_assert_cmpint(job->job.pause_count, ==, 0); | ||
137 | + g_assert_false(job->job.paused); | ||
138 | + g_assert_true(job->job.busy); /* We're in qemu_co_sleep_ns() */ | ||
139 | + } | ||
140 | |||
141 | aio_context_acquire(ctx); | ||
142 | - ret = job_complete_sync(&job->job, &error_abort); | ||
143 | + WITH_JOB_LOCK_GUARD() { | ||
144 | + ret = job_complete_sync_locked(&job->job, &error_abort); | ||
145 | + } | ||
146 | g_assert_cmpint(ret, ==, (result == TEST_JOB_SUCCESS ? 0 : -EIO)); | ||
147 | |||
148 | if (use_iothread) { | ||
149 | diff --git a/tests/unit/test-block-iothread.c b/tests/unit/test-block-iothread.c | ||
150 | index XXXXXXX..XXXXXXX 100644 | ||
151 | --- a/tests/unit/test-block-iothread.c | ||
152 | +++ b/tests/unit/test-block-iothread.c | ||
153 | @@ -XXX,XX +XXX,XX @@ static void test_attach_blockjob(void) | ||
154 | } | ||
155 | |||
156 | aio_context_acquire(ctx); | ||
157 | - job_complete_sync(&tjob->common.job, &error_abort); | ||
158 | + WITH_JOB_LOCK_GUARD() { | ||
159 | + job_complete_sync_locked(&tjob->common.job, &error_abort); | ||
160 | + } | ||
161 | blk_set_aio_context(blk, qemu_get_aio_context(), &error_abort); | ||
162 | aio_context_release(ctx); | ||
163 | |||
164 | @@ -XXX,XX +XXX,XX @@ static void test_propagate_mirror(void) | ||
165 | BLOCKDEV_ON_ERROR_REPORT, BLOCKDEV_ON_ERROR_REPORT, | ||
166 | false, "filter_node", MIRROR_COPY_MODE_BACKGROUND, | ||
167 | &error_abort); | ||
168 | - job = job_get("job0"); | ||
169 | + WITH_JOB_LOCK_GUARD() { | ||
170 | + job = job_get_locked("job0"); | ||
171 | + } | ||
172 | filter = bdrv_find_node("filter_node"); | ||
173 | |||
174 | /* Change the AioContext of src */ | ||
175 | diff --git a/tests/unit/test-blockjob-txn.c b/tests/unit/test-blockjob-txn.c | ||
176 | index XXXXXXX..XXXXXXX 100644 | ||
177 | --- a/tests/unit/test-blockjob-txn.c | ||
178 | +++ b/tests/unit/test-blockjob-txn.c | ||
179 | @@ -XXX,XX +XXX,XX @@ static void test_single_job(int expected) | ||
180 | job = test_block_job_start(1, true, expected, &result, txn); | ||
181 | job_start(&job->job); | ||
182 | |||
183 | - if (expected == -ECANCELED) { | ||
184 | - job_cancel(&job->job, false); | ||
185 | + WITH_JOB_LOCK_GUARD() { | ||
186 | + if (expected == -ECANCELED) { | ||
187 | + job_cancel_locked(&job->job, false); | ||
188 | + } | ||
189 | } | ||
190 | |||
191 | while (result == -EINPROGRESS) { | ||
192 | @@ -XXX,XX +XXX,XX @@ static void test_pair_jobs(int expected1, int expected2) | ||
193 | /* Release our reference now to trigger as many nice | ||
194 | * use-after-free bugs as possible. | ||
195 | */ | ||
196 | - job_txn_unref(txn); | ||
197 | + WITH_JOB_LOCK_GUARD() { | ||
198 | + job_txn_unref_locked(txn); | ||
199 | |||
200 | - if (expected1 == -ECANCELED) { | ||
201 | - job_cancel(&job1->job, false); | ||
202 | - } | ||
203 | - if (expected2 == -ECANCELED) { | ||
204 | - job_cancel(&job2->job, false); | ||
205 | + if (expected1 == -ECANCELED) { | ||
206 | + job_cancel_locked(&job1->job, false); | ||
207 | + } | ||
208 | + if (expected2 == -ECANCELED) { | ||
209 | + job_cancel_locked(&job2->job, false); | ||
210 | + } | ||
211 | } | ||
212 | |||
213 | while (result1 == -EINPROGRESS || result2 == -EINPROGRESS) { | ||
214 | @@ -XXX,XX +XXX,XX @@ static void test_pair_jobs_fail_cancel_race(void) | ||
215 | job_start(&job1->job); | ||
216 | job_start(&job2->job); | ||
217 | |||
218 | - job_cancel(&job1->job, false); | ||
219 | + WITH_JOB_LOCK_GUARD() { | ||
220 | + job_cancel_locked(&job1->job, false); | ||
221 | + } | ||
222 | |||
223 | /* Now make job2 finish before the main loop kicks jobs. This simulates | ||
224 | * the race between a pending kick and another job completing. | ||
225 | diff --git a/tests/unit/test-blockjob.c b/tests/unit/test-blockjob.c | ||
226 | index XXXXXXX..XXXXXXX 100644 | ||
227 | --- a/tests/unit/test-blockjob.c | ||
228 | +++ b/tests/unit/test-blockjob.c | ||
229 | @@ -XXX,XX +XXX,XX @@ static CancelJob *create_common(Job **pjob) | ||
230 | bjob = mk_job(blk, "Steve", &test_cancel_driver, true, | ||
231 | JOB_MANUAL_FINALIZE | JOB_MANUAL_DISMISS); | ||
232 | job = &bjob->job; | ||
233 | - job_ref(job); | ||
234 | - assert(job->status == JOB_STATUS_CREATED); | ||
235 | + WITH_JOB_LOCK_GUARD() { | ||
236 | + job_ref_locked(job); | ||
237 | + assert(job->status == JOB_STATUS_CREATED); | ||
20 | + } | 238 | + } |
21 | + | 239 | + |
22 | /* numeric-tail generation */ | 240 | s = container_of(bjob, CancelJob, common); |
23 | for (j = 0; j < 8; j++) { | 241 | s->blk = blk; |
24 | if (entry->name[j] == ' ') { | 242 | |
25 | @@ -XXX,XX +XXX,XX @@ static inline void init_fat(BDRVVVFATState* s) | 243 | @@ -XXX,XX +XXX,XX @@ static void cancel_common(CancelJob *s) |
26 | 244 | aio_context_acquire(ctx); | |
27 | } | 245 | |
28 | 246 | job_cancel_sync(&job->job, true); | |
29 | -/* TODO: in create_short_filename, 0xe5->0x05 is not yet handled! */ | 247 | - if (sts != JOB_STATUS_CREATED && sts != JOB_STATUS_CONCLUDED) { |
30 | -/* TODO: in parse_short_filename, 0x05->0xe5 is not yet handled! */ | 248 | - Job *dummy = &job->job; |
31 | static inline direntry_t* create_short_and_long_name(BDRVVVFATState* s, | 249 | - job_dismiss(&dummy, &error_abort); |
32 | unsigned int directory_start, const char* filename, int is_dot) | 250 | + WITH_JOB_LOCK_GUARD() { |
251 | + if (sts != JOB_STATUS_CREATED && sts != JOB_STATUS_CONCLUDED) { | ||
252 | + Job *dummy = &job->job; | ||
253 | + job_dismiss_locked(&dummy, &error_abort); | ||
254 | + } | ||
255 | + assert(job->job.status == JOB_STATUS_NULL); | ||
256 | + job_unref_locked(&job->job); | ||
257 | } | ||
258 | - assert(job->job.status == JOB_STATUS_NULL); | ||
259 | - job_unref(&job->job); | ||
260 | destroy_blk(blk); | ||
261 | |||
262 | aio_context_release(ctx); | ||
263 | @@ -XXX,XX +XXX,XX @@ static void test_cancel_created(void) | ||
264 | cancel_common(s); | ||
265 | } | ||
266 | |||
267 | +static void assert_job_status_is(Job *job, int status) | ||
268 | +{ | ||
269 | + WITH_JOB_LOCK_GUARD() { | ||
270 | + assert(job->status == status); | ||
271 | + } | ||
272 | +} | ||
273 | + | ||
274 | static void test_cancel_running(void) | ||
33 | { | 275 | { |
34 | @@ -XXX,XX +XXX,XX @@ static int parse_short_name(BDRVVVFATState* s, | 276 | Job *job; |
35 | } else | 277 | @@ -XXX,XX +XXX,XX @@ static void test_cancel_running(void) |
36 | lfn->name[i + j + 1] = '\0'; | 278 | s = create_common(&job); |
37 | 279 | ||
38 | + if (lfn->name[0] == 0x05) { | 280 | job_start(job); |
39 | + lfn->name[0] = 0xe5; | 281 | - assert(job->status == JOB_STATUS_RUNNING); |
40 | + } | 282 | + assert_job_status_is(job, JOB_STATUS_RUNNING); |
41 | lfn->len = strlen((char*)lfn->name); | 283 | |
42 | 284 | cancel_common(s); | |
43 | return 0; | 285 | } |
286 | @@ -XXX,XX +XXX,XX @@ static void test_cancel_paused(void) | ||
287 | s = create_common(&job); | ||
288 | |||
289 | job_start(job); | ||
290 | - assert(job->status == JOB_STATUS_RUNNING); | ||
291 | - | ||
292 | - job_user_pause(job, &error_abort); | ||
293 | + WITH_JOB_LOCK_GUARD() { | ||
294 | + assert(job->status == JOB_STATUS_RUNNING); | ||
295 | + job_user_pause_locked(job, &error_abort); | ||
296 | + } | ||
297 | job_enter(job); | ||
298 | - assert(job->status == JOB_STATUS_PAUSED); | ||
299 | + assert_job_status_is(job, JOB_STATUS_PAUSED); | ||
300 | |||
301 | cancel_common(s); | ||
302 | } | ||
303 | @@ -XXX,XX +XXX,XX @@ static void test_cancel_ready(void) | ||
304 | s = create_common(&job); | ||
305 | |||
306 | job_start(job); | ||
307 | - assert(job->status == JOB_STATUS_RUNNING); | ||
308 | + assert_job_status_is(job, JOB_STATUS_RUNNING); | ||
309 | |||
310 | s->should_converge = true; | ||
311 | job_enter(job); | ||
312 | - assert(job->status == JOB_STATUS_READY); | ||
313 | + assert_job_status_is(job, JOB_STATUS_READY); | ||
314 | |||
315 | cancel_common(s); | ||
316 | } | ||
317 | @@ -XXX,XX +XXX,XX @@ static void test_cancel_standby(void) | ||
318 | s = create_common(&job); | ||
319 | |||
320 | job_start(job); | ||
321 | - assert(job->status == JOB_STATUS_RUNNING); | ||
322 | + assert_job_status_is(job, JOB_STATUS_RUNNING); | ||
323 | |||
324 | s->should_converge = true; | ||
325 | job_enter(job); | ||
326 | - assert(job->status == JOB_STATUS_READY); | ||
327 | - | ||
328 | - job_user_pause(job, &error_abort); | ||
329 | + WITH_JOB_LOCK_GUARD() { | ||
330 | + assert(job->status == JOB_STATUS_READY); | ||
331 | + job_user_pause_locked(job, &error_abort); | ||
332 | + } | ||
333 | job_enter(job); | ||
334 | - assert(job->status == JOB_STATUS_STANDBY); | ||
335 | + assert_job_status_is(job, JOB_STATUS_STANDBY); | ||
336 | |||
337 | cancel_common(s); | ||
338 | } | ||
339 | @@ -XXX,XX +XXX,XX @@ static void test_cancel_pending(void) | ||
340 | s = create_common(&job); | ||
341 | |||
342 | job_start(job); | ||
343 | - assert(job->status == JOB_STATUS_RUNNING); | ||
344 | + assert_job_status_is(job, JOB_STATUS_RUNNING); | ||
345 | |||
346 | s->should_converge = true; | ||
347 | job_enter(job); | ||
348 | - assert(job->status == JOB_STATUS_READY); | ||
349 | - | ||
350 | - job_complete(job, &error_abort); | ||
351 | + WITH_JOB_LOCK_GUARD() { | ||
352 | + assert(job->status == JOB_STATUS_READY); | ||
353 | + job_complete_locked(job, &error_abort); | ||
354 | + } | ||
355 | job_enter(job); | ||
356 | while (!job->deferred_to_main_loop) { | ||
357 | aio_poll(qemu_get_aio_context(), true); | ||
358 | } | ||
359 | - assert(job->status == JOB_STATUS_READY); | ||
360 | + assert_job_status_is(job, JOB_STATUS_READY); | ||
361 | aio_poll(qemu_get_aio_context(), true); | ||
362 | - assert(job->status == JOB_STATUS_PENDING); | ||
363 | + assert_job_status_is(job, JOB_STATUS_PENDING); | ||
364 | |||
365 | cancel_common(s); | ||
366 | } | ||
367 | @@ -XXX,XX +XXX,XX @@ static void test_cancel_concluded(void) | ||
368 | s = create_common(&job); | ||
369 | |||
370 | job_start(job); | ||
371 | - assert(job->status == JOB_STATUS_RUNNING); | ||
372 | + assert_job_status_is(job, JOB_STATUS_RUNNING); | ||
373 | |||
374 | s->should_converge = true; | ||
375 | job_enter(job); | ||
376 | - assert(job->status == JOB_STATUS_READY); | ||
377 | - | ||
378 | - job_complete(job, &error_abort); | ||
379 | + WITH_JOB_LOCK_GUARD() { | ||
380 | + assert(job->status == JOB_STATUS_READY); | ||
381 | + job_complete_locked(job, &error_abort); | ||
382 | + } | ||
383 | job_enter(job); | ||
384 | while (!job->deferred_to_main_loop) { | ||
385 | aio_poll(qemu_get_aio_context(), true); | ||
386 | } | ||
387 | - assert(job->status == JOB_STATUS_READY); | ||
388 | + assert_job_status_is(job, JOB_STATUS_READY); | ||
389 | aio_poll(qemu_get_aio_context(), true); | ||
390 | - assert(job->status == JOB_STATUS_PENDING); | ||
391 | + assert_job_status_is(job, JOB_STATUS_PENDING); | ||
392 | |||
393 | aio_context_acquire(job->aio_context); | ||
394 | - job_finalize(job, &error_abort); | ||
395 | + WITH_JOB_LOCK_GUARD() { | ||
396 | + job_finalize_locked(job, &error_abort); | ||
397 | + } | ||
398 | aio_context_release(job->aio_context); | ||
399 | - assert(job->status == JOB_STATUS_CONCLUDED); | ||
400 | + assert_job_status_is(job, JOB_STATUS_CONCLUDED); | ||
401 | |||
402 | cancel_common(s); | ||
403 | } | ||
404 | @@ -XXX,XX +XXX,XX @@ static void test_complete_in_standby(void) | ||
405 | bjob = mk_job(blk, "job", &test_yielding_driver, true, | ||
406 | JOB_MANUAL_FINALIZE | JOB_MANUAL_DISMISS); | ||
407 | job = &bjob->job; | ||
408 | - assert(job->status == JOB_STATUS_CREATED); | ||
409 | + assert_job_status_is(job, JOB_STATUS_CREATED); | ||
410 | |||
411 | /* Wait for the job to become READY */ | ||
412 | job_start(job); | ||
413 | aio_context_acquire(ctx); | ||
414 | + /* | ||
415 | + * Here we are waiting for the status to change, so don't bother | ||
416 | + * protecting the read every time. | ||
417 | + */ | ||
418 | AIO_WAIT_WHILE(ctx, job->status != JOB_STATUS_READY); | ||
419 | aio_context_release(ctx); | ||
420 | |||
421 | /* Begin the drained section, pausing the job */ | ||
422 | bdrv_drain_all_begin(); | ||
423 | - assert(job->status == JOB_STATUS_STANDBY); | ||
424 | + assert_job_status_is(job, JOB_STATUS_STANDBY); | ||
425 | + | ||
426 | /* Lock the IO thread to prevent the job from being run */ | ||
427 | aio_context_acquire(ctx); | ||
428 | /* This will schedule the job to resume it */ | ||
429 | bdrv_drain_all_end(); | ||
430 | |||
431 | - /* But the job cannot run, so it will remain on standby */ | ||
432 | - assert(job->status == JOB_STATUS_STANDBY); | ||
433 | + WITH_JOB_LOCK_GUARD() { | ||
434 | + /* But the job cannot run, so it will remain on standby */ | ||
435 | + assert(job->status == JOB_STATUS_STANDBY); | ||
436 | |||
437 | - /* Even though the job is on standby, this should work */ | ||
438 | - job_complete(job, &error_abort); | ||
439 | + /* Even though the job is on standby, this should work */ | ||
440 | + job_complete_locked(job, &error_abort); | ||
441 | |||
442 | - /* The test is done now, clean up. */ | ||
443 | - job_finish_sync(job, NULL, &error_abort); | ||
444 | - assert(job->status == JOB_STATUS_PENDING); | ||
445 | + /* The test is done now, clean up. */ | ||
446 | + job_finish_sync_locked(job, NULL, &error_abort); | ||
447 | + assert(job->status == JOB_STATUS_PENDING); | ||
448 | |||
449 | - job_finalize(job, &error_abort); | ||
450 | - assert(job->status == JOB_STATUS_CONCLUDED); | ||
451 | + job_finalize_locked(job, &error_abort); | ||
452 | + assert(job->status == JOB_STATUS_CONCLUDED); | ||
453 | |||
454 | - job_dismiss(&job, &error_abort); | ||
455 | + job_dismiss_locked(&job, &error_abort); | ||
456 | + } | ||
457 | |||
458 | destroy_blk(blk); | ||
459 | aio_context_release(ctx); | ||
44 | -- | 460 | -- |
45 | 1.8.3.1 | 461 | 2.37.3 |
46 | |||
47 | diff view generated by jsdifflib |
1 | From: Eric Blake <eblake@redhat.com> | 1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | We are gradually converting to byte-based interfaces, as they are | 3 | Once job lock is used and aiocontext is removed, mirror has |
4 | easier to reason about than sector-based. Convert another internal | 4 | to perform job operations under the same critical section, |
5 | function (no semantic change), and add mirror_clip_bytes() as a | 5 | Note: at this stage, job_{lock/unlock} and job lock guard macros |
6 | counterpart to mirror_clip_sectors(). Some of the conversion is | 6 | are *nop*. |
7 | a bit tricky, requiring temporaries to convert between units; it | ||
8 | will be cleared up in a following patch. | ||
9 | 7 | ||
10 | Signed-off-by: Eric Blake <eblake@redhat.com> | 8 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
11 | Reviewed-by: John Snow <jsnow@redhat.com> | 9 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> |
12 | Reviewed-by: Jeff Cody <jcody@redhat.com> | 10 | Message-Id: <20220926093214.506243-11-eesposit@redhat.com> |
13 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | 11 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> |
14 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
15 | --- | 13 | --- |
16 | block/mirror.c | 63 ++++++++++++++++++++++++++++++++++------------------------ | 14 | block/mirror.c | 13 +++++++++---- |
17 | 1 file changed, 37 insertions(+), 26 deletions(-) | 15 | 1 file changed, 9 insertions(+), 4 deletions(-) |
18 | 16 | ||
19 | diff --git a/block/mirror.c b/block/mirror.c | 17 | diff --git a/block/mirror.c b/block/mirror.c |
20 | index XXXXXXX..XXXXXXX 100644 | 18 | index XXXXXXX..XXXXXXX 100644 |
21 | --- a/block/mirror.c | 19 | --- a/block/mirror.c |
22 | +++ b/block/mirror.c | 20 | +++ b/block/mirror.c |
23 | @@ -XXX,XX +XXX,XX @@ static void mirror_read_complete(void *opaque, int ret) | 21 | @@ -XXX,XX +XXX,XX @@ static void mirror_complete(Job *job, Error **errp) |
24 | aio_context_release(blk_get_aio_context(s->common.blk)); | 22 | s->should_complete = true; |
23 | |||
24 | /* If the job is paused, it will be re-entered when it is resumed */ | ||
25 | - if (!job->paused) { | ||
26 | - job_enter(job); | ||
27 | + WITH_JOB_LOCK_GUARD() { | ||
28 | + if (!job->paused) { | ||
29 | + job_enter_cond_locked(job, NULL); | ||
30 | + } | ||
31 | } | ||
25 | } | 32 | } |
26 | 33 | ||
27 | +/* Clip bytes relative to offset to not exceed end-of-file */ | 34 | @@ -XXX,XX +XXX,XX @@ static bool mirror_drained_poll(BlockJob *job) |
28 | +static inline int64_t mirror_clip_bytes(MirrorBlockJob *s, | 35 | * from one of our own drain sections, to avoid a deadlock waiting for |
29 | + int64_t offset, | 36 | * ourselves. |
30 | + int64_t bytes) | 37 | */ |
31 | +{ | 38 | - if (!s->common.job.paused && !job_is_cancelled(&job->job) && !s->in_drain) { |
32 | + return MIN(bytes, s->bdev_length - offset); | 39 | - return true; |
33 | +} | 40 | + WITH_JOB_LOCK_GUARD() { |
34 | + | 41 | + if (!s->common.job.paused && !job_is_cancelled_locked(&job->job) |
35 | +/* Clip nb_sectors relative to sector_num to not exceed end-of-file */ | 42 | + && !s->in_drain) { |
36 | static inline int mirror_clip_sectors(MirrorBlockJob *s, | 43 | + return true; |
37 | int64_t sector_num, | 44 | + } |
38 | int nb_sectors) | ||
39 | @@ -XXX,XX +XXX,XX @@ static inline int mirror_clip_sectors(MirrorBlockJob *s, | ||
40 | s->bdev_length / BDRV_SECTOR_SIZE - sector_num); | ||
41 | } | ||
42 | |||
43 | -/* Round sector_num and/or nb_sectors to target cluster if COW is needed, and | ||
44 | - * return the offset of the adjusted tail sector against original. */ | ||
45 | -static int mirror_cow_align(MirrorBlockJob *s, | ||
46 | - int64_t *sector_num, | ||
47 | - int *nb_sectors) | ||
48 | +/* Round offset and/or bytes to target cluster if COW is needed, and | ||
49 | + * return the offset of the adjusted tail against original. */ | ||
50 | +static int mirror_cow_align(MirrorBlockJob *s, int64_t *offset, | ||
51 | + unsigned int *bytes) | ||
52 | { | ||
53 | bool need_cow; | ||
54 | int ret = 0; | ||
55 | - int chunk_sectors = s->granularity >> BDRV_SECTOR_BITS; | ||
56 | - int64_t align_sector_num = *sector_num; | ||
57 | - int align_nb_sectors = *nb_sectors; | ||
58 | - int max_sectors = chunk_sectors * s->max_iov; | ||
59 | + int64_t align_offset = *offset; | ||
60 | + unsigned int align_bytes = *bytes; | ||
61 | + int max_bytes = s->granularity * s->max_iov; | ||
62 | |||
63 | - need_cow = !test_bit(*sector_num / chunk_sectors, s->cow_bitmap); | ||
64 | - need_cow |= !test_bit((*sector_num + *nb_sectors - 1) / chunk_sectors, | ||
65 | + need_cow = !test_bit(*offset / s->granularity, s->cow_bitmap); | ||
66 | + need_cow |= !test_bit((*offset + *bytes - 1) / s->granularity, | ||
67 | s->cow_bitmap); | ||
68 | if (need_cow) { | ||
69 | - bdrv_round_sectors_to_clusters(blk_bs(s->target), *sector_num, | ||
70 | - *nb_sectors, &align_sector_num, | ||
71 | - &align_nb_sectors); | ||
72 | + bdrv_round_to_clusters(blk_bs(s->target), *offset, *bytes, | ||
73 | + &align_offset, &align_bytes); | ||
74 | } | 45 | } |
75 | 46 | ||
76 | - if (align_nb_sectors > max_sectors) { | 47 | return !!s->in_flight; |
77 | - align_nb_sectors = max_sectors; | ||
78 | + if (align_bytes > max_bytes) { | ||
79 | + align_bytes = max_bytes; | ||
80 | if (need_cow) { | ||
81 | - align_nb_sectors = QEMU_ALIGN_DOWN(align_nb_sectors, | ||
82 | - s->target_cluster_size >> | ||
83 | - BDRV_SECTOR_BITS); | ||
84 | + align_bytes = QEMU_ALIGN_DOWN(align_bytes, s->target_cluster_size); | ||
85 | } | ||
86 | } | ||
87 | - /* Clipping may result in align_nb_sectors unaligned to chunk boundary, but | ||
88 | + /* Clipping may result in align_bytes unaligned to chunk boundary, but | ||
89 | * that doesn't matter because it's already the end of source image. */ | ||
90 | - align_nb_sectors = mirror_clip_sectors(s, align_sector_num, | ||
91 | - align_nb_sectors); | ||
92 | + align_bytes = mirror_clip_bytes(s, align_offset, align_bytes); | ||
93 | |||
94 | - ret = align_sector_num + align_nb_sectors - (*sector_num + *nb_sectors); | ||
95 | - *sector_num = align_sector_num; | ||
96 | - *nb_sectors = align_nb_sectors; | ||
97 | + ret = align_offset + align_bytes - (*offset + *bytes); | ||
98 | + *offset = align_offset; | ||
99 | + *bytes = align_bytes; | ||
100 | assert(ret >= 0); | ||
101 | return ret; | ||
102 | } | ||
103 | @@ -XXX,XX +XXX,XX @@ static int mirror_do_read(MirrorBlockJob *s, int64_t sector_num, | ||
104 | nb_sectors = MIN(s->buf_size >> BDRV_SECTOR_BITS, nb_sectors); | ||
105 | nb_sectors = MIN(max_sectors, nb_sectors); | ||
106 | assert(nb_sectors); | ||
107 | + assert(nb_sectors < BDRV_REQUEST_MAX_SECTORS); | ||
108 | ret = nb_sectors; | ||
109 | |||
110 | if (s->cow_bitmap) { | ||
111 | - ret += mirror_cow_align(s, §or_num, &nb_sectors); | ||
112 | + int64_t offset = sector_num * BDRV_SECTOR_SIZE; | ||
113 | + unsigned int bytes = nb_sectors * BDRV_SECTOR_SIZE; | ||
114 | + int gap; | ||
115 | + | ||
116 | + gap = mirror_cow_align(s, &offset, &bytes); | ||
117 | + sector_num = offset / BDRV_SECTOR_SIZE; | ||
118 | + nb_sectors = bytes / BDRV_SECTOR_SIZE; | ||
119 | + ret += gap / BDRV_SECTOR_SIZE; | ||
120 | } | ||
121 | assert(nb_sectors << BDRV_SECTOR_BITS <= s->buf_size); | ||
122 | /* The sector range must meet granularity because: | ||
123 | -- | 48 | -- |
124 | 1.8.3.1 | 49 | 2.37.3 |
125 | |||
126 | diff view generated by jsdifflib |
1 | From: "Daniel P. Berrange" <berrange@redhat.com> | 1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Now that all encryption keys must be provided upfront via | 3 | Now that the API offers also _locked() functions, take advantage |
4 | the QCryptoSecret API and associated block driver properties | 4 | of it and give also the caller control to take the lock and call |
5 | there is no need for any explicit encryption handling APIs | 5 | _locked functions. |
6 | in the block layer. Encryption can be handled transparently | 6 | |
7 | within the block driver. We only retain an API for querying | 7 | This makes sense especially when we have for loops, because it |
8 | whether an image is encrypted or not, since that is a | 8 | makes no sense to have: |
9 | potentially useful piece of metadata to report to the user. | 9 | |
10 | 10 | for(job = job_next(); ...) | |
11 | Reviewed-by: Alberto Garcia <berto@igalia.com> | 11 | |
12 | Reviewed-by: Max Reitz <mreitz@redhat.com> | 12 | where each job_next() takes the lock internally. |
13 | Signed-off-by: Daniel P. Berrange <berrange@redhat.com> | 13 | Instead we want |
14 | Message-id: 20170623162419.26068-18-berrange@redhat.com | 14 | |
15 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 15 | JOB_LOCK_GUARD(); |
16 | for(job = job_next_locked(); ...) | ||
17 | |||
18 | In addition, protect also direct field accesses, by either creating a | ||
19 | new critical section or widening the existing ones. | ||
20 | |||
21 | Note: at this stage, job_{lock/unlock} and job lock guard macros | ||
22 | are *nop*. | ||
23 | |||
24 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
25 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> | ||
26 | Message-Id: <20220926093214.506243-12-eesposit@redhat.com> | ||
27 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
28 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
16 | --- | 29 | --- |
17 | block.c | 77 +---------------------------------------------- | 30 | block.c | 17 ++++++++++------- |
18 | block/crypto.c | 1 - | 31 | blockdev.c | 14 ++++++++++---- |
19 | block/qapi.c | 2 +- | 32 | blockjob.c | 35 ++++++++++++++++++++++------------- |
20 | block/qcow.c | 8 ++++- | 33 | job-qmp.c | 9 ++++++--- |
21 | block/qcow2.c | 1 - | 34 | monitor/qmp-cmds.c | 7 +++++-- |
22 | blockdev.c | 37 ++--------------------- | 35 | qemu-img.c | 15 ++++++++++----- |
23 | hmp-commands.hx | 2 ++ | 36 | 6 files changed, 63 insertions(+), 34 deletions(-) |
24 | include/block/block.h | 3 -- | ||
25 | include/block/block_int.h | 1 - | ||
26 | include/qapi/error.h | 1 - | ||
27 | qapi/block-core.json | 37 ++--------------------- | ||
28 | qapi/common.json | 5 +-- | ||
29 | 12 files changed, 16 insertions(+), 159 deletions(-) | ||
30 | 37 | ||
31 | diff --git a/block.c b/block.c | 38 | diff --git a/block.c b/block.c |
32 | index XXXXXXX..XXXXXXX 100644 | 39 | index XXXXXXX..XXXXXXX 100644 |
33 | --- a/block.c | 40 | --- a/block.c |
34 | +++ b/block.c | 41 | +++ b/block.c |
35 | @@ -XXX,XX +XXX,XX @@ static BlockDriverState *bdrv_open_inherit(const char *filename, | ||
36 | goto close_and_fail; | ||
37 | } | ||
38 | |||
39 | - if (!bdrv_key_required(bs)) { | ||
40 | - bdrv_parent_cb_change_media(bs, true); | ||
41 | - } else if (!runstate_check(RUN_STATE_PRELAUNCH) | ||
42 | - && !runstate_check(RUN_STATE_INMIGRATE) | ||
43 | - && !runstate_check(RUN_STATE_PAUSED)) { /* HACK */ | ||
44 | - error_setg(errp, | ||
45 | - "Guest must be stopped for opening of encrypted image"); | ||
46 | - goto close_and_fail; | ||
47 | - } | ||
48 | + bdrv_parent_cb_change_media(bs, true); | ||
49 | |||
50 | QDECREF(options); | ||
51 | |||
52 | @@ -XXX,XX +XXX,XX @@ static void bdrv_close(BlockDriverState *bs) | 42 | @@ -XXX,XX +XXX,XX @@ static void bdrv_close(BlockDriverState *bs) |
53 | bs->backing_format[0] = '\0'; | 43 | |
54 | bs->total_sectors = 0; | 44 | void bdrv_close_all(void) |
55 | bs->encrypted = false; | ||
56 | - bs->valid_key = false; | ||
57 | bs->sg = false; | ||
58 | QDECREF(bs->options); | ||
59 | QDECREF(bs->explicit_options); | ||
60 | @@ -XXX,XX +XXX,XX @@ bool bdrv_is_encrypted(BlockDriverState *bs) | ||
61 | return bs->encrypted; | ||
62 | } | ||
63 | |||
64 | -bool bdrv_key_required(BlockDriverState *bs) | ||
65 | -{ | ||
66 | - BdrvChild *backing = bs->backing; | ||
67 | - | ||
68 | - if (backing && backing->bs->encrypted && !backing->bs->valid_key) { | ||
69 | - return true; | ||
70 | - } | ||
71 | - return (bs->encrypted && !bs->valid_key); | ||
72 | -} | ||
73 | - | ||
74 | -int bdrv_set_key(BlockDriverState *bs, const char *key) | ||
75 | -{ | ||
76 | - int ret; | ||
77 | - if (bs->backing && bs->backing->bs->encrypted) { | ||
78 | - ret = bdrv_set_key(bs->backing->bs, key); | ||
79 | - if (ret < 0) | ||
80 | - return ret; | ||
81 | - if (!bs->encrypted) | ||
82 | - return 0; | ||
83 | - } | ||
84 | - if (!bs->encrypted) { | ||
85 | - return -EINVAL; | ||
86 | - } else if (!bs->drv || !bs->drv->bdrv_set_key) { | ||
87 | - return -ENOMEDIUM; | ||
88 | - } | ||
89 | - ret = bs->drv->bdrv_set_key(bs, key); | ||
90 | - if (ret < 0) { | ||
91 | - bs->valid_key = false; | ||
92 | - } else if (!bs->valid_key) { | ||
93 | - /* call the change callback now, we skipped it on open */ | ||
94 | - bs->valid_key = true; | ||
95 | - bdrv_parent_cb_change_media(bs, true); | ||
96 | - } | ||
97 | - return ret; | ||
98 | -} | ||
99 | - | ||
100 | -/* | ||
101 | - * Provide an encryption key for @bs. | ||
102 | - * If @key is non-null: | ||
103 | - * If @bs is not encrypted, fail. | ||
104 | - * Else if the key is invalid, fail. | ||
105 | - * Else set @bs's key to @key, replacing the existing key, if any. | ||
106 | - * If @key is null: | ||
107 | - * If @bs is encrypted and still lacks a key, fail. | ||
108 | - * Else do nothing. | ||
109 | - * On failure, store an error object through @errp if non-null. | ||
110 | - */ | ||
111 | -void bdrv_add_key(BlockDriverState *bs, const char *key, Error **errp) | ||
112 | -{ | ||
113 | - if (key) { | ||
114 | - if (!bdrv_is_encrypted(bs)) { | ||
115 | - error_setg(errp, "Node '%s' is not encrypted", | ||
116 | - bdrv_get_device_or_node_name(bs)); | ||
117 | - } else if (bdrv_set_key(bs, key) < 0) { | ||
118 | - error_setg(errp, QERR_INVALID_PASSWORD); | ||
119 | - } | ||
120 | - } else { | ||
121 | - if (bdrv_key_required(bs)) { | ||
122 | - error_set(errp, ERROR_CLASS_DEVICE_ENCRYPTED, | ||
123 | - "'%s' (%s) is encrypted", | ||
124 | - bdrv_get_device_or_node_name(bs), | ||
125 | - bdrv_get_encrypted_filename(bs)); | ||
126 | - } | ||
127 | - } | ||
128 | -} | ||
129 | - | ||
130 | const char *bdrv_get_format_name(BlockDriverState *bs) | ||
131 | { | 45 | { |
132 | return bs->drv ? bs->drv->format_name : NULL; | 46 | - assert(job_next(NULL) == NULL); |
133 | diff --git a/block/crypto.c b/block/crypto.c | 47 | GLOBAL_STATE_CODE(); |
134 | index XXXXXXX..XXXXXXX 100644 | 48 | + assert(job_next(NULL) == NULL); |
135 | --- a/block/crypto.c | 49 | |
136 | +++ b/block/crypto.c | 50 | /* Drop references from requests still in flight, such as canceled block |
137 | @@ -XXX,XX +XXX,XX @@ static int block_crypto_open_generic(QCryptoBlockFormat format, | 51 | * jobs whose AIO context has not been polled yet */ |
138 | } | 52 | @@ -XXX,XX +XXX,XX @@ XDbgBlockGraph *bdrv_get_xdbg_block_graph(Error **errp) |
139 | 53 | } | |
140 | bs->encrypted = true; | 54 | } |
141 | - bs->valid_key = true; | 55 | |
142 | 56 | - for (job = block_job_next(NULL); job; job = block_job_next(job)) { | |
143 | ret = 0; | 57 | - GSList *el; |
144 | cleanup: | 58 | + WITH_JOB_LOCK_GUARD() { |
145 | diff --git a/block/qapi.c b/block/qapi.c | 59 | + for (job = block_job_next_locked(NULL); job; |
146 | index XXXXXXX..XXXXXXX 100644 | 60 | + job = block_job_next_locked(job)) { |
147 | --- a/block/qapi.c | 61 | + GSList *el; |
148 | +++ b/block/qapi.c | 62 | |
149 | @@ -XXX,XX +XXX,XX @@ BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk, | 63 | - xdbg_graph_add_node(gr, job, X_DBG_BLOCK_GRAPH_NODE_TYPE_BLOCK_JOB, |
150 | info->ro = bs->read_only; | 64 | - job->job.id); |
151 | info->drv = g_strdup(bs->drv->format_name); | 65 | - for (el = job->nodes; el; el = el->next) { |
152 | info->encrypted = bs->encrypted; | 66 | - xdbg_graph_add_edge(gr, job, (BdrvChild *)el->data); |
153 | - info->encryption_key_missing = bdrv_key_required(bs); | 67 | + xdbg_graph_add_node(gr, job, X_DBG_BLOCK_GRAPH_NODE_TYPE_BLOCK_JOB, |
154 | + info->encryption_key_missing = false; | 68 | + job->job.id); |
155 | 69 | + for (el = job->nodes; el; el = el->next) { | |
156 | info->cache = g_new(BlockdevCacheInfo, 1); | 70 | + xdbg_graph_add_edge(gr, job, (BdrvChild *)el->data); |
157 | *info->cache = (BlockdevCacheInfo) { | 71 | + } |
158 | diff --git a/block/qcow.c b/block/qcow.c | 72 | } |
159 | index XXXXXXX..XXXXXXX 100644 | 73 | } |
160 | --- a/block/qcow.c | 74 | |
161 | +++ b/block/qcow.c | ||
162 | @@ -XXX,XX +XXX,XX @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags, | ||
163 | goto fail; | ||
164 | } | ||
165 | bs->encrypted = true; | ||
166 | - bs->valid_key = true; | ||
167 | + } else { | ||
168 | + if (encryptfmt) { | ||
169 | + error_setg(errp, "No encryption in image header, but options " | ||
170 | + "specified format '%s'", encryptfmt); | ||
171 | + ret = -EINVAL; | ||
172 | + goto fail; | ||
173 | + } | ||
174 | } | ||
175 | s->cluster_bits = header.cluster_bits; | ||
176 | s->cluster_size = 1 << s->cluster_bits; | ||
177 | diff --git a/block/qcow2.c b/block/qcow2.c | ||
178 | index XXXXXXX..XXXXXXX 100644 | ||
179 | --- a/block/qcow2.c | ||
180 | +++ b/block/qcow2.c | ||
181 | @@ -XXX,XX +XXX,XX @@ static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags, | ||
182 | } | ||
183 | |||
184 | bs->encrypted = true; | ||
185 | - bs->valid_key = true; | ||
186 | } | ||
187 | |||
188 | s->l2_bits = s->cluster_bits - 3; /* L2 is always one cluster */ | ||
189 | diff --git a/blockdev.c b/blockdev.c | 75 | diff --git a/blockdev.c b/blockdev.c |
190 | index XXXXXXX..XXXXXXX 100644 | 76 | index XXXXXXX..XXXXXXX 100644 |
191 | --- a/blockdev.c | 77 | --- a/blockdev.c |
192 | +++ b/blockdev.c | 78 | +++ b/blockdev.c |
193 | @@ -XXX,XX +XXX,XX @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts, | 79 | @@ -XXX,XX +XXX,XX @@ void blockdev_mark_auto_del(BlockBackend *blk) |
194 | 80 | return; | |
195 | bs->detect_zeroes = detect_zeroes; | 81 | } |
196 | 82 | ||
197 | - if (bdrv_key_required(bs)) { | 83 | - for (job = block_job_next(NULL); job; job = block_job_next(job)) { |
198 | - autostart = 0; | 84 | + JOB_LOCK_GUARD(); |
199 | - } | 85 | + |
200 | - | 86 | + for (job = block_job_next_locked(NULL); job; |
201 | block_acct_setup(blk_get_stats(blk), account_invalid, account_failed); | 87 | + job = block_job_next_locked(job)) { |
202 | 88 | if (block_job_has_bdrv(job, blk_bs(blk))) { | |
203 | if (!parse_stats_intervals(blk_get_stats(blk), interval_list, errp)) { | 89 | AioContext *aio_context = job->job.aio_context; |
204 | @@ -XXX,XX +XXX,XX @@ void qmp_block_passwd(bool has_device, const char *device, | 90 | aio_context_acquire(aio_context); |
205 | bool has_node_name, const char *node_name, | 91 | |
206 | const char *password, Error **errp) | 92 | - job_cancel(&job->job, false); |
93 | + job_cancel_locked(&job->job, false); | ||
94 | |||
95 | aio_context_release(aio_context); | ||
96 | } | ||
97 | @@ -XXX,XX +XXX,XX @@ BlockJobInfoList *qmp_query_block_jobs(Error **errp) | ||
98 | BlockJobInfoList *head = NULL, **tail = &head; | ||
99 | BlockJob *job; | ||
100 | |||
101 | - for (job = block_job_next(NULL); job; job = block_job_next(job)) { | ||
102 | + JOB_LOCK_GUARD(); | ||
103 | + | ||
104 | + for (job = block_job_next_locked(NULL); job; | ||
105 | + job = block_job_next_locked(job)) { | ||
106 | BlockJobInfo *value; | ||
107 | AioContext *aio_context; | ||
108 | |||
109 | @@ -XXX,XX +XXX,XX @@ BlockJobInfoList *qmp_query_block_jobs(Error **errp) | ||
110 | } | ||
111 | aio_context = block_job_get_aio_context(job); | ||
112 | aio_context_acquire(aio_context); | ||
113 | - value = block_job_query(job, errp); | ||
114 | + value = block_job_query_locked(job, errp); | ||
115 | aio_context_release(aio_context); | ||
116 | if (!value) { | ||
117 | qapi_free_BlockJobInfoList(head); | ||
118 | diff --git a/blockjob.c b/blockjob.c | ||
119 | index XXXXXXX..XXXXXXX 100644 | ||
120 | --- a/blockjob.c | ||
121 | +++ b/blockjob.c | ||
122 | @@ -XXX,XX +XXX,XX @@ static bool child_job_drained_poll(BdrvChild *c) | ||
123 | /* An inactive or completed job doesn't have any pending requests. Jobs | ||
124 | * with !job->busy are either already paused or have a pause point after | ||
125 | * being reentered, so no job driver code will run before they pause. */ | ||
126 | - if (!job->busy || job_is_completed(job)) { | ||
127 | - return false; | ||
128 | + WITH_JOB_LOCK_GUARD() { | ||
129 | + if (!job->busy || job_is_completed_locked(job)) { | ||
130 | + return false; | ||
131 | + } | ||
132 | } | ||
133 | |||
134 | /* Otherwise, assume that it isn't fully stopped yet, but allow the job to | ||
135 | @@ -XXX,XX +XXX,XX @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver, | ||
136 | job->ready_notifier.notify = block_job_event_ready; | ||
137 | job->idle_notifier.notify = block_job_on_idle; | ||
138 | |||
139 | - notifier_list_add(&job->job.on_finalize_cancelled, | ||
140 | - &job->finalize_cancelled_notifier); | ||
141 | - notifier_list_add(&job->job.on_finalize_completed, | ||
142 | - &job->finalize_completed_notifier); | ||
143 | - notifier_list_add(&job->job.on_pending, &job->pending_notifier); | ||
144 | - notifier_list_add(&job->job.on_ready, &job->ready_notifier); | ||
145 | - notifier_list_add(&job->job.on_idle, &job->idle_notifier); | ||
146 | + WITH_JOB_LOCK_GUARD() { | ||
147 | + notifier_list_add(&job->job.on_finalize_cancelled, | ||
148 | + &job->finalize_cancelled_notifier); | ||
149 | + notifier_list_add(&job->job.on_finalize_completed, | ||
150 | + &job->finalize_completed_notifier); | ||
151 | + notifier_list_add(&job->job.on_pending, &job->pending_notifier); | ||
152 | + notifier_list_add(&job->job.on_ready, &job->ready_notifier); | ||
153 | + notifier_list_add(&job->job.on_idle, &job->idle_notifier); | ||
154 | + } | ||
155 | |||
156 | error_setg(&job->blocker, "block device is in use by block job: %s", | ||
157 | job_type_str(&job->job)); | ||
158 | @@ -XXX,XX +XXX,XX @@ BlockErrorAction block_job_error_action(BlockJob *job, BlockdevOnError on_err, | ||
159 | action); | ||
160 | } | ||
161 | if (action == BLOCK_ERROR_ACTION_STOP) { | ||
162 | - if (!job->job.user_paused) { | ||
163 | - job_pause(&job->job); | ||
164 | - /* make the pause user visible, which will be resumed from QMP. */ | ||
165 | - job->job.user_paused = true; | ||
166 | + WITH_JOB_LOCK_GUARD() { | ||
167 | + if (!job->job.user_paused) { | ||
168 | + job_pause_locked(&job->job); | ||
169 | + /* | ||
170 | + * make the pause user visible, which will be | ||
171 | + * resumed from QMP. | ||
172 | + */ | ||
173 | + job->job.user_paused = true; | ||
174 | + } | ||
175 | } | ||
176 | block_job_iostatus_set_err(job, error); | ||
177 | } | ||
178 | diff --git a/job-qmp.c b/job-qmp.c | ||
179 | index XXXXXXX..XXXXXXX 100644 | ||
180 | --- a/job-qmp.c | ||
181 | +++ b/job-qmp.c | ||
182 | @@ -XXX,XX +XXX,XX @@ void qmp_job_dismiss(const char *id, Error **errp) | ||
183 | aio_context_release(aio_context); | ||
184 | } | ||
185 | |||
186 | -static JobInfo *job_query_single(Job *job, Error **errp) | ||
187 | +/* Called with job_mutex held. */ | ||
188 | +static JobInfo *job_query_single_locked(Job *job, Error **errp) | ||
207 | { | 189 | { |
208 | - Error *local_err = NULL; | 190 | JobInfo *info; |
209 | - BlockDriverState *bs; | 191 | uint64_t progress_current; |
210 | - AioContext *aio_context; | 192 | @@ -XXX,XX +XXX,XX @@ JobInfoList *qmp_query_jobs(Error **errp) |
211 | - | 193 | JobInfoList *head = NULL, **tail = &head; |
212 | - bs = bdrv_lookup_bs(has_device ? device : NULL, | 194 | Job *job; |
213 | - has_node_name ? node_name : NULL, | 195 | |
214 | - &local_err); | 196 | - for (job = job_next(NULL); job; job = job_next(job)) { |
215 | - if (local_err) { | 197 | + JOB_LOCK_GUARD(); |
216 | - error_propagate(errp, local_err); | ||
217 | - return; | ||
218 | - } | ||
219 | - | ||
220 | - aio_context = bdrv_get_aio_context(bs); | ||
221 | - aio_context_acquire(aio_context); | ||
222 | - | ||
223 | - bdrv_add_key(bs, password, errp); | ||
224 | - | ||
225 | - aio_context_release(aio_context); | ||
226 | + error_setg(errp, | ||
227 | + "Setting block passwords directly is no longer supported"); | ||
228 | } | ||
229 | |||
230 | /* | ||
231 | @@ -XXX,XX +XXX,XX @@ void qmp_blockdev_change_medium(bool has_device, const char *device, | ||
232 | goto fail; | ||
233 | } | ||
234 | |||
235 | - bdrv_add_key(medium_bs, NULL, &err); | ||
236 | - if (err) { | ||
237 | - error_propagate(errp, err); | ||
238 | - goto fail; | ||
239 | - } | ||
240 | - | ||
241 | rc = do_open_tray(has_device ? device : NULL, | ||
242 | has_id ? id : NULL, | ||
243 | false, &err); | ||
244 | @@ -XXX,XX +XXX,XX @@ void qmp_blockdev_add(BlockdevOptions *options, Error **errp) | ||
245 | |||
246 | QTAILQ_INSERT_TAIL(&monitor_bdrv_states, bs, monitor_list); | ||
247 | |||
248 | - if (bs && bdrv_key_required(bs)) { | ||
249 | - QTAILQ_REMOVE(&monitor_bdrv_states, bs, monitor_list); | ||
250 | - bdrv_unref(bs); | ||
251 | - error_setg(errp, "blockdev-add doesn't support encrypted devices"); | ||
252 | - goto fail; | ||
253 | - } | ||
254 | - | ||
255 | fail: | ||
256 | visit_free(v); | ||
257 | } | ||
258 | diff --git a/hmp-commands.hx b/hmp-commands.hx | ||
259 | index XXXXXXX..XXXXXXX 100644 | ||
260 | --- a/hmp-commands.hx | ||
261 | +++ b/hmp-commands.hx | ||
262 | @@ -XXX,XX +XXX,XX @@ STEXI | ||
263 | @item block_passwd @var{device} @var{password} | ||
264 | @findex block_passwd | ||
265 | Set the encrypted device @var{device} password to @var{password} | ||
266 | + | 198 | + |
267 | +This command is now obsolete and will always return an error since 2.10 | 199 | + for (job = job_next_locked(NULL); job; job = job_next_locked(job)) { |
268 | ETEXI | 200 | JobInfo *value; |
269 | 201 | AioContext *aio_context; | |
270 | { | 202 | |
271 | diff --git a/include/block/block.h b/include/block/block.h | 203 | @@ -XXX,XX +XXX,XX @@ JobInfoList *qmp_query_jobs(Error **errp) |
272 | index XXXXXXX..XXXXXXX 100644 | 204 | } |
273 | --- a/include/block/block.h | 205 | aio_context = job->aio_context; |
274 | +++ b/include/block/block.h | 206 | aio_context_acquire(aio_context); |
275 | @@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_next(BdrvNextIterator *it); | 207 | - value = job_query_single(job, errp); |
276 | 208 | + value = job_query_single_locked(job, errp); | |
277 | BlockDriverState *bdrv_next_monitor_owned(BlockDriverState *bs); | 209 | aio_context_release(aio_context); |
278 | bool bdrv_is_encrypted(BlockDriverState *bs); | 210 | if (!value) { |
279 | -bool bdrv_key_required(BlockDriverState *bs); | 211 | qapi_free_JobInfoList(head); |
280 | -int bdrv_set_key(BlockDriverState *bs, const char *key); | 212 | diff --git a/monitor/qmp-cmds.c b/monitor/qmp-cmds.c |
281 | -void bdrv_add_key(BlockDriverState *bs, const char *key, Error **errp); | 213 | index XXXXXXX..XXXXXXX 100644 |
282 | void bdrv_iterate_format(void (*it)(void *opaque, const char *name), | 214 | --- a/monitor/qmp-cmds.c |
283 | void *opaque); | 215 | +++ b/monitor/qmp-cmds.c |
284 | const char *bdrv_get_node_name(const BlockDriverState *bs); | 216 | @@ -XXX,XX +XXX,XX @@ void qmp_cont(Error **errp) |
285 | diff --git a/include/block/block_int.h b/include/block/block_int.h | 217 | blk_iostatus_reset(blk); |
286 | index XXXXXXX..XXXXXXX 100644 | 218 | } |
287 | --- a/include/block/block_int.h | 219 | |
288 | +++ b/include/block/block_int.h | 220 | - for (job = block_job_next(NULL); job; job = block_job_next(job)) { |
289 | @@ -XXX,XX +XXX,XX @@ struct BlockDriverState { | 221 | - block_job_iostatus_reset(job); |
290 | int open_flags; /* flags used to open the file, re-used for re-open */ | 222 | + WITH_JOB_LOCK_GUARD() { |
291 | bool read_only; /* if true, the media is read only */ | 223 | + for (job = block_job_next_locked(NULL); job; |
292 | bool encrypted; /* if true, the media is encrypted */ | 224 | + job = block_job_next_locked(job)) { |
293 | - bool valid_key; /* if true, a valid encryption key has been set */ | 225 | + block_job_iostatus_reset_locked(job); |
294 | bool sg; /* if true, the device is a /dev/sg* */ | 226 | + } |
295 | bool probed; /* if true, format was probed rather than specified */ | 227 | } |
296 | bool force_share; /* if true, always allow all shared permissions */ | 228 | |
297 | diff --git a/include/qapi/error.h b/include/qapi/error.h | 229 | /* Continuing after completed migration. Images have been inactivated to |
298 | index XXXXXXX..XXXXXXX 100644 | 230 | diff --git a/qemu-img.c b/qemu-img.c |
299 | --- a/include/qapi/error.h | 231 | index XXXXXXX..XXXXXXX 100644 |
300 | +++ b/include/qapi/error.h | 232 | --- a/qemu-img.c |
301 | @@ -XXX,XX +XXX,XX @@ | 233 | +++ b/qemu-img.c |
302 | typedef enum ErrorClass { | 234 | @@ -XXX,XX +XXX,XX @@ static void run_block_job(BlockJob *job, Error **errp) |
303 | ERROR_CLASS_GENERIC_ERROR = QAPI_ERROR_CLASS_GENERICERROR, | 235 | int ret = 0; |
304 | ERROR_CLASS_COMMAND_NOT_FOUND = QAPI_ERROR_CLASS_COMMANDNOTFOUND, | 236 | |
305 | - ERROR_CLASS_DEVICE_ENCRYPTED = QAPI_ERROR_CLASS_DEVICEENCRYPTED, | 237 | aio_context_acquire(aio_context); |
306 | ERROR_CLASS_DEVICE_NOT_ACTIVE = QAPI_ERROR_CLASS_DEVICENOTACTIVE, | 238 | - job_ref(&job->job); |
307 | ERROR_CLASS_DEVICE_NOT_FOUND = QAPI_ERROR_CLASS_DEVICENOTFOUND, | 239 | + job_lock(); |
308 | ERROR_CLASS_KVM_MISSING_CAP = QAPI_ERROR_CLASS_KVMMISSINGCAP, | 240 | + job_ref_locked(&job->job); |
309 | diff --git a/qapi/block-core.json b/qapi/block-core.json | 241 | do { |
310 | index XXXXXXX..XXXXXXX 100644 | 242 | float progress = 0.0f; |
311 | --- a/qapi/block-core.json | 243 | + job_unlock(); |
312 | +++ b/qapi/block-core.json | 244 | aio_poll(aio_context, true); |
313 | @@ -XXX,XX +XXX,XX @@ | 245 | |
314 | # | 246 | progress_get_snapshot(&job->job.progress, &progress_current, |
315 | # @encrypted: true if the backing device is encrypted | 247 | @@ -XXX,XX +XXX,XX @@ static void run_block_job(BlockJob *job, Error **errp) |
316 | # | 248 | progress = (float)progress_current / progress_total * 100.f; |
317 | -# @encryption_key_missing: true if the backing device is encrypted but an | 249 | } |
318 | -# valid encryption key is missing | 250 | qemu_progress_print(progress, 0); |
319 | +# @encryption_key_missing: Deprecated; always false | 251 | - } while (!job_is_ready(&job->job) && !job_is_completed(&job->job)); |
320 | # | 252 | + job_lock(); |
321 | # @detect_zeroes: detect and optimize zero writes (Since 2.1) | 253 | + } while (!job_is_ready_locked(&job->job) && |
322 | # | 254 | + !job_is_completed_locked(&job->job)); |
323 | @@ -XXX,XX +XXX,XX @@ | 255 | |
324 | # This command sets the password of a block device that has not been open | 256 | - if (!job_is_completed(&job->job)) { |
325 | # with a password and requires one. | 257 | - ret = job_complete_sync(&job->job, errp); |
326 | # | 258 | + if (!job_is_completed_locked(&job->job)) { |
327 | -# The two cases where this can happen are a block device is created through | 259 | + ret = job_complete_sync_locked(&job->job, errp); |
328 | -# QEMU's initial command line or a block device is changed through the legacy | 260 | } else { |
329 | -# @change interface. | 261 | ret = job->job.ret; |
330 | -# | 262 | } |
331 | -# In the event that the block device is created through the initial command | 263 | - job_unref(&job->job); |
332 | -# line, the VM will start in the stopped state regardless of whether '-S' is | 264 | + job_unref_locked(&job->job); |
333 | -# used. The intention is for a management tool to query the block devices to | 265 | + job_unlock(); |
334 | -# determine which ones are encrypted, set the passwords with this command, and | 266 | aio_context_release(aio_context); |
335 | -# then start the guest with the @cont command. | 267 | |
336 | -# | 268 | /* publish completion progress only when success */ |
337 | -# Either @device or @node-name must be set but not both. | ||
338 | -# | ||
339 | -# @device: the name of the block backend device to set the password on | ||
340 | -# | ||
341 | -# @node-name: graph node name to set the password on (Since 2.0) | ||
342 | -# | ||
343 | -# @password: the password to use for the device | ||
344 | -# | ||
345 | -# Returns: nothing on success | ||
346 | -# If @device is not a valid block device, DeviceNotFound | ||
347 | -# If @device is not encrypted, DeviceNotEncrypted | ||
348 | -# | ||
349 | -# Notes: Not all block formats support encryption and some that do are not | ||
350 | -# able to validate that a password is correct. Disk corruption may | ||
351 | -# occur if an invalid password is specified. | ||
352 | -# | ||
353 | -# Since: 0.14.0 | ||
354 | -# | ||
355 | -# Example: | ||
356 | -# | ||
357 | -# -> { "execute": "block_passwd", "arguments": { "device": "ide0-hd0", | ||
358 | -# "password": "12345" } } | ||
359 | -# <- { "return": {} } | ||
360 | +# This command is now obsolete and will always return an error since 2.10 | ||
361 | # | ||
362 | ## | ||
363 | { 'command': 'block_passwd', 'data': {'*device': 'str', | ||
364 | diff --git a/qapi/common.json b/qapi/common.json | ||
365 | index XXXXXXX..XXXXXXX 100644 | ||
366 | --- a/qapi/common.json | ||
367 | +++ b/qapi/common.json | ||
368 | @@ -XXX,XX +XXX,XX @@ | ||
369 | # | ||
370 | # @CommandNotFound: the requested command has not been found | ||
371 | # | ||
372 | -# @DeviceEncrypted: the requested operation can't be fulfilled because the | ||
373 | -# selected device is encrypted | ||
374 | -# | ||
375 | # @DeviceNotActive: a device has failed to be become active | ||
376 | # | ||
377 | # @DeviceNotFound: the requested device has not been found | ||
378 | @@ -XXX,XX +XXX,XX @@ | ||
379 | ## | ||
380 | { 'enum': 'QapiErrorClass', | ||
381 | # Keep this in sync with ErrorClass in error.h | ||
382 | - 'data': [ 'GenericError', 'CommandNotFound', 'DeviceEncrypted', | ||
383 | + 'data': [ 'GenericError', 'CommandNotFound', | ||
384 | 'DeviceNotActive', 'DeviceNotFound', 'KVMMissingCap' ] } | ||
385 | |||
386 | ## | ||
387 | -- | 269 | -- |
388 | 1.8.3.1 | 270 | 2.37.3 |
389 | |||
390 | diff view generated by jsdifflib |
1 | From: Hervé Poussineau <hpoussin@reactos.org> | 1 | From: Paolo Bonzini <pbonzini@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | More specifically, create short name from filename and change blacklist of | 3 | We want to make sure access of job->aio_context is always done |
4 | invalid chars to whitelist of valid chars. | 4 | under either BQL or job_mutex. The problem is that using |
5 | aio_co_enter(job->aiocontext, job->co) in job_start and job_enter_cond | ||
6 | makes the coroutine immediately resume, so we can't hold the job lock. | ||
7 | And caching it is not safe either, as it might change. | ||
5 | 8 | ||
6 | Windows 9x also now correctly see long file names of filenames containing a space, | 9 | job_start is under BQL, so it can freely read job->aiocontext, but |
7 | but Scandisk still complains about mismatch between SFN and LFN. | 10 | job_enter_cond is not. |
11 | We want to avoid reading job->aio_context in job_enter_cond, therefore: | ||
12 | 1) use aio_co_wake(), since it doesn't want an aiocontext as argument | ||
13 | but uses job->co->ctx | ||
14 | 2) detect possible discrepancy between job->co->ctx and job->aio_context | ||
15 | by checking right after the coroutine resumes back from yielding if | ||
16 | job->aio_context has changed. If so, reschedule the coroutine to the | ||
17 | new context. | ||
8 | 18 | ||
9 | [kwolf: Build fix for this intermediate patch (it included declarations | 19 | Calling bdrv_try_set_aio_context() will issue the following calls |
10 | for variables that are only used in the next patch) ] | 20 | (simplified): |
21 | * in terms of bdrv callbacks: | ||
22 | .drained_begin -> .set_aio_context -> .drained_end | ||
23 | * in terms of child_job functions: | ||
24 | child_job_drained_begin -> child_job_set_aio_context -> child_job_drained_end | ||
25 | * in terms of job functions: | ||
26 | job_pause_locked -> job_set_aio_context -> job_resume_locked | ||
11 | 27 | ||
12 | Specification: "FAT: General overview of on-disk format" v1.03, pages 30-31 | 28 | We can see that after setting the new aio_context, job_resume_locked |
13 | Signed-off-by: Hervé Poussineau <hpoussin@reactos.org> | 29 | calls again job_enter_cond, which then invokes aio_co_wake(). But |
30 | while job->aiocontext has been set in job_set_aio_context, | ||
31 | job->co->ctx has not changed, so the coroutine would be entering in | ||
32 | the wrong aiocontext. | ||
33 | |||
34 | Using aio_co_schedule in job_resume_locked() might seem as a valid | ||
35 | alternative, but the problem is that the bh resuming the coroutine | ||
36 | is not scheduled immediately, and if in the meanwhile another | ||
37 | bdrv_try_set_aio_context() is run (see test_propagate_mirror() in | ||
38 | test-block-iothread.c), we would have the first schedule in the | ||
39 | wrong aiocontext, and the second set of drains won't even manage | ||
40 | to schedule the coroutine, as job->busy would still be true from | ||
41 | the previous job_resume_locked(). | ||
42 | |||
43 | The solution is to stick with aio_co_wake() and detect every time | ||
44 | the coroutine resumes back from yielding if job->aio_context | ||
45 | has changed. If so, we can reschedule it to the new context. | ||
46 | |||
47 | Check for the aiocontext change in job_do_yield_locked because: | ||
48 | 1) aio_co_reschedule_self requires to be in the running coroutine | ||
49 | 2) since child_job_set_aio_context allows changing the aiocontext only | ||
50 | while the job is paused, this is the exact place where the coroutine | ||
51 | resumes, before running JobDriver's code. | ||
52 | |||
53 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> | ||
54 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
55 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> | ||
56 | Message-Id: <20220926093214.506243-13-eesposit@redhat.com> | ||
57 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
14 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 58 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
15 | --- | 59 | --- |
16 | block/vvfat.c | 104 ++++++++++++++++++++++++++++++++++++++++++---------------- | 60 | job.c | 19 +++++++++++++++++-- |
17 | 1 file changed, 76 insertions(+), 28 deletions(-) | 61 | 1 file changed, 17 insertions(+), 2 deletions(-) |
18 | 62 | ||
19 | diff --git a/block/vvfat.c b/block/vvfat.c | 63 | diff --git a/job.c b/job.c |
20 | index XXXXXXX..XXXXXXX 100644 | 64 | index XXXXXXX..XXXXXXX 100644 |
21 | --- a/block/vvfat.c | 65 | --- a/job.c |
22 | +++ b/block/vvfat.c | 66 | +++ b/job.c |
23 | @@ -XXX,XX +XXX,XX @@ static void set_begin_of_direntry(direntry_t* direntry, uint32_t begin) | 67 | @@ -XXX,XX +XXX,XX @@ void job_enter_cond_locked(Job *job, bool(*fn)(Job *job)) |
24 | direntry->begin_hi = cpu_to_le16((begin >> 16) & 0xffff); | 68 | job->busy = true; |
69 | real_job_unlock(); | ||
70 | job_unlock(); | ||
71 | - aio_co_enter(job->aio_context, job->co); | ||
72 | + aio_co_wake(job->co); | ||
73 | job_lock(); | ||
25 | } | 74 | } |
26 | 75 | ||
27 | +static uint8_t to_valid_short_char(gunichar c) | 76 | @@ -XXX,XX +XXX,XX @@ void job_enter(Job *job) |
28 | +{ | 77 | */ |
29 | + c = g_unichar_toupper(c); | 78 | static void coroutine_fn job_do_yield_locked(Job *job, uint64_t ns) |
30 | + if ((c >= '0' && c <= '9') || | 79 | { |
31 | + (c >= 'A' && c <= 'Z') || | 80 | + AioContext *next_aio_context; |
32 | + strchr("$%'-_@~`!(){}^#&", c) != 0) { | ||
33 | + return c; | ||
34 | + } else { | ||
35 | + return 0; | ||
36 | + } | ||
37 | +} | ||
38 | + | 81 | + |
39 | +static direntry_t *create_short_filename(BDRVVVFATState *s, | 82 | real_job_lock(); |
40 | + const char *filename) | 83 | if (ns != -1) { |
41 | +{ | 84 | timer_mod(&job->sleep_timer, ns); |
42 | + int j = 0; | 85 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn job_do_yield_locked(Job *job, uint64_t ns) |
43 | + direntry_t *entry = array_get_next(&(s->directory)); | 86 | qemu_coroutine_yield(); |
44 | + const gchar *p, *last_dot = NULL; | 87 | job_lock(); |
45 | + gunichar c; | 88 | |
46 | + bool lossy_conversion = false; | 89 | - /* Set by job_enter_cond() before re-entering the coroutine. */ |
47 | + | 90 | + next_aio_context = job->aio_context; |
48 | + if (!entry) { | 91 | + /* |
49 | + return NULL; | 92 | + * Coroutine has resumed, but in the meanwhile the job AioContext |
50 | + } | 93 | + * might have changed via bdrv_try_set_aio_context(), so we need to move |
51 | + memset(entry->name, 0x20, sizeof(entry->name)); | 94 | + * the coroutine too in the new aiocontext. |
52 | + | 95 | + */ |
53 | + /* copy filename and search last dot */ | 96 | + while (qemu_get_current_aio_context() != next_aio_context) { |
54 | + for (p = filename; ; p = g_utf8_next_char(p)) { | 97 | + job_unlock(); |
55 | + c = g_utf8_get_char(p); | 98 | + aio_co_reschedule_self(next_aio_context); |
56 | + if (c == '\0') { | 99 | + job_lock(); |
57 | + break; | 100 | + next_aio_context = job->aio_context; |
58 | + } else if (c == '.') { | ||
59 | + if (j == 0) { | ||
60 | + /* '.' at start of filename */ | ||
61 | + lossy_conversion = true; | ||
62 | + } else { | ||
63 | + if (last_dot) { | ||
64 | + lossy_conversion = true; | ||
65 | + } | ||
66 | + last_dot = p; | ||
67 | + } | ||
68 | + } else if (!last_dot) { | ||
69 | + /* first part of the name; copy it */ | ||
70 | + uint8_t v = to_valid_short_char(c); | ||
71 | + if (j < 8 && v) { | ||
72 | + entry->name[j++] = v; | ||
73 | + } else { | ||
74 | + lossy_conversion = true; | ||
75 | + } | ||
76 | + } | ||
77 | + } | 101 | + } |
78 | + | 102 | + |
79 | + /* copy extension (if any) */ | 103 | + /* Set by job_enter_cond_locked() before re-entering the coroutine. */ |
80 | + if (last_dot) { | 104 | assert(job->busy); |
81 | + j = 0; | 105 | } |
82 | + for (p = g_utf8_next_char(last_dot); ; p = g_utf8_next_char(p)) { | 106 | |
83 | + c = g_utf8_get_char(p); | ||
84 | + if (c == '\0') { | ||
85 | + break; | ||
86 | + } else { | ||
87 | + /* extension; copy it */ | ||
88 | + uint8_t v = to_valid_short_char(c); | ||
89 | + if (j < 3 && v) { | ||
90 | + entry->name[8 + (j++)] = v; | ||
91 | + } else { | ||
92 | + lossy_conversion = true; | ||
93 | + } | ||
94 | + } | ||
95 | + } | ||
96 | + } | ||
97 | + (void)lossy_conversion; | ||
98 | + return entry; | ||
99 | +} | ||
100 | + | ||
101 | /* fat functions */ | ||
102 | |||
103 | static inline uint8_t fat_chksum(const direntry_t* entry) | ||
104 | @@ -XXX,XX +XXX,XX @@ static inline void init_fat(BDRVVVFATState* s) | ||
105 | static inline direntry_t* create_short_and_long_name(BDRVVVFATState* s, | ||
106 | unsigned int directory_start, const char* filename, int is_dot) | ||
107 | { | ||
108 | - int i,j,long_index=s->directory.next; | ||
109 | + int long_index = s->directory.next; | ||
110 | direntry_t* entry = NULL; | ||
111 | direntry_t* entry_long = NULL; | ||
112 | |||
113 | @@ -XXX,XX +XXX,XX @@ static inline direntry_t* create_short_and_long_name(BDRVVVFATState* s, | ||
114 | } | ||
115 | |||
116 | entry_long=create_long_filename(s,filename); | ||
117 | - | ||
118 | - i = strlen(filename); | ||
119 | - for(j = i - 1; j>0 && filename[j]!='.';j--); | ||
120 | - if (j > 0) | ||
121 | - i = (j > 8 ? 8 : j); | ||
122 | - else if (i > 8) | ||
123 | - i = 8; | ||
124 | - | ||
125 | - entry=array_get_next(&(s->directory)); | ||
126 | - memset(entry->name, 0x20, sizeof(entry->name)); | ||
127 | - memcpy(entry->name, filename, i); | ||
128 | - | ||
129 | - if (j > 0) { | ||
130 | - for (i = 0; i < 3 && filename[j + 1 + i]; i++) { | ||
131 | - entry->name[8 + i] = filename[j + 1 + i]; | ||
132 | - } | ||
133 | - } | ||
134 | - | ||
135 | - /* upcase & remove unwanted characters */ | ||
136 | - for(i=10;i>=0;i--) { | ||
137 | - if(i==10 || i==7) for(;i>0 && entry->name[i]==' ';i--); | ||
138 | - if(entry->name[i]<=' ' || entry->name[i]>0x7f | ||
139 | - || strchr(".*?<>|\":/\\[];,+='",entry->name[i])) | ||
140 | - entry->name[i]='_'; | ||
141 | - else if(entry->name[i]>='a' && entry->name[i]<='z') | ||
142 | - entry->name[i]+='A'-'a'; | ||
143 | - } | ||
144 | + entry = create_short_filename(s, filename); | ||
145 | |||
146 | /* mangle duplicates */ | ||
147 | while(1) { | ||
148 | -- | 107 | -- |
149 | 1.8.3.1 | 108 | 2.37.3 |
150 | |||
151 | diff view generated by jsdifflib |
1 | From: Eric Blake <eblake@redhat.com> | 1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | We are gradually converting to byte-based interfaces, as they are | 3 | In order to make it thread safe, implement a "fake rwlock", |
4 | easier to reason about than sector-based. Continue by converting | 4 | where we allow reads under BQL *or* job_mutex held, but |
5 | the public interface to backup jobs (no semantic change), including | 5 | writes only under BQL *and* job_mutex. |
6 | a change to CowRequest to track by bytes instead of cluster indices. | ||
7 | 6 | ||
8 | Note that this does not change the difference between the public | 7 | The only write we have is in child_job_set_aio_ctx, which always |
9 | interface (starting point, and size of the subsequent range) and | 8 | happens under drain (so the job is paused). |
10 | the internal interface (starting and end points). | 9 | For this reason, introduce job_set_aio_context and make sure that |
10 | the context is set under BQL, job_mutex and drain. | ||
11 | Also make sure all other places where the aiocontext is read | ||
12 | are protected. | ||
11 | 13 | ||
12 | Signed-off-by: Eric Blake <eblake@redhat.com> | 14 | The reads in commit.c and mirror.c are actually safe, because always |
13 | Reviewed-by: John Snow <jsnow@redhat.com> | 15 | done under BQL. |
14 | Reviewed-by: Xie Changlong <xiechanglong@cmss.chinamobile.com> | 16 | |
15 | Reviewed-by: Jeff Cody <jcody@redhat.com> | 17 | Note: at this stage, job_{lock/unlock} and job lock guard macros |
18 | are *nop*. | ||
19 | |||
20 | Suggested-by: Paolo Bonzini <pbonzini@redhat.com> | ||
21 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
22 | Message-Id: <20220926093214.506243-14-eesposit@redhat.com> | ||
16 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | 23 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> |
24 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> | ||
17 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 25 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
18 | --- | 26 | --- |
19 | block/backup.c | 31 +++++++++++++++---------------- | 27 | include/qemu/job.h | 23 ++++++++++++++++++++--- |
20 | block/replication.c | 12 ++++++++---- | 28 | block/replication.c | 1 + |
21 | include/block/block_backup.h | 11 +++++------ | 29 | blockjob.c | 3 ++- |
22 | 3 files changed, 28 insertions(+), 26 deletions(-) | 30 | job.c | 12 ++++++++++++ |
31 | 4 files changed, 35 insertions(+), 4 deletions(-) | ||
23 | 32 | ||
24 | diff --git a/block/backup.c b/block/backup.c | 33 | diff --git a/include/qemu/job.h b/include/qemu/job.h |
25 | index XXXXXXX..XXXXXXX 100644 | 34 | index XXXXXXX..XXXXXXX 100644 |
26 | --- a/block/backup.c | 35 | --- a/include/qemu/job.h |
27 | +++ b/block/backup.c | 36 | +++ b/include/qemu/job.h |
28 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn wait_for_overlapping_requests(BackupBlockJob *job, | 37 | @@ -XXX,XX +XXX,XX @@ typedef struct Job { |
29 | do { | 38 | /* ProgressMeter API is thread-safe */ |
30 | retry = false; | 39 | ProgressMeter progress; |
31 | QLIST_FOREACH(req, &job->inflight_reqs, list) { | 40 | |
32 | - if (end > req->start && start < req->end) { | 41 | + /** |
33 | + if (end > req->start_byte && start < req->end_byte) { | 42 | + * AioContext to run the job coroutine in. |
34 | qemu_co_queue_wait(&req->wait_queue, NULL); | 43 | + * The job Aiocontext can be read when holding *either* |
35 | retry = true; | 44 | + * the BQL (so we are in the main loop) or the job_mutex. |
36 | break; | 45 | + * It can only be written when we hold *both* BQL |
37 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn wait_for_overlapping_requests(BackupBlockJob *job, | 46 | + * and the job_mutex. |
38 | 47 | + */ | |
39 | /* Keep track of an in-flight request */ | 48 | + AioContext *aio_context; |
40 | static void cow_request_begin(CowRequest *req, BackupBlockJob *job, | 49 | |
41 | - int64_t start, int64_t end) | 50 | - /** Protected by AioContext lock */ |
42 | + int64_t start, int64_t end) | 51 | |
43 | { | 52 | - /** AioContext to run the job coroutine in */ |
44 | - req->start = start; | 53 | - AioContext *aio_context; |
45 | - req->end = end; | 54 | + /** Protected by AioContext lock */ |
46 | + req->start_byte = start; | 55 | |
47 | + req->end_byte = end; | 56 | /** Reference count of the block job */ |
48 | qemu_co_queue_init(&req->wait_queue); | 57 | int refcnt; |
49 | QLIST_INSERT_HEAD(&job->inflight_reqs, req, list); | 58 | @@ -XXX,XX +XXX,XX @@ int job_finish_sync(Job *job, void (*finish)(Job *, Error **errp), |
50 | } | 59 | int job_finish_sync_locked(Job *job, void (*finish)(Job *, Error **errp), |
51 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_do_cow(BackupBlockJob *job, | 60 | Error **errp); |
52 | sector_num * BDRV_SECTOR_SIZE, | 61 | |
53 | nb_sectors * BDRV_SECTOR_SIZE); | 62 | +/** |
54 | 63 | + * Sets the @job->aio_context. | |
55 | - wait_for_overlapping_requests(job, start, end); | 64 | + * Called with job_mutex *not* held. |
56 | - cow_request_begin(&cow_request, job, start, end); | 65 | + * |
57 | + wait_for_overlapping_requests(job, start * job->cluster_size, | 66 | + * This function must run in the main thread to protect against |
58 | + end * job->cluster_size); | 67 | + * concurrent read in job_finish_sync_locked(), takes the job_mutex |
59 | + cow_request_begin(&cow_request, job, start * job->cluster_size, | 68 | + * lock to protect against the read in job_do_yield_locked(), and must |
60 | + end * job->cluster_size); | 69 | + * be called when the job is quiescent. |
61 | 70 | + */ | |
62 | for (; start < end; start++) { | 71 | +void job_set_aio_context(Job *job, AioContext *ctx); |
63 | if (test_bit(start, job->done_bitmap)) { | 72 | + |
64 | @@ -XXX,XX +XXX,XX @@ void backup_do_checkpoint(BlockJob *job, Error **errp) | 73 | #endif |
65 | bitmap_zero(backup_job->done_bitmap, len); | ||
66 | } | ||
67 | |||
68 | -void backup_wait_for_overlapping_requests(BlockJob *job, int64_t sector_num, | ||
69 | - int nb_sectors) | ||
70 | +void backup_wait_for_overlapping_requests(BlockJob *job, int64_t offset, | ||
71 | + uint64_t bytes) | ||
72 | { | ||
73 | BackupBlockJob *backup_job = container_of(job, BackupBlockJob, common); | ||
74 | - int64_t sectors_per_cluster = cluster_size_sectors(backup_job); | ||
75 | int64_t start, end; | ||
76 | |||
77 | assert(job->driver->job_type == BLOCK_JOB_TYPE_BACKUP); | ||
78 | |||
79 | - start = sector_num / sectors_per_cluster; | ||
80 | - end = DIV_ROUND_UP(sector_num + nb_sectors, sectors_per_cluster); | ||
81 | + start = QEMU_ALIGN_DOWN(offset, backup_job->cluster_size); | ||
82 | + end = QEMU_ALIGN_UP(offset + bytes, backup_job->cluster_size); | ||
83 | wait_for_overlapping_requests(backup_job, start, end); | ||
84 | } | ||
85 | |||
86 | void backup_cow_request_begin(CowRequest *req, BlockJob *job, | ||
87 | - int64_t sector_num, | ||
88 | - int nb_sectors) | ||
89 | + int64_t offset, uint64_t bytes) | ||
90 | { | ||
91 | BackupBlockJob *backup_job = container_of(job, BackupBlockJob, common); | ||
92 | - int64_t sectors_per_cluster = cluster_size_sectors(backup_job); | ||
93 | int64_t start, end; | ||
94 | |||
95 | assert(job->driver->job_type == BLOCK_JOB_TYPE_BACKUP); | ||
96 | |||
97 | - start = sector_num / sectors_per_cluster; | ||
98 | - end = DIV_ROUND_UP(sector_num + nb_sectors, sectors_per_cluster); | ||
99 | + start = QEMU_ALIGN_DOWN(offset, backup_job->cluster_size); | ||
100 | + end = QEMU_ALIGN_UP(offset + bytes, backup_job->cluster_size); | ||
101 | cow_request_begin(req, backup_job, start, end); | ||
102 | } | ||
103 | |||
104 | diff --git a/block/replication.c b/block/replication.c | 74 | diff --git a/block/replication.c b/block/replication.c |
105 | index XXXXXXX..XXXXXXX 100644 | 75 | index XXXXXXX..XXXXXXX 100644 |
106 | --- a/block/replication.c | 76 | --- a/block/replication.c |
107 | +++ b/block/replication.c | 77 | +++ b/block/replication.c |
108 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int replication_co_readv(BlockDriverState *bs, | 78 | @@ -XXX,XX +XXX,XX @@ static void replication_close(BlockDriverState *bs) |
79 | { | ||
80 | BDRVReplicationState *s = bs->opaque; | ||
81 | Job *commit_job; | ||
82 | + GLOBAL_STATE_CODE(); | ||
83 | |||
84 | if (s->stage == BLOCK_REPLICATION_RUNNING) { | ||
85 | replication_stop(s->rs, false, NULL); | ||
86 | diff --git a/blockjob.c b/blockjob.c | ||
87 | index XXXXXXX..XXXXXXX 100644 | ||
88 | --- a/blockjob.c | ||
89 | +++ b/blockjob.c | ||
90 | @@ -XXX,XX +XXX,XX @@ static void child_job_set_aio_ctx(BdrvChild *c, AioContext *ctx, | ||
91 | bdrv_set_aio_context_ignore(sibling->bs, ctx, ignore); | ||
109 | } | 92 | } |
110 | 93 | ||
111 | if (job) { | 94 | - job->job.aio_context = ctx; |
112 | - backup_wait_for_overlapping_requests(child->bs->job, sector_num, | 95 | + job_set_aio_context(&job->job, ctx); |
113 | - remaining_sectors); | 96 | } |
114 | - backup_cow_request_begin(&req, child->bs->job, sector_num, | 97 | |
115 | - remaining_sectors); | 98 | static AioContext *child_job_get_parent_aio_context(BdrvChild *c) |
116 | + uint64_t remaining_bytes = remaining_sectors * BDRV_SECTOR_SIZE; | 99 | { |
100 | BlockJob *job = c->opaque; | ||
101 | + GLOBAL_STATE_CODE(); | ||
102 | |||
103 | return job->job.aio_context; | ||
104 | } | ||
105 | diff --git a/job.c b/job.c | ||
106 | index XXXXXXX..XXXXXXX 100644 | ||
107 | --- a/job.c | ||
108 | +++ b/job.c | ||
109 | @@ -XXX,XX +XXX,XX @@ Job *job_get(const char *id) | ||
110 | return job_get_locked(id); | ||
111 | } | ||
112 | |||
113 | +void job_set_aio_context(Job *job, AioContext *ctx) | ||
114 | +{ | ||
115 | + /* protect against read in job_finish_sync_locked and job_start */ | ||
116 | + GLOBAL_STATE_CODE(); | ||
117 | + /* protect against read in job_do_yield_locked */ | ||
118 | + JOB_LOCK_GUARD(); | ||
119 | + /* ensure the job is quiescent while the AioContext is changed */ | ||
120 | + assert(job->paused || job_is_completed_locked(job)); | ||
121 | + job->aio_context = ctx; | ||
122 | +} | ||
117 | + | 123 | + |
118 | + backup_wait_for_overlapping_requests(child->bs->job, | 124 | /* Called with job_mutex *not* held. */ |
119 | + sector_num * BDRV_SECTOR_SIZE, | 125 | static void job_sleep_timer_cb(void *opaque) |
120 | + remaining_bytes); | 126 | { |
121 | + backup_cow_request_begin(&req, child->bs->job, | 127 | @@ -XXX,XX +XXX,XX @@ int job_finish_sync_locked(Job *job, |
122 | + sector_num * BDRV_SECTOR_SIZE, | 128 | { |
123 | + remaining_bytes); | 129 | Error *local_err = NULL; |
124 | ret = bdrv_co_readv(bs->file, sector_num, remaining_sectors, | 130 | int ret; |
125 | qiov); | 131 | + GLOBAL_STATE_CODE(); |
126 | backup_cow_request_end(&req); | 132 | |
127 | diff --git a/include/block/block_backup.h b/include/block/block_backup.h | 133 | job_ref_locked(job); |
128 | index XXXXXXX..XXXXXXX 100644 | 134 | |
129 | --- a/include/block/block_backup.h | ||
130 | +++ b/include/block/block_backup.h | ||
131 | @@ -XXX,XX +XXX,XX @@ | ||
132 | #include "block/block_int.h" | ||
133 | |||
134 | typedef struct CowRequest { | ||
135 | - int64_t start; | ||
136 | - int64_t end; | ||
137 | + int64_t start_byte; | ||
138 | + int64_t end_byte; | ||
139 | QLIST_ENTRY(CowRequest) list; | ||
140 | CoQueue wait_queue; /* coroutines blocked on this request */ | ||
141 | } CowRequest; | ||
142 | |||
143 | -void backup_wait_for_overlapping_requests(BlockJob *job, int64_t sector_num, | ||
144 | - int nb_sectors); | ||
145 | +void backup_wait_for_overlapping_requests(BlockJob *job, int64_t offset, | ||
146 | + uint64_t bytes); | ||
147 | void backup_cow_request_begin(CowRequest *req, BlockJob *job, | ||
148 | - int64_t sector_num, | ||
149 | - int nb_sectors); | ||
150 | + int64_t offset, uint64_t bytes); | ||
151 | void backup_cow_request_end(CowRequest *req); | ||
152 | |||
153 | void backup_do_checkpoint(BlockJob *job, Error **errp); | ||
154 | -- | 135 | -- |
155 | 1.8.3.1 | 136 | 2.37.3 |
156 | |||
157 | diff view generated by jsdifflib |
1 | From: Eric Blake <eblake@redhat.com> | 1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | stream_complete() skips the work of rewriting the backing file if | 3 | The same job lock is being used also to protect some of blockjob fields. |
4 | the job was cancelled, if data->reached_end is false, or if there | 4 | Categorize them just as done in job.h. |
5 | was an error detected (non-zero data->ret) during the streaming. | ||
6 | But note that in stream_run(), data->reached_end is only set if the | ||
7 | loop ran to completion, and data->ret is only 0 in two cases: | ||
8 | either the loop ran to completion (possibly by cancellation, but | ||
9 | stream_complete checks for that), or we took an early goto out | ||
10 | because there is no bs->backing. Thus, we can preserve the same | ||
11 | semantics without the use of reached_end, by merely checking for | ||
12 | bs->backing (and logically, if there was no backing file, streaming | ||
13 | is a no-op, so there is no backing file to rewrite). | ||
14 | 5 | ||
15 | Suggested-by: Kevin Wolf <kwolf@redhat.com> | 6 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> |
16 | Signed-off-by: Eric Blake <eblake@redhat.com> | 7 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
17 | Reviewed-by: John Snow <jsnow@redhat.com> | 8 | Message-Id: <20220926093214.506243-15-eesposit@redhat.com> |
18 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | 9 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> |
19 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
20 | --- | 11 | --- |
21 | block/stream.c | 4 +--- | 12 | include/block/blockjob.h | 32 ++++++++++++++++++++++++++------ |
22 | 1 file changed, 1 insertion(+), 3 deletions(-) | 13 | 1 file changed, 26 insertions(+), 6 deletions(-) |
23 | 14 | ||
24 | diff --git a/block/stream.c b/block/stream.c | 15 | diff --git a/include/block/blockjob.h b/include/block/blockjob.h |
25 | index XXXXXXX..XXXXXXX 100644 | 16 | index XXXXXXX..XXXXXXX 100644 |
26 | --- a/block/stream.c | 17 | --- a/include/block/blockjob.h |
27 | +++ b/block/stream.c | 18 | +++ b/include/block/blockjob.h |
28 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn stream_populate(BlockBackend *blk, | 19 | @@ -XXX,XX +XXX,XX @@ typedef struct BlockJobDriver BlockJobDriver; |
29 | 20 | * Long-running operation on a BlockDriverState. | |
30 | typedef struct { | 21 | */ |
31 | int ret; | 22 | typedef struct BlockJob { |
32 | - bool reached_end; | 23 | - /** Data belonging to the generic Job infrastructure */ |
33 | } StreamCompleteData; | 24 | + /** |
34 | 25 | + * Data belonging to the generic Job infrastructure. | |
35 | static void stream_complete(BlockJob *job, void *opaque) | 26 | + * Protected by job mutex. |
36 | @@ -XXX,XX +XXX,XX @@ static void stream_complete(BlockJob *job, void *opaque) | 27 | + */ |
37 | BlockDriverState *base = s->base; | 28 | Job job; |
38 | Error *local_err = NULL; | 29 | |
39 | 30 | - /** Status that is published by the query-block-jobs QMP API */ | |
40 | - if (!block_job_is_cancelled(&s->common) && data->reached_end && | 31 | + /** |
41 | + if (!block_job_is_cancelled(&s->common) && bs->backing && | 32 | + * Status that is published by the query-block-jobs QMP API. |
42 | data->ret == 0) { | 33 | + * Protected by job mutex. |
43 | const char *base_id = NULL, *base_fmt = NULL; | 34 | + */ |
44 | if (base) { | 35 | BlockDeviceIoStatus iostatus; |
45 | @@ -XXX,XX +XXX,XX @@ out: | 36 | |
46 | /* Modify backing chain and close BDSes in main loop */ | 37 | - /** Speed that was set with @block_job_set_speed. */ |
47 | data = g_malloc(sizeof(*data)); | 38 | + /** |
48 | data->ret = ret; | 39 | + * Speed that was set with @block_job_set_speed. |
49 | - data->reached_end = sector_num == end; | 40 | + * Always modified and read under QEMU global mutex (GLOBAL_STATE_CODE). |
50 | block_job_defer_to_main_loop(&s->common, stream_complete, data); | 41 | + */ |
51 | } | 42 | int64_t speed; |
43 | |||
44 | - /** Rate limiting data structure for implementing @speed. */ | ||
45 | + /** | ||
46 | + * Rate limiting data structure for implementing @speed. | ||
47 | + * RateLimit API is thread-safe. | ||
48 | + */ | ||
49 | RateLimit limit; | ||
50 | |||
51 | - /** Block other operations when block job is running */ | ||
52 | + /** | ||
53 | + * Block other operations when block job is running. | ||
54 | + * Always modified and read under QEMU global mutex (GLOBAL_STATE_CODE). | ||
55 | + */ | ||
56 | Error *blocker; | ||
57 | |||
58 | + /** All notifiers are set once in block_job_create() and never modified. */ | ||
59 | + | ||
60 | /** Called when a cancelled job is finalised. */ | ||
61 | Notifier finalize_cancelled_notifier; | ||
62 | |||
63 | @@ -XXX,XX +XXX,XX @@ typedef struct BlockJob { | ||
64 | /** Called when the job coroutine yields or terminates */ | ||
65 | Notifier idle_notifier; | ||
66 | |||
67 | - /** BlockDriverStates that are involved in this block job */ | ||
68 | + /** | ||
69 | + * BlockDriverStates that are involved in this block job. | ||
70 | + * Always modified and read under QEMU global mutex (GLOBAL_STATE_CODE). | ||
71 | + */ | ||
72 | GSList *nodes; | ||
73 | } BlockJob; | ||
52 | 74 | ||
53 | -- | 75 | -- |
54 | 1.8.3.1 | 76 | 2.37.3 |
55 | |||
56 | diff view generated by jsdifflib |
1 | From: "Daniel P. Berrange" <berrange@redhat.com> | 1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | This converts the qcow2 driver to make use of the QCryptoBlock | 3 | They all are called with job_lock held, in job_event_*_locked() |
4 | APIs for encrypting image content, using the legacy QCow2 AES | ||
5 | scheme. | ||
6 | 4 | ||
7 | With this change it is now required to use the QCryptoSecret | 5 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
8 | object for providing passwords, instead of the current block | 6 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> |
9 | password APIs / interactive prompting. | 7 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> |
8 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
9 | Message-Id: <20220926093214.506243-16-eesposit@redhat.com> | ||
10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
11 | --- | ||
12 | blockjob.c | 25 +++++++++++++++---------- | ||
13 | 1 file changed, 15 insertions(+), 10 deletions(-) | ||
10 | 14 | ||
11 | $QEMU \ | 15 | diff --git a/blockjob.c b/blockjob.c |
12 | -object secret,id=sec0,file=/home/berrange/encrypted.pw \ | ||
13 | -drive file=/home/berrange/encrypted.qcow2,encrypt.key-secret=sec0 | ||
14 | |||
15 | The test 087 could be simplified since there is no longer a | ||
16 | difference in behaviour when using blockdev_add with encrypted | ||
17 | images for the running vs stopped CPU state. | ||
18 | |||
19 | Signed-off-by: Daniel P. Berrange <berrange@redhat.com> | ||
20 | Message-id: 20170623162419.26068-12-berrange@redhat.com | ||
21 | Reviewed-by: Alberto Garcia <berto@igalia.com> | ||
22 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
23 | --- | ||
24 | block/qcow2-cluster.c | 47 +--------- | ||
25 | block/qcow2.c | 226 ++++++++++++++++++++++++++++++--------------- | ||
26 | block/qcow2.h | 5 +- | ||
27 | qapi/block-core.json | 27 +++++- | ||
28 | tests/qemu-iotests/049 | 2 +- | ||
29 | tests/qemu-iotests/049.out | 4 +- | ||
30 | tests/qemu-iotests/082.out | 27 ++++++ | ||
31 | tests/qemu-iotests/087 | 28 +++--- | ||
32 | tests/qemu-iotests/087.out | 12 +-- | ||
33 | tests/qemu-iotests/134 | 18 +++- | ||
34 | tests/qemu-iotests/134.out | 10 +- | ||
35 | tests/qemu-iotests/158 | 19 ++-- | ||
36 | tests/qemu-iotests/158.out | 14 +-- | ||
37 | tests/qemu-iotests/common | 10 +- | ||
38 | 14 files changed, 263 insertions(+), 186 deletions(-) | ||
39 | |||
40 | diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c | ||
41 | index XXXXXXX..XXXXXXX 100644 | 16 | index XXXXXXX..XXXXXXX 100644 |
42 | --- a/block/qcow2-cluster.c | 17 | --- a/blockjob.c |
43 | +++ b/block/qcow2-cluster.c | 18 | +++ b/blockjob.c |
44 | @@ -XXX,XX +XXX,XX @@ static int count_contiguous_clusters_unallocated(int nb_clusters, | 19 | @@ -XXX,XX +XXX,XX @@ int block_job_add_bdrv(BlockJob *job, const char *name, BlockDriverState *bs, |
45 | return i; | 20 | return 0; |
46 | } | 21 | } |
47 | 22 | ||
48 | -/* The crypt function is compatible with the linux cryptoloop | 23 | -static void block_job_on_idle(Notifier *n, void *opaque) |
49 | - algorithm for < 4 GB images. */ | 24 | +/* Called with job_mutex lock held. */ |
50 | -int qcow2_encrypt_sectors(BDRVQcow2State *s, int64_t sector_num, | 25 | +static void block_job_on_idle_locked(Notifier *n, void *opaque) |
51 | - uint8_t *buf, int nb_sectors, bool enc, | 26 | { |
52 | - Error **errp) | 27 | aio_wait_kick(); |
53 | -{ | 28 | } |
54 | - union { | 29 | @@ -XXX,XX +XXX,XX @@ static void block_job_iostatus_set_err(BlockJob *job, int error) |
55 | - uint64_t ll[2]; | ||
56 | - uint8_t b[16]; | ||
57 | - } ivec; | ||
58 | - int i; | ||
59 | - int ret; | ||
60 | - | ||
61 | - for(i = 0; i < nb_sectors; i++) { | ||
62 | - ivec.ll[0] = cpu_to_le64(sector_num); | ||
63 | - ivec.ll[1] = 0; | ||
64 | - if (qcrypto_cipher_setiv(s->cipher, | ||
65 | - ivec.b, G_N_ELEMENTS(ivec.b), | ||
66 | - errp) < 0) { | ||
67 | - return -1; | ||
68 | - } | ||
69 | - if (enc) { | ||
70 | - ret = qcrypto_cipher_encrypt(s->cipher, | ||
71 | - buf, buf, | ||
72 | - 512, | ||
73 | - errp); | ||
74 | - } else { | ||
75 | - ret = qcrypto_cipher_decrypt(s->cipher, | ||
76 | - buf, buf, | ||
77 | - 512, | ||
78 | - errp); | ||
79 | - } | ||
80 | - if (ret < 0) { | ||
81 | - return -1; | ||
82 | - } | ||
83 | - sector_num++; | ||
84 | - buf += 512; | ||
85 | - } | ||
86 | - return 0; | ||
87 | -} | ||
88 | - | ||
89 | static int coroutine_fn do_perform_cow_read(BlockDriverState *bs, | ||
90 | uint64_t src_cluster_offset, | ||
91 | unsigned offset_in_cluster, | ||
92 | @@ -XXX,XX +XXX,XX @@ static bool coroutine_fn do_perform_cow_encrypt(BlockDriverState *bs, | ||
93 | BDRVQcow2State *s = bs->opaque; | ||
94 | int64_t sector = (src_cluster_offset + offset_in_cluster) | ||
95 | >> BDRV_SECTOR_BITS; | ||
96 | - assert(s->cipher); | ||
97 | assert((offset_in_cluster & ~BDRV_SECTOR_MASK) == 0); | ||
98 | assert((bytes & ~BDRV_SECTOR_MASK) == 0); | ||
99 | - if (qcow2_encrypt_sectors(s, sector, buffer, | ||
100 | - bytes >> BDRV_SECTOR_BITS, true, NULL) < 0) { | ||
101 | + assert(s->crypto); | ||
102 | + if (qcrypto_block_encrypt(s->crypto, sector, buffer, | ||
103 | + bytes, NULL) < 0) { | ||
104 | return false; | ||
105 | } | ||
106 | } | 30 | } |
107 | diff --git a/block/qcow2.c b/block/qcow2.c | ||
108 | index XXXXXXX..XXXXXXX 100644 | ||
109 | --- a/block/qcow2.c | ||
110 | +++ b/block/qcow2.c | ||
111 | @@ -XXX,XX +XXX,XX @@ | ||
112 | #include "qemu/option_int.h" | ||
113 | #include "qemu/cutils.h" | ||
114 | #include "qemu/bswap.h" | ||
115 | +#include "qapi/opts-visitor.h" | ||
116 | +#include "qapi-visit.h" | ||
117 | +#include "block/crypto.h" | ||
118 | |||
119 | /* | ||
120 | Differences with QCOW: | ||
121 | @@ -XXX,XX +XXX,XX @@ static QemuOptsList qcow2_runtime_opts = { | ||
122 | .type = QEMU_OPT_NUMBER, | ||
123 | .help = "Clean unused cache entries after this time (in seconds)", | ||
124 | }, | ||
125 | + BLOCK_CRYPTO_OPT_DEF_QCOW_KEY_SECRET("encrypt."), | ||
126 | { /* end of list */ } | ||
127 | }, | ||
128 | }; | ||
129 | @@ -XXX,XX +XXX,XX @@ typedef struct Qcow2ReopenState { | ||
130 | int overlap_check; | ||
131 | bool discard_passthrough[QCOW2_DISCARD_MAX]; | ||
132 | uint64_t cache_clean_interval; | ||
133 | + QCryptoBlockOpenOptions *crypto_opts; /* Disk encryption runtime options */ | ||
134 | } Qcow2ReopenState; | ||
135 | |||
136 | static int qcow2_update_options_prepare(BlockDriverState *bs, | ||
137 | @@ -XXX,XX +XXX,XX @@ static int qcow2_update_options_prepare(BlockDriverState *bs, | ||
138 | int overlap_check_template = 0; | ||
139 | uint64_t l2_cache_size, refcount_cache_size; | ||
140 | int i; | ||
141 | + const char *encryptfmt; | ||
142 | + QDict *encryptopts = NULL; | ||
143 | Error *local_err = NULL; | ||
144 | int ret; | ||
145 | |||
146 | + qdict_extract_subqdict(options, &encryptopts, "encrypt."); | ||
147 | + encryptfmt = qdict_get_try_str(encryptopts, "format"); | ||
148 | + | ||
149 | opts = qemu_opts_create(&qcow2_runtime_opts, NULL, 0, &error_abort); | ||
150 | qemu_opts_absorb_qdict(opts, options, &local_err); | ||
151 | if (local_err) { | ||
152 | @@ -XXX,XX +XXX,XX @@ static int qcow2_update_options_prepare(BlockDriverState *bs, | ||
153 | r->discard_passthrough[QCOW2_DISCARD_OTHER] = | ||
154 | qemu_opt_get_bool(opts, QCOW2_OPT_DISCARD_OTHER, false); | ||
155 | |||
156 | + switch (s->crypt_method_header) { | ||
157 | + case QCOW_CRYPT_NONE: | ||
158 | + if (encryptfmt) { | ||
159 | + error_setg(errp, "No encryption in image header, but options " | ||
160 | + "specified format '%s'", encryptfmt); | ||
161 | + ret = -EINVAL; | ||
162 | + goto fail; | ||
163 | + } | ||
164 | + break; | ||
165 | + | ||
166 | + case QCOW_CRYPT_AES: | ||
167 | + if (encryptfmt && !g_str_equal(encryptfmt, "aes")) { | ||
168 | + error_setg(errp, | ||
169 | + "Header reported 'aes' encryption format but " | ||
170 | + "options specify '%s'", encryptfmt); | ||
171 | + ret = -EINVAL; | ||
172 | + goto fail; | ||
173 | + } | ||
174 | + qdict_del(encryptopts, "format"); | ||
175 | + r->crypto_opts = block_crypto_open_opts_init( | ||
176 | + Q_CRYPTO_BLOCK_FORMAT_QCOW, encryptopts, errp); | ||
177 | + break; | ||
178 | + | ||
179 | + default: | ||
180 | + error_setg(errp, "Unsupported encryption method %d", | ||
181 | + s->crypt_method_header); | ||
182 | + break; | ||
183 | + } | ||
184 | + if (s->crypt_method_header != QCOW_CRYPT_NONE && !r->crypto_opts) { | ||
185 | + ret = -EINVAL; | ||
186 | + goto fail; | ||
187 | + } | ||
188 | + | ||
189 | ret = 0; | ||
190 | fail: | ||
191 | + QDECREF(encryptopts); | ||
192 | qemu_opts_del(opts); | ||
193 | opts = NULL; | ||
194 | return ret; | ||
195 | @@ -XXX,XX +XXX,XX @@ static void qcow2_update_options_commit(BlockDriverState *bs, | ||
196 | s->cache_clean_interval = r->cache_clean_interval; | ||
197 | cache_clean_timer_init(bs, bdrv_get_aio_context(bs)); | ||
198 | } | ||
199 | + | ||
200 | + qapi_free_QCryptoBlockOpenOptions(s->crypto_opts); | ||
201 | + s->crypto_opts = r->crypto_opts; | ||
202 | } | 31 | } |
203 | 32 | ||
204 | static void qcow2_update_options_abort(BlockDriverState *bs, | 33 | -static void block_job_event_cancelled(Notifier *n, void *opaque) |
205 | @@ -XXX,XX +XXX,XX @@ static void qcow2_update_options_abort(BlockDriverState *bs, | 34 | +/* Called with job_mutex lock held. */ |
206 | if (r->refcount_block_cache) { | 35 | +static void block_job_event_cancelled_locked(Notifier *n, void *opaque) |
207 | qcow2_cache_destroy(bs, r->refcount_block_cache); | 36 | { |
208 | } | 37 | BlockJob *job = opaque; |
209 | + qapi_free_QCryptoBlockOpenOptions(r->crypto_opts); | 38 | uint64_t progress_current, progress_total; |
39 | @@ -XXX,XX +XXX,XX @@ static void block_job_event_cancelled(Notifier *n, void *opaque) | ||
40 | job->speed); | ||
210 | } | 41 | } |
211 | 42 | ||
212 | static int qcow2_update_options(BlockDriverState *bs, QDict *options, | 43 | -static void block_job_event_completed(Notifier *n, void *opaque) |
213 | @@ -XXX,XX +XXX,XX @@ static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags, | 44 | +/* Called with job_mutex lock held. */ |
214 | ret = -EINVAL; | 45 | +static void block_job_event_completed_locked(Notifier *n, void *opaque) |
215 | goto fail; | 46 | { |
216 | } | 47 | BlockJob *job = opaque; |
217 | - if (!qcrypto_cipher_supports(QCRYPTO_CIPHER_ALG_AES_128, | 48 | const char *msg = NULL; |
218 | - QCRYPTO_CIPHER_MODE_CBC)) { | 49 | @@ -XXX,XX +XXX,XX @@ static void block_job_event_completed(Notifier *n, void *opaque) |
219 | - error_setg(errp, "AES cipher not available"); | 50 | msg); |
220 | - ret = -EINVAL; | ||
221 | - goto fail; | ||
222 | - } | ||
223 | s->crypt_method_header = header.crypt_method; | ||
224 | if (s->crypt_method_header) { | ||
225 | if (bdrv_uses_whitelist() && | ||
226 | @@ -XXX,XX +XXX,XX @@ static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags, | ||
227 | } | ||
228 | |||
229 | bs->encrypted = true; | ||
230 | + bs->valid_key = true; | ||
231 | } | ||
232 | |||
233 | s->l2_bits = s->cluster_bits - 3; /* L2 is always one cluster */ | ||
234 | @@ -XXX,XX +XXX,XX @@ static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags, | ||
235 | goto fail; | ||
236 | } | ||
237 | |||
238 | + if (s->crypt_method_header == QCOW_CRYPT_AES) { | ||
239 | + unsigned int cflags = 0; | ||
240 | + if (flags & BDRV_O_NO_IO) { | ||
241 | + cflags |= QCRYPTO_BLOCK_OPEN_NO_IO; | ||
242 | + } | ||
243 | + s->crypto = qcrypto_block_open(s->crypto_opts, NULL, NULL, | ||
244 | + cflags, errp); | ||
245 | + if (!s->crypto) { | ||
246 | + ret = -EINVAL; | ||
247 | + goto fail; | ||
248 | + } | ||
249 | + } | ||
250 | + | ||
251 | /* read the backing file name */ | ||
252 | if (header.backing_file_offset != 0) { | ||
253 | len = header.backing_file_size; | ||
254 | @@ -XXX,XX +XXX,XX @@ static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags, | ||
255 | } | ||
256 | g_free(s->cluster_cache); | ||
257 | qemu_vfree(s->cluster_data); | ||
258 | + qcrypto_block_free(s->crypto); | ||
259 | + qapi_free_QCryptoBlockOpenOptions(s->crypto_opts); | ||
260 | return ret; | ||
261 | } | 51 | } |
262 | 52 | ||
263 | @@ -XXX,XX +XXX,XX @@ static void qcow2_refresh_limits(BlockDriverState *bs, Error **errp) | 53 | -static void block_job_event_pending(Notifier *n, void *opaque) |
264 | bs->bl.pdiscard_alignment = s->cluster_size; | 54 | +/* Called with job_mutex lock held. */ |
55 | +static void block_job_event_pending_locked(Notifier *n, void *opaque) | ||
56 | { | ||
57 | BlockJob *job = opaque; | ||
58 | |||
59 | @@ -XXX,XX +XXX,XX @@ static void block_job_event_pending(Notifier *n, void *opaque) | ||
60 | job->job.id); | ||
265 | } | 61 | } |
266 | 62 | ||
267 | -static int qcow2_set_key(BlockDriverState *bs, const char *key) | 63 | -static void block_job_event_ready(Notifier *n, void *opaque) |
268 | -{ | 64 | +/* Called with job_mutex lock held. */ |
269 | - BDRVQcow2State *s = bs->opaque; | 65 | +static void block_job_event_ready_locked(Notifier *n, void *opaque) |
270 | - uint8_t keybuf[16]; | ||
271 | - int len, i; | ||
272 | - Error *err = NULL; | ||
273 | - | ||
274 | - memset(keybuf, 0, 16); | ||
275 | - len = strlen(key); | ||
276 | - if (len > 16) | ||
277 | - len = 16; | ||
278 | - /* XXX: we could compress the chars to 7 bits to increase | ||
279 | - entropy */ | ||
280 | - for(i = 0;i < len;i++) { | ||
281 | - keybuf[i] = key[i]; | ||
282 | - } | ||
283 | - assert(bs->encrypted); | ||
284 | - | ||
285 | - qcrypto_cipher_free(s->cipher); | ||
286 | - s->cipher = qcrypto_cipher_new( | ||
287 | - QCRYPTO_CIPHER_ALG_AES_128, | ||
288 | - QCRYPTO_CIPHER_MODE_CBC, | ||
289 | - keybuf, G_N_ELEMENTS(keybuf), | ||
290 | - &err); | ||
291 | - | ||
292 | - if (!s->cipher) { | ||
293 | - /* XXX would be nice if errors in this method could | ||
294 | - * be properly propagate to the caller. Would need | ||
295 | - * the bdrv_set_key() API signature to be fixed. */ | ||
296 | - error_free(err); | ||
297 | - return -1; | ||
298 | - } | ||
299 | - return 0; | ||
300 | -} | ||
301 | - | ||
302 | static int qcow2_reopen_prepare(BDRVReopenState *state, | ||
303 | BlockReopenQueue *queue, Error **errp) | ||
304 | { | 66 | { |
305 | @@ -XXX,XX +XXX,XX @@ static int64_t coroutine_fn qcow2_co_get_block_status(BlockDriverState *bs, | 67 | BlockJob *job = opaque; |
306 | *pnum = bytes >> BDRV_SECTOR_BITS; | 68 | uint64_t progress_current, progress_total; |
307 | 69 | @@ -XXX,XX +XXX,XX @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver, | |
308 | if (cluster_offset != 0 && ret != QCOW2_CLUSTER_COMPRESSED && | 70 | |
309 | - !s->cipher) { | 71 | ratelimit_init(&job->limit); |
310 | + !s->crypto) { | 72 | |
311 | index_in_cluster = sector_num & (s->cluster_sectors - 1); | 73 | - job->finalize_cancelled_notifier.notify = block_job_event_cancelled; |
312 | cluster_offset |= (index_in_cluster << BDRV_SECTOR_BITS); | 74 | - job->finalize_completed_notifier.notify = block_job_event_completed; |
313 | *file = bs->file->bs; | 75 | - job->pending_notifier.notify = block_job_event_pending; |
314 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset, | 76 | - job->ready_notifier.notify = block_job_event_ready; |
315 | 77 | - job->idle_notifier.notify = block_job_on_idle; | |
316 | /* prepare next request */ | 78 | + job->finalize_cancelled_notifier.notify = block_job_event_cancelled_locked; |
317 | cur_bytes = MIN(bytes, INT_MAX); | 79 | + job->finalize_completed_notifier.notify = block_job_event_completed_locked; |
318 | - if (s->cipher) { | 80 | + job->pending_notifier.notify = block_job_event_pending_locked; |
319 | + if (s->crypto) { | 81 | + job->ready_notifier.notify = block_job_event_ready_locked; |
320 | cur_bytes = MIN(cur_bytes, | 82 | + job->idle_notifier.notify = block_job_on_idle_locked; |
321 | QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size); | 83 | |
322 | } | 84 | WITH_JOB_LOCK_GUARD() { |
323 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset, | 85 | notifier_list_add(&job->job.on_finalize_cancelled, |
324 | } | ||
325 | |||
326 | if (bs->encrypted) { | ||
327 | - assert(s->cipher); | ||
328 | + assert(s->crypto); | ||
329 | |||
330 | /* | ||
331 | * For encrypted images, read everything into a temporary | ||
332 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset, | ||
333 | goto fail; | ||
334 | } | ||
335 | if (bs->encrypted) { | ||
336 | - assert(s->cipher); | ||
337 | + assert(s->crypto); | ||
338 | assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0); | ||
339 | assert((cur_bytes & (BDRV_SECTOR_SIZE - 1)) == 0); | ||
340 | Error *err = NULL; | ||
341 | - if (qcow2_encrypt_sectors(s, offset >> BDRV_SECTOR_BITS, | ||
342 | + if (qcrypto_block_decrypt(s->crypto, | ||
343 | + offset >> BDRV_SECTOR_BITS, | ||
344 | cluster_data, | ||
345 | - cur_bytes >> BDRV_SECTOR_BITS, | ||
346 | - false, &err) < 0) { | ||
347 | + cur_bytes, | ||
348 | + &err) < 0) { | ||
349 | error_free(err); | ||
350 | ret = -EIO; | ||
351 | goto fail; | ||
352 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_pwritev(BlockDriverState *bs, uint64_t offset, | ||
353 | |||
354 | if (bs->encrypted) { | ||
355 | Error *err = NULL; | ||
356 | - assert(s->cipher); | ||
357 | + assert(s->crypto); | ||
358 | if (!cluster_data) { | ||
359 | cluster_data = qemu_try_blockalign(bs->file->bs, | ||
360 | QCOW_MAX_CRYPT_CLUSTERS | ||
361 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_pwritev(BlockDriverState *bs, uint64_t offset, | ||
362 | QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size); | ||
363 | qemu_iovec_to_buf(&hd_qiov, 0, cluster_data, hd_qiov.size); | ||
364 | |||
365 | - if (qcow2_encrypt_sectors(s, offset >> BDRV_SECTOR_BITS, | ||
366 | + if (qcrypto_block_encrypt(s->crypto, offset >> BDRV_SECTOR_BITS, | ||
367 | cluster_data, | ||
368 | - cur_bytes >>BDRV_SECTOR_BITS, | ||
369 | - true, &err) < 0) { | ||
370 | + cur_bytes, &err) < 0) { | ||
371 | error_free(err); | ||
372 | ret = -EIO; | ||
373 | goto fail; | ||
374 | @@ -XXX,XX +XXX,XX @@ static void qcow2_close(BlockDriverState *bs) | ||
375 | qcow2_cache_destroy(bs, s->l2_table_cache); | ||
376 | qcow2_cache_destroy(bs, s->refcount_block_cache); | ||
377 | |||
378 | - qcrypto_cipher_free(s->cipher); | ||
379 | - s->cipher = NULL; | ||
380 | + qcrypto_block_free(s->crypto); | ||
381 | + s->crypto = NULL; | ||
382 | |||
383 | g_free(s->unknown_header_fields); | ||
384 | cleanup_unknown_header_ext(bs); | ||
385 | @@ -XXX,XX +XXX,XX @@ static void qcow2_invalidate_cache(BlockDriverState *bs, Error **errp) | ||
386 | { | ||
387 | BDRVQcow2State *s = bs->opaque; | ||
388 | int flags = s->flags; | ||
389 | - QCryptoCipher *cipher = NULL; | ||
390 | + QCryptoBlock *crypto = NULL; | ||
391 | QDict *options; | ||
392 | Error *local_err = NULL; | ||
393 | int ret; | ||
394 | @@ -XXX,XX +XXX,XX @@ static void qcow2_invalidate_cache(BlockDriverState *bs, Error **errp) | ||
395 | * that means we don't have to worry about reopening them here. | ||
396 | */ | ||
397 | |||
398 | - cipher = s->cipher; | ||
399 | - s->cipher = NULL; | ||
400 | + crypto = s->crypto; | ||
401 | + s->crypto = NULL; | ||
402 | |||
403 | qcow2_close(bs); | ||
404 | |||
405 | @@ -XXX,XX +XXX,XX @@ static void qcow2_invalidate_cache(BlockDriverState *bs, Error **errp) | ||
406 | return; | ||
407 | } | ||
408 | |||
409 | - s->cipher = cipher; | ||
410 | + s->crypto = crypto; | ||
411 | } | ||
412 | |||
413 | static size_t header_ext_add(char *buf, uint32_t magic, const void *s, | ||
414 | @@ -XXX,XX +XXX,XX @@ static int qcow2_change_backing_file(BlockDriverState *bs, | ||
415 | return qcow2_update_header(bs); | ||
416 | } | ||
417 | |||
418 | + | ||
419 | +static int qcow2_set_up_encryption(BlockDriverState *bs, const char *encryptfmt, | ||
420 | + QemuOpts *opts, Error **errp) | ||
421 | +{ | ||
422 | + BDRVQcow2State *s = bs->opaque; | ||
423 | + QCryptoBlockCreateOptions *cryptoopts = NULL; | ||
424 | + QCryptoBlock *crypto = NULL; | ||
425 | + int ret = -EINVAL; | ||
426 | + QDict *options, *encryptopts; | ||
427 | + | ||
428 | + options = qemu_opts_to_qdict(opts, NULL); | ||
429 | + qdict_extract_subqdict(options, &encryptopts, "encrypt."); | ||
430 | + QDECREF(options); | ||
431 | + | ||
432 | + if (!g_str_equal(encryptfmt, "aes")) { | ||
433 | + error_setg(errp, "Unknown encryption format '%s', expected 'aes'", | ||
434 | + encryptfmt); | ||
435 | + ret = -EINVAL; | ||
436 | + goto out; | ||
437 | + } | ||
438 | + cryptoopts = block_crypto_create_opts_init( | ||
439 | + Q_CRYPTO_BLOCK_FORMAT_QCOW, encryptopts, errp); | ||
440 | + if (!cryptoopts) { | ||
441 | + ret = -EINVAL; | ||
442 | + goto out; | ||
443 | + } | ||
444 | + s->crypt_method_header = QCOW_CRYPT_AES; | ||
445 | + | ||
446 | + crypto = qcrypto_block_create(cryptoopts, | ||
447 | + NULL, NULL, | ||
448 | + bs, errp); | ||
449 | + if (!crypto) { | ||
450 | + ret = -EINVAL; | ||
451 | + goto out; | ||
452 | + } | ||
453 | + | ||
454 | + ret = qcow2_update_header(bs); | ||
455 | + if (ret < 0) { | ||
456 | + error_setg_errno(errp, -ret, "Could not write encryption header"); | ||
457 | + goto out; | ||
458 | + } | ||
459 | + | ||
460 | + out: | ||
461 | + QDECREF(encryptopts); | ||
462 | + qcrypto_block_free(crypto); | ||
463 | + qapi_free_QCryptoBlockCreateOptions(cryptoopts); | ||
464 | + return ret; | ||
465 | +} | ||
466 | + | ||
467 | + | ||
468 | static int preallocate(BlockDriverState *bs) | ||
469 | { | ||
470 | uint64_t bytes; | ||
471 | @@ -XXX,XX +XXX,XX @@ static int qcow2_create2(const char *filename, int64_t total_size, | ||
472 | .header_length = cpu_to_be32(sizeof(*header)), | ||
473 | }; | ||
474 | |||
475 | - if (encryptfmt) { | ||
476 | - if (!g_str_equal(encryptfmt, "aes")) { | ||
477 | - error_setg(errp, "Unknown encryption format '%s', expected 'aes'", | ||
478 | - encryptfmt); | ||
479 | - ret = -EINVAL; | ||
480 | - goto out; | ||
481 | - } | ||
482 | - header->crypt_method = cpu_to_be32(QCOW_CRYPT_AES); | ||
483 | - } else { | ||
484 | - header->crypt_method = cpu_to_be32(QCOW_CRYPT_NONE); | ||
485 | - } | ||
486 | + /* We'll update this to correct value later */ | ||
487 | + header->crypt_method = cpu_to_be32(QCOW_CRYPT_NONE); | ||
488 | |||
489 | if (flags & BLOCK_FLAG_LAZY_REFCOUNTS) { | ||
490 | header->compatible_features |= | ||
491 | @@ -XXX,XX +XXX,XX @@ static int qcow2_create2(const char *filename, int64_t total_size, | ||
492 | } | ||
493 | } | ||
494 | |||
495 | + /* Want encryption? There you go. */ | ||
496 | + if (encryptfmt) { | ||
497 | + ret = qcow2_set_up_encryption(blk_bs(blk), encryptfmt, opts, errp); | ||
498 | + if (ret < 0) { | ||
499 | + goto out; | ||
500 | + } | ||
501 | + } | ||
502 | + | ||
503 | /* And if we're supposed to preallocate metadata, do that now */ | ||
504 | if (prealloc != PREALLOC_MODE_OFF) { | ||
505 | BDRVQcow2State *s = blk_bs(blk)->opaque; | ||
506 | @@ -XXX,XX +XXX,XX @@ static int qcow2_create2(const char *filename, int64_t total_size, | ||
507 | blk_unref(blk); | ||
508 | blk = NULL; | ||
509 | |||
510 | - /* Reopen the image without BDRV_O_NO_FLUSH to flush it before returning */ | ||
511 | + /* Reopen the image without BDRV_O_NO_FLUSH to flush it before returning. | ||
512 | + * Using BDRV_O_NO_IO, since encryption is now setup we don't want to | ||
513 | + * have to setup decryption context. We're not doing any I/O on the top | ||
514 | + * level BlockDriverState, only lower layers, where BDRV_O_NO_IO does | ||
515 | + * not have effect. | ||
516 | + */ | ||
517 | options = qdict_new(); | ||
518 | qdict_put_str(options, "driver", "qcow2"); | ||
519 | blk = blk_new_open(filename, NULL, options, | ||
520 | - BDRV_O_RDWR | BDRV_O_NO_BACKING, &local_err); | ||
521 | + BDRV_O_RDWR | BDRV_O_NO_BACKING | BDRV_O_NO_IO, | ||
522 | + &local_err); | ||
523 | if (blk == NULL) { | ||
524 | error_propagate(errp, local_err); | ||
525 | ret = -EIO; | ||
526 | @@ -XXX,XX +XXX,XX @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, | ||
527 | backing_format = qemu_opt_get(opts, BLOCK_OPT_BACKING_FMT); | ||
528 | } else if (!strcmp(desc->name, BLOCK_OPT_ENCRYPT)) { | ||
529 | encrypt = qemu_opt_get_bool(opts, BLOCK_OPT_ENCRYPT, | ||
530 | - !!s->cipher); | ||
531 | + !!s->crypto); | ||
532 | |||
533 | - if (encrypt != !!s->cipher) { | ||
534 | + if (encrypt != !!s->crypto) { | ||
535 | error_report("Changing the encryption flag is not supported"); | ||
536 | return -ENOTSUP; | ||
537 | } | ||
538 | @@ -XXX,XX +XXX,XX @@ static QemuOptsList qcow2_create_opts = { | ||
539 | .type = QEMU_OPT_STRING, | ||
540 | .help = "Encrypt the image, format choices: 'aes'", | ||
541 | }, | ||
542 | + BLOCK_CRYPTO_OPT_DEF_QCOW_KEY_SECRET("encrypt."), | ||
543 | { | ||
544 | .name = BLOCK_OPT_CLUSTER_SIZE, | ||
545 | .type = QEMU_OPT_SIZE, | ||
546 | @@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_qcow2 = { | ||
547 | .bdrv_create = qcow2_create, | ||
548 | .bdrv_has_zero_init = bdrv_has_zero_init_1, | ||
549 | .bdrv_co_get_block_status = qcow2_co_get_block_status, | ||
550 | - .bdrv_set_key = qcow2_set_key, | ||
551 | |||
552 | .bdrv_co_preadv = qcow2_co_preadv, | ||
553 | .bdrv_co_pwritev = qcow2_co_pwritev, | ||
554 | diff --git a/block/qcow2.h b/block/qcow2.h | ||
555 | index XXXXXXX..XXXXXXX 100644 | ||
556 | --- a/block/qcow2.h | ||
557 | +++ b/block/qcow2.h | ||
558 | @@ -XXX,XX +XXX,XX @@ | ||
559 | #ifndef BLOCK_QCOW2_H | ||
560 | #define BLOCK_QCOW2_H | ||
561 | |||
562 | -#include "crypto/cipher.h" | ||
563 | +#include "crypto/block.h" | ||
564 | #include "qemu/coroutine.h" | ||
565 | |||
566 | //#define DEBUG_ALLOC | ||
567 | @@ -XXX,XX +XXX,XX @@ typedef struct BDRVQcow2State { | ||
568 | |||
569 | CoMutex lock; | ||
570 | |||
571 | - QCryptoCipher *cipher; /* current cipher, NULL if no key yet */ | ||
572 | + QCryptoBlockOpenOptions *crypto_opts; /* Disk encryption runtime options */ | ||
573 | + QCryptoBlock *crypto; /* Disk encryption format driver */ | ||
574 | uint32_t crypt_method_header; | ||
575 | uint64_t snapshots_offset; | ||
576 | int snapshots_size; | ||
577 | diff --git a/qapi/block-core.json b/qapi/block-core.json | ||
578 | index XXXXXXX..XXXXXXX 100644 | ||
579 | --- a/qapi/block-core.json | ||
580 | +++ b/qapi/block-core.json | ||
581 | @@ -XXX,XX +XXX,XX @@ | ||
582 | 'data': { '*encrypt': 'BlockdevQcowEncryption' } } | ||
583 | |||
584 | |||
585 | + | ||
586 | +## | ||
587 | +# @BlockdevQcow2EncryptionFormat: | ||
588 | +# @aes: AES-CBC with plain64 initialization venctors | ||
589 | +# | ||
590 | +# Since: 2.10 | ||
591 | +## | ||
592 | +{ 'enum': 'BlockdevQcow2EncryptionFormat', | ||
593 | + 'data': [ 'aes' ] } | ||
594 | + | ||
595 | +## | ||
596 | +# @BlockdevQcow2Encryption: | ||
597 | +# | ||
598 | +# Since: 2.10 | ||
599 | +## | ||
600 | +{ 'union': 'BlockdevQcow2Encryption', | ||
601 | + 'base': { 'format': 'BlockdevQcow2EncryptionFormat' }, | ||
602 | + 'discriminator': 'format', | ||
603 | + 'data': { 'aes': 'QCryptoBlockOptionsQCow' } } | ||
604 | + | ||
605 | ## | ||
606 | # @BlockdevOptionsQcow2: | ||
607 | # | ||
608 | @@ -XXX,XX +XXX,XX @@ | ||
609 | # @cache-clean-interval: clean unused entries in the L2 and refcount | ||
610 | # caches. The interval is in seconds. The default value | ||
611 | # is 0 and it disables this feature (since 2.5) | ||
612 | +# @encrypt: Image decryption options. Mandatory for | ||
613 | +# encrypted images, except when doing a metadata-only | ||
614 | +# probe of the image. (since 2.10) | ||
615 | # | ||
616 | # Since: 2.9 | ||
617 | ## | ||
618 | @@ -XXX,XX +XXX,XX @@ | ||
619 | '*cache-size': 'int', | ||
620 | '*l2-cache-size': 'int', | ||
621 | '*refcount-cache-size': 'int', | ||
622 | - '*cache-clean-interval': 'int' } } | ||
623 | - | ||
624 | + '*cache-clean-interval': 'int', | ||
625 | + '*encrypt': 'BlockdevQcow2Encryption' } } | ||
626 | |||
627 | ## | ||
628 | # @BlockdevOptionsSsh: | ||
629 | diff --git a/tests/qemu-iotests/049 b/tests/qemu-iotests/049 | ||
630 | index XXXXXXX..XXXXXXX 100755 | ||
631 | --- a/tests/qemu-iotests/049 | ||
632 | +++ b/tests/qemu-iotests/049 | ||
633 | @@ -XXX,XX +XXX,XX @@ test_qemu_img create -f $IMGFMT -o preallocation=1234 "$TEST_IMG" 64M | ||
634 | echo "== Check encryption option ==" | ||
635 | echo | ||
636 | test_qemu_img create -f $IMGFMT -o encryption=off "$TEST_IMG" 64M | ||
637 | -test_qemu_img create -f $IMGFMT -o encryption=on "$TEST_IMG" 64M | ||
638 | +test_qemu_img create -f $IMGFMT --object secret,id=sec0,data=123456 -o encryption=on,encrypt.key-secret=sec0 "$TEST_IMG" 64M | ||
639 | |||
640 | echo "== Check lazy_refcounts option (only with v3) ==" | ||
641 | echo | ||
642 | diff --git a/tests/qemu-iotests/049.out b/tests/qemu-iotests/049.out | ||
643 | index XXXXXXX..XXXXXXX 100644 | ||
644 | --- a/tests/qemu-iotests/049.out | ||
645 | +++ b/tests/qemu-iotests/049.out | ||
646 | @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=65536 preall | ||
647 | qemu-img create -f qcow2 -o encryption=off TEST_DIR/t.qcow2 64M | ||
648 | Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
649 | |||
650 | -qemu-img create -f qcow2 -o encryption=on TEST_DIR/t.qcow2 64M | ||
651 | -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=on cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
652 | +qemu-img create -f qcow2 --object secret,id=sec0,data=123456 -o encryption=on,encrypt.key-secret=sec0 TEST_DIR/t.qcow2 64M | ||
653 | +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=on encrypt.key-secret=sec0 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
654 | |||
655 | == Check lazy_refcounts option (only with v3) == | ||
656 | |||
657 | diff --git a/tests/qemu-iotests/082.out b/tests/qemu-iotests/082.out | ||
658 | index XXXXXXX..XXXXXXX 100644 | ||
659 | --- a/tests/qemu-iotests/082.out | ||
660 | +++ b/tests/qemu-iotests/082.out | ||
661 | @@ -XXX,XX +XXX,XX @@ backing_file File name of a base image | ||
662 | backing_fmt Image format of the base image | ||
663 | encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
664 | encrypt.format Encrypt the image, format choices: 'aes' | ||
665 | +encrypt.key-secret ID of the secret that provides the AES encryption key | ||
666 | cluster_size qcow2 cluster size | ||
667 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
668 | lazy_refcounts Postpone refcount updates | ||
669 | @@ -XXX,XX +XXX,XX @@ backing_file File name of a base image | ||
670 | backing_fmt Image format of the base image | ||
671 | encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
672 | encrypt.format Encrypt the image, format choices: 'aes' | ||
673 | +encrypt.key-secret ID of the secret that provides the AES encryption key | ||
674 | cluster_size qcow2 cluster size | ||
675 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
676 | lazy_refcounts Postpone refcount updates | ||
677 | @@ -XXX,XX +XXX,XX @@ backing_file File name of a base image | ||
678 | backing_fmt Image format of the base image | ||
679 | encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
680 | encrypt.format Encrypt the image, format choices: 'aes' | ||
681 | +encrypt.key-secret ID of the secret that provides the AES encryption key | ||
682 | cluster_size qcow2 cluster size | ||
683 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
684 | lazy_refcounts Postpone refcount updates | ||
685 | @@ -XXX,XX +XXX,XX @@ backing_file File name of a base image | ||
686 | backing_fmt Image format of the base image | ||
687 | encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
688 | encrypt.format Encrypt the image, format choices: 'aes' | ||
689 | +encrypt.key-secret ID of the secret that provides the AES encryption key | ||
690 | cluster_size qcow2 cluster size | ||
691 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
692 | lazy_refcounts Postpone refcount updates | ||
693 | @@ -XXX,XX +XXX,XX @@ backing_file File name of a base image | ||
694 | backing_fmt Image format of the base image | ||
695 | encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
696 | encrypt.format Encrypt the image, format choices: 'aes' | ||
697 | +encrypt.key-secret ID of the secret that provides the AES encryption key | ||
698 | cluster_size qcow2 cluster size | ||
699 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
700 | lazy_refcounts Postpone refcount updates | ||
701 | @@ -XXX,XX +XXX,XX @@ backing_file File name of a base image | ||
702 | backing_fmt Image format of the base image | ||
703 | encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
704 | encrypt.format Encrypt the image, format choices: 'aes' | ||
705 | +encrypt.key-secret ID of the secret that provides the AES encryption key | ||
706 | cluster_size qcow2 cluster size | ||
707 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
708 | lazy_refcounts Postpone refcount updates | ||
709 | @@ -XXX,XX +XXX,XX @@ backing_file File name of a base image | ||
710 | backing_fmt Image format of the base image | ||
711 | encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
712 | encrypt.format Encrypt the image, format choices: 'aes' | ||
713 | +encrypt.key-secret ID of the secret that provides the AES encryption key | ||
714 | cluster_size qcow2 cluster size | ||
715 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
716 | lazy_refcounts Postpone refcount updates | ||
717 | @@ -XXX,XX +XXX,XX @@ backing_file File name of a base image | ||
718 | backing_fmt Image format of the base image | ||
719 | encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
720 | encrypt.format Encrypt the image, format choices: 'aes' | ||
721 | +encrypt.key-secret ID of the secret that provides the AES encryption key | ||
722 | cluster_size qcow2 cluster size | ||
723 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
724 | lazy_refcounts Postpone refcount updates | ||
725 | @@ -XXX,XX +XXX,XX @@ backing_file File name of a base image | ||
726 | backing_fmt Image format of the base image | ||
727 | encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
728 | encrypt.format Encrypt the image, format choices: 'aes' | ||
729 | +encrypt.key-secret ID of the secret that provides the AES encryption key | ||
730 | cluster_size qcow2 cluster size | ||
731 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
732 | lazy_refcounts Postpone refcount updates | ||
733 | @@ -XXX,XX +XXX,XX @@ backing_file File name of a base image | ||
734 | backing_fmt Image format of the base image | ||
735 | encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
736 | encrypt.format Encrypt the image, format choices: 'aes' | ||
737 | +encrypt.key-secret ID of the secret that provides the AES encryption key | ||
738 | cluster_size qcow2 cluster size | ||
739 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
740 | lazy_refcounts Postpone refcount updates | ||
741 | @@ -XXX,XX +XXX,XX @@ backing_file File name of a base image | ||
742 | backing_fmt Image format of the base image | ||
743 | encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
744 | encrypt.format Encrypt the image, format choices: 'aes' | ||
745 | +encrypt.key-secret ID of the secret that provides the AES encryption key | ||
746 | cluster_size qcow2 cluster size | ||
747 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
748 | lazy_refcounts Postpone refcount updates | ||
749 | @@ -XXX,XX +XXX,XX @@ backing_file File name of a base image | ||
750 | backing_fmt Image format of the base image | ||
751 | encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
752 | encrypt.format Encrypt the image, format choices: 'aes' | ||
753 | +encrypt.key-secret ID of the secret that provides the AES encryption key | ||
754 | cluster_size qcow2 cluster size | ||
755 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
756 | lazy_refcounts Postpone refcount updates | ||
757 | @@ -XXX,XX +XXX,XX @@ backing_file File name of a base image | ||
758 | backing_fmt Image format of the base image | ||
759 | encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
760 | encrypt.format Encrypt the image, format choices: 'aes' | ||
761 | +encrypt.key-secret ID of the secret that provides the AES encryption key | ||
762 | cluster_size qcow2 cluster size | ||
763 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
764 | lazy_refcounts Postpone refcount updates | ||
765 | @@ -XXX,XX +XXX,XX @@ backing_file File name of a base image | ||
766 | backing_fmt Image format of the base image | ||
767 | encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
768 | encrypt.format Encrypt the image, format choices: 'aes' | ||
769 | +encrypt.key-secret ID of the secret that provides the AES encryption key | ||
770 | cluster_size qcow2 cluster size | ||
771 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
772 | lazy_refcounts Postpone refcount updates | ||
773 | @@ -XXX,XX +XXX,XX @@ backing_file File name of a base image | ||
774 | backing_fmt Image format of the base image | ||
775 | encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
776 | encrypt.format Encrypt the image, format choices: 'aes' | ||
777 | +encrypt.key-secret ID of the secret that provides the AES encryption key | ||
778 | cluster_size qcow2 cluster size | ||
779 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
780 | lazy_refcounts Postpone refcount updates | ||
781 | @@ -XXX,XX +XXX,XX @@ backing_file File name of a base image | ||
782 | backing_fmt Image format of the base image | ||
783 | encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
784 | encrypt.format Encrypt the image, format choices: 'aes' | ||
785 | +encrypt.key-secret ID of the secret that provides the AES encryption key | ||
786 | cluster_size qcow2 cluster size | ||
787 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
788 | lazy_refcounts Postpone refcount updates | ||
789 | @@ -XXX,XX +XXX,XX @@ backing_file File name of a base image | ||
790 | backing_fmt Image format of the base image | ||
791 | encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
792 | encrypt.format Encrypt the image, format choices: 'aes' | ||
793 | +encrypt.key-secret ID of the secret that provides the AES encryption key | ||
794 | cluster_size qcow2 cluster size | ||
795 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
796 | lazy_refcounts Postpone refcount updates | ||
797 | @@ -XXX,XX +XXX,XX @@ backing_file File name of a base image | ||
798 | backing_fmt Image format of the base image | ||
799 | encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
800 | encrypt.format Encrypt the image, format choices: 'aes' | ||
801 | +encrypt.key-secret ID of the secret that provides the AES encryption key | ||
802 | cluster_size qcow2 cluster size | ||
803 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
804 | lazy_refcounts Postpone refcount updates | ||
805 | @@ -XXX,XX +XXX,XX @@ backing_file File name of a base image | ||
806 | backing_fmt Image format of the base image | ||
807 | encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
808 | encrypt.format Encrypt the image, format choices: 'aes' | ||
809 | +encrypt.key-secret ID of the secret that provides the AES encryption key | ||
810 | cluster_size qcow2 cluster size | ||
811 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
812 | lazy_refcounts Postpone refcount updates | ||
813 | @@ -XXX,XX +XXX,XX @@ backing_file File name of a base image | ||
814 | backing_fmt Image format of the base image | ||
815 | encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
816 | encrypt.format Encrypt the image, format choices: 'aes' | ||
817 | +encrypt.key-secret ID of the secret that provides the AES encryption key | ||
818 | cluster_size qcow2 cluster size | ||
819 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
820 | lazy_refcounts Postpone refcount updates | ||
821 | @@ -XXX,XX +XXX,XX @@ backing_file File name of a base image | ||
822 | backing_fmt Image format of the base image | ||
823 | encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
824 | encrypt.format Encrypt the image, format choices: 'aes' | ||
825 | +encrypt.key-secret ID of the secret that provides the AES encryption key | ||
826 | cluster_size qcow2 cluster size | ||
827 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
828 | lazy_refcounts Postpone refcount updates | ||
829 | @@ -XXX,XX +XXX,XX @@ backing_file File name of a base image | ||
830 | backing_fmt Image format of the base image | ||
831 | encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
832 | encrypt.format Encrypt the image, format choices: 'aes' | ||
833 | +encrypt.key-secret ID of the secret that provides the AES encryption key | ||
834 | cluster_size qcow2 cluster size | ||
835 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
836 | lazy_refcounts Postpone refcount updates | ||
837 | @@ -XXX,XX +XXX,XX @@ backing_file File name of a base image | ||
838 | backing_fmt Image format of the base image | ||
839 | encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
840 | encrypt.format Encrypt the image, format choices: 'aes' | ||
841 | +encrypt.key-secret ID of the secret that provides the AES encryption key | ||
842 | cluster_size qcow2 cluster size | ||
843 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
844 | lazy_refcounts Postpone refcount updates | ||
845 | @@ -XXX,XX +XXX,XX @@ backing_file File name of a base image | ||
846 | backing_fmt Image format of the base image | ||
847 | encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
848 | encrypt.format Encrypt the image, format choices: 'aes' | ||
849 | +encrypt.key-secret ID of the secret that provides the AES encryption key | ||
850 | cluster_size qcow2 cluster size | ||
851 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
852 | lazy_refcounts Postpone refcount updates | ||
853 | @@ -XXX,XX +XXX,XX @@ backing_file File name of a base image | ||
854 | backing_fmt Image format of the base image | ||
855 | encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
856 | encrypt.format Encrypt the image, format choices: 'aes' | ||
857 | +encrypt.key-secret ID of the secret that provides the AES encryption key | ||
858 | cluster_size qcow2 cluster size | ||
859 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
860 | lazy_refcounts Postpone refcount updates | ||
861 | @@ -XXX,XX +XXX,XX @@ backing_file File name of a base image | ||
862 | backing_fmt Image format of the base image | ||
863 | encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
864 | encrypt.format Encrypt the image, format choices: 'aes' | ||
865 | +encrypt.key-secret ID of the secret that provides the AES encryption key | ||
866 | cluster_size qcow2 cluster size | ||
867 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
868 | lazy_refcounts Postpone refcount updates | ||
869 | @@ -XXX,XX +XXX,XX @@ backing_file File name of a base image | ||
870 | backing_fmt Image format of the base image | ||
871 | encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
872 | encrypt.format Encrypt the image, format choices: 'aes' | ||
873 | +encrypt.key-secret ID of the secret that provides the AES encryption key | ||
874 | cluster_size qcow2 cluster size | ||
875 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
876 | lazy_refcounts Postpone refcount updates | ||
877 | diff --git a/tests/qemu-iotests/087 b/tests/qemu-iotests/087 | ||
878 | index XXXXXXX..XXXXXXX 100755 | ||
879 | --- a/tests/qemu-iotests/087 | ||
880 | +++ b/tests/qemu-iotests/087 | ||
881 | @@ -XXX,XX +XXX,XX @@ echo | ||
882 | echo === Encrypted image === | ||
883 | echo | ||
884 | |||
885 | -_make_test_img -o encryption=on $size | ||
886 | -run_qemu -S <<EOF | ||
887 | +_make_test_img --object secret,id=sec0,data=123456 -o encryption=on,encrypt.key-secret=sec0 $size | ||
888 | +run_qemu <<EOF | ||
889 | { "execute": "qmp_capabilities" } | ||
890 | -{ "execute": "blockdev-add", | ||
891 | +{ "execute": "object-add", | ||
892 | "arguments": { | ||
893 | - "driver": "$IMGFMT", | ||
894 | - "node-name": "disk", | ||
895 | - "file": { | ||
896 | - "driver": "file", | ||
897 | - "filename": "$TEST_IMG" | ||
898 | + "qom-type": "secret", | ||
899 | + "id": "sec0", | ||
900 | + "props": { | ||
901 | + "data": "123456" | ||
902 | } | ||
903 | - } | ||
904 | } | ||
905 | -{ "execute": "quit" } | ||
906 | -EOF | ||
907 | - | ||
908 | -run_qemu <<EOF | ||
909 | -{ "execute": "qmp_capabilities" } | ||
910 | +} | ||
911 | { "execute": "blockdev-add", | ||
912 | "arguments": { | ||
913 | "driver": "$IMGFMT", | ||
914 | @@ -XXX,XX +XXX,XX @@ run_qemu <<EOF | ||
915 | "file": { | ||
916 | "driver": "file", | ||
917 | "filename": "$TEST_IMG" | ||
918 | + }, | ||
919 | + "encrypt": { | ||
920 | + "format": "aes", | ||
921 | + "key-secret": "sec0" | ||
922 | } | ||
923 | } | ||
924 | } | ||
925 | @@ -XXX,XX +XXX,XX @@ echo | ||
926 | echo === Missing driver === | ||
927 | echo | ||
928 | |||
929 | -_make_test_img -o encryption=on $size | ||
930 | +_make_test_img --object secret,id=sec0,data=123456 -o encryption=on,encrypt.key-secret=sec0 $size | ||
931 | run_qemu -S <<EOF | ||
932 | { "execute": "qmp_capabilities" } | ||
933 | { "execute": "blockdev-add", | ||
934 | diff --git a/tests/qemu-iotests/087.out b/tests/qemu-iotests/087.out | ||
935 | index XXXXXXX..XXXXXXX 100644 | ||
936 | --- a/tests/qemu-iotests/087.out | ||
937 | +++ b/tests/qemu-iotests/087.out | ||
938 | @@ -XXX,XX +XXX,XX @@ QMP_VERSION | ||
939 | |||
940 | === Encrypted image === | ||
941 | |||
942 | -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encryption=on | ||
943 | -Testing: -S | ||
944 | -QMP_VERSION | ||
945 | -{"return": {}} | ||
946 | -{"error": {"class": "GenericError", "desc": "Use of AES-CBC encrypted IMGFMT images is no longer supported in system emulators"}} | ||
947 | -{"return": {}} | ||
948 | -{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} | ||
949 | - | ||
950 | +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encryption=on encrypt.key-secret=sec0 | ||
951 | Testing: | ||
952 | QMP_VERSION | ||
953 | {"return": {}} | ||
954 | +{"return": {}} | ||
955 | {"error": {"class": "GenericError", "desc": "Use of AES-CBC encrypted IMGFMT images is no longer supported in system emulators"}} | ||
956 | {"return": {}} | ||
957 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} | ||
958 | @@ -XXX,XX +XXX,XX @@ QMP_VERSION | ||
959 | |||
960 | === Missing driver === | ||
961 | |||
962 | -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encryption=on | ||
963 | +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encryption=on encrypt.key-secret=sec0 | ||
964 | Testing: -S | ||
965 | QMP_VERSION | ||
966 | {"return": {}} | ||
967 | diff --git a/tests/qemu-iotests/134 b/tests/qemu-iotests/134 | ||
968 | index XXXXXXX..XXXXXXX 100755 | ||
969 | --- a/tests/qemu-iotests/134 | ||
970 | +++ b/tests/qemu-iotests/134 | ||
971 | @@ -XXX,XX +XXX,XX @@ _supported_os Linux | ||
972 | |||
973 | |||
974 | size=128M | ||
975 | -IMGOPTS="encryption=on" _make_test_img $size | ||
976 | + | ||
977 | +SECRET="secret,id=sec0,data=astrochicken" | ||
978 | +SECRETALT="secret,id=sec0,data=platypus" | ||
979 | + | ||
980 | +_make_test_img --object $SECRET -o "encryption=on,encrypt.key-secret=sec0" $size | ||
981 | + | ||
982 | +IMGSPEC="driver=$IMGFMT,file.filename=$TEST_IMG,encrypt.key-secret=sec0" | ||
983 | + | ||
984 | +QEMU_IO_OPTIONS=$QEMU_IO_OPTIONS_NO_FMT | ||
985 | |||
986 | echo | ||
987 | echo "== reading whole image ==" | ||
988 | -echo "astrochicken" | $QEMU_IO -c "read 0 $size" "$TEST_IMG" | _filter_qemu_io | _filter_testdir | ||
989 | +$QEMU_IO --object $SECRET -c "read 0 $size" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir | ||
990 | |||
991 | echo | ||
992 | echo "== rewriting whole image ==" | ||
993 | -echo "astrochicken" | $QEMU_IO -c "write -P 0xa 0 $size" "$TEST_IMG" | _filter_qemu_io | _filter_testdir | ||
994 | +$QEMU_IO --object $SECRET -c "write -P 0xa 0 $size" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir | ||
995 | |||
996 | echo | ||
997 | echo "== verify pattern ==" | ||
998 | -echo "astrochicken" | $QEMU_IO -c "read -P 0xa 0 $size" "$TEST_IMG" | _filter_qemu_io | _filter_testdir | ||
999 | +$QEMU_IO --object $SECRET -c "read -P 0xa 0 $size" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir | ||
1000 | |||
1001 | echo | ||
1002 | echo "== verify pattern failure with wrong password ==" | ||
1003 | -echo "platypus" | $QEMU_IO -c "read -P 0xa 0 $size" "$TEST_IMG" | _filter_qemu_io | _filter_testdir | ||
1004 | +$QEMU_IO --object $SECRETALT -c "read -P 0xa 0 $size" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir | ||
1005 | |||
1006 | |||
1007 | # success, all done | ||
1008 | diff --git a/tests/qemu-iotests/134.out b/tests/qemu-iotests/134.out | ||
1009 | index XXXXXXX..XXXXXXX 100644 | ||
1010 | --- a/tests/qemu-iotests/134.out | ||
1011 | +++ b/tests/qemu-iotests/134.out | ||
1012 | @@ -XXX,XX +XXX,XX @@ | ||
1013 | QA output created by 134 | ||
1014 | -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encryption=on | ||
1015 | +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encryption=on encrypt.key-secret=sec0 | ||
1016 | |||
1017 | == reading whole image == | ||
1018 | -Disk image 'TEST_DIR/t.qcow2' is encrypted. | ||
1019 | -password: | ||
1020 | read 134217728/134217728 bytes at offset 0 | ||
1021 | 128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1022 | |||
1023 | == rewriting whole image == | ||
1024 | -Disk image 'TEST_DIR/t.qcow2' is encrypted. | ||
1025 | -password: | ||
1026 | wrote 134217728/134217728 bytes at offset 0 | ||
1027 | 128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1028 | |||
1029 | == verify pattern == | ||
1030 | -Disk image 'TEST_DIR/t.qcow2' is encrypted. | ||
1031 | -password: | ||
1032 | read 134217728/134217728 bytes at offset 0 | ||
1033 | 128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1034 | |||
1035 | == verify pattern failure with wrong password == | ||
1036 | -Disk image 'TEST_DIR/t.qcow2' is encrypted. | ||
1037 | -password: | ||
1038 | Pattern verification failed at offset 0, 134217728 bytes | ||
1039 | read 134217728/134217728 bytes at offset 0 | ||
1040 | 128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1041 | diff --git a/tests/qemu-iotests/158 b/tests/qemu-iotests/158 | ||
1042 | index XXXXXXX..XXXXXXX 100755 | ||
1043 | --- a/tests/qemu-iotests/158 | ||
1044 | +++ b/tests/qemu-iotests/158 | ||
1045 | @@ -XXX,XX +XXX,XX @@ _supported_os Linux | ||
1046 | |||
1047 | size=128M | ||
1048 | TEST_IMG_BASE=$TEST_IMG.base | ||
1049 | +SECRET="secret,id=sec0,data=astrochicken" | ||
1050 | |||
1051 | TEST_IMG_SAVE=$TEST_IMG | ||
1052 | TEST_IMG=$TEST_IMG_BASE | ||
1053 | echo "== create base ==" | ||
1054 | -IMGOPTS="encryption=on" _make_test_img $size | ||
1055 | +_make_test_img --object $SECRET -o "encryption=on,encrypt.key-secret=sec0" $size | ||
1056 | TEST_IMG=$TEST_IMG_SAVE | ||
1057 | |||
1058 | +IMGSPECBASE="driver=$IMGFMT,file.filename=$TEST_IMG_BASE,encrypt.key-secret=sec0" | ||
1059 | +IMGSPEC="driver=$IMGFMT,file.filename=$TEST_IMG,backing.driver=$IMGFMT,backing.file.filename=$TEST_IMG_BASE,backing.encrypt.key-secret=sec0,encrypt.key-secret=sec0" | ||
1060 | +QEMU_IO_OPTIONS=$QEMU_IO_OPTIONS_NO_FMT | ||
1061 | + | ||
1062 | echo | ||
1063 | echo "== writing whole image ==" | ||
1064 | -echo "astrochicken" | $QEMU_IO -c "write -P 0xa 0 $size" "$TEST_IMG_BASE" | _filter_qemu_io | _filter_testdir | ||
1065 | +$QEMU_IO --object $SECRET -c "write -P 0xa 0 $size" --image-opts $IMGSPECBASE | _filter_qemu_io | _filter_testdir | ||
1066 | |||
1067 | echo | ||
1068 | echo "== verify pattern ==" | ||
1069 | -echo "astrochicken" | $QEMU_IO -c "read -P 0xa 0 $size" "$TEST_IMG_BASE" | _filter_qemu_io | _filter_testdir | ||
1070 | +$QEMU_IO --object $SECRET -c "read -P 0xa 0 $size" --image-opts $IMGSPECBASE | _filter_qemu_io | _filter_testdir | ||
1071 | |||
1072 | echo "== create overlay ==" | ||
1073 | -IMGOPTS="encryption=on" _make_test_img -b "$TEST_IMG_BASE" $size | ||
1074 | +_make_test_img --object $SECRET -o "encryption=on,encrypt.key-secret=sec0" -b "$TEST_IMG_BASE" $size | ||
1075 | |||
1076 | echo | ||
1077 | echo "== writing part of a cluster ==" | ||
1078 | -echo "astrochicken" | $QEMU_IO -c "write -P 0xe 0 1024" "$TEST_IMG" | _filter_qemu_io | _filter_testdir | ||
1079 | +$QEMU_IO --object $SECRET -c "write -P 0xe 0 1024" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir | ||
1080 | |||
1081 | echo | ||
1082 | echo "== verify pattern ==" | ||
1083 | -echo "astrochicken" | $QEMU_IO -c "read -P 0xe 0 1024" "$TEST_IMG" | _filter_qemu_io | _filter_testdir | ||
1084 | +$QEMU_IO --object $SECRET -c "read -P 0xe 0 1024" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir | ||
1085 | echo | ||
1086 | echo "== verify pattern ==" | ||
1087 | -echo "astrochicken" | $QEMU_IO -c "read -P 0xa 1024 64512" "$TEST_IMG" | _filter_qemu_io | _filter_testdir | ||
1088 | +$QEMU_IO --object $SECRET -c "read -P 0xa 1024 64512" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir | ||
1089 | |||
1090 | |||
1091 | # success, all done | ||
1092 | diff --git a/tests/qemu-iotests/158.out b/tests/qemu-iotests/158.out | ||
1093 | index XXXXXXX..XXXXXXX 100644 | ||
1094 | --- a/tests/qemu-iotests/158.out | ||
1095 | +++ b/tests/qemu-iotests/158.out | ||
1096 | @@ -XXX,XX +XXX,XX @@ | ||
1097 | QA output created by 158 | ||
1098 | == create base == | ||
1099 | -Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728 encryption=on | ||
1100 | +Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728 encryption=on encrypt.key-secret=sec0 | ||
1101 | |||
1102 | == writing whole image == | ||
1103 | -Disk image 'TEST_DIR/t.qcow2.base' is encrypted. | ||
1104 | -password: | ||
1105 | wrote 134217728/134217728 bytes at offset 0 | ||
1106 | 128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1107 | |||
1108 | == verify pattern == | ||
1109 | -Disk image 'TEST_DIR/t.qcow2.base' is encrypted. | ||
1110 | -password: | ||
1111 | read 134217728/134217728 bytes at offset 0 | ||
1112 | 128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1113 | == create overlay == | ||
1114 | -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.base encryption=on | ||
1115 | +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.base encryption=on encrypt.key-secret=sec0 | ||
1116 | |||
1117 | == writing part of a cluster == | ||
1118 | -Disk image 'TEST_DIR/t.qcow2' is encrypted. | ||
1119 | -password: | ||
1120 | wrote 1024/1024 bytes at offset 0 | ||
1121 | 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1122 | |||
1123 | == verify pattern == | ||
1124 | -Disk image 'TEST_DIR/t.qcow2' is encrypted. | ||
1125 | -password: | ||
1126 | read 1024/1024 bytes at offset 0 | ||
1127 | 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1128 | |||
1129 | == verify pattern == | ||
1130 | -Disk image 'TEST_DIR/t.qcow2' is encrypted. | ||
1131 | -password: | ||
1132 | read 64512/64512 bytes at offset 1024 | ||
1133 | 63 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1134 | *** done | ||
1135 | diff --git a/tests/qemu-iotests/common b/tests/qemu-iotests/common | ||
1136 | index XXXXXXX..XXXXXXX 100644 | ||
1137 | --- a/tests/qemu-iotests/common | ||
1138 | +++ b/tests/qemu-iotests/common | ||
1139 | @@ -XXX,XX +XXX,XX @@ export IMGPROTO=file | ||
1140 | export IMGOPTS="" | ||
1141 | export CACHEMODE="writeback" | ||
1142 | export QEMU_IO_OPTIONS="" | ||
1143 | +export QEMU_IO_OPTIONS_NO_FMT="" | ||
1144 | export CACHEMODE_IS_DEFAULT=true | ||
1145 | export QEMU_OPTIONS="-nodefaults -machine accel=qtest" | ||
1146 | export VALGRIND_QEMU= | ||
1147 | @@ -XXX,XX +XXX,XX @@ BEGIN { for (t='$start'; t<='$end'; t++) printf "%03d\n",t }' \ | ||
1148 | done | ||
1149 | |||
1150 | # Set qemu-io cache mode with $CACHEMODE we have | ||
1151 | -if [ "$IMGOPTSSYNTAX" = "true" ]; then | ||
1152 | - QEMU_IO_OPTIONS="$QEMU_IO_OPTIONS --cache $CACHEMODE" | ||
1153 | -else | ||
1154 | - QEMU_IO_OPTIONS="$QEMU_IO_OPTIONS -f $IMGFMT --cache $CACHEMODE" | ||
1155 | +QEMU_IO_OPTIONS="$QEMU_IO_OPTIONS --cache $CACHEMODE" | ||
1156 | + | ||
1157 | +QEMU_IO_OPTIONS_NO_FMT="$QEMU_IO_OPTIONS" | ||
1158 | +if [ "$IMGOPTSSYNTAX" != "true" ]; then | ||
1159 | + QEMU_IO_OPTIONS="$QEMU_IO_OPTIONS -f $IMGFMT" | ||
1160 | fi | ||
1161 | |||
1162 | # Set default options for qemu-img create -o if they were not specified | ||
1163 | -- | 86 | -- |
1164 | 1.8.3.1 | 87 | 2.37.3 |
1165 | |||
1166 | diff view generated by jsdifflib |
1 | From: Eric Blake <eblake@redhat.com> | 1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | We are gradually converting to byte-based interfaces, as they are | 3 | iostatus is the only field (together with .job) that needs |
4 | easier to reason about than sector-based. Convert another internal | 4 | protection using the job mutex. |
5 | function, preserving all existing semantics, and adding one more | ||
6 | assertion that things are still sector-aligned (so that conversions | ||
7 | to sectors in mirror_read_complete don't need to round). | ||
8 | 5 | ||
9 | Signed-off-by: Eric Blake <eblake@redhat.com> | 6 | It is set in the main loop (GLOBAL_STATE functions) but read |
7 | in I/O code (block_job_error_action). | ||
8 | |||
9 | In order to protect it, change block_job_iostatus_set_err | ||
10 | to block_job_iostatus_set_err_locked(), always called under | ||
11 | job lock. | ||
12 | |||
13 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
14 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
15 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> | ||
16 | Message-Id: <20220926093214.506243-17-eesposit@redhat.com> | ||
17 | [kwolf: Fixed up type of iostatus] | ||
10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 18 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
11 | --- | 19 | --- |
12 | block/mirror.c | 74 ++++++++++++++++++++++++++-------------------------------- | 20 | block/mirror.c | 6 +++++- |
13 | 1 file changed, 33 insertions(+), 41 deletions(-) | 21 | blockjob.c | 5 +++-- |
22 | 2 files changed, 8 insertions(+), 3 deletions(-) | ||
14 | 23 | ||
15 | diff --git a/block/mirror.c b/block/mirror.c | 24 | diff --git a/block/mirror.c b/block/mirror.c |
16 | index XXXXXXX..XXXXXXX 100644 | 25 | index XXXXXXX..XXXXXXX 100644 |
17 | --- a/block/mirror.c | 26 | --- a/block/mirror.c |
18 | +++ b/block/mirror.c | 27 | +++ b/block/mirror.c |
19 | @@ -XXX,XX +XXX,XX @@ static inline int mirror_clip_sectors(MirrorBlockJob *s, | 28 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn mirror_run(Job *job, Error **errp) |
20 | /* Round offset and/or bytes to target cluster if COW is needed, and | 29 | BlockDriverState *bs = s->mirror_top_bs->backing->bs; |
21 | * return the offset of the adjusted tail against original. */ | 30 | BlockDriverState *target_bs = blk_bs(s->target); |
22 | static int mirror_cow_align(MirrorBlockJob *s, int64_t *offset, | 31 | bool need_drain = true; |
23 | - unsigned int *bytes) | 32 | + BlockDeviceIoStatus iostatus; |
24 | + uint64_t *bytes) | 33 | int64_t length; |
34 | int64_t target_length; | ||
35 | BlockDriverInfo bdi; | ||
36 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn mirror_run(Job *job, Error **errp) | ||
37 | * We do so every BLKOCK_JOB_SLICE_TIME nanoseconds, or when there is | ||
38 | * an error, or when the source is clean, whichever comes first. */ | ||
39 | delta = qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - s->last_pause_ns; | ||
40 | + WITH_JOB_LOCK_GUARD() { | ||
41 | + iostatus = s->common.iostatus; | ||
42 | + } | ||
43 | if (delta < BLOCK_JOB_SLICE_TIME && | ||
44 | - s->common.iostatus == BLOCK_DEVICE_IO_STATUS_OK) { | ||
45 | + iostatus == BLOCK_DEVICE_IO_STATUS_OK) { | ||
46 | if (s->in_flight >= MAX_IN_FLIGHT || s->buf_free_count == 0 || | ||
47 | (cnt == 0 && s->in_flight > 0)) { | ||
48 | trace_mirror_yield(s, cnt, s->buf_free_count, s->in_flight); | ||
49 | diff --git a/blockjob.c b/blockjob.c | ||
50 | index XXXXXXX..XXXXXXX 100644 | ||
51 | --- a/blockjob.c | ||
52 | +++ b/blockjob.c | ||
53 | @@ -XXX,XX +XXX,XX @@ BlockJobInfo *block_job_query(BlockJob *job, Error **errp) | ||
54 | return block_job_query_locked(job, errp); | ||
55 | } | ||
56 | |||
57 | -static void block_job_iostatus_set_err(BlockJob *job, int error) | ||
58 | +/* Called with job lock held */ | ||
59 | +static void block_job_iostatus_set_err_locked(BlockJob *job, int error) | ||
25 | { | 60 | { |
26 | bool need_cow; | 61 | if (job->iostatus == BLOCK_DEVICE_IO_STATUS_OK) { |
27 | int ret = 0; | 62 | job->iostatus = error == ENOSPC ? BLOCK_DEVICE_IO_STATUS_NOSPACE : |
28 | @@ -XXX,XX +XXX,XX @@ static int mirror_cow_align(MirrorBlockJob *s, int64_t *offset, | 63 | @@ -XXX,XX +XXX,XX @@ BlockErrorAction block_job_error_action(BlockJob *job, BlockdevOnError on_err, |
29 | unsigned int align_bytes = *bytes; | 64 | */ |
30 | int max_bytes = s->granularity * s->max_iov; | 65 | job->job.user_paused = true; |
31 | 66 | } | |
32 | + assert(*bytes < INT_MAX); | 67 | + block_job_iostatus_set_err_locked(job, error); |
33 | need_cow = !test_bit(*offset / s->granularity, s->cow_bitmap); | 68 | } |
34 | need_cow |= !test_bit((*offset + *bytes - 1) / s->granularity, | 69 | - block_job_iostatus_set_err(job, error); |
35 | s->cow_bitmap); | 70 | } |
36 | @@ -XXX,XX +XXX,XX @@ static inline void mirror_wait_for_io(MirrorBlockJob *s) | 71 | return action; |
37 | } | 72 | } |
38 | |||
39 | /* Submit async read while handling COW. | ||
40 | - * Returns: The number of sectors copied after and including sector_num, | ||
41 | - * excluding any sectors copied prior to sector_num due to alignment. | ||
42 | - * This will be nb_sectors if no alignment is necessary, or | ||
43 | - * (new_end - sector_num) if tail is rounded up or down due to | ||
44 | + * Returns: The number of bytes copied after and including offset, | ||
45 | + * excluding any bytes copied prior to offset due to alignment. | ||
46 | + * This will be @bytes if no alignment is necessary, or | ||
47 | + * (new_end - offset) if tail is rounded up or down due to | ||
48 | * alignment or buffer limit. | ||
49 | */ | ||
50 | -static int mirror_do_read(MirrorBlockJob *s, int64_t sector_num, | ||
51 | - int nb_sectors) | ||
52 | +static uint64_t mirror_do_read(MirrorBlockJob *s, int64_t offset, | ||
53 | + uint64_t bytes) | ||
54 | { | ||
55 | BlockBackend *source = s->common.blk; | ||
56 | - int sectors_per_chunk, nb_chunks; | ||
57 | - int ret; | ||
58 | + int nb_chunks; | ||
59 | + uint64_t ret; | ||
60 | MirrorOp *op; | ||
61 | - int max_sectors; | ||
62 | + uint64_t max_bytes; | ||
63 | |||
64 | - sectors_per_chunk = s->granularity >> BDRV_SECTOR_BITS; | ||
65 | - max_sectors = sectors_per_chunk * s->max_iov; | ||
66 | + max_bytes = s->granularity * s->max_iov; | ||
67 | |||
68 | /* We can only handle as much as buf_size at a time. */ | ||
69 | - nb_sectors = MIN(s->buf_size >> BDRV_SECTOR_BITS, nb_sectors); | ||
70 | - nb_sectors = MIN(max_sectors, nb_sectors); | ||
71 | - assert(nb_sectors); | ||
72 | - assert(nb_sectors < BDRV_REQUEST_MAX_SECTORS); | ||
73 | - ret = nb_sectors; | ||
74 | + bytes = MIN(s->buf_size, MIN(max_bytes, bytes)); | ||
75 | + assert(bytes); | ||
76 | + assert(bytes < BDRV_REQUEST_MAX_BYTES); | ||
77 | + ret = bytes; | ||
78 | |||
79 | if (s->cow_bitmap) { | ||
80 | - int64_t offset = sector_num * BDRV_SECTOR_SIZE; | ||
81 | - unsigned int bytes = nb_sectors * BDRV_SECTOR_SIZE; | ||
82 | - int gap; | ||
83 | - | ||
84 | - gap = mirror_cow_align(s, &offset, &bytes); | ||
85 | - sector_num = offset / BDRV_SECTOR_SIZE; | ||
86 | - nb_sectors = bytes / BDRV_SECTOR_SIZE; | ||
87 | - ret += gap / BDRV_SECTOR_SIZE; | ||
88 | + ret += mirror_cow_align(s, &offset, &bytes); | ||
89 | } | ||
90 | - assert(nb_sectors << BDRV_SECTOR_BITS <= s->buf_size); | ||
91 | - /* The sector range must meet granularity because: | ||
92 | + assert(bytes <= s->buf_size); | ||
93 | + /* The offset is granularity-aligned because: | ||
94 | * 1) Caller passes in aligned values; | ||
95 | * 2) mirror_cow_align is used only when target cluster is larger. */ | ||
96 | - assert(!(sector_num % sectors_per_chunk)); | ||
97 | - nb_chunks = DIV_ROUND_UP(nb_sectors, sectors_per_chunk); | ||
98 | + assert(QEMU_IS_ALIGNED(offset, s->granularity)); | ||
99 | + /* The range is sector-aligned, since bdrv_getlength() rounds up. */ | ||
100 | + assert(QEMU_IS_ALIGNED(bytes, BDRV_SECTOR_SIZE)); | ||
101 | + nb_chunks = DIV_ROUND_UP(bytes, s->granularity); | ||
102 | |||
103 | while (s->buf_free_count < nb_chunks) { | ||
104 | - trace_mirror_yield_in_flight(s, sector_num * BDRV_SECTOR_SIZE, | ||
105 | - s->in_flight); | ||
106 | + trace_mirror_yield_in_flight(s, offset, s->in_flight); | ||
107 | mirror_wait_for_io(s); | ||
108 | } | ||
109 | |||
110 | /* Allocate a MirrorOp that is used as an AIO callback. */ | ||
111 | op = g_new(MirrorOp, 1); | ||
112 | op->s = s; | ||
113 | - op->offset = sector_num * BDRV_SECTOR_SIZE; | ||
114 | - op->bytes = nb_sectors * BDRV_SECTOR_SIZE; | ||
115 | + op->offset = offset; | ||
116 | + op->bytes = bytes; | ||
117 | |||
118 | /* Now make a QEMUIOVector taking enough granularity-sized chunks | ||
119 | * from s->buf_free. | ||
120 | @@ -XXX,XX +XXX,XX @@ static int mirror_do_read(MirrorBlockJob *s, int64_t sector_num, | ||
121 | qemu_iovec_init(&op->qiov, nb_chunks); | ||
122 | while (nb_chunks-- > 0) { | ||
123 | MirrorBuffer *buf = QSIMPLEQ_FIRST(&s->buf_free); | ||
124 | - size_t remaining = nb_sectors * BDRV_SECTOR_SIZE - op->qiov.size; | ||
125 | + size_t remaining = bytes - op->qiov.size; | ||
126 | |||
127 | QSIMPLEQ_REMOVE_HEAD(&s->buf_free, next); | ||
128 | s->buf_free_count--; | ||
129 | @@ -XXX,XX +XXX,XX @@ static int mirror_do_read(MirrorBlockJob *s, int64_t sector_num, | ||
130 | |||
131 | /* Copy the dirty cluster. */ | ||
132 | s->in_flight++; | ||
133 | - s->bytes_in_flight += nb_sectors * BDRV_SECTOR_SIZE; | ||
134 | - trace_mirror_one_iteration(s, sector_num * BDRV_SECTOR_SIZE, | ||
135 | - nb_sectors * BDRV_SECTOR_SIZE); | ||
136 | + s->bytes_in_flight += bytes; | ||
137 | + trace_mirror_one_iteration(s, offset, bytes); | ||
138 | |||
139 | - blk_aio_preadv(source, sector_num * BDRV_SECTOR_SIZE, &op->qiov, 0, | ||
140 | - mirror_read_complete, op); | ||
141 | + blk_aio_preadv(source, offset, &op->qiov, 0, mirror_read_complete, op); | ||
142 | return ret; | ||
143 | } | ||
144 | |||
145 | @@ -XXX,XX +XXX,XX @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s) | ||
146 | io_sectors = mirror_clip_sectors(s, sector_num, io_sectors); | ||
147 | switch (mirror_method) { | ||
148 | case MIRROR_METHOD_COPY: | ||
149 | - io_sectors = mirror_do_read(s, sector_num, io_sectors); | ||
150 | - io_bytes_acct = io_sectors * BDRV_SECTOR_SIZE; | ||
151 | + io_bytes_acct = mirror_do_read(s, sector_num * BDRV_SECTOR_SIZE, | ||
152 | + io_sectors * BDRV_SECTOR_SIZE); | ||
153 | + io_sectors = io_bytes_acct / BDRV_SECTOR_SIZE; | ||
154 | break; | ||
155 | case MIRROR_METHOD_ZERO: | ||
156 | case MIRROR_METHOD_DISCARD: | ||
157 | -- | 73 | -- |
158 | 1.8.3.1 | 74 | 2.37.3 |
159 | |||
160 | diff view generated by jsdifflib |
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Add format driver handler, which should mark loaded read-only | 3 | Some callbacks implementation use bdrv_* APIs that assume the |
4 | bitmaps as 'IN_USE' in the image and unset read_only field in | 4 | AioContext lock is held. Make sure this invariant is documented. |
5 | corresponding BdrvDirtyBitmap's. | ||
6 | 5 | ||
7 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 6 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
8 | Reviewed-by: John Snow <jsnow@redhat.com> | 7 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> |
9 | Reviewed-by: Max Reitz <mreitz@redhat.com> | 8 | Message-Id: <20220926093214.506243-18-eesposit@redhat.com> |
10 | Message-id: 20170628120530.31251-14-vsementsov@virtuozzo.com | 9 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> |
11 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
12 | --- | 11 | --- |
13 | block.c | 19 +++++++++++++++++++ | 12 | include/qemu/job.h | 27 +++++++++++++++++++++++++-- |
14 | include/block/block_int.h | 7 +++++++ | 13 | 1 file changed, 25 insertions(+), 2 deletions(-) |
15 | 2 files changed, 26 insertions(+) | ||
16 | 14 | ||
17 | diff --git a/block.c b/block.c | 15 | diff --git a/include/qemu/job.h b/include/qemu/job.h |
18 | index XXXXXXX..XXXXXXX 100644 | 16 | index XXXXXXX..XXXXXXX 100644 |
19 | --- a/block.c | 17 | --- a/include/qemu/job.h |
20 | +++ b/block.c | 18 | +++ b/include/qemu/job.h |
21 | @@ -XXX,XX +XXX,XX @@ void bdrv_reopen_commit(BDRVReopenState *reopen_state) | 19 | @@ -XXX,XX +XXX,XX @@ typedef struct Job { |
22 | { | 20 | /** True if this job should automatically dismiss itself */ |
23 | BlockDriver *drv; | 21 | bool auto_dismiss; |
24 | BlockDriverState *bs; | 22 | |
25 | + bool old_can_write, new_can_write; | 23 | - /** The completion function that will be called when the job completes. */ |
26 | |||
27 | assert(reopen_state != NULL); | ||
28 | bs = reopen_state->bs; | ||
29 | drv = bs->drv; | ||
30 | assert(drv != NULL); | ||
31 | |||
32 | + old_can_write = | ||
33 | + !bdrv_is_read_only(bs) && !(bdrv_get_flags(bs) & BDRV_O_INACTIVE); | ||
34 | + | ||
35 | /* If there are any driver level actions to take */ | ||
36 | if (drv->bdrv_reopen_commit) { | ||
37 | drv->bdrv_reopen_commit(reopen_state); | ||
38 | @@ -XXX,XX +XXX,XX @@ void bdrv_reopen_commit(BDRVReopenState *reopen_state) | ||
39 | bs->read_only = !(reopen_state->flags & BDRV_O_RDWR); | ||
40 | |||
41 | bdrv_refresh_limits(bs, NULL); | ||
42 | + | ||
43 | + new_can_write = | ||
44 | + !bdrv_is_read_only(bs) && !(bdrv_get_flags(bs) & BDRV_O_INACTIVE); | ||
45 | + if (!old_can_write && new_can_write && drv->bdrv_reopen_bitmaps_rw) { | ||
46 | + Error *local_err = NULL; | ||
47 | + if (drv->bdrv_reopen_bitmaps_rw(bs, &local_err) < 0) { | ||
48 | + /* This is not fatal, bitmaps just left read-only, so all following | ||
49 | + * writes will fail. User can remove read-only bitmaps to unblock | ||
50 | + * writes. | ||
51 | + */ | ||
52 | + error_reportf_err(local_err, | ||
53 | + "%s: Failed to make dirty bitmaps writable: ", | ||
54 | + bdrv_get_node_name(bs)); | ||
55 | + } | ||
56 | + } | ||
57 | } | ||
58 | |||
59 | /* | ||
60 | diff --git a/include/block/block_int.h b/include/block/block_int.h | ||
61 | index XXXXXXX..XXXXXXX 100644 | ||
62 | --- a/include/block/block_int.h | ||
63 | +++ b/include/block/block_int.h | ||
64 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { | ||
65 | uint64_t parent_perm, uint64_t parent_shared, | ||
66 | uint64_t *nperm, uint64_t *nshared); | ||
67 | |||
68 | + /** | 24 | + /** |
69 | + * Bitmaps should be marked as 'IN_USE' in the image on reopening image | 25 | + * The completion function that will be called when the job completes. |
70 | + * as rw. This handler should realize it. It also should unset readonly | 26 | + * Called with AioContext lock held, since many callback implementations |
71 | + * field of BlockDirtyBitmap's in case of success. | 27 | + * use bdrv_* functions that require to hold the lock. |
72 | + */ | 28 | + */ |
73 | + int (*bdrv_reopen_bitmaps_rw)(BlockDriverState *bs, Error **errp); | 29 | BlockCompletionFunc *cb; |
74 | + | 30 | |
75 | QLIST_ENTRY(BlockDriver) list; | 31 | /** The opaque value that is passed to the completion function. */ |
32 | @@ -XXX,XX +XXX,XX @@ struct JobDriver { | ||
33 | * | ||
34 | * This callback will not be invoked if the job has already failed. | ||
35 | * If it fails, abort and then clean will be called. | ||
36 | + * | ||
37 | + * Called with AioContext lock held, since many callbacs implementations | ||
38 | + * use bdrv_* functions that require to hold the lock. | ||
39 | */ | ||
40 | int (*prepare)(Job *job); | ||
41 | |||
42 | @@ -XXX,XX +XXX,XX @@ struct JobDriver { | ||
43 | * | ||
44 | * All jobs will complete with a call to either .commit() or .abort() but | ||
45 | * never both. | ||
46 | + * | ||
47 | + * Called with AioContext lock held, since many callback implementations | ||
48 | + * use bdrv_* functions that require to hold the lock. | ||
49 | */ | ||
50 | void (*commit)(Job *job); | ||
51 | |||
52 | @@ -XXX,XX +XXX,XX @@ struct JobDriver { | ||
53 | * | ||
54 | * All jobs will complete with a call to either .commit() or .abort() but | ||
55 | * never both. | ||
56 | + * | ||
57 | + * Called with AioContext lock held, since many callback implementations | ||
58 | + * use bdrv_* functions that require to hold the lock. | ||
59 | */ | ||
60 | void (*abort)(Job *job); | ||
61 | |||
62 | @@ -XXX,XX +XXX,XX @@ struct JobDriver { | ||
63 | * .commit() or .abort(). Regardless of which callback is invoked after | ||
64 | * completion, .clean() will always be called, even if the job does not | ||
65 | * belong to a transaction group. | ||
66 | + * | ||
67 | + * Called with AioContext lock held, since many callbacs implementations | ||
68 | + * use bdrv_* functions that require to hold the lock. | ||
69 | */ | ||
70 | void (*clean)(Job *job); | ||
71 | |||
72 | @@ -XXX,XX +XXX,XX @@ struct JobDriver { | ||
73 | * READY). | ||
74 | * (If the callback is NULL, the job is assumed to terminate | ||
75 | * without I/O.) | ||
76 | + * | ||
77 | + * Called with AioContext lock held, since many callback implementations | ||
78 | + * use bdrv_* functions that require to hold the lock. | ||
79 | */ | ||
80 | bool (*cancel)(Job *job, bool force); | ||
81 | |||
82 | |||
83 | - /** Called when the job is freed */ | ||
84 | + /** | ||
85 | + * Called when the job is freed. | ||
86 | + * Called with AioContext lock held, since many callback implementations | ||
87 | + * use bdrv_* functions that require to hold the lock. | ||
88 | + */ | ||
89 | void (*free)(Job *job); | ||
76 | }; | 90 | }; |
77 | 91 | ||
78 | -- | 92 | -- |
79 | 1.8.3.1 | 93 | 2.37.3 |
80 | |||
81 | diff view generated by jsdifflib |
1 | From: Eric Blake <eblake@redhat.com> | 1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | We are gradually moving away from sector-based interfaces, towards | 3 | Change the job_{lock/unlock} and macros to use job_mutex. |
4 | byte-based. In the common case, allocation is unlikely to ever use | ||
5 | values that are not naturally sector-aligned, but it is possible | ||
6 | that byte-based values will let us be more precise about allocation | ||
7 | at the end of an unaligned file that can do byte-based access. | ||
8 | 4 | ||
9 | Changing the signature of the function to use int64_t *pnum ensures | 5 | Now that they are not nop anymore, remove the aiocontext |
10 | that the compiler enforces that all callers are updated. For now, | 6 | to avoid deadlocks. |
11 | the io.c layer still assert()s that all callers are sector-aligned, | ||
12 | but that can be relaxed when a later patch implements byte-based | ||
13 | block status. Therefore, for the most part this patch is just the | ||
14 | addition of scaling at the callers followed by inverse scaling at | ||
15 | bdrv_is_allocated(). But some code, particularly stream_run(), | ||
16 | gets a lot simpler because it no longer has to mess with sectors. | ||
17 | Leave comments where we can further simplify by switching to | ||
18 | byte-based iterations, once later patches eliminate the need for | ||
19 | sector-aligned operations. | ||
20 | 7 | ||
21 | For ease of review, bdrv_is_allocated() was tackled separately. | 8 | Therefore: |
9 | - when possible, remove completely the aiocontext lock/unlock pair | ||
10 | - if it is used by some other function too, reduce the locking | ||
11 | section as much as possible, leaving the job API outside. | ||
12 | - change AIO_WAIT_WHILE in AIO_WAIT_WHILE_UNLOCKED, since we | ||
13 | are not using the aiocontext lock anymore | ||
22 | 14 | ||
23 | Signed-off-by: Eric Blake <eblake@redhat.com> | 15 | The only functions that still need the aiocontext lock are: |
16 | - the JobDriver callbacks, already documented in job.h | ||
17 | - job_cancel_sync() in replication.c is called with aio_context_lock | ||
18 | taken, but now job is using AIO_WAIT_WHILE_UNLOCKED so we need to | ||
19 | release the lock. | ||
20 | |||
21 | Reduce the locking section to only cover the callback invocation | ||
22 | and document the functions that take the AioContext lock, | ||
23 | to avoid taking it twice. | ||
24 | |||
25 | Also remove real_job_{lock/unlock}, as they are replaced by the | ||
26 | public functions. | ||
27 | |||
28 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
29 | Message-Id: <20220926093214.506243-19-eesposit@redhat.com> | ||
30 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
31 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> | ||
24 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 32 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
25 | --- | 33 | --- |
26 | block/commit.c | 20 ++++++++------------ | 34 | include/qemu/job.h | 17 ++--- |
27 | block/io.c | 38 ++++++++++++++++++-------------------- | 35 | block/replication.c | 2 + |
28 | block/mirror.c | 8 +++++++- | 36 | blockdev.c | 72 +++----------------- |
29 | block/replication.c | 17 ++++++++++++----- | 37 | job-qmp.c | 46 +++---------- |
30 | block/stream.c | 23 +++++++++-------------- | 38 | job.c | 111 +++++++++---------------------- |
31 | include/block/block.h | 2 +- | 39 | qemu-img.c | 2 - |
32 | qemu-img.c | 13 ++++++++++--- | 40 | tests/unit/test-bdrv-drain.c | 4 +- |
33 | 7 files changed, 65 insertions(+), 56 deletions(-) | 41 | tests/unit/test-block-iothread.c | 2 +- |
42 | tests/unit/test-blockjob.c | 19 +++--- | ||
43 | 9 files changed, 72 insertions(+), 203 deletions(-) | ||
34 | 44 | ||
35 | diff --git a/block/commit.c b/block/commit.c | 45 | diff --git a/include/qemu/job.h b/include/qemu/job.h |
36 | index XXXXXXX..XXXXXXX 100644 | 46 | index XXXXXXX..XXXXXXX 100644 |
37 | --- a/block/commit.c | 47 | --- a/include/qemu/job.h |
38 | +++ b/block/commit.c | 48 | +++ b/include/qemu/job.h |
39 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn commit_run(void *opaque) | 49 | @@ -XXX,XX +XXX,XX @@ typedef struct Job { |
40 | int64_t offset; | 50 | AioContext *aio_context; |
41 | uint64_t delay_ns = 0; | 51 | |
42 | int ret = 0; | 52 | |
43 | - int n = 0; /* sectors */ | 53 | - /** Protected by AioContext lock */ |
44 | + int64_t n = 0; /* bytes */ | 54 | + /** Protected by job_mutex */ |
45 | void *buf = NULL; | 55 | |
46 | int bytes_written = 0; | 56 | /** Reference count of the block job */ |
47 | int64_t base_len; | 57 | int refcnt; |
48 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn commit_run(void *opaque) | 58 | @@ -XXX,XX +XXX,XX @@ typedef struct Job { |
49 | 59 | /** | |
50 | buf = blk_blockalign(s->top, COMMIT_BUFFER_SIZE); | 60 | * Set to false by the job while the coroutine has yielded and may be |
51 | 61 | * re-entered by job_enter(). There may still be I/O or event loop activity | |
52 | - for (offset = 0; offset < s->common.len; offset += n * BDRV_SECTOR_SIZE) { | 62 | - * pending. Accessed under block_job_mutex (in blockjob.c). |
53 | + for (offset = 0; offset < s->common.len; offset += n) { | 63 | + * pending. Accessed under job_mutex. |
54 | bool copy; | 64 | * |
55 | 65 | * When the job is deferred to the main loop, busy is true as long as the | |
56 | /* Note that even when no rate limit is applied we need to yield | 66 | * bottom half is still pending. |
57 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn commit_run(void *opaque) | 67 | @@ -XXX,XX +XXX,XX @@ typedef enum JobCreateFlags { |
58 | } | 68 | |
59 | /* Copy if allocated above the base */ | 69 | extern QemuMutex job_mutex; |
60 | ret = bdrv_is_allocated_above(blk_bs(s->top), blk_bs(s->base), | 70 | |
61 | - offset / BDRV_SECTOR_SIZE, | 71 | -#define JOB_LOCK_GUARD() /* QEMU_LOCK_GUARD(&job_mutex) */ |
62 | - COMMIT_BUFFER_SIZE / BDRV_SECTOR_SIZE, | 72 | +#define JOB_LOCK_GUARD() QEMU_LOCK_GUARD(&job_mutex) |
63 | - &n); | 73 | |
64 | + offset, COMMIT_BUFFER_SIZE, &n); | 74 | -#define WITH_JOB_LOCK_GUARD() /* WITH_QEMU_LOCK_GUARD(&job_mutex) */ |
65 | copy = (ret == 1); | 75 | +#define WITH_JOB_LOCK_GUARD() WITH_QEMU_LOCK_GUARD(&job_mutex) |
66 | - trace_commit_one_iteration(s, offset, n * BDRV_SECTOR_SIZE, ret); | 76 | |
67 | + trace_commit_one_iteration(s, offset, n, ret); | 77 | /** |
68 | if (copy) { | 78 | * job_lock: |
69 | - ret = commit_populate(s->top, s->base, offset, | 79 | @@ -XXX,XX +XXX,XX @@ void job_ref_locked(Job *job); |
70 | - n * BDRV_SECTOR_SIZE, buf); | 80 | /** |
71 | - bytes_written += n * BDRV_SECTOR_SIZE; | 81 | * Release a reference that was previously acquired with job_ref() or |
72 | + ret = commit_populate(s->top, s->base, offset, n, buf); | 82 | * job_create(). If it's the last reference to the object, it will be freed. |
73 | + bytes_written += n; | 83 | + * |
74 | } | 84 | + * Takes AioContext lock internally to invoke a job->driver callback. |
75 | if (ret < 0) { | 85 | */ |
76 | BlockErrorAction action = | 86 | void job_unref(Job *job); |
77 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn commit_run(void *opaque) | 87 | |
78 | } | 88 | @@ -XXX,XX +XXX,XX @@ void job_user_cancel_locked(Job *job, bool force, Error **errp); |
79 | } | 89 | * Returns the return value from the job if the job actually completed |
80 | /* Publish progress */ | 90 | * during the call, or -ECANCELED if it was canceled. |
81 | - s->common.offset += n * BDRV_SECTOR_SIZE; | ||
82 | + s->common.offset += n; | ||
83 | |||
84 | if (copy && s->common.speed) { | ||
85 | - delay_ns = ratelimit_calculate_delay(&s->limit, | ||
86 | - n * BDRV_SECTOR_SIZE); | ||
87 | + delay_ns = ratelimit_calculate_delay(&s->limit, n); | ||
88 | } | ||
89 | } | ||
90 | |||
91 | diff --git a/block/io.c b/block/io.c | ||
92 | index XXXXXXX..XXXXXXX 100644 | ||
93 | --- a/block/io.c | ||
94 | +++ b/block/io.c | ||
95 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_is_allocated(BlockDriverState *bs, int64_t offset, | ||
96 | /* | ||
97 | * Given an image chain: ... -> [BASE] -> [INTER1] -> [INTER2] -> [TOP] | ||
98 | * | 91 | * |
99 | - * Return true if the given sector is allocated in any image between | 92 | - * Callers must hold the AioContext lock of job->aio_context. |
100 | - * BASE and TOP (inclusive). BASE can be NULL to check if the given | 93 | + * Called with job_lock *not* held. |
101 | - * sector is allocated in any image of the chain. Return false otherwise, | 94 | */ |
102 | + * Return true if (a prefix of) the given range is allocated in any image | 95 | int job_cancel_sync(Job *job, bool force); |
103 | + * between BASE and TOP (inclusive). BASE can be NULL to check if the given | 96 | |
104 | + * offset is allocated in any image of the chain. Return false otherwise, | 97 | @@ -XXX,XX +XXX,XX @@ void job_cancel_sync_all(void); |
105 | * or negative errno on failure. | 98 | * function). |
106 | * | 99 | * |
107 | - * 'pnum' is set to the number of sectors (including and immediately following | 100 | * Returns the return value from the job. |
108 | - * the specified sector) that are known to be in the same | 101 | - * |
109 | - * allocated/unallocated state. | 102 | - * Callers must hold the AioContext lock of job->aio_context. |
110 | + * 'pnum' is set to the number of bytes (including and immediately | 103 | + * Called with job_lock *not* held. |
111 | + * following the specified offset) that are known to be in the same | 104 | */ |
112 | + * allocated/unallocated state. Note that a subsequent call starting | 105 | int job_complete_sync(Job *job, Error **errp); |
113 | + * at 'offset + *pnum' may return the same allocation status (in other | 106 | |
114 | + * words, the result is not necessarily the maximum possible range); | 107 | @@ -XXX,XX +XXX,XX @@ void job_dismiss_locked(Job **job, Error **errp); |
115 | + * but 'pnum' will only be 0 when end of file is reached. | 108 | * Returns 0 if the job is successfully completed, -ECANCELED if the job was |
109 | * cancelled before completing, and -errno in other error cases. | ||
116 | * | 110 | * |
111 | - * Callers must hold the AioContext lock of job->aio_context. | ||
112 | + * Called with job_lock *not* held. | ||
117 | */ | 113 | */ |
118 | int bdrv_is_allocated_above(BlockDriverState *top, | 114 | int job_finish_sync(Job *job, void (*finish)(Job *, Error **errp), |
119 | BlockDriverState *base, | 115 | Error **errp); |
120 | - int64_t sector_num, | ||
121 | - int nb_sectors, int *pnum) | ||
122 | + int64_t offset, int64_t bytes, int64_t *pnum) | ||
123 | { | ||
124 | BlockDriverState *intermediate; | ||
125 | - int ret, n = nb_sectors; | ||
126 | + int ret; | ||
127 | + int64_t n = bytes; | ||
128 | |||
129 | intermediate = top; | ||
130 | while (intermediate && intermediate != base) { | ||
131 | int64_t pnum_inter; | ||
132 | int64_t size_inter; | ||
133 | - int psectors_inter; | ||
134 | |||
135 | - ret = bdrv_is_allocated(intermediate, sector_num * BDRV_SECTOR_SIZE, | ||
136 | - nb_sectors * BDRV_SECTOR_SIZE, | ||
137 | - &pnum_inter); | ||
138 | + ret = bdrv_is_allocated(intermediate, offset, bytes, &pnum_inter); | ||
139 | if (ret < 0) { | ||
140 | return ret; | ||
141 | } | ||
142 | - assert(pnum_inter < INT_MAX * BDRV_SECTOR_SIZE); | ||
143 | - psectors_inter = pnum_inter >> BDRV_SECTOR_BITS; | ||
144 | if (ret) { | ||
145 | - *pnum = psectors_inter; | ||
146 | + *pnum = pnum_inter; | ||
147 | return 1; | ||
148 | } | ||
149 | |||
150 | - size_inter = bdrv_nb_sectors(intermediate); | ||
151 | + size_inter = bdrv_getlength(intermediate); | ||
152 | if (size_inter < 0) { | ||
153 | return size_inter; | ||
154 | } | ||
155 | - if (n > psectors_inter && | ||
156 | - (intermediate == top || sector_num + psectors_inter < size_inter)) { | ||
157 | - n = psectors_inter; | ||
158 | + if (n > pnum_inter && | ||
159 | + (intermediate == top || offset + pnum_inter < size_inter)) { | ||
160 | + n = pnum_inter; | ||
161 | } | ||
162 | |||
163 | intermediate = backing_bs(intermediate); | ||
164 | diff --git a/block/mirror.c b/block/mirror.c | ||
165 | index XXXXXXX..XXXXXXX 100644 | ||
166 | --- a/block/mirror.c | ||
167 | +++ b/block/mirror.c | ||
168 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn mirror_dirty_init(MirrorBlockJob *s) | ||
169 | BlockDriverState *bs = s->source; | ||
170 | BlockDriverState *target_bs = blk_bs(s->target); | ||
171 | int ret, n; | ||
172 | + int64_t count; | ||
173 | |||
174 | end = s->bdev_length / BDRV_SECTOR_SIZE; | ||
175 | |||
176 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn mirror_dirty_init(MirrorBlockJob *s) | ||
177 | return 0; | ||
178 | } | ||
179 | |||
180 | - ret = bdrv_is_allocated_above(bs, base, sector_num, nb_sectors, &n); | ||
181 | + ret = bdrv_is_allocated_above(bs, base, sector_num * BDRV_SECTOR_SIZE, | ||
182 | + nb_sectors * BDRV_SECTOR_SIZE, &count); | ||
183 | if (ret < 0) { | ||
184 | return ret; | ||
185 | } | ||
186 | |||
187 | + /* TODO: Relax this once bdrv_is_allocated_above and dirty | ||
188 | + * bitmaps no longer require sector alignment. */ | ||
189 | + assert(QEMU_IS_ALIGNED(count, BDRV_SECTOR_SIZE)); | ||
190 | + n = count >> BDRV_SECTOR_BITS; | ||
191 | assert(n > 0); | ||
192 | if (ret == 1) { | ||
193 | bdrv_set_dirty_bitmap(s->dirty_bitmap, sector_num, n); | ||
194 | diff --git a/block/replication.c b/block/replication.c | 116 | diff --git a/block/replication.c b/block/replication.c |
195 | index XXXXXXX..XXXXXXX 100644 | 117 | index XXXXXXX..XXXXXXX 100644 |
196 | --- a/block/replication.c | 118 | --- a/block/replication.c |
197 | +++ b/block/replication.c | 119 | +++ b/block/replication.c |
198 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int replication_co_writev(BlockDriverState *bs, | 120 | @@ -XXX,XX +XXX,XX @@ static void replication_stop(ReplicationState *rs, bool failover, Error **errp) |
199 | BdrvChild *top = bs->file; | 121 | * disk, secondary disk in backup_job_completed(). |
200 | BdrvChild *base = s->secondary_disk; | 122 | */ |
201 | BdrvChild *target; | 123 | if (s->backup_job) { |
202 | - int ret, n; | 124 | + aio_context_release(aio_context); |
203 | + int ret; | 125 | job_cancel_sync(&s->backup_job->job, true); |
204 | + int64_t n; | 126 | + aio_context_acquire(aio_context); |
205 | 127 | } | |
206 | ret = replication_get_io_status(s); | 128 | |
207 | if (ret < 0) { | 129 | if (!failover) { |
208 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int replication_co_writev(BlockDriverState *bs, | 130 | diff --git a/blockdev.c b/blockdev.c |
131 | index XXXXXXX..XXXXXXX 100644 | ||
132 | --- a/blockdev.c | ||
133 | +++ b/blockdev.c | ||
134 | @@ -XXX,XX +XXX,XX @@ void blockdev_mark_auto_del(BlockBackend *blk) | ||
135 | for (job = block_job_next_locked(NULL); job; | ||
136 | job = block_job_next_locked(job)) { | ||
137 | if (block_job_has_bdrv(job, blk_bs(blk))) { | ||
138 | - AioContext *aio_context = job->job.aio_context; | ||
139 | - aio_context_acquire(aio_context); | ||
140 | - | ||
141 | job_cancel_locked(&job->job, false); | ||
142 | - | ||
143 | - aio_context_release(aio_context); | ||
144 | } | ||
145 | } | ||
146 | |||
147 | @@ -XXX,XX +XXX,XX @@ static void drive_backup_abort(BlkActionState *common) | ||
148 | DriveBackupState *state = DO_UPCAST(DriveBackupState, common, common); | ||
149 | |||
150 | if (state->job) { | ||
151 | - AioContext *aio_context; | ||
152 | - | ||
153 | - aio_context = bdrv_get_aio_context(state->bs); | ||
154 | - aio_context_acquire(aio_context); | ||
155 | - | ||
156 | job_cancel_sync(&state->job->job, true); | ||
157 | - | ||
158 | - aio_context_release(aio_context); | ||
159 | } | ||
160 | } | ||
161 | |||
162 | @@ -XXX,XX +XXX,XX @@ static void blockdev_backup_abort(BlkActionState *common) | ||
163 | BlockdevBackupState *state = DO_UPCAST(BlockdevBackupState, common, common); | ||
164 | |||
165 | if (state->job) { | ||
166 | - AioContext *aio_context; | ||
167 | - | ||
168 | - aio_context = bdrv_get_aio_context(state->bs); | ||
169 | - aio_context_acquire(aio_context); | ||
170 | - | ||
171 | job_cancel_sync(&state->job->job, true); | ||
172 | - | ||
173 | - aio_context_release(aio_context); | ||
174 | } | ||
175 | } | ||
176 | |||
177 | @@ -XXX,XX +XXX,XX @@ out: | ||
178 | } | ||
179 | |||
180 | /* | ||
181 | - * Get a block job using its ID and acquire its AioContext. | ||
182 | - * Called with job_mutex held. | ||
183 | + * Get a block job using its ID. Called with job_mutex held. | ||
184 | */ | ||
185 | -static BlockJob *find_block_job_locked(const char *id, | ||
186 | - AioContext **aio_context, | ||
187 | - Error **errp) | ||
188 | +static BlockJob *find_block_job_locked(const char *id, Error **errp) | ||
189 | { | ||
190 | BlockJob *job; | ||
191 | |||
192 | assert(id != NULL); | ||
193 | |||
194 | - *aio_context = NULL; | ||
195 | - | ||
196 | job = block_job_get_locked(id); | ||
197 | |||
198 | if (!job) { | ||
199 | @@ -XXX,XX +XXX,XX @@ static BlockJob *find_block_job_locked(const char *id, | ||
200 | return NULL; | ||
201 | } | ||
202 | |||
203 | - *aio_context = block_job_get_aio_context(job); | ||
204 | - aio_context_acquire(*aio_context); | ||
205 | - | ||
206 | return job; | ||
207 | } | ||
208 | |||
209 | void qmp_block_job_set_speed(const char *device, int64_t speed, Error **errp) | ||
210 | { | ||
211 | - AioContext *aio_context; | ||
212 | BlockJob *job; | ||
213 | |||
214 | JOB_LOCK_GUARD(); | ||
215 | - job = find_block_job_locked(device, &aio_context, errp); | ||
216 | + job = find_block_job_locked(device, errp); | ||
217 | |||
218 | if (!job) { | ||
219 | return; | ||
220 | } | ||
221 | |||
222 | block_job_set_speed_locked(job, speed, errp); | ||
223 | - aio_context_release(aio_context); | ||
224 | } | ||
225 | |||
226 | void qmp_block_job_cancel(const char *device, | ||
227 | bool has_force, bool force, Error **errp) | ||
228 | { | ||
229 | - AioContext *aio_context; | ||
230 | BlockJob *job; | ||
231 | |||
232 | JOB_LOCK_GUARD(); | ||
233 | - job = find_block_job_locked(device, &aio_context, errp); | ||
234 | + job = find_block_job_locked(device, errp); | ||
235 | |||
236 | if (!job) { | ||
237 | return; | ||
238 | @@ -XXX,XX +XXX,XX @@ void qmp_block_job_cancel(const char *device, | ||
239 | if (job_user_paused_locked(&job->job) && !force) { | ||
240 | error_setg(errp, "The block job for device '%s' is currently paused", | ||
241 | device); | ||
242 | - goto out; | ||
243 | + return; | ||
244 | } | ||
245 | |||
246 | trace_qmp_block_job_cancel(job); | ||
247 | job_user_cancel_locked(&job->job, force, errp); | ||
248 | -out: | ||
249 | - aio_context_release(aio_context); | ||
250 | } | ||
251 | |||
252 | void qmp_block_job_pause(const char *device, Error **errp) | ||
253 | { | ||
254 | - AioContext *aio_context; | ||
255 | BlockJob *job; | ||
256 | |||
257 | JOB_LOCK_GUARD(); | ||
258 | - job = find_block_job_locked(device, &aio_context, errp); | ||
259 | + job = find_block_job_locked(device, errp); | ||
260 | |||
261 | if (!job) { | ||
262 | return; | ||
263 | @@ -XXX,XX +XXX,XX @@ void qmp_block_job_pause(const char *device, Error **errp) | ||
264 | |||
265 | trace_qmp_block_job_pause(job); | ||
266 | job_user_pause_locked(&job->job, errp); | ||
267 | - aio_context_release(aio_context); | ||
268 | } | ||
269 | |||
270 | void qmp_block_job_resume(const char *device, Error **errp) | ||
271 | { | ||
272 | - AioContext *aio_context; | ||
273 | BlockJob *job; | ||
274 | |||
275 | JOB_LOCK_GUARD(); | ||
276 | - job = find_block_job_locked(device, &aio_context, errp); | ||
277 | + job = find_block_job_locked(device, errp); | ||
278 | |||
279 | if (!job) { | ||
280 | return; | ||
281 | @@ -XXX,XX +XXX,XX @@ void qmp_block_job_resume(const char *device, Error **errp) | ||
282 | |||
283 | trace_qmp_block_job_resume(job); | ||
284 | job_user_resume_locked(&job->job, errp); | ||
285 | - aio_context_release(aio_context); | ||
286 | } | ||
287 | |||
288 | void qmp_block_job_complete(const char *device, Error **errp) | ||
289 | { | ||
290 | - AioContext *aio_context; | ||
291 | BlockJob *job; | ||
292 | |||
293 | JOB_LOCK_GUARD(); | ||
294 | - job = find_block_job_locked(device, &aio_context, errp); | ||
295 | + job = find_block_job_locked(device, errp); | ||
296 | |||
297 | if (!job) { | ||
298 | return; | ||
299 | @@ -XXX,XX +XXX,XX @@ void qmp_block_job_complete(const char *device, Error **errp) | ||
300 | |||
301 | trace_qmp_block_job_complete(job); | ||
302 | job_complete_locked(&job->job, errp); | ||
303 | - aio_context_release(aio_context); | ||
304 | } | ||
305 | |||
306 | void qmp_block_job_finalize(const char *id, Error **errp) | ||
307 | { | ||
308 | - AioContext *aio_context; | ||
309 | BlockJob *job; | ||
310 | |||
311 | JOB_LOCK_GUARD(); | ||
312 | - job = find_block_job_locked(id, &aio_context, errp); | ||
313 | + job = find_block_job_locked(id, errp); | ||
314 | |||
315 | if (!job) { | ||
316 | return; | ||
317 | @@ -XXX,XX +XXX,XX @@ void qmp_block_job_finalize(const char *id, Error **errp) | ||
318 | job_ref_locked(&job->job); | ||
319 | job_finalize_locked(&job->job, errp); | ||
320 | |||
321 | - /* | ||
322 | - * Job's context might have changed via job_finalize (and job_txn_apply | ||
323 | - * automatically acquires the new one), so make sure we release the correct | ||
324 | - * one. | ||
325 | - */ | ||
326 | - aio_context = block_job_get_aio_context(job); | ||
327 | job_unref_locked(&job->job); | ||
328 | - aio_context_release(aio_context); | ||
329 | } | ||
330 | |||
331 | void qmp_block_job_dismiss(const char *id, Error **errp) | ||
332 | { | ||
333 | - AioContext *aio_context; | ||
334 | BlockJob *bjob; | ||
335 | Job *job; | ||
336 | |||
337 | JOB_LOCK_GUARD(); | ||
338 | - bjob = find_block_job_locked(id, &aio_context, errp); | ||
339 | + bjob = find_block_job_locked(id, errp); | ||
340 | |||
341 | if (!bjob) { | ||
342 | return; | ||
343 | @@ -XXX,XX +XXX,XX @@ void qmp_block_job_dismiss(const char *id, Error **errp) | ||
344 | trace_qmp_block_job_dismiss(bjob); | ||
345 | job = &bjob->job; | ||
346 | job_dismiss_locked(&job, errp); | ||
347 | - aio_context_release(aio_context); | ||
348 | } | ||
349 | |||
350 | void qmp_change_backing_file(const char *device, | ||
351 | @@ -XXX,XX +XXX,XX @@ BlockJobInfoList *qmp_query_block_jobs(Error **errp) | ||
352 | for (job = block_job_next_locked(NULL); job; | ||
353 | job = block_job_next_locked(job)) { | ||
354 | BlockJobInfo *value; | ||
355 | - AioContext *aio_context; | ||
356 | |||
357 | if (block_job_is_internal(job)) { | ||
358 | continue; | ||
359 | } | ||
360 | - aio_context = block_job_get_aio_context(job); | ||
361 | - aio_context_acquire(aio_context); | ||
362 | value = block_job_query_locked(job, errp); | ||
363 | - aio_context_release(aio_context); | ||
364 | if (!value) { | ||
365 | qapi_free_BlockJobInfoList(head); | ||
366 | return NULL; | ||
367 | diff --git a/job-qmp.c b/job-qmp.c | ||
368 | index XXXXXXX..XXXXXXX 100644 | ||
369 | --- a/job-qmp.c | ||
370 | +++ b/job-qmp.c | ||
371 | @@ -XXX,XX +XXX,XX @@ | ||
372 | #include "trace/trace-root.h" | ||
373 | |||
374 | /* | ||
375 | - * Get a job using its ID and acquire its AioContext. | ||
376 | - * Called with job_mutex held. | ||
377 | + * Get a job using its ID. Called with job_mutex held. | ||
378 | */ | ||
379 | -static Job *find_job_locked(const char *id, | ||
380 | - AioContext **aio_context, | ||
381 | - Error **errp) | ||
382 | +static Job *find_job_locked(const char *id, Error **errp) | ||
383 | { | ||
384 | Job *job; | ||
385 | |||
386 | - *aio_context = NULL; | ||
387 | - | ||
388 | job = job_get_locked(id); | ||
389 | if (!job) { | ||
390 | error_setg(errp, "Job not found"); | ||
391 | return NULL; | ||
392 | } | ||
393 | |||
394 | - *aio_context = job->aio_context; | ||
395 | - aio_context_acquire(*aio_context); | ||
396 | - | ||
397 | return job; | ||
398 | } | ||
399 | |||
400 | void qmp_job_cancel(const char *id, Error **errp) | ||
401 | { | ||
402 | - AioContext *aio_context; | ||
403 | Job *job; | ||
404 | |||
405 | JOB_LOCK_GUARD(); | ||
406 | - job = find_job_locked(id, &aio_context, errp); | ||
407 | + job = find_job_locked(id, errp); | ||
408 | |||
409 | if (!job) { | ||
410 | return; | ||
411 | @@ -XXX,XX +XXX,XX @@ void qmp_job_cancel(const char *id, Error **errp) | ||
412 | |||
413 | trace_qmp_job_cancel(job); | ||
414 | job_user_cancel_locked(job, true, errp); | ||
415 | - aio_context_release(aio_context); | ||
416 | } | ||
417 | |||
418 | void qmp_job_pause(const char *id, Error **errp) | ||
419 | { | ||
420 | - AioContext *aio_context; | ||
421 | Job *job; | ||
422 | |||
423 | JOB_LOCK_GUARD(); | ||
424 | - job = find_job_locked(id, &aio_context, errp); | ||
425 | + job = find_job_locked(id, errp); | ||
426 | |||
427 | if (!job) { | ||
428 | return; | ||
429 | @@ -XXX,XX +XXX,XX @@ void qmp_job_pause(const char *id, Error **errp) | ||
430 | |||
431 | trace_qmp_job_pause(job); | ||
432 | job_user_pause_locked(job, errp); | ||
433 | - aio_context_release(aio_context); | ||
434 | } | ||
435 | |||
436 | void qmp_job_resume(const char *id, Error **errp) | ||
437 | { | ||
438 | - AioContext *aio_context; | ||
439 | Job *job; | ||
440 | |||
441 | JOB_LOCK_GUARD(); | ||
442 | - job = find_job_locked(id, &aio_context, errp); | ||
443 | + job = find_job_locked(id, errp); | ||
444 | |||
445 | if (!job) { | ||
446 | return; | ||
447 | @@ -XXX,XX +XXX,XX @@ void qmp_job_resume(const char *id, Error **errp) | ||
448 | |||
449 | trace_qmp_job_resume(job); | ||
450 | job_user_resume_locked(job, errp); | ||
451 | - aio_context_release(aio_context); | ||
452 | } | ||
453 | |||
454 | void qmp_job_complete(const char *id, Error **errp) | ||
455 | { | ||
456 | - AioContext *aio_context; | ||
457 | Job *job; | ||
458 | |||
459 | JOB_LOCK_GUARD(); | ||
460 | - job = find_job_locked(id, &aio_context, errp); | ||
461 | + job = find_job_locked(id, errp); | ||
462 | |||
463 | if (!job) { | ||
464 | return; | ||
465 | @@ -XXX,XX +XXX,XX @@ void qmp_job_complete(const char *id, Error **errp) | ||
466 | |||
467 | trace_qmp_job_complete(job); | ||
468 | job_complete_locked(job, errp); | ||
469 | - aio_context_release(aio_context); | ||
470 | } | ||
471 | |||
472 | void qmp_job_finalize(const char *id, Error **errp) | ||
473 | { | ||
474 | - AioContext *aio_context; | ||
475 | Job *job; | ||
476 | |||
477 | JOB_LOCK_GUARD(); | ||
478 | - job = find_job_locked(id, &aio_context, errp); | ||
479 | + job = find_job_locked(id, errp); | ||
480 | |||
481 | if (!job) { | ||
482 | return; | ||
483 | @@ -XXX,XX +XXX,XX @@ void qmp_job_finalize(const char *id, Error **errp) | ||
484 | job_ref_locked(job); | ||
485 | job_finalize_locked(job, errp); | ||
486 | |||
487 | - /* | ||
488 | - * Job's context might have changed via job_finalize (and job_txn_apply | ||
489 | - * automatically acquires the new one), so make sure we release the correct | ||
490 | - * one. | ||
491 | - */ | ||
492 | - aio_context = job->aio_context; | ||
493 | job_unref_locked(job); | ||
494 | - aio_context_release(aio_context); | ||
495 | } | ||
496 | |||
497 | void qmp_job_dismiss(const char *id, Error **errp) | ||
498 | { | ||
499 | - AioContext *aio_context; | ||
500 | Job *job; | ||
501 | |||
502 | JOB_LOCK_GUARD(); | ||
503 | - job = find_job_locked(id, &aio_context, errp); | ||
504 | + job = find_job_locked(id, errp); | ||
505 | |||
506 | if (!job) { | ||
507 | return; | ||
508 | @@ -XXX,XX +XXX,XX @@ void qmp_job_dismiss(const char *id, Error **errp) | ||
509 | |||
510 | trace_qmp_job_dismiss(job); | ||
511 | job_dismiss_locked(&job, errp); | ||
512 | - aio_context_release(aio_context); | ||
513 | } | ||
514 | |||
515 | /* Called with job_mutex held. */ | ||
516 | @@ -XXX,XX +XXX,XX @@ JobInfoList *qmp_query_jobs(Error **errp) | ||
517 | |||
518 | for (job = job_next_locked(NULL); job; job = job_next_locked(job)) { | ||
519 | JobInfo *value; | ||
520 | - AioContext *aio_context; | ||
521 | |||
522 | if (job_is_internal(job)) { | ||
523 | continue; | ||
524 | } | ||
525 | - aio_context = job->aio_context; | ||
526 | - aio_context_acquire(aio_context); | ||
527 | value = job_query_single_locked(job, errp); | ||
528 | - aio_context_release(aio_context); | ||
529 | if (!value) { | ||
530 | qapi_free_JobInfoList(head); | ||
531 | return NULL; | ||
532 | diff --git a/job.c b/job.c | ||
533 | index XXXXXXX..XXXXXXX 100644 | ||
534 | --- a/job.c | ||
535 | +++ b/job.c | ||
536 | @@ -XXX,XX +XXX,XX @@ | ||
537 | * | ||
538 | * The second includes functions used by the job drivers and sometimes | ||
539 | * by the core block layer. These delegate the locking to the callee instead. | ||
540 | - * | ||
541 | - * TODO Actually make this true | ||
542 | */ | ||
543 | |||
544 | /* | ||
545 | @@ -XXX,XX +XXX,XX @@ struct JobTxn { | ||
546 | }; | ||
547 | |||
548 | void job_lock(void) | ||
549 | -{ | ||
550 | - /* nop */ | ||
551 | -} | ||
552 | - | ||
553 | -void job_unlock(void) | ||
554 | -{ | ||
555 | - /* nop */ | ||
556 | -} | ||
557 | - | ||
558 | -static void real_job_lock(void) | ||
559 | { | ||
560 | qemu_mutex_lock(&job_mutex); | ||
561 | } | ||
562 | |||
563 | -static void real_job_unlock(void) | ||
564 | +void job_unlock(void) | ||
565 | { | ||
566 | qemu_mutex_unlock(&job_mutex); | ||
567 | } | ||
568 | @@ -XXX,XX +XXX,XX @@ static void job_txn_del_job_locked(Job *job) | ||
569 | /* Called with job_mutex held, but releases it temporarily. */ | ||
570 | static int job_txn_apply_locked(Job *job, int fn(Job *)) | ||
571 | { | ||
572 | - AioContext *inner_ctx; | ||
573 | Job *other_job, *next; | ||
574 | JobTxn *txn = job->txn; | ||
575 | int rc = 0; | ||
576 | @@ -XXX,XX +XXX,XX @@ static int job_txn_apply_locked(Job *job, int fn(Job *)) | ||
577 | * break AIO_WAIT_WHILE from within fn. | ||
209 | */ | 578 | */ |
210 | qemu_iovec_init(&hd_qiov, qiov->niov); | 579 | job_ref_locked(job); |
211 | while (remaining_sectors > 0) { | 580 | - aio_context_release(job->aio_context); |
212 | - ret = bdrv_is_allocated_above(top->bs, base->bs, sector_num, | 581 | |
213 | - remaining_sectors, &n); | 582 | QLIST_FOREACH_SAFE(other_job, &txn->jobs, txn_list, next) { |
214 | + int64_t count; | 583 | - inner_ctx = other_job->aio_context; |
584 | - aio_context_acquire(inner_ctx); | ||
585 | rc = fn(other_job); | ||
586 | - aio_context_release(inner_ctx); | ||
587 | if (rc) { | ||
588 | break; | ||
589 | } | ||
590 | } | ||
591 | |||
592 | - /* | ||
593 | - * Note that job->aio_context might have been changed by calling fn, so we | ||
594 | - * can't use a local variable to cache it. | ||
595 | - */ | ||
596 | - aio_context_acquire(job->aio_context); | ||
597 | job_unref_locked(job); | ||
598 | return rc; | ||
599 | } | ||
600 | @@ -XXX,XX +XXX,XX @@ void job_unref_locked(Job *job) | ||
601 | assert(!job->txn); | ||
602 | |||
603 | if (job->driver->free) { | ||
604 | + AioContext *aio_context = job->aio_context; | ||
605 | job_unlock(); | ||
606 | + /* FIXME: aiocontext lock is required because cb calls blk_unref */ | ||
607 | + aio_context_acquire(aio_context); | ||
608 | job->driver->free(job); | ||
609 | + aio_context_release(aio_context); | ||
610 | job_lock(); | ||
611 | } | ||
612 | |||
613 | @@ -XXX,XX +XXX,XX @@ void job_enter_cond_locked(Job *job, bool(*fn)(Job *job)) | ||
614 | return; | ||
615 | } | ||
616 | |||
617 | - real_job_lock(); | ||
618 | if (job->busy) { | ||
619 | - real_job_unlock(); | ||
620 | return; | ||
621 | } | ||
622 | |||
623 | if (fn && !fn(job)) { | ||
624 | - real_job_unlock(); | ||
625 | return; | ||
626 | } | ||
627 | |||
628 | assert(!job->deferred_to_main_loop); | ||
629 | timer_del(&job->sleep_timer); | ||
630 | job->busy = true; | ||
631 | - real_job_unlock(); | ||
632 | job_unlock(); | ||
633 | aio_co_wake(job->co); | ||
634 | job_lock(); | ||
635 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn job_do_yield_locked(Job *job, uint64_t ns) | ||
636 | { | ||
637 | AioContext *next_aio_context; | ||
638 | |||
639 | - real_job_lock(); | ||
640 | if (ns != -1) { | ||
641 | timer_mod(&job->sleep_timer, ns); | ||
642 | } | ||
643 | job->busy = false; | ||
644 | job_event_idle_locked(job); | ||
645 | - real_job_unlock(); | ||
646 | job_unlock(); | ||
647 | qemu_coroutine_yield(); | ||
648 | job_lock(); | ||
649 | @@ -XXX,XX +XXX,XX @@ static void job_clean(Job *job) | ||
650 | } | ||
651 | } | ||
652 | |||
653 | -/* Called with job_mutex held, but releases it temporarily */ | ||
654 | +/* | ||
655 | + * Called with job_mutex held, but releases it temporarily. | ||
656 | + * Takes AioContext lock internally to invoke a job->driver callback. | ||
657 | + */ | ||
658 | static int job_finalize_single_locked(Job *job) | ||
659 | { | ||
660 | int job_ret; | ||
661 | + AioContext *ctx = job->aio_context; | ||
662 | |||
663 | assert(job_is_completed_locked(job)); | ||
664 | |||
665 | @@ -XXX,XX +XXX,XX @@ static int job_finalize_single_locked(Job *job) | ||
666 | |||
667 | job_ret = job->ret; | ||
668 | job_unlock(); | ||
669 | + aio_context_acquire(ctx); | ||
670 | |||
671 | if (!job_ret) { | ||
672 | job_commit(job); | ||
673 | @@ -XXX,XX +XXX,XX @@ static int job_finalize_single_locked(Job *job) | ||
674 | } | ||
675 | job_clean(job); | ||
676 | |||
677 | - job_lock(); | ||
678 | - | ||
679 | if (job->cb) { | ||
680 | - job_ret = job->ret; | ||
681 | - job_unlock(); | ||
682 | job->cb(job->opaque, job_ret); | ||
683 | - job_lock(); | ||
684 | } | ||
685 | |||
686 | + aio_context_release(ctx); | ||
687 | + job_lock(); | ||
215 | + | 688 | + |
216 | + ret = bdrv_is_allocated_above(top->bs, base->bs, | 689 | /* Emit events only if we actually started */ |
217 | + sector_num * BDRV_SECTOR_SIZE, | 690 | if (job_started_locked(job)) { |
218 | + remaining_sectors * BDRV_SECTOR_SIZE, | 691 | if (job_is_cancelled_locked(job)) { |
219 | + &count); | 692 | @@ -XXX,XX +XXX,XX @@ static int job_finalize_single_locked(Job *job) |
220 | if (ret < 0) { | 693 | return 0; |
221 | goto out1; | 694 | } |
695 | |||
696 | -/* Called with job_mutex held, but releases it temporarily */ | ||
697 | +/* | ||
698 | + * Called with job_mutex held, but releases it temporarily. | ||
699 | + * Takes AioContext lock internally to invoke a job->driver callback. | ||
700 | + */ | ||
701 | static void job_cancel_async_locked(Job *job, bool force) | ||
702 | { | ||
703 | + AioContext *ctx = job->aio_context; | ||
704 | GLOBAL_STATE_CODE(); | ||
705 | if (job->driver->cancel) { | ||
706 | job_unlock(); | ||
707 | + aio_context_acquire(ctx); | ||
708 | force = job->driver->cancel(job, force); | ||
709 | + aio_context_release(ctx); | ||
710 | job_lock(); | ||
711 | } else { | ||
712 | /* No .cancel() means the job will behave as if force-cancelled */ | ||
713 | @@ -XXX,XX +XXX,XX @@ static void job_cancel_async_locked(Job *job, bool force) | ||
714 | } | ||
715 | } | ||
716 | |||
717 | -/* Called with job_mutex held, but releases it temporarily. */ | ||
718 | +/* | ||
719 | + * Called with job_mutex held, but releases it temporarily. | ||
720 | + * Takes AioContext lock internally to invoke a job->driver callback. | ||
721 | + */ | ||
722 | static void job_completed_txn_abort_locked(Job *job) | ||
723 | { | ||
724 | - AioContext *ctx; | ||
725 | JobTxn *txn = job->txn; | ||
726 | Job *other_job; | ||
727 | |||
728 | @@ -XXX,XX +XXX,XX @@ static void job_completed_txn_abort_locked(Job *job) | ||
729 | txn->aborting = true; | ||
730 | job_txn_ref_locked(txn); | ||
731 | |||
732 | - /* | ||
733 | - * We can only hold the single job's AioContext lock while calling | ||
734 | - * job_finalize_single() because the finalization callbacks can involve | ||
735 | - * calls of AIO_WAIT_WHILE(), which could deadlock otherwise. | ||
736 | - * Note that the job's AioContext may change when it is finalized. | ||
737 | - */ | ||
738 | job_ref_locked(job); | ||
739 | - aio_context_release(job->aio_context); | ||
740 | |||
741 | /* Other jobs are effectively cancelled by us, set the status for | ||
742 | * them; this job, however, may or may not be cancelled, depending | ||
743 | * on the caller, so leave it. */ | ||
744 | QLIST_FOREACH(other_job, &txn->jobs, txn_list) { | ||
745 | if (other_job != job) { | ||
746 | - ctx = other_job->aio_context; | ||
747 | - aio_context_acquire(ctx); | ||
748 | /* | ||
749 | * This is a transaction: If one job failed, no result will matter. | ||
750 | * Therefore, pass force=true to terminate all other jobs as quickly | ||
751 | * as possible. | ||
752 | */ | ||
753 | job_cancel_async_locked(other_job, true); | ||
754 | - aio_context_release(ctx); | ||
222 | } | 755 | } |
223 | 756 | } | |
224 | + assert(QEMU_IS_ALIGNED(count, BDRV_SECTOR_SIZE)); | 757 | while (!QLIST_EMPTY(&txn->jobs)) { |
225 | + n = count >> BDRV_SECTOR_BITS; | 758 | other_job = QLIST_FIRST(&txn->jobs); |
226 | qemu_iovec_reset(&hd_qiov); | 759 | - /* |
227 | - qemu_iovec_concat(&hd_qiov, qiov, bytes_done, n * BDRV_SECTOR_SIZE); | 760 | - * The job's AioContext may change, so store it in @ctx so we |
228 | + qemu_iovec_concat(&hd_qiov, qiov, bytes_done, count); | 761 | - * release the same context that we have acquired before. |
229 | 762 | - */ | |
230 | target = ret ? top : base; | 763 | - ctx = other_job->aio_context; |
231 | ret = bdrv_co_writev(target, sector_num, n, &hd_qiov); | 764 | - aio_context_acquire(ctx); |
232 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int replication_co_writev(BlockDriverState *bs, | 765 | if (!job_is_completed_locked(other_job)) { |
233 | 766 | assert(job_cancel_requested_locked(other_job)); | |
234 | remaining_sectors -= n; | 767 | job_finish_sync_locked(other_job, NULL, NULL); |
235 | sector_num += n; | ||
236 | - bytes_done += n * BDRV_SECTOR_SIZE; | ||
237 | + bytes_done += count; | ||
238 | } | ||
239 | |||
240 | out1: | ||
241 | diff --git a/block/stream.c b/block/stream.c | ||
242 | index XXXXXXX..XXXXXXX 100644 | ||
243 | --- a/block/stream.c | ||
244 | +++ b/block/stream.c | ||
245 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn stream_run(void *opaque) | ||
246 | uint64_t delay_ns = 0; | ||
247 | int error = 0; | ||
248 | int ret = 0; | ||
249 | - int n = 0; /* sectors */ | ||
250 | + int64_t n = 0; /* bytes */ | ||
251 | void *buf; | ||
252 | |||
253 | if (!bs->backing) { | ||
254 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn stream_run(void *opaque) | ||
255 | bdrv_enable_copy_on_read(bs); | ||
256 | } | ||
257 | |||
258 | - for ( ; offset < s->common.len; offset += n * BDRV_SECTOR_SIZE) { | ||
259 | + for ( ; offset < s->common.len; offset += n) { | ||
260 | bool copy; | ||
261 | - int64_t count = 0; | ||
262 | |||
263 | /* Note that even when no rate limit is applied we need to yield | ||
264 | * with no pending I/O here so that bdrv_drain_all() returns. | ||
265 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn stream_run(void *opaque) | ||
266 | |||
267 | copy = false; | ||
268 | |||
269 | - ret = bdrv_is_allocated(bs, offset, STREAM_BUFFER_SIZE, &count); | ||
270 | - /* TODO relax this once bdrv_is_allocated does not enforce sectors */ | ||
271 | - assert(QEMU_IS_ALIGNED(count, BDRV_SECTOR_SIZE)); | ||
272 | - n = count >> BDRV_SECTOR_BITS; | ||
273 | + ret = bdrv_is_allocated(bs, offset, STREAM_BUFFER_SIZE, &n); | ||
274 | if (ret == 1) { | ||
275 | /* Allocated in the top, no need to copy. */ | ||
276 | } else if (ret >= 0) { | ||
277 | /* Copy if allocated in the intermediate images. Limit to the | ||
278 | * known-unallocated area [offset, offset+n*BDRV_SECTOR_SIZE). */ | ||
279 | ret = bdrv_is_allocated_above(backing_bs(bs), base, | ||
280 | - offset / BDRV_SECTOR_SIZE, n, &n); | ||
281 | + offset, n, &n); | ||
282 | |||
283 | /* Finish early if end of backing file has been reached */ | ||
284 | if (ret == 0 && n == 0) { | ||
285 | - n = (s->common.len - offset) / BDRV_SECTOR_SIZE; | ||
286 | + n = s->common.len - offset; | ||
287 | } | ||
288 | |||
289 | copy = (ret == 1); | ||
290 | } | 768 | } |
291 | - trace_stream_one_iteration(s, offset, n * BDRV_SECTOR_SIZE, ret); | 769 | job_finalize_single_locked(other_job); |
292 | + trace_stream_one_iteration(s, offset, n, ret); | 770 | - aio_context_release(ctx); |
293 | if (copy) { | 771 | } |
294 | - ret = stream_populate(blk, offset, n * BDRV_SECTOR_SIZE, buf); | 772 | |
295 | + ret = stream_populate(blk, offset, n, buf); | 773 | - /* |
296 | } | 774 | - * Use job_ref()/job_unref() so we can read the AioContext here |
297 | if (ret < 0) { | 775 | - * even if the job went away during job_finalize_single(). |
298 | BlockErrorAction action = | 776 | - */ |
299 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn stream_run(void *opaque) | 777 | - aio_context_acquire(job->aio_context); |
300 | ret = 0; | 778 | job_unref_locked(job); |
301 | 779 | - | |
302 | /* Publish progress */ | 780 | job_txn_unref_locked(txn); |
303 | - s->common.offset += n * BDRV_SECTOR_SIZE; | 781 | } |
304 | + s->common.offset += n; | 782 | |
305 | if (copy && s->common.speed) { | 783 | @@ -XXX,XX +XXX,XX @@ static void job_completed_txn_abort_locked(Job *job) |
306 | - delay_ns = ratelimit_calculate_delay(&s->limit, | 784 | static int job_prepare_locked(Job *job) |
307 | - n * BDRV_SECTOR_SIZE); | 785 | { |
308 | + delay_ns = ratelimit_calculate_delay(&s->limit, n); | 786 | int ret; |
309 | } | 787 | + AioContext *ctx = job->aio_context; |
310 | } | 788 | |
311 | 789 | GLOBAL_STATE_CODE(); | |
312 | diff --git a/include/block/block.h b/include/block/block.h | 790 | + |
313 | index XXXXXXX..XXXXXXX 100644 | 791 | if (job->ret == 0 && job->driver->prepare) { |
314 | --- a/include/block/block.h | 792 | job_unlock(); |
315 | +++ b/include/block/block.h | 793 | + aio_context_acquire(ctx); |
316 | @@ -XXX,XX +XXX,XX @@ int64_t bdrv_get_block_status_above(BlockDriverState *bs, | 794 | ret = job->driver->prepare(job); |
317 | int bdrv_is_allocated(BlockDriverState *bs, int64_t offset, int64_t bytes, | 795 | + aio_context_release(ctx); |
318 | int64_t *pnum); | 796 | job_lock(); |
319 | int bdrv_is_allocated_above(BlockDriverState *top, BlockDriverState *base, | 797 | job->ret = ret; |
320 | - int64_t sector_num, int nb_sectors, int *pnum); | 798 | job_update_rc_locked(job); |
321 | + int64_t offset, int64_t bytes, int64_t *pnum); | 799 | } |
322 | 800 | + | |
323 | bool bdrv_is_read_only(BlockDriverState *bs); | 801 | return job->ret; |
324 | bool bdrv_is_writable(BlockDriverState *bs); | 802 | } |
803 | |||
804 | @@ -XXX,XX +XXX,XX @@ static void job_completed_locked(Job *job) | ||
805 | static void job_exit(void *opaque) | ||
806 | { | ||
807 | Job *job = (Job *)opaque; | ||
808 | - AioContext *ctx; | ||
809 | JOB_LOCK_GUARD(); | ||
810 | - | ||
811 | job_ref_locked(job); | ||
812 | - aio_context_acquire(job->aio_context); | ||
813 | |||
814 | /* This is a lie, we're not quiescent, but still doing the completion | ||
815 | * callbacks. However, completion callbacks tend to involve operations that | ||
816 | @@ -XXX,XX +XXX,XX @@ static void job_exit(void *opaque) | ||
817 | job_event_idle_locked(job); | ||
818 | |||
819 | job_completed_locked(job); | ||
820 | - | ||
821 | - /* | ||
822 | - * Note that calling job_completed can move the job to a different | ||
823 | - * aio_context, so we cannot cache from above. job_txn_apply takes care of | ||
824 | - * acquiring the new lock, and we ref/unref to avoid job_completed freeing | ||
825 | - * the job underneath us. | ||
826 | - */ | ||
827 | - ctx = job->aio_context; | ||
828 | job_unref_locked(job); | ||
829 | - aio_context_release(ctx); | ||
830 | } | ||
831 | |||
832 | /** | ||
833 | @@ -XXX,XX +XXX,XX @@ int job_cancel_sync(Job *job, bool force) | ||
834 | void job_cancel_sync_all(void) | ||
835 | { | ||
836 | Job *job; | ||
837 | - AioContext *aio_context; | ||
838 | JOB_LOCK_GUARD(); | ||
839 | |||
840 | while ((job = job_next_locked(NULL))) { | ||
841 | - aio_context = job->aio_context; | ||
842 | - aio_context_acquire(aio_context); | ||
843 | job_cancel_sync_locked(job, true); | ||
844 | - aio_context_release(aio_context); | ||
845 | } | ||
846 | } | ||
847 | |||
848 | @@ -XXX,XX +XXX,XX @@ int job_finish_sync_locked(Job *job, | ||
849 | } | ||
850 | |||
851 | job_unlock(); | ||
852 | - AIO_WAIT_WHILE(job->aio_context, | ||
853 | - (job_enter(job), !job_is_completed(job))); | ||
854 | + AIO_WAIT_WHILE_UNLOCKED(job->aio_context, | ||
855 | + (job_enter(job), !job_is_completed(job))); | ||
856 | job_lock(); | ||
857 | |||
858 | ret = (job_is_cancelled_locked(job) && job->ret == 0) | ||
325 | diff --git a/qemu-img.c b/qemu-img.c | 859 | diff --git a/qemu-img.c b/qemu-img.c |
326 | index XXXXXXX..XXXXXXX 100644 | 860 | index XXXXXXX..XXXXXXX 100644 |
327 | --- a/qemu-img.c | 861 | --- a/qemu-img.c |
328 | +++ b/qemu-img.c | 862 | +++ b/qemu-img.c |
329 | @@ -XXX,XX +XXX,XX @@ static int img_compare(int argc, char **argv) | 863 | @@ -XXX,XX +XXX,XX @@ static void run_block_job(BlockJob *job, Error **errp) |
330 | } | 864 | AioContext *aio_context = block_job_get_aio_context(job); |
331 | 865 | int ret = 0; | |
332 | for (;;) { | 866 | |
333 | + int64_t count; | 867 | - aio_context_acquire(aio_context); |
868 | job_lock(); | ||
869 | job_ref_locked(&job->job); | ||
870 | do { | ||
871 | @@ -XXX,XX +XXX,XX @@ static void run_block_job(BlockJob *job, Error **errp) | ||
872 | } | ||
873 | job_unref_locked(&job->job); | ||
874 | job_unlock(); | ||
875 | - aio_context_release(aio_context); | ||
876 | |||
877 | /* publish completion progress only when success */ | ||
878 | if (!ret) { | ||
879 | diff --git a/tests/unit/test-bdrv-drain.c b/tests/unit/test-bdrv-drain.c | ||
880 | index XXXXXXX..XXXXXXX 100644 | ||
881 | --- a/tests/unit/test-bdrv-drain.c | ||
882 | +++ b/tests/unit/test-bdrv-drain.c | ||
883 | @@ -XXX,XX +XXX,XX @@ static void test_blockjob_common_drain_node(enum drain_type drain_type, | ||
884 | tjob->prepare_ret = -EIO; | ||
885 | break; | ||
886 | } | ||
887 | + aio_context_release(ctx); | ||
888 | |||
889 | job_start(&job->job); | ||
890 | - aio_context_release(ctx); | ||
891 | |||
892 | if (use_iothread) { | ||
893 | /* job_co_entry() is run in the I/O thread, wait for the actual job | ||
894 | @@ -XXX,XX +XXX,XX @@ static void test_blockjob_common_drain_node(enum drain_type drain_type, | ||
895 | g_assert_true(job->job.busy); /* We're in qemu_co_sleep_ns() */ | ||
896 | } | ||
897 | |||
898 | - aio_context_acquire(ctx); | ||
899 | WITH_JOB_LOCK_GUARD() { | ||
900 | ret = job_complete_sync_locked(&job->job, &error_abort); | ||
901 | } | ||
902 | g_assert_cmpint(ret, ==, (result == TEST_JOB_SUCCESS ? 0 : -EIO)); | ||
903 | |||
904 | + aio_context_acquire(ctx); | ||
905 | if (use_iothread) { | ||
906 | blk_set_aio_context(blk_src, qemu_get_aio_context(), &error_abort); | ||
907 | assert(blk_get_aio_context(blk_target) == qemu_get_aio_context()); | ||
908 | diff --git a/tests/unit/test-block-iothread.c b/tests/unit/test-block-iothread.c | ||
909 | index XXXXXXX..XXXXXXX 100644 | ||
910 | --- a/tests/unit/test-block-iothread.c | ||
911 | +++ b/tests/unit/test-block-iothread.c | ||
912 | @@ -XXX,XX +XXX,XX @@ static void test_attach_blockjob(void) | ||
913 | aio_poll(qemu_get_aio_context(), false); | ||
914 | } | ||
915 | |||
916 | - aio_context_acquire(ctx); | ||
917 | WITH_JOB_LOCK_GUARD() { | ||
918 | job_complete_sync_locked(&tjob->common.job, &error_abort); | ||
919 | } | ||
920 | + aio_context_acquire(ctx); | ||
921 | blk_set_aio_context(blk, qemu_get_aio_context(), &error_abort); | ||
922 | aio_context_release(ctx); | ||
923 | |||
924 | diff --git a/tests/unit/test-blockjob.c b/tests/unit/test-blockjob.c | ||
925 | index XXXXXXX..XXXXXXX 100644 | ||
926 | --- a/tests/unit/test-blockjob.c | ||
927 | +++ b/tests/unit/test-blockjob.c | ||
928 | @@ -XXX,XX +XXX,XX @@ static void cancel_common(CancelJob *s) | ||
929 | BlockJob *job = &s->common; | ||
930 | BlockBackend *blk = s->blk; | ||
931 | JobStatus sts = job->job.status; | ||
932 | - AioContext *ctx; | ||
933 | - | ||
934 | - ctx = job->job.aio_context; | ||
935 | - aio_context_acquire(ctx); | ||
936 | + AioContext *ctx = job->job.aio_context; | ||
937 | |||
938 | job_cancel_sync(&job->job, true); | ||
939 | WITH_JOB_LOCK_GUARD() { | ||
940 | @@ -XXX,XX +XXX,XX @@ static void cancel_common(CancelJob *s) | ||
941 | assert(job->job.status == JOB_STATUS_NULL); | ||
942 | job_unref_locked(&job->job); | ||
943 | } | ||
944 | - destroy_blk(blk); | ||
945 | |||
946 | + aio_context_acquire(ctx); | ||
947 | + destroy_blk(blk); | ||
948 | aio_context_release(ctx); | ||
334 | + | 949 | + |
335 | nb_sectors = sectors_to_process(total_sectors_over, sector_num); | 950 | } |
336 | if (nb_sectors <= 0) { | 951 | |
337 | break; | 952 | static void test_cancel_created(void) |
338 | } | 953 | @@ -XXX,XX +XXX,XX @@ static void test_cancel_concluded(void) |
339 | - ret = bdrv_is_allocated_above(blk_bs(blk_over), NULL, sector_num, | 954 | aio_poll(qemu_get_aio_context(), true); |
340 | - nb_sectors, &pnum); | 955 | assert_job_status_is(job, JOB_STATUS_PENDING); |
341 | + ret = bdrv_is_allocated_above(blk_bs(blk_over), NULL, | 956 | |
342 | + sector_num * BDRV_SECTOR_SIZE, | 957 | - aio_context_acquire(job->aio_context); |
343 | + nb_sectors * BDRV_SECTOR_SIZE, | 958 | WITH_JOB_LOCK_GUARD() { |
344 | + &count); | 959 | job_finalize_locked(job, &error_abort); |
345 | if (ret < 0) { | 960 | + assert(job->status == JOB_STATUS_CONCLUDED); |
346 | ret = 3; | 961 | } |
347 | error_report("Sector allocation test failed for %s", | 962 | - aio_context_release(job->aio_context); |
348 | @@ -XXX,XX +XXX,XX @@ static int img_compare(int argc, char **argv) | 963 | - assert_job_status_is(job, JOB_STATUS_CONCLUDED); |
349 | goto out; | 964 | |
350 | 965 | cancel_common(s); | |
351 | } | 966 | } |
352 | - nb_sectors = pnum; | 967 | @@ -XXX,XX +XXX,XX @@ static void test_complete_in_standby(void) |
353 | + /* TODO relax this once bdrv_is_allocated_above does not enforce | 968 | |
354 | + * sector alignment */ | 969 | /* Wait for the job to become READY */ |
355 | + assert(QEMU_IS_ALIGNED(count, BDRV_SECTOR_SIZE)); | 970 | job_start(job); |
356 | + nb_sectors = count >> BDRV_SECTOR_BITS; | 971 | - aio_context_acquire(ctx); |
357 | if (ret) { | 972 | /* |
358 | ret = check_empty_sectors(blk_over, sector_num, nb_sectors, | 973 | * Here we are waiting for the status to change, so don't bother |
359 | filename_over, buf1, quiet); | 974 | * protecting the read every time. |
975 | */ | ||
976 | - AIO_WAIT_WHILE(ctx, job->status != JOB_STATUS_READY); | ||
977 | - aio_context_release(ctx); | ||
978 | + AIO_WAIT_WHILE_UNLOCKED(ctx, job->status != JOB_STATUS_READY); | ||
979 | |||
980 | /* Begin the drained section, pausing the job */ | ||
981 | bdrv_drain_all_begin(); | ||
982 | @@ -XXX,XX +XXX,XX @@ static void test_complete_in_standby(void) | ||
983 | aio_context_acquire(ctx); | ||
984 | /* This will schedule the job to resume it */ | ||
985 | bdrv_drain_all_end(); | ||
986 | + aio_context_release(ctx); | ||
987 | |||
988 | WITH_JOB_LOCK_GUARD() { | ||
989 | /* But the job cannot run, so it will remain on standby */ | ||
990 | @@ -XXX,XX +XXX,XX @@ static void test_complete_in_standby(void) | ||
991 | job_dismiss_locked(&job, &error_abort); | ||
992 | } | ||
993 | |||
994 | + aio_context_acquire(ctx); | ||
995 | destroy_blk(blk); | ||
996 | aio_context_release(ctx); | ||
997 | iothread_join(iothread); | ||
360 | -- | 998 | -- |
361 | 1.8.3.1 | 999 | 2.37.3 |
362 | |||
363 | diff view generated by jsdifflib |
1 | From: Hervé Poussineau <hpoussin@reactos.org> | 1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | According to specification: | 3 | Not sure what the atomic here was supposed to do, since job.busy |
4 | "'MSWIN4.1' is the recommanded setting, because it is the setting least likely | 4 | is protected by the job lock. Since the whole function |
5 | to cause compatibility problems. If you want to put something else in here, | 5 | is called under job_mutex, just remove the atomic. |
6 | that is your option, but the result may be that some FAT drivers might not | ||
7 | recognize the volume." | ||
8 | 6 | ||
9 | Specification: "FAT: General overview of on-disk format" v1.03, page 9 | 7 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
10 | Signed-off-by: Hervé Poussineau <hpoussin@reactos.org> | 8 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> |
11 | Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org> | 9 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> |
10 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
11 | Message-Id: <20220926093214.506243-20-eesposit@redhat.com> | ||
12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
13 | --- | 13 | --- |
14 | block/vvfat.c | 2 +- | 14 | blockjob.c | 2 +- |
15 | 1 file changed, 1 insertion(+), 1 deletion(-) | 15 | 1 file changed, 1 insertion(+), 1 deletion(-) |
16 | 16 | ||
17 | diff --git a/block/vvfat.c b/block/vvfat.c | 17 | diff --git a/blockjob.c b/blockjob.c |
18 | index XXXXXXX..XXXXXXX 100644 | 18 | index XXXXXXX..XXXXXXX 100644 |
19 | --- a/block/vvfat.c | 19 | --- a/blockjob.c |
20 | +++ b/block/vvfat.c | 20 | +++ b/blockjob.c |
21 | @@ -XXX,XX +XXX,XX @@ static int init_directories(BDRVVVFATState* s, | 21 | @@ -XXX,XX +XXX,XX @@ BlockJobInfo *block_job_query_locked(BlockJob *job, Error **errp) |
22 | bootsector->jump[0]=0xeb; | 22 | info = g_new0(BlockJobInfo, 1); |
23 | bootsector->jump[1]=0x3e; | 23 | info->type = g_strdup(job_type_str(&job->job)); |
24 | bootsector->jump[2]=0x90; | 24 | info->device = g_strdup(job->job.id); |
25 | - memcpy(bootsector->name,"QEMU ",8); | 25 | - info->busy = qatomic_read(&job->job.busy); |
26 | + memcpy(bootsector->name, "MSWIN4.1", 8); | 26 | + info->busy = job->job.busy; |
27 | bootsector->sector_size=cpu_to_le16(0x200); | 27 | info->paused = job->job.pause_count > 0; |
28 | bootsector->sectors_per_cluster=s->sectors_per_cluster; | 28 | info->offset = progress_current; |
29 | bootsector->reserved_sectors=cpu_to_le16(1); | 29 | info->len = progress_total; |
30 | -- | 30 | -- |
31 | 1.8.3.1 | 31 | 2.37.3 |
32 | |||
33 | diff view generated by jsdifflib |
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Store persistent dirty bitmaps in qcow2 image. | 3 | These public functions are not used anywhere, thus can be dropped. |
4 | 4 | ||
5 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 5 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
6 | Reviewed-by: Max Reitz <mreitz@redhat.com> | 6 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> |
7 | Message-id: 20170628120530.31251-20-vsementsov@virtuozzo.com | 7 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> |
8 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 8 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> |
9 | Message-Id: <20220926093214.506243-21-eesposit@redhat.com> | ||
10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
9 | --- | 11 | --- |
10 | block/qcow2-bitmap.c | 475 +++++++++++++++++++++++++++++++++++++++++++++++++++ | 12 | include/block/blockjob.h | 31 ++++++++++++------------------- |
11 | block/qcow2.c | 9 + | 13 | blockjob.c | 16 ++-------------- |
12 | block/qcow2.h | 1 + | 14 | 2 files changed, 14 insertions(+), 33 deletions(-) |
13 | 3 files changed, 485 insertions(+) | ||
14 | 15 | ||
15 | diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c | 16 | diff --git a/include/block/blockjob.h b/include/block/blockjob.h |
16 | index XXXXXXX..XXXXXXX 100644 | 17 | index XXXXXXX..XXXXXXX 100644 |
17 | --- a/block/qcow2-bitmap.c | 18 | --- a/include/block/blockjob.h |
18 | +++ b/block/qcow2-bitmap.c | 19 | +++ b/include/block/blockjob.h |
19 | @@ -XXX,XX +XXX,XX @@ | 20 | @@ -XXX,XX +XXX,XX @@ typedef struct BlockJob { |
20 | 21 | */ | |
21 | #include "qemu/osdep.h" | 22 | |
22 | #include "qapi/error.h" | 23 | /** |
23 | +#include "qemu/cutils.h" | 24 | - * block_job_next: |
24 | 25 | + * block_job_next_locked: | |
25 | #include "block/block_int.h" | 26 | * @job: A block job, or %NULL. |
26 | #include "block/qcow2.h" | 27 | * |
27 | @@ -XXX,XX +XXX,XX @@ | 28 | * Get the next element from the list of block jobs after @job, or the |
28 | #define BME_MIN_GRANULARITY_BITS 9 | 29 | * first one if @job is %NULL. |
29 | #define BME_MAX_NAME_SIZE 1023 | 30 | * |
30 | 31 | * Returns the requested job, or %NULL if there are no more jobs left. | |
31 | +#if BME_MAX_TABLE_SIZE * 8ULL > INT_MAX | 32 | + * Called with job lock held. |
32 | +#error In the code bitmap table physical size assumed to fit into int | 33 | */ |
33 | +#endif | 34 | -BlockJob *block_job_next(BlockJob *job); |
34 | + | 35 | - |
35 | /* Bitmap directory entry flags */ | 36 | -/* Same as block_job_next(), but called with job lock held. */ |
36 | #define BME_RESERVED_FLAGS 0xfffffffcU | 37 | BlockJob *block_job_next_locked(BlockJob *job); |
37 | #define BME_FLAG_IN_USE (1U << 0) | 38 | |
38 | @@ -XXX,XX +XXX,XX @@ typedef struct Qcow2BitmapTable { | 39 | /** |
39 | uint32_t size; /* number of 64bit entries */ | 40 | @@ -XXX,XX +XXX,XX @@ BlockJob *block_job_next_locked(BlockJob *job); |
40 | QSIMPLEQ_ENTRY(Qcow2BitmapTable) entry; | 41 | * Get the block job identified by @id (which must not be %NULL). |
41 | } Qcow2BitmapTable; | 42 | * |
42 | +typedef QSIMPLEQ_HEAD(Qcow2BitmapTableList, Qcow2BitmapTable) | 43 | * Returns the requested job, or %NULL if it doesn't exist. |
43 | + Qcow2BitmapTableList; | 44 | + * Called with job lock *not* held. |
44 | 45 | */ | |
45 | typedef struct Qcow2Bitmap { | 46 | BlockJob *block_job_get(const char *id); |
46 | Qcow2BitmapTable table; | 47 | |
47 | @@ -XXX,XX +XXX,XX @@ typedef struct Qcow2Bitmap { | 48 | @@ -XXX,XX +XXX,XX @@ void block_job_remove_all_bdrv(BlockJob *job); |
48 | uint8_t granularity_bits; | 49 | bool block_job_has_bdrv(BlockJob *job, BlockDriverState *bs); |
49 | char *name; | 50 | |
50 | 51 | /** | |
51 | + BdrvDirtyBitmap *dirty_bitmap; | 52 | - * block_job_set_speed: |
52 | + | 53 | + * block_job_set_speed_locked: |
53 | QSIMPLEQ_ENTRY(Qcow2Bitmap) entry; | 54 | * @job: The job to set the speed for. |
54 | } Qcow2Bitmap; | 55 | * @speed: The new value |
55 | typedef QSIMPLEQ_HEAD(Qcow2BitmapList, Qcow2Bitmap) Qcow2BitmapList; | 56 | * @errp: Error object. |
56 | @@ -XXX,XX +XXX,XX @@ static int update_header_sync(BlockDriverState *bs) | 57 | * |
57 | return bdrv_flush(bs); | 58 | * Set a rate-limiting parameter for the job; the actual meaning may |
59 | * vary depending on the job type. | ||
60 | - */ | ||
61 | -bool block_job_set_speed(BlockJob *job, int64_t speed, Error **errp); | ||
62 | - | ||
63 | -/* | ||
64 | - * Same as block_job_set_speed(), but called with job lock held. | ||
65 | - * Might release the lock temporarily. | ||
66 | + * | ||
67 | + * Called with job lock held, but might release it temporarily. | ||
68 | */ | ||
69 | bool block_job_set_speed_locked(BlockJob *job, int64_t speed, Error **errp); | ||
70 | |||
71 | /** | ||
72 | - * block_job_query: | ||
73 | + * block_job_query_locked: | ||
74 | * @job: The job to get information about. | ||
75 | * | ||
76 | * Return information about a job. | ||
77 | + * | ||
78 | + * Called with job lock held. | ||
79 | */ | ||
80 | -BlockJobInfo *block_job_query(BlockJob *job, Error **errp); | ||
81 | - | ||
82 | -/* Same as block_job_query(), but called with job lock held. */ | ||
83 | BlockJobInfo *block_job_query_locked(BlockJob *job, Error **errp); | ||
84 | |||
85 | /** | ||
86 | - * block_job_iostatus_reset: | ||
87 | + * block_job_iostatus_reset_locked: | ||
88 | * @job: The job whose I/O status should be reset. | ||
89 | * | ||
90 | * Reset I/O status on @job and on BlockDriverState objects it uses, | ||
91 | * other than job->blk. | ||
92 | + * | ||
93 | + * Called with job lock held. | ||
94 | */ | ||
95 | -void block_job_iostatus_reset(BlockJob *job); | ||
96 | - | ||
97 | -/* Same as block_job_iostatus_reset(), but called with job lock held. */ | ||
98 | void block_job_iostatus_reset_locked(BlockJob *job); | ||
99 | |||
100 | /* | ||
101 | diff --git a/blockjob.c b/blockjob.c | ||
102 | index XXXXXXX..XXXXXXX 100644 | ||
103 | --- a/blockjob.c | ||
104 | +++ b/blockjob.c | ||
105 | @@ -XXX,XX +XXX,XX @@ BlockJob *block_job_next_locked(BlockJob *bjob) | ||
106 | return job ? container_of(job, BlockJob, job) : NULL; | ||
58 | } | 107 | } |
59 | 108 | ||
60 | +static inline void bitmap_table_to_be(uint64_t *bitmap_table, size_t size) | 109 | -BlockJob *block_job_next(BlockJob *bjob) |
61 | +{ | 110 | -{ |
62 | + size_t i; | 111 | - JOB_LOCK_GUARD(); |
63 | + | 112 | - return block_job_next_locked(bjob); |
64 | + for (i = 0; i < size; ++i) { | 113 | -} |
65 | + cpu_to_be64s(&bitmap_table[i]); | 114 | - |
66 | + } | 115 | BlockJob *block_job_get_locked(const char *id) |
67 | +} | ||
68 | + | ||
69 | static int check_table_entry(uint64_t entry, int cluster_size) | ||
70 | { | 116 | { |
71 | uint64_t offset; | 117 | Job *job = job_get_locked(id); |
72 | @@ -XXX,XX +XXX,XX @@ static int check_table_entry(uint64_t entry, int cluster_size) | 118 | @@ -XXX,XX +XXX,XX @@ bool block_job_set_speed_locked(BlockJob *job, int64_t speed, Error **errp) |
73 | return 0; | 119 | return true; |
74 | } | 120 | } |
75 | 121 | ||
76 | +static int check_constraints_on_bitmap(BlockDriverState *bs, | 122 | -bool block_job_set_speed(BlockJob *job, int64_t speed, Error **errp) |
77 | + const char *name, | 123 | +static bool block_job_set_speed(BlockJob *job, int64_t speed, Error **errp) |
78 | + uint32_t granularity, | ||
79 | + Error **errp) | ||
80 | +{ | ||
81 | + BDRVQcow2State *s = bs->opaque; | ||
82 | + int granularity_bits = ctz32(granularity); | ||
83 | + int64_t len = bdrv_getlength(bs); | ||
84 | + | ||
85 | + assert(granularity > 0); | ||
86 | + assert((granularity & (granularity - 1)) == 0); | ||
87 | + | ||
88 | + if (len < 0) { | ||
89 | + error_setg_errno(errp, -len, "Failed to get size of '%s'", | ||
90 | + bdrv_get_device_or_node_name(bs)); | ||
91 | + return len; | ||
92 | + } | ||
93 | + | ||
94 | + if (granularity_bits > BME_MAX_GRANULARITY_BITS) { | ||
95 | + error_setg(errp, "Granularity exceeds maximum (%llu bytes)", | ||
96 | + 1ULL << BME_MAX_GRANULARITY_BITS); | ||
97 | + return -EINVAL; | ||
98 | + } | ||
99 | + if (granularity_bits < BME_MIN_GRANULARITY_BITS) { | ||
100 | + error_setg(errp, "Granularity is under minimum (%llu bytes)", | ||
101 | + 1ULL << BME_MIN_GRANULARITY_BITS); | ||
102 | + return -EINVAL; | ||
103 | + } | ||
104 | + | ||
105 | + if ((len > (uint64_t)BME_MAX_PHYS_SIZE << granularity_bits) || | ||
106 | + (len > (uint64_t)BME_MAX_TABLE_SIZE * s->cluster_size << | ||
107 | + granularity_bits)) | ||
108 | + { | ||
109 | + error_setg(errp, "Too much space will be occupied by the bitmap. " | ||
110 | + "Use larger granularity"); | ||
111 | + return -EINVAL; | ||
112 | + } | ||
113 | + | ||
114 | + if (strlen(name) > BME_MAX_NAME_SIZE) { | ||
115 | + error_setg(errp, "Name length exceeds maximum (%u characters)", | ||
116 | + BME_MAX_NAME_SIZE); | ||
117 | + return -EINVAL; | ||
118 | + } | ||
119 | + | ||
120 | + return 0; | ||
121 | +} | ||
122 | + | ||
123 | +static void clear_bitmap_table(BlockDriverState *bs, uint64_t *bitmap_table, | ||
124 | + uint32_t bitmap_table_size) | ||
125 | +{ | ||
126 | + BDRVQcow2State *s = bs->opaque; | ||
127 | + int i; | ||
128 | + | ||
129 | + for (i = 0; i < bitmap_table_size; ++i) { | ||
130 | + uint64_t addr = bitmap_table[i] & BME_TABLE_ENTRY_OFFSET_MASK; | ||
131 | + if (!addr) { | ||
132 | + continue; | ||
133 | + } | ||
134 | + | ||
135 | + qcow2_free_clusters(bs, addr, s->cluster_size, QCOW2_DISCARD_OTHER); | ||
136 | + bitmap_table[i] = 0; | ||
137 | + } | ||
138 | +} | ||
139 | + | ||
140 | static int bitmap_table_load(BlockDriverState *bs, Qcow2BitmapTable *tb, | ||
141 | uint64_t **bitmap_table) | ||
142 | { | 124 | { |
143 | @@ -XXX,XX +XXX,XX @@ fail: | 125 | JOB_LOCK_GUARD(); |
144 | return ret; | 126 | return block_job_set_speed_locked(job, speed, errp); |
127 | @@ -XXX,XX +XXX,XX @@ BlockJobInfo *block_job_query_locked(BlockJob *job, Error **errp) | ||
128 | return info; | ||
145 | } | 129 | } |
146 | 130 | ||
147 | +static int free_bitmap_clusters(BlockDriverState *bs, Qcow2BitmapTable *tb) | 131 | -BlockJobInfo *block_job_query(BlockJob *job, Error **errp) |
148 | +{ | 132 | -{ |
149 | + int ret; | 133 | - JOB_LOCK_GUARD(); |
150 | + uint64_t *bitmap_table; | 134 | - return block_job_query_locked(job, errp); |
151 | + | 135 | -} |
152 | + ret = bitmap_table_load(bs, tb, &bitmap_table); | 136 | - |
153 | + if (ret < 0) { | 137 | /* Called with job lock held */ |
154 | + assert(bitmap_table == NULL); | 138 | static void block_job_iostatus_set_err_locked(BlockJob *job, int error) |
155 | + return ret; | 139 | { |
156 | + } | 140 | @@ -XXX,XX +XXX,XX @@ void block_job_iostatus_reset_locked(BlockJob *job) |
157 | + | 141 | job->iostatus = BLOCK_DEVICE_IO_STATUS_OK; |
158 | + clear_bitmap_table(bs, bitmap_table, tb->size); | ||
159 | + qcow2_free_clusters(bs, tb->offset, tb->size * sizeof(uint64_t), | ||
160 | + QCOW2_DISCARD_OTHER); | ||
161 | + g_free(bitmap_table); | ||
162 | + | ||
163 | + tb->offset = 0; | ||
164 | + tb->size = 0; | ||
165 | + | ||
166 | + return 0; | ||
167 | +} | ||
168 | + | ||
169 | /* This function returns the number of disk sectors covered by a single qcow2 | ||
170 | * cluster of bitmap data. */ | ||
171 | static uint64_t sectors_covered_by_bitmap_cluster(const BDRVQcow2State *s, | ||
172 | @@ -XXX,XX +XXX,XX @@ static int update_ext_header_and_dir_in_place(BlockDriverState *bs, | ||
173 | */ | ||
174 | } | 142 | } |
175 | 143 | ||
176 | +static int update_ext_header_and_dir(BlockDriverState *bs, | 144 | -void block_job_iostatus_reset(BlockJob *job) |
177 | + Qcow2BitmapList *bm_list) | 145 | +static void block_job_iostatus_reset(BlockJob *job) |
178 | +{ | ||
179 | + BDRVQcow2State *s = bs->opaque; | ||
180 | + int ret; | ||
181 | + uint64_t new_offset = 0; | ||
182 | + uint64_t new_size = 0; | ||
183 | + uint32_t new_nb_bitmaps = 0; | ||
184 | + uint64_t old_offset = s->bitmap_directory_offset; | ||
185 | + uint64_t old_size = s->bitmap_directory_size; | ||
186 | + uint32_t old_nb_bitmaps = s->nb_bitmaps; | ||
187 | + uint64_t old_autocl = s->autoclear_features; | ||
188 | + | ||
189 | + if (bm_list != NULL && !QSIMPLEQ_EMPTY(bm_list)) { | ||
190 | + new_nb_bitmaps = bitmap_list_count(bm_list); | ||
191 | + | ||
192 | + if (new_nb_bitmaps > QCOW2_MAX_BITMAPS) { | ||
193 | + return -EINVAL; | ||
194 | + } | ||
195 | + | ||
196 | + ret = bitmap_list_store(bs, bm_list, &new_offset, &new_size, false); | ||
197 | + if (ret < 0) { | ||
198 | + return ret; | ||
199 | + } | ||
200 | + | ||
201 | + ret = bdrv_flush(bs->file->bs); | ||
202 | + if (ret < 0) { | ||
203 | + goto fail; | ||
204 | + } | ||
205 | + | ||
206 | + s->autoclear_features |= QCOW2_AUTOCLEAR_BITMAPS; | ||
207 | + } else { | ||
208 | + s->autoclear_features &= ~(uint64_t)QCOW2_AUTOCLEAR_BITMAPS; | ||
209 | + } | ||
210 | + | ||
211 | + s->bitmap_directory_offset = new_offset; | ||
212 | + s->bitmap_directory_size = new_size; | ||
213 | + s->nb_bitmaps = new_nb_bitmaps; | ||
214 | + | ||
215 | + ret = update_header_sync(bs); | ||
216 | + if (ret < 0) { | ||
217 | + goto fail; | ||
218 | + } | ||
219 | + | ||
220 | + if (old_size > 0) { | ||
221 | + qcow2_free_clusters(bs, old_offset, old_size, QCOW2_DISCARD_OTHER); | ||
222 | + } | ||
223 | + | ||
224 | + return 0; | ||
225 | + | ||
226 | +fail: | ||
227 | + if (new_offset > 0) { | ||
228 | + qcow2_free_clusters(bs, new_offset, new_size, QCOW2_DISCARD_OTHER); | ||
229 | + } | ||
230 | + | ||
231 | + s->bitmap_directory_offset = old_offset; | ||
232 | + s->bitmap_directory_size = old_size; | ||
233 | + s->nb_bitmaps = old_nb_bitmaps; | ||
234 | + s->autoclear_features = old_autocl; | ||
235 | + | ||
236 | + return ret; | ||
237 | +} | ||
238 | + | ||
239 | /* for g_slist_foreach for GSList of BdrvDirtyBitmap* elements */ | ||
240 | static void release_dirty_bitmap_helper(gpointer bitmap, | ||
241 | gpointer bs) | ||
242 | @@ -XXX,XX +XXX,XX @@ out: | ||
243 | |||
244 | return ret; | ||
245 | } | ||
246 | + | ||
247 | +/* store_bitmap_data() | ||
248 | + * Store bitmap to image, filling bitmap table accordingly. | ||
249 | + */ | ||
250 | +static uint64_t *store_bitmap_data(BlockDriverState *bs, | ||
251 | + BdrvDirtyBitmap *bitmap, | ||
252 | + uint32_t *bitmap_table_size, Error **errp) | ||
253 | +{ | ||
254 | + int ret; | ||
255 | + BDRVQcow2State *s = bs->opaque; | ||
256 | + int64_t sector; | ||
257 | + uint64_t sbc; | ||
258 | + uint64_t bm_size = bdrv_dirty_bitmap_size(bitmap); | ||
259 | + const char *bm_name = bdrv_dirty_bitmap_name(bitmap); | ||
260 | + uint8_t *buf = NULL; | ||
261 | + BdrvDirtyBitmapIter *dbi; | ||
262 | + uint64_t *tb; | ||
263 | + uint64_t tb_size = | ||
264 | + size_to_clusters(s, | ||
265 | + bdrv_dirty_bitmap_serialization_size(bitmap, 0, bm_size)); | ||
266 | + | ||
267 | + if (tb_size > BME_MAX_TABLE_SIZE || | ||
268 | + tb_size * s->cluster_size > BME_MAX_PHYS_SIZE) | ||
269 | + { | ||
270 | + error_setg(errp, "Bitmap '%s' is too big", bm_name); | ||
271 | + return NULL; | ||
272 | + } | ||
273 | + | ||
274 | + tb = g_try_new0(uint64_t, tb_size); | ||
275 | + if (tb == NULL) { | ||
276 | + error_setg(errp, "No memory"); | ||
277 | + return NULL; | ||
278 | + } | ||
279 | + | ||
280 | + dbi = bdrv_dirty_iter_new(bitmap, 0); | ||
281 | + buf = g_malloc(s->cluster_size); | ||
282 | + sbc = sectors_covered_by_bitmap_cluster(s, bitmap); | ||
283 | + assert(DIV_ROUND_UP(bm_size, sbc) == tb_size); | ||
284 | + | ||
285 | + while ((sector = bdrv_dirty_iter_next(dbi)) != -1) { | ||
286 | + uint64_t cluster = sector / sbc; | ||
287 | + uint64_t end, write_size; | ||
288 | + int64_t off; | ||
289 | + | ||
290 | + sector = cluster * sbc; | ||
291 | + end = MIN(bm_size, sector + sbc); | ||
292 | + write_size = | ||
293 | + bdrv_dirty_bitmap_serialization_size(bitmap, sector, end - sector); | ||
294 | + assert(write_size <= s->cluster_size); | ||
295 | + | ||
296 | + off = qcow2_alloc_clusters(bs, s->cluster_size); | ||
297 | + if (off < 0) { | ||
298 | + error_setg_errno(errp, -off, | ||
299 | + "Failed to allocate clusters for bitmap '%s'", | ||
300 | + bm_name); | ||
301 | + goto fail; | ||
302 | + } | ||
303 | + tb[cluster] = off; | ||
304 | + | ||
305 | + bdrv_dirty_bitmap_serialize_part(bitmap, buf, sector, end - sector); | ||
306 | + if (write_size < s->cluster_size) { | ||
307 | + memset(buf + write_size, 0, s->cluster_size - write_size); | ||
308 | + } | ||
309 | + | ||
310 | + ret = qcow2_pre_write_overlap_check(bs, 0, off, s->cluster_size); | ||
311 | + if (ret < 0) { | ||
312 | + error_setg_errno(errp, -ret, "Qcow2 overlap check failed"); | ||
313 | + goto fail; | ||
314 | + } | ||
315 | + | ||
316 | + ret = bdrv_pwrite(bs->file, off, buf, s->cluster_size); | ||
317 | + if (ret < 0) { | ||
318 | + error_setg_errno(errp, -ret, "Failed to write bitmap '%s' to file", | ||
319 | + bm_name); | ||
320 | + goto fail; | ||
321 | + } | ||
322 | + | ||
323 | + if (end >= bm_size) { | ||
324 | + break; | ||
325 | + } | ||
326 | + | ||
327 | + bdrv_set_dirty_iter(dbi, end); | ||
328 | + } | ||
329 | + | ||
330 | + *bitmap_table_size = tb_size; | ||
331 | + g_free(buf); | ||
332 | + bdrv_dirty_iter_free(dbi); | ||
333 | + | ||
334 | + return tb; | ||
335 | + | ||
336 | +fail: | ||
337 | + clear_bitmap_table(bs, tb, tb_size); | ||
338 | + g_free(buf); | ||
339 | + bdrv_dirty_iter_free(dbi); | ||
340 | + g_free(tb); | ||
341 | + | ||
342 | + return NULL; | ||
343 | +} | ||
344 | + | ||
345 | +/* store_bitmap() | ||
346 | + * Store bm->dirty_bitmap to qcow2. | ||
347 | + * Set bm->table_offset and bm->table_size accordingly. | ||
348 | + */ | ||
349 | +static int store_bitmap(BlockDriverState *bs, Qcow2Bitmap *bm, Error **errp) | ||
350 | +{ | ||
351 | + int ret; | ||
352 | + uint64_t *tb; | ||
353 | + int64_t tb_offset; | ||
354 | + uint32_t tb_size; | ||
355 | + BdrvDirtyBitmap *bitmap = bm->dirty_bitmap; | ||
356 | + const char *bm_name; | ||
357 | + | ||
358 | + assert(bitmap != NULL); | ||
359 | + | ||
360 | + bm_name = bdrv_dirty_bitmap_name(bitmap); | ||
361 | + | ||
362 | + tb = store_bitmap_data(bs, bitmap, &tb_size, errp); | ||
363 | + if (tb == NULL) { | ||
364 | + return -EINVAL; | ||
365 | + } | ||
366 | + | ||
367 | + assert(tb_size <= BME_MAX_TABLE_SIZE); | ||
368 | + tb_offset = qcow2_alloc_clusters(bs, tb_size * sizeof(tb[0])); | ||
369 | + if (tb_offset < 0) { | ||
370 | + error_setg_errno(errp, -tb_offset, | ||
371 | + "Failed to allocate clusters for bitmap '%s'", | ||
372 | + bm_name); | ||
373 | + goto fail; | ||
374 | + } | ||
375 | + | ||
376 | + ret = qcow2_pre_write_overlap_check(bs, 0, tb_offset, | ||
377 | + tb_size * sizeof(tb[0])); | ||
378 | + if (ret < 0) { | ||
379 | + error_setg_errno(errp, -ret, "Qcow2 overlap check failed"); | ||
380 | + goto fail; | ||
381 | + } | ||
382 | + | ||
383 | + bitmap_table_to_be(tb, tb_size); | ||
384 | + ret = bdrv_pwrite(bs->file, tb_offset, tb, tb_size * sizeof(tb[0])); | ||
385 | + if (ret < 0) { | ||
386 | + error_setg_errno(errp, -ret, "Failed to write bitmap '%s' to file", | ||
387 | + bm_name); | ||
388 | + goto fail; | ||
389 | + } | ||
390 | + | ||
391 | + g_free(tb); | ||
392 | + | ||
393 | + bm->table.offset = tb_offset; | ||
394 | + bm->table.size = tb_size; | ||
395 | + | ||
396 | + return 0; | ||
397 | + | ||
398 | +fail: | ||
399 | + clear_bitmap_table(bs, tb, tb_size); | ||
400 | + | ||
401 | + if (tb_offset > 0) { | ||
402 | + qcow2_free_clusters(bs, tb_offset, tb_size * sizeof(tb[0]), | ||
403 | + QCOW2_DISCARD_OTHER); | ||
404 | + } | ||
405 | + | ||
406 | + g_free(tb); | ||
407 | + | ||
408 | + return ret; | ||
409 | +} | ||
410 | + | ||
411 | +static Qcow2Bitmap *find_bitmap_by_name(Qcow2BitmapList *bm_list, | ||
412 | + const char *name) | ||
413 | +{ | ||
414 | + Qcow2Bitmap *bm; | ||
415 | + | ||
416 | + QSIMPLEQ_FOREACH(bm, bm_list, entry) { | ||
417 | + if (strcmp(name, bm->name) == 0) { | ||
418 | + return bm; | ||
419 | + } | ||
420 | + } | ||
421 | + | ||
422 | + return NULL; | ||
423 | +} | ||
424 | + | ||
425 | +void qcow2_store_persistent_dirty_bitmaps(BlockDriverState *bs, Error **errp) | ||
426 | +{ | ||
427 | + BdrvDirtyBitmap *bitmap; | ||
428 | + BDRVQcow2State *s = bs->opaque; | ||
429 | + uint32_t new_nb_bitmaps = s->nb_bitmaps; | ||
430 | + uint64_t new_dir_size = s->bitmap_directory_size; | ||
431 | + int ret; | ||
432 | + Qcow2BitmapList *bm_list; | ||
433 | + Qcow2Bitmap *bm; | ||
434 | + Qcow2BitmapTableList drop_tables; | ||
435 | + Qcow2BitmapTable *tb, *tb_next; | ||
436 | + | ||
437 | + if (!bdrv_has_changed_persistent_bitmaps(bs)) { | ||
438 | + /* nothing to do */ | ||
439 | + return; | ||
440 | + } | ||
441 | + | ||
442 | + if (!can_write(bs)) { | ||
443 | + error_setg(errp, "No write access"); | ||
444 | + return; | ||
445 | + } | ||
446 | + | ||
447 | + QSIMPLEQ_INIT(&drop_tables); | ||
448 | + | ||
449 | + if (s->nb_bitmaps == 0) { | ||
450 | + bm_list = bitmap_list_new(); | ||
451 | + } else { | ||
452 | + bm_list = bitmap_list_load(bs, s->bitmap_directory_offset, | ||
453 | + s->bitmap_directory_size, errp); | ||
454 | + if (bm_list == NULL) { | ||
455 | + return; | ||
456 | + } | ||
457 | + } | ||
458 | + | ||
459 | + /* check constraints and names */ | ||
460 | + for (bitmap = bdrv_dirty_bitmap_next(bs, NULL); bitmap != NULL; | ||
461 | + bitmap = bdrv_dirty_bitmap_next(bs, bitmap)) | ||
462 | + { | ||
463 | + const char *name = bdrv_dirty_bitmap_name(bitmap); | ||
464 | + uint32_t granularity = bdrv_dirty_bitmap_granularity(bitmap); | ||
465 | + Qcow2Bitmap *bm; | ||
466 | + | ||
467 | + if (!bdrv_dirty_bitmap_get_persistance(bitmap) || | ||
468 | + bdrv_dirty_bitmap_readonly(bitmap)) | ||
469 | + { | ||
470 | + continue; | ||
471 | + } | ||
472 | + | ||
473 | + if (check_constraints_on_bitmap(bs, name, granularity, errp) < 0) { | ||
474 | + error_prepend(errp, "Bitmap '%s' doesn't satisfy the constraints: ", | ||
475 | + name); | ||
476 | + goto fail; | ||
477 | + } | ||
478 | + | ||
479 | + bm = find_bitmap_by_name(bm_list, name); | ||
480 | + if (bm == NULL) { | ||
481 | + if (++new_nb_bitmaps > QCOW2_MAX_BITMAPS) { | ||
482 | + error_setg(errp, "Too many persistent bitmaps"); | ||
483 | + goto fail; | ||
484 | + } | ||
485 | + | ||
486 | + new_dir_size += calc_dir_entry_size(strlen(name), 0); | ||
487 | + if (new_dir_size > QCOW2_MAX_BITMAP_DIRECTORY_SIZE) { | ||
488 | + error_setg(errp, "Bitmap directory is too large"); | ||
489 | + goto fail; | ||
490 | + } | ||
491 | + | ||
492 | + bm = g_new0(Qcow2Bitmap, 1); | ||
493 | + bm->name = g_strdup(name); | ||
494 | + QSIMPLEQ_INSERT_TAIL(bm_list, bm, entry); | ||
495 | + } else { | ||
496 | + if (!(bm->flags & BME_FLAG_IN_USE)) { | ||
497 | + error_setg(errp, "Bitmap '%s' already exists in the image", | ||
498 | + name); | ||
499 | + goto fail; | ||
500 | + } | ||
501 | + tb = g_memdup(&bm->table, sizeof(bm->table)); | ||
502 | + bm->table.offset = 0; | ||
503 | + bm->table.size = 0; | ||
504 | + QSIMPLEQ_INSERT_TAIL(&drop_tables, tb, entry); | ||
505 | + } | ||
506 | + bm->flags = bdrv_dirty_bitmap_get_autoload(bitmap) ? BME_FLAG_AUTO : 0; | ||
507 | + bm->granularity_bits = ctz32(bdrv_dirty_bitmap_granularity(bitmap)); | ||
508 | + bm->dirty_bitmap = bitmap; | ||
509 | + } | ||
510 | + | ||
511 | + /* allocate clusters and store bitmaps */ | ||
512 | + QSIMPLEQ_FOREACH(bm, bm_list, entry) { | ||
513 | + if (bm->dirty_bitmap == NULL) { | ||
514 | + continue; | ||
515 | + } | ||
516 | + | ||
517 | + ret = store_bitmap(bs, bm, errp); | ||
518 | + if (ret < 0) { | ||
519 | + goto fail; | ||
520 | + } | ||
521 | + } | ||
522 | + | ||
523 | + ret = update_ext_header_and_dir(bs, bm_list); | ||
524 | + if (ret < 0) { | ||
525 | + error_setg_errno(errp, -ret, "Failed to update bitmap extension"); | ||
526 | + goto fail; | ||
527 | + } | ||
528 | + | ||
529 | + /* Bitmap directory was successfully updated, so, old data can be dropped. | ||
530 | + * TODO it is better to reuse these clusters */ | ||
531 | + QSIMPLEQ_FOREACH_SAFE(tb, &drop_tables, entry, tb_next) { | ||
532 | + free_bitmap_clusters(bs, tb); | ||
533 | + g_free(tb); | ||
534 | + } | ||
535 | + | ||
536 | + bitmap_list_free(bm_list); | ||
537 | + return; | ||
538 | + | ||
539 | +fail: | ||
540 | + QSIMPLEQ_FOREACH(bm, bm_list, entry) { | ||
541 | + if (bm->dirty_bitmap == NULL || bm->table.offset == 0) { | ||
542 | + continue; | ||
543 | + } | ||
544 | + | ||
545 | + free_bitmap_clusters(bs, &bm->table); | ||
546 | + } | ||
547 | + | ||
548 | + QSIMPLEQ_FOREACH_SAFE(tb, &drop_tables, entry, tb_next) { | ||
549 | + g_free(tb); | ||
550 | + } | ||
551 | + | ||
552 | + bitmap_list_free(bm_list); | ||
553 | +} | ||
554 | diff --git a/block/qcow2.c b/block/qcow2.c | ||
555 | index XXXXXXX..XXXXXXX 100644 | ||
556 | --- a/block/qcow2.c | ||
557 | +++ b/block/qcow2.c | ||
558 | @@ -XXX,XX +XXX,XX @@ static int qcow2_inactivate(BlockDriverState *bs) | ||
559 | { | 146 | { |
560 | BDRVQcow2State *s = bs->opaque; | 147 | JOB_LOCK_GUARD(); |
561 | int ret, result = 0; | 148 | block_job_iostatus_reset_locked(job); |
562 | + Error *local_err = NULL; | ||
563 | |||
564 | ret = qcow2_cache_flush(bs, s->l2_table_cache); | ||
565 | if (ret) { | ||
566 | @@ -XXX,XX +XXX,XX @@ static int qcow2_inactivate(BlockDriverState *bs) | ||
567 | strerror(-ret)); | ||
568 | } | ||
569 | |||
570 | + qcow2_store_persistent_dirty_bitmaps(bs, &local_err); | ||
571 | + if (local_err != NULL) { | ||
572 | + result = -EINVAL; | ||
573 | + error_report_err(local_err); | ||
574 | + error_report("Persistent bitmaps are lost for node '%s'", | ||
575 | + bdrv_get_device_or_node_name(bs)); | ||
576 | + } | ||
577 | + | ||
578 | if (result == 0) { | ||
579 | qcow2_mark_clean(bs); | ||
580 | } | ||
581 | diff --git a/block/qcow2.h b/block/qcow2.h | ||
582 | index XXXXXXX..XXXXXXX 100644 | ||
583 | --- a/block/qcow2.h | ||
584 | +++ b/block/qcow2.h | ||
585 | @@ -XXX,XX +XXX,XX @@ int qcow2_check_bitmaps_refcounts(BlockDriverState *bs, BdrvCheckResult *res, | ||
586 | int64_t *refcount_table_size); | ||
587 | bool qcow2_load_autoloading_dirty_bitmaps(BlockDriverState *bs, Error **errp); | ||
588 | int qcow2_reopen_bitmaps_rw(BlockDriverState *bs, Error **errp); | ||
589 | +void qcow2_store_persistent_dirty_bitmaps(BlockDriverState *bs, Error **errp); | ||
590 | |||
591 | #endif | ||
592 | -- | 149 | -- |
593 | 1.8.3.1 | 150 | 2.37.3 |
594 | |||
595 | diff view generated by jsdifflib |
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Realize bdrv_reopen_bitmaps_rw interface. | 3 | These public functions are not used anywhere, thus can be dropped. |
4 | Also, since this is the final job API that doesn't use AioContext | ||
5 | lock and replaces it with job_lock, adjust all remaining function | ||
6 | documentation to clearly specify if the job lock is taken or not. | ||
4 | 7 | ||
5 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 8 | Also document the locking requirements for a few functions |
6 | Reviewed-by: John Snow <jsnow@redhat.com> | 9 | where the second version is not removed. |
7 | Reviewed-by: Max Reitz <mreitz@redhat.com> | 10 | |
8 | Message-id: 20170628120530.31251-15-vsementsov@virtuozzo.com | 11 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
9 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 12 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> |
13 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
14 | Message-Id: <20220926093214.506243-22-eesposit@redhat.com> | ||
15 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> | ||
16 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
10 | --- | 17 | --- |
11 | block/qcow2-bitmap.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++ | 18 | include/qemu/job.h | 110 +++++++++++++------------------------ |
12 | block/qcow2.c | 2 ++ | 19 | job.c | 107 ++---------------------------------- |
13 | block/qcow2.h | 1 + | 20 | tests/unit/test-blockjob.c | 4 +- |
14 | 3 files changed, 64 insertions(+) | 21 | 3 files changed, 46 insertions(+), 175 deletions(-) |
15 | 22 | ||
16 | diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c | 23 | diff --git a/include/qemu/job.h b/include/qemu/job.h |
17 | index XXXXXXX..XXXXXXX 100644 | 24 | index XXXXXXX..XXXXXXX 100644 |
18 | --- a/block/qcow2-bitmap.c | 25 | --- a/include/qemu/job.h |
19 | +++ b/block/qcow2-bitmap.c | 26 | +++ b/include/qemu/job.h |
20 | @@ -XXX,XX +XXX,XX @@ fail: | 27 | @@ -XXX,XX +XXX,XX @@ JobTxn *job_txn_new(void); |
21 | 28 | /** | |
29 | * Release a reference that was previously acquired with job_txn_add_job or | ||
30 | * job_txn_new. If it's the last reference to the object, it will be freed. | ||
31 | + * | ||
32 | + * Called with job lock *not* held. | ||
33 | */ | ||
34 | void job_txn_unref(JobTxn *txn); | ||
35 | |||
36 | @@ -XXX,XX +XXX,XX @@ void *job_create(const char *job_id, const JobDriver *driver, JobTxn *txn, | ||
37 | /** | ||
38 | * Add a reference to Job refcnt, it will be decreased with job_unref, and then | ||
39 | * be freed if it comes to be the last reference. | ||
40 | + * | ||
41 | + * Called with job lock held. | ||
42 | */ | ||
43 | -void job_ref(Job *job); | ||
44 | - | ||
45 | -/* Same as job_ref(), but called with job lock held. */ | ||
46 | void job_ref_locked(Job *job); | ||
47 | |||
48 | /** | ||
49 | - * Release a reference that was previously acquired with job_ref() or | ||
50 | + * Release a reference that was previously acquired with job_ref_locked() or | ||
51 | * job_create(). If it's the last reference to the object, it will be freed. | ||
52 | * | ||
53 | * Takes AioContext lock internally to invoke a job->driver callback. | ||
54 | + * Called with job lock held. | ||
55 | */ | ||
56 | -void job_unref(Job *job); | ||
57 | - | ||
58 | -/* Same as job_unref(), but called with job lock held. */ | ||
59 | void job_unref_locked(Job *job); | ||
60 | |||
61 | /** | ||
62 | @@ -XXX,XX +XXX,XX @@ void job_progress_increase_remaining(Job *job, uint64_t delta); | ||
63 | * Conditionally enter the job coroutine if the job is ready to run, not | ||
64 | * already busy and fn() returns true. fn() is called while under the job_lock | ||
65 | * critical section. | ||
66 | - */ | ||
67 | -void job_enter_cond(Job *job, bool(*fn)(Job *job)); | ||
68 | - | ||
69 | -/* | ||
70 | - * Same as job_enter_cond(), but called with job lock held. | ||
71 | - * Might release the lock temporarily. | ||
72 | + * | ||
73 | + * Called with job lock held, but might release it temporarily. | ||
74 | */ | ||
75 | void job_enter_cond_locked(Job *job, bool(*fn)(Job *job)); | ||
76 | |||
77 | @@ -XXX,XX +XXX,XX @@ bool job_cancel_requested(Job *job); | ||
78 | |||
79 | /** | ||
80 | * Returns whether the job is in a completed state. | ||
81 | - * Called with job_mutex *not* held. | ||
82 | + * Called with job lock held. | ||
83 | */ | ||
84 | -bool job_is_completed(Job *job); | ||
85 | - | ||
86 | -/* Same as job_is_completed(), but called with job lock held. */ | ||
87 | bool job_is_completed_locked(Job *job); | ||
88 | |||
89 | /** | ||
90 | @@ -XXX,XX +XXX,XX @@ bool job_is_ready_locked(Job *job); | ||
91 | /** | ||
92 | * Request @job to pause at the next pause point. Must be paired with | ||
93 | * job_resume(). If the job is supposed to be resumed by user action, call | ||
94 | - * job_user_pause() instead. | ||
95 | + * job_user_pause_locked() instead. | ||
96 | + * | ||
97 | + * Called with job lock *not* held. | ||
98 | */ | ||
99 | void job_pause(Job *job); | ||
100 | |||
101 | /* Same as job_pause(), but called with job lock held. */ | ||
102 | void job_pause_locked(Job *job); | ||
103 | |||
104 | -/** Resumes a @job paused with job_pause. */ | ||
105 | +/** Resumes a @job paused with job_pause. Called with job lock *not* held. */ | ||
106 | void job_resume(Job *job); | ||
107 | |||
108 | /* | ||
109 | @@ -XXX,XX +XXX,XX @@ void job_resume_locked(Job *job); | ||
110 | /** | ||
111 | * Asynchronously pause the specified @job. | ||
112 | * Do not allow a resume until a matching call to job_user_resume. | ||
113 | + * Called with job lock held. | ||
114 | */ | ||
115 | -void job_user_pause(Job *job, Error **errp); | ||
116 | - | ||
117 | -/* Same as job_user_pause(), but called with job lock held. */ | ||
118 | void job_user_pause_locked(Job *job, Error **errp); | ||
119 | |||
120 | -/** Returns true if the job is user-paused. */ | ||
121 | -bool job_user_paused(Job *job); | ||
122 | - | ||
123 | -/* Same as job_user_paused(), but called with job lock held. */ | ||
124 | +/** | ||
125 | + * Returns true if the job is user-paused. | ||
126 | + * Called with job lock held. | ||
127 | + */ | ||
128 | bool job_user_paused_locked(Job *job); | ||
129 | |||
130 | /** | ||
131 | * Resume the specified @job. | ||
132 | - * Must be paired with a preceding job_user_pause. | ||
133 | - */ | ||
134 | -void job_user_resume(Job *job, Error **errp); | ||
135 | - | ||
136 | -/* | ||
137 | - * Same as job_user_resume(), but called with job lock held. | ||
138 | - * Might release the lock temporarily. | ||
139 | + * Must be paired with a preceding job_user_pause_locked. | ||
140 | + * Called with job lock held, but might release it temporarily. | ||
141 | */ | ||
142 | void job_user_resume_locked(Job *job, Error **errp); | ||
143 | |||
144 | @@ -XXX,XX +XXX,XX @@ void job_user_resume_locked(Job *job, Error **errp); | ||
145 | * first one if @job is %NULL. | ||
146 | * | ||
147 | * Returns the requested job, or %NULL if there are no more jobs left. | ||
148 | + * Called with job lock *not* held. | ||
149 | */ | ||
150 | Job *job_next(Job *job); | ||
151 | |||
152 | @@ -XXX,XX +XXX,XX @@ Job *job_next_locked(Job *job); | ||
153 | * Get the job identified by @id (which must not be %NULL). | ||
154 | * | ||
155 | * Returns the requested job, or %NULL if it doesn't exist. | ||
156 | + * Called with job lock held. | ||
157 | */ | ||
158 | -Job *job_get(const char *id); | ||
159 | - | ||
160 | -/* Same as job_get(), but called with job lock held. */ | ||
161 | Job *job_get_locked(const char *id); | ||
162 | |||
163 | /** | ||
164 | * Check whether the verb @verb can be applied to @job in its current state. | ||
165 | * Returns 0 if the verb can be applied; otherwise errp is set and -EPERM | ||
166 | * returned. | ||
167 | + * | ||
168 | + * Called with job lock held. | ||
169 | */ | ||
170 | -int job_apply_verb(Job *job, JobVerb verb, Error **errp); | ||
171 | - | ||
172 | -/* Same as job_apply_verb, but called with job lock held. */ | ||
173 | int job_apply_verb_locked(Job *job, JobVerb verb, Error **errp); | ||
174 | |||
175 | /** | ||
176 | @@ -XXX,XX +XXX,XX @@ void job_early_fail(Job *job); | ||
177 | */ | ||
178 | void job_transition_to_ready(Job *job); | ||
179 | |||
180 | -/** Asynchronously complete the specified @job. */ | ||
181 | -void job_complete(Job *job, Error **errp); | ||
182 | - | ||
183 | -/* | ||
184 | - * Same as job_complete(), but called with job lock held. | ||
185 | - * Might release the lock temporarily. | ||
186 | +/** | ||
187 | + * Asynchronously complete the specified @job. | ||
188 | + * Called with job lock held, but might release it temporarily. | ||
189 | */ | ||
190 | void job_complete_locked(Job *job, Error **errp); | ||
191 | |||
192 | /** | ||
193 | * Asynchronously cancel the specified @job. If @force is true, the job should | ||
194 | * be cancelled immediately without waiting for a consistent state. | ||
195 | + * Called with job lock held. | ||
196 | */ | ||
197 | -void job_cancel(Job *job, bool force); | ||
198 | - | ||
199 | -/* Same as job_cancel(), but called with job lock held. */ | ||
200 | void job_cancel_locked(Job *job, bool force); | ||
201 | |||
202 | /** | ||
203 | - * Cancels the specified job like job_cancel(), but may refuse to do so if the | ||
204 | - * operation isn't meaningful in the current state of the job. | ||
205 | + * Cancels the specified job like job_cancel_locked(), but may refuse | ||
206 | + * to do so if the operation isn't meaningful in the current state of the job. | ||
207 | + * Called with job lock held. | ||
208 | */ | ||
209 | -void job_user_cancel(Job *job, bool force, Error **errp); | ||
210 | - | ||
211 | -/* Same as job_user_cancel(), but called with job lock held. */ | ||
212 | void job_user_cancel_locked(Job *job, bool force, Error **errp); | ||
213 | |||
214 | /** | ||
215 | @@ -XXX,XX +XXX,XX @@ void job_cancel_sync_all(void); | ||
216 | |||
217 | /** | ||
218 | * @job: The job to be completed. | ||
219 | - * @errp: Error object which may be set by job_complete(); this is not | ||
220 | + * @errp: Error object which may be set by job_complete_locked(); this is not | ||
221 | * necessarily set on every error, the job return value has to be | ||
222 | * checked as well. | ||
223 | * | ||
224 | @@ -XXX,XX +XXX,XX @@ void job_cancel_sync_all(void); | ||
225 | * function). | ||
226 | * | ||
227 | * Returns the return value from the job. | ||
228 | - * Called with job_lock *not* held. | ||
229 | + * Called with job_lock held. | ||
230 | */ | ||
231 | -int job_complete_sync(Job *job, Error **errp); | ||
232 | - | ||
233 | -/* Same as job_complete_sync, but called with job lock held. */ | ||
234 | int job_complete_sync_locked(Job *job, Error **errp); | ||
235 | |||
236 | /** | ||
237 | @@ -XXX,XX +XXX,XX @@ int job_complete_sync_locked(Job *job, Error **errp); | ||
238 | * FIXME: Make the below statement universally true: | ||
239 | * For jobs that support the manual workflow mode, all graph changes that occur | ||
240 | * as a result will occur after this command and before a successful reply. | ||
241 | + * | ||
242 | + * Called with job lock held. | ||
243 | */ | ||
244 | -void job_finalize(Job *job, Error **errp); | ||
245 | - | ||
246 | -/* Same as job_finalize(), but called with job lock held. */ | ||
247 | void job_finalize_locked(Job *job, Error **errp); | ||
248 | |||
249 | /** | ||
250 | * Remove the concluded @job from the query list and resets the passed pointer | ||
251 | * to %NULL. Returns an error if the job is not actually concluded. | ||
252 | + * | ||
253 | + * Called with job lock held. | ||
254 | */ | ||
255 | -void job_dismiss(Job **job, Error **errp); | ||
256 | - | ||
257 | -/* Same as job_dismiss(), but called with job lock held. */ | ||
258 | void job_dismiss_locked(Job **job, Error **errp); | ||
259 | |||
260 | /** | ||
261 | @@ -XXX,XX +XXX,XX @@ void job_dismiss_locked(Job **job, Error **errp); | ||
262 | * Returns 0 if the job is successfully completed, -ECANCELED if the job was | ||
263 | * cancelled before completing, and -errno in other error cases. | ||
264 | * | ||
265 | - * Called with job_lock *not* held. | ||
266 | - */ | ||
267 | -int job_finish_sync(Job *job, void (*finish)(Job *, Error **errp), | ||
268 | - Error **errp); | ||
269 | - | ||
270 | -/* | ||
271 | - * Same as job_finish_sync(), but called with job lock held. | ||
272 | - * Might release the lock temporarily. | ||
273 | + * Called with job_lock held, but might release it temporarily. | ||
274 | */ | ||
275 | int job_finish_sync_locked(Job *job, void (*finish)(Job *, Error **errp), | ||
276 | Error **errp); | ||
277 | diff --git a/job.c b/job.c | ||
278 | index XXXXXXX..XXXXXXX 100644 | ||
279 | --- a/job.c | ||
280 | +++ b/job.c | ||
281 | @@ -XXX,XX +XXX,XX @@ int job_apply_verb_locked(Job *job, JobVerb verb, Error **errp) | ||
282 | return -EPERM; | ||
283 | } | ||
284 | |||
285 | -int job_apply_verb(Job *job, JobVerb verb, Error **errp) | ||
286 | -{ | ||
287 | - JOB_LOCK_GUARD(); | ||
288 | - return job_apply_verb_locked(job, verb, errp); | ||
289 | -} | ||
290 | - | ||
291 | JobType job_type(const Job *job) | ||
292 | { | ||
293 | return job->driver->job_type; | ||
294 | @@ -XXX,XX +XXX,XX @@ bool job_is_completed_locked(Job *job) | ||
22 | return false; | 295 | return false; |
23 | } | 296 | } |
24 | + | 297 | |
25 | +int qcow2_reopen_bitmaps_rw(BlockDriverState *bs, Error **errp) | 298 | -bool job_is_completed(Job *job) |
26 | +{ | 299 | +static bool job_is_completed(Job *job) |
27 | + BDRVQcow2State *s = bs->opaque; | 300 | { |
28 | + Qcow2BitmapList *bm_list; | 301 | JOB_LOCK_GUARD(); |
29 | + Qcow2Bitmap *bm; | 302 | return job_is_completed_locked(job); |
30 | + GSList *ro_dirty_bitmaps = NULL; | 303 | @@ -XXX,XX +XXX,XX @@ Job *job_get_locked(const char *id) |
31 | + int ret = 0; | 304 | return NULL; |
32 | + | 305 | } |
33 | + if (s->nb_bitmaps == 0) { | 306 | |
34 | + /* No bitmaps - nothing to do */ | 307 | -Job *job_get(const char *id) |
35 | + return 0; | 308 | -{ |
36 | + } | 309 | - JOB_LOCK_GUARD(); |
37 | + | 310 | - return job_get_locked(id); |
38 | + if (!can_write(bs)) { | 311 | -} |
39 | + error_setg(errp, "Can't write to the image on reopening bitmaps rw"); | 312 | - |
40 | + return -EINVAL; | 313 | void job_set_aio_context(Job *job, AioContext *ctx) |
41 | + } | 314 | { |
42 | + | 315 | /* protect against read in job_finish_sync_locked and job_start */ |
43 | + bm_list = bitmap_list_load(bs, s->bitmap_directory_offset, | 316 | @@ -XXX,XX +XXX,XX @@ void job_ref_locked(Job *job) |
44 | + s->bitmap_directory_size, errp); | 317 | ++job->refcnt; |
45 | + if (bm_list == NULL) { | 318 | } |
46 | + return -EINVAL; | 319 | |
47 | + } | 320 | -void job_ref(Job *job) |
48 | + | 321 | -{ |
49 | + QSIMPLEQ_FOREACH(bm, bm_list, entry) { | 322 | - JOB_LOCK_GUARD(); |
50 | + if (!(bm->flags & BME_FLAG_IN_USE)) { | 323 | - job_ref_locked(job); |
51 | + BdrvDirtyBitmap *bitmap = bdrv_find_dirty_bitmap(bs, bm->name); | 324 | -} |
52 | + if (bitmap == NULL) { | 325 | - |
53 | + continue; | 326 | void job_unref_locked(Job *job) |
54 | + } | 327 | { |
55 | + | 328 | GLOBAL_STATE_CODE(); |
56 | + if (!bdrv_dirty_bitmap_readonly(bitmap)) { | 329 | @@ -XXX,XX +XXX,XX @@ void job_unref_locked(Job *job) |
57 | + error_setg(errp, "Bitmap %s is not readonly but not marked" | 330 | } |
58 | + "'IN_USE' in the image. Something went wrong," | 331 | } |
59 | + "all the bitmaps may be corrupted", bm->name); | 332 | |
60 | + ret = -EINVAL; | 333 | -void job_unref(Job *job) |
61 | + goto out; | 334 | -{ |
62 | + } | 335 | - JOB_LOCK_GUARD(); |
63 | + | 336 | - job_unref_locked(job); |
64 | + bm->flags |= BME_FLAG_IN_USE; | 337 | -} |
65 | + ro_dirty_bitmaps = g_slist_append(ro_dirty_bitmaps, bitmap); | 338 | - |
66 | + } | 339 | void job_progress_update(Job *job, uint64_t done) |
67 | + } | 340 | { |
68 | + | 341 | progress_work_done(&job->progress, done); |
69 | + if (ro_dirty_bitmaps != NULL) { | 342 | @@ -XXX,XX +XXX,XX @@ void job_enter_cond_locked(Job *job, bool(*fn)(Job *job)) |
70 | + /* in_use flags must be updated */ | 343 | job_lock(); |
71 | + ret = update_ext_header_and_dir_in_place(bs, bm_list); | 344 | } |
72 | + if (ret < 0) { | 345 | |
73 | + error_setg_errno(errp, -ret, "Can't update bitmap directory"); | 346 | -void job_enter_cond(Job *job, bool(*fn)(Job *job)) |
74 | + goto out; | 347 | -{ |
75 | + } | 348 | - JOB_LOCK_GUARD(); |
76 | + g_slist_foreach(ro_dirty_bitmaps, set_readonly_helper, false); | 349 | - job_enter_cond_locked(job, fn); |
77 | + } | 350 | -} |
78 | + | 351 | - |
79 | +out: | 352 | void job_enter(Job *job) |
80 | + g_slist_free(ro_dirty_bitmaps); | 353 | { |
81 | + bitmap_list_free(bm_list); | 354 | JOB_LOCK_GUARD(); |
82 | + | 355 | @@ -XXX,XX +XXX,XX @@ void coroutine_fn job_pause_point(Job *job) |
83 | + return ret; | 356 | job_pause_point_locked(job); |
84 | +} | 357 | } |
85 | diff --git a/block/qcow2.c b/block/qcow2.c | 358 | |
359 | -static void coroutine_fn job_yield_locked(Job *job) | ||
360 | +void coroutine_fn job_yield(Job *job) | ||
361 | { | ||
362 | + JOB_LOCK_GUARD(); | ||
363 | assert(job->busy); | ||
364 | |||
365 | /* Check cancellation *before* setting busy = false, too! */ | ||
366 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn job_yield_locked(Job *job) | ||
367 | job_pause_point_locked(job); | ||
368 | } | ||
369 | |||
370 | -void coroutine_fn job_yield(Job *job) | ||
371 | -{ | ||
372 | - JOB_LOCK_GUARD(); | ||
373 | - job_yield_locked(job); | ||
374 | -} | ||
375 | - | ||
376 | void coroutine_fn job_sleep_ns(Job *job, int64_t ns) | ||
377 | { | ||
378 | JOB_LOCK_GUARD(); | ||
379 | @@ -XXX,XX +XXX,XX @@ void job_user_pause_locked(Job *job, Error **errp) | ||
380 | job_pause_locked(job); | ||
381 | } | ||
382 | |||
383 | -void job_user_pause(Job *job, Error **errp) | ||
384 | -{ | ||
385 | - JOB_LOCK_GUARD(); | ||
386 | - job_user_pause_locked(job, errp); | ||
387 | -} | ||
388 | - | ||
389 | bool job_user_paused_locked(Job *job) | ||
390 | { | ||
391 | return job->user_paused; | ||
392 | } | ||
393 | |||
394 | -bool job_user_paused(Job *job) | ||
395 | -{ | ||
396 | - JOB_LOCK_GUARD(); | ||
397 | - return job_user_paused_locked(job); | ||
398 | -} | ||
399 | - | ||
400 | void job_user_resume_locked(Job *job, Error **errp) | ||
401 | { | ||
402 | assert(job); | ||
403 | @@ -XXX,XX +XXX,XX @@ void job_user_resume_locked(Job *job, Error **errp) | ||
404 | job_resume_locked(job); | ||
405 | } | ||
406 | |||
407 | -void job_user_resume(Job *job, Error **errp) | ||
408 | -{ | ||
409 | - JOB_LOCK_GUARD(); | ||
410 | - job_user_resume_locked(job, errp); | ||
411 | -} | ||
412 | - | ||
413 | /* Called with job_mutex held, but releases it temporarily. */ | ||
414 | static void job_do_dismiss_locked(Job *job) | ||
415 | { | ||
416 | @@ -XXX,XX +XXX,XX @@ void job_dismiss_locked(Job **jobptr, Error **errp) | ||
417 | *jobptr = NULL; | ||
418 | } | ||
419 | |||
420 | -void job_dismiss(Job **jobptr, Error **errp) | ||
421 | -{ | ||
422 | - JOB_LOCK_GUARD(); | ||
423 | - job_dismiss_locked(jobptr, errp); | ||
424 | -} | ||
425 | - | ||
426 | void job_early_fail(Job *job) | ||
427 | { | ||
428 | JOB_LOCK_GUARD(); | ||
429 | @@ -XXX,XX +XXX,XX @@ void job_finalize_locked(Job *job, Error **errp) | ||
430 | job_do_finalize_locked(job); | ||
431 | } | ||
432 | |||
433 | -void job_finalize(Job *job, Error **errp) | ||
434 | -{ | ||
435 | - JOB_LOCK_GUARD(); | ||
436 | - job_finalize_locked(job, errp); | ||
437 | -} | ||
438 | - | ||
439 | /* Called with job_mutex held. */ | ||
440 | static int job_transition_to_pending_locked(Job *job) | ||
441 | { | ||
442 | @@ -XXX,XX +XXX,XX @@ void job_cancel_locked(Job *job, bool force) | ||
443 | } | ||
444 | } | ||
445 | |||
446 | -void job_cancel(Job *job, bool force) | ||
447 | -{ | ||
448 | - JOB_LOCK_GUARD(); | ||
449 | - job_cancel_locked(job, force); | ||
450 | -} | ||
451 | - | ||
452 | void job_user_cancel_locked(Job *job, bool force, Error **errp) | ||
453 | { | ||
454 | if (job_apply_verb_locked(job, JOB_VERB_CANCEL, errp)) { | ||
455 | @@ -XXX,XX +XXX,XX @@ void job_user_cancel_locked(Job *job, bool force, Error **errp) | ||
456 | job_cancel_locked(job, force); | ||
457 | } | ||
458 | |||
459 | -void job_user_cancel(Job *job, bool force, Error **errp) | ||
460 | -{ | ||
461 | - JOB_LOCK_GUARD(); | ||
462 | - job_user_cancel_locked(job, force, errp); | ||
463 | -} | ||
464 | - | ||
465 | -/* A wrapper around job_cancel() taking an Error ** parameter so it may be | ||
466 | - * used with job_finish_sync() without the need for (rather nasty) function | ||
467 | - * pointer casts there. | ||
468 | +/* A wrapper around job_cancel_locked() taking an Error ** parameter so it may | ||
469 | + * be used with job_finish_sync_locked() without the need for (rather nasty) | ||
470 | + * function pointer casts there. | ||
471 | * | ||
472 | * Called with job_mutex held. | ||
473 | */ | ||
474 | @@ -XXX,XX +XXX,XX @@ int job_complete_sync_locked(Job *job, Error **errp) | ||
475 | return job_finish_sync_locked(job, job_complete_locked, errp); | ||
476 | } | ||
477 | |||
478 | -int job_complete_sync(Job *job, Error **errp) | ||
479 | -{ | ||
480 | - JOB_LOCK_GUARD(); | ||
481 | - return job_complete_sync_locked(job, errp); | ||
482 | -} | ||
483 | - | ||
484 | void job_complete_locked(Job *job, Error **errp) | ||
485 | { | ||
486 | /* Should not be reachable via external interface for internal jobs */ | ||
487 | @@ -XXX,XX +XXX,XX @@ void job_complete_locked(Job *job, Error **errp) | ||
488 | job_lock(); | ||
489 | } | ||
490 | |||
491 | -void job_complete(Job *job, Error **errp) | ||
492 | -{ | ||
493 | - JOB_LOCK_GUARD(); | ||
494 | - job_complete_locked(job, errp); | ||
495 | -} | ||
496 | - | ||
497 | int job_finish_sync_locked(Job *job, | ||
498 | void (*finish)(Job *, Error **errp), | ||
499 | Error **errp) | ||
500 | @@ -XXX,XX +XXX,XX @@ int job_finish_sync_locked(Job *job, | ||
501 | job_unref_locked(job); | ||
502 | return ret; | ||
503 | } | ||
504 | - | ||
505 | -int job_finish_sync(Job *job, void (*finish)(Job *, Error **errp), Error **errp) | ||
506 | -{ | ||
507 | - JOB_LOCK_GUARD(); | ||
508 | - return job_finish_sync_locked(job, finish, errp); | ||
509 | -} | ||
510 | diff --git a/tests/unit/test-blockjob.c b/tests/unit/test-blockjob.c | ||
86 | index XXXXXXX..XXXXXXX 100644 | 511 | index XXXXXXX..XXXXXXX 100644 |
87 | --- a/block/qcow2.c | 512 | --- a/tests/unit/test-blockjob.c |
88 | +++ b/block/qcow2.c | 513 | +++ b/tests/unit/test-blockjob.c |
89 | @@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_qcow2 = { | 514 | @@ -XXX,XX +XXX,XX @@ static const BlockJobDriver test_yielding_driver = { |
90 | |||
91 | .bdrv_detach_aio_context = qcow2_detach_aio_context, | ||
92 | .bdrv_attach_aio_context = qcow2_attach_aio_context, | ||
93 | + | ||
94 | + .bdrv_reopen_bitmaps_rw = qcow2_reopen_bitmaps_rw, | ||
95 | }; | 515 | }; |
96 | 516 | ||
97 | static void bdrv_qcow2_init(void) | 517 | /* |
98 | diff --git a/block/qcow2.h b/block/qcow2.h | 518 | - * Test that job_complete() works even on jobs that are in a paused |
99 | index XXXXXXX..XXXXXXX 100644 | 519 | + * Test that job_complete_locked() works even on jobs that are in a paused |
100 | --- a/block/qcow2.h | 520 | * state (i.e., STANDBY). |
101 | +++ b/block/qcow2.h | 521 | * |
102 | @@ -XXX,XX +XXX,XX @@ int qcow2_check_bitmaps_refcounts(BlockDriverState *bs, BdrvCheckResult *res, | 522 | * To do this, run YieldingJob in an IO thread, get it into the READY |
103 | void **refcount_table, | 523 | @@ -XXX,XX +XXX,XX @@ static const BlockJobDriver test_yielding_driver = { |
104 | int64_t *refcount_table_size); | 524 | * acquire the context so the job will not be entered and will thus |
105 | bool qcow2_load_autoloading_dirty_bitmaps(BlockDriverState *bs, Error **errp); | 525 | * remain on STANDBY. |
106 | +int qcow2_reopen_bitmaps_rw(BlockDriverState *bs, Error **errp); | 526 | * |
107 | 527 | - * job_complete() should still work without error. | |
108 | #endif | 528 | + * job_complete_locked() should still work without error. |
529 | * | ||
530 | * Note that on the QMP interface, it is impossible to lock an IO | ||
531 | * thread before a drained section ends. In practice, the | ||
109 | -- | 532 | -- |
110 | 1.8.3.1 | 533 | 2.37.3 |
111 | |||
112 | diff view generated by jsdifflib |
1 | From: Hervé Poussineau <hpoussin@reactos.org> | 1 | The field is unused (only ever set, but never read) since commit |
---|---|---|---|
2 | ac9185603. Additionally, the commit message of commit 34fa110e already | ||
3 | explained earlier why it's unreliable. Remove it. | ||
2 | 4 | ||
3 | FAT12/FAT16 root directory is two sectors in size, which allows only 512 directory entries. | 5 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
4 | Prevent QEMU startup if too much files exist, instead of overflowing root directory. | 6 | Message-Id: <20220923142838.91043-1-kwolf@redhat.com> |
5 | |||
6 | Also introduce variable root_entries, which will be required for FAT32. | ||
7 | |||
8 | Fixes: https://bugs.launchpad.net/qemu/+bug/1599539/comments/4 | ||
9 | Signed-off-by: Hervé Poussineau <hpoussin@reactos.org> | ||
10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 7 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
11 | --- | 8 | --- |
12 | block/vvfat.c | 26 +++++++++++++++++--------- | 9 | block/file-posix.c | 9 --------- |
13 | 1 file changed, 17 insertions(+), 9 deletions(-) | 10 | 1 file changed, 9 deletions(-) |
14 | 11 | ||
15 | diff --git a/block/vvfat.c b/block/vvfat.c | 12 | diff --git a/block/file-posix.c b/block/file-posix.c |
16 | index XXXXXXX..XXXXXXX 100644 | 13 | index XXXXXXX..XXXXXXX 100644 |
17 | --- a/block/vvfat.c | 14 | --- a/block/file-posix.c |
18 | +++ b/block/vvfat.c | 15 | +++ b/block/file-posix.c |
19 | @@ -XXX,XX +XXX,XX @@ typedef struct BDRVVVFATState { | 16 | @@ -XXX,XX +XXX,XX @@ typedef struct BDRVRawState { |
20 | unsigned int cluster_size; | 17 | |
21 | unsigned int sectors_per_cluster; | 18 | bool has_discard:1; |
22 | unsigned int sectors_per_fat; | 19 | bool has_write_zeroes:1; |
23 | - unsigned int sectors_of_root_directory; | 20 | - bool discard_zeroes:1; |
24 | uint32_t last_cluster_of_root_directory; | 21 | bool use_linux_aio:1; |
25 | + /* how many entries are available in root directory (0 for FAT32) */ | 22 | bool use_linux_io_uring:1; |
26 | + uint16_t root_entries; | 23 | int page_cache_inconsistent; /* errno from fdatasync failure */ |
27 | uint32_t sector_count; /* total number of sectors of the partition */ | 24 | @@ -XXX,XX +XXX,XX @@ static int raw_open_common(BlockDriverState *bs, QDict *options, |
28 | uint32_t cluster_count; /* total number of clusters of this partition */ | 25 | ret = -EINVAL; |
29 | uint32_t max_fat_value; | 26 | goto fail; |
30 | @@ -XXX,XX +XXX,XX @@ static int read_directory(BDRVVVFATState* s, int mapping_index) | 27 | } else { |
31 | int is_dot=!strcmp(entry->d_name,"."); | 28 | - s->discard_zeroes = true; |
32 | int is_dotdot=!strcmp(entry->d_name,".."); | 29 | s->has_fallocate = true; |
33 | 30 | } | |
34 | + if (first_cluster == 0 && s->directory.next >= s->root_entries - 1) { | 31 | } else { |
35 | + fprintf(stderr, "Too many entries in root directory\n"); | 32 | @@ -XXX,XX +XXX,XX @@ static int raw_open_common(BlockDriverState *bs, QDict *options, |
36 | + closedir(dir); | ||
37 | + return -2; | ||
38 | + } | ||
39 | + | ||
40 | if(first_cluster == 0 && (is_dotdot || is_dot)) | ||
41 | continue; | ||
42 | |||
43 | @@ -XXX,XX +XXX,XX @@ static int read_directory(BDRVVVFATState* s, int mapping_index) | ||
44 | memset(direntry,0,sizeof(direntry_t)); | ||
45 | } | 33 | } |
46 | 34 | ||
47 | -/* TODO: if there are more entries, bootsector has to be adjusted! */ | 35 | if (S_ISBLK(st.st_mode)) { |
48 | -#define ROOT_ENTRIES (0x02 * 0x10 * s->sectors_per_cluster) | 36 | -#ifdef BLKDISCARDZEROES |
49 | - if (mapping_index == 0 && s->directory.next < ROOT_ENTRIES) { | 37 | - unsigned int arg; |
50 | + if (s->fat_type != 32 && | 38 | - if (ioctl(s->fd, BLKDISCARDZEROES, &arg) == 0 && arg) { |
51 | + mapping_index == 0 && | 39 | - s->discard_zeroes = true; |
52 | + s->directory.next < s->root_entries) { | 40 | - } |
53 | /* root directory */ | 41 | -#endif |
54 | int cur = s->directory.next; | 42 | #ifdef __linux__ |
55 | - array_ensure_allocated(&(s->directory), ROOT_ENTRIES - 1); | 43 | /* On Linux 3.10, BLKDISCARD leaves stale data in the page cache. Do |
56 | - s->directory.next = ROOT_ENTRIES; | 44 | * not rely on the contents of discarded blocks unless using O_DIRECT. |
57 | + array_ensure_allocated(&(s->directory), s->root_entries - 1); | 45 | * Same for BLKZEROOUT. |
58 | + s->directory.next = s->root_entries; | 46 | */ |
59 | memset(array_get(&(s->directory), cur), 0, | 47 | if (!(bs->open_flags & BDRV_O_NOCACHE)) { |
60 | - (ROOT_ENTRIES - cur) * sizeof(direntry_t)); | 48 | - s->discard_zeroes = false; |
61 | + (s->root_entries - cur) * sizeof(direntry_t)); | 49 | s->has_write_zeroes = false; |
62 | } | 50 | } |
63 | 51 | #endif | |
64 | /* re-get the mapping, since s->mapping was possibly realloc()ed */ | ||
65 | @@ -XXX,XX +XXX,XX @@ static int init_directories(BDRVVVFATState* s, | ||
66 | /* Now build FAT, and write back information into directory */ | ||
67 | init_fat(s); | ||
68 | |||
69 | + /* TODO: if there are more entries, bootsector has to be adjusted! */ | ||
70 | + s->root_entries = 0x02 * 0x10 * s->sectors_per_cluster; | ||
71 | s->cluster_count=sector2cluster(s, s->sector_count); | ||
72 | |||
73 | mapping = array_get_next(&(s->mapping)); | ||
74 | @@ -XXX,XX +XXX,XX @@ static int init_directories(BDRVVVFATState* s, | ||
75 | } | ||
76 | |||
77 | mapping = array_get(&(s->mapping), 0); | ||
78 | - s->sectors_of_root_directory = mapping->end * s->sectors_per_cluster; | ||
79 | s->last_cluster_of_root_directory = mapping->end; | ||
80 | |||
81 | /* the FAT signature */ | ||
82 | @@ -XXX,XX +XXX,XX @@ static int init_directories(BDRVVVFATState* s, | ||
83 | bootsector->sectors_per_cluster=s->sectors_per_cluster; | ||
84 | bootsector->reserved_sectors=cpu_to_le16(1); | ||
85 | bootsector->number_of_fats=0x2; /* number of FATs */ | ||
86 | - bootsector->root_entries=cpu_to_le16(s->sectors_of_root_directory*0x10); | ||
87 | + bootsector->root_entries = cpu_to_le16(s->root_entries); | ||
88 | bootsector->total_sectors16=s->sector_count>0xffff?0:cpu_to_le16(s->sector_count); | ||
89 | /* media descriptor: hard disk=0xf8, floppy=0xf0 */ | ||
90 | bootsector->media_type = (s->offset_to_bootsector > 0 ? 0xf8 : 0xf0); | ||
91 | -- | 52 | -- |
92 | 1.8.3.1 | 53 | 2.37.3 |
93 | |||
94 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: "Daniel P. Berrange" <berrange@redhat.com> | ||
2 | 1 | ||
3 | The '-e' and '-6' options to the 'create' & 'convert' commands were | ||
4 | "deprecated" in favour of the more generic '-o' option many years ago: | ||
5 | |||
6 | commit eec77d9e712bd4157a4e1c0b5a9249d168add738 | ||
7 | Author: Jes Sorensen <Jes.Sorensen@redhat.com> | ||
8 | Date: Tue Dec 7 17:44:34 2010 +0100 | ||
9 | |||
10 | qemu-img: Deprecate obsolete -6 and -e options | ||
11 | |||
12 | Except this was never actually a deprecation, which would imply giving | ||
13 | the user a warning while the functionality continues to work for a | ||
14 | number of releases before eventual removal. Instead the options were | ||
15 | immediately turned into an error + exit. Given that the functionality | ||
16 | is already broken, there's no point in keeping these psuedo-deprecation | ||
17 | messages around any longer. | ||
18 | |||
19 | Signed-off-by: Daniel P. Berrange <berrange@redhat.com> | ||
20 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
21 | --- | ||
22 | qemu-img.c | 20 ++------------------ | ||
23 | 1 file changed, 2 insertions(+), 18 deletions(-) | ||
24 | |||
25 | diff --git a/qemu-img.c b/qemu-img.c | ||
26 | index XXXXXXX..XXXXXXX 100644 | ||
27 | --- a/qemu-img.c | ||
28 | +++ b/qemu-img.c | ||
29 | @@ -XXX,XX +XXX,XX @@ static int img_create(int argc, char **argv) | ||
30 | {"object", required_argument, 0, OPTION_OBJECT}, | ||
31 | {0, 0, 0, 0} | ||
32 | }; | ||
33 | - c = getopt_long(argc, argv, ":F:b:f:he6o:q", | ||
34 | + c = getopt_long(argc, argv, ":F:b:f:ho:q", | ||
35 | long_options, NULL); | ||
36 | if (c == -1) { | ||
37 | break; | ||
38 | @@ -XXX,XX +XXX,XX @@ static int img_create(int argc, char **argv) | ||
39 | case 'f': | ||
40 | fmt = optarg; | ||
41 | break; | ||
42 | - case 'e': | ||
43 | - error_report("option -e is deprecated, please use \'-o " | ||
44 | - "encryption\' instead!"); | ||
45 | - goto fail; | ||
46 | - case '6': | ||
47 | - error_report("option -6 is deprecated, please use \'-o " | ||
48 | - "compat6\' instead!"); | ||
49 | - goto fail; | ||
50 | case 'o': | ||
51 | if (!is_valid_option_list(optarg)) { | ||
52 | error_report("Invalid option list: %s", optarg); | ||
53 | @@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv) | ||
54 | {"target-image-opts", no_argument, 0, OPTION_TARGET_IMAGE_OPTS}, | ||
55 | {0, 0, 0, 0} | ||
56 | }; | ||
57 | - c = getopt_long(argc, argv, ":hf:O:B:ce6o:s:l:S:pt:T:qnm:WU", | ||
58 | + c = getopt_long(argc, argv, ":hf:O:B:co:s:l:S:pt:T:qnm:WU", | ||
59 | long_options, NULL); | ||
60 | if (c == -1) { | ||
61 | break; | ||
62 | @@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv) | ||
63 | case 'c': | ||
64 | s.compressed = true; | ||
65 | break; | ||
66 | - case 'e': | ||
67 | - error_report("option -e is deprecated, please use \'-o " | ||
68 | - "encryption\' instead!"); | ||
69 | - goto fail_getopt; | ||
70 | - case '6': | ||
71 | - error_report("option -6 is deprecated, please use \'-o " | ||
72 | - "compat6\' instead!"); | ||
73 | - goto fail_getopt; | ||
74 | case 'o': | ||
75 | if (!is_valid_option_list(optarg)) { | ||
76 | error_report("Invalid option list: %s", optarg); | ||
77 | -- | ||
78 | 1.8.3.1 | ||
79 | |||
80 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Eric Blake <eblake@redhat.com> | ||
2 | 1 | ||
3 | We are gradually converting to byte-based interfaces, as they are | ||
4 | easier to reason about than sector-based. Continue by converting an | ||
5 | internal structure (no semantic change), and all references to | ||
6 | tracking progress. Drop a redundant local variable bytes_per_cluster. | ||
7 | |||
8 | Signed-off-by: Eric Blake <eblake@redhat.com> | ||
9 | Reviewed-by: John Snow <jsnow@redhat.com> | ||
10 | Reviewed-by: Jeff Cody <jcody@redhat.com> | ||
11 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
13 | --- | ||
14 | block/backup.c | 33 +++++++++++++++------------------ | ||
15 | 1 file changed, 15 insertions(+), 18 deletions(-) | ||
16 | |||
17 | diff --git a/block/backup.c b/block/backup.c | ||
18 | index XXXXXXX..XXXXXXX 100644 | ||
19 | --- a/block/backup.c | ||
20 | +++ b/block/backup.c | ||
21 | @@ -XXX,XX +XXX,XX @@ typedef struct BackupBlockJob { | ||
22 | BlockdevOnError on_source_error; | ||
23 | BlockdevOnError on_target_error; | ||
24 | CoRwlock flush_rwlock; | ||
25 | - uint64_t sectors_read; | ||
26 | + uint64_t bytes_read; | ||
27 | unsigned long *done_bitmap; | ||
28 | int64_t cluster_size; | ||
29 | bool compress; | ||
30 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_do_cow(BackupBlockJob *job, | ||
31 | void *bounce_buffer = NULL; | ||
32 | int ret = 0; | ||
33 | int64_t sectors_per_cluster = cluster_size_sectors(job); | ||
34 | - int64_t bytes_per_cluster = sectors_per_cluster * BDRV_SECTOR_SIZE; | ||
35 | - int64_t start, end; | ||
36 | - int n; | ||
37 | + int64_t start, end; /* clusters */ | ||
38 | + int n; /* bytes */ | ||
39 | |||
40 | qemu_co_rwlock_rdlock(&job->flush_rwlock); | ||
41 | |||
42 | start = sector_num / sectors_per_cluster; | ||
43 | end = DIV_ROUND_UP(sector_num + nb_sectors, sectors_per_cluster); | ||
44 | |||
45 | - trace_backup_do_cow_enter(job, start * bytes_per_cluster, | ||
46 | + trace_backup_do_cow_enter(job, start * job->cluster_size, | ||
47 | sector_num * BDRV_SECTOR_SIZE, | ||
48 | nb_sectors * BDRV_SECTOR_SIZE); | ||
49 | |||
50 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_do_cow(BackupBlockJob *job, | ||
51 | |||
52 | for (; start < end; start++) { | ||
53 | if (test_bit(start, job->done_bitmap)) { | ||
54 | - trace_backup_do_cow_skip(job, start * bytes_per_cluster); | ||
55 | + trace_backup_do_cow_skip(job, start * job->cluster_size); | ||
56 | continue; /* already copied */ | ||
57 | } | ||
58 | |||
59 | - trace_backup_do_cow_process(job, start * bytes_per_cluster); | ||
60 | + trace_backup_do_cow_process(job, start * job->cluster_size); | ||
61 | |||
62 | - n = MIN(sectors_per_cluster, | ||
63 | - job->common.len / BDRV_SECTOR_SIZE - | ||
64 | - start * sectors_per_cluster); | ||
65 | + n = MIN(job->cluster_size, | ||
66 | + job->common.len - start * job->cluster_size); | ||
67 | |||
68 | if (!bounce_buffer) { | ||
69 | bounce_buffer = blk_blockalign(blk, job->cluster_size); | ||
70 | } | ||
71 | iov.iov_base = bounce_buffer; | ||
72 | - iov.iov_len = n * BDRV_SECTOR_SIZE; | ||
73 | + iov.iov_len = n; | ||
74 | qemu_iovec_init_external(&bounce_qiov, &iov, 1); | ||
75 | |||
76 | ret = blk_co_preadv(blk, start * job->cluster_size, | ||
77 | bounce_qiov.size, &bounce_qiov, | ||
78 | is_write_notifier ? BDRV_REQ_NO_SERIALISING : 0); | ||
79 | if (ret < 0) { | ||
80 | - trace_backup_do_cow_read_fail(job, start * bytes_per_cluster, ret); | ||
81 | + trace_backup_do_cow_read_fail(job, start * job->cluster_size, ret); | ||
82 | if (error_is_read) { | ||
83 | *error_is_read = true; | ||
84 | } | ||
85 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_do_cow(BackupBlockJob *job, | ||
86 | job->compress ? BDRV_REQ_WRITE_COMPRESSED : 0); | ||
87 | } | ||
88 | if (ret < 0) { | ||
89 | - trace_backup_do_cow_write_fail(job, start * bytes_per_cluster, ret); | ||
90 | + trace_backup_do_cow_write_fail(job, start * job->cluster_size, ret); | ||
91 | if (error_is_read) { | ||
92 | *error_is_read = false; | ||
93 | } | ||
94 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_do_cow(BackupBlockJob *job, | ||
95 | /* Publish progress, guest I/O counts as progress too. Note that the | ||
96 | * offset field is an opaque progress value, it is not a disk offset. | ||
97 | */ | ||
98 | - job->sectors_read += n; | ||
99 | - job->common.offset += n * BDRV_SECTOR_SIZE; | ||
100 | + job->bytes_read += n; | ||
101 | + job->common.offset += n; | ||
102 | } | ||
103 | |||
104 | out: | ||
105 | @@ -XXX,XX +XXX,XX @@ static bool coroutine_fn yield_and_check(BackupBlockJob *job) | ||
106 | */ | ||
107 | if (job->common.speed) { | ||
108 | uint64_t delay_ns = ratelimit_calculate_delay(&job->limit, | ||
109 | - job->sectors_read * | ||
110 | - BDRV_SECTOR_SIZE); | ||
111 | - job->sectors_read = 0; | ||
112 | + job->bytes_read); | ||
113 | + job->bytes_read = 0; | ||
114 | block_job_sleep_ns(&job->common, QEMU_CLOCK_REALTIME, delay_ns); | ||
115 | } else { | ||
116 | block_job_sleep_ns(&job->common, QEMU_CLOCK_REALTIME, 0); | ||
117 | -- | ||
118 | 1.8.3.1 | ||
119 | |||
120 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Eric Blake <eblake@redhat.com> | ||
2 | 1 | ||
3 | We are gradually converting to byte-based interfaces, as they are | ||
4 | easier to reason about than sector-based. Change the internal | ||
5 | loop iteration of backups to track by bytes instead of sectors | ||
6 | (although we are still guaranteed that we iterate by steps that | ||
7 | are cluster-aligned). | ||
8 | |||
9 | Signed-off-by: Eric Blake <eblake@redhat.com> | ||
10 | Reviewed-by: John Snow <jsnow@redhat.com> | ||
11 | Reviewed-by: Jeff Cody <jcody@redhat.com> | ||
12 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
13 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
14 | --- | ||
15 | block/backup.c | 32 +++++++++++++++----------------- | ||
16 | 1 file changed, 15 insertions(+), 17 deletions(-) | ||
17 | |||
18 | diff --git a/block/backup.c b/block/backup.c | ||
19 | index XXXXXXX..XXXXXXX 100644 | ||
20 | --- a/block/backup.c | ||
21 | +++ b/block/backup.c | ||
22 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_run_incremental(BackupBlockJob *job) | ||
23 | int ret = 0; | ||
24 | int clusters_per_iter; | ||
25 | uint32_t granularity; | ||
26 | - int64_t sector; | ||
27 | + int64_t offset; | ||
28 | int64_t cluster; | ||
29 | int64_t end; | ||
30 | int64_t last_cluster = -1; | ||
31 | - int64_t sectors_per_cluster = cluster_size_sectors(job); | ||
32 | BdrvDirtyBitmapIter *dbi; | ||
33 | |||
34 | granularity = bdrv_dirty_bitmap_granularity(job->sync_bitmap); | ||
35 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_run_incremental(BackupBlockJob *job) | ||
36 | dbi = bdrv_dirty_iter_new(job->sync_bitmap, 0); | ||
37 | |||
38 | /* Find the next dirty sector(s) */ | ||
39 | - while ((sector = bdrv_dirty_iter_next(dbi)) != -1) { | ||
40 | - cluster = sector / sectors_per_cluster; | ||
41 | + while ((offset = bdrv_dirty_iter_next(dbi) * BDRV_SECTOR_SIZE) >= 0) { | ||
42 | + cluster = offset / job->cluster_size; | ||
43 | |||
44 | /* Fake progress updates for any clusters we skipped */ | ||
45 | if (cluster != last_cluster + 1) { | ||
46 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_run_incremental(BackupBlockJob *job) | ||
47 | /* If the bitmap granularity is smaller than the backup granularity, | ||
48 | * we need to advance the iterator pointer to the next cluster. */ | ||
49 | if (granularity < job->cluster_size) { | ||
50 | - bdrv_set_dirty_iter(dbi, cluster * sectors_per_cluster); | ||
51 | + bdrv_set_dirty_iter(dbi, | ||
52 | + cluster * job->cluster_size / BDRV_SECTOR_SIZE); | ||
53 | } | ||
54 | |||
55 | last_cluster = cluster - 1; | ||
56 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn backup_run(void *opaque) | ||
57 | BackupBlockJob *job = opaque; | ||
58 | BackupCompleteData *data; | ||
59 | BlockDriverState *bs = blk_bs(job->common.blk); | ||
60 | - int64_t start, end; | ||
61 | + int64_t offset; | ||
62 | int64_t sectors_per_cluster = cluster_size_sectors(job); | ||
63 | int ret = 0; | ||
64 | |||
65 | QLIST_INIT(&job->inflight_reqs); | ||
66 | qemu_co_rwlock_init(&job->flush_rwlock); | ||
67 | |||
68 | - start = 0; | ||
69 | - end = DIV_ROUND_UP(job->common.len, job->cluster_size); | ||
70 | - | ||
71 | - job->done_bitmap = bitmap_new(end); | ||
72 | + job->done_bitmap = bitmap_new(DIV_ROUND_UP(job->common.len, | ||
73 | + job->cluster_size)); | ||
74 | |||
75 | job->before_write.notify = backup_before_write_notify; | ||
76 | bdrv_add_before_write_notifier(bs, &job->before_write); | ||
77 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn backup_run(void *opaque) | ||
78 | ret = backup_run_incremental(job); | ||
79 | } else { | ||
80 | /* Both FULL and TOP SYNC_MODE's require copying.. */ | ||
81 | - for (; start < end; start++) { | ||
82 | + for (offset = 0; offset < job->common.len; | ||
83 | + offset += job->cluster_size) { | ||
84 | bool error_is_read; | ||
85 | int alloced = 0; | ||
86 | |||
87 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn backup_run(void *opaque) | ||
88 | * needed but at some point that is always the case. */ | ||
89 | alloced = | ||
90 | bdrv_is_allocated(bs, | ||
91 | - start * sectors_per_cluster + i, | ||
92 | - sectors_per_cluster - i, &n); | ||
93 | + (offset >> BDRV_SECTOR_BITS) + i, | ||
94 | + sectors_per_cluster - i, &n); | ||
95 | i += n; | ||
96 | |||
97 | if (alloced || n == 0) { | ||
98 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn backup_run(void *opaque) | ||
99 | if (alloced < 0) { | ||
100 | ret = alloced; | ||
101 | } else { | ||
102 | - ret = backup_do_cow(job, start * job->cluster_size, | ||
103 | - job->cluster_size, &error_is_read, | ||
104 | - false); | ||
105 | + ret = backup_do_cow(job, offset, job->cluster_size, | ||
106 | + &error_is_read, false); | ||
107 | } | ||
108 | if (ret < 0) { | ||
109 | /* Depending on error action, fail now or retry cluster */ | ||
110 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn backup_run(void *opaque) | ||
111 | if (action == BLOCK_ERROR_ACTION_REPORT) { | ||
112 | break; | ||
113 | } else { | ||
114 | - start--; | ||
115 | + offset -= job->cluster_size; | ||
116 | continue; | ||
117 | } | ||
118 | } | ||
119 | -- | ||
120 | 1.8.3.1 | ||
121 | |||
122 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Eric Blake <eblake@redhat.com> | ||
2 | 1 | ||
3 | bdrv_is_allocated_above() was relying on intermediate->total_sectors, | ||
4 | which is a field that can have stale contents depending on the value | ||
5 | of intermediate->has_variable_length. An audit shows that we are safe | ||
6 | (we were first calling through bdrv_co_get_block_status() which in | ||
7 | turn calls bdrv_nb_sectors() and therefore just refreshed the current | ||
8 | length), but it's nicer to favor our accessor functions to avoid having | ||
9 | to repeat such an audit, even if it means refresh_total_sectors() is | ||
10 | called more frequently. | ||
11 | |||
12 | Suggested-by: John Snow <jsnow@redhat.com> | ||
13 | Signed-off-by: Eric Blake <eblake@redhat.com> | ||
14 | Reviewed-by: Manos Pitsidianakis <el13635@mail.ntua.gr> | ||
15 | Reviewed-by: Jeff Cody <jcody@redhat.com> | ||
16 | Reviewed-by: John Snow <jsnow@redhat.com> | ||
17 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
18 | --- | ||
19 | block/io.c | 14 ++++++-------- | ||
20 | 1 file changed, 6 insertions(+), 8 deletions(-) | ||
21 | |||
22 | diff --git a/block/io.c b/block/io.c | ||
23 | index XXXXXXX..XXXXXXX 100644 | ||
24 | --- a/block/io.c | ||
25 | +++ b/block/io.c | ||
26 | @@ -XXX,XX +XXX,XX @@ int bdrv_is_allocated_above(BlockDriverState *top, | ||
27 | intermediate = top; | ||
28 | while (intermediate && intermediate != base) { | ||
29 | int64_t pnum_inter; | ||
30 | + int64_t size_inter; | ||
31 | int psectors_inter; | ||
32 | |||
33 | ret = bdrv_is_allocated(intermediate, sector_num * BDRV_SECTOR_SIZE, | ||
34 | @@ -XXX,XX +XXX,XX @@ int bdrv_is_allocated_above(BlockDriverState *top, | ||
35 | return 1; | ||
36 | } | ||
37 | |||
38 | - /* | ||
39 | - * [sector_num, nb_sectors] is unallocated on top but intermediate | ||
40 | - * might have | ||
41 | - * | ||
42 | - * [sector_num+x, nr_sectors] allocated. | ||
43 | - */ | ||
44 | + size_inter = bdrv_nb_sectors(intermediate); | ||
45 | + if (size_inter < 0) { | ||
46 | + return size_inter; | ||
47 | + } | ||
48 | if (n > psectors_inter && | ||
49 | - (intermediate == top || | ||
50 | - sector_num + psectors_inter < intermediate->total_sectors)) { | ||
51 | + (intermediate == top || sector_num + psectors_inter < size_inter)) { | ||
52 | n = psectors_inter; | ||
53 | } | ||
54 | |||
55 | -- | ||
56 | 1.8.3.1 | ||
57 | |||
58 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: "Daniel P. Berrange" <berrange@redhat.com> | ||
2 | 1 | ||
3 | When integrating the crypto support with qcow/qcow2, we don't | ||
4 | want to use the bare LUKS option names "hash-alg", "key-secret", | ||
5 | etc. We need to namespace them to match the nested QAPI schema. | ||
6 | |||
7 | e.g. "encrypt.hash-alg", "encrypt.key-secret" | ||
8 | |||
9 | so that they don't clash with any general qcow options at a later | ||
10 | date. | ||
11 | |||
12 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
13 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
14 | Reviewed-by: Alberto Garcia <berto@igalia.com> | ||
15 | Signed-off-by: Daniel P. Berrange <berrange@redhat.com> | ||
16 | Message-id: 20170623162419.26068-3-berrange@redhat.com | ||
17 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
18 | --- | ||
19 | block/crypto.c | 16 ++++++++-------- | ||
20 | block/crypto.h | 40 ++++++++++++++++++++-------------------- | ||
21 | 2 files changed, 28 insertions(+), 28 deletions(-) | ||
22 | |||
23 | diff --git a/block/crypto.c b/block/crypto.c | ||
24 | index XXXXXXX..XXXXXXX 100644 | ||
25 | --- a/block/crypto.c | ||
26 | +++ b/block/crypto.c | ||
27 | @@ -XXX,XX +XXX,XX @@ static QemuOptsList block_crypto_runtime_opts_luks = { | ||
28 | .name = "crypto", | ||
29 | .head = QTAILQ_HEAD_INITIALIZER(block_crypto_runtime_opts_luks.head), | ||
30 | .desc = { | ||
31 | - BLOCK_CRYPTO_OPT_DEF_LUKS_KEY_SECRET, | ||
32 | + BLOCK_CRYPTO_OPT_DEF_LUKS_KEY_SECRET(""), | ||
33 | { /* end of list */ } | ||
34 | }, | ||
35 | }; | ||
36 | @@ -XXX,XX +XXX,XX @@ static QemuOptsList block_crypto_create_opts_luks = { | ||
37 | .type = QEMU_OPT_SIZE, | ||
38 | .help = "Virtual disk size" | ||
39 | }, | ||
40 | - BLOCK_CRYPTO_OPT_DEF_LUKS_KEY_SECRET, | ||
41 | - BLOCK_CRYPTO_OPT_DEF_LUKS_CIPHER_ALG, | ||
42 | - BLOCK_CRYPTO_OPT_DEF_LUKS_CIPHER_MODE, | ||
43 | - BLOCK_CRYPTO_OPT_DEF_LUKS_IVGEN_ALG, | ||
44 | - BLOCK_CRYPTO_OPT_DEF_LUKS_IVGEN_HASH_ALG, | ||
45 | - BLOCK_CRYPTO_OPT_DEF_LUKS_HASH_ALG, | ||
46 | - BLOCK_CRYPTO_OPT_DEF_LUKS_ITER_TIME, | ||
47 | + BLOCK_CRYPTO_OPT_DEF_LUKS_KEY_SECRET(""), | ||
48 | + BLOCK_CRYPTO_OPT_DEF_LUKS_CIPHER_ALG(""), | ||
49 | + BLOCK_CRYPTO_OPT_DEF_LUKS_CIPHER_MODE(""), | ||
50 | + BLOCK_CRYPTO_OPT_DEF_LUKS_IVGEN_ALG(""), | ||
51 | + BLOCK_CRYPTO_OPT_DEF_LUKS_IVGEN_HASH_ALG(""), | ||
52 | + BLOCK_CRYPTO_OPT_DEF_LUKS_HASH_ALG(""), | ||
53 | + BLOCK_CRYPTO_OPT_DEF_LUKS_ITER_TIME(""), | ||
54 | { /* end of list */ } | ||
55 | }, | ||
56 | }; | ||
57 | diff --git a/block/crypto.h b/block/crypto.h | ||
58 | index XXXXXXX..XXXXXXX 100644 | ||
59 | --- a/block/crypto.h | ||
60 | +++ b/block/crypto.h | ||
61 | @@ -XXX,XX +XXX,XX @@ | ||
62 | #define BLOCK_CRYPTO_OPT_LUKS_HASH_ALG "hash-alg" | ||
63 | #define BLOCK_CRYPTO_OPT_LUKS_ITER_TIME "iter-time" | ||
64 | |||
65 | -#define BLOCK_CRYPTO_OPT_DEF_LUKS_KEY_SECRET \ | ||
66 | +#define BLOCK_CRYPTO_OPT_DEF_LUKS_KEY_SECRET(prefix) \ | ||
67 | { \ | ||
68 | - .name = BLOCK_CRYPTO_OPT_LUKS_KEY_SECRET, \ | ||
69 | + .name = prefix BLOCK_CRYPTO_OPT_LUKS_KEY_SECRET, \ | ||
70 | .type = QEMU_OPT_STRING, \ | ||
71 | .help = "ID of the secret that provides the keyslot passphrase", \ | ||
72 | } | ||
73 | |||
74 | -#define BLOCK_CRYPTO_OPT_DEF_LUKS_CIPHER_ALG \ | ||
75 | +#define BLOCK_CRYPTO_OPT_DEF_LUKS_CIPHER_ALG(prefix) \ | ||
76 | { \ | ||
77 | - .name = BLOCK_CRYPTO_OPT_LUKS_CIPHER_ALG, \ | ||
78 | + .name = prefix BLOCK_CRYPTO_OPT_LUKS_CIPHER_ALG, \ | ||
79 | .type = QEMU_OPT_STRING, \ | ||
80 | .help = "Name of encryption cipher algorithm", \ | ||
81 | } | ||
82 | |||
83 | -#define BLOCK_CRYPTO_OPT_DEF_LUKS_CIPHER_MODE \ | ||
84 | - { \ | ||
85 | - .name = BLOCK_CRYPTO_OPT_LUKS_CIPHER_MODE, \ | ||
86 | - .type = QEMU_OPT_STRING, \ | ||
87 | - .help = "Name of encryption cipher mode", \ | ||
88 | +#define BLOCK_CRYPTO_OPT_DEF_LUKS_CIPHER_MODE(prefix) \ | ||
89 | + { \ | ||
90 | + .name = prefix BLOCK_CRYPTO_OPT_LUKS_CIPHER_MODE, \ | ||
91 | + .type = QEMU_OPT_STRING, \ | ||
92 | + .help = "Name of encryption cipher mode", \ | ||
93 | } | ||
94 | |||
95 | -#define BLOCK_CRYPTO_OPT_DEF_LUKS_IVGEN_ALG \ | ||
96 | - { \ | ||
97 | - .name = BLOCK_CRYPTO_OPT_LUKS_IVGEN_ALG, \ | ||
98 | - .type = QEMU_OPT_STRING, \ | ||
99 | - .help = "Name of IV generator algorithm", \ | ||
100 | +#define BLOCK_CRYPTO_OPT_DEF_LUKS_IVGEN_ALG(prefix) \ | ||
101 | + { \ | ||
102 | + .name = prefix BLOCK_CRYPTO_OPT_LUKS_IVGEN_ALG, \ | ||
103 | + .type = QEMU_OPT_STRING, \ | ||
104 | + .help = "Name of IV generator algorithm", \ | ||
105 | } | ||
106 | |||
107 | -#define BLOCK_CRYPTO_OPT_DEF_LUKS_IVGEN_HASH_ALG \ | ||
108 | +#define BLOCK_CRYPTO_OPT_DEF_LUKS_IVGEN_HASH_ALG(prefix) \ | ||
109 | { \ | ||
110 | - .name = BLOCK_CRYPTO_OPT_LUKS_IVGEN_HASH_ALG, \ | ||
111 | + .name = prefix BLOCK_CRYPTO_OPT_LUKS_IVGEN_HASH_ALG, \ | ||
112 | .type = QEMU_OPT_STRING, \ | ||
113 | .help = "Name of IV generator hash algorithm", \ | ||
114 | } | ||
115 | |||
116 | -#define BLOCK_CRYPTO_OPT_DEF_LUKS_HASH_ALG \ | ||
117 | +#define BLOCK_CRYPTO_OPT_DEF_LUKS_HASH_ALG(prefix) \ | ||
118 | { \ | ||
119 | - .name = BLOCK_CRYPTO_OPT_LUKS_HASH_ALG, \ | ||
120 | + .name = prefix BLOCK_CRYPTO_OPT_LUKS_HASH_ALG, \ | ||
121 | .type = QEMU_OPT_STRING, \ | ||
122 | .help = "Name of encryption hash algorithm", \ | ||
123 | } | ||
124 | |||
125 | -#define BLOCK_CRYPTO_OPT_DEF_LUKS_ITER_TIME \ | ||
126 | +#define BLOCK_CRYPTO_OPT_DEF_LUKS_ITER_TIME(prefix) \ | ||
127 | { \ | ||
128 | - .name = BLOCK_CRYPTO_OPT_LUKS_ITER_TIME, \ | ||
129 | + .name = prefix BLOCK_CRYPTO_OPT_LUKS_ITER_TIME, \ | ||
130 | .type = QEMU_OPT_NUMBER, \ | ||
131 | .help = "Time to spend in PBKDF in milliseconds", \ | ||
132 | } | ||
133 | -- | ||
134 | 1.8.3.1 | ||
135 | |||
136 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: "Daniel P. Berrange" <berrange@redhat.com> | ||
2 | 1 | ||
3 | Document that use of guest virtual sector numbers as the basis for | ||
4 | the initialization vectors is a potential weakness, when combined | ||
5 | with internal snapshots or multiple images using the same passphrase. | ||
6 | This fixes the formatting of the itemized list too. | ||
7 | |||
8 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
9 | Reviewed-by: Alberto Garcia <berto@igalia.com> | ||
10 | Signed-off-by: Daniel P. Berrange <berrange@redhat.com> | ||
11 | Message-id: 20170623162419.26068-4-berrange@redhat.com | ||
12 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
13 | --- | ||
14 | qemu-img.texi | 19 ++++++++++++++++--- | ||
15 | 1 file changed, 16 insertions(+), 3 deletions(-) | ||
16 | |||
17 | diff --git a/qemu-img.texi b/qemu-img.texi | ||
18 | index XXXXXXX..XXXXXXX 100644 | ||
19 | --- a/qemu-img.texi | ||
20 | +++ b/qemu-img.texi | ||
21 | @@ -XXX,XX +XXX,XX @@ The use of encryption in qcow and qcow2 images is considered to be flawed by | ||
22 | modern cryptography standards, suffering from a number of design problems: | ||
23 | |||
24 | @itemize @minus | ||
25 | -@item The AES-CBC cipher is used with predictable initialization vectors based | ||
26 | +@item | ||
27 | +The AES-CBC cipher is used with predictable initialization vectors based | ||
28 | on the sector number. This makes it vulnerable to chosen plaintext attacks | ||
29 | which can reveal the existence of encrypted data. | ||
30 | -@item The user passphrase is directly used as the encryption key. A poorly | ||
31 | +@item | ||
32 | +The user passphrase is directly used as the encryption key. A poorly | ||
33 | chosen or short passphrase will compromise the security of the encryption. | ||
34 | -@item In the event of the passphrase being compromised there is no way to | ||
35 | +@item | ||
36 | +In the event of the passphrase being compromised there is no way to | ||
37 | change the passphrase to protect data in any qcow images. The files must | ||
38 | be cloned, using a different encryption passphrase in the new file. The | ||
39 | original file must then be securely erased using a program like shred, | ||
40 | though even this is ineffective with many modern storage technologies. | ||
41 | +@item | ||
42 | +Initialization vectors used to encrypt sectors are based on the | ||
43 | +guest virtual sector number, instead of the host physical sector. When | ||
44 | +a disk image has multiple internal snapshots this means that data in | ||
45 | +multiple physical sectors is encrypted with the same initialization | ||
46 | +vector. With the CBC mode, this opens the possibility of watermarking | ||
47 | +attacks if the attack can collect multiple sectors encrypted with the | ||
48 | +same IV and some predictable data. Having multiple qcow2 images with | ||
49 | +the same passphrase also exposes this weakness since the passphrase | ||
50 | +is directly used as the key. | ||
51 | @end itemize | ||
52 | |||
53 | Use of qcow / qcow2 encryption is thus strongly discouraged. Users are | ||
54 | -- | ||
55 | 1.8.3.1 | ||
56 | |||
57 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: "Daniel P. Berrange" <berrange@redhat.com> | ||
2 | 1 | ||
3 | The qcow driver refuses to open images which are less than | ||
4 | 2 bytes in size, but will happily create such images. Add | ||
5 | a check in the create path to avoid this discrepancy. | ||
6 | |||
7 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
8 | Reviewed-by: Alberto Garcia <berto@igalia.com> | ||
9 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
10 | Signed-off-by: Daniel P. Berrange <berrange@redhat.com> | ||
11 | Message-id: 20170623162419.26068-5-berrange@redhat.com | ||
12 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
13 | --- | ||
14 | block/qcow.c | 6 ++++++ | ||
15 | 1 file changed, 6 insertions(+) | ||
16 | |||
17 | diff --git a/block/qcow.c b/block/qcow.c | ||
18 | index XXXXXXX..XXXXXXX 100644 | ||
19 | --- a/block/qcow.c | ||
20 | +++ b/block/qcow.c | ||
21 | @@ -XXX,XX +XXX,XX @@ static int qcow_create(const char *filename, QemuOpts *opts, Error **errp) | ||
22 | /* Read out options */ | ||
23 | total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0), | ||
24 | BDRV_SECTOR_SIZE); | ||
25 | + if (total_size == 0) { | ||
26 | + error_setg(errp, "Image size is too small, cannot be zero length"); | ||
27 | + ret = -EINVAL; | ||
28 | + goto cleanup; | ||
29 | + } | ||
30 | + | ||
31 | backing_file = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE); | ||
32 | if (qemu_opt_get_bool_del(opts, BLOCK_OPT_ENCRYPT, false)) { | ||
33 | flags |= BLOCK_FLAG_ENCRYPT; | ||
34 | -- | ||
35 | 1.8.3.1 | ||
36 | |||
37 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: "Daniel P. Berrange" <berrange@redhat.com> | ||
2 | 1 | ||
3 | Test 042 is designed to verify operation with zero sized images. | ||
4 | Such images are not supported with qcow (v1), so this test has | ||
5 | always failed. | ||
6 | |||
7 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
8 | Reviewed-by: Alberto Garcia <berto@igalia.com> | ||
9 | Signed-off-by: Daniel P. Berrange <berrange@redhat.com> | ||
10 | Message-id: 20170623162419.26068-6-berrange@redhat.com | ||
11 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
12 | --- | ||
13 | tests/qemu-iotests/042 | 2 +- | ||
14 | 1 file changed, 1 insertion(+), 1 deletion(-) | ||
15 | |||
16 | diff --git a/tests/qemu-iotests/042 b/tests/qemu-iotests/042 | ||
17 | index XXXXXXX..XXXXXXX 100755 | ||
18 | --- a/tests/qemu-iotests/042 | ||
19 | +++ b/tests/qemu-iotests/042 | ||
20 | @@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15 | ||
21 | . ./common.rc | ||
22 | . ./common.filter | ||
23 | |||
24 | -_supported_fmt qcow2 qcow qed | ||
25 | +_supported_fmt qcow2 qed | ||
26 | _supported_proto file | ||
27 | _supported_os Linux | ||
28 | |||
29 | -- | ||
30 | 1.8.3.1 | ||
31 | |||
32 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: "Daniel P. Berrange" <berrange@redhat.com> | ||
2 | 1 | ||
3 | Test 048 is designed to verify data preservation during an | ||
4 | image resize. The qcow (v1) format impl has never supported | ||
5 | resize so always fails. | ||
6 | |||
7 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
8 | Reviewed-by: Alberto Garcia <berto@igalia.com> | ||
9 | Signed-off-by: Daniel P. Berrange <berrange@redhat.com> | ||
10 | Message-id: 20170623162419.26068-7-berrange@redhat.com | ||
11 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
12 | --- | ||
13 | tests/qemu-iotests/048 | 2 +- | ||
14 | 1 file changed, 1 insertion(+), 1 deletion(-) | ||
15 | |||
16 | diff --git a/tests/qemu-iotests/048 b/tests/qemu-iotests/048 | ||
17 | index XXXXXXX..XXXXXXX 100755 | ||
18 | --- a/tests/qemu-iotests/048 | ||
19 | +++ b/tests/qemu-iotests/048 | ||
20 | @@ -XXX,XX +XXX,XX @@ _compare() | ||
21 | . ./common.filter | ||
22 | . ./common.pattern | ||
23 | |||
24 | -_supported_fmt raw qcow qcow2 qed luks | ||
25 | +_supported_fmt raw qcow2 qed luks | ||
26 | _supported_proto file | ||
27 | _supported_os Linux | ||
28 | |||
29 | -- | ||
30 | 1.8.3.1 | ||
31 | |||
32 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: "Daniel P. Berrange" <berrange@redhat.com> | ||
2 | 1 | ||
3 | Historically the qcow & qcow2 image formats supported a property | ||
4 | "encryption=on" to enable their built-in AES encryption. We'll | ||
5 | soon be supporting LUKS for qcow2, so need a more general purpose | ||
6 | way to enable encryption, with a choice of formats. | ||
7 | |||
8 | This introduces an "encrypt.format" option, which will later be | ||
9 | joined by a number of other "encrypt.XXX" options. The use of | ||
10 | a "encrypt." prefix instead of "encrypt-" is done to facilitate | ||
11 | mapping to a nested QAPI schema at later date. | ||
12 | |||
13 | e.g. the preferred syntax is now | ||
14 | |||
15 | qemu-img create -f qcow2 -o encrypt.format=aes demo.qcow2 | ||
16 | |||
17 | Signed-off-by: Daniel P. Berrange <berrange@redhat.com> | ||
18 | Message-id: 20170623162419.26068-8-berrange@redhat.com | ||
19 | Reviewed-by: Alberto Garcia <berto@igalia.com> | ||
20 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
21 | --- | ||
22 | block/qcow.c | 31 ++++++++++++--- | ||
23 | block/qcow2.c | 34 ++++++++++++---- | ||
24 | include/block/block_int.h | 2 +- | ||
25 | qemu-img.c | 4 +- | ||
26 | tests/qemu-iotests/049.out | 98 +++++++++++++++++++++++----------------------- | ||
27 | tests/qemu-iotests/082.out | 95 ++++++++++++++++++++++++++++---------------- | ||
28 | tests/qemu-iotests/085.out | 38 +++++++++--------- | ||
29 | tests/qemu-iotests/144.out | 4 +- | ||
30 | tests/qemu-iotests/185.out | 8 ++-- | ||
31 | 9 files changed, 191 insertions(+), 123 deletions(-) | ||
32 | |||
33 | diff --git a/block/qcow.c b/block/qcow.c | ||
34 | index XXXXXXX..XXXXXXX 100644 | ||
35 | --- a/block/qcow.c | ||
36 | +++ b/block/qcow.c | ||
37 | @@ -XXX,XX +XXX,XX @@ static int qcow_create(const char *filename, QemuOpts *opts, Error **errp) | ||
38 | uint8_t *tmp; | ||
39 | int64_t total_size = 0; | ||
40 | char *backing_file = NULL; | ||
41 | - int flags = 0; | ||
42 | Error *local_err = NULL; | ||
43 | int ret; | ||
44 | BlockBackend *qcow_blk; | ||
45 | + const char *encryptfmt = NULL; | ||
46 | |||
47 | /* Read out options */ | ||
48 | total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0), | ||
49 | @@ -XXX,XX +XXX,XX @@ static int qcow_create(const char *filename, QemuOpts *opts, Error **errp) | ||
50 | } | ||
51 | |||
52 | backing_file = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE); | ||
53 | - if (qemu_opt_get_bool_del(opts, BLOCK_OPT_ENCRYPT, false)) { | ||
54 | - flags |= BLOCK_FLAG_ENCRYPT; | ||
55 | + encryptfmt = qemu_opt_get_del(opts, BLOCK_OPT_ENCRYPT_FORMAT); | ||
56 | + if (encryptfmt) { | ||
57 | + if (qemu_opt_get(opts, BLOCK_OPT_ENCRYPT)) { | ||
58 | + error_setg(errp, "Options " BLOCK_OPT_ENCRYPT " and " | ||
59 | + BLOCK_OPT_ENCRYPT_FORMAT " are mutually exclusive"); | ||
60 | + ret = -EINVAL; | ||
61 | + goto cleanup; | ||
62 | + } | ||
63 | + } else if (qemu_opt_get_bool_del(opts, BLOCK_OPT_ENCRYPT, false)) { | ||
64 | + encryptfmt = "aes"; | ||
65 | } | ||
66 | |||
67 | ret = bdrv_create_file(filename, opts, &local_err); | ||
68 | @@ -XXX,XX +XXX,XX @@ static int qcow_create(const char *filename, QemuOpts *opts, Error **errp) | ||
69 | l1_size = (total_size + (1LL << shift) - 1) >> shift; | ||
70 | |||
71 | header.l1_table_offset = cpu_to_be64(header_size); | ||
72 | - if (flags & BLOCK_FLAG_ENCRYPT) { | ||
73 | + if (encryptfmt) { | ||
74 | + if (!g_str_equal(encryptfmt, "aes")) { | ||
75 | + error_setg(errp, "Unknown encryption format '%s', expected 'aes'", | ||
76 | + encryptfmt); | ||
77 | + ret = -EINVAL; | ||
78 | + goto exit; | ||
79 | + } | ||
80 | header.crypt_method = cpu_to_be32(QCOW_CRYPT_AES); | ||
81 | } else { | ||
82 | header.crypt_method = cpu_to_be32(QCOW_CRYPT_NONE); | ||
83 | @@ -XXX,XX +XXX,XX @@ static QemuOptsList qcow_create_opts = { | ||
84 | { | ||
85 | .name = BLOCK_OPT_ENCRYPT, | ||
86 | .type = QEMU_OPT_BOOL, | ||
87 | - .help = "Encrypt the image", | ||
88 | - .def_value_str = "off" | ||
89 | + .help = "Encrypt the image with format 'aes'. (Deprecated " | ||
90 | + "in favor of " BLOCK_OPT_ENCRYPT_FORMAT "=aes)", | ||
91 | + }, | ||
92 | + { | ||
93 | + .name = BLOCK_OPT_ENCRYPT_FORMAT, | ||
94 | + .type = QEMU_OPT_STRING, | ||
95 | + .help = "Encrypt the image, format choices: 'aes'", | ||
96 | }, | ||
97 | { /* end of list */ } | ||
98 | } | ||
99 | diff --git a/block/qcow2.c b/block/qcow2.c | ||
100 | index XXXXXXX..XXXXXXX 100644 | ||
101 | --- a/block/qcow2.c | ||
102 | +++ b/block/qcow2.c | ||
103 | @@ -XXX,XX +XXX,XX @@ static int qcow2_create2(const char *filename, int64_t total_size, | ||
104 | const char *backing_file, const char *backing_format, | ||
105 | int flags, size_t cluster_size, PreallocMode prealloc, | ||
106 | QemuOpts *opts, int version, int refcount_order, | ||
107 | - Error **errp) | ||
108 | + const char *encryptfmt, Error **errp) | ||
109 | { | ||
110 | int cluster_bits; | ||
111 | QDict *options; | ||
112 | @@ -XXX,XX +XXX,XX @@ static int qcow2_create2(const char *filename, int64_t total_size, | ||
113 | .header_length = cpu_to_be32(sizeof(*header)), | ||
114 | }; | ||
115 | |||
116 | - if (flags & BLOCK_FLAG_ENCRYPT) { | ||
117 | + if (encryptfmt) { | ||
118 | + if (!g_str_equal(encryptfmt, "aes")) { | ||
119 | + error_setg(errp, "Unknown encryption format '%s', expected 'aes'", | ||
120 | + encryptfmt); | ||
121 | + ret = -EINVAL; | ||
122 | + goto out; | ||
123 | + } | ||
124 | header->crypt_method = cpu_to_be32(QCOW_CRYPT_AES); | ||
125 | } else { | ||
126 | header->crypt_method = cpu_to_be32(QCOW_CRYPT_NONE); | ||
127 | @@ -XXX,XX +XXX,XX @@ static int qcow2_create(const char *filename, QemuOpts *opts, Error **errp) | ||
128 | int version = 3; | ||
129 | uint64_t refcount_bits = 16; | ||
130 | int refcount_order; | ||
131 | + const char *encryptfmt = NULL; | ||
132 | Error *local_err = NULL; | ||
133 | int ret; | ||
134 | |||
135 | @@ -XXX,XX +XXX,XX @@ static int qcow2_create(const char *filename, QemuOpts *opts, Error **errp) | ||
136 | BDRV_SECTOR_SIZE); | ||
137 | backing_file = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE); | ||
138 | backing_fmt = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FMT); | ||
139 | - if (qemu_opt_get_bool_del(opts, BLOCK_OPT_ENCRYPT, false)) { | ||
140 | - flags |= BLOCK_FLAG_ENCRYPT; | ||
141 | + encryptfmt = qemu_opt_get_del(opts, BLOCK_OPT_ENCRYPT_FORMAT); | ||
142 | + if (encryptfmt) { | ||
143 | + if (qemu_opt_get_del(opts, BLOCK_OPT_ENCRYPT)) { | ||
144 | + error_setg(errp, "Options " BLOCK_OPT_ENCRYPT " and " | ||
145 | + BLOCK_OPT_ENCRYPT_FORMAT " are mutually exclusive"); | ||
146 | + ret = -EINVAL; | ||
147 | + goto finish; | ||
148 | + } | ||
149 | + } else if (qemu_opt_get_bool_del(opts, BLOCK_OPT_ENCRYPT, false)) { | ||
150 | + encryptfmt = "aes"; | ||
151 | } | ||
152 | cluster_size = qemu_opt_get_size_del(opts, BLOCK_OPT_CLUSTER_SIZE, | ||
153 | DEFAULT_CLUSTER_SIZE); | ||
154 | @@ -XXX,XX +XXX,XX @@ static int qcow2_create(const char *filename, QemuOpts *opts, Error **errp) | ||
155 | |||
156 | ret = qcow2_create2(filename, size, backing_file, backing_fmt, flags, | ||
157 | cluster_size, prealloc, opts, version, refcount_order, | ||
158 | - &local_err); | ||
159 | + encryptfmt, &local_err); | ||
160 | error_propagate(errp, local_err); | ||
161 | |||
162 | finish: | ||
163 | @@ -XXX,XX +XXX,XX @@ static QemuOptsList qcow2_create_opts = { | ||
164 | { | ||
165 | .name = BLOCK_OPT_ENCRYPT, | ||
166 | .type = QEMU_OPT_BOOL, | ||
167 | - .help = "Encrypt the image", | ||
168 | - .def_value_str = "off" | ||
169 | + .help = "Encrypt the image with format 'aes'. (Deprecated " | ||
170 | + "in favor of " BLOCK_OPT_ENCRYPT_FORMAT "=aes)", | ||
171 | + }, | ||
172 | + { | ||
173 | + .name = BLOCK_OPT_ENCRYPT_FORMAT, | ||
174 | + .type = QEMU_OPT_STRING, | ||
175 | + .help = "Encrypt the image, format choices: 'aes'", | ||
176 | }, | ||
177 | { | ||
178 | .name = BLOCK_OPT_CLUSTER_SIZE, | ||
179 | diff --git a/include/block/block_int.h b/include/block/block_int.h | ||
180 | index XXXXXXX..XXXXXXX 100644 | ||
181 | --- a/include/block/block_int.h | ||
182 | +++ b/include/block/block_int.h | ||
183 | @@ -XXX,XX +XXX,XX @@ | ||
184 | #include "qemu/main-loop.h" | ||
185 | #include "qemu/throttle.h" | ||
186 | |||
187 | -#define BLOCK_FLAG_ENCRYPT 1 | ||
188 | #define BLOCK_FLAG_LAZY_REFCOUNTS 8 | ||
189 | |||
190 | #define BLOCK_OPT_SIZE "size" | ||
191 | #define BLOCK_OPT_ENCRYPT "encryption" | ||
192 | +#define BLOCK_OPT_ENCRYPT_FORMAT "encrypt.format" | ||
193 | #define BLOCK_OPT_COMPAT6 "compat6" | ||
194 | #define BLOCK_OPT_HWVERSION "hwversion" | ||
195 | #define BLOCK_OPT_BACKING_FILE "backing_file" | ||
196 | diff --git a/qemu-img.c b/qemu-img.c | ||
197 | index XXXXXXX..XXXXXXX 100644 | ||
198 | --- a/qemu-img.c | ||
199 | +++ b/qemu-img.c | ||
200 | @@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv) | ||
201 | if (s.compressed) { | ||
202 | bool encryption = | ||
203 | qemu_opt_get_bool(opts, BLOCK_OPT_ENCRYPT, false); | ||
204 | + const char *encryptfmt = | ||
205 | + qemu_opt_get(opts, BLOCK_OPT_ENCRYPT_FORMAT); | ||
206 | const char *preallocation = | ||
207 | qemu_opt_get(opts, BLOCK_OPT_PREALLOC); | ||
208 | |||
209 | @@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv) | ||
210 | goto out; | ||
211 | } | ||
212 | |||
213 | - if (encryption) { | ||
214 | + if (encryption || encryptfmt) { | ||
215 | error_report("Compression and encryption not supported at " | ||
216 | "the same time"); | ||
217 | ret = -1; | ||
218 | diff --git a/tests/qemu-iotests/049.out b/tests/qemu-iotests/049.out | ||
219 | index XXXXXXX..XXXXXXX 100644 | ||
220 | --- a/tests/qemu-iotests/049.out | ||
221 | +++ b/tests/qemu-iotests/049.out | ||
222 | @@ -XXX,XX +XXX,XX @@ QA output created by 049 | ||
223 | == 1. Traditional size parameter == | ||
224 | |||
225 | qemu-img create -f qcow2 TEST_DIR/t.qcow2 1024 | ||
226 | -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
227 | +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
228 | |||
229 | qemu-img create -f qcow2 TEST_DIR/t.qcow2 1024b | ||
230 | -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
231 | +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
232 | |||
233 | qemu-img create -f qcow2 TEST_DIR/t.qcow2 1k | ||
234 | -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
235 | +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
236 | |||
237 | qemu-img create -f qcow2 TEST_DIR/t.qcow2 1K | ||
238 | -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
239 | +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
240 | |||
241 | qemu-img create -f qcow2 TEST_DIR/t.qcow2 1M | ||
242 | -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1048576 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
243 | +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1048576 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
244 | |||
245 | qemu-img create -f qcow2 TEST_DIR/t.qcow2 1G | ||
246 | -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1073741824 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
247 | +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1073741824 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
248 | |||
249 | qemu-img create -f qcow2 TEST_DIR/t.qcow2 1T | ||
250 | -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1099511627776 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
251 | +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1099511627776 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
252 | |||
253 | qemu-img create -f qcow2 TEST_DIR/t.qcow2 1024.0 | ||
254 | -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
255 | +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
256 | |||
257 | qemu-img create -f qcow2 TEST_DIR/t.qcow2 1024.0b | ||
258 | -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
259 | +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
260 | |||
261 | qemu-img create -f qcow2 TEST_DIR/t.qcow2 1.5k | ||
262 | -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1536 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
263 | +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1536 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
264 | |||
265 | qemu-img create -f qcow2 TEST_DIR/t.qcow2 1.5K | ||
266 | -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1536 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
267 | +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1536 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
268 | |||
269 | qemu-img create -f qcow2 TEST_DIR/t.qcow2 1.5M | ||
270 | -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1572864 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
271 | +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1572864 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
272 | |||
273 | qemu-img create -f qcow2 TEST_DIR/t.qcow2 1.5G | ||
274 | -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1610612736 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
275 | +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1610612736 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
276 | |||
277 | qemu-img create -f qcow2 TEST_DIR/t.qcow2 1.5T | ||
278 | -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1649267441664 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
279 | +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1649267441664 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
280 | |||
281 | == 2. Specifying size via -o == | ||
282 | |||
283 | qemu-img create -f qcow2 -o size=1024 TEST_DIR/t.qcow2 | ||
284 | -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
285 | +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
286 | |||
287 | qemu-img create -f qcow2 -o size=1024b TEST_DIR/t.qcow2 | ||
288 | -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
289 | +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
290 | |||
291 | qemu-img create -f qcow2 -o size=1k TEST_DIR/t.qcow2 | ||
292 | -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
293 | +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
294 | |||
295 | qemu-img create -f qcow2 -o size=1K TEST_DIR/t.qcow2 | ||
296 | -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
297 | +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
298 | |||
299 | qemu-img create -f qcow2 -o size=1M TEST_DIR/t.qcow2 | ||
300 | -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1048576 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
301 | +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1048576 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
302 | |||
303 | qemu-img create -f qcow2 -o size=1G TEST_DIR/t.qcow2 | ||
304 | -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1073741824 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
305 | +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1073741824 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
306 | |||
307 | qemu-img create -f qcow2 -o size=1T TEST_DIR/t.qcow2 | ||
308 | -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1099511627776 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
309 | +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1099511627776 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
310 | |||
311 | qemu-img create -f qcow2 -o size=1024.0 TEST_DIR/t.qcow2 | ||
312 | -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
313 | +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
314 | |||
315 | qemu-img create -f qcow2 -o size=1024.0b TEST_DIR/t.qcow2 | ||
316 | -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
317 | +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
318 | |||
319 | qemu-img create -f qcow2 -o size=1.5k TEST_DIR/t.qcow2 | ||
320 | -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1536 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
321 | +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1536 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
322 | |||
323 | qemu-img create -f qcow2 -o size=1.5K TEST_DIR/t.qcow2 | ||
324 | -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1536 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
325 | +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1536 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
326 | |||
327 | qemu-img create -f qcow2 -o size=1.5M TEST_DIR/t.qcow2 | ||
328 | -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1572864 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
329 | +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1572864 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
330 | |||
331 | qemu-img create -f qcow2 -o size=1.5G TEST_DIR/t.qcow2 | ||
332 | -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1610612736 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
333 | +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1610612736 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
334 | |||
335 | qemu-img create -f qcow2 -o size=1.5T TEST_DIR/t.qcow2 | ||
336 | -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1649267441664 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
337 | +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1649267441664 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
338 | |||
339 | == 3. Invalid sizes == | ||
340 | |||
341 | @@ -XXX,XX +XXX,XX @@ qemu-img: TEST_DIR/t.qcow2: Invalid options for file format 'qcow2' | ||
342 | == Check correct interpretation of suffixes for cluster size == | ||
343 | |||
344 | qemu-img create -f qcow2 -o cluster_size=1024 TEST_DIR/t.qcow2 64M | ||
345 | -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=1024 lazy_refcounts=off refcount_bits=16 | ||
346 | +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=1024 lazy_refcounts=off refcount_bits=16 | ||
347 | |||
348 | qemu-img create -f qcow2 -o cluster_size=1024b TEST_DIR/t.qcow2 64M | ||
349 | -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=1024 lazy_refcounts=off refcount_bits=16 | ||
350 | +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=1024 lazy_refcounts=off refcount_bits=16 | ||
351 | |||
352 | qemu-img create -f qcow2 -o cluster_size=1k TEST_DIR/t.qcow2 64M | ||
353 | -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=1024 lazy_refcounts=off refcount_bits=16 | ||
354 | +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=1024 lazy_refcounts=off refcount_bits=16 | ||
355 | |||
356 | qemu-img create -f qcow2 -o cluster_size=1K TEST_DIR/t.qcow2 64M | ||
357 | -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=1024 lazy_refcounts=off refcount_bits=16 | ||
358 | +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=1024 lazy_refcounts=off refcount_bits=16 | ||
359 | |||
360 | qemu-img create -f qcow2 -o cluster_size=1M TEST_DIR/t.qcow2 64M | ||
361 | -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=1048576 lazy_refcounts=off refcount_bits=16 | ||
362 | +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=1048576 lazy_refcounts=off refcount_bits=16 | ||
363 | |||
364 | qemu-img create -f qcow2 -o cluster_size=1024.0 TEST_DIR/t.qcow2 64M | ||
365 | -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=1024 lazy_refcounts=off refcount_bits=16 | ||
366 | +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=1024 lazy_refcounts=off refcount_bits=16 | ||
367 | |||
368 | qemu-img create -f qcow2 -o cluster_size=1024.0b TEST_DIR/t.qcow2 64M | ||
369 | -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=1024 lazy_refcounts=off refcount_bits=16 | ||
370 | +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=1024 lazy_refcounts=off refcount_bits=16 | ||
371 | |||
372 | qemu-img create -f qcow2 -o cluster_size=0.5k TEST_DIR/t.qcow2 64M | ||
373 | -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=512 lazy_refcounts=off refcount_bits=16 | ||
374 | +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=512 lazy_refcounts=off refcount_bits=16 | ||
375 | |||
376 | qemu-img create -f qcow2 -o cluster_size=0.5K TEST_DIR/t.qcow2 64M | ||
377 | -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=512 lazy_refcounts=off refcount_bits=16 | ||
378 | +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=512 lazy_refcounts=off refcount_bits=16 | ||
379 | |||
380 | qemu-img create -f qcow2 -o cluster_size=0.5M TEST_DIR/t.qcow2 64M | ||
381 | -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=524288 lazy_refcounts=off refcount_bits=16 | ||
382 | +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=524288 lazy_refcounts=off refcount_bits=16 | ||
383 | |||
384 | == Check compat level option == | ||
385 | |||
386 | qemu-img create -f qcow2 -o compat=0.10 TEST_DIR/t.qcow2 64M | ||
387 | -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=0.10 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
388 | +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=0.10 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
389 | |||
390 | qemu-img create -f qcow2 -o compat=1.1 TEST_DIR/t.qcow2 64M | ||
391 | -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=1.1 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
392 | +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=1.1 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
393 | |||
394 | qemu-img create -f qcow2 -o compat=0.42 TEST_DIR/t.qcow2 64M | ||
395 | qemu-img: TEST_DIR/t.qcow2: Invalid compatibility level: '0.42' | ||
396 | -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=0.42 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
397 | +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=0.42 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
398 | |||
399 | qemu-img create -f qcow2 -o compat=foobar TEST_DIR/t.qcow2 64M | ||
400 | qemu-img: TEST_DIR/t.qcow2: Invalid compatibility level: 'foobar' | ||
401 | -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=foobar encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
402 | +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=foobar cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
403 | |||
404 | == Check preallocation option == | ||
405 | |||
406 | qemu-img create -f qcow2 -o preallocation=off TEST_DIR/t.qcow2 64M | ||
407 | -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=65536 preallocation=off lazy_refcounts=off refcount_bits=16 | ||
408 | +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=65536 preallocation=off lazy_refcounts=off refcount_bits=16 | ||
409 | |||
410 | qemu-img create -f qcow2 -o preallocation=metadata TEST_DIR/t.qcow2 64M | ||
411 | -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=65536 preallocation=metadata lazy_refcounts=off refcount_bits=16 | ||
412 | +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=65536 preallocation=metadata lazy_refcounts=off refcount_bits=16 | ||
413 | |||
414 | qemu-img create -f qcow2 -o preallocation=1234 TEST_DIR/t.qcow2 64M | ||
415 | qemu-img: TEST_DIR/t.qcow2: invalid parameter value: 1234 | ||
416 | -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=65536 preallocation=1234 lazy_refcounts=off refcount_bits=16 | ||
417 | +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=65536 preallocation=1234 lazy_refcounts=off refcount_bits=16 | ||
418 | |||
419 | == Check encryption option == | ||
420 | |||
421 | @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=on cluster_siz | ||
422 | == Check lazy_refcounts option (only with v3) == | ||
423 | |||
424 | qemu-img create -f qcow2 -o compat=1.1,lazy_refcounts=off TEST_DIR/t.qcow2 64M | ||
425 | -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=1.1 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
426 | +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=1.1 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
427 | |||
428 | qemu-img create -f qcow2 -o compat=1.1,lazy_refcounts=on TEST_DIR/t.qcow2 64M | ||
429 | -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=1.1 encryption=off cluster_size=65536 lazy_refcounts=on refcount_bits=16 | ||
430 | +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=1.1 cluster_size=65536 lazy_refcounts=on refcount_bits=16 | ||
431 | |||
432 | qemu-img create -f qcow2 -o compat=0.10,lazy_refcounts=off TEST_DIR/t.qcow2 64M | ||
433 | -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=0.10 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
434 | +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=0.10 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
435 | |||
436 | qemu-img create -f qcow2 -o compat=0.10,lazy_refcounts=on TEST_DIR/t.qcow2 64M | ||
437 | qemu-img: TEST_DIR/t.qcow2: Lazy refcounts only supported with compatibility level 1.1 and above (use compat=1.1 or greater) | ||
438 | -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=0.10 encryption=off cluster_size=65536 lazy_refcounts=on refcount_bits=16 | ||
439 | +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=0.10 cluster_size=65536 lazy_refcounts=on refcount_bits=16 | ||
440 | |||
441 | *** done | ||
442 | diff --git a/tests/qemu-iotests/082.out b/tests/qemu-iotests/082.out | ||
443 | index XXXXXXX..XXXXXXX 100644 | ||
444 | --- a/tests/qemu-iotests/082.out | ||
445 | +++ b/tests/qemu-iotests/082.out | ||
446 | @@ -XXX,XX +XXX,XX @@ QA output created by 082 | ||
447 | === create: Options specified more than once === | ||
448 | |||
449 | Testing: create -f foo -f qcow2 TEST_DIR/t.qcow2 128M | ||
450 | -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
451 | +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
452 | image: TEST_DIR/t.IMGFMT | ||
453 | file format: IMGFMT | ||
454 | virtual size: 128M (134217728 bytes) | ||
455 | cluster_size: 65536 | ||
456 | |||
457 | Testing: create -f qcow2 -o cluster_size=4k -o lazy_refcounts=on TEST_DIR/t.qcow2 128M | ||
458 | -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 encryption=off cluster_size=4096 lazy_refcounts=on refcount_bits=16 | ||
459 | +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 cluster_size=4096 lazy_refcounts=on refcount_bits=16 | ||
460 | image: TEST_DIR/t.IMGFMT | ||
461 | file format: IMGFMT | ||
462 | virtual size: 128M (134217728 bytes) | ||
463 | @@ -XXX,XX +XXX,XX @@ Format specific information: | ||
464 | corrupt: false | ||
465 | |||
466 | Testing: create -f qcow2 -o cluster_size=4k -o lazy_refcounts=on -o cluster_size=8k TEST_DIR/t.qcow2 128M | ||
467 | -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 encryption=off cluster_size=8192 lazy_refcounts=on refcount_bits=16 | ||
468 | +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 cluster_size=8192 lazy_refcounts=on refcount_bits=16 | ||
469 | image: TEST_DIR/t.IMGFMT | ||
470 | file format: IMGFMT | ||
471 | virtual size: 128M (134217728 bytes) | ||
472 | @@ -XXX,XX +XXX,XX @@ Format specific information: | ||
473 | corrupt: false | ||
474 | |||
475 | Testing: create -f qcow2 -o cluster_size=4k,cluster_size=8k TEST_DIR/t.qcow2 128M | ||
476 | -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 encryption=off cluster_size=8192 lazy_refcounts=off refcount_bits=16 | ||
477 | +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 cluster_size=8192 lazy_refcounts=off refcount_bits=16 | ||
478 | image: TEST_DIR/t.IMGFMT | ||
479 | file format: IMGFMT | ||
480 | virtual size: 128M (134217728 bytes) | ||
481 | @@ -XXX,XX +XXX,XX @@ size Virtual disk size | ||
482 | compat Compatibility level (0.10 or 1.1) | ||
483 | backing_file File name of a base image | ||
484 | backing_fmt Image format of the base image | ||
485 | -encryption Encrypt the image | ||
486 | +encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
487 | +encrypt.format Encrypt the image, format choices: 'aes' | ||
488 | cluster_size qcow2 cluster size | ||
489 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
490 | lazy_refcounts Postpone refcount updates | ||
491 | @@ -XXX,XX +XXX,XX @@ size Virtual disk size | ||
492 | compat Compatibility level (0.10 or 1.1) | ||
493 | backing_file File name of a base image | ||
494 | backing_fmt Image format of the base image | ||
495 | -encryption Encrypt the image | ||
496 | +encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
497 | +encrypt.format Encrypt the image, format choices: 'aes' | ||
498 | cluster_size qcow2 cluster size | ||
499 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
500 | lazy_refcounts Postpone refcount updates | ||
501 | @@ -XXX,XX +XXX,XX @@ size Virtual disk size | ||
502 | compat Compatibility level (0.10 or 1.1) | ||
503 | backing_file File name of a base image | ||
504 | backing_fmt Image format of the base image | ||
505 | -encryption Encrypt the image | ||
506 | +encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
507 | +encrypt.format Encrypt the image, format choices: 'aes' | ||
508 | cluster_size qcow2 cluster size | ||
509 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
510 | lazy_refcounts Postpone refcount updates | ||
511 | @@ -XXX,XX +XXX,XX @@ size Virtual disk size | ||
512 | compat Compatibility level (0.10 or 1.1) | ||
513 | backing_file File name of a base image | ||
514 | backing_fmt Image format of the base image | ||
515 | -encryption Encrypt the image | ||
516 | +encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
517 | +encrypt.format Encrypt the image, format choices: 'aes' | ||
518 | cluster_size qcow2 cluster size | ||
519 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
520 | lazy_refcounts Postpone refcount updates | ||
521 | @@ -XXX,XX +XXX,XX @@ size Virtual disk size | ||
522 | compat Compatibility level (0.10 or 1.1) | ||
523 | backing_file File name of a base image | ||
524 | backing_fmt Image format of the base image | ||
525 | -encryption Encrypt the image | ||
526 | +encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
527 | +encrypt.format Encrypt the image, format choices: 'aes' | ||
528 | cluster_size qcow2 cluster size | ||
529 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
530 | lazy_refcounts Postpone refcount updates | ||
531 | @@ -XXX,XX +XXX,XX @@ size Virtual disk size | ||
532 | compat Compatibility level (0.10 or 1.1) | ||
533 | backing_file File name of a base image | ||
534 | backing_fmt Image format of the base image | ||
535 | -encryption Encrypt the image | ||
536 | +encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
537 | +encrypt.format Encrypt the image, format choices: 'aes' | ||
538 | cluster_size qcow2 cluster size | ||
539 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
540 | lazy_refcounts Postpone refcount updates | ||
541 | @@ -XXX,XX +XXX,XX @@ size Virtual disk size | ||
542 | compat Compatibility level (0.10 or 1.1) | ||
543 | backing_file File name of a base image | ||
544 | backing_fmt Image format of the base image | ||
545 | -encryption Encrypt the image | ||
546 | +encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
547 | +encrypt.format Encrypt the image, format choices: 'aes' | ||
548 | cluster_size qcow2 cluster size | ||
549 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
550 | lazy_refcounts Postpone refcount updates | ||
551 | @@ -XXX,XX +XXX,XX @@ size Virtual disk size | ||
552 | compat Compatibility level (0.10 or 1.1) | ||
553 | backing_file File name of a base image | ||
554 | backing_fmt Image format of the base image | ||
555 | -encryption Encrypt the image | ||
556 | +encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
557 | +encrypt.format Encrypt the image, format choices: 'aes' | ||
558 | cluster_size qcow2 cluster size | ||
559 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
560 | lazy_refcounts Postpone refcount updates | ||
561 | @@ -XXX,XX +XXX,XX @@ refcount_bits Width of a reference count entry in bits | ||
562 | nocow Turn off copy-on-write (valid only on btrfs) | ||
563 | |||
564 | Testing: create -f qcow2 -o backing_file=TEST_DIR/t.qcow2,,help TEST_DIR/t.qcow2 128M | ||
565 | -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/t.qcow2,,help encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
566 | +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/t.qcow2,,help cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
567 | |||
568 | Testing: create -f qcow2 -o backing_file=TEST_DIR/t.qcow2,,? TEST_DIR/t.qcow2 128M | ||
569 | -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/t.qcow2,,? encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
570 | +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/t.qcow2,,? cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
571 | |||
572 | Testing: create -f qcow2 -o backing_file=TEST_DIR/t.qcow2, -o help TEST_DIR/t.qcow2 128M | ||
573 | qemu-img: Invalid option list: backing_file=TEST_DIR/t.qcow2, | ||
574 | @@ -XXX,XX +XXX,XX @@ size Virtual disk size | ||
575 | compat Compatibility level (0.10 or 1.1) | ||
576 | backing_file File name of a base image | ||
577 | backing_fmt Image format of the base image | ||
578 | -encryption Encrypt the image | ||
579 | +encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
580 | +encrypt.format Encrypt the image, format choices: 'aes' | ||
581 | cluster_size qcow2 cluster size | ||
582 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
583 | lazy_refcounts Postpone refcount updates | ||
584 | @@ -XXX,XX +XXX,XX @@ size Virtual disk size | ||
585 | === convert: Options specified more than once === | ||
586 | |||
587 | Testing: create -f qcow2 TEST_DIR/t.qcow2 128M | ||
588 | -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
589 | +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
590 | |||
591 | Testing: convert -f foo -f qcow2 TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base | ||
592 | image: TEST_DIR/t.IMGFMT.base | ||
593 | @@ -XXX,XX +XXX,XX @@ size Virtual disk size | ||
594 | compat Compatibility level (0.10 or 1.1) | ||
595 | backing_file File name of a base image | ||
596 | backing_fmt Image format of the base image | ||
597 | -encryption Encrypt the image | ||
598 | +encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
599 | +encrypt.format Encrypt the image, format choices: 'aes' | ||
600 | cluster_size qcow2 cluster size | ||
601 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
602 | lazy_refcounts Postpone refcount updates | ||
603 | @@ -XXX,XX +XXX,XX @@ size Virtual disk size | ||
604 | compat Compatibility level (0.10 or 1.1) | ||
605 | backing_file File name of a base image | ||
606 | backing_fmt Image format of the base image | ||
607 | -encryption Encrypt the image | ||
608 | +encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
609 | +encrypt.format Encrypt the image, format choices: 'aes' | ||
610 | cluster_size qcow2 cluster size | ||
611 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
612 | lazy_refcounts Postpone refcount updates | ||
613 | @@ -XXX,XX +XXX,XX @@ size Virtual disk size | ||
614 | compat Compatibility level (0.10 or 1.1) | ||
615 | backing_file File name of a base image | ||
616 | backing_fmt Image format of the base image | ||
617 | -encryption Encrypt the image | ||
618 | +encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
619 | +encrypt.format Encrypt the image, format choices: 'aes' | ||
620 | cluster_size qcow2 cluster size | ||
621 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
622 | lazy_refcounts Postpone refcount updates | ||
623 | @@ -XXX,XX +XXX,XX @@ size Virtual disk size | ||
624 | compat Compatibility level (0.10 or 1.1) | ||
625 | backing_file File name of a base image | ||
626 | backing_fmt Image format of the base image | ||
627 | -encryption Encrypt the image | ||
628 | +encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
629 | +encrypt.format Encrypt the image, format choices: 'aes' | ||
630 | cluster_size qcow2 cluster size | ||
631 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
632 | lazy_refcounts Postpone refcount updates | ||
633 | @@ -XXX,XX +XXX,XX @@ size Virtual disk size | ||
634 | compat Compatibility level (0.10 or 1.1) | ||
635 | backing_file File name of a base image | ||
636 | backing_fmt Image format of the base image | ||
637 | -encryption Encrypt the image | ||
638 | +encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
639 | +encrypt.format Encrypt the image, format choices: 'aes' | ||
640 | cluster_size qcow2 cluster size | ||
641 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
642 | lazy_refcounts Postpone refcount updates | ||
643 | @@ -XXX,XX +XXX,XX @@ size Virtual disk size | ||
644 | compat Compatibility level (0.10 or 1.1) | ||
645 | backing_file File name of a base image | ||
646 | backing_fmt Image format of the base image | ||
647 | -encryption Encrypt the image | ||
648 | +encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
649 | +encrypt.format Encrypt the image, format choices: 'aes' | ||
650 | cluster_size qcow2 cluster size | ||
651 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
652 | lazy_refcounts Postpone refcount updates | ||
653 | @@ -XXX,XX +XXX,XX @@ size Virtual disk size | ||
654 | compat Compatibility level (0.10 or 1.1) | ||
655 | backing_file File name of a base image | ||
656 | backing_fmt Image format of the base image | ||
657 | -encryption Encrypt the image | ||
658 | +encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
659 | +encrypt.format Encrypt the image, format choices: 'aes' | ||
660 | cluster_size qcow2 cluster size | ||
661 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
662 | lazy_refcounts Postpone refcount updates | ||
663 | @@ -XXX,XX +XXX,XX @@ size Virtual disk size | ||
664 | compat Compatibility level (0.10 or 1.1) | ||
665 | backing_file File name of a base image | ||
666 | backing_fmt Image format of the base image | ||
667 | -encryption Encrypt the image | ||
668 | +encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
669 | +encrypt.format Encrypt the image, format choices: 'aes' | ||
670 | cluster_size qcow2 cluster size | ||
671 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
672 | lazy_refcounts Postpone refcount updates | ||
673 | @@ -XXX,XX +XXX,XX @@ size Virtual disk size | ||
674 | compat Compatibility level (0.10 or 1.1) | ||
675 | backing_file File name of a base image | ||
676 | backing_fmt Image format of the base image | ||
677 | -encryption Encrypt the image | ||
678 | +encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
679 | +encrypt.format Encrypt the image, format choices: 'aes' | ||
680 | cluster_size qcow2 cluster size | ||
681 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
682 | lazy_refcounts Postpone refcount updates | ||
683 | @@ -XXX,XX +XXX,XX @@ size Virtual disk size | ||
684 | compat Compatibility level (0.10 or 1.1) | ||
685 | backing_file File name of a base image | ||
686 | backing_fmt Image format of the base image | ||
687 | -encryption Encrypt the image | ||
688 | +encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
689 | +encrypt.format Encrypt the image, format choices: 'aes' | ||
690 | cluster_size qcow2 cluster size | ||
691 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
692 | lazy_refcounts Postpone refcount updates | ||
693 | @@ -XXX,XX +XXX,XX @@ size Virtual disk size | ||
694 | compat Compatibility level (0.10 or 1.1) | ||
695 | backing_file File name of a base image | ||
696 | backing_fmt Image format of the base image | ||
697 | -encryption Encrypt the image | ||
698 | +encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
699 | +encrypt.format Encrypt the image, format choices: 'aes' | ||
700 | cluster_size qcow2 cluster size | ||
701 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
702 | lazy_refcounts Postpone refcount updates | ||
703 | @@ -XXX,XX +XXX,XX @@ size Virtual disk size | ||
704 | compat Compatibility level (0.10 or 1.1) | ||
705 | backing_file File name of a base image | ||
706 | backing_fmt Image format of the base image | ||
707 | -encryption Encrypt the image | ||
708 | +encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
709 | +encrypt.format Encrypt the image, format choices: 'aes' | ||
710 | cluster_size qcow2 cluster size | ||
711 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
712 | lazy_refcounts Postpone refcount updates | ||
713 | @@ -XXX,XX +XXX,XX @@ size Virtual disk size | ||
714 | compat Compatibility level (0.10 or 1.1) | ||
715 | backing_file File name of a base image | ||
716 | backing_fmt Image format of the base image | ||
717 | -encryption Encrypt the image | ||
718 | +encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
719 | +encrypt.format Encrypt the image, format choices: 'aes' | ||
720 | cluster_size qcow2 cluster size | ||
721 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
722 | lazy_refcounts Postpone refcount updates | ||
723 | @@ -XXX,XX +XXX,XX @@ size Virtual disk size | ||
724 | compat Compatibility level (0.10 or 1.1) | ||
725 | backing_file File name of a base image | ||
726 | backing_fmt Image format of the base image | ||
727 | -encryption Encrypt the image | ||
728 | +encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
729 | +encrypt.format Encrypt the image, format choices: 'aes' | ||
730 | cluster_size qcow2 cluster size | ||
731 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
732 | lazy_refcounts Postpone refcount updates | ||
733 | @@ -XXX,XX +XXX,XX @@ size Virtual disk size | ||
734 | compat Compatibility level (0.10 or 1.1) | ||
735 | backing_file File name of a base image | ||
736 | backing_fmt Image format of the base image | ||
737 | -encryption Encrypt the image | ||
738 | +encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
739 | +encrypt.format Encrypt the image, format choices: 'aes' | ||
740 | cluster_size qcow2 cluster size | ||
741 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
742 | lazy_refcounts Postpone refcount updates | ||
743 | @@ -XXX,XX +XXX,XX @@ size Virtual disk size | ||
744 | compat Compatibility level (0.10 or 1.1) | ||
745 | backing_file File name of a base image | ||
746 | backing_fmt Image format of the base image | ||
747 | -encryption Encrypt the image | ||
748 | +encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
749 | +encrypt.format Encrypt the image, format choices: 'aes' | ||
750 | cluster_size qcow2 cluster size | ||
751 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
752 | lazy_refcounts Postpone refcount updates | ||
753 | @@ -XXX,XX +XXX,XX @@ size Virtual disk size | ||
754 | compat Compatibility level (0.10 or 1.1) | ||
755 | backing_file File name of a base image | ||
756 | backing_fmt Image format of the base image | ||
757 | -encryption Encrypt the image | ||
758 | +encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
759 | +encrypt.format Encrypt the image, format choices: 'aes' | ||
760 | cluster_size qcow2 cluster size | ||
761 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
762 | lazy_refcounts Postpone refcount updates | ||
763 | @@ -XXX,XX +XXX,XX @@ size Virtual disk size | ||
764 | compat Compatibility level (0.10 or 1.1) | ||
765 | backing_file File name of a base image | ||
766 | backing_fmt Image format of the base image | ||
767 | -encryption Encrypt the image | ||
768 | +encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) | ||
769 | +encrypt.format Encrypt the image, format choices: 'aes' | ||
770 | cluster_size qcow2 cluster size | ||
771 | preallocation Preallocation mode (allowed values: off, metadata, falloc, full) | ||
772 | lazy_refcounts Postpone refcount updates | ||
773 | diff --git a/tests/qemu-iotests/085.out b/tests/qemu-iotests/085.out | ||
774 | index XXXXXXX..XXXXXXX 100644 | ||
775 | --- a/tests/qemu-iotests/085.out | ||
776 | +++ b/tests/qemu-iotests/085.out | ||
777 | @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 | ||
778 | |||
779 | === Create a single snapshot on virtio0 === | ||
780 | |||
781 | -Formatting 'TEST_DIR/1-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/t.qcow2.1 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
782 | +Formatting 'TEST_DIR/1-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/t.qcow2.1 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
783 | {"return": {}} | ||
784 | |||
785 | === Invalid command - missing device and nodename === | ||
786 | @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/1-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file | ||
787 | |||
788 | === Create several transactional group snapshots === | ||
789 | |||
790 | -Formatting 'TEST_DIR/2-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/1-snapshot-v0.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
791 | -Formatting 'TEST_DIR/2-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/t.qcow2.2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
792 | +Formatting 'TEST_DIR/2-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/1-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
793 | +Formatting 'TEST_DIR/2-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/t.qcow2.2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
794 | {"return": {}} | ||
795 | -Formatting 'TEST_DIR/3-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/2-snapshot-v0.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
796 | -Formatting 'TEST_DIR/3-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/2-snapshot-v1.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
797 | +Formatting 'TEST_DIR/3-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/2-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
798 | +Formatting 'TEST_DIR/3-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/2-snapshot-v1.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
799 | {"return": {}} | ||
800 | -Formatting 'TEST_DIR/4-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/3-snapshot-v0.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
801 | -Formatting 'TEST_DIR/4-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/3-snapshot-v1.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
802 | +Formatting 'TEST_DIR/4-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/3-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
803 | +Formatting 'TEST_DIR/4-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/3-snapshot-v1.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
804 | {"return": {}} | ||
805 | -Formatting 'TEST_DIR/5-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/4-snapshot-v0.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
806 | -Formatting 'TEST_DIR/5-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/4-snapshot-v1.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
807 | +Formatting 'TEST_DIR/5-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/4-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
808 | +Formatting 'TEST_DIR/5-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/4-snapshot-v1.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
809 | {"return": {}} | ||
810 | -Formatting 'TEST_DIR/6-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/5-snapshot-v0.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
811 | -Formatting 'TEST_DIR/6-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/5-snapshot-v1.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
812 | +Formatting 'TEST_DIR/6-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/5-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
813 | +Formatting 'TEST_DIR/6-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/5-snapshot-v1.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
814 | {"return": {}} | ||
815 | -Formatting 'TEST_DIR/7-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/6-snapshot-v0.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
816 | -Formatting 'TEST_DIR/7-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/6-snapshot-v1.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
817 | +Formatting 'TEST_DIR/7-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/6-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
818 | +Formatting 'TEST_DIR/7-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/6-snapshot-v1.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
819 | {"return": {}} | ||
820 | -Formatting 'TEST_DIR/8-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/7-snapshot-v0.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
821 | -Formatting 'TEST_DIR/8-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/7-snapshot-v1.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
822 | +Formatting 'TEST_DIR/8-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/7-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
823 | +Formatting 'TEST_DIR/8-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/7-snapshot-v1.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
824 | {"return": {}} | ||
825 | -Formatting 'TEST_DIR/9-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/8-snapshot-v0.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
826 | -Formatting 'TEST_DIR/9-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/8-snapshot-v1.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
827 | +Formatting 'TEST_DIR/9-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/8-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
828 | +Formatting 'TEST_DIR/9-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/8-snapshot-v1.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
829 | {"return": {}} | ||
830 | -Formatting 'TEST_DIR/10-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/9-snapshot-v0.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
831 | -Formatting 'TEST_DIR/10-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/9-snapshot-v1.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
832 | +Formatting 'TEST_DIR/10-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/9-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
833 | +Formatting 'TEST_DIR/10-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/9-snapshot-v1.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
834 | {"return": {}} | ||
835 | |||
836 | === Create a couple of snapshots using blockdev-snapshot === | ||
837 | diff --git a/tests/qemu-iotests/144.out b/tests/qemu-iotests/144.out | ||
838 | index XXXXXXX..XXXXXXX 100644 | ||
839 | --- a/tests/qemu-iotests/144.out | ||
840 | +++ b/tests/qemu-iotests/144.out | ||
841 | @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=536870912 | ||
842 | === Performing Live Snapshot 1 === | ||
843 | |||
844 | {"return": {}} | ||
845 | -Formatting 'TEST_DIR/tmp.qcow2', fmt=qcow2 size=536870912 backing_file=TEST_DIR/t.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
846 | +Formatting 'TEST_DIR/tmp.qcow2', fmt=qcow2 size=536870912 backing_file=TEST_DIR/t.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
847 | {"return": {}} | ||
848 | |||
849 | === Performing block-commit on active layer === | ||
850 | @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/tmp.qcow2', fmt=qcow2 size=536870912 backing_file=TEST_DIR/ | ||
851 | |||
852 | === Performing Live Snapshot 2 === | ||
853 | |||
854 | -Formatting 'TEST_DIR/tmp2.qcow2', fmt=qcow2 size=536870912 backing_file=TEST_DIR/t.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
855 | +Formatting 'TEST_DIR/tmp2.qcow2', fmt=qcow2 size=536870912 backing_file=TEST_DIR/t.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
856 | {"return": {}} | ||
857 | *** done | ||
858 | diff --git a/tests/qemu-iotests/185.out b/tests/qemu-iotests/185.out | ||
859 | index XXXXXXX..XXXXXXX 100644 | ||
860 | --- a/tests/qemu-iotests/185.out | ||
861 | +++ b/tests/qemu-iotests/185.out | ||
862 | @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864 | ||
863 | |||
864 | === Creating backing chain === | ||
865 | |||
866 | -Formatting 'TEST_DIR/t.qcow2.mid', fmt=qcow2 size=67108864 backing_file=TEST_DIR/t.qcow2.base backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
867 | +Formatting 'TEST_DIR/t.qcow2.mid', fmt=qcow2 size=67108864 backing_file=TEST_DIR/t.qcow2.base backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
868 | {"return": {}} | ||
869 | wrote 4194304/4194304 bytes at offset 0 | ||
870 | 4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
871 | {"return": ""} | ||
872 | -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 backing_file=TEST_DIR/t.qcow2.mid backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
873 | +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 backing_file=TEST_DIR/t.qcow2.mid backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
874 | {"return": {}} | ||
875 | |||
876 | === Start commit job and exit qemu === | ||
877 | @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 backing_file=TEST_DIR/t.q | ||
878 | === Start mirror job and exit qemu === | ||
879 | |||
880 | {"return": {}} | ||
881 | -Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 size=67108864 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
882 | +Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 size=67108864 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
883 | {"return": {}} | ||
884 | {"return": {}} | ||
885 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} | ||
886 | @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 size=67108864 encryption=off clust | ||
887 | === Start backup job and exit qemu === | ||
888 | |||
889 | {"return": {}} | ||
890 | -Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 size=67108864 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
891 | +Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 size=67108864 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
892 | {"return": {}} | ||
893 | {"return": {}} | ||
894 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} | ||
895 | -- | ||
896 | 1.8.3.1 | ||
897 | |||
898 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: "Daniel P. Berrange" <berrange@redhat.com> | ||
2 | 1 | ||
3 | Instead of requiring separate input/output buffers for | ||
4 | encrypting data, change encrypt_sectors() to assume | ||
5 | use of a single buffer, encrypting in place. One current | ||
6 | caller uses the same buffer for input/output already | ||
7 | and the other two callers are easily converted to do so. | ||
8 | |||
9 | Reviewed-by: Alberto Garcia <berto@igalia.com> | ||
10 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
11 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
12 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
13 | Signed-off-by: Daniel P. Berrange <berrange@redhat.com> | ||
14 | Message-id: 20170623162419.26068-9-berrange@redhat.com | ||
15 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
16 | --- | ||
17 | block/qcow.c | 45 +++++++++++++++------------------------------ | ||
18 | 1 file changed, 15 insertions(+), 30 deletions(-) | ||
19 | |||
20 | diff --git a/block/qcow.c b/block/qcow.c | ||
21 | index XXXXXXX..XXXXXXX 100644 | ||
22 | --- a/block/qcow.c | ||
23 | +++ b/block/qcow.c | ||
24 | @@ -XXX,XX +XXX,XX @@ static int qcow_set_key(BlockDriverState *bs, const char *key) | ||
25 | } | ||
26 | |||
27 | /* The crypt function is compatible with the linux cryptoloop | ||
28 | - algorithm for < 4 GB images. NOTE: out_buf == in_buf is | ||
29 | - supported */ | ||
30 | + algorithm for < 4 GB images. */ | ||
31 | static int encrypt_sectors(BDRVQcowState *s, int64_t sector_num, | ||
32 | - uint8_t *out_buf, const uint8_t *in_buf, | ||
33 | - int nb_sectors, bool enc, Error **errp) | ||
34 | + uint8_t *buf, int nb_sectors, bool enc, | ||
35 | + Error **errp) | ||
36 | { | ||
37 | union { | ||
38 | uint64_t ll[2]; | ||
39 | @@ -XXX,XX +XXX,XX @@ static int encrypt_sectors(BDRVQcowState *s, int64_t sector_num, | ||
40 | } | ||
41 | if (enc) { | ||
42 | ret = qcrypto_cipher_encrypt(s->cipher, | ||
43 | - in_buf, | ||
44 | - out_buf, | ||
45 | + buf, buf, | ||
46 | 512, | ||
47 | errp); | ||
48 | } else { | ||
49 | ret = qcrypto_cipher_decrypt(s->cipher, | ||
50 | - in_buf, | ||
51 | - out_buf, | ||
52 | + buf, buf, | ||
53 | 512, | ||
54 | errp); | ||
55 | } | ||
56 | @@ -XXX,XX +XXX,XX @@ static int encrypt_sectors(BDRVQcowState *s, int64_t sector_num, | ||
57 | return -1; | ||
58 | } | ||
59 | sector_num++; | ||
60 | - in_buf += 512; | ||
61 | - out_buf += 512; | ||
62 | + buf += 512; | ||
63 | } | ||
64 | return 0; | ||
65 | } | ||
66 | @@ -XXX,XX +XXX,XX @@ static uint64_t get_cluster_offset(BlockDriverState *bs, | ||
67 | uint64_t start_sect; | ||
68 | assert(s->cipher); | ||
69 | start_sect = (offset & ~(s->cluster_size - 1)) >> 9; | ||
70 | - memset(s->cluster_data + 512, 0x00, 512); | ||
71 | for(i = 0; i < s->cluster_sectors; i++) { | ||
72 | if (i < n_start || i >= n_end) { | ||
73 | Error *err = NULL; | ||
74 | + memset(s->cluster_data, 0x00, 512); | ||
75 | if (encrypt_sectors(s, start_sect + i, | ||
76 | - s->cluster_data, | ||
77 | - s->cluster_data + 512, 1, | ||
78 | + s->cluster_data, 1, | ||
79 | true, &err) < 0) { | ||
80 | error_free(err); | ||
81 | errno = EIO; | ||
82 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow_co_readv(BlockDriverState *bs, int64_t sector_num, | ||
83 | } | ||
84 | if (bs->encrypted) { | ||
85 | assert(s->cipher); | ||
86 | - if (encrypt_sectors(s, sector_num, buf, buf, | ||
87 | + if (encrypt_sectors(s, sector_num, buf, | ||
88 | n, false, &err) < 0) { | ||
89 | goto fail; | ||
90 | } | ||
91 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow_co_writev(BlockDriverState *bs, int64_t sector_num, | ||
92 | BDRVQcowState *s = bs->opaque; | ||
93 | int index_in_cluster; | ||
94 | uint64_t cluster_offset; | ||
95 | - const uint8_t *src_buf; | ||
96 | int ret = 0, n; | ||
97 | - uint8_t *cluster_data = NULL; | ||
98 | struct iovec hd_iov; | ||
99 | QEMUIOVector hd_qiov; | ||
100 | uint8_t *buf; | ||
101 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow_co_writev(BlockDriverState *bs, int64_t sector_num, | ||
102 | |||
103 | s->cluster_cache_offset = -1; /* disable compressed cache */ | ||
104 | |||
105 | - if (qiov->niov > 1) { | ||
106 | + /* We must always copy the iov when encrypting, so we | ||
107 | + * don't modify the original data buffer during encryption */ | ||
108 | + if (bs->encrypted || qiov->niov > 1) { | ||
109 | buf = orig_buf = qemu_try_blockalign(bs, qiov->size); | ||
110 | if (buf == NULL) { | ||
111 | return -ENOMEM; | ||
112 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow_co_writev(BlockDriverState *bs, int64_t sector_num, | ||
113 | if (bs->encrypted) { | ||
114 | Error *err = NULL; | ||
115 | assert(s->cipher); | ||
116 | - if (!cluster_data) { | ||
117 | - cluster_data = g_malloc0(s->cluster_size); | ||
118 | - } | ||
119 | - if (encrypt_sectors(s, sector_num, cluster_data, buf, | ||
120 | - n, true, &err) < 0) { | ||
121 | + if (encrypt_sectors(s, sector_num, buf, n, true, &err) < 0) { | ||
122 | error_free(err); | ||
123 | ret = -EIO; | ||
124 | break; | ||
125 | } | ||
126 | - src_buf = cluster_data; | ||
127 | - } else { | ||
128 | - src_buf = buf; | ||
129 | } | ||
130 | |||
131 | - hd_iov.iov_base = (void *)src_buf; | ||
132 | + hd_iov.iov_base = (void *)buf; | ||
133 | hd_iov.iov_len = n * 512; | ||
134 | qemu_iovec_init_external(&hd_qiov, &hd_iov, 1); | ||
135 | qemu_co_mutex_unlock(&s->lock); | ||
136 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow_co_writev(BlockDriverState *bs, int64_t sector_num, | ||
137 | } | ||
138 | qemu_co_mutex_unlock(&s->lock); | ||
139 | |||
140 | - if (qiov->niov > 1) { | ||
141 | - qemu_vfree(orig_buf); | ||
142 | - } | ||
143 | - g_free(cluster_data); | ||
144 | + qemu_vfree(orig_buf); | ||
145 | |||
146 | return ret; | ||
147 | } | ||
148 | -- | ||
149 | 1.8.3.1 | ||
150 | |||
151 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: "Daniel P. Berrange" <berrange@redhat.com> | ||
2 | 1 | ||
3 | This converts the qcow driver to make use of the QCryptoBlock | ||
4 | APIs for encrypting image content. This is only wired up to | ||
5 | permit use of the legacy QCow encryption format. Users who wish | ||
6 | to have the strong LUKS format should switch to qcow2 instead. | ||
7 | |||
8 | With this change it is now required to use the QCryptoSecret | ||
9 | object for providing passwords, instead of the current block | ||
10 | password APIs / interactive prompting. | ||
11 | |||
12 | $QEMU \ | ||
13 | -object secret,id=sec0,file=/home/berrange/encrypted.pw \ | ||
14 | -drive file=/home/berrange/encrypted.qcow,encrypt.format=aes,\ | ||
15 | encrypt.key-secret=sec0 | ||
16 | |||
17 | Though note that running QEMU system emulators with the AES | ||
18 | encryption is no longer supported, so while the above syntax | ||
19 | is valid, QEMU will refuse to actually run the VM in this | ||
20 | particular example. | ||
21 | |||
22 | Likewise when creating images with the legacy AES-CBC format | ||
23 | |||
24 | qemu-img create -f qcow \ | ||
25 | --object secret,id=sec0,file=/home/berrange/encrypted.pw \ | ||
26 | -o encrypt.format=aes,encrypt.key-secret=sec0 \ | ||
27 | /home/berrange/encrypted.qcow 64M | ||
28 | |||
29 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
30 | Reviewed-by: Alberto Garcia <berto@igalia.com> | ||
31 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
32 | Signed-off-by: Daniel P. Berrange <berrange@redhat.com> | ||
33 | Message-id: 20170623162419.26068-10-berrange@redhat.com | ||
34 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
35 | --- | ||
36 | block/crypto.c | 10 +++ | ||
37 | block/crypto.h | 20 ++++-- | ||
38 | block/qcow.c | 198 +++++++++++++++++++++++++-------------------------- | ||
39 | qapi/block-core.json | 38 +++++++++- | ||
40 | 4 files changed, 158 insertions(+), 108 deletions(-) | ||
41 | |||
42 | diff --git a/block/crypto.c b/block/crypto.c | ||
43 | index XXXXXXX..XXXXXXX 100644 | ||
44 | --- a/block/crypto.c | ||
45 | +++ b/block/crypto.c | ||
46 | @@ -XXX,XX +XXX,XX @@ block_crypto_open_opts_init(QCryptoBlockFormat format, | ||
47 | v, &ret->u.luks, &local_err); | ||
48 | break; | ||
49 | |||
50 | + case Q_CRYPTO_BLOCK_FORMAT_QCOW: | ||
51 | + visit_type_QCryptoBlockOptionsQCow_members( | ||
52 | + v, &ret->u.qcow, &local_err); | ||
53 | + break; | ||
54 | + | ||
55 | default: | ||
56 | error_setg(&local_err, "Unsupported block format %d", format); | ||
57 | break; | ||
58 | @@ -XXX,XX +XXX,XX @@ block_crypto_create_opts_init(QCryptoBlockFormat format, | ||
59 | v, &ret->u.luks, &local_err); | ||
60 | break; | ||
61 | |||
62 | + case Q_CRYPTO_BLOCK_FORMAT_QCOW: | ||
63 | + visit_type_QCryptoBlockOptionsQCow_members( | ||
64 | + v, &ret->u.qcow, &local_err); | ||
65 | + break; | ||
66 | + | ||
67 | default: | ||
68 | error_setg(&local_err, "Unsupported block format %d", format); | ||
69 | break; | ||
70 | diff --git a/block/crypto.h b/block/crypto.h | ||
71 | index XXXXXXX..XXXXXXX 100644 | ||
72 | --- a/block/crypto.h | ||
73 | +++ b/block/crypto.h | ||
74 | @@ -XXX,XX +XXX,XX @@ | ||
75 | #ifndef BLOCK_CRYPTO_H__ | ||
76 | #define BLOCK_CRYPTO_H__ | ||
77 | |||
78 | +#define BLOCK_CRYPTO_OPT_DEF_KEY_SECRET(prefix, helpstr) \ | ||
79 | + { \ | ||
80 | + .name = prefix BLOCK_CRYPTO_OPT_QCOW_KEY_SECRET, \ | ||
81 | + .type = QEMU_OPT_STRING, \ | ||
82 | + .help = helpstr, \ | ||
83 | + } | ||
84 | + | ||
85 | +#define BLOCK_CRYPTO_OPT_QCOW_KEY_SECRET "key-secret" | ||
86 | + | ||
87 | +#define BLOCK_CRYPTO_OPT_DEF_QCOW_KEY_SECRET(prefix) \ | ||
88 | + BLOCK_CRYPTO_OPT_DEF_KEY_SECRET(prefix, \ | ||
89 | + "ID of the secret that provides the AES encryption key") | ||
90 | + | ||
91 | #define BLOCK_CRYPTO_OPT_LUKS_KEY_SECRET "key-secret" | ||
92 | #define BLOCK_CRYPTO_OPT_LUKS_CIPHER_ALG "cipher-alg" | ||
93 | #define BLOCK_CRYPTO_OPT_LUKS_CIPHER_MODE "cipher-mode" | ||
94 | @@ -XXX,XX +XXX,XX @@ | ||
95 | #define BLOCK_CRYPTO_OPT_LUKS_ITER_TIME "iter-time" | ||
96 | |||
97 | #define BLOCK_CRYPTO_OPT_DEF_LUKS_KEY_SECRET(prefix) \ | ||
98 | - { \ | ||
99 | - .name = prefix BLOCK_CRYPTO_OPT_LUKS_KEY_SECRET, \ | ||
100 | - .type = QEMU_OPT_STRING, \ | ||
101 | - .help = "ID of the secret that provides the keyslot passphrase", \ | ||
102 | - } | ||
103 | + BLOCK_CRYPTO_OPT_DEF_KEY_SECRET(prefix, \ | ||
104 | + "ID of the secret that provides the keyslot passphrase") | ||
105 | |||
106 | #define BLOCK_CRYPTO_OPT_DEF_LUKS_CIPHER_ALG(prefix) \ | ||
107 | { \ | ||
108 | diff --git a/block/qcow.c b/block/qcow.c | ||
109 | index XXXXXXX..XXXXXXX 100644 | ||
110 | --- a/block/qcow.c | ||
111 | +++ b/block/qcow.c | ||
112 | @@ -XXX,XX +XXX,XX @@ | ||
113 | #include "qemu/bswap.h" | ||
114 | #include <zlib.h> | ||
115 | #include "qapi/qmp/qerror.h" | ||
116 | -#include "crypto/cipher.h" | ||
117 | +#include "qapi/qmp/qstring.h" | ||
118 | +#include "crypto/block.h" | ||
119 | #include "migration/blocker.h" | ||
120 | +#include "block/crypto.h" | ||
121 | |||
122 | /**************************************************************/ | ||
123 | /* QEMU COW block driver with compression and encryption support */ | ||
124 | @@ -XXX,XX +XXX,XX @@ typedef struct BDRVQcowState { | ||
125 | uint8_t *cluster_cache; | ||
126 | uint8_t *cluster_data; | ||
127 | uint64_t cluster_cache_offset; | ||
128 | - QCryptoCipher *cipher; /* NULL if no key yet */ | ||
129 | + QCryptoBlock *crypto; /* Disk encryption format driver */ | ||
130 | uint32_t crypt_method_header; | ||
131 | CoMutex lock; | ||
132 | Error *migration_blocker; | ||
133 | @@ -XXX,XX +XXX,XX @@ static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename) | ||
134 | return 0; | ||
135 | } | ||
136 | |||
137 | +static QemuOptsList qcow_runtime_opts = { | ||
138 | + .name = "qcow", | ||
139 | + .head = QTAILQ_HEAD_INITIALIZER(qcow_runtime_opts.head), | ||
140 | + .desc = { | ||
141 | + BLOCK_CRYPTO_OPT_DEF_QCOW_KEY_SECRET("encrypt."), | ||
142 | + { /* end of list */ } | ||
143 | + }, | ||
144 | +}; | ||
145 | + | ||
146 | static int qcow_open(BlockDriverState *bs, QDict *options, int flags, | ||
147 | Error **errp) | ||
148 | { | ||
149 | @@ -XXX,XX +XXX,XX @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags, | ||
150 | int ret; | ||
151 | QCowHeader header; | ||
152 | Error *local_err = NULL; | ||
153 | + QCryptoBlockOpenOptions *crypto_opts = NULL; | ||
154 | + unsigned int cflags = 0; | ||
155 | + QDict *encryptopts = NULL; | ||
156 | + const char *encryptfmt; | ||
157 | + | ||
158 | + qdict_extract_subqdict(options, &encryptopts, "encrypt."); | ||
159 | + encryptfmt = qdict_get_try_str(encryptopts, "format"); | ||
160 | |||
161 | bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, | ||
162 | false, errp); | ||
163 | if (!bs->file) { | ||
164 | - return -EINVAL; | ||
165 | + ret = -EINVAL; | ||
166 | + goto fail; | ||
167 | } | ||
168 | |||
169 | ret = bdrv_pread(bs->file, 0, &header, sizeof(header)); | ||
170 | @@ -XXX,XX +XXX,XX @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags, | ||
171 | goto fail; | ||
172 | } | ||
173 | |||
174 | - if (header.crypt_method > QCOW_CRYPT_AES) { | ||
175 | - error_setg(errp, "invalid encryption method in qcow header"); | ||
176 | - ret = -EINVAL; | ||
177 | - goto fail; | ||
178 | - } | ||
179 | - if (!qcrypto_cipher_supports(QCRYPTO_CIPHER_ALG_AES_128, | ||
180 | - QCRYPTO_CIPHER_MODE_CBC)) { | ||
181 | - error_setg(errp, "AES cipher not available"); | ||
182 | - ret = -EINVAL; | ||
183 | - goto fail; | ||
184 | - } | ||
185 | s->crypt_method_header = header.crypt_method; | ||
186 | if (s->crypt_method_header) { | ||
187 | if (bdrv_uses_whitelist() && | ||
188 | @@ -XXX,XX +XXX,XX @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags, | ||
189 | ret = -ENOSYS; | ||
190 | goto fail; | ||
191 | } | ||
192 | + if (s->crypt_method_header == QCOW_CRYPT_AES) { | ||
193 | + if (encryptfmt && !g_str_equal(encryptfmt, "aes")) { | ||
194 | + error_setg(errp, | ||
195 | + "Header reported 'aes' encryption format but " | ||
196 | + "options specify '%s'", encryptfmt); | ||
197 | + ret = -EINVAL; | ||
198 | + goto fail; | ||
199 | + } | ||
200 | + qdict_del(encryptopts, "format"); | ||
201 | + crypto_opts = block_crypto_open_opts_init( | ||
202 | + Q_CRYPTO_BLOCK_FORMAT_QCOW, encryptopts, errp); | ||
203 | + if (!crypto_opts) { | ||
204 | + ret = -EINVAL; | ||
205 | + goto fail; | ||
206 | + } | ||
207 | |||
208 | + if (flags & BDRV_O_NO_IO) { | ||
209 | + cflags |= QCRYPTO_BLOCK_OPEN_NO_IO; | ||
210 | + } | ||
211 | + s->crypto = qcrypto_block_open(crypto_opts, NULL, NULL, | ||
212 | + cflags, errp); | ||
213 | + if (!s->crypto) { | ||
214 | + ret = -EINVAL; | ||
215 | + goto fail; | ||
216 | + } | ||
217 | + } else { | ||
218 | + error_setg(errp, "invalid encryption method in qcow header"); | ||
219 | + ret = -EINVAL; | ||
220 | + goto fail; | ||
221 | + } | ||
222 | bs->encrypted = true; | ||
223 | + bs->valid_key = true; | ||
224 | } | ||
225 | s->cluster_bits = header.cluster_bits; | ||
226 | s->cluster_size = 1 << s->cluster_bits; | ||
227 | @@ -XXX,XX +XXX,XX @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags, | ||
228 | goto fail; | ||
229 | } | ||
230 | |||
231 | + QDECREF(encryptopts); | ||
232 | + qapi_free_QCryptoBlockOpenOptions(crypto_opts); | ||
233 | qemu_co_mutex_init(&s->lock); | ||
234 | return 0; | ||
235 | |||
236 | @@ -XXX,XX +XXX,XX @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags, | ||
237 | qemu_vfree(s->l2_cache); | ||
238 | g_free(s->cluster_cache); | ||
239 | g_free(s->cluster_data); | ||
240 | + qcrypto_block_free(s->crypto); | ||
241 | + QDECREF(encryptopts); | ||
242 | + qapi_free_QCryptoBlockOpenOptions(crypto_opts); | ||
243 | return ret; | ||
244 | } | ||
245 | |||
246 | @@ -XXX,XX +XXX,XX @@ static int qcow_reopen_prepare(BDRVReopenState *state, | ||
247 | return 0; | ||
248 | } | ||
249 | |||
250 | -static int qcow_set_key(BlockDriverState *bs, const char *key) | ||
251 | -{ | ||
252 | - BDRVQcowState *s = bs->opaque; | ||
253 | - uint8_t keybuf[16]; | ||
254 | - int len, i; | ||
255 | - Error *err; | ||
256 | - | ||
257 | - memset(keybuf, 0, 16); | ||
258 | - len = strlen(key); | ||
259 | - if (len > 16) | ||
260 | - len = 16; | ||
261 | - /* XXX: we could compress the chars to 7 bits to increase | ||
262 | - entropy */ | ||
263 | - for(i = 0;i < len;i++) { | ||
264 | - keybuf[i] = key[i]; | ||
265 | - } | ||
266 | - assert(bs->encrypted); | ||
267 | - | ||
268 | - qcrypto_cipher_free(s->cipher); | ||
269 | - s->cipher = qcrypto_cipher_new( | ||
270 | - QCRYPTO_CIPHER_ALG_AES_128, | ||
271 | - QCRYPTO_CIPHER_MODE_CBC, | ||
272 | - keybuf, G_N_ELEMENTS(keybuf), | ||
273 | - &err); | ||
274 | - | ||
275 | - if (!s->cipher) { | ||
276 | - /* XXX would be nice if errors in this method could | ||
277 | - * be properly propagate to the caller. Would need | ||
278 | - * the bdrv_set_key() API signature to be fixed. */ | ||
279 | - error_free(err); | ||
280 | - return -1; | ||
281 | - } | ||
282 | - return 0; | ||
283 | -} | ||
284 | - | ||
285 | -/* The crypt function is compatible with the linux cryptoloop | ||
286 | - algorithm for < 4 GB images. */ | ||
287 | -static int encrypt_sectors(BDRVQcowState *s, int64_t sector_num, | ||
288 | - uint8_t *buf, int nb_sectors, bool enc, | ||
289 | - Error **errp) | ||
290 | -{ | ||
291 | - union { | ||
292 | - uint64_t ll[2]; | ||
293 | - uint8_t b[16]; | ||
294 | - } ivec; | ||
295 | - int i; | ||
296 | - int ret; | ||
297 | - | ||
298 | - for(i = 0; i < nb_sectors; i++) { | ||
299 | - ivec.ll[0] = cpu_to_le64(sector_num); | ||
300 | - ivec.ll[1] = 0; | ||
301 | - if (qcrypto_cipher_setiv(s->cipher, | ||
302 | - ivec.b, G_N_ELEMENTS(ivec.b), | ||
303 | - errp) < 0) { | ||
304 | - return -1; | ||
305 | - } | ||
306 | - if (enc) { | ||
307 | - ret = qcrypto_cipher_encrypt(s->cipher, | ||
308 | - buf, buf, | ||
309 | - 512, | ||
310 | - errp); | ||
311 | - } else { | ||
312 | - ret = qcrypto_cipher_decrypt(s->cipher, | ||
313 | - buf, buf, | ||
314 | - 512, | ||
315 | - errp); | ||
316 | - } | ||
317 | - if (ret < 0) { | ||
318 | - return -1; | ||
319 | - } | ||
320 | - sector_num++; | ||
321 | - buf += 512; | ||
322 | - } | ||
323 | - return 0; | ||
324 | -} | ||
325 | |||
326 | /* 'allocate' is: | ||
327 | * | ||
328 | @@ -XXX,XX +XXX,XX @@ static uint64_t get_cluster_offset(BlockDriverState *bs, | ||
329 | if (bs->encrypted && | ||
330 | (n_end - n_start) < s->cluster_sectors) { | ||
331 | uint64_t start_sect; | ||
332 | - assert(s->cipher); | ||
333 | + assert(s->crypto); | ||
334 | start_sect = (offset & ~(s->cluster_size - 1)) >> 9; | ||
335 | for(i = 0; i < s->cluster_sectors; i++) { | ||
336 | if (i < n_start || i >= n_end) { | ||
337 | Error *err = NULL; | ||
338 | memset(s->cluster_data, 0x00, 512); | ||
339 | - if (encrypt_sectors(s, start_sect + i, | ||
340 | - s->cluster_data, 1, | ||
341 | - true, &err) < 0) { | ||
342 | + if (qcrypto_block_encrypt(s->crypto, start_sect + i, | ||
343 | + s->cluster_data, | ||
344 | + BDRV_SECTOR_SIZE, | ||
345 | + &err) < 0) { | ||
346 | error_free(err); | ||
347 | errno = EIO; | ||
348 | return -1; | ||
349 | @@ -XXX,XX +XXX,XX @@ static int64_t coroutine_fn qcow_co_get_block_status(BlockDriverState *bs, | ||
350 | if (!cluster_offset) { | ||
351 | return 0; | ||
352 | } | ||
353 | - if ((cluster_offset & QCOW_OFLAG_COMPRESSED) || s->cipher) { | ||
354 | + if ((cluster_offset & QCOW_OFLAG_COMPRESSED) || s->crypto) { | ||
355 | return BDRV_BLOCK_DATA; | ||
356 | } | ||
357 | cluster_offset |= (index_in_cluster << BDRV_SECTOR_BITS); | ||
358 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow_co_readv(BlockDriverState *bs, int64_t sector_num, | ||
359 | break; | ||
360 | } | ||
361 | if (bs->encrypted) { | ||
362 | - assert(s->cipher); | ||
363 | - if (encrypt_sectors(s, sector_num, buf, | ||
364 | - n, false, &err) < 0) { | ||
365 | + assert(s->crypto); | ||
366 | + if (qcrypto_block_decrypt(s->crypto, sector_num, buf, | ||
367 | + n * BDRV_SECTOR_SIZE, &err) < 0) { | ||
368 | goto fail; | ||
369 | } | ||
370 | } | ||
371 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow_co_writev(BlockDriverState *bs, int64_t sector_num, | ||
372 | } | ||
373 | if (bs->encrypted) { | ||
374 | Error *err = NULL; | ||
375 | - assert(s->cipher); | ||
376 | - if (encrypt_sectors(s, sector_num, buf, n, true, &err) < 0) { | ||
377 | + assert(s->crypto); | ||
378 | + if (qcrypto_block_encrypt(s->crypto, sector_num, buf, | ||
379 | + n * BDRV_SECTOR_SIZE, &err) < 0) { | ||
380 | error_free(err); | ||
381 | ret = -EIO; | ||
382 | break; | ||
383 | @@ -XXX,XX +XXX,XX @@ static void qcow_close(BlockDriverState *bs) | ||
384 | { | ||
385 | BDRVQcowState *s = bs->opaque; | ||
386 | |||
387 | - qcrypto_cipher_free(s->cipher); | ||
388 | - s->cipher = NULL; | ||
389 | + qcrypto_block_free(s->crypto); | ||
390 | + s->crypto = NULL; | ||
391 | g_free(s->l1_table); | ||
392 | qemu_vfree(s->l2_cache); | ||
393 | g_free(s->cluster_cache); | ||
394 | @@ -XXX,XX +XXX,XX @@ static int qcow_create(const char *filename, QemuOpts *opts, Error **errp) | ||
395 | int ret; | ||
396 | BlockBackend *qcow_blk; | ||
397 | const char *encryptfmt = NULL; | ||
398 | + QDict *options; | ||
399 | + QDict *encryptopts = NULL; | ||
400 | + QCryptoBlockCreateOptions *crypto_opts = NULL; | ||
401 | + QCryptoBlock *crypto = NULL; | ||
402 | |||
403 | /* Read out options */ | ||
404 | total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0), | ||
405 | @@ -XXX,XX +XXX,XX @@ static int qcow_create(const char *filename, QemuOpts *opts, Error **errp) | ||
406 | l1_size = (total_size + (1LL << shift) - 1) >> shift; | ||
407 | |||
408 | header.l1_table_offset = cpu_to_be64(header_size); | ||
409 | + | ||
410 | + options = qemu_opts_to_qdict(opts, NULL); | ||
411 | + qdict_extract_subqdict(options, &encryptopts, "encrypt."); | ||
412 | + QDECREF(options); | ||
413 | if (encryptfmt) { | ||
414 | if (!g_str_equal(encryptfmt, "aes")) { | ||
415 | error_setg(errp, "Unknown encryption format '%s', expected 'aes'", | ||
416 | @@ -XXX,XX +XXX,XX @@ static int qcow_create(const char *filename, QemuOpts *opts, Error **errp) | ||
417 | goto exit; | ||
418 | } | ||
419 | header.crypt_method = cpu_to_be32(QCOW_CRYPT_AES); | ||
420 | + | ||
421 | + crypto_opts = block_crypto_create_opts_init( | ||
422 | + Q_CRYPTO_BLOCK_FORMAT_QCOW, encryptopts, errp); | ||
423 | + if (!crypto_opts) { | ||
424 | + ret = -EINVAL; | ||
425 | + goto exit; | ||
426 | + } | ||
427 | + | ||
428 | + crypto = qcrypto_block_create(crypto_opts, NULL, NULL, NULL, errp); | ||
429 | + if (!crypto) { | ||
430 | + ret = -EINVAL; | ||
431 | + goto exit; | ||
432 | + } | ||
433 | } else { | ||
434 | header.crypt_method = cpu_to_be32(QCOW_CRYPT_NONE); | ||
435 | } | ||
436 | @@ -XXX,XX +XXX,XX @@ static int qcow_create(const char *filename, QemuOpts *opts, Error **errp) | ||
437 | exit: | ||
438 | blk_unref(qcow_blk); | ||
439 | cleanup: | ||
440 | + QDECREF(encryptopts); | ||
441 | + qcrypto_block_free(crypto); | ||
442 | + qapi_free_QCryptoBlockCreateOptions(crypto_opts); | ||
443 | g_free(backing_file); | ||
444 | return ret; | ||
445 | } | ||
446 | @@ -XXX,XX +XXX,XX @@ static QemuOptsList qcow_create_opts = { | ||
447 | .type = QEMU_OPT_STRING, | ||
448 | .help = "Encrypt the image, format choices: 'aes'", | ||
449 | }, | ||
450 | + BLOCK_CRYPTO_OPT_DEF_QCOW_KEY_SECRET("encrypt."), | ||
451 | { /* end of list */ } | ||
452 | } | ||
453 | }; | ||
454 | @@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_qcow = { | ||
455 | .bdrv_co_writev = qcow_co_writev, | ||
456 | .bdrv_co_get_block_status = qcow_co_get_block_status, | ||
457 | |||
458 | - .bdrv_set_key = qcow_set_key, | ||
459 | .bdrv_make_empty = qcow_make_empty, | ||
460 | .bdrv_co_pwritev_compressed = qcow_co_pwritev_compressed, | ||
461 | .bdrv_get_info = qcow_get_info, | ||
462 | diff --git a/qapi/block-core.json b/qapi/block-core.json | ||
463 | index XXXXXXX..XXXXXXX 100644 | ||
464 | --- a/qapi/block-core.json | ||
465 | +++ b/qapi/block-core.json | ||
466 | @@ -XXX,XX +XXX,XX @@ | ||
467 | 'mode': 'Qcow2OverlapCheckMode' } } | ||
468 | |||
469 | ## | ||
470 | +# @BlockdevQcowEncryptionFormat: | ||
471 | +# | ||
472 | +# @aes: AES-CBC with plain64 initialization vectors | ||
473 | +# | ||
474 | +# Since: 2.10 | ||
475 | +## | ||
476 | +{ 'enum': 'BlockdevQcowEncryptionFormat', | ||
477 | + 'data': [ 'aes' ] } | ||
478 | + | ||
479 | +## | ||
480 | +# @BlockdevQcowEncryption: | ||
481 | +# | ||
482 | +# Since: 2.10 | ||
483 | +## | ||
484 | +{ 'union': 'BlockdevQcowEncryption', | ||
485 | + 'base': { 'format': 'BlockdevQcowEncryptionFormat' }, | ||
486 | + 'discriminator': 'format', | ||
487 | + 'data': { 'aes': 'QCryptoBlockOptionsQCow' } } | ||
488 | + | ||
489 | +## | ||
490 | +# @BlockdevOptionsQcow: | ||
491 | +# | ||
492 | +# Driver specific block device options for qcow. | ||
493 | +# | ||
494 | +# @encrypt: Image decryption options. Mandatory for | ||
495 | +# encrypted images, except when doing a metadata-only | ||
496 | +# probe of the image. | ||
497 | +# | ||
498 | +# Since: 2.10 | ||
499 | +## | ||
500 | +{ 'struct': 'BlockdevOptionsQcow', | ||
501 | + 'base': 'BlockdevOptionsGenericCOWFormat', | ||
502 | + 'data': { '*encrypt': 'BlockdevQcowEncryption' } } | ||
503 | + | ||
504 | + | ||
505 | +## | ||
506 | # @BlockdevOptionsQcow2: | ||
507 | # | ||
508 | # Driver specific block device options for qcow2. | ||
509 | @@ -XXX,XX +XXX,XX @@ | ||
510 | 'null-co': 'BlockdevOptionsNull', | ||
511 | 'parallels': 'BlockdevOptionsGenericFormat', | ||
512 | 'qcow2': 'BlockdevOptionsQcow2', | ||
513 | - 'qcow': 'BlockdevOptionsGenericCOWFormat', | ||
514 | + 'qcow': 'BlockdevOptionsQcow', | ||
515 | 'qed': 'BlockdevOptionsGenericCOWFormat', | ||
516 | 'quorum': 'BlockdevOptionsQuorum', | ||
517 | 'raw': 'BlockdevOptionsRaw', | ||
518 | -- | ||
519 | 1.8.3.1 | ||
520 | |||
521 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: "Daniel P. Berrange" <berrange@redhat.com> | ||
2 | 1 | ||
3 | Instead of requiring separate input/output buffers for | ||
4 | encrypting data, change qcow2_encrypt_sectors() to assume | ||
5 | use of a single buffer, encrypting in place. The current | ||
6 | callers all used the same buffer for input/output already. | ||
7 | |||
8 | Signed-off-by: Daniel P. Berrange <berrange@redhat.com> | ||
9 | Message-id: 20170623162419.26068-11-berrange@redhat.com | ||
10 | Reviewed-by: Alberto Garcia <berto@igalia.com> | ||
11 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
12 | --- | ||
13 | block/qcow2-cluster.c | 17 ++++++----------- | ||
14 | block/qcow2.c | 4 ++-- | ||
15 | block/qcow2.h | 3 +-- | ||
16 | 3 files changed, 9 insertions(+), 15 deletions(-) | ||
17 | |||
18 | diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c | ||
19 | index XXXXXXX..XXXXXXX 100644 | ||
20 | --- a/block/qcow2-cluster.c | ||
21 | +++ b/block/qcow2-cluster.c | ||
22 | @@ -XXX,XX +XXX,XX @@ static int count_contiguous_clusters_unallocated(int nb_clusters, | ||
23 | } | ||
24 | |||
25 | /* The crypt function is compatible with the linux cryptoloop | ||
26 | - algorithm for < 4 GB images. NOTE: out_buf == in_buf is | ||
27 | - supported */ | ||
28 | + algorithm for < 4 GB images. */ | ||
29 | int qcow2_encrypt_sectors(BDRVQcow2State *s, int64_t sector_num, | ||
30 | - uint8_t *out_buf, const uint8_t *in_buf, | ||
31 | - int nb_sectors, bool enc, | ||
32 | + uint8_t *buf, int nb_sectors, bool enc, | ||
33 | Error **errp) | ||
34 | { | ||
35 | union { | ||
36 | @@ -XXX,XX +XXX,XX @@ int qcow2_encrypt_sectors(BDRVQcow2State *s, int64_t sector_num, | ||
37 | } | ||
38 | if (enc) { | ||
39 | ret = qcrypto_cipher_encrypt(s->cipher, | ||
40 | - in_buf, | ||
41 | - out_buf, | ||
42 | + buf, buf, | ||
43 | 512, | ||
44 | errp); | ||
45 | } else { | ||
46 | ret = qcrypto_cipher_decrypt(s->cipher, | ||
47 | - in_buf, | ||
48 | - out_buf, | ||
49 | + buf, buf, | ||
50 | 512, | ||
51 | errp); | ||
52 | } | ||
53 | @@ -XXX,XX +XXX,XX @@ int qcow2_encrypt_sectors(BDRVQcow2State *s, int64_t sector_num, | ||
54 | return -1; | ||
55 | } | ||
56 | sector_num++; | ||
57 | - in_buf += 512; | ||
58 | - out_buf += 512; | ||
59 | + buf += 512; | ||
60 | } | ||
61 | return 0; | ||
62 | } | ||
63 | @@ -XXX,XX +XXX,XX @@ static bool coroutine_fn do_perform_cow_encrypt(BlockDriverState *bs, | ||
64 | assert(s->cipher); | ||
65 | assert((offset_in_cluster & ~BDRV_SECTOR_MASK) == 0); | ||
66 | assert((bytes & ~BDRV_SECTOR_MASK) == 0); | ||
67 | - if (qcow2_encrypt_sectors(s, sector, buffer, buffer, | ||
68 | + if (qcow2_encrypt_sectors(s, sector, buffer, | ||
69 | bytes >> BDRV_SECTOR_BITS, true, NULL) < 0) { | ||
70 | return false; | ||
71 | } | ||
72 | diff --git a/block/qcow2.c b/block/qcow2.c | ||
73 | index XXXXXXX..XXXXXXX 100644 | ||
74 | --- a/block/qcow2.c | ||
75 | +++ b/block/qcow2.c | ||
76 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset, | ||
77 | assert((cur_bytes & (BDRV_SECTOR_SIZE - 1)) == 0); | ||
78 | Error *err = NULL; | ||
79 | if (qcow2_encrypt_sectors(s, offset >> BDRV_SECTOR_BITS, | ||
80 | - cluster_data, cluster_data, | ||
81 | + cluster_data, | ||
82 | cur_bytes >> BDRV_SECTOR_BITS, | ||
83 | false, &err) < 0) { | ||
84 | error_free(err); | ||
85 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_pwritev(BlockDriverState *bs, uint64_t offset, | ||
86 | qemu_iovec_to_buf(&hd_qiov, 0, cluster_data, hd_qiov.size); | ||
87 | |||
88 | if (qcow2_encrypt_sectors(s, offset >> BDRV_SECTOR_BITS, | ||
89 | - cluster_data, cluster_data, | ||
90 | + cluster_data, | ||
91 | cur_bytes >>BDRV_SECTOR_BITS, | ||
92 | true, &err) < 0) { | ||
93 | error_free(err); | ||
94 | diff --git a/block/qcow2.h b/block/qcow2.h | ||
95 | index XXXXXXX..XXXXXXX 100644 | ||
96 | --- a/block/qcow2.h | ||
97 | +++ b/block/qcow2.h | ||
98 | @@ -XXX,XX +XXX,XX @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size, | ||
99 | int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index); | ||
100 | int qcow2_decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset); | ||
101 | int qcow2_encrypt_sectors(BDRVQcow2State *s, int64_t sector_num, | ||
102 | - uint8_t *out_buf, const uint8_t *in_buf, | ||
103 | - int nb_sectors, bool enc, Error **errp); | ||
104 | + uint8_t *buf, int nb_sectors, bool enc, Error **errp); | ||
105 | |||
106 | int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset, | ||
107 | unsigned int *bytes, uint64_t *cluster_offset); | ||
108 | -- | ||
109 | 1.8.3.1 | ||
110 | |||
111 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: "Daniel P. Berrange" <berrange@redhat.com> | ||
2 | 1 | ||
3 | Update the qcow2 specification to describe how the LUKS header is | ||
4 | placed inside a qcow2 file, when using LUKS encryption for the | ||
5 | qcow2 payload instead of the legacy AES-CBC encryption | ||
6 | |||
7 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
8 | Reviewed-by: Alberto Garcia <berto@igalia.com> | ||
9 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
10 | Signed-off-by: Daniel P. Berrange <berrange@redhat.com> | ||
11 | Message-id: 20170623162419.26068-13-berrange@redhat.com | ||
12 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
13 | --- | ||
14 | docs/interop/qcow2.txt | 103 +++++++++++++++++++++++++++++++++++++++++++++++++ | ||
15 | 1 file changed, 103 insertions(+) | ||
16 | |||
17 | diff --git a/docs/interop/qcow2.txt b/docs/interop/qcow2.txt | ||
18 | index XXXXXXX..XXXXXXX 100644 | ||
19 | --- a/docs/interop/qcow2.txt | ||
20 | +++ b/docs/interop/qcow2.txt | ||
21 | @@ -XXX,XX +XXX,XX @@ The first cluster of a qcow2 image contains the file header: | ||
22 | 32 - 35: crypt_method | ||
23 | 0 for no encryption | ||
24 | 1 for AES encryption | ||
25 | + 2 for LUKS encryption | ||
26 | |||
27 | 36 - 39: l1_size | ||
28 | Number of entries in the active L1 table | ||
29 | @@ -XXX,XX +XXX,XX @@ be stored. Each extension has a structure like the following: | ||
30 | 0xE2792ACA - Backing file format name | ||
31 | 0x6803f857 - Feature name table | ||
32 | 0x23852875 - Bitmaps extension | ||
33 | + 0x0537be77 - Full disk encryption header pointer | ||
34 | other - Unknown header extension, can be safely | ||
35 | ignored | ||
36 | |||
37 | @@ -XXX,XX +XXX,XX @@ The fields of the bitmaps extension are: | ||
38 | Offset into the image file at which the bitmap directory | ||
39 | starts. Must be aligned to a cluster boundary. | ||
40 | |||
41 | +== Full disk encryption header pointer == | ||
42 | + | ||
43 | +The full disk encryption header must be present if, and only if, the | ||
44 | +'crypt_method' header requires metadata. Currently this is only true | ||
45 | +of the 'LUKS' crypt method. The header extension must be absent for | ||
46 | +other methods. | ||
47 | + | ||
48 | +This header provides the offset at which the crypt method can store | ||
49 | +its additional data, as well as the length of such data. | ||
50 | + | ||
51 | + Byte 0 - 7: Offset into the image file at which the encryption | ||
52 | + header starts in bytes. Must be aligned to a cluster | ||
53 | + boundary. | ||
54 | + Byte 8 - 15: Length of the written encryption header in bytes. | ||
55 | + Note actual space allocated in the qcow2 file may | ||
56 | + be larger than this value, since it will be rounded | ||
57 | + to the nearest multiple of the cluster size. Any | ||
58 | + unused bytes in the allocated space will be initialized | ||
59 | + to 0. | ||
60 | + | ||
61 | +For the LUKS crypt method, the encryption header works as follows. | ||
62 | + | ||
63 | +The first 592 bytes of the header clusters will contain the LUKS | ||
64 | +partition header. This is then followed by the key material data areas. | ||
65 | +The size of the key material data areas is determined by the number of | ||
66 | +stripes in the key slot and key size. Refer to the LUKS format | ||
67 | +specification ('docs/on-disk-format.pdf' in the cryptsetup source | ||
68 | +package) for details of the LUKS partition header format. | ||
69 | + | ||
70 | +In the LUKS partition header, the "payload-offset" field will be | ||
71 | +calculated as normal for the LUKS spec. ie the size of the LUKS | ||
72 | +header, plus key material regions, plus padding, relative to the | ||
73 | +start of the LUKS header. This offset value is not required to be | ||
74 | +qcow2 cluster aligned. Its value is currently never used in the | ||
75 | +context of qcow2, since the qcow2 file format itself defines where | ||
76 | +the real payload offset is, but none the less a valid payload offset | ||
77 | +should always be present. | ||
78 | + | ||
79 | +In the LUKS key slots header, the "key-material-offset" is relative | ||
80 | +to the start of the LUKS header clusters in the qcow2 container, | ||
81 | +not the start of the qcow2 file. | ||
82 | + | ||
83 | +Logically the layout looks like | ||
84 | + | ||
85 | + +-----------------------------+ | ||
86 | + | QCow2 header | | ||
87 | + | QCow2 header extension X | | ||
88 | + | QCow2 header extension FDE | | ||
89 | + | QCow2 header extension ... | | ||
90 | + | QCow2 header extension Z | | ||
91 | + +-----------------------------+ | ||
92 | + | ....other QCow2 tables.... | | ||
93 | + . . | ||
94 | + . . | ||
95 | + +-----------------------------+ | ||
96 | + | +-------------------------+ | | ||
97 | + | | LUKS partition header | | | ||
98 | + | +-------------------------+ | | ||
99 | + | | LUKS key material 1 | | | ||
100 | + | +-------------------------+ | | ||
101 | + | | LUKS key material 2 | | | ||
102 | + | +-------------------------+ | | ||
103 | + | | LUKS key material ... | | | ||
104 | + | +-------------------------+ | | ||
105 | + | | LUKS key material 8 | | | ||
106 | + | +-------------------------+ | | ||
107 | + +-----------------------------+ | ||
108 | + | QCow2 cluster payload | | ||
109 | + . . | ||
110 | + . . | ||
111 | + . . | ||
112 | + | | | ||
113 | + +-----------------------------+ | ||
114 | + | ||
115 | +== Data encryption == | ||
116 | + | ||
117 | +When an encryption method is requested in the header, the image payload | ||
118 | +data must be encrypted/decrypted on every write/read. The image headers | ||
119 | +and metadata are never encrypted. | ||
120 | + | ||
121 | +The algorithms used for encryption vary depending on the method | ||
122 | + | ||
123 | + - AES: | ||
124 | + | ||
125 | + The AES cipher, in CBC mode, with 256 bit keys. | ||
126 | + | ||
127 | + Initialization vectors generated using plain64 method, with | ||
128 | + the virtual disk sector as the input tweak. | ||
129 | + | ||
130 | + This format is no longer supported in QEMU system emulators, due | ||
131 | + to a number of design flaws affecting its security. It is only | ||
132 | + supported in the command line tools for the sake of back compatibility | ||
133 | + and data liberation. | ||
134 | + | ||
135 | + - LUKS: | ||
136 | + | ||
137 | + The algorithms are specified in the LUKS header. | ||
138 | + | ||
139 | + Initialization vectors generated using the method specified | ||
140 | + in the LUKS header, with the physical disk sector as the | ||
141 | + input tweak. | ||
142 | |||
143 | == Host cluster management == | ||
144 | |||
145 | -- | ||
146 | 1.8.3.1 | ||
147 | |||
148 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: "Daniel P. Berrange" <berrange@redhat.com> | ||
2 | 1 | ||
3 | This extends the 087 iotest to cover LUKS encryption when doing | ||
4 | blockdev-add. | ||
5 | |||
6 | Two further tests are added to validate read/write of LUKS | ||
7 | encrypted images with a single file and with a backing file. | ||
8 | |||
9 | Reviewed-by: Alberto Garcia <berto@igalia.com> | ||
10 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
11 | Signed-off-by: Daniel P. Berrange <berrange@redhat.com> | ||
12 | Message-id: 20170623162419.26068-15-berrange@redhat.com | ||
13 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
14 | --- | ||
15 | tests/qemu-iotests/087 | 35 ++++++++++++++++++- | ||
16 | tests/qemu-iotests/087.out | 14 +++++++- | ||
17 | tests/qemu-iotests/188 | 76 ++++++++++++++++++++++++++++++++++++++++ | ||
18 | tests/qemu-iotests/188.out | 18 ++++++++++ | ||
19 | tests/qemu-iotests/189 | 86 ++++++++++++++++++++++++++++++++++++++++++++++ | ||
20 | tests/qemu-iotests/189.out | 26 ++++++++++++++ | ||
21 | tests/qemu-iotests/group | 2 ++ | ||
22 | 7 files changed, 255 insertions(+), 2 deletions(-) | ||
23 | create mode 100755 tests/qemu-iotests/188 | ||
24 | create mode 100644 tests/qemu-iotests/188.out | ||
25 | create mode 100755 tests/qemu-iotests/189 | ||
26 | create mode 100644 tests/qemu-iotests/189.out | ||
27 | |||
28 | diff --git a/tests/qemu-iotests/087 b/tests/qemu-iotests/087 | ||
29 | index XXXXXXX..XXXXXXX 100755 | ||
30 | --- a/tests/qemu-iotests/087 | ||
31 | +++ b/tests/qemu-iotests/087 | ||
32 | @@ -XXX,XX +XXX,XX @@ run_qemu <<EOF | ||
33 | EOF | ||
34 | |||
35 | echo | ||
36 | -echo === Encrypted image === | ||
37 | +echo === Encrypted image QCow === | ||
38 | echo | ||
39 | |||
40 | _make_test_img --object secret,id=sec0,data=123456 -o encryption=on,encrypt.key-secret=sec0 $size | ||
41 | @@ -XXX,XX +XXX,XX @@ run_qemu <<EOF | ||
42 | EOF | ||
43 | |||
44 | echo | ||
45 | +echo === Encrypted image LUKS === | ||
46 | +echo | ||
47 | + | ||
48 | +_make_test_img --object secret,id=sec0,data=123456 -o encrypt.format=luks,encrypt.key-secret=sec0 $size | ||
49 | +run_qemu <<EOF | ||
50 | +{ "execute": "qmp_capabilities" } | ||
51 | +{ "execute": "object-add", | ||
52 | + "arguments": { | ||
53 | + "qom-type": "secret", | ||
54 | + "id": "sec0", | ||
55 | + "props": { | ||
56 | + "data": "123456" | ||
57 | + } | ||
58 | + } | ||
59 | +} | ||
60 | +{ "execute": "blockdev-add", | ||
61 | + "arguments": { | ||
62 | + "driver": "$IMGFMT", | ||
63 | + "node-name": "disk", | ||
64 | + "file": { | ||
65 | + "driver": "file", | ||
66 | + "filename": "$TEST_IMG" | ||
67 | + }, | ||
68 | + "encrypt": { | ||
69 | + "format": "luks", | ||
70 | + "key-secret": "sec0" | ||
71 | + } | ||
72 | + } | ||
73 | + } | ||
74 | +{ "execute": "quit" } | ||
75 | +EOF | ||
76 | + | ||
77 | +echo | ||
78 | echo === Missing driver === | ||
79 | echo | ||
80 | |||
81 | diff --git a/tests/qemu-iotests/087.out b/tests/qemu-iotests/087.out | ||
82 | index XXXXXXX..XXXXXXX 100644 | ||
83 | --- a/tests/qemu-iotests/087.out | ||
84 | +++ b/tests/qemu-iotests/087.out | ||
85 | @@ -XXX,XX +XXX,XX @@ QMP_VERSION | ||
86 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} | ||
87 | |||
88 | |||
89 | -=== Encrypted image === | ||
90 | +=== Encrypted image QCow === | ||
91 | |||
92 | Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encryption=on encrypt.key-secret=sec0 | ||
93 | Testing: | ||
94 | @@ -XXX,XX +XXX,XX @@ QMP_VERSION | ||
95 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} | ||
96 | |||
97 | |||
98 | +=== Encrypted image LUKS === | ||
99 | + | ||
100 | +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encrypt.format=luks encrypt.key-secret=sec0 | ||
101 | +Testing: | ||
102 | +QMP_VERSION | ||
103 | +{"return": {}} | ||
104 | +{"return": {}} | ||
105 | +{"return": {}} | ||
106 | +{"return": {}} | ||
107 | +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} | ||
108 | + | ||
109 | + | ||
110 | === Missing driver === | ||
111 | |||
112 | Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encryption=on encrypt.key-secret=sec0 | ||
113 | diff --git a/tests/qemu-iotests/188 b/tests/qemu-iotests/188 | ||
114 | new file mode 100755 | ||
115 | index XXXXXXX..XXXXXXX | ||
116 | --- /dev/null | ||
117 | +++ b/tests/qemu-iotests/188 | ||
118 | @@ -XXX,XX +XXX,XX @@ | ||
119 | +#!/bin/bash | ||
120 | +# | ||
121 | +# Test encrypted read/write using plain bdrv_read/bdrv_write | ||
122 | +# | ||
123 | +# Copyright (C) 2017 Red Hat, Inc. | ||
124 | +# | ||
125 | +# This program is free software; you can redistribute it and/or modify | ||
126 | +# it under the terms of the GNU General Public License as published by | ||
127 | +# the Free Software Foundation; either version 2 of the License, or | ||
128 | +# (at your option) any later version. | ||
129 | +# | ||
130 | +# This program is distributed in the hope that it will be useful, | ||
131 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
132 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
133 | +# GNU General Public License for more details. | ||
134 | +# | ||
135 | +# You should have received a copy of the GNU General Public License | ||
136 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
137 | +# | ||
138 | + | ||
139 | +# creator | ||
140 | +owner=berrange@redhat.com | ||
141 | + | ||
142 | +seq=`basename $0` | ||
143 | +echo "QA output created by $seq" | ||
144 | + | ||
145 | +here=`pwd` | ||
146 | +status=1 # failure is the default! | ||
147 | + | ||
148 | +_cleanup() | ||
149 | +{ | ||
150 | + _cleanup_test_img | ||
151 | +} | ||
152 | +trap "_cleanup; exit \$status" 0 1 2 3 15 | ||
153 | + | ||
154 | +# get standard environment, filters and checks | ||
155 | +. ./common.rc | ||
156 | +. ./common.filter | ||
157 | + | ||
158 | +_supported_fmt qcow2 | ||
159 | +_supported_proto generic | ||
160 | +_supported_os Linux | ||
161 | + | ||
162 | + | ||
163 | +size=16M | ||
164 | + | ||
165 | +SECRET="secret,id=sec0,data=astrochicken" | ||
166 | +SECRETALT="secret,id=sec0,data=platypus" | ||
167 | + | ||
168 | +_make_test_img --object $SECRET -o "encrypt.format=luks,encrypt.key-secret=sec0,encrypt.iter-time=10" $size | ||
169 | + | ||
170 | +IMGSPEC="driver=$IMGFMT,file.filename=$TEST_IMG,encrypt.key-secret=sec0" | ||
171 | + | ||
172 | +QEMU_IO_OPTIONS=$QEMU_IO_OPTIONS_NO_FMT | ||
173 | + | ||
174 | +echo | ||
175 | +echo "== reading whole image ==" | ||
176 | +$QEMU_IO --object $SECRET -c "read -P 0 0 $size" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir | ||
177 | + | ||
178 | +echo | ||
179 | +echo "== rewriting whole image ==" | ||
180 | +$QEMU_IO --object $SECRET -c "write -P 0xa 0 $size" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir | ||
181 | + | ||
182 | +echo | ||
183 | +echo "== verify pattern ==" | ||
184 | +$QEMU_IO --object $SECRET -c "read -P 0xa 0 $size" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir | ||
185 | + | ||
186 | +echo | ||
187 | +echo "== verify open failure with wrong password ==" | ||
188 | +$QEMU_IO --object $SECRETALT -c "read -P 0xa 0 $size" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir | ||
189 | + | ||
190 | + | ||
191 | +# success, all done | ||
192 | +echo "*** done" | ||
193 | +rm -f $seq.full | ||
194 | +status=0 | ||
195 | diff --git a/tests/qemu-iotests/188.out b/tests/qemu-iotests/188.out | ||
196 | new file mode 100644 | ||
197 | index XXXXXXX..XXXXXXX | ||
198 | --- /dev/null | ||
199 | +++ b/tests/qemu-iotests/188.out | ||
200 | @@ -XXX,XX +XXX,XX @@ | ||
201 | +QA output created by 188 | ||
202 | +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=16777216 encrypt.format=luks encrypt.key-secret=sec0 encrypt.iter-time=10 | ||
203 | + | ||
204 | +== reading whole image == | ||
205 | +read 16777216/16777216 bytes at offset 0 | ||
206 | +16 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
207 | + | ||
208 | +== rewriting whole image == | ||
209 | +wrote 16777216/16777216 bytes at offset 0 | ||
210 | +16 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
211 | + | ||
212 | +== verify pattern == | ||
213 | +read 16777216/16777216 bytes at offset 0 | ||
214 | +16 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
215 | + | ||
216 | +== verify open failure with wrong password == | ||
217 | +can't open: Invalid password, cannot unlock any keyslot | ||
218 | +*** done | ||
219 | diff --git a/tests/qemu-iotests/189 b/tests/qemu-iotests/189 | ||
220 | new file mode 100755 | ||
221 | index XXXXXXX..XXXXXXX | ||
222 | --- /dev/null | ||
223 | +++ b/tests/qemu-iotests/189 | ||
224 | @@ -XXX,XX +XXX,XX @@ | ||
225 | +#!/bin/bash | ||
226 | +# | ||
227 | +# Test encrypted read/write using backing files | ||
228 | +# | ||
229 | +# Copyright (C) 2017 Red Hat, Inc. | ||
230 | +# | ||
231 | +# This program is free software; you can redistribute it and/or modify | ||
232 | +# it under the terms of the GNU General Public License as published by | ||
233 | +# the Free Software Foundation; either version 2 of the License, or | ||
234 | +# (at your option) any later version. | ||
235 | +# | ||
236 | +# This program is distributed in the hope that it will be useful, | ||
237 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
238 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
239 | +# GNU General Public License for more details. | ||
240 | +# | ||
241 | +# You should have received a copy of the GNU General Public License | ||
242 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
243 | +# | ||
244 | + | ||
245 | +# creator | ||
246 | +owner=berrange@redhat.com | ||
247 | + | ||
248 | +seq=`basename $0` | ||
249 | +echo "QA output created by $seq" | ||
250 | + | ||
251 | +here=`pwd` | ||
252 | +status=1 # failure is the default! | ||
253 | + | ||
254 | +_cleanup() | ||
255 | +{ | ||
256 | + _cleanup_test_img | ||
257 | +} | ||
258 | +trap "_cleanup; exit \$status" 0 1 2 3 15 | ||
259 | + | ||
260 | +# get standard environment, filters and checks | ||
261 | +. ./common.rc | ||
262 | +. ./common.filter | ||
263 | + | ||
264 | +_supported_fmt qcow2 | ||
265 | +_supported_proto generic | ||
266 | +_supported_os Linux | ||
267 | + | ||
268 | + | ||
269 | +size=16M | ||
270 | +TEST_IMG_BASE=$TEST_IMG.base | ||
271 | +SECRET0="secret,id=sec0,data=astrochicken" | ||
272 | +SECRET1="secret,id=sec1,data=furby" | ||
273 | + | ||
274 | +TEST_IMG_SAVE=$TEST_IMG | ||
275 | +TEST_IMG=$TEST_IMG_BASE | ||
276 | +echo "== create base ==" | ||
277 | +_make_test_img --object $SECRET0 -o "encrypt.format=luks,encrypt.key-secret=sec0,encrypt.iter-time=10" $size | ||
278 | +TEST_IMG=$TEST_IMG_SAVE | ||
279 | + | ||
280 | +IMGSPECBASE="driver=$IMGFMT,file.filename=$TEST_IMG_BASE,encrypt.key-secret=sec0" | ||
281 | +IMGSPEC="driver=$IMGFMT,file.filename=$TEST_IMG,backing.driver=$IMGFMT,backing.file.filename=$TEST_IMG_BASE,backing.encrypt.key-secret=sec0,encrypt.key-secret=sec1" | ||
282 | +QEMU_IO_OPTIONS=$QEMU_IO_OPTIONS_NO_FMT | ||
283 | + | ||
284 | +echo | ||
285 | +echo "== writing whole image ==" | ||
286 | +$QEMU_IO --object $SECRET0 -c "write -P 0xa 0 $size" --image-opts $IMGSPECBASE | _filter_qemu_io | _filter_testdir | ||
287 | + | ||
288 | +echo | ||
289 | +echo "== verify pattern ==" | ||
290 | +$QEMU_IO --object $SECRET0 -c "read -P 0xa 0 $size" --image-opts $IMGSPECBASE | _filter_qemu_io | _filter_testdir | ||
291 | + | ||
292 | +echo "== create overlay ==" | ||
293 | +_make_test_img --object $SECRET1 -o "encrypt.format=luks,encrypt.key-secret=sec1,encrypt.iter-time=10" -b "$TEST_IMG_BASE" $size | ||
294 | + | ||
295 | +echo | ||
296 | +echo "== writing part of a cluster ==" | ||
297 | +$QEMU_IO --object $SECRET0 --object $SECRET1 -c "write -P 0xe 0 1024" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir | ||
298 | + | ||
299 | +echo | ||
300 | +echo "== verify pattern ==" | ||
301 | +$QEMU_IO --object $SECRET0 --object $SECRET1 -c "read -P 0xe 0 1024" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir | ||
302 | +echo | ||
303 | +echo "== verify pattern ==" | ||
304 | +$QEMU_IO --object $SECRET0 --object $SECRET1 -c "read -P 0xa 1024 64512" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir | ||
305 | + | ||
306 | + | ||
307 | +# success, all done | ||
308 | +echo "*** done" | ||
309 | +rm -f $seq.full | ||
310 | +status=0 | ||
311 | diff --git a/tests/qemu-iotests/189.out b/tests/qemu-iotests/189.out | ||
312 | new file mode 100644 | ||
313 | index XXXXXXX..XXXXXXX | ||
314 | --- /dev/null | ||
315 | +++ b/tests/qemu-iotests/189.out | ||
316 | @@ -XXX,XX +XXX,XX @@ | ||
317 | +QA output created by 189 | ||
318 | +== create base == | ||
319 | +Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=16777216 encrypt.format=luks encrypt.key-secret=sec0 encrypt.iter-time=10 | ||
320 | + | ||
321 | +== writing whole image == | ||
322 | +wrote 16777216/16777216 bytes at offset 0 | ||
323 | +16 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
324 | + | ||
325 | +== verify pattern == | ||
326 | +read 16777216/16777216 bytes at offset 0 | ||
327 | +16 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
328 | +== create overlay == | ||
329 | +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=16777216 backing_file=TEST_DIR/t.IMGFMT.base encrypt.format=luks encrypt.key-secret=sec1 encrypt.iter-time=10 | ||
330 | + | ||
331 | +== writing part of a cluster == | ||
332 | +wrote 1024/1024 bytes at offset 0 | ||
333 | +1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
334 | + | ||
335 | +== verify pattern == | ||
336 | +read 1024/1024 bytes at offset 0 | ||
337 | +1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
338 | + | ||
339 | +== verify pattern == | ||
340 | +read 64512/64512 bytes at offset 1024 | ||
341 | +63 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
342 | +*** done | ||
343 | diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group | ||
344 | index XXXXXXX..XXXXXXX 100644 | ||
345 | --- a/tests/qemu-iotests/group | ||
346 | +++ b/tests/qemu-iotests/group | ||
347 | @@ -XXX,XX +XXX,XX @@ | ||
348 | 182 rw auto quick | ||
349 | 183 rw auto migration | ||
350 | 185 rw auto | ||
351 | +188 rw auto quick | ||
352 | +189 rw auto quick | ||
353 | -- | ||
354 | 1.8.3.1 | ||
355 | |||
356 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: "Daniel P. Berrange" <berrange@redhat.com> | ||
2 | 1 | ||
3 | The 138 and 158 iotests exercise the legacy qcow2 aes encryption | ||
4 | code path and they work fine with qcow v1 too. | ||
5 | |||
6 | Reviewed-by: Alberto Garcia <berto@igalia.com> | ||
7 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
8 | Signed-off-by: Daniel P. Berrange <berrange@redhat.com> | ||
9 | Message-id: 20170623162419.26068-16-berrange@redhat.com | ||
10 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
11 | --- | ||
12 | tests/qemu-iotests/134 | 2 +- | ||
13 | tests/qemu-iotests/158 | 2 +- | ||
14 | 2 files changed, 2 insertions(+), 2 deletions(-) | ||
15 | |||
16 | diff --git a/tests/qemu-iotests/134 b/tests/qemu-iotests/134 | ||
17 | index XXXXXXX..XXXXXXX 100755 | ||
18 | --- a/tests/qemu-iotests/134 | ||
19 | +++ b/tests/qemu-iotests/134 | ||
20 | @@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15 | ||
21 | . ./common.rc | ||
22 | . ./common.filter | ||
23 | |||
24 | -_supported_fmt qcow2 | ||
25 | +_supported_fmt qcow qcow2 | ||
26 | _supported_proto generic | ||
27 | _unsupported_proto vxhs | ||
28 | _supported_os Linux | ||
29 | diff --git a/tests/qemu-iotests/158 b/tests/qemu-iotests/158 | ||
30 | index XXXXXXX..XXXXXXX 100755 | ||
31 | --- a/tests/qemu-iotests/158 | ||
32 | +++ b/tests/qemu-iotests/158 | ||
33 | @@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15 | ||
34 | . ./common.rc | ||
35 | . ./common.filter | ||
36 | |||
37 | -_supported_fmt qcow2 | ||
38 | +_supported_fmt qcow qcow2 | ||
39 | _supported_proto generic | ||
40 | _unsupported_proto vxhs | ||
41 | _supported_os Linux | ||
42 | -- | ||
43 | 1.8.3.1 | ||
44 | |||
45 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: "Daniel P. Berrange" <berrange@redhat.com> | ||
2 | 1 | ||
3 | While the crypto layer uses a fixed option name "key-secret", | ||
4 | the upper block layer may have a prefix on the options. e.g. | ||
5 | "encrypt.key-secret", in order to avoid clashes between crypto | ||
6 | option names & other block option names. To ensure the crypto | ||
7 | layer can report accurate error messages, we must tell it what | ||
8 | option name prefix was used. | ||
9 | |||
10 | Reviewed-by: Alberto Garcia <berto@igalia.com> | ||
11 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
12 | Signed-off-by: Daniel P. Berrange <berrange@redhat.com> | ||
13 | Message-id: 20170623162419.26068-19-berrange@redhat.com | ||
14 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
15 | --- | ||
16 | block/crypto.c | 4 ++-- | ||
17 | block/qcow.c | 7 ++++--- | ||
18 | block/qcow2.c | 8 ++++---- | ||
19 | crypto/block-luks.c | 8 ++++++-- | ||
20 | crypto/block-qcow.c | 8 ++++++-- | ||
21 | crypto/block.c | 6 ++++-- | ||
22 | crypto/blockpriv.h | 2 ++ | ||
23 | include/crypto/block.h | 6 +++++- | ||
24 | tests/test-crypto-block.c | 8 ++++---- | ||
25 | 9 files changed, 37 insertions(+), 20 deletions(-) | ||
26 | |||
27 | diff --git a/block/crypto.c b/block/crypto.c | ||
28 | index XXXXXXX..XXXXXXX 100644 | ||
29 | --- a/block/crypto.c | ||
30 | +++ b/block/crypto.c | ||
31 | @@ -XXX,XX +XXX,XX @@ static int block_crypto_open_generic(QCryptoBlockFormat format, | ||
32 | if (flags & BDRV_O_NO_IO) { | ||
33 | cflags |= QCRYPTO_BLOCK_OPEN_NO_IO; | ||
34 | } | ||
35 | - crypto->block = qcrypto_block_open(open_opts, | ||
36 | + crypto->block = qcrypto_block_open(open_opts, NULL, | ||
37 | block_crypto_read_func, | ||
38 | bs, | ||
39 | cflags, | ||
40 | @@ -XXX,XX +XXX,XX @@ static int block_crypto_create_generic(QCryptoBlockFormat format, | ||
41 | return -1; | ||
42 | } | ||
43 | |||
44 | - crypto = qcrypto_block_create(create_opts, | ||
45 | + crypto = qcrypto_block_create(create_opts, NULL, | ||
46 | block_crypto_init_func, | ||
47 | block_crypto_write_func, | ||
48 | &data, | ||
49 | diff --git a/block/qcow.c b/block/qcow.c | ||
50 | index XXXXXXX..XXXXXXX 100644 | ||
51 | --- a/block/qcow.c | ||
52 | +++ b/block/qcow.c | ||
53 | @@ -XXX,XX +XXX,XX @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags, | ||
54 | if (flags & BDRV_O_NO_IO) { | ||
55 | cflags |= QCRYPTO_BLOCK_OPEN_NO_IO; | ||
56 | } | ||
57 | - s->crypto = qcrypto_block_open(crypto_opts, NULL, NULL, | ||
58 | - cflags, errp); | ||
59 | + s->crypto = qcrypto_block_open(crypto_opts, "encrypt.", | ||
60 | + NULL, NULL, cflags, errp); | ||
61 | if (!s->crypto) { | ||
62 | ret = -EINVAL; | ||
63 | goto fail; | ||
64 | @@ -XXX,XX +XXX,XX @@ static int qcow_create(const char *filename, QemuOpts *opts, Error **errp) | ||
65 | goto exit; | ||
66 | } | ||
67 | |||
68 | - crypto = qcrypto_block_create(crypto_opts, NULL, NULL, NULL, errp); | ||
69 | + crypto = qcrypto_block_create(crypto_opts, "encrypt.", | ||
70 | + NULL, NULL, NULL, errp); | ||
71 | if (!crypto) { | ||
72 | ret = -EINVAL; | ||
73 | goto exit; | ||
74 | diff --git a/block/qcow2.c b/block/qcow2.c | ||
75 | index XXXXXXX..XXXXXXX 100644 | ||
76 | --- a/block/qcow2.c | ||
77 | +++ b/block/qcow2.c | ||
78 | @@ -XXX,XX +XXX,XX @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset, | ||
79 | if (flags & BDRV_O_NO_IO) { | ||
80 | cflags |= QCRYPTO_BLOCK_OPEN_NO_IO; | ||
81 | } | ||
82 | - s->crypto = qcrypto_block_open(s->crypto_opts, | ||
83 | + s->crypto = qcrypto_block_open(s->crypto_opts, "encrypt.", | ||
84 | qcow2_crypto_hdr_read_func, | ||
85 | bs, cflags, errp); | ||
86 | if (!s->crypto) { | ||
87 | @@ -XXX,XX +XXX,XX @@ static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags, | ||
88 | if (flags & BDRV_O_NO_IO) { | ||
89 | cflags |= QCRYPTO_BLOCK_OPEN_NO_IO; | ||
90 | } | ||
91 | - s->crypto = qcrypto_block_open(s->crypto_opts, NULL, NULL, | ||
92 | - cflags, errp); | ||
93 | + s->crypto = qcrypto_block_open(s->crypto_opts, "encrypt.", | ||
94 | + NULL, NULL, cflags, errp); | ||
95 | if (!s->crypto) { | ||
96 | ret = -EINVAL; | ||
97 | goto fail; | ||
98 | @@ -XXX,XX +XXX,XX @@ static int qcow2_set_up_encryption(BlockDriverState *bs, const char *encryptfmt, | ||
99 | } | ||
100 | s->crypt_method_header = fmt; | ||
101 | |||
102 | - crypto = qcrypto_block_create(cryptoopts, | ||
103 | + crypto = qcrypto_block_create(cryptoopts, "encrypt.", | ||
104 | qcow2_crypto_hdr_init_func, | ||
105 | qcow2_crypto_hdr_write_func, | ||
106 | bs, errp); | ||
107 | diff --git a/crypto/block-luks.c b/crypto/block-luks.c | ||
108 | index XXXXXXX..XXXXXXX 100644 | ||
109 | --- a/crypto/block-luks.c | ||
110 | +++ b/crypto/block-luks.c | ||
111 | @@ -XXX,XX +XXX,XX @@ qcrypto_block_luks_find_key(QCryptoBlock *block, | ||
112 | static int | ||
113 | qcrypto_block_luks_open(QCryptoBlock *block, | ||
114 | QCryptoBlockOpenOptions *options, | ||
115 | + const char *optprefix, | ||
116 | QCryptoBlockReadFunc readfunc, | ||
117 | void *opaque, | ||
118 | unsigned int flags, | ||
119 | @@ -XXX,XX +XXX,XX @@ qcrypto_block_luks_open(QCryptoBlock *block, | ||
120 | |||
121 | if (!(flags & QCRYPTO_BLOCK_OPEN_NO_IO)) { | ||
122 | if (!options->u.luks.key_secret) { | ||
123 | - error_setg(errp, "Parameter 'key-secret' is required for cipher"); | ||
124 | + error_setg(errp, "Parameter '%skey-secret' is required for cipher", | ||
125 | + optprefix ? optprefix : ""); | ||
126 | return -1; | ||
127 | } | ||
128 | password = qcrypto_secret_lookup_as_utf8( | ||
129 | @@ -XXX,XX +XXX,XX @@ qcrypto_block_luks_uuid_gen(uint8_t *uuidstr) | ||
130 | static int | ||
131 | qcrypto_block_luks_create(QCryptoBlock *block, | ||
132 | QCryptoBlockCreateOptions *options, | ||
133 | + const char *optprefix, | ||
134 | QCryptoBlockInitFunc initfunc, | ||
135 | QCryptoBlockWriteFunc writefunc, | ||
136 | void *opaque, | ||
137 | @@ -XXX,XX +XXX,XX @@ qcrypto_block_luks_create(QCryptoBlock *block, | ||
138 | * be silently ignored, for compatibility with dm-crypt */ | ||
139 | |||
140 | if (!options->u.luks.key_secret) { | ||
141 | - error_setg(errp, "Parameter 'key-secret' is required for cipher"); | ||
142 | + error_setg(errp, "Parameter '%skey-secret' is required for cipher", | ||
143 | + optprefix ? optprefix : ""); | ||
144 | return -1; | ||
145 | } | ||
146 | password = qcrypto_secret_lookup_as_utf8(luks_opts.key_secret, errp); | ||
147 | diff --git a/crypto/block-qcow.c b/crypto/block-qcow.c | ||
148 | index XXXXXXX..XXXXXXX 100644 | ||
149 | --- a/crypto/block-qcow.c | ||
150 | +++ b/crypto/block-qcow.c | ||
151 | @@ -XXX,XX +XXX,XX @@ qcrypto_block_qcow_init(QCryptoBlock *block, | ||
152 | static int | ||
153 | qcrypto_block_qcow_open(QCryptoBlock *block, | ||
154 | QCryptoBlockOpenOptions *options, | ||
155 | + const char *optprefix, | ||
156 | QCryptoBlockReadFunc readfunc G_GNUC_UNUSED, | ||
157 | void *opaque G_GNUC_UNUSED, | ||
158 | unsigned int flags, | ||
159 | @@ -XXX,XX +XXX,XX @@ qcrypto_block_qcow_open(QCryptoBlock *block, | ||
160 | } else { | ||
161 | if (!options->u.qcow.key_secret) { | ||
162 | error_setg(errp, | ||
163 | - "Parameter 'key-secret' is required for cipher"); | ||
164 | + "Parameter '%skey-secret' is required for cipher", | ||
165 | + optprefix ? optprefix : ""); | ||
166 | return -1; | ||
167 | } | ||
168 | return qcrypto_block_qcow_init(block, | ||
169 | @@ -XXX,XX +XXX,XX @@ qcrypto_block_qcow_open(QCryptoBlock *block, | ||
170 | static int | ||
171 | qcrypto_block_qcow_create(QCryptoBlock *block, | ||
172 | QCryptoBlockCreateOptions *options, | ||
173 | + const char *optprefix, | ||
174 | QCryptoBlockInitFunc initfunc G_GNUC_UNUSED, | ||
175 | QCryptoBlockWriteFunc writefunc G_GNUC_UNUSED, | ||
176 | void *opaque G_GNUC_UNUSED, | ||
177 | Error **errp) | ||
178 | { | ||
179 | if (!options->u.qcow.key_secret) { | ||
180 | - error_setg(errp, "Parameter 'key-secret' is required for cipher"); | ||
181 | + error_setg(errp, "Parameter '%skey-secret' is required for cipher", | ||
182 | + optprefix ? optprefix : ""); | ||
183 | return -1; | ||
184 | } | ||
185 | /* QCow2 has no special header, since everything is hardwired */ | ||
186 | diff --git a/crypto/block.c b/crypto/block.c | ||
187 | index XXXXXXX..XXXXXXX 100644 | ||
188 | --- a/crypto/block.c | ||
189 | +++ b/crypto/block.c | ||
190 | @@ -XXX,XX +XXX,XX @@ bool qcrypto_block_has_format(QCryptoBlockFormat format, | ||
191 | |||
192 | |||
193 | QCryptoBlock *qcrypto_block_open(QCryptoBlockOpenOptions *options, | ||
194 | + const char *optprefix, | ||
195 | QCryptoBlockReadFunc readfunc, | ||
196 | void *opaque, | ||
197 | unsigned int flags, | ||
198 | @@ -XXX,XX +XXX,XX @@ QCryptoBlock *qcrypto_block_open(QCryptoBlockOpenOptions *options, | ||
199 | |||
200 | block->driver = qcrypto_block_drivers[options->format]; | ||
201 | |||
202 | - if (block->driver->open(block, options, | ||
203 | + if (block->driver->open(block, options, optprefix, | ||
204 | readfunc, opaque, flags, errp) < 0) { | ||
205 | g_free(block); | ||
206 | return NULL; | ||
207 | @@ -XXX,XX +XXX,XX @@ QCryptoBlock *qcrypto_block_open(QCryptoBlockOpenOptions *options, | ||
208 | |||
209 | |||
210 | QCryptoBlock *qcrypto_block_create(QCryptoBlockCreateOptions *options, | ||
211 | + const char *optprefix, | ||
212 | QCryptoBlockInitFunc initfunc, | ||
213 | QCryptoBlockWriteFunc writefunc, | ||
214 | void *opaque, | ||
215 | @@ -XXX,XX +XXX,XX @@ QCryptoBlock *qcrypto_block_create(QCryptoBlockCreateOptions *options, | ||
216 | |||
217 | block->driver = qcrypto_block_drivers[options->format]; | ||
218 | |||
219 | - if (block->driver->create(block, options, initfunc, | ||
220 | + if (block->driver->create(block, options, optprefix, initfunc, | ||
221 | writefunc, opaque, errp) < 0) { | ||
222 | g_free(block); | ||
223 | return NULL; | ||
224 | diff --git a/crypto/blockpriv.h b/crypto/blockpriv.h | ||
225 | index XXXXXXX..XXXXXXX 100644 | ||
226 | --- a/crypto/blockpriv.h | ||
227 | +++ b/crypto/blockpriv.h | ||
228 | @@ -XXX,XX +XXX,XX @@ struct QCryptoBlock { | ||
229 | struct QCryptoBlockDriver { | ||
230 | int (*open)(QCryptoBlock *block, | ||
231 | QCryptoBlockOpenOptions *options, | ||
232 | + const char *optprefix, | ||
233 | QCryptoBlockReadFunc readfunc, | ||
234 | void *opaque, | ||
235 | unsigned int flags, | ||
236 | @@ -XXX,XX +XXX,XX @@ struct QCryptoBlockDriver { | ||
237 | |||
238 | int (*create)(QCryptoBlock *block, | ||
239 | QCryptoBlockCreateOptions *options, | ||
240 | + const char *optprefix, | ||
241 | QCryptoBlockInitFunc initfunc, | ||
242 | QCryptoBlockWriteFunc writefunc, | ||
243 | void *opaque, | ||
244 | diff --git a/include/crypto/block.h b/include/crypto/block.h | ||
245 | index XXXXXXX..XXXXXXX 100644 | ||
246 | --- a/include/crypto/block.h | ||
247 | +++ b/include/crypto/block.h | ||
248 | @@ -XXX,XX +XXX,XX @@ typedef enum { | ||
249 | /** | ||
250 | * qcrypto_block_open: | ||
251 | * @options: the encryption options | ||
252 | + * @optprefix: name prefix for options | ||
253 | * @readfunc: callback for reading data from the volume | ||
254 | * @opaque: data to pass to @readfunc | ||
255 | * @flags: bitmask of QCryptoBlockOpenFlags values | ||
256 | @@ -XXX,XX +XXX,XX @@ typedef enum { | ||
257 | * Returns: a block encryption format, or NULL on error | ||
258 | */ | ||
259 | QCryptoBlock *qcrypto_block_open(QCryptoBlockOpenOptions *options, | ||
260 | + const char *optprefix, | ||
261 | QCryptoBlockReadFunc readfunc, | ||
262 | void *opaque, | ||
263 | unsigned int flags, | ||
264 | @@ -XXX,XX +XXX,XX @@ QCryptoBlock *qcrypto_block_open(QCryptoBlockOpenOptions *options, | ||
265 | |||
266 | /** | ||
267 | * qcrypto_block_create: | ||
268 | - * @format: the encryption format | ||
269 | + * @options: the encryption options | ||
270 | + * @optprefix: name prefix for options | ||
271 | * @initfunc: callback for initializing volume header | ||
272 | * @writefunc: callback for writing data to the volume header | ||
273 | * @opaque: data to pass to @initfunc and @writefunc | ||
274 | @@ -XXX,XX +XXX,XX @@ QCryptoBlock *qcrypto_block_open(QCryptoBlockOpenOptions *options, | ||
275 | * Returns: a block encryption format, or NULL on error | ||
276 | */ | ||
277 | QCryptoBlock *qcrypto_block_create(QCryptoBlockCreateOptions *options, | ||
278 | + const char *optprefix, | ||
279 | QCryptoBlockInitFunc initfunc, | ||
280 | QCryptoBlockWriteFunc writefunc, | ||
281 | void *opaque, | ||
282 | diff --git a/tests/test-crypto-block.c b/tests/test-crypto-block.c | ||
283 | index XXXXXXX..XXXXXXX 100644 | ||
284 | --- a/tests/test-crypto-block.c | ||
285 | +++ b/tests/test-crypto-block.c | ||
286 | @@ -XXX,XX +XXX,XX @@ static void test_block(gconstpointer opaque) | ||
287 | memset(&header, 0, sizeof(header)); | ||
288 | buffer_init(&header, "header"); | ||
289 | |||
290 | - blk = qcrypto_block_create(data->create_opts, | ||
291 | + blk = qcrypto_block_create(data->create_opts, NULL, | ||
292 | test_block_init_func, | ||
293 | test_block_write_func, | ||
294 | &header, | ||
295 | @@ -XXX,XX +XXX,XX @@ static void test_block(gconstpointer opaque) | ||
296 | object_unparent(sec); | ||
297 | |||
298 | /* Ensure we can't open without the secret */ | ||
299 | - blk = qcrypto_block_open(data->open_opts, | ||
300 | + blk = qcrypto_block_open(data->open_opts, NULL, | ||
301 | test_block_read_func, | ||
302 | &header, | ||
303 | 0, | ||
304 | @@ -XXX,XX +XXX,XX @@ static void test_block(gconstpointer opaque) | ||
305 | g_assert(blk == NULL); | ||
306 | |||
307 | /* Ensure we can't open without the secret, unless NO_IO */ | ||
308 | - blk = qcrypto_block_open(data->open_opts, | ||
309 | + blk = qcrypto_block_open(data->open_opts, NULL, | ||
310 | test_block_read_func, | ||
311 | &header, | ||
312 | QCRYPTO_BLOCK_OPEN_NO_IO, | ||
313 | @@ -XXX,XX +XXX,XX @@ static void test_block(gconstpointer opaque) | ||
314 | |||
315 | /* Now open for real with secret */ | ||
316 | sec = test_block_secret(); | ||
317 | - blk = qcrypto_block_open(data->open_opts, | ||
318 | + blk = qcrypto_block_open(data->open_opts, NULL, | ||
319 | test_block_read_func, | ||
320 | &header, | ||
321 | 0, | ||
322 | -- | ||
323 | 1.8.3.1 | ||
324 | |||
325 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: "Daniel P. Berrange" <berrange@redhat.com> | ||
2 | 1 | ||
3 | Currently 'qemu-img info' reports a simple "encrypted: yes" | ||
4 | field. This is not very useful now that qcow2 can support | ||
5 | multiple encryption formats. Users want to know which format | ||
6 | is in use and some data related to it. | ||
7 | |||
8 | Wire up usage of the qcrypto_block_get_info() method so that | ||
9 | 'qemu-img info' can report about the encryption format | ||
10 | and parameters in use | ||
11 | |||
12 | $ qemu-img create \ | ||
13 | --object secret,id=sec0,data=123456 \ | ||
14 | -o encrypt.format=luks,encrypt.key-secret=sec0 \ | ||
15 | -f qcow2 demo.qcow2 1G | ||
16 | Formatting 'demo.qcow2', fmt=qcow2 size=1073741824 \ | ||
17 | encryption=off encrypt.format=luks encrypt.key-secret=sec0 \ | ||
18 | cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
19 | |||
20 | $ qemu-img info demo.qcow2 | ||
21 | image: demo.qcow2 | ||
22 | file format: qcow2 | ||
23 | virtual size: 1.0G (1073741824 bytes) | ||
24 | disk size: 480K | ||
25 | encrypted: yes | ||
26 | cluster_size: 65536 | ||
27 | Format specific information: | ||
28 | compat: 1.1 | ||
29 | lazy refcounts: false | ||
30 | refcount bits: 16 | ||
31 | encrypt: | ||
32 | ivgen alg: plain64 | ||
33 | hash alg: sha256 | ||
34 | cipher alg: aes-256 | ||
35 | uuid: 3fa930c4-58c8-4ef7-b3c5-314bb5af21f3 | ||
36 | format: luks | ||
37 | cipher mode: xts | ||
38 | slots: | ||
39 | [0]: | ||
40 | active: true | ||
41 | iters: 1839058 | ||
42 | key offset: 4096 | ||
43 | stripes: 4000 | ||
44 | [1]: | ||
45 | active: false | ||
46 | key offset: 262144 | ||
47 | [2]: | ||
48 | active: false | ||
49 | key offset: 520192 | ||
50 | [3]: | ||
51 | active: false | ||
52 | key offset: 778240 | ||
53 | [4]: | ||
54 | active: false | ||
55 | key offset: 1036288 | ||
56 | [5]: | ||
57 | active: false | ||
58 | key offset: 1294336 | ||
59 | [6]: | ||
60 | active: false | ||
61 | key offset: 1552384 | ||
62 | [7]: | ||
63 | active: false | ||
64 | key offset: 1810432 | ||
65 | payload offset: 2068480 | ||
66 | master key iters: 438487 | ||
67 | corrupt: false | ||
68 | |||
69 | With the legacy "AES" encryption we just report the format | ||
70 | name | ||
71 | |||
72 | $ qemu-img create \ | ||
73 | --object secret,id=sec0,data=123456 \ | ||
74 | -o encrypt.format=aes,encrypt.key-secret=sec0 \ | ||
75 | -f qcow2 demo.qcow2 1G | ||
76 | Formatting 'demo.qcow2', fmt=qcow2 size=1073741824 \ | ||
77 | encryption=off encrypt.format=aes encrypt.key-secret=sec0 \ | ||
78 | cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
79 | |||
80 | $ ./qemu-img info demo.qcow2 | ||
81 | image: demo.qcow2 | ||
82 | file format: qcow2 | ||
83 | virtual size: 1.0G (1073741824 bytes) | ||
84 | disk size: 196K | ||
85 | encrypted: yes | ||
86 | cluster_size: 65536 | ||
87 | Format specific information: | ||
88 | compat: 1.1 | ||
89 | lazy refcounts: false | ||
90 | refcount bits: 16 | ||
91 | encrypt: | ||
92 | format: aes | ||
93 | corrupt: false | ||
94 | |||
95 | Reviewed-by: Alberto Garcia <berto@igalia.com> | ||
96 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
97 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
98 | Signed-off-by: Daniel P. Berrange <berrange@redhat.com> | ||
99 | Message-id: 20170623162419.26068-20-berrange@redhat.com | ||
100 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
101 | --- | ||
102 | block/qcow2.c | 32 +++++++++++++++++++++++++++++++- | ||
103 | qapi/block-core.json | 27 ++++++++++++++++++++++++++- | ||
104 | 2 files changed, 57 insertions(+), 2 deletions(-) | ||
105 | |||
106 | diff --git a/block/qcow2.c b/block/qcow2.c | ||
107 | index XXXXXXX..XXXXXXX 100644 | ||
108 | --- a/block/qcow2.c | ||
109 | +++ b/block/qcow2.c | ||
110 | @@ -XXX,XX +XXX,XX @@ static int qcow2_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) | ||
111 | static ImageInfoSpecific *qcow2_get_specific_info(BlockDriverState *bs) | ||
112 | { | ||
113 | BDRVQcow2State *s = bs->opaque; | ||
114 | - ImageInfoSpecific *spec_info = g_new(ImageInfoSpecific, 1); | ||
115 | + ImageInfoSpecific *spec_info; | ||
116 | + QCryptoBlockInfo *encrypt_info = NULL; | ||
117 | |||
118 | + if (s->crypto != NULL) { | ||
119 | + encrypt_info = qcrypto_block_get_info(s->crypto, &error_abort); | ||
120 | + } | ||
121 | + | ||
122 | + spec_info = g_new(ImageInfoSpecific, 1); | ||
123 | *spec_info = (ImageInfoSpecific){ | ||
124 | .type = IMAGE_INFO_SPECIFIC_KIND_QCOW2, | ||
125 | .u.qcow2.data = g_new(ImageInfoSpecificQCow2, 1), | ||
126 | @@ -XXX,XX +XXX,XX @@ static ImageInfoSpecific *qcow2_get_specific_info(BlockDriverState *bs) | ||
127 | assert(false); | ||
128 | } | ||
129 | |||
130 | + if (encrypt_info) { | ||
131 | + ImageInfoSpecificQCow2Encryption *qencrypt = | ||
132 | + g_new(ImageInfoSpecificQCow2Encryption, 1); | ||
133 | + switch (encrypt_info->format) { | ||
134 | + case Q_CRYPTO_BLOCK_FORMAT_QCOW: | ||
135 | + qencrypt->format = BLOCKDEV_QCOW2_ENCRYPTION_FORMAT_AES; | ||
136 | + qencrypt->u.aes = encrypt_info->u.qcow; | ||
137 | + break; | ||
138 | + case Q_CRYPTO_BLOCK_FORMAT_LUKS: | ||
139 | + qencrypt->format = BLOCKDEV_QCOW2_ENCRYPTION_FORMAT_LUKS; | ||
140 | + qencrypt->u.luks = encrypt_info->u.luks; | ||
141 | + break; | ||
142 | + default: | ||
143 | + abort(); | ||
144 | + } | ||
145 | + /* Since we did shallow copy above, erase any pointers | ||
146 | + * in the original info */ | ||
147 | + memset(&encrypt_info->u, 0, sizeof(encrypt_info->u)); | ||
148 | + qapi_free_QCryptoBlockInfo(encrypt_info); | ||
149 | + | ||
150 | + spec_info->u.qcow2.data->has_encrypt = true; | ||
151 | + spec_info->u.qcow2.data->encrypt = qencrypt; | ||
152 | + } | ||
153 | + | ||
154 | return spec_info; | ||
155 | } | ||
156 | |||
157 | diff --git a/qapi/block-core.json b/qapi/block-core.json | ||
158 | index XXXXXXX..XXXXXXX 100644 | ||
159 | --- a/qapi/block-core.json | ||
160 | +++ b/qapi/block-core.json | ||
161 | @@ -XXX,XX +XXX,XX @@ | ||
162 | 'vm-clock-sec': 'int', 'vm-clock-nsec': 'int' } } | ||
163 | |||
164 | ## | ||
165 | +# @ImageInfoSpecificQCow2EncryptionBase: | ||
166 | +# | ||
167 | +# @format: The encryption format | ||
168 | +# | ||
169 | +# Since: 2.10 | ||
170 | +## | ||
171 | +{ 'struct': 'ImageInfoSpecificQCow2EncryptionBase', | ||
172 | + 'data': { 'format': 'BlockdevQcow2EncryptionFormat'}} | ||
173 | + | ||
174 | +## | ||
175 | +# @ImageInfoSpecificQCow2Encryption: | ||
176 | +# | ||
177 | +# Since: 2.10 | ||
178 | +## | ||
179 | +{ 'union': 'ImageInfoSpecificQCow2Encryption', | ||
180 | + 'base': 'ImageInfoSpecificQCow2EncryptionBase', | ||
181 | + 'discriminator': 'format', | ||
182 | + 'data': { 'aes': 'QCryptoBlockInfoQCow', | ||
183 | + 'luks': 'QCryptoBlockInfoLUKS' } } | ||
184 | + | ||
185 | +## | ||
186 | # @ImageInfoSpecificQCow2: | ||
187 | # | ||
188 | # @compat: compatibility level | ||
189 | @@ -XXX,XX +XXX,XX @@ | ||
190 | # | ||
191 | # @refcount-bits: width of a refcount entry in bits (since 2.3) | ||
192 | # | ||
193 | +# @encrypt: details about encryption parameters; only set if image | ||
194 | +# is encrypted (since 2.10) | ||
195 | +# | ||
196 | # Since: 1.7 | ||
197 | ## | ||
198 | { 'struct': 'ImageInfoSpecificQCow2', | ||
199 | @@ -XXX,XX +XXX,XX @@ | ||
200 | 'compat': 'str', | ||
201 | '*lazy-refcounts': 'bool', | ||
202 | '*corrupt': 'bool', | ||
203 | - 'refcount-bits': 'int' | ||
204 | + 'refcount-bits': 'int', | ||
205 | + '*encrypt': 'ImageInfoSpecificQCow2Encryption' | ||
206 | } } | ||
207 | |||
208 | ## | ||
209 | -- | ||
210 | 1.8.3.1 | ||
211 | |||
212 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: "Daniel P. Berrange" <berrange@redhat.com> | ||
2 | 1 | ||
3 | Expand the image format docs to cover the new options for | ||
4 | the qcow, qcow2 and luks disk image formats | ||
5 | |||
6 | Reviewed-by: Alberto Garcia <berto@igalia.com> | ||
7 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
8 | Signed-off-by: Daniel P. Berrange <berrange@redhat.com> | ||
9 | Message-id: 20170623162419.26068-21-berrange@redhat.com | ||
10 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
11 | --- | ||
12 | qemu-doc.texi | 123 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---- | ||
13 | 1 file changed, 115 insertions(+), 8 deletions(-) | ||
14 | |||
15 | diff --git a/qemu-doc.texi b/qemu-doc.texi | ||
16 | index XXXXXXX..XXXXXXX 100644 | ||
17 | --- a/qemu-doc.texi | ||
18 | +++ b/qemu-doc.texi | ||
19 | @@ -XXX,XX +XXX,XX @@ File name of a base image (see @option{create} subcommand) | ||
20 | @item backing_fmt | ||
21 | Image format of the base image | ||
22 | @item encryption | ||
23 | -If this option is set to @code{on}, the image is encrypted with 128-bit AES-CBC. | ||
24 | +This option is deprecated and equivalent to @code{encrypt.format=aes} | ||
25 | |||
26 | -The use of encryption in qcow and qcow2 images is considered to be flawed by | ||
27 | -modern cryptography standards, suffering from a number of design problems: | ||
28 | +@item encrypt.format | ||
29 | + | ||
30 | +If this is set to @code{luks}, it requests that the qcow2 payload (not | ||
31 | +qcow2 header) be encrypted using the LUKS format. The passphrase to | ||
32 | +use to unlock the LUKS key slot is given by the @code{encrypt.key-secret} | ||
33 | +parameter. LUKS encryption parameters can be tuned with the other | ||
34 | +@code{encrypt.*} parameters. | ||
35 | + | ||
36 | +If this is set to @code{aes}, the image is encrypted with 128-bit AES-CBC. | ||
37 | +The encryption key is given by the @code{encrypt.key-secret} parameter. | ||
38 | +This encryption format is considered to be flawed by modern cryptography | ||
39 | +standards, suffering from a number of design problems: | ||
40 | |||
41 | @itemize @minus | ||
42 | @item The AES-CBC cipher is used with predictable initialization vectors based | ||
43 | @@ -XXX,XX +XXX,XX @@ original file must then be securely erased using a program like shred, | ||
44 | though even this is ineffective with many modern storage technologies. | ||
45 | @end itemize | ||
46 | |||
47 | -Use of qcow / qcow2 encryption with QEMU is deprecated, and support for | ||
48 | -it will go away in a future release. Users are recommended to use an | ||
49 | -alternative encryption technology such as the Linux dm-crypt / LUKS | ||
50 | -system. | ||
51 | +The use of this is no longer supported in system emulators. Support only | ||
52 | +remains in the command line utilities, for the purposes of data liberation | ||
53 | +and interoperability with old versions of QEMU. The @code{luks} format | ||
54 | +should be used instead. | ||
55 | + | ||
56 | +@item encrypt.key-secret | ||
57 | + | ||
58 | +Provides the ID of a @code{secret} object that contains the passphrase | ||
59 | +(@code{encrypt.format=luks}) or encryption key (@code{encrypt.format=aes}). | ||
60 | + | ||
61 | +@item encrypt.cipher-alg | ||
62 | + | ||
63 | +Name of the cipher algorithm and key length. Currently defaults | ||
64 | +to @code{aes-256}. Only used when @code{encrypt.format=luks}. | ||
65 | + | ||
66 | +@item encrypt.cipher-mode | ||
67 | + | ||
68 | +Name of the encryption mode to use. Currently defaults to @code{xts}. | ||
69 | +Only used when @code{encrypt.format=luks}. | ||
70 | + | ||
71 | +@item encrypt.ivgen-alg | ||
72 | + | ||
73 | +Name of the initialization vector generator algorithm. Currently defaults | ||
74 | +to @code{plain64}. Only used when @code{encrypt.format=luks}. | ||
75 | + | ||
76 | +@item encrypt.ivgen-hash-alg | ||
77 | + | ||
78 | +Name of the hash algorithm to use with the initialization vector generator | ||
79 | +(if required). Defaults to @code{sha256}. Only used when @code{encrypt.format=luks}. | ||
80 | + | ||
81 | +@item encrypt.hash-alg | ||
82 | + | ||
83 | +Name of the hash algorithm to use for PBKDF algorithm | ||
84 | +Defaults to @code{sha256}. Only used when @code{encrypt.format=luks}. | ||
85 | + | ||
86 | +@item encrypt.iter-time | ||
87 | + | ||
88 | +Amount of time, in milliseconds, to use for PBKDF algorithm per key slot. | ||
89 | +Defaults to @code{2000}. Only used when @code{encrypt.format=luks}. | ||
90 | |||
91 | @item cluster_size | ||
92 | Changes the qcow2 cluster size (must be between 512 and 2M). Smaller cluster | ||
93 | @@ -XXX,XX +XXX,XX @@ Supported options: | ||
94 | @item backing_file | ||
95 | File name of a base image (see @option{create} subcommand) | ||
96 | @item encryption | ||
97 | -If this option is set to @code{on}, the image is encrypted. | ||
98 | +This option is deprecated and equivalent to @code{encrypt.format=aes} | ||
99 | + | ||
100 | +@item encrypt.format | ||
101 | +If this is set to @code{aes}, the image is encrypted with 128-bit AES-CBC. | ||
102 | +The encryption key is given by the @code{encrypt.key-secret} parameter. | ||
103 | +This encryption format is considered to be flawed by modern cryptography | ||
104 | +standards, suffering from a number of design problems enumerated previously | ||
105 | +against the @code{qcow2} image format. | ||
106 | + | ||
107 | +The use of this is no longer supported in system emulators. Support only | ||
108 | +remains in the command line utilities, for the purposes of data liberation | ||
109 | +and interoperability with old versions of QEMU. | ||
110 | + | ||
111 | +Users requiring native encryption should use the @code{qcow2} format | ||
112 | +instead with @code{encrypt.format=luks}. | ||
113 | + | ||
114 | +@item encrypt.key-secret | ||
115 | + | ||
116 | +Provides the ID of a @code{secret} object that contains the encryption | ||
117 | +key (@code{encrypt.format=aes}). | ||
118 | + | ||
119 | +@end table | ||
120 | + | ||
121 | +@item luks | ||
122 | + | ||
123 | +LUKS v1 encryption format, compatible with Linux dm-crypt/cryptsetup | ||
124 | + | ||
125 | +Supported options: | ||
126 | +@table @code | ||
127 | + | ||
128 | +@item key-secret | ||
129 | + | ||
130 | +Provides the ID of a @code{secret} object that contains the passphrase. | ||
131 | + | ||
132 | +@item cipher-alg | ||
133 | + | ||
134 | +Name of the cipher algorithm and key length. Currently defaults | ||
135 | +to @code{aes-256}. | ||
136 | + | ||
137 | +@item cipher-mode | ||
138 | + | ||
139 | +Name of the encryption mode to use. Currently defaults to @code{xts}. | ||
140 | + | ||
141 | +@item ivgen-alg | ||
142 | + | ||
143 | +Name of the initialization vector generator algorithm. Currently defaults | ||
144 | +to @code{plain64}. | ||
145 | + | ||
146 | +@item ivgen-hash-alg | ||
147 | + | ||
148 | +Name of the hash algorithm to use with the initialization vector generator | ||
149 | +(if required). Defaults to @code{sha256}. | ||
150 | + | ||
151 | +@item hash-alg | ||
152 | + | ||
153 | +Name of the hash algorithm to use for PBKDF algorithm | ||
154 | +Defaults to @code{sha256}. | ||
155 | + | ||
156 | +@item iter-time | ||
157 | + | ||
158 | +Amount of time, in milliseconds, to use for PBKDF algorithm per key slot. | ||
159 | +Defaults to @code{2000}. | ||
160 | + | ||
161 | @end table | ||
162 | |||
163 | @item vdi | ||
164 | -- | ||
165 | 1.8.3.1 | ||
166 | |||
167 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Max Reitz <mreitz@redhat.com> | ||
2 | 1 | ||
3 | Test 181 only works for formats which support live migration (naturally, | ||
4 | as it is a live migration test). Disable it for all formats which do | ||
5 | not. | ||
6 | |||
7 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
8 | Message-id: 20170621131157.16584-1-mreitz@redhat.com | ||
9 | Reviewed-by: John Snow <jsnow@redhat.com> | ||
10 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
11 | --- | ||
12 | tests/qemu-iotests/181 | 2 ++ | ||
13 | 1 file changed, 2 insertions(+) | ||
14 | |||
15 | diff --git a/tests/qemu-iotests/181 b/tests/qemu-iotests/181 | ||
16 | index XXXXXXX..XXXXXXX 100755 | ||
17 | --- a/tests/qemu-iotests/181 | ||
18 | +++ b/tests/qemu-iotests/181 | ||
19 | @@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15 | ||
20 | . ./common.qemu | ||
21 | |||
22 | _supported_fmt generic | ||
23 | +# Formats that do not support live migration | ||
24 | +_unsupported_fmt qcow vdi vhdx vmdk vpc vvfat | ||
25 | _supported_proto generic | ||
26 | _supported_os Linux | ||
27 | |||
28 | -- | ||
29 | 1.8.3.1 | ||
30 | |||
31 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: "sochin.jiang" <sochin.jiang@huawei.com> | ||
2 | 1 | ||
3 | mirror_complete opens the backing chain, which should have the same | ||
4 | AioContext as the top when using iothreads. Make the code guarantee | ||
5 | this, which fixes a failed assertion in bdrv_attach_child. | ||
6 | |||
7 | Signed-off-by: sochin.jiang <sochin.jiang@huawei.com> | ||
8 | Message-id: 1498475064-39816-1-git-send-email-sochin.jiang@huawei.com | ||
9 | [mreitz: Reworded commit message] | ||
10 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
11 | --- | ||
12 | block.c | 1 + | ||
13 | 1 file changed, 1 insertion(+) | ||
14 | |||
15 | diff --git a/block.c b/block.c | ||
16 | index XXXXXXX..XXXXXXX 100644 | ||
17 | --- a/block.c | ||
18 | +++ b/block.c | ||
19 | @@ -XXX,XX +XXX,XX @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options, | ||
20 | ret = -EINVAL; | ||
21 | goto free_exit; | ||
22 | } | ||
23 | + bdrv_set_aio_context(backing_hd, bdrv_get_aio_context(bs)); | ||
24 | |||
25 | /* Hook up the backing file link; drop our reference, bs owns the | ||
26 | * backing_hd reference now */ | ||
27 | -- | ||
28 | 1.8.3.1 | ||
29 | |||
30 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
2 | 1 | ||
3 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
4 | Reviewed-by: John Snow <jsnow@redhat.com> | ||
5 | Message-id: 20170628120530.31251-2-vsementsov@virtuozzo.com | ||
6 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
7 | --- | ||
8 | docs/interop/qcow2.txt | 3 +-- | ||
9 | 1 file changed, 1 insertion(+), 2 deletions(-) | ||
10 | |||
11 | diff --git a/docs/interop/qcow2.txt b/docs/interop/qcow2.txt | ||
12 | index XXXXXXX..XXXXXXX 100644 | ||
13 | --- a/docs/interop/qcow2.txt | ||
14 | +++ b/docs/interop/qcow2.txt | ||
15 | @@ -XXX,XX +XXX,XX @@ Structure of a bitmap directory entry: | ||
16 | 17: granularity_bits | ||
17 | Granularity bits. Valid values: 0 - 63. | ||
18 | |||
19 | - Note: Qemu currently doesn't support granularity_bits | ||
20 | - greater than 31. | ||
21 | + Note: Qemu currently supports only values 9 - 31. | ||
22 | |||
23 | Granularity is calculated as | ||
24 | granularity = 1 << granularity_bits | ||
25 | -- | ||
26 | 1.8.3.1 | ||
27 | |||
28 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
2 | 1 | ||
3 | A bitmap directory entry is sometimes called a 'bitmap header'. This | ||
4 | patch leaves only one name - 'bitmap directory entry'. The name 'bitmap | ||
5 | header' creates misunderstandings with 'qcow2 header' and 'qcow2 bitmap | ||
6 | header extension' (which is extension of qcow2 header) | ||
7 | |||
8 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
9 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
10 | Reviewed-by: John Snow <jsnow@redhat.com> | ||
11 | Message-id: 20170628120530.31251-3-vsementsov@virtuozzo.com | ||
12 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
13 | --- | ||
14 | docs/interop/qcow2.txt | 5 ++--- | ||
15 | 1 file changed, 2 insertions(+), 3 deletions(-) | ||
16 | |||
17 | diff --git a/docs/interop/qcow2.txt b/docs/interop/qcow2.txt | ||
18 | index XXXXXXX..XXXXXXX 100644 | ||
19 | --- a/docs/interop/qcow2.txt | ||
20 | +++ b/docs/interop/qcow2.txt | ||
21 | @@ -XXX,XX +XXX,XX @@ The fields of the bitmaps extension are: | ||
22 | |||
23 | 8 - 15: bitmap_directory_size | ||
24 | Size of the bitmap directory in bytes. It is the cumulative | ||
25 | - size of all (nb_bitmaps) bitmap headers. | ||
26 | + size of all (nb_bitmaps) bitmap directory entries. | ||
27 | |||
28 | 16 - 23: bitmap_directory_offset | ||
29 | Offset into the image file at which the bitmap directory | ||
30 | @@ -XXX,XX +XXX,XX @@ Each bitmap saved in the image is described in a bitmap directory entry. The | ||
31 | bitmap directory is a contiguous area in the image file, whose starting offset | ||
32 | and length are given by the header extension fields bitmap_directory_offset and | ||
33 | bitmap_directory_size. The entries of the bitmap directory have variable | ||
34 | -length, depending on the lengths of the bitmap name and extra data. These | ||
35 | -entries are also called bitmap headers. | ||
36 | +length, depending on the lengths of the bitmap name and extra data. | ||
37 | |||
38 | Structure of a bitmap directory entry: | ||
39 | |||
40 | -- | ||
41 | 1.8.3.1 | ||
42 | |||
43 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
2 | 1 | ||
3 | Test that hbitmap iter is resistant to bitmap resetting. | ||
4 | |||
5 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
6 | Signed-off-by: Denis V. Lunev <den@openvz.org> | ||
7 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
8 | Reviewed-by: John Snow <jsnow@redhat.com> | ||
9 | Message-id: 20170628120530.31251-5-vsementsov@virtuozzo.com | ||
10 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
11 | --- | ||
12 | tests/test-hbitmap.c | 19 +++++++++++++++++++ | ||
13 | 1 file changed, 19 insertions(+) | ||
14 | |||
15 | diff --git a/tests/test-hbitmap.c b/tests/test-hbitmap.c | ||
16 | index XXXXXXX..XXXXXXX 100644 | ||
17 | --- a/tests/test-hbitmap.c | ||
18 | +++ b/tests/test-hbitmap.c | ||
19 | @@ -XXX,XX +XXX,XX @@ static void hbitmap_test_add(const char *testpath, | ||
20 | hbitmap_test_teardown); | ||
21 | } | ||
22 | |||
23 | +static void test_hbitmap_iter_and_reset(TestHBitmapData *data, | ||
24 | + const void *unused) | ||
25 | +{ | ||
26 | + HBitmapIter hbi; | ||
27 | + | ||
28 | + hbitmap_test_init(data, L1 * 2, 0); | ||
29 | + hbitmap_set(data->hb, 0, data->size); | ||
30 | + | ||
31 | + hbitmap_iter_init(&hbi, data->hb, BITS_PER_LONG - 1); | ||
32 | + | ||
33 | + hbitmap_iter_next(&hbi); | ||
34 | + | ||
35 | + hbitmap_reset_all(data->hb); | ||
36 | + hbitmap_iter_next(&hbi); | ||
37 | +} | ||
38 | + | ||
39 | int main(int argc, char **argv) | ||
40 | { | ||
41 | g_test_init(&argc, &argv, NULL); | ||
42 | @@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv) | ||
43 | test_hbitmap_serialize_part); | ||
44 | hbitmap_test_add("/hbitmap/serialize/zeroes", | ||
45 | test_hbitmap_serialize_zeroes); | ||
46 | + | ||
47 | + hbitmap_test_add("/hbitmap/iter/iter_and_reset", | ||
48 | + test_hbitmap_iter_and_reset); | ||
49 | g_test_run(); | ||
50 | |||
51 | return 0; | ||
52 | -- | ||
53 | 1.8.3.1 | ||
54 | |||
55 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
2 | 1 | ||
3 | Add bdrv_dirty_bitmap_deserialize_ones() function, which is needed for | ||
4 | qcow2 bitmap loading, to handle unallocated bitmap parts, marked as | ||
5 | all-ones. | ||
6 | |||
7 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
8 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
9 | Reviewed-by: John Snow <jsnow@redhat.com> | ||
10 | Message-id: 20170628120530.31251-7-vsementsov@virtuozzo.com | ||
11 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
12 | --- | ||
13 | block/dirty-bitmap.c | 7 +++++++ | ||
14 | include/block/dirty-bitmap.h | 3 +++ | ||
15 | include/qemu/hbitmap.h | 15 +++++++++++++++ | ||
16 | util/hbitmap.c | 17 +++++++++++++++++ | ||
17 | 4 files changed, 42 insertions(+) | ||
18 | |||
19 | diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c | ||
20 | index XXXXXXX..XXXXXXX 100644 | ||
21 | --- a/block/dirty-bitmap.c | ||
22 | +++ b/block/dirty-bitmap.c | ||
23 | @@ -XXX,XX +XXX,XX @@ void bdrv_dirty_bitmap_deserialize_zeroes(BdrvDirtyBitmap *bitmap, | ||
24 | hbitmap_deserialize_zeroes(bitmap->bitmap, start, count, finish); | ||
25 | } | ||
26 | |||
27 | +void bdrv_dirty_bitmap_deserialize_ones(BdrvDirtyBitmap *bitmap, | ||
28 | + uint64_t start, uint64_t count, | ||
29 | + bool finish) | ||
30 | +{ | ||
31 | + hbitmap_deserialize_ones(bitmap->bitmap, start, count, finish); | ||
32 | +} | ||
33 | + | ||
34 | void bdrv_dirty_bitmap_deserialize_finish(BdrvDirtyBitmap *bitmap) | ||
35 | { | ||
36 | hbitmap_deserialize_finish(bitmap->bitmap); | ||
37 | diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h | ||
38 | index XXXXXXX..XXXXXXX 100644 | ||
39 | --- a/include/block/dirty-bitmap.h | ||
40 | +++ b/include/block/dirty-bitmap.h | ||
41 | @@ -XXX,XX +XXX,XX @@ void bdrv_dirty_bitmap_deserialize_part(BdrvDirtyBitmap *bitmap, | ||
42 | void bdrv_dirty_bitmap_deserialize_zeroes(BdrvDirtyBitmap *bitmap, | ||
43 | uint64_t start, uint64_t count, | ||
44 | bool finish); | ||
45 | +void bdrv_dirty_bitmap_deserialize_ones(BdrvDirtyBitmap *bitmap, | ||
46 | + uint64_t start, uint64_t count, | ||
47 | + bool finish); | ||
48 | void bdrv_dirty_bitmap_deserialize_finish(BdrvDirtyBitmap *bitmap); | ||
49 | |||
50 | /* Functions that require manual locking. */ | ||
51 | diff --git a/include/qemu/hbitmap.h b/include/qemu/hbitmap.h | ||
52 | index XXXXXXX..XXXXXXX 100644 | ||
53 | --- a/include/qemu/hbitmap.h | ||
54 | +++ b/include/qemu/hbitmap.h | ||
55 | @@ -XXX,XX +XXX,XX @@ void hbitmap_deserialize_zeroes(HBitmap *hb, uint64_t start, uint64_t count, | ||
56 | bool finish); | ||
57 | |||
58 | /** | ||
59 | + * hbitmap_deserialize_ones | ||
60 | + * @hb: HBitmap to operate on. | ||
61 | + * @start: First bit to restore. | ||
62 | + * @count: Number of bits to restore. | ||
63 | + * @finish: Whether to call hbitmap_deserialize_finish automatically. | ||
64 | + * | ||
65 | + * Fills the bitmap with ones. | ||
66 | + * | ||
67 | + * If @finish is false, caller must call hbitmap_serialize_finish before using | ||
68 | + * the bitmap. | ||
69 | + */ | ||
70 | +void hbitmap_deserialize_ones(HBitmap *hb, uint64_t start, uint64_t count, | ||
71 | + bool finish); | ||
72 | + | ||
73 | +/** | ||
74 | * hbitmap_deserialize_finish | ||
75 | * @hb: HBitmap to operate on. | ||
76 | * | ||
77 | diff --git a/util/hbitmap.c b/util/hbitmap.c | ||
78 | index XXXXXXX..XXXXXXX 100644 | ||
79 | --- a/util/hbitmap.c | ||
80 | +++ b/util/hbitmap.c | ||
81 | @@ -XXX,XX +XXX,XX @@ void hbitmap_deserialize_zeroes(HBitmap *hb, uint64_t start, uint64_t count, | ||
82 | } | ||
83 | } | ||
84 | |||
85 | +void hbitmap_deserialize_ones(HBitmap *hb, uint64_t start, uint64_t count, | ||
86 | + bool finish) | ||
87 | +{ | ||
88 | + uint64_t el_count; | ||
89 | + unsigned long *first; | ||
90 | + | ||
91 | + if (!count) { | ||
92 | + return; | ||
93 | + } | ||
94 | + serialization_chunk(hb, start, count, &first, &el_count); | ||
95 | + | ||
96 | + memset(first, 0xff, el_count * sizeof(unsigned long)); | ||
97 | + if (finish) { | ||
98 | + hbitmap_deserialize_finish(hb); | ||
99 | + } | ||
100 | +} | ||
101 | + | ||
102 | void hbitmap_deserialize_finish(HBitmap *bitmap) | ||
103 | { | ||
104 | int64_t i, size, prev_size; | ||
105 | -- | ||
106 | 1.8.3.1 | ||
107 | |||
108 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
2 | 1 | ||
3 | This is needed for the following patch, which will introduce refcounts | ||
4 | checking for qcow2 bitmaps. | ||
5 | |||
6 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
7 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
8 | Reviewed-by: John Snow <jsnow@redhat.com> | ||
9 | Message-id: 20170628120530.31251-8-vsementsov@virtuozzo.com | ||
10 | [mreitz: s/inc_refcounts/qcow2_inc_refcounts_imrt/ in one more (new) | ||
11 | place] | ||
12 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
13 | --- | ||
14 | block/qcow2-refcount.c | 59 ++++++++++++++++++++++++++------------------------ | ||
15 | block/qcow2.h | 4 ++++ | ||
16 | 2 files changed, 35 insertions(+), 28 deletions(-) | ||
17 | |||
18 | diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c | ||
19 | index XXXXXXX..XXXXXXX 100644 | ||
20 | --- a/block/qcow2-refcount.c | ||
21 | +++ b/block/qcow2-refcount.c | ||
22 | @@ -XXX,XX +XXX,XX @@ static int realloc_refcount_array(BDRVQcow2State *s, void **array, | ||
23 | * | ||
24 | * Modifies the number of errors in res. | ||
25 | */ | ||
26 | -static int inc_refcounts(BlockDriverState *bs, | ||
27 | - BdrvCheckResult *res, | ||
28 | - void **refcount_table, | ||
29 | - int64_t *refcount_table_size, | ||
30 | - int64_t offset, int64_t size) | ||
31 | +int qcow2_inc_refcounts_imrt(BlockDriverState *bs, BdrvCheckResult *res, | ||
32 | + void **refcount_table, | ||
33 | + int64_t *refcount_table_size, | ||
34 | + int64_t offset, int64_t size) | ||
35 | { | ||
36 | BDRVQcow2State *s = bs->opaque; | ||
37 | uint64_t start, last, cluster_offset, k, refcount; | ||
38 | @@ -XXX,XX +XXX,XX @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res, | ||
39 | nb_csectors = ((l2_entry >> s->csize_shift) & | ||
40 | s->csize_mask) + 1; | ||
41 | l2_entry &= s->cluster_offset_mask; | ||
42 | - ret = inc_refcounts(bs, res, refcount_table, refcount_table_size, | ||
43 | - l2_entry & ~511, nb_csectors * 512); | ||
44 | + ret = qcow2_inc_refcounts_imrt(bs, res, | ||
45 | + refcount_table, refcount_table_size, | ||
46 | + l2_entry & ~511, nb_csectors * 512); | ||
47 | if (ret < 0) { | ||
48 | goto fail; | ||
49 | } | ||
50 | @@ -XXX,XX +XXX,XX @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res, | ||
51 | } | ||
52 | |||
53 | /* Mark cluster as used */ | ||
54 | - ret = inc_refcounts(bs, res, refcount_table, refcount_table_size, | ||
55 | - offset, s->cluster_size); | ||
56 | + ret = qcow2_inc_refcounts_imrt(bs, res, | ||
57 | + refcount_table, refcount_table_size, | ||
58 | + offset, s->cluster_size); | ||
59 | if (ret < 0) { | ||
60 | goto fail; | ||
61 | } | ||
62 | @@ -XXX,XX +XXX,XX @@ static int check_refcounts_l1(BlockDriverState *bs, | ||
63 | l1_size2 = l1_size * sizeof(uint64_t); | ||
64 | |||
65 | /* Mark L1 table as used */ | ||
66 | - ret = inc_refcounts(bs, res, refcount_table, refcount_table_size, | ||
67 | - l1_table_offset, l1_size2); | ||
68 | + ret = qcow2_inc_refcounts_imrt(bs, res, refcount_table, refcount_table_size, | ||
69 | + l1_table_offset, l1_size2); | ||
70 | if (ret < 0) { | ||
71 | goto fail; | ||
72 | } | ||
73 | @@ -XXX,XX +XXX,XX @@ static int check_refcounts_l1(BlockDriverState *bs, | ||
74 | if (l2_offset) { | ||
75 | /* Mark L2 table as used */ | ||
76 | l2_offset &= L1E_OFFSET_MASK; | ||
77 | - ret = inc_refcounts(bs, res, refcount_table, refcount_table_size, | ||
78 | - l2_offset, s->cluster_size); | ||
79 | + ret = qcow2_inc_refcounts_imrt(bs, res, | ||
80 | + refcount_table, refcount_table_size, | ||
81 | + l2_offset, s->cluster_size); | ||
82 | if (ret < 0) { | ||
83 | goto fail; | ||
84 | } | ||
85 | @@ -XXX,XX +XXX,XX @@ static int check_refblocks(BlockDriverState *bs, BdrvCheckResult *res, | ||
86 | } | ||
87 | |||
88 | res->corruptions_fixed++; | ||
89 | - ret = inc_refcounts(bs, res, refcount_table, nb_clusters, | ||
90 | - offset, s->cluster_size); | ||
91 | + ret = qcow2_inc_refcounts_imrt(bs, res, | ||
92 | + refcount_table, nb_clusters, | ||
93 | + offset, s->cluster_size); | ||
94 | if (ret < 0) { | ||
95 | return ret; | ||
96 | } | ||
97 | /* No need to check whether the refcount is now greater than 1: | ||
98 | * This area was just allocated and zeroed, so it can only be | ||
99 | - * exactly 1 after inc_refcounts() */ | ||
100 | + * exactly 1 after qcow2_inc_refcounts_imrt() */ | ||
101 | continue; | ||
102 | |||
103 | resize_fail: | ||
104 | @@ -XXX,XX +XXX,XX @@ resize_fail: | ||
105 | } | ||
106 | |||
107 | if (offset != 0) { | ||
108 | - ret = inc_refcounts(bs, res, refcount_table, nb_clusters, | ||
109 | - offset, s->cluster_size); | ||
110 | + ret = qcow2_inc_refcounts_imrt(bs, res, refcount_table, nb_clusters, | ||
111 | + offset, s->cluster_size); | ||
112 | if (ret < 0) { | ||
113 | return ret; | ||
114 | } | ||
115 | @@ -XXX,XX +XXX,XX @@ static int calculate_refcounts(BlockDriverState *bs, BdrvCheckResult *res, | ||
116 | } | ||
117 | |||
118 | /* header */ | ||
119 | - ret = inc_refcounts(bs, res, refcount_table, nb_clusters, | ||
120 | - 0, s->cluster_size); | ||
121 | + ret = qcow2_inc_refcounts_imrt(bs, res, refcount_table, nb_clusters, | ||
122 | + 0, s->cluster_size); | ||
123 | if (ret < 0) { | ||
124 | return ret; | ||
125 | } | ||
126 | @@ -XXX,XX +XXX,XX @@ static int calculate_refcounts(BlockDriverState *bs, BdrvCheckResult *res, | ||
127 | return ret; | ||
128 | } | ||
129 | } | ||
130 | - ret = inc_refcounts(bs, res, refcount_table, nb_clusters, | ||
131 | - s->snapshots_offset, s->snapshots_size); | ||
132 | + ret = qcow2_inc_refcounts_imrt(bs, res, refcount_table, nb_clusters, | ||
133 | + s->snapshots_offset, s->snapshots_size); | ||
134 | if (ret < 0) { | ||
135 | return ret; | ||
136 | } | ||
137 | |||
138 | /* refcount data */ | ||
139 | - ret = inc_refcounts(bs, res, refcount_table, nb_clusters, | ||
140 | - s->refcount_table_offset, | ||
141 | - s->refcount_table_size * sizeof(uint64_t)); | ||
142 | + ret = qcow2_inc_refcounts_imrt(bs, res, refcount_table, nb_clusters, | ||
143 | + s->refcount_table_offset, | ||
144 | + s->refcount_table_size * sizeof(uint64_t)); | ||
145 | if (ret < 0) { | ||
146 | return ret; | ||
147 | } | ||
148 | |||
149 | /* encryption */ | ||
150 | if (s->crypto_header.length) { | ||
151 | - ret = inc_refcounts(bs, res, refcount_table, nb_clusters, | ||
152 | - s->crypto_header.offset, | ||
153 | - s->crypto_header.length); | ||
154 | + ret = qcow2_inc_refcounts_imrt(bs, res, refcount_table, nb_clusters, | ||
155 | + s->crypto_header.offset, | ||
156 | + s->crypto_header.length); | ||
157 | if (ret < 0) { | ||
158 | return ret; | ||
159 | } | ||
160 | diff --git a/block/qcow2.h b/block/qcow2.h | ||
161 | index XXXXXXX..XXXXXXX 100644 | ||
162 | --- a/block/qcow2.h | ||
163 | +++ b/block/qcow2.h | ||
164 | @@ -XXX,XX +XXX,XX @@ int qcow2_check_metadata_overlap(BlockDriverState *bs, int ign, int64_t offset, | ||
165 | int64_t size); | ||
166 | int qcow2_pre_write_overlap_check(BlockDriverState *bs, int ign, int64_t offset, | ||
167 | int64_t size); | ||
168 | +int qcow2_inc_refcounts_imrt(BlockDriverState *bs, BdrvCheckResult *res, | ||
169 | + void **refcount_table, | ||
170 | + int64_t *refcount_table_size, | ||
171 | + int64_t offset, int64_t size); | ||
172 | |||
173 | int qcow2_change_refcount_order(BlockDriverState *bs, int refcount_order, | ||
174 | BlockDriverAmendStatusCB *status_cb, | ||
175 | -- | ||
176 | 1.8.3.1 | ||
177 | |||
178 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
2 | 1 | ||
3 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
4 | Reviewed-by: John Snow <jsnow@redhat.com> | ||
5 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
6 | Message-id: 20170628120530.31251-10-vsementsov@virtuozzo.com | ||
7 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
8 | --- | ||
9 | block/dirty-bitmap.c | 3 ++- | ||
10 | 1 file changed, 2 insertions(+), 1 deletion(-) | ||
11 | |||
12 | diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c | ||
13 | index XXXXXXX..XXXXXXX 100644 | ||
14 | --- a/block/dirty-bitmap.c | ||
15 | +++ b/block/dirty-bitmap.c | ||
16 | @@ -XXX,XX +XXX,XX @@ struct BdrvDirtyBitmap { | ||
17 | BdrvDirtyBitmap *successor; /* Anonymous child; implies frozen status */ | ||
18 | char *name; /* Optional non-empty unique ID */ | ||
19 | int64_t size; /* Size of the bitmap (Number of sectors) */ | ||
20 | - bool disabled; /* Bitmap is read-only */ | ||
21 | + bool disabled; /* Bitmap is disabled. It ignores all writes to | ||
22 | + the device */ | ||
23 | int active_iterators; /* How many iterators are active */ | ||
24 | QLIST_ENTRY(BdrvDirtyBitmap) list; | ||
25 | }; | ||
26 | -- | ||
27 | 1.8.3.1 | ||
28 | |||
29 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
2 | 1 | ||
3 | Add bs local variable to simplify code. | ||
4 | |||
5 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
6 | Reviewed-by: John Snow <jsnow@redhat.com> | ||
7 | Message-id: 20170628120530.31251-13-vsementsov@virtuozzo.com | ||
8 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
9 | --- | ||
10 | block.c | 14 ++++++++------ | ||
11 | 1 file changed, 8 insertions(+), 6 deletions(-) | ||
12 | |||
13 | diff --git a/block.c b/block.c | ||
14 | index XXXXXXX..XXXXXXX 100644 | ||
15 | --- a/block.c | ||
16 | +++ b/block.c | ||
17 | @@ -XXX,XX +XXX,XX @@ error: | ||
18 | void bdrv_reopen_commit(BDRVReopenState *reopen_state) | ||
19 | { | ||
20 | BlockDriver *drv; | ||
21 | + BlockDriverState *bs; | ||
22 | |||
23 | assert(reopen_state != NULL); | ||
24 | - drv = reopen_state->bs->drv; | ||
25 | + bs = reopen_state->bs; | ||
26 | + drv = bs->drv; | ||
27 | assert(drv != NULL); | ||
28 | |||
29 | /* If there are any driver level actions to take */ | ||
30 | @@ -XXX,XX +XXX,XX @@ void bdrv_reopen_commit(BDRVReopenState *reopen_state) | ||
31 | } | ||
32 | |||
33 | /* set BDS specific flags now */ | ||
34 | - QDECREF(reopen_state->bs->explicit_options); | ||
35 | + QDECREF(bs->explicit_options); | ||
36 | |||
37 | - reopen_state->bs->explicit_options = reopen_state->explicit_options; | ||
38 | - reopen_state->bs->open_flags = reopen_state->flags; | ||
39 | - reopen_state->bs->read_only = !(reopen_state->flags & BDRV_O_RDWR); | ||
40 | + bs->explicit_options = reopen_state->explicit_options; | ||
41 | + bs->open_flags = reopen_state->flags; | ||
42 | + bs->read_only = !(reopen_state->flags & BDRV_O_RDWR); | ||
43 | |||
44 | - bdrv_refresh_limits(reopen_state->bs, NULL); | ||
45 | + bdrv_refresh_limits(bs, NULL); | ||
46 | } | ||
47 | |||
48 | /* | ||
49 | -- | ||
50 | 1.8.3.1 | ||
51 | |||
52 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
2 | 1 | ||
3 | Mirror AUTO flag from Qcow2 bitmap in BdrvDirtyBitmap. This will be | ||
4 | needed in future, to save this flag back to Qcow2 for persistent | ||
5 | bitmaps. | ||
6 | |||
7 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
8 | Message-id: 20170628120530.31251-16-vsementsov@virtuozzo.com | ||
9 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
10 | --- | ||
11 | block/dirty-bitmap.c | 18 ++++++++++++++++++ | ||
12 | block/qcow2-bitmap.c | 2 ++ | ||
13 | include/block/dirty-bitmap.h | 2 ++ | ||
14 | 3 files changed, 22 insertions(+) | ||
15 | |||
16 | diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c | ||
17 | index XXXXXXX..XXXXXXX 100644 | ||
18 | --- a/block/dirty-bitmap.c | ||
19 | +++ b/block/dirty-bitmap.c | ||
20 | @@ -XXX,XX +XXX,XX @@ struct BdrvDirtyBitmap { | ||
21 | Such operations must fail and both the image | ||
22 | and this bitmap must remain unchanged while | ||
23 | this flag is set. */ | ||
24 | + bool autoload; /* For persistent bitmaps: bitmap must be | ||
25 | + autoloaded on image opening */ | ||
26 | QLIST_ENTRY(BdrvDirtyBitmap) list; | ||
27 | }; | ||
28 | |||
29 | @@ -XXX,XX +XXX,XX @@ void bdrv_dirty_bitmap_make_anon(BdrvDirtyBitmap *bitmap) | ||
30 | assert(!bdrv_dirty_bitmap_frozen(bitmap)); | ||
31 | g_free(bitmap->name); | ||
32 | bitmap->name = NULL; | ||
33 | + bitmap->autoload = false; | ||
34 | } | ||
35 | |||
36 | /* Called with BQL taken. */ | ||
37 | @@ -XXX,XX +XXX,XX @@ BdrvDirtyBitmap *bdrv_dirty_bitmap_abdicate(BlockDriverState *bs, | ||
38 | bitmap->name = NULL; | ||
39 | successor->name = name; | ||
40 | bitmap->successor = NULL; | ||
41 | + successor->autoload = bitmap->autoload; | ||
42 | + bitmap->autoload = false; | ||
43 | bdrv_release_dirty_bitmap(bs, bitmap); | ||
44 | |||
45 | return successor; | ||
46 | @@ -XXX,XX +XXX,XX @@ bool bdrv_has_readonly_bitmaps(BlockDriverState *bs) | ||
47 | |||
48 | return false; | ||
49 | } | ||
50 | + | ||
51 | +/* Called with BQL taken. */ | ||
52 | +void bdrv_dirty_bitmap_set_autoload(BdrvDirtyBitmap *bitmap, bool autoload) | ||
53 | +{ | ||
54 | + qemu_mutex_lock(bitmap->mutex); | ||
55 | + bitmap->autoload = autoload; | ||
56 | + qemu_mutex_unlock(bitmap->mutex); | ||
57 | +} | ||
58 | + | ||
59 | +bool bdrv_dirty_bitmap_get_autoload(const BdrvDirtyBitmap *bitmap) | ||
60 | +{ | ||
61 | + return bitmap->autoload; | ||
62 | +} | ||
63 | diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c | ||
64 | index XXXXXXX..XXXXXXX 100644 | ||
65 | --- a/block/qcow2-bitmap.c | ||
66 | +++ b/block/qcow2-bitmap.c | ||
67 | @@ -XXX,XX +XXX,XX @@ bool qcow2_load_autoloading_dirty_bitmaps(BlockDriverState *bs, Error **errp) | ||
68 | if (bitmap == NULL) { | ||
69 | goto fail; | ||
70 | } | ||
71 | + | ||
72 | + bdrv_dirty_bitmap_set_autoload(bitmap, true); | ||
73 | bm->flags |= BME_FLAG_IN_USE; | ||
74 | created_dirty_bitmaps = | ||
75 | g_slist_append(created_dirty_bitmaps, bitmap); | ||
76 | diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h | ||
77 | index XXXXXXX..XXXXXXX 100644 | ||
78 | --- a/include/block/dirty-bitmap.h | ||
79 | +++ b/include/block/dirty-bitmap.h | ||
80 | @@ -XXX,XX +XXX,XX @@ void bdrv_dirty_bitmap_deserialize_ones(BdrvDirtyBitmap *bitmap, | ||
81 | void bdrv_dirty_bitmap_deserialize_finish(BdrvDirtyBitmap *bitmap); | ||
82 | |||
83 | void bdrv_dirty_bitmap_set_readonly(BdrvDirtyBitmap *bitmap, bool value); | ||
84 | +void bdrv_dirty_bitmap_set_autoload(BdrvDirtyBitmap *bitmap, bool autoload); | ||
85 | |||
86 | /* Functions that require manual locking. */ | ||
87 | void bdrv_dirty_bitmap_lock(BdrvDirtyBitmap *bitmap); | ||
88 | @@ -XXX,XX +XXX,XX @@ int64_t bdrv_get_meta_dirty_count(BdrvDirtyBitmap *bitmap); | ||
89 | void bdrv_dirty_bitmap_truncate(BlockDriverState *bs); | ||
90 | bool bdrv_dirty_bitmap_readonly(const BdrvDirtyBitmap *bitmap); | ||
91 | bool bdrv_has_readonly_bitmaps(BlockDriverState *bs); | ||
92 | +bool bdrv_dirty_bitmap_get_autoload(const BdrvDirtyBitmap *bitmap); | ||
93 | |||
94 | #endif | ||
95 | -- | ||
96 | 1.8.3.1 | ||
97 | |||
98 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
2 | 1 | ||
3 | Release bitmaps after 'if (bs->drv) { ... }' block. This will allow | ||
4 | format driver to save persistent bitmaps, which will appear in following | ||
5 | commits. | ||
6 | |||
7 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
8 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
9 | Message-id: 20170628120530.31251-17-vsementsov@virtuozzo.com | ||
10 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
11 | --- | ||
12 | block.c | 6 +++--- | ||
13 | 1 file changed, 3 insertions(+), 3 deletions(-) | ||
14 | |||
15 | diff --git a/block.c b/block.c | ||
16 | index XXXXXXX..XXXXXXX 100644 | ||
17 | --- a/block.c | ||
18 | +++ b/block.c | ||
19 | @@ -XXX,XX +XXX,XX @@ static void bdrv_close(BlockDriverState *bs) | ||
20 | bdrv_flush(bs); | ||
21 | bdrv_drain(bs); /* in case flush left pending I/O */ | ||
22 | |||
23 | - bdrv_release_named_dirty_bitmaps(bs); | ||
24 | - assert(QLIST_EMPTY(&bs->dirty_bitmaps)); | ||
25 | - | ||
26 | if (bs->drv) { | ||
27 | BdrvChild *child, *next; | ||
28 | |||
29 | @@ -XXX,XX +XXX,XX @@ static void bdrv_close(BlockDriverState *bs) | ||
30 | bs->full_open_options = NULL; | ||
31 | } | ||
32 | |||
33 | + bdrv_release_named_dirty_bitmaps(bs); | ||
34 | + assert(QLIST_EMPTY(&bs->dirty_bitmaps)); | ||
35 | + | ||
36 | QLIST_FOREACH_SAFE(ban, &bs->aio_notifiers, list, ban_next) { | ||
37 | g_free(ban); | ||
38 | } | ||
39 | -- | ||
40 | 1.8.3.1 | ||
41 | |||
42 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
2 | 1 | ||
3 | New field BdrvDirtyBitmap.persistent means, that bitmap should be saved | ||
4 | by format driver in .bdrv_close and .bdrv_inactivate. No format driver | ||
5 | supports it for now. | ||
6 | |||
7 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
8 | Message-id: 20170628120530.31251-18-vsementsov@virtuozzo.com | ||
9 | [mreitz: Fixed indentation] | ||
10 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
11 | --- | ||
12 | block/dirty-bitmap.c | 29 +++++++++++++++++++++++++++++ | ||
13 | block/qcow2-bitmap.c | 1 + | ||
14 | include/block/dirty-bitmap.h | 4 ++++ | ||
15 | 3 files changed, 34 insertions(+) | ||
16 | |||
17 | diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c | ||
18 | index XXXXXXX..XXXXXXX 100644 | ||
19 | --- a/block/dirty-bitmap.c | ||
20 | +++ b/block/dirty-bitmap.c | ||
21 | @@ -XXX,XX +XXX,XX @@ struct BdrvDirtyBitmap { | ||
22 | this flag is set. */ | ||
23 | bool autoload; /* For persistent bitmaps: bitmap must be | ||
24 | autoloaded on image opening */ | ||
25 | + bool persistent; /* bitmap must be saved to owner disk image */ | ||
26 | QLIST_ENTRY(BdrvDirtyBitmap) list; | ||
27 | }; | ||
28 | |||
29 | @@ -XXX,XX +XXX,XX @@ void bdrv_dirty_bitmap_make_anon(BdrvDirtyBitmap *bitmap) | ||
30 | assert(!bdrv_dirty_bitmap_frozen(bitmap)); | ||
31 | g_free(bitmap->name); | ||
32 | bitmap->name = NULL; | ||
33 | + bitmap->persistent = false; | ||
34 | bitmap->autoload = false; | ||
35 | } | ||
36 | |||
37 | @@ -XXX,XX +XXX,XX @@ BdrvDirtyBitmap *bdrv_dirty_bitmap_abdicate(BlockDriverState *bs, | ||
38 | bitmap->name = NULL; | ||
39 | successor->name = name; | ||
40 | bitmap->successor = NULL; | ||
41 | + successor->persistent = bitmap->persistent; | ||
42 | + bitmap->persistent = false; | ||
43 | successor->autoload = bitmap->autoload; | ||
44 | bitmap->autoload = false; | ||
45 | bdrv_release_dirty_bitmap(bs, bitmap); | ||
46 | @@ -XXX,XX +XXX,XX @@ bool bdrv_dirty_bitmap_get_autoload(const BdrvDirtyBitmap *bitmap) | ||
47 | { | ||
48 | return bitmap->autoload; | ||
49 | } | ||
50 | + | ||
51 | +/* Called with BQL taken. */ | ||
52 | +void bdrv_dirty_bitmap_set_persistance(BdrvDirtyBitmap *bitmap, bool persistent) | ||
53 | +{ | ||
54 | + qemu_mutex_lock(bitmap->mutex); | ||
55 | + bitmap->persistent = persistent; | ||
56 | + qemu_mutex_unlock(bitmap->mutex); | ||
57 | +} | ||
58 | + | ||
59 | +bool bdrv_dirty_bitmap_get_persistance(BdrvDirtyBitmap *bitmap) | ||
60 | +{ | ||
61 | + return bitmap->persistent; | ||
62 | +} | ||
63 | + | ||
64 | +bool bdrv_has_changed_persistent_bitmaps(BlockDriverState *bs) | ||
65 | +{ | ||
66 | + BdrvDirtyBitmap *bm; | ||
67 | + QLIST_FOREACH(bm, &bs->dirty_bitmaps, list) { | ||
68 | + if (bm->persistent && !bm->readonly) { | ||
69 | + return true; | ||
70 | + } | ||
71 | + } | ||
72 | + | ||
73 | + return false; | ||
74 | +} | ||
75 | diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c | ||
76 | index XXXXXXX..XXXXXXX 100644 | ||
77 | --- a/block/qcow2-bitmap.c | ||
78 | +++ b/block/qcow2-bitmap.c | ||
79 | @@ -XXX,XX +XXX,XX @@ bool qcow2_load_autoloading_dirty_bitmaps(BlockDriverState *bs, Error **errp) | ||
80 | goto fail; | ||
81 | } | ||
82 | |||
83 | + bdrv_dirty_bitmap_set_persistance(bitmap, true); | ||
84 | bdrv_dirty_bitmap_set_autoload(bitmap, true); | ||
85 | bm->flags |= BME_FLAG_IN_USE; | ||
86 | created_dirty_bitmaps = | ||
87 | diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h | ||
88 | index XXXXXXX..XXXXXXX 100644 | ||
89 | --- a/include/block/dirty-bitmap.h | ||
90 | +++ b/include/block/dirty-bitmap.h | ||
91 | @@ -XXX,XX +XXX,XX @@ void bdrv_dirty_bitmap_deserialize_finish(BdrvDirtyBitmap *bitmap); | ||
92 | |||
93 | void bdrv_dirty_bitmap_set_readonly(BdrvDirtyBitmap *bitmap, bool value); | ||
94 | void bdrv_dirty_bitmap_set_autoload(BdrvDirtyBitmap *bitmap, bool autoload); | ||
95 | +void bdrv_dirty_bitmap_set_persistance(BdrvDirtyBitmap *bitmap, | ||
96 | + bool persistent); | ||
97 | |||
98 | /* Functions that require manual locking. */ | ||
99 | void bdrv_dirty_bitmap_lock(BdrvDirtyBitmap *bitmap); | ||
100 | @@ -XXX,XX +XXX,XX @@ void bdrv_dirty_bitmap_truncate(BlockDriverState *bs); | ||
101 | bool bdrv_dirty_bitmap_readonly(const BdrvDirtyBitmap *bitmap); | ||
102 | bool bdrv_has_readonly_bitmaps(BlockDriverState *bs); | ||
103 | bool bdrv_dirty_bitmap_get_autoload(const BdrvDirtyBitmap *bitmap); | ||
104 | +bool bdrv_dirty_bitmap_get_persistance(BdrvDirtyBitmap *bitmap); | ||
105 | +bool bdrv_has_changed_persistent_bitmaps(BlockDriverState *bs); | ||
106 | |||
107 | #endif | ||
108 | -- | ||
109 | 1.8.3.1 | ||
110 | |||
111 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
2 | 1 | ||
3 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
4 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
5 | Reviewed-by: John Snow <jsnow@redhat.com> | ||
6 | Message-id: 20170628120530.31251-19-vsementsov@virtuozzo.com | ||
7 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
8 | --- | ||
9 | block/dirty-bitmap.c | 7 +++++++ | ||
10 | include/block/dirty-bitmap.h | 2 ++ | ||
11 | 2 files changed, 9 insertions(+) | ||
12 | |||
13 | diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c | ||
14 | index XXXXXXX..XXXXXXX 100644 | ||
15 | --- a/block/dirty-bitmap.c | ||
16 | +++ b/block/dirty-bitmap.c | ||
17 | @@ -XXX,XX +XXX,XX @@ bool bdrv_has_changed_persistent_bitmaps(BlockDriverState *bs) | ||
18 | |||
19 | return false; | ||
20 | } | ||
21 | + | ||
22 | +BdrvDirtyBitmap *bdrv_dirty_bitmap_next(BlockDriverState *bs, | ||
23 | + BdrvDirtyBitmap *bitmap) | ||
24 | +{ | ||
25 | + return bitmap == NULL ? QLIST_FIRST(&bs->dirty_bitmaps) : | ||
26 | + QLIST_NEXT(bitmap, list); | ||
27 | +} | ||
28 | diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h | ||
29 | index XXXXXXX..XXXXXXX 100644 | ||
30 | --- a/include/block/dirty-bitmap.h | ||
31 | +++ b/include/block/dirty-bitmap.h | ||
32 | @@ -XXX,XX +XXX,XX @@ bool bdrv_has_readonly_bitmaps(BlockDriverState *bs); | ||
33 | bool bdrv_dirty_bitmap_get_autoload(const BdrvDirtyBitmap *bitmap); | ||
34 | bool bdrv_dirty_bitmap_get_persistance(BdrvDirtyBitmap *bitmap); | ||
35 | bool bdrv_has_changed_persistent_bitmaps(BlockDriverState *bs); | ||
36 | +BdrvDirtyBitmap *bdrv_dirty_bitmap_next(BlockDriverState *bs, | ||
37 | + BdrvDirtyBitmap *bitmap); | ||
38 | |||
39 | #endif | ||
40 | -- | ||
41 | 1.8.3.1 | ||
42 | |||
43 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
2 | 1 | ||
3 | Store bitmaps and mark them read-only on reopening image as read-only. | ||
4 | |||
5 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
6 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
7 | Message-id: 20170628120530.31251-21-vsementsov@virtuozzo.com | ||
8 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
9 | --- | ||
10 | block/qcow2-bitmap.c | 22 ++++++++++++++++++++++ | ||
11 | block/qcow2.c | 5 +++++ | ||
12 | block/qcow2.h | 1 + | ||
13 | 3 files changed, 28 insertions(+) | ||
14 | |||
15 | diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c | ||
16 | index XXXXXXX..XXXXXXX 100644 | ||
17 | --- a/block/qcow2-bitmap.c | ||
18 | +++ b/block/qcow2-bitmap.c | ||
19 | @@ -XXX,XX +XXX,XX @@ fail: | ||
20 | |||
21 | bitmap_list_free(bm_list); | ||
22 | } | ||
23 | + | ||
24 | +int qcow2_reopen_bitmaps_ro(BlockDriverState *bs, Error **errp) | ||
25 | +{ | ||
26 | + BdrvDirtyBitmap *bitmap; | ||
27 | + Error *local_err = NULL; | ||
28 | + | ||
29 | + qcow2_store_persistent_dirty_bitmaps(bs, &local_err); | ||
30 | + if (local_err != NULL) { | ||
31 | + error_propagate(errp, local_err); | ||
32 | + return -EINVAL; | ||
33 | + } | ||
34 | + | ||
35 | + for (bitmap = bdrv_dirty_bitmap_next(bs, NULL); bitmap != NULL; | ||
36 | + bitmap = bdrv_dirty_bitmap_next(bs, bitmap)) | ||
37 | + { | ||
38 | + if (bdrv_dirty_bitmap_get_persistance(bitmap)) { | ||
39 | + bdrv_dirty_bitmap_set_readonly(bitmap, true); | ||
40 | + } | ||
41 | + } | ||
42 | + | ||
43 | + return 0; | ||
44 | +} | ||
45 | diff --git a/block/qcow2.c b/block/qcow2.c | ||
46 | index XXXXXXX..XXXXXXX 100644 | ||
47 | --- a/block/qcow2.c | ||
48 | +++ b/block/qcow2.c | ||
49 | @@ -XXX,XX +XXX,XX @@ static int qcow2_reopen_prepare(BDRVReopenState *state, | ||
50 | |||
51 | /* We need to write out any unwritten data if we reopen read-only. */ | ||
52 | if ((state->flags & BDRV_O_RDWR) == 0) { | ||
53 | + ret = qcow2_reopen_bitmaps_ro(state->bs, errp); | ||
54 | + if (ret < 0) { | ||
55 | + goto fail; | ||
56 | + } | ||
57 | + | ||
58 | ret = bdrv_flush(state->bs); | ||
59 | if (ret < 0) { | ||
60 | goto fail; | ||
61 | diff --git a/block/qcow2.h b/block/qcow2.h | ||
62 | index XXXXXXX..XXXXXXX 100644 | ||
63 | --- a/block/qcow2.h | ||
64 | +++ b/block/qcow2.h | ||
65 | @@ -XXX,XX +XXX,XX @@ int qcow2_check_bitmaps_refcounts(BlockDriverState *bs, BdrvCheckResult *res, | ||
66 | bool qcow2_load_autoloading_dirty_bitmaps(BlockDriverState *bs, Error **errp); | ||
67 | int qcow2_reopen_bitmaps_rw(BlockDriverState *bs, Error **errp); | ||
68 | void qcow2_store_persistent_dirty_bitmaps(BlockDriverState *bs, Error **errp); | ||
69 | +int qcow2_reopen_bitmaps_ro(BlockDriverState *bs, Error **errp); | ||
70 | |||
71 | #endif | ||
72 | -- | ||
73 | 1.8.3.1 | ||
74 | |||
75 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
2 | 1 | ||
3 | This will be needed to check some restrictions before making bitmap | ||
4 | persistent in qmp-block-dirty-bitmap-add (this functionality will be | ||
5 | added by future patch) | ||
6 | |||
7 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
8 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
9 | Reviewed-by: John Snow <jsnow@redhat.com> | ||
10 | Message-id: 20170628120530.31251-22-vsementsov@virtuozzo.com | ||
11 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
12 | --- | ||
13 | block.c | 22 ++++++++++++++++++++++ | ||
14 | include/block/block.h | 3 +++ | ||
15 | include/block/block_int.h | 4 ++++ | ||
16 | 3 files changed, 29 insertions(+) | ||
17 | |||
18 | diff --git a/block.c b/block.c | ||
19 | index XXXXXXX..XXXXXXX 100644 | ||
20 | --- a/block.c | ||
21 | +++ b/block.c | ||
22 | @@ -XXX,XX +XXX,XX @@ void bdrv_del_child(BlockDriverState *parent_bs, BdrvChild *child, Error **errp) | ||
23 | |||
24 | parent_bs->drv->bdrv_del_child(parent_bs, child, errp); | ||
25 | } | ||
26 | + | ||
27 | +bool bdrv_can_store_new_dirty_bitmap(BlockDriverState *bs, const char *name, | ||
28 | + uint32_t granularity, Error **errp) | ||
29 | +{ | ||
30 | + BlockDriver *drv = bs->drv; | ||
31 | + | ||
32 | + if (!drv) { | ||
33 | + error_setg_errno(errp, ENOMEDIUM, | ||
34 | + "Can't store persistent bitmaps to %s", | ||
35 | + bdrv_get_device_or_node_name(bs)); | ||
36 | + return false; | ||
37 | + } | ||
38 | + | ||
39 | + if (!drv->bdrv_can_store_new_dirty_bitmap) { | ||
40 | + error_setg_errno(errp, ENOTSUP, | ||
41 | + "Can't store persistent bitmaps to %s", | ||
42 | + bdrv_get_device_or_node_name(bs)); | ||
43 | + return false; | ||
44 | + } | ||
45 | + | ||
46 | + return drv->bdrv_can_store_new_dirty_bitmap(bs, name, granularity, errp); | ||
47 | +} | ||
48 | diff --git a/include/block/block.h b/include/block/block.h | ||
49 | index XXXXXXX..XXXXXXX 100644 | ||
50 | --- a/include/block/block.h | ||
51 | +++ b/include/block/block.h | ||
52 | @@ -XXX,XX +XXX,XX @@ void bdrv_add_child(BlockDriverState *parent, BlockDriverState *child, | ||
53 | Error **errp); | ||
54 | void bdrv_del_child(BlockDriverState *parent, BdrvChild *child, Error **errp); | ||
55 | |||
56 | +bool bdrv_can_store_new_dirty_bitmap(BlockDriverState *bs, const char *name, | ||
57 | + uint32_t granularity, Error **errp); | ||
58 | + | ||
59 | #endif | ||
60 | diff --git a/include/block/block_int.h b/include/block/block_int.h | ||
61 | index XXXXXXX..XXXXXXX 100644 | ||
62 | --- a/include/block/block_int.h | ||
63 | +++ b/include/block/block_int.h | ||
64 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { | ||
65 | * field of BlockDirtyBitmap's in case of success. | ||
66 | */ | ||
67 | int (*bdrv_reopen_bitmaps_rw)(BlockDriverState *bs, Error **errp); | ||
68 | + bool (*bdrv_can_store_new_dirty_bitmap)(BlockDriverState *bs, | ||
69 | + const char *name, | ||
70 | + uint32_t granularity, | ||
71 | + Error **errp); | ||
72 | |||
73 | QLIST_ENTRY(BlockDriver) list; | ||
74 | }; | ||
75 | -- | ||
76 | 1.8.3.1 | ||
77 | |||
78 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
2 | 1 | ||
3 | Add optional 'persistent' flag to qmp command block-dirty-bitmap-add. | ||
4 | Default is false. | ||
5 | |||
6 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
7 | Signed-off-by: Denis V. Lunev <den@openvz.org> | ||
8 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
9 | Reviewed-by: John Snow <jsnow@redhat.com> | ||
10 | Message-id: 20170628120530.31251-24-vsementsov@virtuozzo.com | ||
11 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
12 | --- | ||
13 | blockdev.c | 18 +++++++++++++++++- | ||
14 | qapi/block-core.json | 8 +++++++- | ||
15 | 2 files changed, 24 insertions(+), 2 deletions(-) | ||
16 | |||
17 | diff --git a/blockdev.c b/blockdev.c | ||
18 | index XXXXXXX..XXXXXXX 100644 | ||
19 | --- a/blockdev.c | ||
20 | +++ b/blockdev.c | ||
21 | @@ -XXX,XX +XXX,XX @@ static void block_dirty_bitmap_add_prepare(BlkActionState *common, | ||
22 | /* AIO context taken and released within qmp_block_dirty_bitmap_add */ | ||
23 | qmp_block_dirty_bitmap_add(action->node, action->name, | ||
24 | action->has_granularity, action->granularity, | ||
25 | + action->has_persistent, action->persistent, | ||
26 | &local_err); | ||
27 | |||
28 | if (!local_err) { | ||
29 | @@ -XXX,XX +XXX,XX @@ out: | ||
30 | |||
31 | void qmp_block_dirty_bitmap_add(const char *node, const char *name, | ||
32 | bool has_granularity, uint32_t granularity, | ||
33 | + bool has_persistent, bool persistent, | ||
34 | Error **errp) | ||
35 | { | ||
36 | BlockDriverState *bs; | ||
37 | + BdrvDirtyBitmap *bitmap; | ||
38 | |||
39 | if (!name || name[0] == '\0') { | ||
40 | error_setg(errp, "Bitmap name cannot be empty"); | ||
41 | @@ -XXX,XX +XXX,XX @@ void qmp_block_dirty_bitmap_add(const char *node, const char *name, | ||
42 | granularity = bdrv_get_default_bitmap_granularity(bs); | ||
43 | } | ||
44 | |||
45 | - bdrv_create_dirty_bitmap(bs, granularity, name, errp); | ||
46 | + if (!has_persistent) { | ||
47 | + persistent = false; | ||
48 | + } | ||
49 | + | ||
50 | + if (persistent && | ||
51 | + !bdrv_can_store_new_dirty_bitmap(bs, name, granularity, errp)) | ||
52 | + { | ||
53 | + return; | ||
54 | + } | ||
55 | + | ||
56 | + bitmap = bdrv_create_dirty_bitmap(bs, granularity, name, errp); | ||
57 | + if (bitmap != NULL) { | ||
58 | + bdrv_dirty_bitmap_set_persistance(bitmap, persistent); | ||
59 | + } | ||
60 | } | ||
61 | |||
62 | void qmp_block_dirty_bitmap_remove(const char *node, const char *name, | ||
63 | diff --git a/qapi/block-core.json b/qapi/block-core.json | ||
64 | index XXXXXXX..XXXXXXX 100644 | ||
65 | --- a/qapi/block-core.json | ||
66 | +++ b/qapi/block-core.json | ||
67 | @@ -XXX,XX +XXX,XX @@ | ||
68 | # @granularity: the bitmap granularity, default is 64k for | ||
69 | # block-dirty-bitmap-add | ||
70 | # | ||
71 | +# @persistent: the bitmap is persistent, i.e. it will be saved to the | ||
72 | +# corresponding block device image file on its close. For now only | ||
73 | +# Qcow2 disks support persistent bitmaps. Default is false for | ||
74 | +# block-dirty-bitmap-add. (Since: 2.10) | ||
75 | +# | ||
76 | # Since: 2.4 | ||
77 | ## | ||
78 | { 'struct': 'BlockDirtyBitmapAdd', | ||
79 | - 'data': { 'node': 'str', 'name': 'str', '*granularity': 'uint32' } } | ||
80 | + 'data': { 'node': 'str', 'name': 'str', '*granularity': 'uint32', | ||
81 | + '*persistent': 'bool' } } | ||
82 | |||
83 | ## | ||
84 | # @block-dirty-bitmap-add: | ||
85 | -- | ||
86 | 1.8.3.1 | ||
87 | |||
88 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
2 | 1 | ||
3 | Optional. Default is false. | ||
4 | |||
5 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
6 | Signed-off-by: Denis V. Lunev <den@openvz.org> | ||
7 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
8 | Reviewed-by: John Snow <jsnow@redhat.com> | ||
9 | Message-id: 20170628120530.31251-25-vsementsov@virtuozzo.com | ||
10 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
11 | --- | ||
12 | blockdev.c | 18 ++++++++++++++++-- | ||
13 | qapi/block-core.json | 6 +++++- | ||
14 | 2 files changed, 21 insertions(+), 3 deletions(-) | ||
15 | |||
16 | diff --git a/blockdev.c b/blockdev.c | ||
17 | index XXXXXXX..XXXXXXX 100644 | ||
18 | --- a/blockdev.c | ||
19 | +++ b/blockdev.c | ||
20 | @@ -XXX,XX +XXX,XX @@ static void block_dirty_bitmap_add_prepare(BlkActionState *common, | ||
21 | qmp_block_dirty_bitmap_add(action->node, action->name, | ||
22 | action->has_granularity, action->granularity, | ||
23 | action->has_persistent, action->persistent, | ||
24 | + action->has_autoload, action->autoload, | ||
25 | &local_err); | ||
26 | |||
27 | if (!local_err) { | ||
28 | @@ -XXX,XX +XXX,XX @@ out: | ||
29 | void qmp_block_dirty_bitmap_add(const char *node, const char *name, | ||
30 | bool has_granularity, uint32_t granularity, | ||
31 | bool has_persistent, bool persistent, | ||
32 | + bool has_autoload, bool autoload, | ||
33 | Error **errp) | ||
34 | { | ||
35 | BlockDriverState *bs; | ||
36 | @@ -XXX,XX +XXX,XX @@ void qmp_block_dirty_bitmap_add(const char *node, const char *name, | ||
37 | if (!has_persistent) { | ||
38 | persistent = false; | ||
39 | } | ||
40 | + if (!has_autoload) { | ||
41 | + autoload = false; | ||
42 | + } | ||
43 | + | ||
44 | + if (has_autoload && !persistent) { | ||
45 | + error_setg(errp, "Autoload flag must be used only for persistent " | ||
46 | + "bitmaps"); | ||
47 | + return; | ||
48 | + } | ||
49 | |||
50 | if (persistent && | ||
51 | !bdrv_can_store_new_dirty_bitmap(bs, name, granularity, errp)) | ||
52 | @@ -XXX,XX +XXX,XX @@ void qmp_block_dirty_bitmap_add(const char *node, const char *name, | ||
53 | } | ||
54 | |||
55 | bitmap = bdrv_create_dirty_bitmap(bs, granularity, name, errp); | ||
56 | - if (bitmap != NULL) { | ||
57 | - bdrv_dirty_bitmap_set_persistance(bitmap, persistent); | ||
58 | + if (bitmap == NULL) { | ||
59 | + return; | ||
60 | } | ||
61 | + | ||
62 | + bdrv_dirty_bitmap_set_persistance(bitmap, persistent); | ||
63 | + bdrv_dirty_bitmap_set_autoload(bitmap, autoload); | ||
64 | } | ||
65 | |||
66 | void qmp_block_dirty_bitmap_remove(const char *node, const char *name, | ||
67 | diff --git a/qapi/block-core.json b/qapi/block-core.json | ||
68 | index XXXXXXX..XXXXXXX 100644 | ||
69 | --- a/qapi/block-core.json | ||
70 | +++ b/qapi/block-core.json | ||
71 | @@ -XXX,XX +XXX,XX @@ | ||
72 | # Qcow2 disks support persistent bitmaps. Default is false for | ||
73 | # block-dirty-bitmap-add. (Since: 2.10) | ||
74 | # | ||
75 | +# @autoload: the bitmap will be automatically loaded when the image it is stored | ||
76 | +# in is opened. This flag may only be specified for persistent | ||
77 | +# bitmaps. Default is false for block-dirty-bitmap-add. (Since: 2.10) | ||
78 | +# | ||
79 | # Since: 2.4 | ||
80 | ## | ||
81 | { 'struct': 'BlockDirtyBitmapAdd', | ||
82 | 'data': { 'node': 'str', 'name': 'str', '*granularity': 'uint32', | ||
83 | - '*persistent': 'bool' } } | ||
84 | + '*persistent': 'bool', '*autoload': 'bool' } } | ||
85 | |||
86 | ## | ||
87 | # @block-dirty-bitmap-add: | ||
88 | -- | ||
89 | 1.8.3.1 | ||
90 | |||
91 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
2 | 1 | ||
3 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
4 | Message-id: 20170628120530.31251-26-vsementsov@virtuozzo.com | ||
5 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
6 | --- | ||
7 | block/dirty-bitmap.c | 5 +++++ | ||
8 | blockdev.c | 25 +++++++++++++++++++++++++ | ||
9 | include/block/dirty-bitmap.h | 1 + | ||
10 | include/qemu/hbitmap.h | 8 ++++++++ | ||
11 | qapi/block-core.json | 27 +++++++++++++++++++++++++++ | ||
12 | tests/Makefile.include | 2 +- | ||
13 | util/hbitmap.c | 11 +++++++++++ | ||
14 | 7 files changed, 78 insertions(+), 1 deletion(-) | ||
15 | |||
16 | diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c | ||
17 | index XXXXXXX..XXXXXXX 100644 | ||
18 | --- a/block/dirty-bitmap.c | ||
19 | +++ b/block/dirty-bitmap.c | ||
20 | @@ -XXX,XX +XXX,XX @@ BdrvDirtyBitmap *bdrv_dirty_bitmap_next(BlockDriverState *bs, | ||
21 | return bitmap == NULL ? QLIST_FIRST(&bs->dirty_bitmaps) : | ||
22 | QLIST_NEXT(bitmap, list); | ||
23 | } | ||
24 | + | ||
25 | +char *bdrv_dirty_bitmap_sha256(const BdrvDirtyBitmap *bitmap, Error **errp) | ||
26 | +{ | ||
27 | + return hbitmap_sha256(bitmap->bitmap, errp); | ||
28 | +} | ||
29 | diff --git a/blockdev.c b/blockdev.c | ||
30 | index XXXXXXX..XXXXXXX 100644 | ||
31 | --- a/blockdev.c | ||
32 | +++ b/blockdev.c | ||
33 | @@ -XXX,XX +XXX,XX @@ void qmp_block_dirty_bitmap_clear(const char *node, const char *name, | ||
34 | bdrv_clear_dirty_bitmap(bitmap, NULL); | ||
35 | } | ||
36 | |||
37 | +BlockDirtyBitmapSha256 *qmp_x_debug_block_dirty_bitmap_sha256(const char *node, | ||
38 | + const char *name, | ||
39 | + Error **errp) | ||
40 | +{ | ||
41 | + BdrvDirtyBitmap *bitmap; | ||
42 | + BlockDriverState *bs; | ||
43 | + BlockDirtyBitmapSha256 *ret = NULL; | ||
44 | + char *sha256; | ||
45 | + | ||
46 | + bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp); | ||
47 | + if (!bitmap || !bs) { | ||
48 | + return NULL; | ||
49 | + } | ||
50 | + | ||
51 | + sha256 = bdrv_dirty_bitmap_sha256(bitmap, errp); | ||
52 | + if (sha256 == NULL) { | ||
53 | + return NULL; | ||
54 | + } | ||
55 | + | ||
56 | + ret = g_new(BlockDirtyBitmapSha256, 1); | ||
57 | + ret->sha256 = sha256; | ||
58 | + | ||
59 | + return ret; | ||
60 | +} | ||
61 | + | ||
62 | void hmp_drive_del(Monitor *mon, const QDict *qdict) | ||
63 | { | ||
64 | const char *id = qdict_get_str(qdict, "id"); | ||
65 | diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h | ||
66 | index XXXXXXX..XXXXXXX 100644 | ||
67 | --- a/include/block/dirty-bitmap.h | ||
68 | +++ b/include/block/dirty-bitmap.h | ||
69 | @@ -XXX,XX +XXX,XX @@ bool bdrv_dirty_bitmap_get_persistance(BdrvDirtyBitmap *bitmap); | ||
70 | bool bdrv_has_changed_persistent_bitmaps(BlockDriverState *bs); | ||
71 | BdrvDirtyBitmap *bdrv_dirty_bitmap_next(BlockDriverState *bs, | ||
72 | BdrvDirtyBitmap *bitmap); | ||
73 | +char *bdrv_dirty_bitmap_sha256(const BdrvDirtyBitmap *bitmap, Error **errp); | ||
74 | |||
75 | #endif | ||
76 | diff --git a/include/qemu/hbitmap.h b/include/qemu/hbitmap.h | ||
77 | index XXXXXXX..XXXXXXX 100644 | ||
78 | --- a/include/qemu/hbitmap.h | ||
79 | +++ b/include/qemu/hbitmap.h | ||
80 | @@ -XXX,XX +XXX,XX @@ void hbitmap_deserialize_ones(HBitmap *hb, uint64_t start, uint64_t count, | ||
81 | void hbitmap_deserialize_finish(HBitmap *hb); | ||
82 | |||
83 | /** | ||
84 | + * hbitmap_sha256: | ||
85 | + * @bitmap: HBitmap to operate on. | ||
86 | + * | ||
87 | + * Returns SHA256 hash of the last level. | ||
88 | + */ | ||
89 | +char *hbitmap_sha256(const HBitmap *bitmap, Error **errp); | ||
90 | + | ||
91 | +/** | ||
92 | * hbitmap_free: | ||
93 | * @hb: HBitmap to operate on. | ||
94 | * | ||
95 | diff --git a/qapi/block-core.json b/qapi/block-core.json | ||
96 | index XXXXXXX..XXXXXXX 100644 | ||
97 | --- a/qapi/block-core.json | ||
98 | +++ b/qapi/block-core.json | ||
99 | @@ -XXX,XX +XXX,XX @@ | ||
100 | 'data': 'BlockDirtyBitmap' } | ||
101 | |||
102 | ## | ||
103 | +# @BlockDirtyBitmapSha256: | ||
104 | +# | ||
105 | +# SHA256 hash of dirty bitmap data | ||
106 | +# | ||
107 | +# @sha256: ASCII representation of SHA256 bitmap hash | ||
108 | +# | ||
109 | +# Since: 2.10 | ||
110 | +## | ||
111 | + { 'struct': 'BlockDirtyBitmapSha256', | ||
112 | + 'data': {'sha256': 'str'} } | ||
113 | + | ||
114 | +## | ||
115 | +# @x-debug-block-dirty-bitmap-sha256: | ||
116 | +# | ||
117 | +# Get bitmap SHA256 | ||
118 | +# | ||
119 | +# Returns: BlockDirtyBitmapSha256 on success | ||
120 | +# If @node is not a valid block device, DeviceNotFound | ||
121 | +# If @name is not found or if hashing has failed, GenericError with an | ||
122 | +# explanation | ||
123 | +# | ||
124 | +# Since: 2.10 | ||
125 | +## | ||
126 | + { 'command': 'x-debug-block-dirty-bitmap-sha256', | ||
127 | + 'data': 'BlockDirtyBitmap', 'returns': 'BlockDirtyBitmapSha256' } | ||
128 | + | ||
129 | +## | ||
130 | # @blockdev-mirror: | ||
131 | # | ||
132 | # Start mirroring a block device's writes to a new destination. | ||
133 | diff --git a/tests/Makefile.include b/tests/Makefile.include | ||
134 | index XXXXXXX..XXXXXXX 100644 | ||
135 | --- a/tests/Makefile.include | ||
136 | +++ b/tests/Makefile.include | ||
137 | @@ -XXX,XX +XXX,XX @@ tests/test-blockjob$(EXESUF): tests/test-blockjob.o $(test-block-obj-y) $(test-u | ||
138 | tests/test-blockjob-txn$(EXESUF): tests/test-blockjob-txn.o $(test-block-obj-y) $(test-util-obj-y) | ||
139 | tests/test-thread-pool$(EXESUF): tests/test-thread-pool.o $(test-block-obj-y) | ||
140 | tests/test-iov$(EXESUF): tests/test-iov.o $(test-util-obj-y) | ||
141 | -tests/test-hbitmap$(EXESUF): tests/test-hbitmap.o $(test-util-obj-y) | ||
142 | +tests/test-hbitmap$(EXESUF): tests/test-hbitmap.o $(test-util-obj-y) $(test-crypto-obj-y) | ||
143 | tests/test-x86-cpuid$(EXESUF): tests/test-x86-cpuid.o | ||
144 | tests/test-xbzrle$(EXESUF): tests/test-xbzrle.o migration/xbzrle.o migration/page_cache.o $(test-util-obj-y) | ||
145 | tests/test-cutils$(EXESUF): tests/test-cutils.o util/cutils.o | ||
146 | diff --git a/util/hbitmap.c b/util/hbitmap.c | ||
147 | index XXXXXXX..XXXXXXX 100644 | ||
148 | --- a/util/hbitmap.c | ||
149 | +++ b/util/hbitmap.c | ||
150 | @@ -XXX,XX +XXX,XX @@ | ||
151 | #include "qemu/hbitmap.h" | ||
152 | #include "qemu/host-utils.h" | ||
153 | #include "trace.h" | ||
154 | +#include "crypto/hash.h" | ||
155 | |||
156 | /* HBitmaps provides an array of bits. The bits are stored as usual in an | ||
157 | * array of unsigned longs, but HBitmap is also optimized to provide fast | ||
158 | @@ -XXX,XX +XXX,XX @@ void hbitmap_free_meta(HBitmap *hb) | ||
159 | hbitmap_free(hb->meta); | ||
160 | hb->meta = NULL; | ||
161 | } | ||
162 | + | ||
163 | +char *hbitmap_sha256(const HBitmap *bitmap, Error **errp) | ||
164 | +{ | ||
165 | + size_t size = bitmap->sizes[HBITMAP_LEVELS - 1] * sizeof(unsigned long); | ||
166 | + char *data = (char *)bitmap->levels[HBITMAP_LEVELS - 1]; | ||
167 | + char *hash = NULL; | ||
168 | + qcrypto_hash_digest(QCRYPTO_HASH_ALG_SHA256, data, size, &hash, errp); | ||
169 | + | ||
170 | + return hash; | ||
171 | +} | ||
172 | -- | ||
173 | 1.8.3.1 | ||
174 | |||
175 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
2 | 1 | ||
3 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
4 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
5 | Message-id: 20170628120530.31251-27-vsementsov@virtuozzo.com | ||
6 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
7 | --- | ||
8 | tests/qemu-iotests/165 | 105 +++++++++++++++++++++++++++++++++++++++++++++ | ||
9 | tests/qemu-iotests/165.out | 5 +++ | ||
10 | tests/qemu-iotests/group | 1 + | ||
11 | 3 files changed, 111 insertions(+) | ||
12 | create mode 100755 tests/qemu-iotests/165 | ||
13 | create mode 100644 tests/qemu-iotests/165.out | ||
14 | |||
15 | diff --git a/tests/qemu-iotests/165 b/tests/qemu-iotests/165 | ||
16 | new file mode 100755 | ||
17 | index XXXXXXX..XXXXXXX | ||
18 | --- /dev/null | ||
19 | +++ b/tests/qemu-iotests/165 | ||
20 | @@ -XXX,XX +XXX,XX @@ | ||
21 | +#!/usr/bin/env python | ||
22 | +# | ||
23 | +# Tests for persistent dirty bitmaps. | ||
24 | +# | ||
25 | +# Copyright: Vladimir Sementsov-Ogievskiy 2015-2017 | ||
26 | +# | ||
27 | +# This program is free software; you can redistribute it and/or modify | ||
28 | +# it under the terms of the GNU General Public License as published by | ||
29 | +# the Free Software Foundation; either version 2 of the License, or | ||
30 | +# (at your option) any later version. | ||
31 | +# | ||
32 | +# This program is distributed in the hope that it will be useful, | ||
33 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
34 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
35 | +# GNU General Public License for more details. | ||
36 | +# | ||
37 | +# You should have received a copy of the GNU General Public License | ||
38 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
39 | +# | ||
40 | + | ||
41 | +import os | ||
42 | +import re | ||
43 | +import iotests | ||
44 | +from iotests import qemu_img | ||
45 | + | ||
46 | +disk = os.path.join(iotests.test_dir, 'disk') | ||
47 | +disk_size = 0x40000000 # 1G | ||
48 | + | ||
49 | +# regions for qemu_io: (start, count) in bytes | ||
50 | +regions1 = ((0, 0x100000), | ||
51 | + (0x200000, 0x100000)) | ||
52 | + | ||
53 | +regions2 = ((0x10000000, 0x20000), | ||
54 | + (0x3fff0000, 0x10000)) | ||
55 | + | ||
56 | +class TestPersistentDirtyBitmap(iotests.QMPTestCase): | ||
57 | + | ||
58 | + def setUp(self): | ||
59 | + qemu_img('create', '-f', iotests.imgfmt, disk, str(disk_size)) | ||
60 | + | ||
61 | + def tearDown(self): | ||
62 | + os.remove(disk) | ||
63 | + | ||
64 | + def mkVm(self): | ||
65 | + return iotests.VM().add_drive(disk) | ||
66 | + | ||
67 | + def mkVmRo(self): | ||
68 | + return iotests.VM().add_drive(disk, opts='readonly=on') | ||
69 | + | ||
70 | + def getSha256(self): | ||
71 | + result = self.vm.qmp('x-debug-block-dirty-bitmap-sha256', | ||
72 | + node='drive0', name='bitmap0') | ||
73 | + return result['return']['sha256'] | ||
74 | + | ||
75 | + def checkBitmap(self, sha256): | ||
76 | + result = self.vm.qmp('x-debug-block-dirty-bitmap-sha256', | ||
77 | + node='drive0', name='bitmap0') | ||
78 | + self.assert_qmp(result, 'return/sha256', sha256); | ||
79 | + | ||
80 | + def writeRegions(self, regions): | ||
81 | + for r in regions: | ||
82 | + self.vm.hmp_qemu_io('drive0', | ||
83 | + 'write %d %d' % r) | ||
84 | + | ||
85 | + def qmpAddBitmap(self): | ||
86 | + self.vm.qmp('block-dirty-bitmap-add', node='drive0', | ||
87 | + name='bitmap0', persistent=True, autoload=True) | ||
88 | + | ||
89 | + def test_persistent(self): | ||
90 | + self.vm = self.mkVm() | ||
91 | + self.vm.launch() | ||
92 | + self.qmpAddBitmap() | ||
93 | + | ||
94 | + self.writeRegions(regions1) | ||
95 | + sha256 = self.getSha256() | ||
96 | + | ||
97 | + self.vm.shutdown() | ||
98 | + | ||
99 | + self.vm = self.mkVmRo() | ||
100 | + self.vm.launch() | ||
101 | + self.vm.shutdown() | ||
102 | + | ||
103 | + #catch 'Persistent bitmaps are lost' possible error | ||
104 | + log = self.vm.get_log() | ||
105 | + log = re.sub(r'^\[I \d+\.\d+\] OPENED\n', '', log) | ||
106 | + log = re.sub(r'\[I \+\d+\.\d+\] CLOSED\n?$', '', log) | ||
107 | + if log: | ||
108 | + print log | ||
109 | + | ||
110 | + self.vm = self.mkVm() | ||
111 | + self.vm.launch() | ||
112 | + | ||
113 | + self.checkBitmap(sha256) | ||
114 | + self.writeRegions(regions2) | ||
115 | + sha256 = self.getSha256() | ||
116 | + | ||
117 | + self.vm.shutdown() | ||
118 | + self.vm.launch() | ||
119 | + | ||
120 | + self.checkBitmap(sha256) | ||
121 | + | ||
122 | + self.vm.shutdown() | ||
123 | + | ||
124 | +if __name__ == '__main__': | ||
125 | + iotests.main(supported_fmts=['qcow2']) | ||
126 | diff --git a/tests/qemu-iotests/165.out b/tests/qemu-iotests/165.out | ||
127 | new file mode 100644 | ||
128 | index XXXXXXX..XXXXXXX | ||
129 | --- /dev/null | ||
130 | +++ b/tests/qemu-iotests/165.out | ||
131 | @@ -XXX,XX +XXX,XX @@ | ||
132 | +. | ||
133 | +---------------------------------------------------------------------- | ||
134 | +Ran 1 tests | ||
135 | + | ||
136 | +OK | ||
137 | diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group | ||
138 | index XXXXXXX..XXXXXXX 100644 | ||
139 | --- a/tests/qemu-iotests/group | ||
140 | +++ b/tests/qemu-iotests/group | ||
141 | @@ -XXX,XX +XXX,XX @@ | ||
142 | 159 rw auto quick | ||
143 | 160 rw auto quick | ||
144 | 162 auto quick | ||
145 | +165 rw auto quick | ||
146 | 170 rw auto quick | ||
147 | 171 rw auto quick | ||
148 | 172 auto | ||
149 | -- | ||
150 | 1.8.3.1 | ||
151 | |||
152 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
2 | 1 | ||
3 | Interface for removing persistent bitmap from its storage. | ||
4 | |||
5 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
6 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
7 | Reviewed-by: John Snow <jsnow@redhat.com> | ||
8 | Message-id: 20170628120530.31251-28-vsementsov@virtuozzo.com | ||
9 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
10 | --- | ||
11 | block/dirty-bitmap.c | 18 ++++++++++++++++++ | ||
12 | include/block/block_int.h | 3 +++ | ||
13 | include/block/dirty-bitmap.h | 3 +++ | ||
14 | 3 files changed, 24 insertions(+) | ||
15 | |||
16 | diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c | ||
17 | index XXXXXXX..XXXXXXX 100644 | ||
18 | --- a/block/dirty-bitmap.c | ||
19 | +++ b/block/dirty-bitmap.c | ||
20 | @@ -XXX,XX +XXX,XX @@ void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap) | ||
21 | /** | ||
22 | * Release all named dirty bitmaps attached to a BDS (for use in bdrv_close()). | ||
23 | * There must not be any frozen bitmaps attached. | ||
24 | + * This function does not remove persistent bitmaps from the storage. | ||
25 | * Called with BQL taken. | ||
26 | */ | ||
27 | void bdrv_release_named_dirty_bitmaps(BlockDriverState *bs) | ||
28 | @@ -XXX,XX +XXX,XX @@ void bdrv_release_named_dirty_bitmaps(BlockDriverState *bs) | ||
29 | bdrv_do_release_matching_dirty_bitmap(bs, NULL, true); | ||
30 | } | ||
31 | |||
32 | +/** | ||
33 | + * Remove persistent dirty bitmap from the storage if it exists. | ||
34 | + * Absence of bitmap is not an error, because we have the following scenario: | ||
35 | + * BdrvDirtyBitmap can have .persistent = true but not yet saved and have no | ||
36 | + * stored version. For such bitmap bdrv_remove_persistent_dirty_bitmap() should | ||
37 | + * not fail. | ||
38 | + * This function doesn't release corresponding BdrvDirtyBitmap. | ||
39 | + */ | ||
40 | +void bdrv_remove_persistent_dirty_bitmap(BlockDriverState *bs, | ||
41 | + const char *name, | ||
42 | + Error **errp) | ||
43 | +{ | ||
44 | + if (bs->drv && bs->drv->bdrv_remove_persistent_dirty_bitmap) { | ||
45 | + bs->drv->bdrv_remove_persistent_dirty_bitmap(bs, name, errp); | ||
46 | + } | ||
47 | +} | ||
48 | + | ||
49 | /* Called with BQL taken. */ | ||
50 | void bdrv_disable_dirty_bitmap(BdrvDirtyBitmap *bitmap) | ||
51 | { | ||
52 | diff --git a/include/block/block_int.h b/include/block/block_int.h | ||
53 | index XXXXXXX..XXXXXXX 100644 | ||
54 | --- a/include/block/block_int.h | ||
55 | +++ b/include/block/block_int.h | ||
56 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { | ||
57 | const char *name, | ||
58 | uint32_t granularity, | ||
59 | Error **errp); | ||
60 | + void (*bdrv_remove_persistent_dirty_bitmap)(BlockDriverState *bs, | ||
61 | + const char *name, | ||
62 | + Error **errp); | ||
63 | |||
64 | QLIST_ENTRY(BlockDriver) list; | ||
65 | }; | ||
66 | diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h | ||
67 | index XXXXXXX..XXXXXXX 100644 | ||
68 | --- a/include/block/dirty-bitmap.h | ||
69 | +++ b/include/block/dirty-bitmap.h | ||
70 | @@ -XXX,XX +XXX,XX @@ BdrvDirtyBitmap *bdrv_find_dirty_bitmap(BlockDriverState *bs, | ||
71 | void bdrv_dirty_bitmap_make_anon(BdrvDirtyBitmap *bitmap); | ||
72 | void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap); | ||
73 | void bdrv_release_named_dirty_bitmaps(BlockDriverState *bs); | ||
74 | +void bdrv_remove_persistent_dirty_bitmap(BlockDriverState *bs, | ||
75 | + const char *name, | ||
76 | + Error **errp); | ||
77 | void bdrv_disable_dirty_bitmap(BdrvDirtyBitmap *bitmap); | ||
78 | void bdrv_enable_dirty_bitmap(BdrvDirtyBitmap *bitmap); | ||
79 | BlockDirtyInfoList *bdrv_query_dirty_bitmaps(BlockDriverState *bs); | ||
80 | -- | ||
81 | 1.8.3.1 | ||
82 | |||
83 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: "Daniel P. Berrange" <berrange@redhat.com> | ||
2 | 1 | ||
3 | While the qemu-img dd command does accept --image-opts | ||
4 | this is not sufficient to make it work with the LUKS | ||
5 | image yet. This is because bdrv_create() still always | ||
6 | requires the non-image-opts syntax. | ||
7 | |||
8 | Thus we must skip 159/170 with luks for now | ||
9 | |||
10 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
11 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
12 | Signed-off-by: Daniel P. Berrange <berrange@redhat.com> | ||
13 | Message-id: 20170626123510.20134-2-berrange@redhat.com | ||
14 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
15 | --- | ||
16 | tests/qemu-iotests/159 | 1 + | ||
17 | tests/qemu-iotests/170 | 1 + | ||
18 | 2 files changed, 2 insertions(+) | ||
19 | |||
20 | diff --git a/tests/qemu-iotests/159 b/tests/qemu-iotests/159 | ||
21 | index XXXXXXX..XXXXXXX 100755 | ||
22 | --- a/tests/qemu-iotests/159 | ||
23 | +++ b/tests/qemu-iotests/159 | ||
24 | @@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15 | ||
25 | _supported_fmt generic | ||
26 | _supported_proto file | ||
27 | _supported_os Linux | ||
28 | +_unsupported_fmt luks | ||
29 | |||
30 | TEST_SIZES="5 512 1024 1999 1K 64K 1M" | ||
31 | |||
32 | diff --git a/tests/qemu-iotests/170 b/tests/qemu-iotests/170 | ||
33 | index XXXXXXX..XXXXXXX 100755 | ||
34 | --- a/tests/qemu-iotests/170 | ||
35 | +++ b/tests/qemu-iotests/170 | ||
36 | @@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15 | ||
37 | _supported_fmt generic | ||
38 | _supported_proto file | ||
39 | _supported_os Linux | ||
40 | +_unsupported_fmt luks | ||
41 | |||
42 | echo | ||
43 | echo "== Creating image ==" | ||
44 | -- | ||
45 | 1.8.3.1 | ||
46 | |||
47 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: "Daniel P. Berrange" <berrange@redhat.com> | ||
2 | 1 | ||
3 | The tests 033, 140, 145 and 157 were all broken | ||
4 | when run with LUKS, since they did not correctly use | ||
5 | the required image opts args syntax to specify the | ||
6 | decryption secret. Further, the 120 test simply does | ||
7 | not make sense to run with luks, as the scenario | ||
8 | exercised is not relevant. | ||
9 | |||
10 | The test 181 was broken when run with LUKS because | ||
11 | it didn't take account of fact that $TEST_IMG was | ||
12 | already in image opts syntax. The launch_qemu | ||
13 | helper also didn't register the secret object | ||
14 | providing the LUKS password. | ||
15 | |||
16 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
17 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
18 | Signed-off-by: Daniel P. Berrange <berrange@redhat.com> | ||
19 | Message-id: 20170626123510.20134-3-berrange@redhat.com | ||
20 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
21 | --- | ||
22 | tests/qemu-iotests/033 | 12 ++++++++++-- | ||
23 | tests/qemu-iotests/120 | 1 + | ||
24 | tests/qemu-iotests/140 | 9 ++++++++- | ||
25 | tests/qemu-iotests/145 | 19 +++++++++++++++++-- | ||
26 | tests/qemu-iotests/157 | 17 ++++++++++++++--- | ||
27 | tests/qemu-iotests/157.out | 16 ++++++++-------- | ||
28 | tests/qemu-iotests/174 | 2 +- | ||
29 | tests/qemu-iotests/181 | 21 ++++++++++++++++----- | ||
30 | tests/qemu-iotests/common.qemu | 9 +++++++-- | ||
31 | 9 files changed, 82 insertions(+), 24 deletions(-) | ||
32 | |||
33 | diff --git a/tests/qemu-iotests/033 b/tests/qemu-iotests/033 | ||
34 | index XXXXXXX..XXXXXXX 100755 | ||
35 | --- a/tests/qemu-iotests/033 | ||
36 | +++ b/tests/qemu-iotests/033 | ||
37 | @@ -XXX,XX +XXX,XX @@ do_test() | ||
38 | local align=$1 | ||
39 | local iocmd=$2 | ||
40 | local img=$3 | ||
41 | + if [ "$IMGOPTSSYNTAX" = "true" ] | ||
42 | + then | ||
43 | + IO_OPEN_ARG="$img" | ||
44 | + IO_EXTRA_ARGS="--image-opts" | ||
45 | + else | ||
46 | + IO_OPEN_ARG="-o driver=$IMGFMT,file.align=$align blkdebug::$img" | ||
47 | + IO_EXTRA_ARGS="" | ||
48 | + fi | ||
49 | { | ||
50 | - echo "open -o driver=$IMGFMT,file.align=$align blkdebug::$img" | ||
51 | + echo "open $IO_OPEN_ARG" | ||
52 | echo $iocmd | ||
53 | - } | $QEMU_IO | ||
54 | + } | $QEMU_IO $IO_EXTRA_ARGS | ||
55 | } | ||
56 | |||
57 | for write_zero_cmd in "write -z" "aio_write -z"; do | ||
58 | diff --git a/tests/qemu-iotests/120 b/tests/qemu-iotests/120 | ||
59 | index XXXXXXX..XXXXXXX 100755 | ||
60 | --- a/tests/qemu-iotests/120 | ||
61 | +++ b/tests/qemu-iotests/120 | ||
62 | @@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15 | ||
63 | _supported_fmt generic | ||
64 | _supported_proto file | ||
65 | _supported_os Linux | ||
66 | +_unsupported_fmt luks | ||
67 | |||
68 | _make_test_img 64M | ||
69 | |||
70 | diff --git a/tests/qemu-iotests/140 b/tests/qemu-iotests/140 | ||
71 | index XXXXXXX..XXXXXXX 100755 | ||
72 | --- a/tests/qemu-iotests/140 | ||
73 | +++ b/tests/qemu-iotests/140 | ||
74 | @@ -XXX,XX +XXX,XX @@ _make_test_img 64k | ||
75 | |||
76 | $QEMU_IO -c 'write -P 42 0 64k' "$TEST_IMG" | _filter_qemu_io | ||
77 | |||
78 | +if test "$IMGOPTSSYNTAX" = "true" | ||
79 | +then | ||
80 | + SYSEMU_DRIVE_ARG=if=none,media=cdrom,id=drv,"$TEST_IMG" | ||
81 | +else | ||
82 | + SYSEMU_DRIVE_ARG=if=none,media=cdrom,id=drv,file="$TEST_IMG",driver=$IMGFMT | ||
83 | +fi | ||
84 | + | ||
85 | keep_stderr=y \ | ||
86 | -_launch_qemu -drive if=none,media=cdrom,id=drv,file="$TEST_IMG",format=$IMGFMT \ | ||
87 | +_launch_qemu -drive $SYSEMU_DRIVE_ARG \ | ||
88 | 2> >(_filter_nbd) | ||
89 | |||
90 | _send_qemu_cmd $QEMU_HANDLE \ | ||
91 | diff --git a/tests/qemu-iotests/145 b/tests/qemu-iotests/145 | ||
92 | index XXXXXXX..XXXXXXX 100755 | ||
93 | --- a/tests/qemu-iotests/145 | ||
94 | +++ b/tests/qemu-iotests/145 | ||
95 | @@ -XXX,XX +XXX,XX @@ _supported_proto generic | ||
96 | _supported_os Linux | ||
97 | |||
98 | _make_test_img 1M | ||
99 | -echo quit | $QEMU -nographic -hda "$TEST_IMG" -incoming 'exec:true' -snapshot -serial none -monitor stdio | | ||
100 | - _filter_qemu | _filter_hmp | ||
101 | + | ||
102 | +if test "$IMGOPTSSYNTAX" = "true" | ||
103 | +then | ||
104 | + SYSEMU_DRIVE_ARG=if=none,$TEST_IMG | ||
105 | + SYSEMU_EXTRA_ARGS="" | ||
106 | + if [ -n "$IMGKEYSECRET" ]; then | ||
107 | + SECRET_ARG="secret,id=keysec0,data=$IMGKEYSECRET" | ||
108 | + SYSEMU_EXTRA_ARGS="-object $SECRET_ARG" | ||
109 | + fi | ||
110 | +else | ||
111 | + SYSEMU_DRIVE_ARG=if=none,file="$TEST_IMG",driver=$IMGFMT | ||
112 | + SYSEMU_EXTRA_ARGS="" | ||
113 | +fi | ||
114 | + | ||
115 | +echo quit | $QEMU -nographic $SYSEMU_EXTRA_ARGS -drive $SYSEMU_DRIVE_ARG \ | ||
116 | + -incoming 'exec:true' -snapshot -serial none -monitor stdio \ | ||
117 | + | _filter_qemu | _filter_hmp | ||
118 | |||
119 | # success, all done | ||
120 | echo "*** done" | ||
121 | diff --git a/tests/qemu-iotests/157 b/tests/qemu-iotests/157 | ||
122 | index XXXXXXX..XXXXXXX 100755 | ||
123 | --- a/tests/qemu-iotests/157 | ||
124 | +++ b/tests/qemu-iotests/157 | ||
125 | @@ -XXX,XX +XXX,XX @@ _supported_os Linux | ||
126 | |||
127 | function do_run_qemu() | ||
128 | { | ||
129 | - echo Testing: "$@" | ||
130 | ( | ||
131 | if ! test -t 0; then | ||
132 | while read cmd; do | ||
133 | @@ -XXX,XX +XXX,XX @@ function run_qemu() | ||
134 | |||
135 | |||
136 | size=128M | ||
137 | -drive="if=none,file=$TEST_IMG,driver=$IMGFMT" | ||
138 | +if test "$IMGOPTSSYNTAX" = "true" | ||
139 | +then | ||
140 | + SYSEMU_DRIVE_ARG=if=none,$TEST_IMG | ||
141 | + SYSEMU_EXTRA_ARGS="" | ||
142 | + if [ -n "$IMGKEYSECRET" ]; then | ||
143 | + SECRET_ARG="secret,id=keysec0,data=$IMGKEYSECRET" | ||
144 | + SYSEMU_EXTRA_ARGS="-object $SECRET_ARG" | ||
145 | + fi | ||
146 | +else | ||
147 | + SYSEMU_DRIVE_ARG=if=none,file="$TEST_IMG",driver=$IMGFMT | ||
148 | + SYSEMU_EXTRA_ARGS="" | ||
149 | +fi | ||
150 | |||
151 | _make_test_img $size | ||
152 | |||
153 | @@ -XXX,XX +XXX,XX @@ echo | ||
154 | |||
155 | for cache in "writeback" "writethrough"; do | ||
156 | for wce in "" ",write-cache=auto" ",write-cache=on" ",write-cache=off"; do | ||
157 | + echo "Testing: cache='$cache' wce='$wce'" | ||
158 | echo "info block" \ | ||
159 | - | run_qemu -drive "$drive,cache=$cache" \ | ||
160 | + | run_qemu $SYSEMU_EXTRA_ARGS -drive "$SYSEMU_DRIVE_ARG,cache=$cache" \ | ||
161 | -device "virtio-blk,drive=none0$wce" \ | ||
162 | | grep -e "Testing" -e "Cache mode" | ||
163 | done | ||
164 | diff --git a/tests/qemu-iotests/157.out b/tests/qemu-iotests/157.out | ||
165 | index XXXXXXX..XXXXXXX 100644 | ||
166 | --- a/tests/qemu-iotests/157.out | ||
167 | +++ b/tests/qemu-iotests/157.out | ||
168 | @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 | ||
169 | |||
170 | === Setting WCE with qdev and with manually created BB === | ||
171 | |||
172 | -Testing: -drive if=none,file=TEST_DIR/t.IMGFMT,driver=IMGFMT,cache=writeback -device virtio-blk,drive=none0 | ||
173 | +Testing: cache='writeback' wce='' | ||
174 | Cache mode: writeback | ||
175 | -Testing: -drive if=none,file=TEST_DIR/t.IMGFMT,driver=IMGFMT,cache=writeback -device virtio-blk,drive=none0,write-cache=auto | ||
176 | +Testing: cache='writeback' wce=',write-cache=auto' | ||
177 | Cache mode: writeback | ||
178 | -Testing: -drive if=none,file=TEST_DIR/t.IMGFMT,driver=IMGFMT,cache=writeback -device virtio-blk,drive=none0,write-cache=on | ||
179 | +Testing: cache='writeback' wce=',write-cache=on' | ||
180 | Cache mode: writeback | ||
181 | -Testing: -drive if=none,file=TEST_DIR/t.IMGFMT,driver=IMGFMT,cache=writeback -device virtio-blk,drive=none0,write-cache=off | ||
182 | +Testing: cache='writeback' wce=',write-cache=off' | ||
183 | Cache mode: writethrough | ||
184 | -Testing: -drive if=none,file=TEST_DIR/t.IMGFMT,driver=IMGFMT,cache=writethrough -device virtio-blk,drive=none0 | ||
185 | +Testing: cache='writethrough' wce='' | ||
186 | Cache mode: writethrough | ||
187 | -Testing: -drive if=none,file=TEST_DIR/t.IMGFMT,driver=IMGFMT,cache=writethrough -device virtio-blk,drive=none0,write-cache=auto | ||
188 | +Testing: cache='writethrough' wce=',write-cache=auto' | ||
189 | Cache mode: writethrough | ||
190 | -Testing: -drive if=none,file=TEST_DIR/t.IMGFMT,driver=IMGFMT,cache=writethrough -device virtio-blk,drive=none0,write-cache=on | ||
191 | +Testing: cache='writethrough' wce=',write-cache=on' | ||
192 | Cache mode: writeback | ||
193 | -Testing: -drive if=none,file=TEST_DIR/t.IMGFMT,driver=IMGFMT,cache=writethrough -device virtio-blk,drive=none0,write-cache=off | ||
194 | +Testing: cache='writethrough' wce=',write-cache=off' | ||
195 | Cache mode: writethrough | ||
196 | *** done | ||
197 | diff --git a/tests/qemu-iotests/174 b/tests/qemu-iotests/174 | ||
198 | index XXXXXXX..XXXXXXX 100755 | ||
199 | --- a/tests/qemu-iotests/174 | ||
200 | +++ b/tests/qemu-iotests/174 | ||
201 | @@ -XXX,XX +XXX,XX @@ _unsupported_fmt raw | ||
202 | |||
203 | |||
204 | size=256K | ||
205 | -IMGFMT=raw IMGOPTS= _make_test_img $size | _filter_imgfmt | ||
206 | +IMGFMT=raw IMGKEYSECRET= IMGOPTS= _make_test_img $size | _filter_imgfmt | ||
207 | |||
208 | echo | ||
209 | echo "== reading wrong format should fail ==" | ||
210 | diff --git a/tests/qemu-iotests/181 b/tests/qemu-iotests/181 | ||
211 | index XXXXXXX..XXXXXXX 100755 | ||
212 | --- a/tests/qemu-iotests/181 | ||
213 | +++ b/tests/qemu-iotests/181 | ||
214 | @@ -XXX,XX +XXX,XX @@ echo | ||
215 | |||
216 | qemu_comm_method="monitor" | ||
217 | |||
218 | -_launch_qemu \ | ||
219 | - -drive file="${TEST_IMG}",cache=${CACHEMODE},driver=$IMGFMT,id=disk | ||
220 | +if [ "$IMGOPTSSYNTAX" = "true" ]; then | ||
221 | + _launch_qemu \ | ||
222 | + -drive "${TEST_IMG}",cache=${CACHEMODE},id=disk | ||
223 | +else | ||
224 | + _launch_qemu \ | ||
225 | + -drive file="${TEST_IMG}",cache=${CACHEMODE},driver=$IMGFMT,id=disk | ||
226 | +fi | ||
227 | src=$QEMU_HANDLE | ||
228 | |||
229 | -_launch_qemu \ | ||
230 | - -drive file="${TEST_IMG}",cache=${CACHEMODE},driver=$IMGFMT,id=disk \ | ||
231 | - -incoming "unix:${MIG_SOCKET}" | ||
232 | +if [ "$IMGOPTSSYNTAX" = "true" ]; then | ||
233 | + _launch_qemu \ | ||
234 | + -drive "${TEST_IMG}",cache=${CACHEMODE},id=disk \ | ||
235 | + -incoming "unix:${MIG_SOCKET}" | ||
236 | +else | ||
237 | + _launch_qemu \ | ||
238 | + -drive file="${TEST_IMG}",cache=${CACHEMODE},driver=$IMGFMT,id=disk \ | ||
239 | + -incoming "unix:${MIG_SOCKET}" | ||
240 | +fi | ||
241 | dest=$QEMU_HANDLE | ||
242 | |||
243 | echo | ||
244 | diff --git a/tests/qemu-iotests/common.qemu b/tests/qemu-iotests/common.qemu | ||
245 | index XXXXXXX..XXXXXXX 100644 | ||
246 | --- a/tests/qemu-iotests/common.qemu | ||
247 | +++ b/tests/qemu-iotests/common.qemu | ||
248 | @@ -XXX,XX +XXX,XX @@ function _launch_qemu() | ||
249 | mkfifo "${fifo_out}" | ||
250 | mkfifo "${fifo_in}" | ||
251 | |||
252 | + object_options= | ||
253 | + if [ -n "$IMGKEYSECRET" ]; then | ||
254 | + object_options="--object secret,id=keysec0,data=$IMGKEYSECRET" | ||
255 | + fi | ||
256 | + | ||
257 | if [ -z "$keep_stderr" ]; then | ||
258 | QEMU_NEED_PID='y'\ | ||
259 | - ${QEMU} -nographic -serial none ${comm} "${@}" >"${fifo_out}" \ | ||
260 | + ${QEMU} ${object_options} -nographic -serial none ${comm} "${@}" >"${fifo_out}" \ | ||
261 | 2>&1 \ | ||
262 | <"${fifo_in}" & | ||
263 | elif [ "$keep_stderr" = "y" ]; then | ||
264 | QEMU_NEED_PID='y'\ | ||
265 | - ${QEMU} -nographic -serial none ${comm} "${@}" >"${fifo_out}" \ | ||
266 | + ${QEMU} ${object_options} -nographic -serial none ${comm} "${@}" >"${fifo_out}" \ | ||
267 | <"${fifo_in}" & | ||
268 | else | ||
269 | exit 1 | ||
270 | -- | ||
271 | 1.8.3.1 | ||
272 | |||
273 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: "Daniel P. Berrange" <berrange@redhat.com> | ||
2 | 1 | ||
3 | By default the PBKDF algorithm used with LUKS is tuned | ||
4 | based on the number of iterations to produce 1 second | ||
5 | of running time. This makes running the I/O test with | ||
6 | the LUKS format orders of magnitude slower than with | ||
7 | qcow2/raw formats. | ||
8 | |||
9 | When creating LUKS images, set the iteration time to | ||
10 | a 10ms to reduce the time overhead for LUKS, since | ||
11 | security does not matter in I/O tests. | ||
12 | |||
13 | Previously a full 'check -luks' would take | ||
14 | |||
15 | $ time ./check -luks | ||
16 | Passed all 22 tests | ||
17 | |||
18 | real 23m9.988s | ||
19 | user 21m46.223s | ||
20 | sys 0m22.841s | ||
21 | |||
22 | Now it takes | ||
23 | |||
24 | $ time ./check -luks | ||
25 | Passed all 22 tests | ||
26 | |||
27 | real 4m39.235s | ||
28 | user 3m29.590s | ||
29 | sys 0m24.234s | ||
30 | |||
31 | Still slow compared to qcow2/raw, but much improved | ||
32 | none the less. | ||
33 | |||
34 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
35 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
36 | Signed-off-by: Daniel P. Berrange <berrange@redhat.com> | ||
37 | Message-id: 20170626123510.20134-4-berrange@redhat.com | ||
38 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
39 | --- | ||
40 | tests/qemu-iotests/149 | 3 + | ||
41 | tests/qemu-iotests/149.out | 118 +++++++++++++++++++-------------------- | ||
42 | tests/qemu-iotests/common.filter | 3 +- | ||
43 | tests/qemu-iotests/common.rc | 3 + | ||
44 | 4 files changed, 67 insertions(+), 60 deletions(-) | ||
45 | |||
46 | diff --git a/tests/qemu-iotests/149 b/tests/qemu-iotests/149 | ||
47 | index XXXXXXX..XXXXXXX 100755 | ||
48 | --- a/tests/qemu-iotests/149 | ||
49 | +++ b/tests/qemu-iotests/149 | ||
50 | @@ -XXX,XX +XXX,XX @@ def cryptsetup_add_password(config, slot): | ||
51 | args = ["luksAddKey", config.image_path(), | ||
52 | "--key-slot", slot, | ||
53 | "--key-file", "-", | ||
54 | + "--iter-time", "10", | ||
55 | pwfile] | ||
56 | |||
57 | cryptsetup(args, password) | ||
58 | @@ -XXX,XX +XXX,XX @@ def cryptsetup_format(config): | ||
59 | args.extend(["--hash", config.hash]) | ||
60 | args.extend(["--key-slot", slot]) | ||
61 | args.extend(["--key-file", "-"]) | ||
62 | + args.extend(["--iter-time", "10"]) | ||
63 | args.append(config.image_path()) | ||
64 | |||
65 | cryptsetup(args, password) | ||
66 | @@ -XXX,XX +XXX,XX @@ def qemu_img_create(config, size_mb): | ||
67 | |||
68 | opts = [ | ||
69 | "key-secret=sec0", | ||
70 | + "iter-time=10", | ||
71 | "cipher-alg=%s-%d" % (config.cipher, config.keylen), | ||
72 | "cipher-mode=%s" % config.mode, | ||
73 | "ivgen-alg=%s" % config.ivgen, | ||
74 | diff --git a/tests/qemu-iotests/149.out b/tests/qemu-iotests/149.out | ||
75 | index XXXXXXX..XXXXXXX 100644 | ||
76 | --- a/tests/qemu-iotests/149.out | ||
77 | +++ b/tests/qemu-iotests/149.out | ||
78 | @@ -XXX,XX +XXX,XX @@ | ||
79 | # Create image | ||
80 | truncate TEST_DIR/luks-aes-256-xts-plain64-sha1.img --size 4194304MB | ||
81 | # Format image | ||
82 | -sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain64 --key-size 512 --hash sha1 --key-slot 0 --key-file - TEST_DIR/luks-aes-256-xts-plain64-sha1.img | ||
83 | +sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain64 --key-size 512 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-xts-plain64-sha1.img | ||
84 | # Open dev | ||
85 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha1.img qiotest-145-aes-256-xts-plain64-sha1 | ||
86 | # Set dev owner | ||
87 | @@ -XXX,XX +XXX,XX @@ unlink TEST_DIR/luks-aes-256-xts-plain64-sha1.img | ||
88 | |||
89 | # ================= qemu-img aes-256-xts-plain64-sha1 ================= | ||
90 | # Create image | ||
91 | -qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,cipher-alg=aes-256,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-aes-256-xts-plain64-sha1.img 4194304M | ||
92 | -Formatting 'TEST_DIR/luks-aes-256-xts-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 | ||
93 | +qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-aes-256-xts-plain64-sha1.img 4194304M | ||
94 | +Formatting 'TEST_DIR/luks-aes-256-xts-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 iter-time=10 | ||
95 | |||
96 | # Open dev | ||
97 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha1.img qiotest-145-aes-256-xts-plain64-sha1 | ||
98 | @@ -XXX,XX +XXX,XX @@ unlink TEST_DIR/luks-aes-256-xts-plain64-sha1.img | ||
99 | # Create image | ||
100 | truncate TEST_DIR/luks-twofish-256-xts-plain64-sha1.img --size 4194304MB | ||
101 | # Format image | ||
102 | -sudo cryptsetup -q -v luksFormat --cipher twofish-xts-plain64 --key-size 512 --hash sha1 --key-slot 0 --key-file - TEST_DIR/luks-twofish-256-xts-plain64-sha1.img | ||
103 | +sudo cryptsetup -q -v luksFormat --cipher twofish-xts-plain64 --key-size 512 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-twofish-256-xts-plain64-sha1.img | ||
104 | # Open dev | ||
105 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-twofish-256-xts-plain64-sha1.img qiotest-145-twofish-256-xts-plain64-sha1 | ||
106 | # Set dev owner | ||
107 | @@ -XXX,XX +XXX,XX @@ unlink TEST_DIR/luks-twofish-256-xts-plain64-sha1.img | ||
108 | |||
109 | # ================= qemu-img twofish-256-xts-plain64-sha1 ================= | ||
110 | # Create image | ||
111 | -qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,cipher-alg=twofish-256,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-twofish-256-xts-plain64-sha1.img 4194304M | ||
112 | -Formatting 'TEST_DIR/luks-twofish-256-xts-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=twofish-256 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 | ||
113 | +qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=twofish-256,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-twofish-256-xts-plain64-sha1.img 4194304M | ||
114 | +Formatting 'TEST_DIR/luks-twofish-256-xts-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=twofish-256 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 iter-time=10 | ||
115 | |||
116 | # Open dev | ||
117 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-twofish-256-xts-plain64-sha1.img qiotest-145-twofish-256-xts-plain64-sha1 | ||
118 | @@ -XXX,XX +XXX,XX @@ unlink TEST_DIR/luks-twofish-256-xts-plain64-sha1.img | ||
119 | # Create image | ||
120 | truncate TEST_DIR/luks-serpent-256-xts-plain64-sha1.img --size 4194304MB | ||
121 | # Format image | ||
122 | -sudo cryptsetup -q -v luksFormat --cipher serpent-xts-plain64 --key-size 512 --hash sha1 --key-slot 0 --key-file - TEST_DIR/luks-serpent-256-xts-plain64-sha1.img | ||
123 | +sudo cryptsetup -q -v luksFormat --cipher serpent-xts-plain64 --key-size 512 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-serpent-256-xts-plain64-sha1.img | ||
124 | # Open dev | ||
125 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-256-xts-plain64-sha1.img qiotest-145-serpent-256-xts-plain64-sha1 | ||
126 | # Set dev owner | ||
127 | @@ -XXX,XX +XXX,XX @@ unlink TEST_DIR/luks-serpent-256-xts-plain64-sha1.img | ||
128 | |||
129 | # ================= qemu-img serpent-256-xts-plain64-sha1 ================= | ||
130 | # Create image | ||
131 | -qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,cipher-alg=serpent-256,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-serpent-256-xts-plain64-sha1.img 4194304M | ||
132 | -Formatting 'TEST_DIR/luks-serpent-256-xts-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=serpent-256 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 | ||
133 | +qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=serpent-256,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-serpent-256-xts-plain64-sha1.img 4194304M | ||
134 | +Formatting 'TEST_DIR/luks-serpent-256-xts-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=serpent-256 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 iter-time=10 | ||
135 | |||
136 | # Open dev | ||
137 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-256-xts-plain64-sha1.img qiotest-145-serpent-256-xts-plain64-sha1 | ||
138 | @@ -XXX,XX +XXX,XX @@ unlink TEST_DIR/luks-serpent-256-xts-plain64-sha1.img | ||
139 | # Create image | ||
140 | truncate TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img --size 4194304MB | ||
141 | # Format image | ||
142 | -sudo cryptsetup -q -v luksFormat --cipher cast5-cbc-plain64 --key-size 128 --hash sha1 --key-slot 0 --key-file - TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img | ||
143 | +sudo cryptsetup -q -v luksFormat --cipher cast5-cbc-plain64 --key-size 128 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img | ||
144 | # Open dev | ||
145 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img qiotest-145-cast5-128-cbc-plain64-sha1 | ||
146 | # Set dev owner | ||
147 | @@ -XXX,XX +XXX,XX @@ unlink TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img | ||
148 | |||
149 | # ================= qemu-img cast5-128-cbc-plain64-sha1 ================= | ||
150 | # Create image | ||
151 | -qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,cipher-alg=cast5-128,cipher-mode=cbc,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img 4194304M | ||
152 | -Formatting 'TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=cast5-128 cipher-mode=cbc ivgen-alg=plain64 hash-alg=sha1 | ||
153 | +qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=cast5-128,cipher-mode=cbc,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img 4194304M | ||
154 | +Formatting 'TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=cast5-128 cipher-mode=cbc ivgen-alg=plain64 hash-alg=sha1 iter-time=10 | ||
155 | |||
156 | # Open dev | ||
157 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img qiotest-145-cast5-128-cbc-plain64-sha1 | ||
158 | @@ -XXX,XX +XXX,XX @@ Skipping cast6-256-xts-plain64-sha1 in blacklist | ||
159 | # Create image | ||
160 | truncate TEST_DIR/luks-aes-256-cbc-plain-sha1.img --size 4194304MB | ||
161 | # Format image | ||
162 | -sudo cryptsetup -q -v luksFormat --cipher aes-cbc-plain --key-size 256 --hash sha1 --key-slot 0 --key-file - TEST_DIR/luks-aes-256-cbc-plain-sha1.img | ||
163 | +sudo cryptsetup -q -v luksFormat --cipher aes-cbc-plain --key-size 256 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-cbc-plain-sha1.img | ||
164 | # Open dev | ||
165 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-plain-sha1.img qiotest-145-aes-256-cbc-plain-sha1 | ||
166 | # Set dev owner | ||
167 | @@ -XXX,XX +XXX,XX @@ unlink TEST_DIR/luks-aes-256-cbc-plain-sha1.img | ||
168 | |||
169 | # ================= qemu-img aes-256-cbc-plain-sha1 ================= | ||
170 | # Create image | ||
171 | -qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,cipher-alg=aes-256,cipher-mode=cbc,ivgen-alg=plain,hash-alg=sha1 TEST_DIR/luks-aes-256-cbc-plain-sha1.img 4194304M | ||
172 | -Formatting 'TEST_DIR/luks-aes-256-cbc-plain-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=cbc ivgen-alg=plain hash-alg=sha1 | ||
173 | +qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=cbc,ivgen-alg=plain,hash-alg=sha1 TEST_DIR/luks-aes-256-cbc-plain-sha1.img 4194304M | ||
174 | +Formatting 'TEST_DIR/luks-aes-256-cbc-plain-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=cbc ivgen-alg=plain hash-alg=sha1 iter-time=10 | ||
175 | |||
176 | # Open dev | ||
177 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-plain-sha1.img qiotest-145-aes-256-cbc-plain-sha1 | ||
178 | @@ -XXX,XX +XXX,XX @@ unlink TEST_DIR/luks-aes-256-cbc-plain-sha1.img | ||
179 | # Create image | ||
180 | truncate TEST_DIR/luks-aes-256-cbc-plain64-sha1.img --size 4194304MB | ||
181 | # Format image | ||
182 | -sudo cryptsetup -q -v luksFormat --cipher aes-cbc-plain64 --key-size 256 --hash sha1 --key-slot 0 --key-file - TEST_DIR/luks-aes-256-cbc-plain64-sha1.img | ||
183 | +sudo cryptsetup -q -v luksFormat --cipher aes-cbc-plain64 --key-size 256 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-cbc-plain64-sha1.img | ||
184 | # Open dev | ||
185 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-plain64-sha1.img qiotest-145-aes-256-cbc-plain64-sha1 | ||
186 | # Set dev owner | ||
187 | @@ -XXX,XX +XXX,XX @@ unlink TEST_DIR/luks-aes-256-cbc-plain64-sha1.img | ||
188 | |||
189 | # ================= qemu-img aes-256-cbc-plain64-sha1 ================= | ||
190 | # Create image | ||
191 | -qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,cipher-alg=aes-256,cipher-mode=cbc,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-aes-256-cbc-plain64-sha1.img 4194304M | ||
192 | -Formatting 'TEST_DIR/luks-aes-256-cbc-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=cbc ivgen-alg=plain64 hash-alg=sha1 | ||
193 | +qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=cbc,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-aes-256-cbc-plain64-sha1.img 4194304M | ||
194 | +Formatting 'TEST_DIR/luks-aes-256-cbc-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=cbc ivgen-alg=plain64 hash-alg=sha1 iter-time=10 | ||
195 | |||
196 | # Open dev | ||
197 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-plain64-sha1.img qiotest-145-aes-256-cbc-plain64-sha1 | ||
198 | @@ -XXX,XX +XXX,XX @@ unlink TEST_DIR/luks-aes-256-cbc-plain64-sha1.img | ||
199 | # Create image | ||
200 | truncate TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img --size 4194304MB | ||
201 | # Format image | ||
202 | -sudo cryptsetup -q -v luksFormat --cipher aes-cbc-essiv:sha256 --key-size 256 --hash sha1 --key-slot 0 --key-file - TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img | ||
203 | +sudo cryptsetup -q -v luksFormat --cipher aes-cbc-essiv:sha256 --key-size 256 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img | ||
204 | # Open dev | ||
205 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img qiotest-145-aes-256-cbc-essiv-sha256-sha1 | ||
206 | # Set dev owner | ||
207 | @@ -XXX,XX +XXX,XX @@ unlink TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img | ||
208 | |||
209 | # ================= qemu-img aes-256-cbc-essiv-sha256-sha1 ================= | ||
210 | # Create image | ||
211 | -qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,cipher-alg=aes-256,cipher-mode=cbc,ivgen-alg=essiv,hash-alg=sha1,ivgen-hash-alg=sha256 TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img 4194304M | ||
212 | -Formatting 'TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=cbc ivgen-alg=essiv ivgen-hash-alg=sha256 hash-alg=sha1 | ||
213 | +qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=cbc,ivgen-alg=essiv,hash-alg=sha1,ivgen-hash-alg=sha256 TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img 4194304M | ||
214 | +Formatting 'TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=cbc ivgen-alg=essiv ivgen-hash-alg=sha256 hash-alg=sha1 iter-time=10 | ||
215 | |||
216 | # Open dev | ||
217 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img qiotest-145-aes-256-cbc-essiv-sha256-sha1 | ||
218 | @@ -XXX,XX +XXX,XX @@ unlink TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img | ||
219 | # Create image | ||
220 | truncate TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img --size 4194304MB | ||
221 | # Format image | ||
222 | -sudo cryptsetup -q -v luksFormat --cipher aes-xts-essiv:sha256 --key-size 512 --hash sha1 --key-slot 0 --key-file - TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img | ||
223 | +sudo cryptsetup -q -v luksFormat --cipher aes-xts-essiv:sha256 --key-size 512 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img | ||
224 | # Open dev | ||
225 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img qiotest-145-aes-256-xts-essiv-sha256-sha1 | ||
226 | # Set dev owner | ||
227 | @@ -XXX,XX +XXX,XX @@ unlink TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img | ||
228 | |||
229 | # ================= qemu-img aes-256-xts-essiv-sha256-sha1 ================= | ||
230 | # Create image | ||
231 | -qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,cipher-alg=aes-256,cipher-mode=xts,ivgen-alg=essiv,hash-alg=sha1,ivgen-hash-alg=sha256 TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img 4194304M | ||
232 | -Formatting 'TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=xts ivgen-alg=essiv ivgen-hash-alg=sha256 hash-alg=sha1 | ||
233 | +qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=xts,ivgen-alg=essiv,hash-alg=sha1,ivgen-hash-alg=sha256 TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img 4194304M | ||
234 | +Formatting 'TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=xts ivgen-alg=essiv ivgen-hash-alg=sha256 hash-alg=sha1 iter-time=10 | ||
235 | |||
236 | # Open dev | ||
237 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img qiotest-145-aes-256-xts-essiv-sha256-sha1 | ||
238 | @@ -XXX,XX +XXX,XX @@ unlink TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img | ||
239 | # Create image | ||
240 | truncate TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img --size 4194304MB | ||
241 | # Format image | ||
242 | -sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain64 --key-size 256 --hash sha1 --key-slot 0 --key-file - TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img | ||
243 | +sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain64 --key-size 256 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img | ||
244 | # Open dev | ||
245 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img qiotest-145-aes-128-xts-plain64-sha256-sha1 | ||
246 | # Set dev owner | ||
247 | @@ -XXX,XX +XXX,XX @@ unlink TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img | ||
248 | |||
249 | # ================= qemu-img aes-128-xts-plain64-sha256-sha1 ================= | ||
250 | # Create image | ||
251 | -qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,cipher-alg=aes-128,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img 4194304M | ||
252 | -Formatting 'TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-128 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 | ||
253 | +qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-128,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img 4194304M | ||
254 | +Formatting 'TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-128 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 iter-time=10 | ||
255 | |||
256 | # Open dev | ||
257 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img qiotest-145-aes-128-xts-plain64-sha256-sha1 | ||
258 | @@ -XXX,XX +XXX,XX @@ unlink TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img | ||
259 | # Create image | ||
260 | truncate TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img --size 4194304MB | ||
261 | # Format image | ||
262 | -sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain64 --key-size 384 --hash sha1 --key-slot 0 --key-file - TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img | ||
263 | +sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain64 --key-size 384 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img | ||
264 | # Open dev | ||
265 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img qiotest-145-aes-192-xts-plain64-sha256-sha1 | ||
266 | # Set dev owner | ||
267 | @@ -XXX,XX +XXX,XX @@ unlink TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img | ||
268 | |||
269 | # ================= qemu-img aes-192-xts-plain64-sha256-sha1 ================= | ||
270 | # Create image | ||
271 | -qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,cipher-alg=aes-192,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img 4194304M | ||
272 | -Formatting 'TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-192 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 | ||
273 | +qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-192,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img 4194304M | ||
274 | +Formatting 'TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-192 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 iter-time=10 | ||
275 | |||
276 | # Open dev | ||
277 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img qiotest-145-aes-192-xts-plain64-sha256-sha1 | ||
278 | @@ -XXX,XX +XXX,XX @@ unlink TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img | ||
279 | # Create image | ||
280 | truncate TEST_DIR/luks-twofish-128-xts-plain64-sha1.img --size 4194304MB | ||
281 | # Format image | ||
282 | -sudo cryptsetup -q -v luksFormat --cipher twofish-xts-plain64 --key-size 256 --hash sha1 --key-slot 0 --key-file - TEST_DIR/luks-twofish-128-xts-plain64-sha1.img | ||
283 | +sudo cryptsetup -q -v luksFormat --cipher twofish-xts-plain64 --key-size 256 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-twofish-128-xts-plain64-sha1.img | ||
284 | # Open dev | ||
285 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-twofish-128-xts-plain64-sha1.img qiotest-145-twofish-128-xts-plain64-sha1 | ||
286 | # Set dev owner | ||
287 | @@ -XXX,XX +XXX,XX @@ unlink TEST_DIR/luks-twofish-128-xts-plain64-sha1.img | ||
288 | |||
289 | # ================= qemu-img twofish-128-xts-plain64-sha1 ================= | ||
290 | # Create image | ||
291 | -qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,cipher-alg=twofish-128,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-twofish-128-xts-plain64-sha1.img 4194304M | ||
292 | -Formatting 'TEST_DIR/luks-twofish-128-xts-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=twofish-128 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 | ||
293 | +qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=twofish-128,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-twofish-128-xts-plain64-sha1.img 4194304M | ||
294 | +Formatting 'TEST_DIR/luks-twofish-128-xts-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=twofish-128 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 iter-time=10 | ||
295 | |||
296 | # Open dev | ||
297 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-twofish-128-xts-plain64-sha1.img qiotest-145-twofish-128-xts-plain64-sha1 | ||
298 | @@ -XXX,XX +XXX,XX @@ Skipping twofish-192-xts-plain64-sha1 in blacklist | ||
299 | # Create image | ||
300 | truncate TEST_DIR/luks-serpent-128-xts-plain64-sha1.img --size 4194304MB | ||
301 | # Format image | ||
302 | -sudo cryptsetup -q -v luksFormat --cipher serpent-xts-plain64 --key-size 256 --hash sha1 --key-slot 0 --key-file - TEST_DIR/luks-serpent-128-xts-plain64-sha1.img | ||
303 | +sudo cryptsetup -q -v luksFormat --cipher serpent-xts-plain64 --key-size 256 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-serpent-128-xts-plain64-sha1.img | ||
304 | # Open dev | ||
305 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-128-xts-plain64-sha1.img qiotest-145-serpent-128-xts-plain64-sha1 | ||
306 | # Set dev owner | ||
307 | @@ -XXX,XX +XXX,XX @@ unlink TEST_DIR/luks-serpent-128-xts-plain64-sha1.img | ||
308 | |||
309 | # ================= qemu-img serpent-128-xts-plain64-sha1 ================= | ||
310 | # Create image | ||
311 | -qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,cipher-alg=serpent-128,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-serpent-128-xts-plain64-sha1.img 4194304M | ||
312 | -Formatting 'TEST_DIR/luks-serpent-128-xts-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=serpent-128 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 | ||
313 | +qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=serpent-128,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-serpent-128-xts-plain64-sha1.img 4194304M | ||
314 | +Formatting 'TEST_DIR/luks-serpent-128-xts-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=serpent-128 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 iter-time=10 | ||
315 | |||
316 | # Open dev | ||
317 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-128-xts-plain64-sha1.img qiotest-145-serpent-128-xts-plain64-sha1 | ||
318 | @@ -XXX,XX +XXX,XX @@ unlink TEST_DIR/luks-serpent-128-xts-plain64-sha1.img | ||
319 | # Create image | ||
320 | truncate TEST_DIR/luks-serpent-192-xts-plain64-sha1.img --size 4194304MB | ||
321 | # Format image | ||
322 | -sudo cryptsetup -q -v luksFormat --cipher serpent-xts-plain64 --key-size 384 --hash sha1 --key-slot 0 --key-file - TEST_DIR/luks-serpent-192-xts-plain64-sha1.img | ||
323 | +sudo cryptsetup -q -v luksFormat --cipher serpent-xts-plain64 --key-size 384 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-serpent-192-xts-plain64-sha1.img | ||
324 | # Open dev | ||
325 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-192-xts-plain64-sha1.img qiotest-145-serpent-192-xts-plain64-sha1 | ||
326 | # Set dev owner | ||
327 | @@ -XXX,XX +XXX,XX @@ unlink TEST_DIR/luks-serpent-192-xts-plain64-sha1.img | ||
328 | |||
329 | # ================= qemu-img serpent-192-xts-plain64-sha1 ================= | ||
330 | # Create image | ||
331 | -qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,cipher-alg=serpent-192,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-serpent-192-xts-plain64-sha1.img 4194304M | ||
332 | -Formatting 'TEST_DIR/luks-serpent-192-xts-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=serpent-192 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 | ||
333 | +qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=serpent-192,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-serpent-192-xts-plain64-sha1.img 4194304M | ||
334 | +Formatting 'TEST_DIR/luks-serpent-192-xts-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=serpent-192 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 iter-time=10 | ||
335 | |||
336 | # Open dev | ||
337 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-192-xts-plain64-sha1.img qiotest-145-serpent-192-xts-plain64-sha1 | ||
338 | @@ -XXX,XX +XXX,XX @@ Skipping cast6-192-xts-plain64-sha1 in blacklist | ||
339 | # Create image | ||
340 | truncate TEST_DIR/luks-aes-256-xts-plain64-sha256.img --size 4194304MB | ||
341 | # Format image | ||
342 | -sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain64 --key-size 512 --hash sha256 --key-slot 0 --key-file - TEST_DIR/luks-aes-256-xts-plain64-sha256.img | ||
343 | +sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain64 --key-size 512 --hash sha256 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-xts-plain64-sha256.img | ||
344 | # Open dev | ||
345 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha256.img qiotest-145-aes-256-xts-plain64-sha256 | ||
346 | # Set dev owner | ||
347 | @@ -XXX,XX +XXX,XX @@ unlink TEST_DIR/luks-aes-256-xts-plain64-sha256.img | ||
348 | |||
349 | # ================= qemu-img aes-256-xts-plain64-sha256 ================= | ||
350 | # Create image | ||
351 | -qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,cipher-alg=aes-256,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha256 TEST_DIR/luks-aes-256-xts-plain64-sha256.img 4194304M | ||
352 | -Formatting 'TEST_DIR/luks-aes-256-xts-plain64-sha256.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha256 | ||
353 | +qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha256 TEST_DIR/luks-aes-256-xts-plain64-sha256.img 4194304M | ||
354 | +Formatting 'TEST_DIR/luks-aes-256-xts-plain64-sha256.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha256 iter-time=10 | ||
355 | |||
356 | # Open dev | ||
357 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha256.img qiotest-145-aes-256-xts-plain64-sha256 | ||
358 | @@ -XXX,XX +XXX,XX @@ Skipping aes-256-xts-plain64-ripemd160 in blacklist | ||
359 | # Create image | ||
360 | truncate TEST_DIR/luks-aes-256-xts-plain-sha1-pwslot3.img --size 4194304MB | ||
361 | # Format image | ||
362 | -sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain --key-size 512 --hash sha1 --key-slot 3 --key-file - TEST_DIR/luks-aes-256-xts-plain-sha1-pwslot3.img | ||
363 | +sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain --key-size 512 --hash sha1 --key-slot 3 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-xts-plain-sha1-pwslot3.img | ||
364 | # Open dev | ||
365 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain-sha1-pwslot3.img qiotest-145-aes-256-xts-plain-sha1-pwslot3 | ||
366 | # Set dev owner | ||
367 | @@ -XXX,XX +XXX,XX @@ unlink TEST_DIR/luks-aes-256-xts-plain-sha1-pwslot3.img | ||
368 | # Create image | ||
369 | truncate TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img --size 4194304MB | ||
370 | # Format image | ||
371 | -sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain --key-size 512 --hash sha1 --key-slot 0 --key-file - TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img | ||
372 | +sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain --key-size 512 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img | ||
373 | # Add password slot 1 | ||
374 | -sudo cryptsetup -q -v luksAddKey TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img --key-slot 1 --key-file - TEST_DIR/passwd.txt | ||
375 | +sudo cryptsetup -q -v luksAddKey TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img --key-slot 1 --key-file - --iter-time 10 TEST_DIR/passwd.txt | ||
376 | # Add password slot 2 | ||
377 | -sudo cryptsetup -q -v luksAddKey TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img --key-slot 2 --key-file - TEST_DIR/passwd.txt | ||
378 | +sudo cryptsetup -q -v luksAddKey TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img --key-slot 2 --key-file - --iter-time 10 TEST_DIR/passwd.txt | ||
379 | # Add password slot 3 | ||
380 | -sudo cryptsetup -q -v luksAddKey TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img --key-slot 3 --key-file - TEST_DIR/passwd.txt | ||
381 | +sudo cryptsetup -q -v luksAddKey TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img --key-slot 3 --key-file - --iter-time 10 TEST_DIR/passwd.txt | ||
382 | # Add password slot 4 | ||
383 | -sudo cryptsetup -q -v luksAddKey TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img --key-slot 4 --key-file - TEST_DIR/passwd.txt | ||
384 | +sudo cryptsetup -q -v luksAddKey TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img --key-slot 4 --key-file - --iter-time 10 TEST_DIR/passwd.txt | ||
385 | # Add password slot 5 | ||
386 | -sudo cryptsetup -q -v luksAddKey TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img --key-slot 5 --key-file - TEST_DIR/passwd.txt | ||
387 | +sudo cryptsetup -q -v luksAddKey TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img --key-slot 5 --key-file - --iter-time 10 TEST_DIR/passwd.txt | ||
388 | # Add password slot 6 | ||
389 | -sudo cryptsetup -q -v luksAddKey TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img --key-slot 6 --key-file - TEST_DIR/passwd.txt | ||
390 | +sudo cryptsetup -q -v luksAddKey TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img --key-slot 6 --key-file - --iter-time 10 TEST_DIR/passwd.txt | ||
391 | # Add password slot 7 | ||
392 | -sudo cryptsetup -q -v luksAddKey TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img --key-slot 7 --key-file - TEST_DIR/passwd.txt | ||
393 | +sudo cryptsetup -q -v luksAddKey TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img --key-slot 7 --key-file - --iter-time 10 TEST_DIR/passwd.txt | ||
394 | # Open dev | ||
395 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img qiotest-145-aes-256-xts-plain-sha1-pwallslots | ||
396 | # Set dev owner | ||
397 | @@ -XXX,XX +XXX,XX @@ unlink TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img | ||
398 | |||
399 | # ================= qemu-img aes-256-xts-plain-sha1-pwallslots ================= | ||
400 | # Create image | ||
401 | -qemu-img create -f luks --object secret,id=sec0,data=c2xvdDE=,format=base64 -o key-secret=sec0,cipher-alg=aes-256,cipher-mode=xts,ivgen-alg=plain,hash-alg=sha1 TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img 4194304M | ||
402 | -Formatting 'TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=xts ivgen-alg=plain hash-alg=sha1 | ||
403 | +qemu-img create -f luks --object secret,id=sec0,data=c2xvdDE=,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=xts,ivgen-alg=plain,hash-alg=sha1 TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img 4194304M | ||
404 | +Formatting 'TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=xts ivgen-alg=plain hash-alg=sha1 iter-time=10 | ||
405 | |||
406 | # Open dev | ||
407 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img qiotest-145-aes-256-xts-plain-sha1-pwallslots | ||
408 | @@ -XXX,XX +XXX,XX @@ unlink TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img | ||
409 | # Create image | ||
410 | truncate TEST_DIR/luks-aes-256-cbc-essiv-auto-sha1.img --size 4194304MB | ||
411 | # Format image | ||
412 | -sudo cryptsetup -q -v luksFormat --cipher aes-cbc-essiv:sha256 --key-size 256 --hash sha1 --key-slot 0 --key-file - TEST_DIR/luks-aes-256-cbc-essiv-auto-sha1.img | ||
413 | +sudo cryptsetup -q -v luksFormat --cipher aes-cbc-essiv:sha256 --key-size 256 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-cbc-essiv-auto-sha1.img | ||
414 | # Open dev | ||
415 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-essiv-auto-sha1.img qiotest-145-aes-256-cbc-essiv-auto-sha1 | ||
416 | # Set dev owner | ||
417 | @@ -XXX,XX +XXX,XX @@ unlink TEST_DIR/luks-aes-256-cbc-essiv-auto-sha1.img | ||
418 | |||
419 | # ================= qemu-img aes-256-cbc-essiv-auto-sha1 ================= | ||
420 | # Create image | ||
421 | -qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,cipher-alg=aes-256,cipher-mode=cbc,ivgen-alg=essiv,hash-alg=sha1 TEST_DIR/luks-aes-256-cbc-essiv-auto-sha1.img 4194304M | ||
422 | -Formatting 'TEST_DIR/luks-aes-256-cbc-essiv-auto-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=cbc ivgen-alg=essiv hash-alg=sha1 | ||
423 | +qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=cbc,ivgen-alg=essiv,hash-alg=sha1 TEST_DIR/luks-aes-256-cbc-essiv-auto-sha1.img 4194304M | ||
424 | +Formatting 'TEST_DIR/luks-aes-256-cbc-essiv-auto-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=cbc ivgen-alg=essiv hash-alg=sha1 iter-time=10 | ||
425 | |||
426 | # Open dev | ||
427 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-essiv-auto-sha1.img qiotest-145-aes-256-cbc-essiv-auto-sha1 | ||
428 | @@ -XXX,XX +XXX,XX @@ unlink TEST_DIR/luks-aes-256-cbc-essiv-auto-sha1.img | ||
429 | # Create image | ||
430 | truncate TEST_DIR/luks-aes-256-cbc-plain64-sha256-sha1.img --size 4194304MB | ||
431 | # Format image | ||
432 | -sudo cryptsetup -q -v luksFormat --cipher aes-cbc-plain64:sha256 --key-size 256 --hash sha1 --key-slot 0 --key-file - TEST_DIR/luks-aes-256-cbc-plain64-sha256-sha1.img | ||
433 | +sudo cryptsetup -q -v luksFormat --cipher aes-cbc-plain64:sha256 --key-size 256 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-cbc-plain64-sha256-sha1.img | ||
434 | # Open dev | ||
435 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-plain64-sha256-sha1.img qiotest-145-aes-256-cbc-plain64-sha256-sha1 | ||
436 | # Set dev owner | ||
437 | @@ -XXX,XX +XXX,XX @@ unlink TEST_DIR/luks-aes-256-cbc-plain64-sha256-sha1.img | ||
438 | |||
439 | # ================= qemu-img aes-256-cbc-plain64-sha256-sha1 ================= | ||
440 | # Create image | ||
441 | -qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,cipher-alg=aes-256,cipher-mode=cbc,ivgen-alg=plain64,hash-alg=sha1,ivgen-hash-alg=sha256 TEST_DIR/luks-aes-256-cbc-plain64-sha256-sha1.img 4194304M | ||
442 | -Formatting 'TEST_DIR/luks-aes-256-cbc-plain64-sha256-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=cbc ivgen-alg=plain64 ivgen-hash-alg=sha256 hash-alg=sha1 | ||
443 | +qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=cbc,ivgen-alg=plain64,hash-alg=sha1,ivgen-hash-alg=sha256 TEST_DIR/luks-aes-256-cbc-plain64-sha256-sha1.img 4194304M | ||
444 | +Formatting 'TEST_DIR/luks-aes-256-cbc-plain64-sha256-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=cbc ivgen-alg=plain64 ivgen-hash-alg=sha256 hash-alg=sha1 iter-time=10 | ||
445 | |||
446 | # Open dev | ||
447 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-plain64-sha256-sha1.img qiotest-145-aes-256-cbc-plain64-sha256-sha1 | ||
448 | diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter | ||
449 | index XXXXXXX..XXXXXXX 100644 | ||
450 | --- a/tests/qemu-iotests/common.filter | ||
451 | +++ b/tests/qemu-iotests/common.filter | ||
452 | @@ -XXX,XX +XXX,XX @@ _filter_img_create() | ||
453 | -e "s# block_state_zero=\\(on\\|off\\)##g" \ | ||
454 | -e "s# log_size=[0-9]\\+##g" \ | ||
455 | -e "s# refcount_bits=[0-9]\\+##g" \ | ||
456 | - -e "s# key-secret=[a-zA-Z0-9]\\+##g" | ||
457 | + -e "s# key-secret=[a-zA-Z0-9]\\+##g" \ | ||
458 | + -e "s# iter-time=[0-9]\\+##g" | ||
459 | } | ||
460 | |||
461 | _filter_img_info() | ||
462 | diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc | ||
463 | index XXXXXXX..XXXXXXX 100644 | ||
464 | --- a/tests/qemu-iotests/common.rc | ||
465 | +++ b/tests/qemu-iotests/common.rc | ||
466 | @@ -XXX,XX +XXX,XX @@ _set_default_imgopts() | ||
467 | if [ "$IMGFMT" == "qcow2" ] && ! (echo "$IMGOPTS" | grep "compat=" > /dev/null); then | ||
468 | IMGOPTS=$(_optstr_add "$IMGOPTS" "compat=1.1") | ||
469 | fi | ||
470 | + if [ "$IMGFMT" == "luks" ] && ! (echo "$IMGOPTS" | grep "iter-time=" > /dev/null); then | ||
471 | + IMGOPTS=$(_optstr_add "$IMGOPTS" "iter-time=10") | ||
472 | + fi | ||
473 | } | ||
474 | |||
475 | _use_sample_img() | ||
476 | -- | ||
477 | 1.8.3.1 | ||
478 | |||
479 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: "Daniel P. Berrange" <berrange@redhat.com> | ||
2 | 1 | ||
3 | Add tests for sha224, sha512, sha384 and ripemd160 hash | ||
4 | algorithms. | ||
5 | |||
6 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
7 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
8 | Signed-off-by: Daniel P. Berrange <berrange@redhat.com> | ||
9 | Message-id: 20170626123510.20134-5-berrange@redhat.com | ||
10 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
11 | --- | ||
12 | tests/qemu-iotests/149 | 10 +- | ||
13 | tests/qemu-iotests/149.out | 482 ++++++++++++++++++++++++++++++++++++++++++++- | ||
14 | 2 files changed, 484 insertions(+), 8 deletions(-) | ||
15 | |||
16 | diff --git a/tests/qemu-iotests/149 b/tests/qemu-iotests/149 | ||
17 | index XXXXXXX..XXXXXXX 100755 | ||
18 | --- a/tests/qemu-iotests/149 | ||
19 | +++ b/tests/qemu-iotests/149 | ||
20 | @@ -XXX,XX +XXX,XX @@ configs = [ | ||
21 | |||
22 | |||
23 | # LUKS default but diff hash | ||
24 | + LUKSConfig("aes-256-xts-plain64-sha224", | ||
25 | + "aes", 256, "xts", "plain64", None, "sha224"), | ||
26 | LUKSConfig("aes-256-xts-plain64-sha256", | ||
27 | "aes", 256, "xts", "plain64", None, "sha256"), | ||
28 | + LUKSConfig("aes-256-xts-plain64-sha384", | ||
29 | + "aes", 256, "xts", "plain64", None, "sha384"), | ||
30 | LUKSConfig("aes-256-xts-plain64-sha512", | ||
31 | "aes", 256, "xts", "plain64", None, "sha512"), | ||
32 | LUKSConfig("aes-256-xts-plain64-ripemd160", | ||
33 | @@ -XXX,XX +XXX,XX @@ blacklist = [ | ||
34 | |||
35 | # GCrypt doesn't support Twofish with 192 bit key | ||
36 | "twofish-192-xts-plain64-sha1", | ||
37 | - | ||
38 | - # We don't have sha512 hash wired up yet | ||
39 | - "aes-256-xts-plain64-sha512", | ||
40 | - | ||
41 | - # We don't have ripemd160 hash wired up yet | ||
42 | - "aes-256-xts-plain64-ripemd160", | ||
43 | ] | ||
44 | |||
45 | whitelist = [] | ||
46 | diff --git a/tests/qemu-iotests/149.out b/tests/qemu-iotests/149.out | ||
47 | index XXXXXXX..XXXXXXX 100644 | ||
48 | --- a/tests/qemu-iotests/149.out | ||
49 | +++ b/tests/qemu-iotests/149.out | ||
50 | @@ -XXX,XX +XXX,XX @@ unlink TEST_DIR/luks-serpent-192-xts-plain64-sha1.img | ||
51 | |||
52 | Skipping cast6-128-xts-plain64-sha1 in blacklist | ||
53 | Skipping cast6-192-xts-plain64-sha1 in blacklist | ||
54 | +# ================= dm-crypt aes-256-xts-plain64-sha224 ================= | ||
55 | +# Create image | ||
56 | +truncate TEST_DIR/luks-aes-256-xts-plain64-sha224.img --size 4194304MB | ||
57 | +# Format image | ||
58 | +sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain64 --key-size 512 --hash sha224 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-xts-plain64-sha224.img | ||
59 | +# Open dev | ||
60 | +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha224.img qiotest-145-aes-256-xts-plain64-sha224 | ||
61 | +# Set dev owner | ||
62 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 | ||
63 | +# Write test pattern 0xa7 | ||
64 | +qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 | ||
65 | +wrote 10485760/10485760 bytes at offset 104857600 | ||
66 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
67 | + | ||
68 | +# Write test pattern 0x13 | ||
69 | +qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 | ||
70 | +wrote 10485760/10485760 bytes at offset 3298534883328 | ||
71 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
72 | + | ||
73 | +# Close dev | ||
74 | +sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain64-sha224 | ||
75 | +# Read test pattern 0xa7 | ||
76 | +qemu-io -c read -P 0xa7 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha224.img | ||
77 | +read 10485760/10485760 bytes at offset 104857600 | ||
78 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
79 | + | ||
80 | +# Read test pattern 0x13 | ||
81 | +qemu-io -c read -P 0x13 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha224.img | ||
82 | +read 10485760/10485760 bytes at offset 3298534883328 | ||
83 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
84 | + | ||
85 | +# Write test pattern 0x91 | ||
86 | +qemu-io -c write -P 0x91 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha224.img | ||
87 | +wrote 10485760/10485760 bytes at offset 104857600 | ||
88 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
89 | + | ||
90 | +# Write test pattern 0x5e | ||
91 | +qemu-io -c write -P 0x5e 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha224.img | ||
92 | +wrote 10485760/10485760 bytes at offset 3298534883328 | ||
93 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
94 | + | ||
95 | +# Open dev | ||
96 | +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha224.img qiotest-145-aes-256-xts-plain64-sha224 | ||
97 | +# Set dev owner | ||
98 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 | ||
99 | +# Read test pattern 0x91 | ||
100 | +qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 | ||
101 | +read 10485760/10485760 bytes at offset 104857600 | ||
102 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
103 | + | ||
104 | +# Read test pattern 0x5e | ||
105 | +qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 | ||
106 | +read 10485760/10485760 bytes at offset 3298534883328 | ||
107 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
108 | + | ||
109 | +# Close dev | ||
110 | +sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain64-sha224 | ||
111 | +# Delete image | ||
112 | +unlink TEST_DIR/luks-aes-256-xts-plain64-sha224.img | ||
113 | + | ||
114 | +# ================= qemu-img aes-256-xts-plain64-sha224 ================= | ||
115 | +# Create image | ||
116 | +qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha224 TEST_DIR/luks-aes-256-xts-plain64-sha224.img 4194304M | ||
117 | +Formatting 'TEST_DIR/luks-aes-256-xts-plain64-sha224.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha224 iter-time=10 | ||
118 | + | ||
119 | +# Open dev | ||
120 | +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha224.img qiotest-145-aes-256-xts-plain64-sha224 | ||
121 | +# Set dev owner | ||
122 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 | ||
123 | +# Write test pattern 0xa7 | ||
124 | +qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 | ||
125 | +wrote 10485760/10485760 bytes at offset 104857600 | ||
126 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
127 | + | ||
128 | +# Write test pattern 0x13 | ||
129 | +qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 | ||
130 | +wrote 10485760/10485760 bytes at offset 3298534883328 | ||
131 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
132 | + | ||
133 | +# Close dev | ||
134 | +sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain64-sha224 | ||
135 | +# Read test pattern 0xa7 | ||
136 | +qemu-io -c read -P 0xa7 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha224.img | ||
137 | +read 10485760/10485760 bytes at offset 104857600 | ||
138 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
139 | + | ||
140 | +# Read test pattern 0x13 | ||
141 | +qemu-io -c read -P 0x13 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha224.img | ||
142 | +read 10485760/10485760 bytes at offset 3298534883328 | ||
143 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
144 | + | ||
145 | +# Write test pattern 0x91 | ||
146 | +qemu-io -c write -P 0x91 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha224.img | ||
147 | +wrote 10485760/10485760 bytes at offset 104857600 | ||
148 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
149 | + | ||
150 | +# Write test pattern 0x5e | ||
151 | +qemu-io -c write -P 0x5e 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha224.img | ||
152 | +wrote 10485760/10485760 bytes at offset 3298534883328 | ||
153 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
154 | + | ||
155 | +# Open dev | ||
156 | +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha224.img qiotest-145-aes-256-xts-plain64-sha224 | ||
157 | +# Set dev owner | ||
158 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 | ||
159 | +# Read test pattern 0x91 | ||
160 | +qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 | ||
161 | +read 10485760/10485760 bytes at offset 104857600 | ||
162 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
163 | + | ||
164 | +# Read test pattern 0x5e | ||
165 | +qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 | ||
166 | +read 10485760/10485760 bytes at offset 3298534883328 | ||
167 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
168 | + | ||
169 | +# Close dev | ||
170 | +sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain64-sha224 | ||
171 | +# Delete image | ||
172 | +unlink TEST_DIR/luks-aes-256-xts-plain64-sha224.img | ||
173 | + | ||
174 | # ================= dm-crypt aes-256-xts-plain64-sha256 ================= | ||
175 | # Create image | ||
176 | truncate TEST_DIR/luks-aes-256-xts-plain64-sha256.img --size 4194304MB | ||
177 | @@ -XXX,XX +XXX,XX @@ sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain64-sha256 | ||
178 | # Delete image | ||
179 | unlink TEST_DIR/luks-aes-256-xts-plain64-sha256.img | ||
180 | |||
181 | -Skipping aes-256-xts-plain64-sha512 in blacklist | ||
182 | -Skipping aes-256-xts-plain64-ripemd160 in blacklist | ||
183 | +# ================= dm-crypt aes-256-xts-plain64-sha384 ================= | ||
184 | +# Create image | ||
185 | +truncate TEST_DIR/luks-aes-256-xts-plain64-sha384.img --size 4194304MB | ||
186 | +# Format image | ||
187 | +sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain64 --key-size 512 --hash sha384 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-xts-plain64-sha384.img | ||
188 | +# Open dev | ||
189 | +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha384.img qiotest-145-aes-256-xts-plain64-sha384 | ||
190 | +# Set dev owner | ||
191 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 | ||
192 | +# Write test pattern 0xa7 | ||
193 | +qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 | ||
194 | +wrote 10485760/10485760 bytes at offset 104857600 | ||
195 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
196 | + | ||
197 | +# Write test pattern 0x13 | ||
198 | +qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 | ||
199 | +wrote 10485760/10485760 bytes at offset 3298534883328 | ||
200 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
201 | + | ||
202 | +# Close dev | ||
203 | +sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain64-sha384 | ||
204 | +# Read test pattern 0xa7 | ||
205 | +qemu-io -c read -P 0xa7 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha384.img | ||
206 | +read 10485760/10485760 bytes at offset 104857600 | ||
207 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
208 | + | ||
209 | +# Read test pattern 0x13 | ||
210 | +qemu-io -c read -P 0x13 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha384.img | ||
211 | +read 10485760/10485760 bytes at offset 3298534883328 | ||
212 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
213 | + | ||
214 | +# Write test pattern 0x91 | ||
215 | +qemu-io -c write -P 0x91 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha384.img | ||
216 | +wrote 10485760/10485760 bytes at offset 104857600 | ||
217 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
218 | + | ||
219 | +# Write test pattern 0x5e | ||
220 | +qemu-io -c write -P 0x5e 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha384.img | ||
221 | +wrote 10485760/10485760 bytes at offset 3298534883328 | ||
222 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
223 | + | ||
224 | +# Open dev | ||
225 | +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha384.img qiotest-145-aes-256-xts-plain64-sha384 | ||
226 | +# Set dev owner | ||
227 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 | ||
228 | +# Read test pattern 0x91 | ||
229 | +qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 | ||
230 | +read 10485760/10485760 bytes at offset 104857600 | ||
231 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
232 | + | ||
233 | +# Read test pattern 0x5e | ||
234 | +qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 | ||
235 | +read 10485760/10485760 bytes at offset 3298534883328 | ||
236 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
237 | + | ||
238 | +# Close dev | ||
239 | +sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain64-sha384 | ||
240 | +# Delete image | ||
241 | +unlink TEST_DIR/luks-aes-256-xts-plain64-sha384.img | ||
242 | + | ||
243 | +# ================= qemu-img aes-256-xts-plain64-sha384 ================= | ||
244 | +# Create image | ||
245 | +qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha384 TEST_DIR/luks-aes-256-xts-plain64-sha384.img 4194304M | ||
246 | +Formatting 'TEST_DIR/luks-aes-256-xts-plain64-sha384.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha384 iter-time=10 | ||
247 | + | ||
248 | +# Open dev | ||
249 | +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha384.img qiotest-145-aes-256-xts-plain64-sha384 | ||
250 | +# Set dev owner | ||
251 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 | ||
252 | +# Write test pattern 0xa7 | ||
253 | +qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 | ||
254 | +wrote 10485760/10485760 bytes at offset 104857600 | ||
255 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
256 | + | ||
257 | +# Write test pattern 0x13 | ||
258 | +qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 | ||
259 | +wrote 10485760/10485760 bytes at offset 3298534883328 | ||
260 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
261 | + | ||
262 | +# Close dev | ||
263 | +sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain64-sha384 | ||
264 | +# Read test pattern 0xa7 | ||
265 | +qemu-io -c read -P 0xa7 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha384.img | ||
266 | +read 10485760/10485760 bytes at offset 104857600 | ||
267 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
268 | + | ||
269 | +# Read test pattern 0x13 | ||
270 | +qemu-io -c read -P 0x13 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha384.img | ||
271 | +read 10485760/10485760 bytes at offset 3298534883328 | ||
272 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
273 | + | ||
274 | +# Write test pattern 0x91 | ||
275 | +qemu-io -c write -P 0x91 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha384.img | ||
276 | +wrote 10485760/10485760 bytes at offset 104857600 | ||
277 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
278 | + | ||
279 | +# Write test pattern 0x5e | ||
280 | +qemu-io -c write -P 0x5e 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha384.img | ||
281 | +wrote 10485760/10485760 bytes at offset 3298534883328 | ||
282 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
283 | + | ||
284 | +# Open dev | ||
285 | +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha384.img qiotest-145-aes-256-xts-plain64-sha384 | ||
286 | +# Set dev owner | ||
287 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 | ||
288 | +# Read test pattern 0x91 | ||
289 | +qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 | ||
290 | +read 10485760/10485760 bytes at offset 104857600 | ||
291 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
292 | + | ||
293 | +# Read test pattern 0x5e | ||
294 | +qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 | ||
295 | +read 10485760/10485760 bytes at offset 3298534883328 | ||
296 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
297 | + | ||
298 | +# Close dev | ||
299 | +sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain64-sha384 | ||
300 | +# Delete image | ||
301 | +unlink TEST_DIR/luks-aes-256-xts-plain64-sha384.img | ||
302 | + | ||
303 | +# ================= dm-crypt aes-256-xts-plain64-sha512 ================= | ||
304 | +# Create image | ||
305 | +truncate TEST_DIR/luks-aes-256-xts-plain64-sha512.img --size 4194304MB | ||
306 | +# Format image | ||
307 | +sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain64 --key-size 512 --hash sha512 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-xts-plain64-sha512.img | ||
308 | +# Open dev | ||
309 | +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha512.img qiotest-145-aes-256-xts-plain64-sha512 | ||
310 | +# Set dev owner | ||
311 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 | ||
312 | +# Write test pattern 0xa7 | ||
313 | +qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 | ||
314 | +wrote 10485760/10485760 bytes at offset 104857600 | ||
315 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
316 | + | ||
317 | +# Write test pattern 0x13 | ||
318 | +qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 | ||
319 | +wrote 10485760/10485760 bytes at offset 3298534883328 | ||
320 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
321 | + | ||
322 | +# Close dev | ||
323 | +sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain64-sha512 | ||
324 | +# Read test pattern 0xa7 | ||
325 | +qemu-io -c read -P 0xa7 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha512.img | ||
326 | +read 10485760/10485760 bytes at offset 104857600 | ||
327 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
328 | + | ||
329 | +# Read test pattern 0x13 | ||
330 | +qemu-io -c read -P 0x13 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha512.img | ||
331 | +read 10485760/10485760 bytes at offset 3298534883328 | ||
332 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
333 | + | ||
334 | +# Write test pattern 0x91 | ||
335 | +qemu-io -c write -P 0x91 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha512.img | ||
336 | +wrote 10485760/10485760 bytes at offset 104857600 | ||
337 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
338 | + | ||
339 | +# Write test pattern 0x5e | ||
340 | +qemu-io -c write -P 0x5e 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha512.img | ||
341 | +wrote 10485760/10485760 bytes at offset 3298534883328 | ||
342 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
343 | + | ||
344 | +# Open dev | ||
345 | +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha512.img qiotest-145-aes-256-xts-plain64-sha512 | ||
346 | +# Set dev owner | ||
347 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 | ||
348 | +# Read test pattern 0x91 | ||
349 | +qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 | ||
350 | +read 10485760/10485760 bytes at offset 104857600 | ||
351 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
352 | + | ||
353 | +# Read test pattern 0x5e | ||
354 | +qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 | ||
355 | +read 10485760/10485760 bytes at offset 3298534883328 | ||
356 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
357 | + | ||
358 | +# Close dev | ||
359 | +sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain64-sha512 | ||
360 | +# Delete image | ||
361 | +unlink TEST_DIR/luks-aes-256-xts-plain64-sha512.img | ||
362 | + | ||
363 | +# ================= qemu-img aes-256-xts-plain64-sha512 ================= | ||
364 | +# Create image | ||
365 | +qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha512 TEST_DIR/luks-aes-256-xts-plain64-sha512.img 4194304M | ||
366 | +Formatting 'TEST_DIR/luks-aes-256-xts-plain64-sha512.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha512 iter-time=10 | ||
367 | + | ||
368 | +# Open dev | ||
369 | +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha512.img qiotest-145-aes-256-xts-plain64-sha512 | ||
370 | +# Set dev owner | ||
371 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 | ||
372 | +# Write test pattern 0xa7 | ||
373 | +qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 | ||
374 | +wrote 10485760/10485760 bytes at offset 104857600 | ||
375 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
376 | + | ||
377 | +# Write test pattern 0x13 | ||
378 | +qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 | ||
379 | +wrote 10485760/10485760 bytes at offset 3298534883328 | ||
380 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
381 | + | ||
382 | +# Close dev | ||
383 | +sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain64-sha512 | ||
384 | +# Read test pattern 0xa7 | ||
385 | +qemu-io -c read -P 0xa7 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha512.img | ||
386 | +read 10485760/10485760 bytes at offset 104857600 | ||
387 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
388 | + | ||
389 | +# Read test pattern 0x13 | ||
390 | +qemu-io -c read -P 0x13 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha512.img | ||
391 | +read 10485760/10485760 bytes at offset 3298534883328 | ||
392 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
393 | + | ||
394 | +# Write test pattern 0x91 | ||
395 | +qemu-io -c write -P 0x91 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha512.img | ||
396 | +wrote 10485760/10485760 bytes at offset 104857600 | ||
397 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
398 | + | ||
399 | +# Write test pattern 0x5e | ||
400 | +qemu-io -c write -P 0x5e 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha512.img | ||
401 | +wrote 10485760/10485760 bytes at offset 3298534883328 | ||
402 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
403 | + | ||
404 | +# Open dev | ||
405 | +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha512.img qiotest-145-aes-256-xts-plain64-sha512 | ||
406 | +# Set dev owner | ||
407 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 | ||
408 | +# Read test pattern 0x91 | ||
409 | +qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 | ||
410 | +read 10485760/10485760 bytes at offset 104857600 | ||
411 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
412 | + | ||
413 | +# Read test pattern 0x5e | ||
414 | +qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 | ||
415 | +read 10485760/10485760 bytes at offset 3298534883328 | ||
416 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
417 | + | ||
418 | +# Close dev | ||
419 | +sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain64-sha512 | ||
420 | +# Delete image | ||
421 | +unlink TEST_DIR/luks-aes-256-xts-plain64-sha512.img | ||
422 | + | ||
423 | +# ================= dm-crypt aes-256-xts-plain64-ripemd160 ================= | ||
424 | +# Create image | ||
425 | +truncate TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img --size 4194304MB | ||
426 | +# Format image | ||
427 | +sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain64 --key-size 512 --hash ripemd160 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img | ||
428 | +# Open dev | ||
429 | +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img qiotest-145-aes-256-xts-plain64-ripemd160 | ||
430 | +# Set dev owner | ||
431 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 | ||
432 | +# Write test pattern 0xa7 | ||
433 | +qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 | ||
434 | +wrote 10485760/10485760 bytes at offset 104857600 | ||
435 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
436 | + | ||
437 | +# Write test pattern 0x13 | ||
438 | +qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 | ||
439 | +wrote 10485760/10485760 bytes at offset 3298534883328 | ||
440 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
441 | + | ||
442 | +# Close dev | ||
443 | +sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain64-ripemd160 | ||
444 | +# Read test pattern 0xa7 | ||
445 | +qemu-io -c read -P 0xa7 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img | ||
446 | +read 10485760/10485760 bytes at offset 104857600 | ||
447 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
448 | + | ||
449 | +# Read test pattern 0x13 | ||
450 | +qemu-io -c read -P 0x13 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img | ||
451 | +read 10485760/10485760 bytes at offset 3298534883328 | ||
452 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
453 | + | ||
454 | +# Write test pattern 0x91 | ||
455 | +qemu-io -c write -P 0x91 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img | ||
456 | +wrote 10485760/10485760 bytes at offset 104857600 | ||
457 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
458 | + | ||
459 | +# Write test pattern 0x5e | ||
460 | +qemu-io -c write -P 0x5e 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img | ||
461 | +wrote 10485760/10485760 bytes at offset 3298534883328 | ||
462 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
463 | + | ||
464 | +# Open dev | ||
465 | +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img qiotest-145-aes-256-xts-plain64-ripemd160 | ||
466 | +# Set dev owner | ||
467 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 | ||
468 | +# Read test pattern 0x91 | ||
469 | +qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 | ||
470 | +read 10485760/10485760 bytes at offset 104857600 | ||
471 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
472 | + | ||
473 | +# Read test pattern 0x5e | ||
474 | +qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 | ||
475 | +read 10485760/10485760 bytes at offset 3298534883328 | ||
476 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
477 | + | ||
478 | +# Close dev | ||
479 | +sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain64-ripemd160 | ||
480 | +# Delete image | ||
481 | +unlink TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img | ||
482 | + | ||
483 | +# ================= qemu-img aes-256-xts-plain64-ripemd160 ================= | ||
484 | +# Create image | ||
485 | +qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=xts,ivgen-alg=plain64,hash-alg=ripemd160 TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img 4194304M | ||
486 | +Formatting 'TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=xts ivgen-alg=plain64 hash-alg=ripemd160 iter-time=10 | ||
487 | + | ||
488 | +# Open dev | ||
489 | +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img qiotest-145-aes-256-xts-plain64-ripemd160 | ||
490 | +# Set dev owner | ||
491 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 | ||
492 | +# Write test pattern 0xa7 | ||
493 | +qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 | ||
494 | +wrote 10485760/10485760 bytes at offset 104857600 | ||
495 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
496 | + | ||
497 | +# Write test pattern 0x13 | ||
498 | +qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 | ||
499 | +wrote 10485760/10485760 bytes at offset 3298534883328 | ||
500 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
501 | + | ||
502 | +# Close dev | ||
503 | +sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain64-ripemd160 | ||
504 | +# Read test pattern 0xa7 | ||
505 | +qemu-io -c read -P 0xa7 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img | ||
506 | +read 10485760/10485760 bytes at offset 104857600 | ||
507 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
508 | + | ||
509 | +# Read test pattern 0x13 | ||
510 | +qemu-io -c read -P 0x13 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img | ||
511 | +read 10485760/10485760 bytes at offset 3298534883328 | ||
512 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
513 | + | ||
514 | +# Write test pattern 0x91 | ||
515 | +qemu-io -c write -P 0x91 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img | ||
516 | +wrote 10485760/10485760 bytes at offset 104857600 | ||
517 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
518 | + | ||
519 | +# Write test pattern 0x5e | ||
520 | +qemu-io -c write -P 0x5e 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img | ||
521 | +wrote 10485760/10485760 bytes at offset 3298534883328 | ||
522 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
523 | + | ||
524 | +# Open dev | ||
525 | +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img qiotest-145-aes-256-xts-plain64-ripemd160 | ||
526 | +# Set dev owner | ||
527 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 | ||
528 | +# Read test pattern 0x91 | ||
529 | +qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 | ||
530 | +read 10485760/10485760 bytes at offset 104857600 | ||
531 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
532 | + | ||
533 | +# Read test pattern 0x5e | ||
534 | +qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 | ||
535 | +read 10485760/10485760 bytes at offset 3298534883328 | ||
536 | +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
537 | + | ||
538 | +# Close dev | ||
539 | +sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain64-ripemd160 | ||
540 | +# Delete image | ||
541 | +unlink TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img | ||
542 | + | ||
543 | # ================= dm-crypt aes-256-xts-plain-sha1-pwslot3 ================= | ||
544 | # Create image | ||
545 | truncate TEST_DIR/luks-aes-256-xts-plain-sha1-pwslot3.img --size 4194304MB | ||
546 | -- | ||
547 | 1.8.3.1 | ||
548 | |||
549 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: "Daniel P. Berrange" <berrange@redhat.com> | ||
2 | 1 | ||
3 | On some distros, whenever you close a block device file | ||
4 | descriptor there is a udev rule that resets the file | ||
5 | permissions. This can race with the test script when | ||
6 | we run qemu-io multiple times against the same block | ||
7 | device. Occasionally the second qemu-io invocation | ||
8 | will find udev has reset the permissions causing failure. | ||
9 | |||
10 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
11 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
12 | Signed-off-by: Daniel P. Berrange <berrange@redhat.com> | ||
13 | Message-id: 20170626123510.20134-6-berrange@redhat.com | ||
14 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
15 | --- | ||
16 | tests/qemu-iotests/149 | 12 +- | ||
17 | tests/qemu-iotests/149.out | 344 ++++++++++++++++++++++----------------------- | ||
18 | 2 files changed, 177 insertions(+), 179 deletions(-) | ||
19 | |||
20 | diff --git a/tests/qemu-iotests/149 b/tests/qemu-iotests/149 | ||
21 | index XXXXXXX..XXXXXXX 100755 | ||
22 | --- a/tests/qemu-iotests/149 | ||
23 | +++ b/tests/qemu-iotests/149 | ||
24 | @@ -XXX,XX +XXX,XX @@ def chown(config): | ||
25 | msg = proc.communicate()[0] | ||
26 | |||
27 | if proc.returncode != 0: | ||
28 | - raise Exception("Cannot change owner on %s" % path) | ||
29 | + raise Exception(msg) | ||
30 | |||
31 | |||
32 | def cryptsetup_open(config): | ||
33 | @@ -XXX,XX +XXX,XX @@ def qemu_io_image_args(config, dev=False): | ||
34 | def qemu_io_write_pattern(config, pattern, offset_mb, size_mb, dev=False): | ||
35 | """Write a pattern of data to a LUKS image or device""" | ||
36 | |||
37 | + if dev: | ||
38 | + chown(config) | ||
39 | args = ["-c", "write -P 0x%x %dM %dM" % (pattern, offset_mb, size_mb)] | ||
40 | args.extend(qemu_io_image_args(config, dev)) | ||
41 | iotests.log("qemu-io " + " ".join(args), filters=[iotests.filter_test_dir]) | ||
42 | @@ -XXX,XX +XXX,XX @@ def qemu_io_write_pattern(config, pattern, offset_mb, size_mb, dev=False): | ||
43 | def qemu_io_read_pattern(config, pattern, offset_mb, size_mb, dev=False): | ||
44 | """Read a pattern of data to a LUKS image or device""" | ||
45 | |||
46 | + if dev: | ||
47 | + chown(config) | ||
48 | args = ["-c", "read -P 0x%x %dM %dM" % (pattern, offset_mb, size_mb)] | ||
49 | args.extend(qemu_io_image_args(config, dev)) | ||
50 | iotests.log("qemu-io " + " ".join(args), filters=[iotests.filter_test_dir]) | ||
51 | @@ -XXX,XX +XXX,XX @@ def test_once(config, qemu_img=False): | ||
52 | cryptsetup_open(config) | ||
53 | |||
54 | try: | ||
55 | - iotests.log("# Set dev owner") | ||
56 | - chown(config) | ||
57 | - | ||
58 | iotests.log("# Write test pattern 0xa7") | ||
59 | qemu_io_write_pattern(config, 0xa7, lowOffsetMB, 10, dev=True) | ||
60 | iotests.log("# Write test pattern 0x13") | ||
61 | @@ -XXX,XX +XXX,XX @@ def test_once(config, qemu_img=False): | ||
62 | cryptsetup_open(config) | ||
63 | |||
64 | try: | ||
65 | - iotests.log("# Set dev owner") | ||
66 | - chown(config) | ||
67 | - | ||
68 | iotests.log("# Read test pattern 0x91") | ||
69 | qemu_io_read_pattern(config, 0x91, lowOffsetMB, 10, dev=True) | ||
70 | iotests.log("# Read test pattern 0x5e") | ||
71 | diff --git a/tests/qemu-iotests/149.out b/tests/qemu-iotests/149.out | ||
72 | index XXXXXXX..XXXXXXX 100644 | ||
73 | --- a/tests/qemu-iotests/149.out | ||
74 | +++ b/tests/qemu-iotests/149.out | ||
75 | @@ -XXX,XX +XXX,XX @@ truncate TEST_DIR/luks-aes-256-xts-plain64-sha1.img --size 4194304MB | ||
76 | sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain64 --key-size 512 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-xts-plain64-sha1.img | ||
77 | # Open dev | ||
78 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha1.img qiotest-145-aes-256-xts-plain64-sha1 | ||
79 | -# Set dev owner | ||
80 | -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha1 | ||
81 | # Write test pattern 0xa7 | ||
82 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha1 | ||
83 | qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha1 | ||
84 | wrote 10485760/10485760 bytes at offset 104857600 | ||
85 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
86 | |||
87 | # Write test pattern 0x13 | ||
88 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha1 | ||
89 | qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha1 | ||
90 | wrote 10485760/10485760 bytes at offset 3298534883328 | ||
91 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
92 | @@ -XXX,XX +XXX,XX @@ wrote 10485760/10485760 bytes at offset 3298534883328 | ||
93 | |||
94 | # Open dev | ||
95 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha1.img qiotest-145-aes-256-xts-plain64-sha1 | ||
96 | -# Set dev owner | ||
97 | -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha1 | ||
98 | # Read test pattern 0x91 | ||
99 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha1 | ||
100 | qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha1 | ||
101 | read 10485760/10485760 bytes at offset 104857600 | ||
102 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
103 | |||
104 | # Read test pattern 0x5e | ||
105 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha1 | ||
106 | qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha1 | ||
107 | read 10485760/10485760 bytes at offset 3298534883328 | ||
108 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
109 | @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/luks-aes-256-xts-plain64-sha1.img', fmt=luks size=439804651 | ||
110 | |||
111 | # Open dev | ||
112 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha1.img qiotest-145-aes-256-xts-plain64-sha1 | ||
113 | -# Set dev owner | ||
114 | -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha1 | ||
115 | # Write test pattern 0xa7 | ||
116 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha1 | ||
117 | qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha1 | ||
118 | wrote 10485760/10485760 bytes at offset 104857600 | ||
119 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
120 | |||
121 | # Write test pattern 0x13 | ||
122 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha1 | ||
123 | qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha1 | ||
124 | wrote 10485760/10485760 bytes at offset 3298534883328 | ||
125 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
126 | @@ -XXX,XX +XXX,XX @@ wrote 10485760/10485760 bytes at offset 3298534883328 | ||
127 | |||
128 | # Open dev | ||
129 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha1.img qiotest-145-aes-256-xts-plain64-sha1 | ||
130 | -# Set dev owner | ||
131 | -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha1 | ||
132 | # Read test pattern 0x91 | ||
133 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha1 | ||
134 | qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha1 | ||
135 | read 10485760/10485760 bytes at offset 104857600 | ||
136 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
137 | |||
138 | # Read test pattern 0x5e | ||
139 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha1 | ||
140 | qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha1 | ||
141 | read 10485760/10485760 bytes at offset 3298534883328 | ||
142 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
143 | @@ -XXX,XX +XXX,XX @@ truncate TEST_DIR/luks-twofish-256-xts-plain64-sha1.img --size 4194304MB | ||
144 | sudo cryptsetup -q -v luksFormat --cipher twofish-xts-plain64 --key-size 512 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-twofish-256-xts-plain64-sha1.img | ||
145 | # Open dev | ||
146 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-twofish-256-xts-plain64-sha1.img qiotest-145-twofish-256-xts-plain64-sha1 | ||
147 | -# Set dev owner | ||
148 | -sudo chown UID:GID /dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1 | ||
149 | # Write test pattern 0xa7 | ||
150 | +sudo chown UID:GID /dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1 | ||
151 | qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1 | ||
152 | wrote 10485760/10485760 bytes at offset 104857600 | ||
153 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
154 | |||
155 | # Write test pattern 0x13 | ||
156 | +sudo chown UID:GID /dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1 | ||
157 | qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1 | ||
158 | wrote 10485760/10485760 bytes at offset 3298534883328 | ||
159 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
160 | @@ -XXX,XX +XXX,XX @@ wrote 10485760/10485760 bytes at offset 3298534883328 | ||
161 | |||
162 | # Open dev | ||
163 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-twofish-256-xts-plain64-sha1.img qiotest-145-twofish-256-xts-plain64-sha1 | ||
164 | -# Set dev owner | ||
165 | -sudo chown UID:GID /dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1 | ||
166 | # Read test pattern 0x91 | ||
167 | +sudo chown UID:GID /dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1 | ||
168 | qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1 | ||
169 | read 10485760/10485760 bytes at offset 104857600 | ||
170 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
171 | |||
172 | # Read test pattern 0x5e | ||
173 | +sudo chown UID:GID /dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1 | ||
174 | qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1 | ||
175 | read 10485760/10485760 bytes at offset 3298534883328 | ||
176 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
177 | @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/luks-twofish-256-xts-plain64-sha1.img', fmt=luks size=43980 | ||
178 | |||
179 | # Open dev | ||
180 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-twofish-256-xts-plain64-sha1.img qiotest-145-twofish-256-xts-plain64-sha1 | ||
181 | -# Set dev owner | ||
182 | -sudo chown UID:GID /dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1 | ||
183 | # Write test pattern 0xa7 | ||
184 | +sudo chown UID:GID /dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1 | ||
185 | qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1 | ||
186 | wrote 10485760/10485760 bytes at offset 104857600 | ||
187 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
188 | |||
189 | # Write test pattern 0x13 | ||
190 | +sudo chown UID:GID /dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1 | ||
191 | qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1 | ||
192 | wrote 10485760/10485760 bytes at offset 3298534883328 | ||
193 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
194 | @@ -XXX,XX +XXX,XX @@ wrote 10485760/10485760 bytes at offset 3298534883328 | ||
195 | |||
196 | # Open dev | ||
197 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-twofish-256-xts-plain64-sha1.img qiotest-145-twofish-256-xts-plain64-sha1 | ||
198 | -# Set dev owner | ||
199 | -sudo chown UID:GID /dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1 | ||
200 | # Read test pattern 0x91 | ||
201 | +sudo chown UID:GID /dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1 | ||
202 | qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1 | ||
203 | read 10485760/10485760 bytes at offset 104857600 | ||
204 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
205 | |||
206 | # Read test pattern 0x5e | ||
207 | +sudo chown UID:GID /dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1 | ||
208 | qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1 | ||
209 | read 10485760/10485760 bytes at offset 3298534883328 | ||
210 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
211 | @@ -XXX,XX +XXX,XX @@ truncate TEST_DIR/luks-serpent-256-xts-plain64-sha1.img --size 4194304MB | ||
212 | sudo cryptsetup -q -v luksFormat --cipher serpent-xts-plain64 --key-size 512 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-serpent-256-xts-plain64-sha1.img | ||
213 | # Open dev | ||
214 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-256-xts-plain64-sha1.img qiotest-145-serpent-256-xts-plain64-sha1 | ||
215 | -# Set dev owner | ||
216 | -sudo chown UID:GID /dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1 | ||
217 | # Write test pattern 0xa7 | ||
218 | +sudo chown UID:GID /dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1 | ||
219 | qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1 | ||
220 | wrote 10485760/10485760 bytes at offset 104857600 | ||
221 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
222 | |||
223 | # Write test pattern 0x13 | ||
224 | +sudo chown UID:GID /dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1 | ||
225 | qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1 | ||
226 | wrote 10485760/10485760 bytes at offset 3298534883328 | ||
227 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
228 | @@ -XXX,XX +XXX,XX @@ wrote 10485760/10485760 bytes at offset 3298534883328 | ||
229 | |||
230 | # Open dev | ||
231 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-256-xts-plain64-sha1.img qiotest-145-serpent-256-xts-plain64-sha1 | ||
232 | -# Set dev owner | ||
233 | -sudo chown UID:GID /dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1 | ||
234 | # Read test pattern 0x91 | ||
235 | +sudo chown UID:GID /dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1 | ||
236 | qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1 | ||
237 | read 10485760/10485760 bytes at offset 104857600 | ||
238 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
239 | |||
240 | # Read test pattern 0x5e | ||
241 | +sudo chown UID:GID /dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1 | ||
242 | qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1 | ||
243 | read 10485760/10485760 bytes at offset 3298534883328 | ||
244 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
245 | @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/luks-serpent-256-xts-plain64-sha1.img', fmt=luks size=43980 | ||
246 | |||
247 | # Open dev | ||
248 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-256-xts-plain64-sha1.img qiotest-145-serpent-256-xts-plain64-sha1 | ||
249 | -# Set dev owner | ||
250 | -sudo chown UID:GID /dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1 | ||
251 | # Write test pattern 0xa7 | ||
252 | +sudo chown UID:GID /dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1 | ||
253 | qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1 | ||
254 | wrote 10485760/10485760 bytes at offset 104857600 | ||
255 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
256 | |||
257 | # Write test pattern 0x13 | ||
258 | +sudo chown UID:GID /dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1 | ||
259 | qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1 | ||
260 | wrote 10485760/10485760 bytes at offset 3298534883328 | ||
261 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
262 | @@ -XXX,XX +XXX,XX @@ wrote 10485760/10485760 bytes at offset 3298534883328 | ||
263 | |||
264 | # Open dev | ||
265 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-256-xts-plain64-sha1.img qiotest-145-serpent-256-xts-plain64-sha1 | ||
266 | -# Set dev owner | ||
267 | -sudo chown UID:GID /dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1 | ||
268 | # Read test pattern 0x91 | ||
269 | +sudo chown UID:GID /dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1 | ||
270 | qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1 | ||
271 | read 10485760/10485760 bytes at offset 104857600 | ||
272 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
273 | |||
274 | # Read test pattern 0x5e | ||
275 | +sudo chown UID:GID /dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1 | ||
276 | qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1 | ||
277 | read 10485760/10485760 bytes at offset 3298534883328 | ||
278 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
279 | @@ -XXX,XX +XXX,XX @@ truncate TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img --size 4194304MB | ||
280 | sudo cryptsetup -q -v luksFormat --cipher cast5-cbc-plain64 --key-size 128 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img | ||
281 | # Open dev | ||
282 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img qiotest-145-cast5-128-cbc-plain64-sha1 | ||
283 | -# Set dev owner | ||
284 | -sudo chown UID:GID /dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1 | ||
285 | # Write test pattern 0xa7 | ||
286 | +sudo chown UID:GID /dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1 | ||
287 | qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1 | ||
288 | wrote 10485760/10485760 bytes at offset 104857600 | ||
289 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
290 | |||
291 | # Write test pattern 0x13 | ||
292 | +sudo chown UID:GID /dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1 | ||
293 | qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1 | ||
294 | wrote 10485760/10485760 bytes at offset 3298534883328 | ||
295 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
296 | @@ -XXX,XX +XXX,XX @@ wrote 10485760/10485760 bytes at offset 3298534883328 | ||
297 | |||
298 | # Open dev | ||
299 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img qiotest-145-cast5-128-cbc-plain64-sha1 | ||
300 | -# Set dev owner | ||
301 | -sudo chown UID:GID /dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1 | ||
302 | # Read test pattern 0x91 | ||
303 | +sudo chown UID:GID /dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1 | ||
304 | qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1 | ||
305 | read 10485760/10485760 bytes at offset 104857600 | ||
306 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
307 | |||
308 | # Read test pattern 0x5e | ||
309 | +sudo chown UID:GID /dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1 | ||
310 | qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1 | ||
311 | read 10485760/10485760 bytes at offset 3298534883328 | ||
312 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
313 | @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img', fmt=luks size=4398046 | ||
314 | |||
315 | # Open dev | ||
316 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img qiotest-145-cast5-128-cbc-plain64-sha1 | ||
317 | -# Set dev owner | ||
318 | -sudo chown UID:GID /dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1 | ||
319 | # Write test pattern 0xa7 | ||
320 | +sudo chown UID:GID /dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1 | ||
321 | qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1 | ||
322 | wrote 10485760/10485760 bytes at offset 104857600 | ||
323 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
324 | |||
325 | # Write test pattern 0x13 | ||
326 | +sudo chown UID:GID /dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1 | ||
327 | qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1 | ||
328 | wrote 10485760/10485760 bytes at offset 3298534883328 | ||
329 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
330 | @@ -XXX,XX +XXX,XX @@ wrote 10485760/10485760 bytes at offset 3298534883328 | ||
331 | |||
332 | # Open dev | ||
333 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img qiotest-145-cast5-128-cbc-plain64-sha1 | ||
334 | -# Set dev owner | ||
335 | -sudo chown UID:GID /dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1 | ||
336 | # Read test pattern 0x91 | ||
337 | +sudo chown UID:GID /dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1 | ||
338 | qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1 | ||
339 | read 10485760/10485760 bytes at offset 104857600 | ||
340 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
341 | |||
342 | # Read test pattern 0x5e | ||
343 | +sudo chown UID:GID /dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1 | ||
344 | qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1 | ||
345 | read 10485760/10485760 bytes at offset 3298534883328 | ||
346 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
347 | @@ -XXX,XX +XXX,XX @@ truncate TEST_DIR/luks-aes-256-cbc-plain-sha1.img --size 4194304MB | ||
348 | sudo cryptsetup -q -v luksFormat --cipher aes-cbc-plain --key-size 256 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-cbc-plain-sha1.img | ||
349 | # Open dev | ||
350 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-plain-sha1.img qiotest-145-aes-256-cbc-plain-sha1 | ||
351 | -# Set dev owner | ||
352 | -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain-sha1 | ||
353 | # Write test pattern 0xa7 | ||
354 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain-sha1 | ||
355 | qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain-sha1 | ||
356 | wrote 10485760/10485760 bytes at offset 104857600 | ||
357 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
358 | |||
359 | # Write test pattern 0x13 | ||
360 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain-sha1 | ||
361 | qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain-sha1 | ||
362 | wrote 10485760/10485760 bytes at offset 3298534883328 | ||
363 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
364 | @@ -XXX,XX +XXX,XX @@ wrote 10485760/10485760 bytes at offset 3298534883328 | ||
365 | |||
366 | # Open dev | ||
367 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-plain-sha1.img qiotest-145-aes-256-cbc-plain-sha1 | ||
368 | -# Set dev owner | ||
369 | -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain-sha1 | ||
370 | # Read test pattern 0x91 | ||
371 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain-sha1 | ||
372 | qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain-sha1 | ||
373 | read 10485760/10485760 bytes at offset 104857600 | ||
374 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
375 | |||
376 | # Read test pattern 0x5e | ||
377 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain-sha1 | ||
378 | qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain-sha1 | ||
379 | read 10485760/10485760 bytes at offset 3298534883328 | ||
380 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
381 | @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/luks-aes-256-cbc-plain-sha1.img', fmt=luks size=43980465111 | ||
382 | |||
383 | # Open dev | ||
384 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-plain-sha1.img qiotest-145-aes-256-cbc-plain-sha1 | ||
385 | -# Set dev owner | ||
386 | -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain-sha1 | ||
387 | # Write test pattern 0xa7 | ||
388 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain-sha1 | ||
389 | qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain-sha1 | ||
390 | wrote 10485760/10485760 bytes at offset 104857600 | ||
391 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
392 | |||
393 | # Write test pattern 0x13 | ||
394 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain-sha1 | ||
395 | qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain-sha1 | ||
396 | wrote 10485760/10485760 bytes at offset 3298534883328 | ||
397 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
398 | @@ -XXX,XX +XXX,XX @@ wrote 10485760/10485760 bytes at offset 3298534883328 | ||
399 | |||
400 | # Open dev | ||
401 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-plain-sha1.img qiotest-145-aes-256-cbc-plain-sha1 | ||
402 | -# Set dev owner | ||
403 | -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain-sha1 | ||
404 | # Read test pattern 0x91 | ||
405 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain-sha1 | ||
406 | qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain-sha1 | ||
407 | read 10485760/10485760 bytes at offset 104857600 | ||
408 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
409 | |||
410 | # Read test pattern 0x5e | ||
411 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain-sha1 | ||
412 | qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain-sha1 | ||
413 | read 10485760/10485760 bytes at offset 3298534883328 | ||
414 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
415 | @@ -XXX,XX +XXX,XX @@ truncate TEST_DIR/luks-aes-256-cbc-plain64-sha1.img --size 4194304MB | ||
416 | sudo cryptsetup -q -v luksFormat --cipher aes-cbc-plain64 --key-size 256 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-cbc-plain64-sha1.img | ||
417 | # Open dev | ||
418 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-plain64-sha1.img qiotest-145-aes-256-cbc-plain64-sha1 | ||
419 | -# Set dev owner | ||
420 | -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1 | ||
421 | # Write test pattern 0xa7 | ||
422 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1 | ||
423 | qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1 | ||
424 | wrote 10485760/10485760 bytes at offset 104857600 | ||
425 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
426 | |||
427 | # Write test pattern 0x13 | ||
428 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1 | ||
429 | qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1 | ||
430 | wrote 10485760/10485760 bytes at offset 3298534883328 | ||
431 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
432 | @@ -XXX,XX +XXX,XX @@ wrote 10485760/10485760 bytes at offset 3298534883328 | ||
433 | |||
434 | # Open dev | ||
435 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-plain64-sha1.img qiotest-145-aes-256-cbc-plain64-sha1 | ||
436 | -# Set dev owner | ||
437 | -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1 | ||
438 | # Read test pattern 0x91 | ||
439 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1 | ||
440 | qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1 | ||
441 | read 10485760/10485760 bytes at offset 104857600 | ||
442 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
443 | |||
444 | # Read test pattern 0x5e | ||
445 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1 | ||
446 | qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1 | ||
447 | read 10485760/10485760 bytes at offset 3298534883328 | ||
448 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
449 | @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/luks-aes-256-cbc-plain64-sha1.img', fmt=luks size=439804651 | ||
450 | |||
451 | # Open dev | ||
452 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-plain64-sha1.img qiotest-145-aes-256-cbc-plain64-sha1 | ||
453 | -# Set dev owner | ||
454 | -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1 | ||
455 | # Write test pattern 0xa7 | ||
456 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1 | ||
457 | qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1 | ||
458 | wrote 10485760/10485760 bytes at offset 104857600 | ||
459 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
460 | |||
461 | # Write test pattern 0x13 | ||
462 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1 | ||
463 | qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1 | ||
464 | wrote 10485760/10485760 bytes at offset 3298534883328 | ||
465 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
466 | @@ -XXX,XX +XXX,XX @@ wrote 10485760/10485760 bytes at offset 3298534883328 | ||
467 | |||
468 | # Open dev | ||
469 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-plain64-sha1.img qiotest-145-aes-256-cbc-plain64-sha1 | ||
470 | -# Set dev owner | ||
471 | -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1 | ||
472 | # Read test pattern 0x91 | ||
473 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1 | ||
474 | qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1 | ||
475 | read 10485760/10485760 bytes at offset 104857600 | ||
476 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
477 | |||
478 | # Read test pattern 0x5e | ||
479 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1 | ||
480 | qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1 | ||
481 | read 10485760/10485760 bytes at offset 3298534883328 | ||
482 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
483 | @@ -XXX,XX +XXX,XX @@ truncate TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img --size 4194304MB | ||
484 | sudo cryptsetup -q -v luksFormat --cipher aes-cbc-essiv:sha256 --key-size 256 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img | ||
485 | # Open dev | ||
486 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img qiotest-145-aes-256-cbc-essiv-sha256-sha1 | ||
487 | -# Set dev owner | ||
488 | -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1 | ||
489 | # Write test pattern 0xa7 | ||
490 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1 | ||
491 | qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1 | ||
492 | wrote 10485760/10485760 bytes at offset 104857600 | ||
493 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
494 | |||
495 | # Write test pattern 0x13 | ||
496 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1 | ||
497 | qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1 | ||
498 | wrote 10485760/10485760 bytes at offset 3298534883328 | ||
499 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
500 | @@ -XXX,XX +XXX,XX @@ wrote 10485760/10485760 bytes at offset 3298534883328 | ||
501 | |||
502 | # Open dev | ||
503 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img qiotest-145-aes-256-cbc-essiv-sha256-sha1 | ||
504 | -# Set dev owner | ||
505 | -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1 | ||
506 | # Read test pattern 0x91 | ||
507 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1 | ||
508 | qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1 | ||
509 | read 10485760/10485760 bytes at offset 104857600 | ||
510 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
511 | |||
512 | # Read test pattern 0x5e | ||
513 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1 | ||
514 | qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1 | ||
515 | read 10485760/10485760 bytes at offset 3298534883328 | ||
516 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
517 | @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img', fmt=luks size=4398 | ||
518 | |||
519 | # Open dev | ||
520 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img qiotest-145-aes-256-cbc-essiv-sha256-sha1 | ||
521 | -# Set dev owner | ||
522 | -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1 | ||
523 | # Write test pattern 0xa7 | ||
524 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1 | ||
525 | qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1 | ||
526 | wrote 10485760/10485760 bytes at offset 104857600 | ||
527 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
528 | |||
529 | # Write test pattern 0x13 | ||
530 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1 | ||
531 | qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1 | ||
532 | wrote 10485760/10485760 bytes at offset 3298534883328 | ||
533 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
534 | @@ -XXX,XX +XXX,XX @@ wrote 10485760/10485760 bytes at offset 3298534883328 | ||
535 | |||
536 | # Open dev | ||
537 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img qiotest-145-aes-256-cbc-essiv-sha256-sha1 | ||
538 | -# Set dev owner | ||
539 | -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1 | ||
540 | # Read test pattern 0x91 | ||
541 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1 | ||
542 | qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1 | ||
543 | read 10485760/10485760 bytes at offset 104857600 | ||
544 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
545 | |||
546 | # Read test pattern 0x5e | ||
547 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1 | ||
548 | qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1 | ||
549 | read 10485760/10485760 bytes at offset 3298534883328 | ||
550 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
551 | @@ -XXX,XX +XXX,XX @@ truncate TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img --size 4194304MB | ||
552 | sudo cryptsetup -q -v luksFormat --cipher aes-xts-essiv:sha256 --key-size 512 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img | ||
553 | # Open dev | ||
554 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img qiotest-145-aes-256-xts-essiv-sha256-sha1 | ||
555 | -# Set dev owner | ||
556 | -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1 | ||
557 | # Write test pattern 0xa7 | ||
558 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1 | ||
559 | qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1 | ||
560 | wrote 10485760/10485760 bytes at offset 104857600 | ||
561 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
562 | |||
563 | # Write test pattern 0x13 | ||
564 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1 | ||
565 | qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1 | ||
566 | wrote 10485760/10485760 bytes at offset 3298534883328 | ||
567 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
568 | @@ -XXX,XX +XXX,XX @@ wrote 10485760/10485760 bytes at offset 3298534883328 | ||
569 | |||
570 | # Open dev | ||
571 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img qiotest-145-aes-256-xts-essiv-sha256-sha1 | ||
572 | -# Set dev owner | ||
573 | -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1 | ||
574 | # Read test pattern 0x91 | ||
575 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1 | ||
576 | qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1 | ||
577 | read 10485760/10485760 bytes at offset 104857600 | ||
578 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
579 | |||
580 | # Read test pattern 0x5e | ||
581 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1 | ||
582 | qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1 | ||
583 | read 10485760/10485760 bytes at offset 3298534883328 | ||
584 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
585 | @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img', fmt=luks size=4398 | ||
586 | |||
587 | # Open dev | ||
588 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img qiotest-145-aes-256-xts-essiv-sha256-sha1 | ||
589 | -# Set dev owner | ||
590 | -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1 | ||
591 | # Write test pattern 0xa7 | ||
592 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1 | ||
593 | qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1 | ||
594 | wrote 10485760/10485760 bytes at offset 104857600 | ||
595 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
596 | |||
597 | # Write test pattern 0x13 | ||
598 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1 | ||
599 | qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1 | ||
600 | wrote 10485760/10485760 bytes at offset 3298534883328 | ||
601 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
602 | @@ -XXX,XX +XXX,XX @@ wrote 10485760/10485760 bytes at offset 3298534883328 | ||
603 | |||
604 | # Open dev | ||
605 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img qiotest-145-aes-256-xts-essiv-sha256-sha1 | ||
606 | -# Set dev owner | ||
607 | -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1 | ||
608 | # Read test pattern 0x91 | ||
609 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1 | ||
610 | qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1 | ||
611 | read 10485760/10485760 bytes at offset 104857600 | ||
612 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
613 | |||
614 | # Read test pattern 0x5e | ||
615 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1 | ||
616 | qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1 | ||
617 | read 10485760/10485760 bytes at offset 3298534883328 | ||
618 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
619 | @@ -XXX,XX +XXX,XX @@ truncate TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img --size 4194304MB | ||
620 | sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain64 --key-size 256 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img | ||
621 | # Open dev | ||
622 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img qiotest-145-aes-128-xts-plain64-sha256-sha1 | ||
623 | -# Set dev owner | ||
624 | -sudo chown UID:GID /dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1 | ||
625 | # Write test pattern 0xa7 | ||
626 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1 | ||
627 | qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1 | ||
628 | wrote 10485760/10485760 bytes at offset 104857600 | ||
629 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
630 | |||
631 | # Write test pattern 0x13 | ||
632 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1 | ||
633 | qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1 | ||
634 | wrote 10485760/10485760 bytes at offset 3298534883328 | ||
635 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
636 | @@ -XXX,XX +XXX,XX @@ wrote 10485760/10485760 bytes at offset 3298534883328 | ||
637 | |||
638 | # Open dev | ||
639 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img qiotest-145-aes-128-xts-plain64-sha256-sha1 | ||
640 | -# Set dev owner | ||
641 | -sudo chown UID:GID /dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1 | ||
642 | # Read test pattern 0x91 | ||
643 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1 | ||
644 | qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1 | ||
645 | read 10485760/10485760 bytes at offset 104857600 | ||
646 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
647 | |||
648 | # Read test pattern 0x5e | ||
649 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1 | ||
650 | qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1 | ||
651 | read 10485760/10485760 bytes at offset 3298534883328 | ||
652 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
653 | @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img', fmt=luks size=43 | ||
654 | |||
655 | # Open dev | ||
656 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img qiotest-145-aes-128-xts-plain64-sha256-sha1 | ||
657 | -# Set dev owner | ||
658 | -sudo chown UID:GID /dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1 | ||
659 | # Write test pattern 0xa7 | ||
660 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1 | ||
661 | qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1 | ||
662 | wrote 10485760/10485760 bytes at offset 104857600 | ||
663 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
664 | |||
665 | # Write test pattern 0x13 | ||
666 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1 | ||
667 | qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1 | ||
668 | wrote 10485760/10485760 bytes at offset 3298534883328 | ||
669 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
670 | @@ -XXX,XX +XXX,XX @@ wrote 10485760/10485760 bytes at offset 3298534883328 | ||
671 | |||
672 | # Open dev | ||
673 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img qiotest-145-aes-128-xts-plain64-sha256-sha1 | ||
674 | -# Set dev owner | ||
675 | -sudo chown UID:GID /dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1 | ||
676 | # Read test pattern 0x91 | ||
677 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1 | ||
678 | qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1 | ||
679 | read 10485760/10485760 bytes at offset 104857600 | ||
680 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
681 | |||
682 | # Read test pattern 0x5e | ||
683 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1 | ||
684 | qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1 | ||
685 | read 10485760/10485760 bytes at offset 3298534883328 | ||
686 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
687 | @@ -XXX,XX +XXX,XX @@ truncate TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img --size 4194304MB | ||
688 | sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain64 --key-size 384 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img | ||
689 | # Open dev | ||
690 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img qiotest-145-aes-192-xts-plain64-sha256-sha1 | ||
691 | -# Set dev owner | ||
692 | -sudo chown UID:GID /dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1 | ||
693 | # Write test pattern 0xa7 | ||
694 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1 | ||
695 | qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1 | ||
696 | wrote 10485760/10485760 bytes at offset 104857600 | ||
697 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
698 | |||
699 | # Write test pattern 0x13 | ||
700 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1 | ||
701 | qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1 | ||
702 | wrote 10485760/10485760 bytes at offset 3298534883328 | ||
703 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
704 | @@ -XXX,XX +XXX,XX @@ wrote 10485760/10485760 bytes at offset 3298534883328 | ||
705 | |||
706 | # Open dev | ||
707 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img qiotest-145-aes-192-xts-plain64-sha256-sha1 | ||
708 | -# Set dev owner | ||
709 | -sudo chown UID:GID /dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1 | ||
710 | # Read test pattern 0x91 | ||
711 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1 | ||
712 | qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1 | ||
713 | read 10485760/10485760 bytes at offset 104857600 | ||
714 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
715 | |||
716 | # Read test pattern 0x5e | ||
717 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1 | ||
718 | qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1 | ||
719 | read 10485760/10485760 bytes at offset 3298534883328 | ||
720 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
721 | @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img', fmt=luks size=43 | ||
722 | |||
723 | # Open dev | ||
724 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img qiotest-145-aes-192-xts-plain64-sha256-sha1 | ||
725 | -# Set dev owner | ||
726 | -sudo chown UID:GID /dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1 | ||
727 | # Write test pattern 0xa7 | ||
728 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1 | ||
729 | qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1 | ||
730 | wrote 10485760/10485760 bytes at offset 104857600 | ||
731 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
732 | |||
733 | # Write test pattern 0x13 | ||
734 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1 | ||
735 | qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1 | ||
736 | wrote 10485760/10485760 bytes at offset 3298534883328 | ||
737 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
738 | @@ -XXX,XX +XXX,XX @@ wrote 10485760/10485760 bytes at offset 3298534883328 | ||
739 | |||
740 | # Open dev | ||
741 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img qiotest-145-aes-192-xts-plain64-sha256-sha1 | ||
742 | -# Set dev owner | ||
743 | -sudo chown UID:GID /dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1 | ||
744 | # Read test pattern 0x91 | ||
745 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1 | ||
746 | qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1 | ||
747 | read 10485760/10485760 bytes at offset 104857600 | ||
748 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
749 | |||
750 | # Read test pattern 0x5e | ||
751 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1 | ||
752 | qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1 | ||
753 | read 10485760/10485760 bytes at offset 3298534883328 | ||
754 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
755 | @@ -XXX,XX +XXX,XX @@ truncate TEST_DIR/luks-twofish-128-xts-plain64-sha1.img --size 4194304MB | ||
756 | sudo cryptsetup -q -v luksFormat --cipher twofish-xts-plain64 --key-size 256 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-twofish-128-xts-plain64-sha1.img | ||
757 | # Open dev | ||
758 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-twofish-128-xts-plain64-sha1.img qiotest-145-twofish-128-xts-plain64-sha1 | ||
759 | -# Set dev owner | ||
760 | -sudo chown UID:GID /dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1 | ||
761 | # Write test pattern 0xa7 | ||
762 | +sudo chown UID:GID /dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1 | ||
763 | qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1 | ||
764 | wrote 10485760/10485760 bytes at offset 104857600 | ||
765 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
766 | |||
767 | # Write test pattern 0x13 | ||
768 | +sudo chown UID:GID /dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1 | ||
769 | qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1 | ||
770 | wrote 10485760/10485760 bytes at offset 3298534883328 | ||
771 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
772 | @@ -XXX,XX +XXX,XX @@ wrote 10485760/10485760 bytes at offset 3298534883328 | ||
773 | |||
774 | # Open dev | ||
775 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-twofish-128-xts-plain64-sha1.img qiotest-145-twofish-128-xts-plain64-sha1 | ||
776 | -# Set dev owner | ||
777 | -sudo chown UID:GID /dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1 | ||
778 | # Read test pattern 0x91 | ||
779 | +sudo chown UID:GID /dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1 | ||
780 | qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1 | ||
781 | read 10485760/10485760 bytes at offset 104857600 | ||
782 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
783 | |||
784 | # Read test pattern 0x5e | ||
785 | +sudo chown UID:GID /dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1 | ||
786 | qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1 | ||
787 | read 10485760/10485760 bytes at offset 3298534883328 | ||
788 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
789 | @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/luks-twofish-128-xts-plain64-sha1.img', fmt=luks size=43980 | ||
790 | |||
791 | # Open dev | ||
792 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-twofish-128-xts-plain64-sha1.img qiotest-145-twofish-128-xts-plain64-sha1 | ||
793 | -# Set dev owner | ||
794 | -sudo chown UID:GID /dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1 | ||
795 | # Write test pattern 0xa7 | ||
796 | +sudo chown UID:GID /dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1 | ||
797 | qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1 | ||
798 | wrote 10485760/10485760 bytes at offset 104857600 | ||
799 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
800 | |||
801 | # Write test pattern 0x13 | ||
802 | +sudo chown UID:GID /dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1 | ||
803 | qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1 | ||
804 | wrote 10485760/10485760 bytes at offset 3298534883328 | ||
805 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
806 | @@ -XXX,XX +XXX,XX @@ wrote 10485760/10485760 bytes at offset 3298534883328 | ||
807 | |||
808 | # Open dev | ||
809 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-twofish-128-xts-plain64-sha1.img qiotest-145-twofish-128-xts-plain64-sha1 | ||
810 | -# Set dev owner | ||
811 | -sudo chown UID:GID /dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1 | ||
812 | # Read test pattern 0x91 | ||
813 | +sudo chown UID:GID /dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1 | ||
814 | qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1 | ||
815 | read 10485760/10485760 bytes at offset 104857600 | ||
816 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
817 | |||
818 | # Read test pattern 0x5e | ||
819 | +sudo chown UID:GID /dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1 | ||
820 | qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1 | ||
821 | read 10485760/10485760 bytes at offset 3298534883328 | ||
822 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
823 | @@ -XXX,XX +XXX,XX @@ truncate TEST_DIR/luks-serpent-128-xts-plain64-sha1.img --size 4194304MB | ||
824 | sudo cryptsetup -q -v luksFormat --cipher serpent-xts-plain64 --key-size 256 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-serpent-128-xts-plain64-sha1.img | ||
825 | # Open dev | ||
826 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-128-xts-plain64-sha1.img qiotest-145-serpent-128-xts-plain64-sha1 | ||
827 | -# Set dev owner | ||
828 | -sudo chown UID:GID /dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1 | ||
829 | # Write test pattern 0xa7 | ||
830 | +sudo chown UID:GID /dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1 | ||
831 | qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1 | ||
832 | wrote 10485760/10485760 bytes at offset 104857600 | ||
833 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
834 | |||
835 | # Write test pattern 0x13 | ||
836 | +sudo chown UID:GID /dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1 | ||
837 | qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1 | ||
838 | wrote 10485760/10485760 bytes at offset 3298534883328 | ||
839 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
840 | @@ -XXX,XX +XXX,XX @@ wrote 10485760/10485760 bytes at offset 3298534883328 | ||
841 | |||
842 | # Open dev | ||
843 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-128-xts-plain64-sha1.img qiotest-145-serpent-128-xts-plain64-sha1 | ||
844 | -# Set dev owner | ||
845 | -sudo chown UID:GID /dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1 | ||
846 | # Read test pattern 0x91 | ||
847 | +sudo chown UID:GID /dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1 | ||
848 | qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1 | ||
849 | read 10485760/10485760 bytes at offset 104857600 | ||
850 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
851 | |||
852 | # Read test pattern 0x5e | ||
853 | +sudo chown UID:GID /dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1 | ||
854 | qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1 | ||
855 | read 10485760/10485760 bytes at offset 3298534883328 | ||
856 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
857 | @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/luks-serpent-128-xts-plain64-sha1.img', fmt=luks size=43980 | ||
858 | |||
859 | # Open dev | ||
860 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-128-xts-plain64-sha1.img qiotest-145-serpent-128-xts-plain64-sha1 | ||
861 | -# Set dev owner | ||
862 | -sudo chown UID:GID /dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1 | ||
863 | # Write test pattern 0xa7 | ||
864 | +sudo chown UID:GID /dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1 | ||
865 | qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1 | ||
866 | wrote 10485760/10485760 bytes at offset 104857600 | ||
867 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
868 | |||
869 | # Write test pattern 0x13 | ||
870 | +sudo chown UID:GID /dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1 | ||
871 | qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1 | ||
872 | wrote 10485760/10485760 bytes at offset 3298534883328 | ||
873 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
874 | @@ -XXX,XX +XXX,XX @@ wrote 10485760/10485760 bytes at offset 3298534883328 | ||
875 | |||
876 | # Open dev | ||
877 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-128-xts-plain64-sha1.img qiotest-145-serpent-128-xts-plain64-sha1 | ||
878 | -# Set dev owner | ||
879 | -sudo chown UID:GID /dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1 | ||
880 | # Read test pattern 0x91 | ||
881 | +sudo chown UID:GID /dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1 | ||
882 | qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1 | ||
883 | read 10485760/10485760 bytes at offset 104857600 | ||
884 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
885 | |||
886 | # Read test pattern 0x5e | ||
887 | +sudo chown UID:GID /dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1 | ||
888 | qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1 | ||
889 | read 10485760/10485760 bytes at offset 3298534883328 | ||
890 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
891 | @@ -XXX,XX +XXX,XX @@ truncate TEST_DIR/luks-serpent-192-xts-plain64-sha1.img --size 4194304MB | ||
892 | sudo cryptsetup -q -v luksFormat --cipher serpent-xts-plain64 --key-size 384 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-serpent-192-xts-plain64-sha1.img | ||
893 | # Open dev | ||
894 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-192-xts-plain64-sha1.img qiotest-145-serpent-192-xts-plain64-sha1 | ||
895 | -# Set dev owner | ||
896 | -sudo chown UID:GID /dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1 | ||
897 | # Write test pattern 0xa7 | ||
898 | +sudo chown UID:GID /dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1 | ||
899 | qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1 | ||
900 | wrote 10485760/10485760 bytes at offset 104857600 | ||
901 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
902 | |||
903 | # Write test pattern 0x13 | ||
904 | +sudo chown UID:GID /dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1 | ||
905 | qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1 | ||
906 | wrote 10485760/10485760 bytes at offset 3298534883328 | ||
907 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
908 | @@ -XXX,XX +XXX,XX @@ wrote 10485760/10485760 bytes at offset 3298534883328 | ||
909 | |||
910 | # Open dev | ||
911 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-192-xts-plain64-sha1.img qiotest-145-serpent-192-xts-plain64-sha1 | ||
912 | -# Set dev owner | ||
913 | -sudo chown UID:GID /dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1 | ||
914 | # Read test pattern 0x91 | ||
915 | +sudo chown UID:GID /dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1 | ||
916 | qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1 | ||
917 | read 10485760/10485760 bytes at offset 104857600 | ||
918 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
919 | |||
920 | # Read test pattern 0x5e | ||
921 | +sudo chown UID:GID /dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1 | ||
922 | qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1 | ||
923 | read 10485760/10485760 bytes at offset 3298534883328 | ||
924 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
925 | @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/luks-serpent-192-xts-plain64-sha1.img', fmt=luks size=43980 | ||
926 | |||
927 | # Open dev | ||
928 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-192-xts-plain64-sha1.img qiotest-145-serpent-192-xts-plain64-sha1 | ||
929 | -# Set dev owner | ||
930 | -sudo chown UID:GID /dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1 | ||
931 | # Write test pattern 0xa7 | ||
932 | +sudo chown UID:GID /dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1 | ||
933 | qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1 | ||
934 | wrote 10485760/10485760 bytes at offset 104857600 | ||
935 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
936 | |||
937 | # Write test pattern 0x13 | ||
938 | +sudo chown UID:GID /dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1 | ||
939 | qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1 | ||
940 | wrote 10485760/10485760 bytes at offset 3298534883328 | ||
941 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
942 | @@ -XXX,XX +XXX,XX @@ wrote 10485760/10485760 bytes at offset 3298534883328 | ||
943 | |||
944 | # Open dev | ||
945 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-192-xts-plain64-sha1.img qiotest-145-serpent-192-xts-plain64-sha1 | ||
946 | -# Set dev owner | ||
947 | -sudo chown UID:GID /dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1 | ||
948 | # Read test pattern 0x91 | ||
949 | +sudo chown UID:GID /dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1 | ||
950 | qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1 | ||
951 | read 10485760/10485760 bytes at offset 104857600 | ||
952 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
953 | |||
954 | # Read test pattern 0x5e | ||
955 | +sudo chown UID:GID /dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1 | ||
956 | qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1 | ||
957 | read 10485760/10485760 bytes at offset 3298534883328 | ||
958 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
959 | @@ -XXX,XX +XXX,XX @@ truncate TEST_DIR/luks-aes-256-xts-plain64-sha224.img --size 4194304MB | ||
960 | sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain64 --key-size 512 --hash sha224 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-xts-plain64-sha224.img | ||
961 | # Open dev | ||
962 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha224.img qiotest-145-aes-256-xts-plain64-sha224 | ||
963 | -# Set dev owner | ||
964 | -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 | ||
965 | # Write test pattern 0xa7 | ||
966 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 | ||
967 | qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 | ||
968 | wrote 10485760/10485760 bytes at offset 104857600 | ||
969 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
970 | |||
971 | # Write test pattern 0x13 | ||
972 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 | ||
973 | qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 | ||
974 | wrote 10485760/10485760 bytes at offset 3298534883328 | ||
975 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
976 | @@ -XXX,XX +XXX,XX @@ wrote 10485760/10485760 bytes at offset 3298534883328 | ||
977 | |||
978 | # Open dev | ||
979 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha224.img qiotest-145-aes-256-xts-plain64-sha224 | ||
980 | -# Set dev owner | ||
981 | -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 | ||
982 | # Read test pattern 0x91 | ||
983 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 | ||
984 | qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 | ||
985 | read 10485760/10485760 bytes at offset 104857600 | ||
986 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
987 | |||
988 | # Read test pattern 0x5e | ||
989 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 | ||
990 | qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 | ||
991 | read 10485760/10485760 bytes at offset 3298534883328 | ||
992 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
993 | @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/luks-aes-256-xts-plain64-sha224.img', fmt=luks size=4398046 | ||
994 | |||
995 | # Open dev | ||
996 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha224.img qiotest-145-aes-256-xts-plain64-sha224 | ||
997 | -# Set dev owner | ||
998 | -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 | ||
999 | # Write test pattern 0xa7 | ||
1000 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 | ||
1001 | qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 | ||
1002 | wrote 10485760/10485760 bytes at offset 104857600 | ||
1003 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1004 | |||
1005 | # Write test pattern 0x13 | ||
1006 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 | ||
1007 | qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 | ||
1008 | wrote 10485760/10485760 bytes at offset 3298534883328 | ||
1009 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1010 | @@ -XXX,XX +XXX,XX @@ wrote 10485760/10485760 bytes at offset 3298534883328 | ||
1011 | |||
1012 | # Open dev | ||
1013 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha224.img qiotest-145-aes-256-xts-plain64-sha224 | ||
1014 | -# Set dev owner | ||
1015 | -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 | ||
1016 | # Read test pattern 0x91 | ||
1017 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 | ||
1018 | qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 | ||
1019 | read 10485760/10485760 bytes at offset 104857600 | ||
1020 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1021 | |||
1022 | # Read test pattern 0x5e | ||
1023 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 | ||
1024 | qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 | ||
1025 | read 10485760/10485760 bytes at offset 3298534883328 | ||
1026 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1027 | @@ -XXX,XX +XXX,XX @@ truncate TEST_DIR/luks-aes-256-xts-plain64-sha256.img --size 4194304MB | ||
1028 | sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain64 --key-size 512 --hash sha256 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-xts-plain64-sha256.img | ||
1029 | # Open dev | ||
1030 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha256.img qiotest-145-aes-256-xts-plain64-sha256 | ||
1031 | -# Set dev owner | ||
1032 | -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha256 | ||
1033 | # Write test pattern 0xa7 | ||
1034 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha256 | ||
1035 | qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha256 | ||
1036 | wrote 10485760/10485760 bytes at offset 104857600 | ||
1037 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1038 | |||
1039 | # Write test pattern 0x13 | ||
1040 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha256 | ||
1041 | qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha256 | ||
1042 | wrote 10485760/10485760 bytes at offset 3298534883328 | ||
1043 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1044 | @@ -XXX,XX +XXX,XX @@ wrote 10485760/10485760 bytes at offset 3298534883328 | ||
1045 | |||
1046 | # Open dev | ||
1047 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha256.img qiotest-145-aes-256-xts-plain64-sha256 | ||
1048 | -# Set dev owner | ||
1049 | -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha256 | ||
1050 | # Read test pattern 0x91 | ||
1051 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha256 | ||
1052 | qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha256 | ||
1053 | read 10485760/10485760 bytes at offset 104857600 | ||
1054 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1055 | |||
1056 | # Read test pattern 0x5e | ||
1057 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha256 | ||
1058 | qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha256 | ||
1059 | read 10485760/10485760 bytes at offset 3298534883328 | ||
1060 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1061 | @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/luks-aes-256-xts-plain64-sha256.img', fmt=luks size=4398046 | ||
1062 | |||
1063 | # Open dev | ||
1064 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha256.img qiotest-145-aes-256-xts-plain64-sha256 | ||
1065 | -# Set dev owner | ||
1066 | -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha256 | ||
1067 | # Write test pattern 0xa7 | ||
1068 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha256 | ||
1069 | qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha256 | ||
1070 | wrote 10485760/10485760 bytes at offset 104857600 | ||
1071 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1072 | |||
1073 | # Write test pattern 0x13 | ||
1074 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha256 | ||
1075 | qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha256 | ||
1076 | wrote 10485760/10485760 bytes at offset 3298534883328 | ||
1077 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1078 | @@ -XXX,XX +XXX,XX @@ wrote 10485760/10485760 bytes at offset 3298534883328 | ||
1079 | |||
1080 | # Open dev | ||
1081 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha256.img qiotest-145-aes-256-xts-plain64-sha256 | ||
1082 | -# Set dev owner | ||
1083 | -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha256 | ||
1084 | # Read test pattern 0x91 | ||
1085 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha256 | ||
1086 | qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha256 | ||
1087 | read 10485760/10485760 bytes at offset 104857600 | ||
1088 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1089 | |||
1090 | # Read test pattern 0x5e | ||
1091 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha256 | ||
1092 | qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha256 | ||
1093 | read 10485760/10485760 bytes at offset 3298534883328 | ||
1094 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1095 | @@ -XXX,XX +XXX,XX @@ truncate TEST_DIR/luks-aes-256-xts-plain64-sha384.img --size 4194304MB | ||
1096 | sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain64 --key-size 512 --hash sha384 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-xts-plain64-sha384.img | ||
1097 | # Open dev | ||
1098 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha384.img qiotest-145-aes-256-xts-plain64-sha384 | ||
1099 | -# Set dev owner | ||
1100 | -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 | ||
1101 | # Write test pattern 0xa7 | ||
1102 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 | ||
1103 | qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 | ||
1104 | wrote 10485760/10485760 bytes at offset 104857600 | ||
1105 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1106 | |||
1107 | # Write test pattern 0x13 | ||
1108 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 | ||
1109 | qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 | ||
1110 | wrote 10485760/10485760 bytes at offset 3298534883328 | ||
1111 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1112 | @@ -XXX,XX +XXX,XX @@ wrote 10485760/10485760 bytes at offset 3298534883328 | ||
1113 | |||
1114 | # Open dev | ||
1115 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha384.img qiotest-145-aes-256-xts-plain64-sha384 | ||
1116 | -# Set dev owner | ||
1117 | -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 | ||
1118 | # Read test pattern 0x91 | ||
1119 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 | ||
1120 | qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 | ||
1121 | read 10485760/10485760 bytes at offset 104857600 | ||
1122 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1123 | |||
1124 | # Read test pattern 0x5e | ||
1125 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 | ||
1126 | qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 | ||
1127 | read 10485760/10485760 bytes at offset 3298534883328 | ||
1128 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1129 | @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/luks-aes-256-xts-plain64-sha384.img', fmt=luks size=4398046 | ||
1130 | |||
1131 | # Open dev | ||
1132 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha384.img qiotest-145-aes-256-xts-plain64-sha384 | ||
1133 | -# Set dev owner | ||
1134 | -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 | ||
1135 | # Write test pattern 0xa7 | ||
1136 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 | ||
1137 | qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 | ||
1138 | wrote 10485760/10485760 bytes at offset 104857600 | ||
1139 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1140 | |||
1141 | # Write test pattern 0x13 | ||
1142 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 | ||
1143 | qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 | ||
1144 | wrote 10485760/10485760 bytes at offset 3298534883328 | ||
1145 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1146 | @@ -XXX,XX +XXX,XX @@ wrote 10485760/10485760 bytes at offset 3298534883328 | ||
1147 | |||
1148 | # Open dev | ||
1149 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha384.img qiotest-145-aes-256-xts-plain64-sha384 | ||
1150 | -# Set dev owner | ||
1151 | -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 | ||
1152 | # Read test pattern 0x91 | ||
1153 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 | ||
1154 | qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 | ||
1155 | read 10485760/10485760 bytes at offset 104857600 | ||
1156 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1157 | |||
1158 | # Read test pattern 0x5e | ||
1159 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 | ||
1160 | qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 | ||
1161 | read 10485760/10485760 bytes at offset 3298534883328 | ||
1162 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1163 | @@ -XXX,XX +XXX,XX @@ truncate TEST_DIR/luks-aes-256-xts-plain64-sha512.img --size 4194304MB | ||
1164 | sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain64 --key-size 512 --hash sha512 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-xts-plain64-sha512.img | ||
1165 | # Open dev | ||
1166 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha512.img qiotest-145-aes-256-xts-plain64-sha512 | ||
1167 | -# Set dev owner | ||
1168 | -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 | ||
1169 | # Write test pattern 0xa7 | ||
1170 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 | ||
1171 | qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 | ||
1172 | wrote 10485760/10485760 bytes at offset 104857600 | ||
1173 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1174 | |||
1175 | # Write test pattern 0x13 | ||
1176 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 | ||
1177 | qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 | ||
1178 | wrote 10485760/10485760 bytes at offset 3298534883328 | ||
1179 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1180 | @@ -XXX,XX +XXX,XX @@ wrote 10485760/10485760 bytes at offset 3298534883328 | ||
1181 | |||
1182 | # Open dev | ||
1183 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha512.img qiotest-145-aes-256-xts-plain64-sha512 | ||
1184 | -# Set dev owner | ||
1185 | -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 | ||
1186 | # Read test pattern 0x91 | ||
1187 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 | ||
1188 | qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 | ||
1189 | read 10485760/10485760 bytes at offset 104857600 | ||
1190 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1191 | |||
1192 | # Read test pattern 0x5e | ||
1193 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 | ||
1194 | qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 | ||
1195 | read 10485760/10485760 bytes at offset 3298534883328 | ||
1196 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1197 | @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/luks-aes-256-xts-plain64-sha512.img', fmt=luks size=4398046 | ||
1198 | |||
1199 | # Open dev | ||
1200 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha512.img qiotest-145-aes-256-xts-plain64-sha512 | ||
1201 | -# Set dev owner | ||
1202 | -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 | ||
1203 | # Write test pattern 0xa7 | ||
1204 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 | ||
1205 | qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 | ||
1206 | wrote 10485760/10485760 bytes at offset 104857600 | ||
1207 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1208 | |||
1209 | # Write test pattern 0x13 | ||
1210 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 | ||
1211 | qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 | ||
1212 | wrote 10485760/10485760 bytes at offset 3298534883328 | ||
1213 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1214 | @@ -XXX,XX +XXX,XX @@ wrote 10485760/10485760 bytes at offset 3298534883328 | ||
1215 | |||
1216 | # Open dev | ||
1217 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha512.img qiotest-145-aes-256-xts-plain64-sha512 | ||
1218 | -# Set dev owner | ||
1219 | -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 | ||
1220 | # Read test pattern 0x91 | ||
1221 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 | ||
1222 | qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 | ||
1223 | read 10485760/10485760 bytes at offset 104857600 | ||
1224 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1225 | |||
1226 | # Read test pattern 0x5e | ||
1227 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 | ||
1228 | qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 | ||
1229 | read 10485760/10485760 bytes at offset 3298534883328 | ||
1230 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1231 | @@ -XXX,XX +XXX,XX @@ truncate TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img --size 4194304MB | ||
1232 | sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain64 --key-size 512 --hash ripemd160 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img | ||
1233 | # Open dev | ||
1234 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img qiotest-145-aes-256-xts-plain64-ripemd160 | ||
1235 | -# Set dev owner | ||
1236 | -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 | ||
1237 | # Write test pattern 0xa7 | ||
1238 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 | ||
1239 | qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 | ||
1240 | wrote 10485760/10485760 bytes at offset 104857600 | ||
1241 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1242 | |||
1243 | # Write test pattern 0x13 | ||
1244 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 | ||
1245 | qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 | ||
1246 | wrote 10485760/10485760 bytes at offset 3298534883328 | ||
1247 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1248 | @@ -XXX,XX +XXX,XX @@ wrote 10485760/10485760 bytes at offset 3298534883328 | ||
1249 | |||
1250 | # Open dev | ||
1251 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img qiotest-145-aes-256-xts-plain64-ripemd160 | ||
1252 | -# Set dev owner | ||
1253 | -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 | ||
1254 | # Read test pattern 0x91 | ||
1255 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 | ||
1256 | qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 | ||
1257 | read 10485760/10485760 bytes at offset 104857600 | ||
1258 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1259 | |||
1260 | # Read test pattern 0x5e | ||
1261 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 | ||
1262 | qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 | ||
1263 | read 10485760/10485760 bytes at offset 3298534883328 | ||
1264 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1265 | @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img', fmt=luks size=4398 | ||
1266 | |||
1267 | # Open dev | ||
1268 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img qiotest-145-aes-256-xts-plain64-ripemd160 | ||
1269 | -# Set dev owner | ||
1270 | -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 | ||
1271 | # Write test pattern 0xa7 | ||
1272 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 | ||
1273 | qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 | ||
1274 | wrote 10485760/10485760 bytes at offset 104857600 | ||
1275 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1276 | |||
1277 | # Write test pattern 0x13 | ||
1278 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 | ||
1279 | qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 | ||
1280 | wrote 10485760/10485760 bytes at offset 3298534883328 | ||
1281 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1282 | @@ -XXX,XX +XXX,XX @@ wrote 10485760/10485760 bytes at offset 3298534883328 | ||
1283 | |||
1284 | # Open dev | ||
1285 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img qiotest-145-aes-256-xts-plain64-ripemd160 | ||
1286 | -# Set dev owner | ||
1287 | -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 | ||
1288 | # Read test pattern 0x91 | ||
1289 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 | ||
1290 | qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 | ||
1291 | read 10485760/10485760 bytes at offset 104857600 | ||
1292 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1293 | |||
1294 | # Read test pattern 0x5e | ||
1295 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 | ||
1296 | qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 | ||
1297 | read 10485760/10485760 bytes at offset 3298534883328 | ||
1298 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1299 | @@ -XXX,XX +XXX,XX @@ truncate TEST_DIR/luks-aes-256-xts-plain-sha1-pwslot3.img --size 4194304MB | ||
1300 | sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain --key-size 512 --hash sha1 --key-slot 3 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-xts-plain-sha1-pwslot3.img | ||
1301 | # Open dev | ||
1302 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain-sha1-pwslot3.img qiotest-145-aes-256-xts-plain-sha1-pwslot3 | ||
1303 | -# Set dev owner | ||
1304 | -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwslot3 | ||
1305 | # Write test pattern 0xa7 | ||
1306 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwslot3 | ||
1307 | qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwslot3 | ||
1308 | wrote 10485760/10485760 bytes at offset 104857600 | ||
1309 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1310 | |||
1311 | # Write test pattern 0x13 | ||
1312 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwslot3 | ||
1313 | qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwslot3 | ||
1314 | wrote 10485760/10485760 bytes at offset 3298534883328 | ||
1315 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1316 | @@ -XXX,XX +XXX,XX @@ wrote 10485760/10485760 bytes at offset 3298534883328 | ||
1317 | |||
1318 | # Open dev | ||
1319 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain-sha1-pwslot3.img qiotest-145-aes-256-xts-plain-sha1-pwslot3 | ||
1320 | -# Set dev owner | ||
1321 | -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwslot3 | ||
1322 | # Read test pattern 0x91 | ||
1323 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwslot3 | ||
1324 | qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwslot3 | ||
1325 | read 10485760/10485760 bytes at offset 104857600 | ||
1326 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1327 | |||
1328 | # Read test pattern 0x5e | ||
1329 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwslot3 | ||
1330 | qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwslot3 | ||
1331 | read 10485760/10485760 bytes at offset 3298534883328 | ||
1332 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1333 | @@ -XXX,XX +XXX,XX @@ sudo cryptsetup -q -v luksAddKey TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots | ||
1334 | sudo cryptsetup -q -v luksAddKey TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img --key-slot 7 --key-file - --iter-time 10 TEST_DIR/passwd.txt | ||
1335 | # Open dev | ||
1336 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img qiotest-145-aes-256-xts-plain-sha1-pwallslots | ||
1337 | -# Set dev owner | ||
1338 | -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots | ||
1339 | # Write test pattern 0xa7 | ||
1340 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots | ||
1341 | qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots | ||
1342 | wrote 10485760/10485760 bytes at offset 104857600 | ||
1343 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1344 | |||
1345 | # Write test pattern 0x13 | ||
1346 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots | ||
1347 | qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots | ||
1348 | wrote 10485760/10485760 bytes at offset 3298534883328 | ||
1349 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1350 | @@ -XXX,XX +XXX,XX @@ wrote 10485760/10485760 bytes at offset 3298534883328 | ||
1351 | |||
1352 | # Open dev | ||
1353 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img qiotest-145-aes-256-xts-plain-sha1-pwallslots | ||
1354 | -# Set dev owner | ||
1355 | -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots | ||
1356 | # Read test pattern 0x91 | ||
1357 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots | ||
1358 | qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots | ||
1359 | read 10485760/10485760 bytes at offset 104857600 | ||
1360 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1361 | |||
1362 | # Read test pattern 0x5e | ||
1363 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots | ||
1364 | qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots | ||
1365 | read 10485760/10485760 bytes at offset 3298534883328 | ||
1366 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1367 | @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img', fmt=luks size= | ||
1368 | |||
1369 | # Open dev | ||
1370 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img qiotest-145-aes-256-xts-plain-sha1-pwallslots | ||
1371 | -# Set dev owner | ||
1372 | -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots | ||
1373 | # Write test pattern 0xa7 | ||
1374 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots | ||
1375 | qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots | ||
1376 | wrote 10485760/10485760 bytes at offset 104857600 | ||
1377 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1378 | |||
1379 | # Write test pattern 0x13 | ||
1380 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots | ||
1381 | qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots | ||
1382 | wrote 10485760/10485760 bytes at offset 3298534883328 | ||
1383 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1384 | @@ -XXX,XX +XXX,XX @@ wrote 10485760/10485760 bytes at offset 3298534883328 | ||
1385 | |||
1386 | # Open dev | ||
1387 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img qiotest-145-aes-256-xts-plain-sha1-pwallslots | ||
1388 | -# Set dev owner | ||
1389 | -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots | ||
1390 | # Read test pattern 0x91 | ||
1391 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots | ||
1392 | qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots | ||
1393 | read 10485760/10485760 bytes at offset 104857600 | ||
1394 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1395 | |||
1396 | # Read test pattern 0x5e | ||
1397 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots | ||
1398 | qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots | ||
1399 | read 10485760/10485760 bytes at offset 3298534883328 | ||
1400 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1401 | @@ -XXX,XX +XXX,XX @@ truncate TEST_DIR/luks-aes-256-cbc-essiv-auto-sha1.img --size 4194304MB | ||
1402 | sudo cryptsetup -q -v luksFormat --cipher aes-cbc-essiv:sha256 --key-size 256 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-cbc-essiv-auto-sha1.img | ||
1403 | # Open dev | ||
1404 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-essiv-auto-sha1.img qiotest-145-aes-256-cbc-essiv-auto-sha1 | ||
1405 | -# Set dev owner | ||
1406 | -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-auto-sha1 | ||
1407 | # Write test pattern 0xa7 | ||
1408 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-auto-sha1 | ||
1409 | qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-essiv-auto-sha1 | ||
1410 | wrote 10485760/10485760 bytes at offset 104857600 | ||
1411 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1412 | |||
1413 | # Write test pattern 0x13 | ||
1414 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-auto-sha1 | ||
1415 | qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-essiv-auto-sha1 | ||
1416 | wrote 10485760/10485760 bytes at offset 3298534883328 | ||
1417 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1418 | @@ -XXX,XX +XXX,XX @@ wrote 10485760/10485760 bytes at offset 3298534883328 | ||
1419 | |||
1420 | # Open dev | ||
1421 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-essiv-auto-sha1.img qiotest-145-aes-256-cbc-essiv-auto-sha1 | ||
1422 | -# Set dev owner | ||
1423 | -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-auto-sha1 | ||
1424 | # Read test pattern 0x91 | ||
1425 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-auto-sha1 | ||
1426 | qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-essiv-auto-sha1 | ||
1427 | read 10485760/10485760 bytes at offset 104857600 | ||
1428 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1429 | |||
1430 | # Read test pattern 0x5e | ||
1431 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-auto-sha1 | ||
1432 | qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-essiv-auto-sha1 | ||
1433 | read 10485760/10485760 bytes at offset 3298534883328 | ||
1434 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1435 | @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/luks-aes-256-cbc-essiv-auto-sha1.img', fmt=luks size=439804 | ||
1436 | |||
1437 | # Open dev | ||
1438 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-essiv-auto-sha1.img qiotest-145-aes-256-cbc-essiv-auto-sha1 | ||
1439 | -# Set dev owner | ||
1440 | -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-auto-sha1 | ||
1441 | # Write test pattern 0xa7 | ||
1442 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-auto-sha1 | ||
1443 | qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-essiv-auto-sha1 | ||
1444 | wrote 10485760/10485760 bytes at offset 104857600 | ||
1445 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1446 | |||
1447 | # Write test pattern 0x13 | ||
1448 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-auto-sha1 | ||
1449 | qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-essiv-auto-sha1 | ||
1450 | wrote 10485760/10485760 bytes at offset 3298534883328 | ||
1451 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1452 | @@ -XXX,XX +XXX,XX @@ wrote 10485760/10485760 bytes at offset 3298534883328 | ||
1453 | |||
1454 | # Open dev | ||
1455 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-essiv-auto-sha1.img qiotest-145-aes-256-cbc-essiv-auto-sha1 | ||
1456 | -# Set dev owner | ||
1457 | -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-auto-sha1 | ||
1458 | # Read test pattern 0x91 | ||
1459 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-auto-sha1 | ||
1460 | qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-essiv-auto-sha1 | ||
1461 | read 10485760/10485760 bytes at offset 104857600 | ||
1462 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1463 | |||
1464 | # Read test pattern 0x5e | ||
1465 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-auto-sha1 | ||
1466 | qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-essiv-auto-sha1 | ||
1467 | read 10485760/10485760 bytes at offset 3298534883328 | ||
1468 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1469 | @@ -XXX,XX +XXX,XX @@ truncate TEST_DIR/luks-aes-256-cbc-plain64-sha256-sha1.img --size 4194304MB | ||
1470 | sudo cryptsetup -q -v luksFormat --cipher aes-cbc-plain64:sha256 --key-size 256 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-cbc-plain64-sha256-sha1.img | ||
1471 | # Open dev | ||
1472 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-plain64-sha256-sha1.img qiotest-145-aes-256-cbc-plain64-sha256-sha1 | ||
1473 | -# Set dev owner | ||
1474 | -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha256-sha1 | ||
1475 | # Write test pattern 0xa7 | ||
1476 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha256-sha1 | ||
1477 | qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain64-sha256-sha1 | ||
1478 | wrote 10485760/10485760 bytes at offset 104857600 | ||
1479 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1480 | |||
1481 | # Write test pattern 0x13 | ||
1482 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha256-sha1 | ||
1483 | qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain64-sha256-sha1 | ||
1484 | wrote 10485760/10485760 bytes at offset 3298534883328 | ||
1485 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1486 | @@ -XXX,XX +XXX,XX @@ wrote 10485760/10485760 bytes at offset 3298534883328 | ||
1487 | |||
1488 | # Open dev | ||
1489 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-plain64-sha256-sha1.img qiotest-145-aes-256-cbc-plain64-sha256-sha1 | ||
1490 | -# Set dev owner | ||
1491 | -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha256-sha1 | ||
1492 | # Read test pattern 0x91 | ||
1493 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha256-sha1 | ||
1494 | qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain64-sha256-sha1 | ||
1495 | read 10485760/10485760 bytes at offset 104857600 | ||
1496 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1497 | |||
1498 | # Read test pattern 0x5e | ||
1499 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha256-sha1 | ||
1500 | qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain64-sha256-sha1 | ||
1501 | read 10485760/10485760 bytes at offset 3298534883328 | ||
1502 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1503 | @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/luks-aes-256-cbc-plain64-sha256-sha1.img', fmt=luks size=43 | ||
1504 | |||
1505 | # Open dev | ||
1506 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-plain64-sha256-sha1.img qiotest-145-aes-256-cbc-plain64-sha256-sha1 | ||
1507 | -# Set dev owner | ||
1508 | -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha256-sha1 | ||
1509 | # Write test pattern 0xa7 | ||
1510 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha256-sha1 | ||
1511 | qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain64-sha256-sha1 | ||
1512 | wrote 10485760/10485760 bytes at offset 104857600 | ||
1513 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1514 | |||
1515 | # Write test pattern 0x13 | ||
1516 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha256-sha1 | ||
1517 | qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain64-sha256-sha1 | ||
1518 | wrote 10485760/10485760 bytes at offset 3298534883328 | ||
1519 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1520 | @@ -XXX,XX +XXX,XX @@ wrote 10485760/10485760 bytes at offset 3298534883328 | ||
1521 | |||
1522 | # Open dev | ||
1523 | sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-plain64-sha256-sha1.img qiotest-145-aes-256-cbc-plain64-sha256-sha1 | ||
1524 | -# Set dev owner | ||
1525 | -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha256-sha1 | ||
1526 | # Read test pattern 0x91 | ||
1527 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha256-sha1 | ||
1528 | qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain64-sha256-sha1 | ||
1529 | read 10485760/10485760 bytes at offset 104857600 | ||
1530 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1531 | |||
1532 | # Read test pattern 0x5e | ||
1533 | +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha256-sha1 | ||
1534 | qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain64-sha256-sha1 | ||
1535 | read 10485760/10485760 bytes at offset 3298534883328 | ||
1536 | 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1537 | -- | ||
1538 | 1.8.3.1 | ||
1539 | |||
1540 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Max Reitz <mreitz@redhat.com> | ||
2 | 1 | ||
3 | A user may specify a relative path for accessing qemu, qemu-img, etc. | ||
4 | through environment variables ($QEMU_PROG and friends) or a symlink. | ||
5 | |||
6 | If a test decides to change its working directory, relative paths will | ||
7 | cease to work, however. Work around this by making all of the paths to | ||
8 | programs that should undergo testing absolute. Besides "realpath", we | ||
9 | also have to use "type -p" to support programs in $PATH. | ||
10 | |||
11 | As a side effect, this fixes specifying these programs as symlinks for | ||
12 | out-of-tree builds: Before, you would have to create two symlinks, one | ||
13 | in the build and one in the source tree (the first one for common.config | ||
14 | to find, the second one for the iotest to use). Now it is sufficient to | ||
15 | create one in the build tree because common.config will resolve it. | ||
16 | |||
17 | Reported-by: Kevin Wolf <kwolf@redhat.com> | ||
18 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
19 | Message-id: 20170702150510.23276-2-mreitz@redhat.com | ||
20 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
21 | Tested-by: Eric Blake <eblake@redhat.com> | ||
22 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
23 | --- | ||
24 | tests/qemu-iotests/common.config | 11 +++++++++++ | ||
25 | 1 file changed, 11 insertions(+) | ||
26 | |||
27 | diff --git a/tests/qemu-iotests/common.config b/tests/qemu-iotests/common.config | ||
28 | index XXXXXXX..XXXXXXX 100644 | ||
29 | --- a/tests/qemu-iotests/common.config | ||
30 | +++ b/tests/qemu-iotests/common.config | ||
31 | @@ -XXX,XX +XXX,XX @@ if [ -z "$QEMU_VXHS_PROG" ]; then | ||
32 | export QEMU_VXHS_PROG="`set_prog_path qnio_server`" | ||
33 | fi | ||
34 | |||
35 | +export QEMU_PROG=$(realpath -- "$(type -p "$QEMU_PROG")") | ||
36 | +export QEMU_IMG_PROG=$(realpath -- "$(type -p "$QEMU_IMG_PROG")") | ||
37 | +export QEMU_IO_PROG=$(realpath -- "$(type -p "$QEMU_IO_PROG")") | ||
38 | +export QEMU_NBD_PROG=$(realpath -- "$(type -p "$QEMU_NBD_PROG")") | ||
39 | + | ||
40 | +# This program is not built as part of qemu but (possibly) provided by the | ||
41 | +# system, so it may not be present at all | ||
42 | +if [ -n "$QEMU_VXHS_PROG" ]; then | ||
43 | + export QEMU_VXHS_PROG=$(realpath -- "$(type -p "$QEMU_VXHS_PROG")") | ||
44 | +fi | ||
45 | + | ||
46 | _qemu_wrapper() | ||
47 | { | ||
48 | ( | ||
49 | -- | ||
50 | 1.8.3.1 | ||
51 | |||
52 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Max Reitz <mreitz@redhat.com> | ||
2 | 1 | ||
3 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
4 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
5 | Message-id: 20170702150510.23276-3-mreitz@redhat.com | ||
6 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
7 | --- | ||
8 | tests/qemu-iotests/126 | 105 +++++++++++++++++++++++++++++++++++++++++++++ | ||
9 | tests/qemu-iotests/126.out | 23 ++++++++++ | ||
10 | tests/qemu-iotests/group | 1 + | ||
11 | 3 files changed, 129 insertions(+) | ||
12 | create mode 100755 tests/qemu-iotests/126 | ||
13 | create mode 100644 tests/qemu-iotests/126.out | ||
14 | |||
15 | diff --git a/tests/qemu-iotests/126 b/tests/qemu-iotests/126 | ||
16 | new file mode 100755 | ||
17 | index XXXXXXX..XXXXXXX | ||
18 | --- /dev/null | ||
19 | +++ b/tests/qemu-iotests/126 | ||
20 | @@ -XXX,XX +XXX,XX @@ | ||
21 | +#!/bin/bash | ||
22 | +# | ||
23 | +# Tests handling of colons in filenames (which may be confused with protocol | ||
24 | +# prefixes) | ||
25 | +# | ||
26 | +# Copyright (C) 2017 Red Hat, Inc. | ||
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 | +# creator | ||
43 | +owner=mreitz@redhat.com | ||
44 | + | ||
45 | +seq="$(basename $0)" | ||
46 | +echo "QA output created by $seq" | ||
47 | + | ||
48 | +here="$PWD" | ||
49 | +status=1 # failure is the default! | ||
50 | + | ||
51 | +# get standard environment, filters and checks | ||
52 | +. ./common.rc | ||
53 | +. ./common.filter | ||
54 | + | ||
55 | +# Needs backing file support | ||
56 | +_supported_fmt qcow qcow2 qed vmdk | ||
57 | +# This is the default protocol (and we want to test the difference between | ||
58 | +# colons which separate a protocol prefix from the rest and colons which are | ||
59 | +# just part of the filename, so we cannot test protocols which require a prefix) | ||
60 | +_supported_proto file | ||
61 | +_supported_os Linux | ||
62 | + | ||
63 | +echo | ||
64 | +echo '=== Testing plain files ===' | ||
65 | +echo | ||
66 | + | ||
67 | +# A colon after a slash is not a protocol prefix separator | ||
68 | +TEST_IMG="$TEST_DIR/a:b.$IMGFMT" _make_test_img 64M | ||
69 | +_rm_test_img "$TEST_DIR/a:b.$IMGFMT" | ||
70 | + | ||
71 | +# But if you want to be really sure, you can do this | ||
72 | +TEST_IMG="file:$TEST_DIR/a:b.$IMGFMT" _make_test_img 64M | ||
73 | +_rm_test_img "$TEST_DIR/a:b.$IMGFMT" | ||
74 | + | ||
75 | + | ||
76 | +echo | ||
77 | +echo '=== Testing relative backing filename resolution ===' | ||
78 | +echo | ||
79 | + | ||
80 | +BASE_IMG="$TEST_DIR/image:base.$IMGFMT" | ||
81 | +TOP_IMG="$TEST_DIR/image:top.$IMGFMT" | ||
82 | + | ||
83 | +TEST_IMG=$BASE_IMG _make_test_img 64M | ||
84 | +TEST_IMG=$TOP_IMG _make_test_img -b ./image:base.$IMGFMT | ||
85 | + | ||
86 | +# The default cluster size depends on the image format | ||
87 | +TEST_IMG=$TOP_IMG _img_info | grep -v 'cluster_size' | ||
88 | + | ||
89 | +_rm_test_img "$BASE_IMG" | ||
90 | +_rm_test_img "$TOP_IMG" | ||
91 | + | ||
92 | + | ||
93 | +# Do another test where we access both top and base without any slash in them | ||
94 | +echo | ||
95 | +pushd "$TEST_DIR" >/dev/null | ||
96 | + | ||
97 | +BASE_IMG="base.$IMGFMT" | ||
98 | +TOP_IMG="file:image:top.$IMGFMT" | ||
99 | + | ||
100 | +TEST_IMG=$BASE_IMG _make_test_img 64M | ||
101 | +TEST_IMG=$TOP_IMG _make_test_img -b "$BASE_IMG" | ||
102 | + | ||
103 | +TEST_IMG=$TOP_IMG _img_info | grep -v 'cluster_size' | ||
104 | + | ||
105 | +_rm_test_img "$BASE_IMG" | ||
106 | +_rm_test_img "image:top.$IMGFMT" | ||
107 | + | ||
108 | +popd >/dev/null | ||
109 | + | ||
110 | +# Note that we could also do the same test with BASE_IMG=file:image:base.$IMGFMT | ||
111 | +# -- but behavior for that case is a bit strange. Protocol-prefixed paths are | ||
112 | +# in a sense always absolute paths, so such paths will never be combined with | ||
113 | +# the path of the overlay. But since "image:base.$IMGFMT" is actually a | ||
114 | +# relative path, it will always be evaluated relative to qemu's CWD (but not | ||
115 | +# relative to the overlay!). While this is more or less intended, it is still | ||
116 | +# pretty strange and thus not something that is tested here. | ||
117 | +# (The root of the issue is the use of a relative path with a protocol prefix. | ||
118 | +# This may always give you weird results because in one sense, qemu considers | ||
119 | +# such paths absolute, whereas in another, they are still relative.) | ||
120 | + | ||
121 | + | ||
122 | +# success, all done | ||
123 | +echo '*** done' | ||
124 | +rm -f $seq.full | ||
125 | +status=0 | ||
126 | diff --git a/tests/qemu-iotests/126.out b/tests/qemu-iotests/126.out | ||
127 | new file mode 100644 | ||
128 | index XXXXXXX..XXXXXXX | ||
129 | --- /dev/null | ||
130 | +++ b/tests/qemu-iotests/126.out | ||
131 | @@ -XXX,XX +XXX,XX @@ | ||
132 | +QA output created by 126 | ||
133 | + | ||
134 | +=== Testing plain files === | ||
135 | + | ||
136 | +Formatting 'TEST_DIR/a:b.IMGFMT', fmt=IMGFMT size=67108864 | ||
137 | +Formatting 'TEST_DIR/a:b.IMGFMT', fmt=IMGFMT size=67108864 | ||
138 | + | ||
139 | +=== Testing relative backing filename resolution === | ||
140 | + | ||
141 | +Formatting 'TEST_DIR/image:base.IMGFMT', fmt=IMGFMT size=67108864 | ||
142 | +Formatting 'TEST_DIR/image:top.IMGFMT', fmt=IMGFMT size=67108864 backing_file=./image:base.IMGFMT | ||
143 | +image: TEST_DIR/image:top.IMGFMT | ||
144 | +file format: IMGFMT | ||
145 | +virtual size: 64M (67108864 bytes) | ||
146 | +backing file: ./image:base.IMGFMT (actual path: TEST_DIR/./image:base.IMGFMT) | ||
147 | + | ||
148 | +Formatting 'base.IMGFMT', fmt=IMGFMT size=67108864 | ||
149 | +Formatting 'file:image:top.IMGFMT', fmt=IMGFMT size=67108864 backing_file=base.IMGFMT | ||
150 | +image: ./image:top.IMGFMT | ||
151 | +file format: IMGFMT | ||
152 | +virtual size: 64M (67108864 bytes) | ||
153 | +backing file: base.IMGFMT (actual path: ./base.IMGFMT) | ||
154 | +*** done | ||
155 | diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group | ||
156 | index XXXXXXX..XXXXXXX 100644 | ||
157 | --- a/tests/qemu-iotests/group | ||
158 | +++ b/tests/qemu-iotests/group | ||
159 | @@ -XXX,XX +XXX,XX @@ | ||
160 | 122 rw auto | ||
161 | 123 rw auto quick | ||
162 | 124 rw auto backing | ||
163 | +126 rw auto backing | ||
164 | 128 rw auto quick | ||
165 | 129 rw auto quick | ||
166 | 130 rw auto quick | ||
167 | -- | ||
168 | 1.8.3.1 | ||
169 | |||
170 | diff view generated by jsdifflib |