1 | The following changes since commit 6629bf78aac7e53f83fd0bcbdbe322e2302dfd1f: | 1 | The following changes since commit 281f327487c9c9b1599f93c589a408bbf4a651b8: |
---|---|---|---|
2 | 2 | ||
3 | Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20220302' into staging (2022-03-03 14:46:48 +0000) | 3 | Merge remote-tracking branch 'remotes/vivier/tags/m68k-for-2.12-pull-request' into staging (2017-12-22 00:11:36 +0000) |
4 | 4 | ||
5 | are available in the Git repository at: | 5 | are available in the git repository at: |
6 | 6 | ||
7 | https://gitlab.com/kmwolf/qemu.git tags/for-upstream | 7 | git://repo.or.cz/qemu/kevin.git tags/for-upstream |
8 | 8 | ||
9 | for you to fetch changes up to a5df6d1db7db37636c8624bf4a9df9da645853aa: | 9 | for you to fetch changes up to 1a63a907507fbbcfaee3f622907ec244b7eabda8: |
10 | 10 | ||
11 | block/amend: Keep strong reference to BDS (2022-03-04 17:15:33 +0100) | 11 | block: Keep nodes drained between reopen_queue/multiple (2017-12-22 15:05:32 +0100) |
12 | 12 | ||
13 | ---------------------------------------------------------------- | 13 | ---------------------------------------------------------------- |
14 | Block layer patches | 14 | Block layer patches |
15 | 15 | ||
16 | - qemu-storage-daemon: Add --daemonize | 16 | ---------------------------------------------------------------- |
17 | - Fix x-blockdev-amend and block node activation code which incorrectly | 17 | Doug Gale (1): |
18 | executed code in the iothread that must run in the main thread. | 18 | nvme: Add tracing |
19 | - Add macros for coroutine-safe TLS variables (required for correctness | ||
20 | with LTO) | ||
21 | - Fix crashes with concurrent I/O and bdrv_refresh_limits() | ||
22 | - Split block APIs in global state and I/O | ||
23 | - iotests: Don't refuse to run at all without GNU sed, just skip tests | ||
24 | that need it | ||
25 | 19 | ||
26 | ---------------------------------------------------------------- | 20 | Edgar Kaziakhmedov (1): |
27 | Emanuele Giuseppe Esposito (36): | 21 | qcow2: get rid of qcow2_backing_read1 routine |
28 | crypto: perform permission checks under BQL | ||
29 | crypto: distinguish between main loop and I/O in block_crypto_amend_options_generic_luks | ||
30 | block: introduce bdrv_activate | ||
31 | block: rename bdrv_invalidate_cache_all, blk_invalidate_cache and test_sync_op_invalidate_cache | ||
32 | block: move BQL logic of bdrv_co_invalidate_cache in bdrv_activate | ||
33 | main-loop.h: introduce qemu_in_main_thread() | ||
34 | main loop: macros to mark GS and I/O functions | ||
35 | include/block/block: split header into I/O and global state API | ||
36 | assertions for block global state API | ||
37 | IO_CODE and IO_OR_GS_CODE for block I/O API | ||
38 | block/export/fuse.c: allow writable exports to take RESIZE permission | ||
39 | include/sysemu/block-backend: split header into I/O and global state (GS) API | ||
40 | block/block-backend.c: assertions for block-backend | ||
41 | IO_CODE and IO_OR_GS_CODE for block-backend I/O API | ||
42 | block.c: assertions to the block layer permissions API | ||
43 | include/block/block_int: split header into I/O and global state API | ||
44 | assertions for block_int global state API | ||
45 | IO_CODE and IO_OR_GS_CODE for block_int I/O API | ||
46 | block: introduce assert_bdrv_graph_writable | ||
47 | include/block/blockjob_int.h: split header into I/O and GS API | ||
48 | GS and IO CODE macros for blockjob_int.h | ||
49 | block.c: add assertions to static functions | ||
50 | include/block/blockjob.h: global state API | ||
51 | assertions for blockjob.h global state API | ||
52 | include/sysemu/blockdev.h: global state API | ||
53 | assertions for blockdev.h global state API | ||
54 | include/block/snapshot: global state API + assertions | ||
55 | block/copy-before-write.h: global state API + assertions | ||
56 | block/coroutines: I/O and "I/O or GS" API | ||
57 | block_int-common.h: split function pointers in BlockDriver | ||
58 | block_int-common.h: assertions in the callers of BlockDriver function pointers | ||
59 | block_int-common.h: split function pointers in BdrvChildClass | ||
60 | block_int-common.h: assertions in the callers of BdrvChildClass function pointers | ||
61 | block-backend-common.h: split function pointers in BlockDevOps | ||
62 | job.h: split function pointers in JobDriver | ||
63 | job.h: assertions in the callers of JobDriver function pointers | ||
64 | 22 | ||
65 | Hanna Reitz (9): | 23 | Fam Zheng (2): |
66 | os-posix: Add os_set_daemonize() | 24 | block: Open backing image in force share mode for size probe |
67 | qsd: Add pre-init argument parsing pass | 25 | block: Remove unused bdrv_requests_pending |
68 | qsd: Add --daemonize | ||
69 | iotests/185: Add post-READY quit tests | ||
70 | block: Make bdrv_refresh_limits() non-recursive | ||
71 | iotests: Allow using QMP with the QSD | ||
72 | iotests/graph-changes-while-io: New test | ||
73 | block/amend: Always call .bdrv_amend_clean() | ||
74 | block/amend: Keep strong reference to BDS | ||
75 | 26 | ||
76 | Stefan Hajnoczi (4): | 27 | John Snow (1): |
77 | tls: add macros for coroutine-safe TLS variables | 28 | iotests: fix 197 for vpc |
78 | util/async: replace __thread with QEMU TLS macros | ||
79 | rcu: use coroutine TLS macros | ||
80 | cpus: use coroutine TLS macros for iothread_locked | ||
81 | 29 | ||
82 | Thomas Huth (1): | 30 | Kevin Wolf (27): |
83 | tests/qemu-iotests: Rework the checks and spots using GNU sed | 31 | block: Formats don't need CONSISTENT_READ with NO_IO |
32 | block: Make bdrv_drain_invoke() recursive | ||
33 | block: Call .drain_begin only once in bdrv_drain_all_begin() | ||
34 | test-bdrv-drain: Test BlockDriver callbacks for drain | ||
35 | block: bdrv_drain_recurse(): Remove unused begin parameter | ||
36 | block: Don't wait for requests in bdrv_drain*_end() | ||
37 | block: Unify order in drain functions | ||
38 | block: Don't acquire AioContext in hmp_qemu_io() | ||
39 | block: Document that x-blockdev-change breaks quorum children list | ||
40 | block: Assert drain_all is only called from main AioContext | ||
41 | block: Make bdrv_drain() driver callbacks non-recursive | ||
42 | test-bdrv-drain: Test callback for bdrv_drain | ||
43 | test-bdrv-drain: Test bs->quiesce_counter | ||
44 | blockjob: Pause job on draining any job BDS | ||
45 | test-bdrv-drain: Test drain vs. block jobs | ||
46 | block: Don't block_job_pause_all() in bdrv_drain_all() | ||
47 | block: Nested drain_end must still call callbacks | ||
48 | test-bdrv-drain: Test nested drain sections | ||
49 | block: Don't notify parents in drain call chain | ||
50 | block: Add bdrv_subtree_drained_begin/end() | ||
51 | test-bdrv-drain: Tests for bdrv_subtree_drain | ||
52 | test-bdrv-drain: Test behaviour in coroutine context | ||
53 | test-bdrv-drain: Recursive draining with multiple parents | ||
54 | block: Allow graph changes in subtree drained section | ||
55 | test-bdrv-drain: Test graph changes in drained section | ||
56 | commit: Simplify reopen of base | ||
57 | block: Keep nodes drained between reopen_queue/multiple | ||
84 | 58 | ||
85 | docs/tools/qemu-storage-daemon.rst | 7 + | 59 | Thomas Huth (3): |
86 | block/copy-before-write.h | 7 + | 60 | block: Remove the obsolete -drive boot=on|off parameter |
87 | block/coroutines.h | 81 +- | 61 | block: Remove the deprecated -hdachs option |
88 | include/block/block-common.h | 418 ++++++ | 62 | block: Mention -drive cyls/heads/secs/trans/serial/addr in deprecation chapter |
89 | include/block/block-global-state.h | 253 ++++ | 63 | |
90 | include/block/block-io.h | 368 +++++ | 64 | qapi/block-core.json | 4 + |
91 | include/block/block.h | 878 +----------- | 65 | block/qcow2.h | 3 - |
92 | include/block/block_int-common.h | 1222 ++++++++++++++++ | 66 | include/block/block.h | 15 +- |
93 | include/block/block_int-global-state.h | 329 +++++ | 67 | include/block/block_int.h | 6 +- |
94 | include/block/block_int-io.h | 185 +++ | 68 | block.c | 75 ++++- |
95 | include/block/block_int.h | 1475 +------------------- | 69 | block/commit.c | 8 +- |
96 | include/block/blockjob.h | 29 +- | 70 | block/io.c | 164 +++++++--- |
97 | include/block/blockjob_int.h | 28 + | 71 | block/qcow2.c | 51 +-- |
98 | include/block/snapshot.h | 13 +- | 72 | block/replication.c | 6 + |
99 | include/qemu/coroutine-tls.h | 165 +++ | 73 | blockdev.c | 11 - |
100 | include/qemu/job.h | 22 + | 74 | blockjob.c | 22 +- |
101 | include/qemu/main-loop.h | 42 + | 75 | hmp.c | 6 - |
102 | include/qemu/rcu.h | 7 +- | 76 | hw/block/nvme.c | 349 +++++++++++++++++---- |
103 | include/sysemu/block-backend-common.h | 102 ++ | 77 | qemu-io-cmds.c | 3 + |
104 | include/sysemu/block-backend-global-state.h | 116 ++ | 78 | tests/test-bdrv-drain.c | 651 +++++++++++++++++++++++++++++++++++++++ |
105 | include/sysemu/block-backend-io.h | 161 +++ | 79 | vl.c | 86 +----- |
106 | include/sysemu/block-backend.h | 269 +--- | 80 | hw/block/trace-events | 93 ++++++ |
107 | include/sysemu/blockdev.h | 13 +- | 81 | qemu-doc.texi | 29 +- |
108 | include/sysemu/os-posix.h | 1 + | 82 | qemu-options.hx | 19 +- |
109 | include/sysemu/os-win32.h | 8 + | 83 | tests/Makefile.include | 2 + |
110 | block.c | 321 ++++- | 84 | tests/qemu-iotests/197 | 4 + |
111 | block/amend.c | 28 + | 85 | tests/qemu-iotests/common.filter | 3 +- |
112 | block/backup.c | 1 + | 86 | 22 files changed, 1294 insertions(+), 316 deletions(-) |
113 | block/block-backend.c | 166 ++- | 87 | create mode 100644 tests/test-bdrv-drain.c |
114 | block/commit.c | 4 + | 88 | |
115 | block/copy-before-write.c | 2 + | ||
116 | block/create.c | 2 + | ||
117 | block/crypto.c | 68 +- | ||
118 | block/dirty-bitmap.c | 5 + | ||
119 | block/export/export.c | 2 +- | ||
120 | block/export/fuse.c | 25 +- | ||
121 | block/io.c | 75 +- | ||
122 | block/mirror.c | 4 + | ||
123 | block/monitor/bitmap-qmp-cmds.c | 6 + | ||
124 | block/nbd.c | 1 + | ||
125 | block/parallels.c | 2 +- | ||
126 | block/snapshot.c | 28 + | ||
127 | block/stream.c | 2 + | ||
128 | blockdev.c | 29 + | ||
129 | blockjob.c | 16 + | ||
130 | hw/block/pflash_cfi01.c | 2 +- | ||
131 | hw/nvram/spapr_nvram.c | 2 +- | ||
132 | job.c | 10 + | ||
133 | migration/block.c | 2 +- | ||
134 | migration/migration.c | 14 +- | ||
135 | migration/savevm.c | 8 +- | ||
136 | monitor/qmp-cmds.c | 2 +- | ||
137 | os-posix.c | 6 + | ||
138 | softmmu/cpus.c | 14 +- | ||
139 | softmmu/qdev-monitor.c | 2 + | ||
140 | storage-daemon/qemu-storage-daemon.c | 58 +- | ||
141 | stubs/iothread-lock.c | 5 + | ||
142 | tests/unit/rcutorture.c | 10 +- | ||
143 | tests/unit/test-block-iothread.c | 8 +- | ||
144 | tests/unit/test-rcu-list.c | 4 +- | ||
145 | util/async.c | 12 +- | ||
146 | util/rcu.c | 10 +- | ||
147 | tests/qemu-iotests/iotests.py | 32 +- | ||
148 | block/meson.build | 7 +- | ||
149 | tests/check-block.sh | 12 - | ||
150 | tests/qemu-iotests/185 | 190 ++- | ||
151 | tests/qemu-iotests/185.out | 48 + | ||
152 | tests/qemu-iotests/271 | 2 +- | ||
153 | tests/qemu-iotests/296 | 8 +- | ||
154 | tests/qemu-iotests/296.out | 17 +- | ||
155 | tests/qemu-iotests/common.filter | 65 +- | ||
156 | tests/qemu-iotests/common.rc | 45 +- | ||
157 | tests/qemu-iotests/tests/graph-changes-while-io | 91 ++ | ||
158 | .../qemu-iotests/tests/graph-changes-while-io.out | 5 + | ||
159 | 74 files changed, 4854 insertions(+), 2823 deletions(-) | ||
160 | create mode 100644 include/block/block-common.h | ||
161 | create mode 100644 include/block/block-global-state.h | ||
162 | create mode 100644 include/block/block-io.h | ||
163 | create mode 100644 include/block/block_int-common.h | ||
164 | create mode 100644 include/block/block_int-global-state.h | ||
165 | create mode 100644 include/block/block_int-io.h | ||
166 | create mode 100644 include/qemu/coroutine-tls.h | ||
167 | create mode 100644 include/sysemu/block-backend-common.h | ||
168 | create mode 100644 include/sysemu/block-backend-global-state.h | ||
169 | create mode 100644 include/sysemu/block-backend-io.h | ||
170 | create mode 100755 tests/qemu-iotests/tests/graph-changes-while-io | ||
171 | create mode 100644 tests/qemu-iotests/tests/graph-changes-while-io.out | diff view generated by jsdifflib |
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | 1 | Commit 1f4ad7d fixed 'qemu-img info' for raw images that are currently |
---|---|---|---|
2 | in use as a mirror target. It is not enough for image formats, though, | ||
3 | as these still unconditionally request BLK_PERM_CONSISTENT_READ. | ||
2 | 4 | ||
3 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | 5 | As this permission is geared towards whether the guest-visible data is |
4 | Message-Id: <20220303151616.325444-27-eesposit@redhat.com> | 6 | consistent, and has no impact on whether the metadata is sane, and |
7 | 'qemu-img info' does not read guest-visible data (except for the raw | ||
8 | format), it makes sense to not require BLK_PERM_CONSISTENT_READ if there | ||
9 | is not going to be any guest I/O performed, regardless of image format. | ||
10 | |||
5 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
6 | --- | 12 | --- |
7 | block.c | 17 +++++++++++++++++ | 13 | block.c | 6 +++++- |
8 | block/create.c | 2 ++ | 14 | 1 file changed, 5 insertions(+), 1 deletion(-) |
9 | 2 files changed, 19 insertions(+) | ||
10 | 15 | ||
11 | diff --git a/block.c b/block.c | 16 | diff --git a/block.c b/block.c |
12 | index XXXXXXX..XXXXXXX 100644 | 17 | index XXXXXXX..XXXXXXX 100644 |
13 | --- a/block.c | 18 | --- a/block.c |
14 | +++ b/block.c | 19 | +++ b/block.c |
15 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_create_co_entry(void *opaque) | 20 | @@ -XXX,XX +XXX,XX @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c, |
16 | 21 | assert(role == &child_backing || role == &child_file); | |
17 | CreateCo *cco = opaque; | 22 | |
18 | assert(cco->drv); | 23 | if (!backing) { |
19 | + GLOBAL_STATE_CODE(); | 24 | + int flags = bdrv_reopen_get_flags(reopen_queue, bs); |
20 | 25 | + | |
21 | ret = cco->drv->bdrv_co_create_opts(cco->drv, | 26 | /* Apart from the modifications below, the same permissions are |
22 | cco->filename, cco->opts, &local_err); | 27 | * forwarded and left alone as for filters */ |
23 | @@ -XXX,XX +XXX,XX @@ int refresh_total_sectors(BlockDriverState *bs, int64_t hint) | 28 | bdrv_filter_default_perms(bs, c, role, reopen_queue, perm, shared, |
24 | static void bdrv_join_options(BlockDriverState *bs, QDict *options, | 29 | @@ -XXX,XX +XXX,XX @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c, |
25 | QDict *old_options) | 30 | |
26 | { | 31 | /* bs->file always needs to be consistent because of the metadata. We |
27 | + GLOBAL_STATE_CODE(); | 32 | * can never allow other users to resize or write to it. */ |
28 | if (bs->drv && bs->drv->bdrv_join_options) { | 33 | - perm |= BLK_PERM_CONSISTENT_READ; |
29 | bs->drv->bdrv_join_options(options, old_options); | 34 | + if (!(flags & BDRV_O_NO_IO)) { |
35 | + perm |= BLK_PERM_CONSISTENT_READ; | ||
36 | + } | ||
37 | shared &= ~(BLK_PERM_WRITE | BLK_PERM_RESIZE); | ||
30 | } else { | 38 | } else { |
31 | @@ -XXX,XX +XXX,XX @@ static int bdrv_open_driver(BlockDriverState *bs, BlockDriver *drv, | 39 | /* We want consistent read from backing files if the parent needs it. |
32 | { | ||
33 | Error *local_err = NULL; | ||
34 | int i, ret; | ||
35 | + GLOBAL_STATE_CODE(); | ||
36 | |||
37 | bdrv_assign_node_name(bs, node_name, &local_err); | ||
38 | if (local_err) { | ||
39 | @@ -XXX,XX +XXX,XX @@ static int bdrv_fill_options(QDict **options, const char *filename, | ||
40 | BlockDriver *drv = NULL; | ||
41 | Error *local_err = NULL; | ||
42 | |||
43 | + GLOBAL_STATE_CODE(); | ||
44 | + | ||
45 | /* | ||
46 | * Caution: while qdict_get_try_str() is fine, getting non-string | ||
47 | * types would require more care. When @options come from | ||
48 | @@ -XXX,XX +XXX,XX @@ static void bdrv_child_perm(BlockDriverState *bs, BlockDriverState *child_bs, | ||
49 | uint64_t *nperm, uint64_t *nshared) | ||
50 | { | ||
51 | assert(bs->drv && bs->drv->bdrv_child_perm); | ||
52 | + GLOBAL_STATE_CODE(); | ||
53 | bs->drv->bdrv_child_perm(bs, c, role, reopen_queue, | ||
54 | parent_perm, parent_shared, | ||
55 | nperm, nshared); | ||
56 | @@ -XXX,XX +XXX,XX @@ static void bdrv_drv_set_perm_commit(void *opaque) | ||
57 | { | ||
58 | BlockDriverState *bs = opaque; | ||
59 | uint64_t cumulative_perms, cumulative_shared_perms; | ||
60 | + GLOBAL_STATE_CODE(); | ||
61 | |||
62 | if (bs->drv->bdrv_set_perm) { | ||
63 | bdrv_get_cumulative_perm(bs, &cumulative_perms, | ||
64 | @@ -XXX,XX +XXX,XX @@ static void bdrv_drv_set_perm_commit(void *opaque) | ||
65 | static void bdrv_drv_set_perm_abort(void *opaque) | ||
66 | { | ||
67 | BlockDriverState *bs = opaque; | ||
68 | + GLOBAL_STATE_CODE(); | ||
69 | |||
70 | if (bs->drv->bdrv_abort_perm_update) { | ||
71 | bs->drv->bdrv_abort_perm_update(bs); | ||
72 | @@ -XXX,XX +XXX,XX @@ static int bdrv_drv_set_perm(BlockDriverState *bs, uint64_t perm, | ||
73 | uint64_t shared_perm, Transaction *tran, | ||
74 | Error **errp) | ||
75 | { | ||
76 | + GLOBAL_STATE_CODE(); | ||
77 | if (!bs->drv) { | ||
78 | return 0; | ||
79 | } | ||
80 | @@ -XXX,XX +XXX,XX @@ int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp) | ||
81 | |||
82 | assert(qemu_get_current_aio_context() == qemu_get_aio_context()); | ||
83 | assert(bs_queue != NULL); | ||
84 | + GLOBAL_STATE_CODE(); | ||
85 | |||
86 | QTAILQ_FOREACH(bs_entry, bs_queue, entry) { | ||
87 | ctx = bdrv_get_aio_context(bs_entry->state.bs); | ||
88 | @@ -XXX,XX +XXX,XX @@ static int bdrv_reopen_prepare(BDRVReopenState *reopen_state, | ||
89 | |||
90 | assert(reopen_state != NULL); | ||
91 | assert(reopen_state->bs->drv != NULL); | ||
92 | + GLOBAL_STATE_CODE(); | ||
93 | drv = reopen_state->bs->drv; | ||
94 | |||
95 | /* This function and each driver's bdrv_reopen_prepare() remove | ||
96 | @@ -XXX,XX +XXX,XX @@ static void bdrv_reopen_commit(BDRVReopenState *reopen_state) | ||
97 | bs = reopen_state->bs; | ||
98 | drv = bs->drv; | ||
99 | assert(drv != NULL); | ||
100 | + GLOBAL_STATE_CODE(); | ||
101 | |||
102 | /* If there are any driver level actions to take */ | ||
103 | if (drv->bdrv_reopen_commit) { | ||
104 | @@ -XXX,XX +XXX,XX @@ static void bdrv_reopen_abort(BDRVReopenState *reopen_state) | ||
105 | assert(reopen_state != NULL); | ||
106 | drv = reopen_state->bs->drv; | ||
107 | assert(drv != NULL); | ||
108 | + GLOBAL_STATE_CODE(); | ||
109 | |||
110 | if (drv->bdrv_reopen_abort) { | ||
111 | drv->bdrv_reopen_abort(reopen_state); | ||
112 | @@ -XXX,XX +XXX,XX @@ static int bdrv_inactivate_recurse(BlockDriverState *bs) | ||
113 | int ret; | ||
114 | uint64_t cumulative_perms, cumulative_shared_perms; | ||
115 | |||
116 | + GLOBAL_STATE_CODE(); | ||
117 | + | ||
118 | if (!bs->drv) { | ||
119 | return -ENOMEDIUM; | ||
120 | } | ||
121 | @@ -XXX,XX +XXX,XX @@ static void bdrv_detach_aio_context(BlockDriverState *bs) | ||
122 | BdrvAioNotifier *baf, *baf_tmp; | ||
123 | |||
124 | assert(!bs->walking_aio_notifiers); | ||
125 | + GLOBAL_STATE_CODE(); | ||
126 | bs->walking_aio_notifiers = true; | ||
127 | QLIST_FOREACH_SAFE(baf, &bs->aio_notifiers, list, baf_tmp) { | ||
128 | if (baf->deleted) { | ||
129 | @@ -XXX,XX +XXX,XX @@ static void bdrv_attach_aio_context(BlockDriverState *bs, | ||
130 | AioContext *new_context) | ||
131 | { | ||
132 | BdrvAioNotifier *ban, *ban_tmp; | ||
133 | + GLOBAL_STATE_CODE(); | ||
134 | |||
135 | if (bs->quiesce_counter) { | ||
136 | aio_disable_external(new_context); | ||
137 | diff --git a/block/create.c b/block/create.c | ||
138 | index XXXXXXX..XXXXXXX 100644 | ||
139 | --- a/block/create.c | ||
140 | +++ b/block/create.c | ||
141 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn blockdev_create_run(Job *job, Error **errp) | ||
142 | BlockdevCreateJob *s = container_of(job, BlockdevCreateJob, common); | ||
143 | int ret; | ||
144 | |||
145 | + GLOBAL_STATE_CODE(); | ||
146 | + | ||
147 | job_progress_set_remaining(&s->common, 1); | ||
148 | ret = s->drv->bdrv_co_create(s->opts, errp); | ||
149 | job_progress_update(&s->common, 1); | ||
150 | -- | 40 | -- |
151 | 2.35.1 | 41 | 2.13.6 |
42 | |||
43 | diff view generated by jsdifflib |
1 | From: Hanna Reitz <hreitz@redhat.com> | 1 | From: John Snow <jsnow@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Add a parameter to optionally open a QMP connection when creating a | 3 | VPC has some difficulty creating geometries of particular size. |
4 | QemuStorageDaemon instance. | 4 | However, we can indeed force it to use a literal one, so let's |
5 | do that for the sake of test 197, which is testing some specific | ||
6 | offsets. | ||
5 | 7 | ||
6 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | 8 | Signed-off-by: John Snow <jsnow@redhat.com> |
7 | Message-Id: <20220216105355.30729-3-hreitz@redhat.com> | ||
8 | Reviewed-by: Eric Blake <eblake@redhat.com> | 9 | Reviewed-by: Eric Blake <eblake@redhat.com> |
9 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | 10 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> |
10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
12 | Reviewed-by: Lukáš Doktor <ldoktor@redhat.com> | ||
11 | --- | 13 | --- |
12 | tests/qemu-iotests/iotests.py | 32 +++++++++++++++++++++++++++++++- | 14 | tests/qemu-iotests/197 | 4 ++++ |
13 | 1 file changed, 31 insertions(+), 1 deletion(-) | 15 | tests/qemu-iotests/common.filter | 3 ++- |
16 | 2 files changed, 6 insertions(+), 1 deletion(-) | ||
14 | 17 | ||
15 | diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py | 18 | diff --git a/tests/qemu-iotests/197 b/tests/qemu-iotests/197 |
19 | index XXXXXXX..XXXXXXX 100755 | ||
20 | --- a/tests/qemu-iotests/197 | ||
21 | +++ b/tests/qemu-iotests/197 | ||
22 | @@ -XXX,XX +XXX,XX @@ echo '=== Copy-on-read ===' | ||
23 | echo | ||
24 | |||
25 | # Prep the images | ||
26 | +# VPC rounds image sizes to a specific geometry, force a specific size. | ||
27 | +if [ "$IMGFMT" = "vpc" ]; then | ||
28 | + IMGOPTS=$(_optstr_add "$IMGOPTS" "force_size") | ||
29 | +fi | ||
30 | _make_test_img 4G | ||
31 | $QEMU_IO -c "write -P 55 3G 1k" "$TEST_IMG" | _filter_qemu_io | ||
32 | IMGPROTO=file IMGFMT=qcow2 IMGOPTS= TEST_IMG_FILE="$TEST_WRAP" \ | ||
33 | diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter | ||
16 | index XXXXXXX..XXXXXXX 100644 | 34 | index XXXXXXX..XXXXXXX 100644 |
17 | --- a/tests/qemu-iotests/iotests.py | 35 | --- a/tests/qemu-iotests/common.filter |
18 | +++ b/tests/qemu-iotests/iotests.py | 36 | +++ b/tests/qemu-iotests/common.filter |
19 | @@ -XXX,XX +XXX,XX @@ | 37 | @@ -XXX,XX +XXX,XX @@ _filter_img_create() |
20 | 38 | -e "s# log_size=[0-9]\\+##g" \ | |
21 | from qemu.machine import qtest | 39 | -e "s# refcount_bits=[0-9]\\+##g" \ |
22 | from qemu.qmp import QMPMessage | 40 | -e "s# key-secret=[a-zA-Z0-9]\\+##g" \ |
23 | +from qemu.aqmp.legacy import QEMUMonitorProtocol | 41 | - -e "s# iter-time=[0-9]\\+##g" |
24 | 42 | + -e "s# iter-time=[0-9]\\+##g" \ | |
25 | # Use this logger for logging messages directly from the iotests module | 43 | + -e "s# force_size=\\(on\\|off\\)##g" |
26 | logger = logging.getLogger('qemu.iotests') | 44 | } |
27 | @@ -XXX,XX +XXX,XX @@ def cmd(self, cmd): | 45 | |
28 | 46 | _filter_img_info() | |
29 | |||
30 | class QemuStorageDaemon: | ||
31 | - def __init__(self, *args: str, instance_id: str = 'a'): | ||
32 | + _qmp: Optional[QEMUMonitorProtocol] = None | ||
33 | + _qmpsock: Optional[str] = None | ||
34 | + # Python < 3.8 would complain if this type were not a string literal | ||
35 | + # (importing `annotations` from `__future__` would work; but not on <= 3.6) | ||
36 | + _p: 'Optional[subprocess.Popen[bytes]]' = None | ||
37 | + | ||
38 | + def __init__(self, *args: str, instance_id: str = 'a', qmp: bool = False): | ||
39 | assert '--pidfile' not in args | ||
40 | self.pidfile = os.path.join(test_dir, f'qsd-{instance_id}-pid') | ||
41 | all_args = [qsd_prog] + list(args) + ['--pidfile', self.pidfile] | ||
42 | |||
43 | + if qmp: | ||
44 | + self._qmpsock = os.path.join(sock_dir, f'qsd-{instance_id}.sock') | ||
45 | + all_args += ['--chardev', | ||
46 | + f'socket,id=qmp-sock,path={self._qmpsock}', | ||
47 | + '--monitor', 'qmp-sock'] | ||
48 | + | ||
49 | + self._qmp = QEMUMonitorProtocol(self._qmpsock, server=True) | ||
50 | + | ||
51 | # Cannot use with here, we want the subprocess to stay around | ||
52 | # pylint: disable=consider-using-with | ||
53 | self._p = subprocess.Popen(all_args) | ||
54 | + if self._qmp is not None: | ||
55 | + self._qmp.accept() | ||
56 | while not os.path.exists(self.pidfile): | ||
57 | if self._p.poll() is not None: | ||
58 | cmd = ' '.join(all_args) | ||
59 | @@ -XXX,XX +XXX,XX @@ def __init__(self, *args: str, instance_id: str = 'a'): | ||
60 | |||
61 | assert self._pid == self._p.pid | ||
62 | |||
63 | + def qmp(self, cmd: str, args: Optional[Dict[str, object]] = None) \ | ||
64 | + -> QMPMessage: | ||
65 | + assert self._qmp is not None | ||
66 | + return self._qmp.cmd(cmd, args) | ||
67 | + | ||
68 | def stop(self, kill_signal=15): | ||
69 | self._p.send_signal(kill_signal) | ||
70 | self._p.wait() | ||
71 | self._p = None | ||
72 | |||
73 | + if self._qmp: | ||
74 | + self._qmp.close() | ||
75 | + | ||
76 | + if self._qmpsock is not None: | ||
77 | + try: | ||
78 | + os.remove(self._qmpsock) | ||
79 | + except OSError: | ||
80 | + pass | ||
81 | try: | ||
82 | os.remove(self.pidfile) | ||
83 | except OSError: | ||
84 | -- | 47 | -- |
85 | 2.35.1 | 48 | 2.13.6 |
49 | |||
50 | diff view generated by jsdifflib |
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | 1 | This change separates bdrv_drain_invoke(), which calls the BlockDriver |
---|---|---|---|
2 | drain callbacks, from bdrv_drain_recurse(). Instead, the function | ||
3 | performs its own recursion now. | ||
2 | 4 | ||
3 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | 5 | One reason for this is that bdrv_drain_recurse() can be called multiple |
4 | Message-Id: <20220303151616.325444-29-eesposit@redhat.com> | 6 | times by bdrv_drain_all_begin(), but the callbacks may only be called |
7 | once. The separation is necessary to fix this bug. | ||
8 | |||
9 | The other reason is that we intend to go to a model where we call all | ||
10 | driver callbacks first, and only then start polling. This is not fully | ||
11 | achieved yet with this patch, as bdrv_drain_invoke() contains a | ||
12 | BDRV_POLL_WHILE() loop for the block driver callbacks, which can still | ||
13 | call callbacks for any unrelated event. It's a step in this direction | ||
14 | anyway. | ||
15 | |||
16 | Cc: qemu-stable@nongnu.org | ||
5 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 17 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
18 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
6 | --- | 19 | --- |
7 | block.c | 10 +++++++++- | 20 | block/io.c | 14 +++++++++++--- |
8 | 1 file changed, 9 insertions(+), 1 deletion(-) | 21 | 1 file changed, 11 insertions(+), 3 deletions(-) |
9 | 22 | ||
10 | diff --git a/block.c b/block.c | 23 | diff --git a/block/io.c b/block/io.c |
11 | index XXXXXXX..XXXXXXX 100644 | 24 | index XXXXXXX..XXXXXXX 100644 |
12 | --- a/block.c | 25 | --- a/block/io.c |
13 | +++ b/block.c | 26 | +++ b/block/io.c |
14 | @@ -XXX,XX +XXX,XX @@ const BdrvChildClass child_of_bds = { | 27 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_drain_invoke_entry(void *opaque) |
15 | 28 | bdrv_wakeup(bs); | |
16 | AioContext *bdrv_child_get_parent_aio_context(BdrvChild *c) | 29 | } |
30 | |||
31 | +/* Recursively call BlockDriver.bdrv_co_drain_begin/end callbacks */ | ||
32 | static void bdrv_drain_invoke(BlockDriverState *bs, bool begin) | ||
17 | { | 33 | { |
18 | - IO_CODE(); | 34 | + BdrvChild *child, *tmp; |
19 | + GLOBAL_STATE_CODE(); | 35 | BdrvCoDrainData data = { .bs = bs, .done = false, .begin = begin}; |
20 | return c->klass->get_parent_aio_context(c); | 36 | |
37 | if (!bs->drv || (begin && !bs->drv->bdrv_co_drain_begin) || | ||
38 | @@ -XXX,XX +XXX,XX @@ static void bdrv_drain_invoke(BlockDriverState *bs, bool begin) | ||
39 | data.co = qemu_coroutine_create(bdrv_drain_invoke_entry, &data); | ||
40 | bdrv_coroutine_enter(bs, data.co); | ||
41 | BDRV_POLL_WHILE(bs, !data.done); | ||
42 | + | ||
43 | + QLIST_FOREACH_SAFE(child, &bs->children, next, tmp) { | ||
44 | + bdrv_drain_invoke(child->bs, begin); | ||
45 | + } | ||
21 | } | 46 | } |
22 | 47 | ||
23 | @@ -XXX,XX +XXX,XX @@ bool bdrv_is_writable(BlockDriverState *bs) | 48 | static bool bdrv_drain_recurse(BlockDriverState *bs, bool begin) |
24 | 49 | @@ -XXX,XX +XXX,XX @@ static bool bdrv_drain_recurse(BlockDriverState *bs, bool begin) | |
25 | static char *bdrv_child_user_desc(BdrvChild *c) | 50 | BdrvChild *child, *tmp; |
26 | { | 51 | bool waited; |
27 | + GLOBAL_STATE_CODE(); | 52 | |
28 | return c->klass->get_parent_desc(c); | 53 | - /* Ensure any pending metadata writes are submitted to bs->file. */ |
54 | - bdrv_drain_invoke(bs, begin); | ||
55 | - | ||
56 | /* Wait for drained requests to finish */ | ||
57 | waited = BDRV_POLL_WHILE(bs, atomic_read(&bs->in_flight) > 0); | ||
58 | |||
59 | @@ -XXX,XX +XXX,XX @@ void bdrv_drained_begin(BlockDriverState *bs) | ||
60 | bdrv_parent_drained_begin(bs); | ||
61 | } | ||
62 | |||
63 | + bdrv_drain_invoke(bs, true); | ||
64 | bdrv_drain_recurse(bs, true); | ||
29 | } | 65 | } |
30 | 66 | ||
31 | @@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_noperm(BdrvChild **childp, | 67 | @@ -XXX,XX +XXX,XX @@ void bdrv_drained_end(BlockDriverState *bs) |
32 | 68 | } | |
33 | assert(!child->frozen); | 69 | |
34 | assert(old_bs != new_bs); | 70 | bdrv_parent_drained_end(bs); |
35 | + GLOBAL_STATE_CODE(); | 71 | + bdrv_drain_invoke(bs, false); |
36 | 72 | bdrv_drain_recurse(bs, false); | |
37 | if (old_bs && new_bs) { | 73 | aio_enable_external(bdrv_get_aio_context(bs)); |
38 | assert(bdrv_get_aio_context(old_bs) == bdrv_get_aio_context(new_bs)); | 74 | } |
39 | @@ -XXX,XX +XXX,XX @@ static void bdrv_attach_child_common_abort(void *opaque) | 75 | @@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void) |
40 | BdrvChild *child = *s->child; | 76 | aio_context_acquire(aio_context); |
41 | BlockDriverState *bs = child->bs; | 77 | for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { |
42 | 78 | if (aio_context == bdrv_get_aio_context(bs)) { | |
43 | + GLOBAL_STATE_CODE(); | 79 | + /* FIXME Calling this multiple times is wrong */ |
44 | /* | 80 | + bdrv_drain_invoke(bs, true); |
45 | * Pass free_empty_child=false, because we still need the child | 81 | waited |= bdrv_drain_recurse(bs, true); |
46 | * for the AioContext operations on the parent below; those | 82 | } |
47 | @@ -XXX,XX +XXX,XX @@ void bdrv_unref_child(BlockDriverState *parent, BdrvChild *child) | 83 | } |
48 | static void bdrv_parent_cb_change_media(BlockDriverState *bs, bool load) | 84 | @@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_end(void) |
49 | { | 85 | aio_context_acquire(aio_context); |
50 | BdrvChild *c; | 86 | aio_enable_external(aio_context); |
51 | + GLOBAL_STATE_CODE(); | 87 | bdrv_parent_drained_end(bs); |
52 | QLIST_FOREACH(c, &bs->parents, next_parent) { | 88 | + bdrv_drain_invoke(bs, false); |
53 | if (c->klass->change_media) { | 89 | bdrv_drain_recurse(bs, false); |
54 | c->klass->change_media(c, load); | 90 | aio_context_release(aio_context); |
55 | @@ -XXX,XX +XXX,XX @@ static BlockDriverState *bdrv_open_inherit(const char *filename, | ||
56 | |||
57 | assert(!child_class || !flags); | ||
58 | assert(!child_class == !parent); | ||
59 | + GLOBAL_STATE_CODE(); | ||
60 | |||
61 | if (reference) { | ||
62 | bool options_non_empty = options ? qdict_size(options) : false; | ||
63 | @@ -XXX,XX +XXX,XX @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue, | ||
64 | * important to avoid graph changes between the recursive queuing here and | ||
65 | * bdrv_reopen_multiple(). */ | ||
66 | assert(bs->quiesce_counter > 0); | ||
67 | + GLOBAL_STATE_CODE(); | ||
68 | |||
69 | if (bs_queue == NULL) { | ||
70 | bs_queue = g_new0(BlockReopenQueue, 1); | ||
71 | @@ -XXX,XX +XXX,XX @@ void bdrv_set_aio_context_ignore(BlockDriverState *bs, | ||
72 | BdrvChild *child, *parent; | ||
73 | |||
74 | g_assert(qemu_get_current_aio_context() == qemu_get_aio_context()); | ||
75 | + GLOBAL_STATE_CODE(); | ||
76 | |||
77 | if (old_context == new_context) { | ||
78 | return; | ||
79 | @@ -XXX,XX +XXX,XX @@ void bdrv_set_aio_context_ignore(BlockDriverState *bs, | ||
80 | static bool bdrv_parent_can_set_aio_context(BdrvChild *c, AioContext *ctx, | ||
81 | GSList **ignore, Error **errp) | ||
82 | { | ||
83 | + GLOBAL_STATE_CODE(); | ||
84 | if (g_slist_find(*ignore, c)) { | ||
85 | return true; | ||
86 | } | 91 | } |
87 | -- | 92 | -- |
88 | 2.35.1 | 93 | 2.13.6 |
94 | |||
95 | diff view generated by jsdifflib |
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | 1 | bdrv_drain_all_begin() used to call the .bdrv_co_drain_begin() driver |
---|---|---|---|
2 | callback inside its polling loop. This means that how many times it got | ||
3 | called for each node depended on long it had to poll the event loop. | ||
2 | 4 | ||
3 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | 5 | This is obviously not right and results in nodes that stay drained even |
4 | Message-Id: <20220303151616.325444-13-eesposit@redhat.com> | 6 | after bdrv_drain_all_end(), which calls .bdrv_co_drain_begin() once per |
7 | node. | ||
8 | |||
9 | Fix bdrv_drain_all_begin() to call the callback only once, too. | ||
10 | |||
11 | Cc: qemu-stable@nongnu.org | ||
5 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
13 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
6 | --- | 14 | --- |
7 | block.c | 15 +++++++++++++++ | 15 | block/io.c | 3 +-- |
8 | block/backup.c | 1 + | 16 | 1 file changed, 1 insertion(+), 2 deletions(-) |
9 | block/block-backend.c | 3 +++ | ||
10 | block/commit.c | 2 ++ | ||
11 | block/dirty-bitmap.c | 1 + | ||
12 | block/io.c | 1 + | ||
13 | block/mirror.c | 4 ++++ | ||
14 | block/monitor/bitmap-qmp-cmds.c | 6 ++++++ | ||
15 | block/stream.c | 2 ++ | ||
16 | blockdev.c | 7 +++++++ | ||
17 | 10 files changed, 42 insertions(+) | ||
18 | 17 | ||
19 | diff --git a/block.c b/block.c | ||
20 | index XXXXXXX..XXXXXXX 100644 | ||
21 | --- a/block.c | ||
22 | +++ b/block.c | ||
23 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_create_opts_simple(BlockDriver *drv, | ||
24 | Error *local_err = NULL; | ||
25 | int ret; | ||
26 | |||
27 | + GLOBAL_STATE_CODE(); | ||
28 | + | ||
29 | size = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0); | ||
30 | buf = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC); | ||
31 | prealloc = qapi_enum_parse(&PreallocMode_lookup, buf, | ||
32 | @@ -XXX,XX +XXX,XX @@ void bdrv_get_cumulative_perm(BlockDriverState *bs, uint64_t *perm, | ||
33 | uint64_t cumulative_perms = 0; | ||
34 | uint64_t cumulative_shared_perms = BLK_PERM_ALL; | ||
35 | |||
36 | + GLOBAL_STATE_CODE(); | ||
37 | + | ||
38 | QLIST_FOREACH(c, &bs->parents, next_parent) { | ||
39 | cumulative_perms |= c->perm; | ||
40 | cumulative_shared_perms &= c->shared_perm; | ||
41 | @@ -XXX,XX +XXX,XX @@ int bdrv_child_try_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared, | ||
42 | Transaction *tran = tran_new(); | ||
43 | int ret; | ||
44 | |||
45 | + GLOBAL_STATE_CODE(); | ||
46 | + | ||
47 | bdrv_child_set_perm(c, perm, shared, tran); | ||
48 | |||
49 | ret = bdrv_refresh_perms(c->bs, &local_err); | ||
50 | @@ -XXX,XX +XXX,XX @@ int bdrv_child_refresh_perms(BlockDriverState *bs, BdrvChild *c, Error **errp) | ||
51 | uint64_t parent_perms, parent_shared; | ||
52 | uint64_t perms, shared; | ||
53 | |||
54 | + GLOBAL_STATE_CODE(); | ||
55 | + | ||
56 | bdrv_get_cumulative_perm(bs, &parent_perms, &parent_shared); | ||
57 | bdrv_child_perm(bs, c->bs, c, c->role, NULL, | ||
58 | parent_perms, parent_shared, &perms, &shared); | ||
59 | @@ -XXX,XX +XXX,XX @@ void bdrv_default_perms(BlockDriverState *bs, BdrvChild *c, | ||
60 | uint64_t perm, uint64_t shared, | ||
61 | uint64_t *nperm, uint64_t *nshared) | ||
62 | { | ||
63 | + GLOBAL_STATE_CODE(); | ||
64 | if (role & BDRV_CHILD_FILTERED) { | ||
65 | assert(!(role & (BDRV_CHILD_DATA | BDRV_CHILD_METADATA | | ||
66 | BDRV_CHILD_COW))); | ||
67 | @@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs, | ||
68 | BdrvChild *child = NULL; | ||
69 | Transaction *tran = tran_new(); | ||
70 | |||
71 | + GLOBAL_STATE_CODE(); | ||
72 | + | ||
73 | ret = bdrv_attach_child_common(child_bs, child_name, child_class, | ||
74 | child_role, perm, shared_perm, opaque, | ||
75 | &child, tran, errp); | ||
76 | @@ -XXX,XX +XXX,XX @@ bool bdrv_recurse_can_replace(BlockDriverState *bs, | ||
77 | { | ||
78 | BlockDriverState *filtered; | ||
79 | |||
80 | + GLOBAL_STATE_CODE(); | ||
81 | + | ||
82 | if (!bs || !bs->drv) { | ||
83 | return false; | ||
84 | } | ||
85 | @@ -XXX,XX +XXX,XX @@ static bool append_strong_runtime_options(QDict *d, BlockDriverState *bs) | ||
86 | * would result in exactly bs->backing. */ | ||
87 | static bool bdrv_backing_overridden(BlockDriverState *bs) | ||
88 | { | ||
89 | + GLOBAL_STATE_CODE(); | ||
90 | if (bs->backing) { | ||
91 | return strcmp(bs->auto_backing_file, | ||
92 | bs->backing->bs->filename); | ||
93 | @@ -XXX,XX +XXX,XX @@ static BlockDriverState *bdrv_do_skip_filters(BlockDriverState *bs, | ||
94 | */ | ||
95 | BlockDriverState *bdrv_skip_implicit_filters(BlockDriverState *bs) | ||
96 | { | ||
97 | + GLOBAL_STATE_CODE(); | ||
98 | return bdrv_do_skip_filters(bs, true); | ||
99 | } | ||
100 | |||
101 | diff --git a/block/backup.c b/block/backup.c | ||
102 | index XXXXXXX..XXXXXXX 100644 | ||
103 | --- a/block/backup.c | ||
104 | +++ b/block/backup.c | ||
105 | @@ -XXX,XX +XXX,XX @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, | ||
106 | |||
107 | assert(bs); | ||
108 | assert(target); | ||
109 | + GLOBAL_STATE_CODE(); | ||
110 | |||
111 | /* QMP interface protects us from these cases */ | ||
112 | assert(sync_mode != MIRROR_SYNC_MODE_INCREMENTAL); | ||
113 | diff --git a/block/block-backend.c b/block/block-backend.c | ||
114 | index XXXXXXX..XXXXXXX 100644 | ||
115 | --- a/block/block-backend.c | ||
116 | +++ b/block/block-backend.c | ||
117 | @@ -XXX,XX +XXX,XX @@ static void blk_root_change_media(BdrvChild *child, bool load) | ||
118 | */ | ||
119 | bool blk_dev_has_removable_media(BlockBackend *blk) | ||
120 | { | ||
121 | + GLOBAL_STATE_CODE(); | ||
122 | return !blk->dev || (blk->dev_ops && blk->dev_ops->change_media_cb); | ||
123 | } | ||
124 | |||
125 | @@ -XXX,XX +XXX,XX @@ bool blk_dev_has_tray(BlockBackend *blk) | ||
126 | */ | ||
127 | void blk_dev_eject_request(BlockBackend *blk, bool force) | ||
128 | { | ||
129 | + GLOBAL_STATE_CODE(); | ||
130 | if (blk->dev_ops && blk->dev_ops->eject_request_cb) { | ||
131 | blk->dev_ops->eject_request_cb(blk->dev_opaque, force); | ||
132 | } | ||
133 | @@ -XXX,XX +XXX,XX @@ bool blk_dev_is_tray_open(BlockBackend *blk) | ||
134 | */ | ||
135 | bool blk_dev_is_medium_locked(BlockBackend *blk) | ||
136 | { | ||
137 | + GLOBAL_STATE_CODE(); | ||
138 | if (blk->dev_ops && blk->dev_ops->is_medium_locked) { | ||
139 | return blk->dev_ops->is_medium_locked(blk->dev_opaque); | ||
140 | } | ||
141 | diff --git a/block/commit.c b/block/commit.c | ||
142 | index XXXXXXX..XXXXXXX 100644 | ||
143 | --- a/block/commit.c | ||
144 | +++ b/block/commit.c | ||
145 | @@ -XXX,XX +XXX,XX @@ void commit_start(const char *job_id, BlockDriverState *bs, | ||
146 | uint64_t base_perms, iter_shared_perms; | ||
147 | int ret; | ||
148 | |||
149 | + GLOBAL_STATE_CODE(); | ||
150 | + | ||
151 | assert(top != bs); | ||
152 | if (bdrv_skip_filters(top) == bdrv_skip_filters(base)) { | ||
153 | error_setg(errp, "Invalid files for merge: top and base are the same"); | ||
154 | diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c | ||
155 | index XXXXXXX..XXXXXXX 100644 | ||
156 | --- a/block/dirty-bitmap.c | ||
157 | +++ b/block/dirty-bitmap.c | ||
158 | @@ -XXX,XX +XXX,XX @@ void bdrv_restore_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap *backup) | ||
159 | { | ||
160 | HBitmap *tmp = bitmap->bitmap; | ||
161 | assert(!bdrv_dirty_bitmap_readonly(bitmap)); | ||
162 | + GLOBAL_STATE_CODE(); | ||
163 | bitmap->bitmap = backup; | ||
164 | hbitmap_free(tmp); | ||
165 | } | ||
166 | diff --git a/block/io.c b/block/io.c | 18 | diff --git a/block/io.c b/block/io.c |
167 | index XXXXXXX..XXXXXXX 100644 | 19 | index XXXXXXX..XXXXXXX 100644 |
168 | --- a/block/io.c | 20 | --- a/block/io.c |
169 | +++ b/block/io.c | 21 | +++ b/block/io.c |
170 | @@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void) | 22 | @@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void) |
171 | void bdrv_drain_all_end_quiesce(BlockDriverState *bs) | 23 | aio_context_acquire(aio_context); |
172 | { | 24 | bdrv_parent_drained_begin(bs); |
173 | int drained_end_counter = 0; | 25 | aio_disable_external(aio_context); |
174 | + GLOBAL_STATE_CODE(); | 26 | + bdrv_drain_invoke(bs, true); |
175 | 27 | aio_context_release(aio_context); | |
176 | g_assert(bs->quiesce_counter > 0); | 28 | |
177 | g_assert(!bs->refcnt); | 29 | if (!g_slist_find(aio_ctxs, aio_context)) { |
178 | diff --git a/block/mirror.c b/block/mirror.c | 30 | @@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void) |
179 | index XXXXXXX..XXXXXXX 100644 | 31 | aio_context_acquire(aio_context); |
180 | --- a/block/mirror.c | 32 | for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { |
181 | +++ b/block/mirror.c | 33 | if (aio_context == bdrv_get_aio_context(bs)) { |
182 | @@ -XXX,XX +XXX,XX @@ void mirror_start(const char *job_id, BlockDriverState *bs, | 34 | - /* FIXME Calling this multiple times is wrong */ |
183 | bool is_none_mode; | 35 | - bdrv_drain_invoke(bs, true); |
184 | BlockDriverState *base; | 36 | waited |= bdrv_drain_recurse(bs, true); |
185 | 37 | } | |
186 | + GLOBAL_STATE_CODE(); | 38 | } |
187 | + | ||
188 | if ((mode == MIRROR_SYNC_MODE_INCREMENTAL) || | ||
189 | (mode == MIRROR_SYNC_MODE_BITMAP)) { | ||
190 | error_setg(errp, "Sync mode '%s' not supported", | ||
191 | @@ -XXX,XX +XXX,XX @@ BlockJob *commit_active_start(const char *job_id, BlockDriverState *bs, | ||
192 | bool base_read_only; | ||
193 | BlockJob *job; | ||
194 | |||
195 | + GLOBAL_STATE_CODE(); | ||
196 | + | ||
197 | base_read_only = bdrv_is_read_only(base); | ||
198 | |||
199 | if (base_read_only) { | ||
200 | diff --git a/block/monitor/bitmap-qmp-cmds.c b/block/monitor/bitmap-qmp-cmds.c | ||
201 | index XXXXXXX..XXXXXXX 100644 | ||
202 | --- a/block/monitor/bitmap-qmp-cmds.c | ||
203 | +++ b/block/monitor/bitmap-qmp-cmds.c | ||
204 | @@ -XXX,XX +XXX,XX @@ BdrvDirtyBitmap *block_dirty_bitmap_lookup(const char *node, | ||
205 | BlockDriverState *bs; | ||
206 | BdrvDirtyBitmap *bitmap; | ||
207 | |||
208 | + GLOBAL_STATE_CODE(); | ||
209 | + | ||
210 | if (!node) { | ||
211 | error_setg(errp, "Node cannot be NULL"); | ||
212 | return NULL; | ||
213 | @@ -XXX,XX +XXX,XX @@ BdrvDirtyBitmap *block_dirty_bitmap_remove(const char *node, const char *name, | ||
214 | BdrvDirtyBitmap *bitmap; | ||
215 | AioContext *aio_context; | ||
216 | |||
217 | + GLOBAL_STATE_CODE(); | ||
218 | + | ||
219 | bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp); | ||
220 | if (!bitmap || !bs) { | ||
221 | return NULL; | ||
222 | @@ -XXX,XX +XXX,XX @@ BdrvDirtyBitmap *block_dirty_bitmap_merge(const char *node, const char *target, | ||
223 | BlockDirtyBitmapMergeSourceList *lst; | ||
224 | Error *local_err = NULL; | ||
225 | |||
226 | + GLOBAL_STATE_CODE(); | ||
227 | + | ||
228 | dst = block_dirty_bitmap_lookup(node, target, &bs, errp); | ||
229 | if (!dst) { | ||
230 | return NULL; | ||
231 | diff --git a/block/stream.c b/block/stream.c | ||
232 | index XXXXXXX..XXXXXXX 100644 | ||
233 | --- a/block/stream.c | ||
234 | +++ b/block/stream.c | ||
235 | @@ -XXX,XX +XXX,XX @@ void stream_start(const char *job_id, BlockDriverState *bs, | ||
236 | QDict *opts; | ||
237 | int ret; | ||
238 | |||
239 | + GLOBAL_STATE_CODE(); | ||
240 | + | ||
241 | assert(!(base && bottom)); | ||
242 | assert(!(backing_file_str && bottom)); | ||
243 | |||
244 | diff --git a/blockdev.c b/blockdev.c | ||
245 | index XXXXXXX..XXXXXXX 100644 | ||
246 | --- a/blockdev.c | ||
247 | +++ b/blockdev.c | ||
248 | @@ -XXX,XX +XXX,XX @@ QTAILQ_HEAD(, BlockDriverState) monitor_bdrv_states = | ||
249 | |||
250 | void bdrv_set_monitor_owned(BlockDriverState *bs) | ||
251 | { | ||
252 | + GLOBAL_STATE_CODE(); | ||
253 | QTAILQ_INSERT_TAIL(&monitor_bdrv_states, bs, monitor_list); | ||
254 | } | ||
255 | |||
256 | @@ -XXX,XX +XXX,XX @@ BlockDriverState *bds_tree_init(QDict *bs_opts, Error **errp) | ||
257 | { | ||
258 | int bdrv_flags = 0; | ||
259 | |||
260 | + GLOBAL_STATE_CODE(); | ||
261 | /* bdrv_open() defaults to the values in bdrv_flags (for compatibility | ||
262 | * with other callers) rather than what we want as the real defaults. | ||
263 | * Apply the defaults here instead. */ | ||
264 | @@ -XXX,XX +XXX,XX @@ void blockdev_close_all_bdrv_states(void) | ||
265 | { | ||
266 | BlockDriverState *bs, *next_bs; | ||
267 | |||
268 | + GLOBAL_STATE_CODE(); | ||
269 | QTAILQ_FOREACH_SAFE(bs, &monitor_bdrv_states, monitor_list, next_bs) { | ||
270 | AioContext *ctx = bdrv_get_aio_context(bs); | ||
271 | |||
272 | @@ -XXX,XX +XXX,XX @@ void qmp_transaction(TransactionActionList *dev_list, | ||
273 | BlkActionState *state, *next; | ||
274 | Error *local_err = NULL; | ||
275 | |||
276 | + GLOBAL_STATE_CODE(); | ||
277 | + | ||
278 | QTAILQ_HEAD(, BlkActionState) snap_bdrv_states; | ||
279 | QTAILQ_INIT(&snap_bdrv_states); | ||
280 | |||
281 | @@ -XXX,XX +XXX,XX @@ void qmp_blockdev_del(const char *node_name, Error **errp) | ||
282 | AioContext *aio_context; | ||
283 | BlockDriverState *bs; | ||
284 | |||
285 | + GLOBAL_STATE_CODE(); | ||
286 | + | ||
287 | bs = bdrv_find_node(node_name); | ||
288 | if (!bs) { | ||
289 | error_setg(errp, "Failed to find node with node-name='%s'", node_name); | ||
290 | -- | 39 | -- |
291 | 2.35.1 | 40 | 2.13.6 |
41 | |||
42 | diff view generated by jsdifflib |
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | 1 | This adds a test case that the BlockDriver callbacks for drain are |
---|---|---|---|
2 | called in bdrv_drained_all_begin/end(), and that both of them are called | ||
3 | exactly once. | ||
2 | 4 | ||
3 | block.h currently contains a mix of functions: | 5 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
4 | some of them run under the BQL and modify the block layer graph, | 6 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> |
5 | others are instead thread-safe and perform I/O in iothreads. | 7 | Reviewed-by: Eric Blake <eblake@redhat.com> |
6 | Some others can only be called by either the main loop or the | 8 | --- |
7 | iothread running the AioContext (and not other iothreads), | 9 | tests/test-bdrv-drain.c | 137 ++++++++++++++++++++++++++++++++++++++++++++++++ |
8 | and using them in another thread would cause deadlocks, and therefore | 10 | tests/Makefile.include | 2 + |
9 | it is not ideal to define them as I/O. | 11 | 2 files changed, 139 insertions(+) |
12 | create mode 100644 tests/test-bdrv-drain.c | ||
10 | 13 | ||
11 | It is not easy to understand which function is part of which | 14 | diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c |
12 | group (I/O vs GS vs "I/O or GS"), and this patch aims to clarify it. | ||
13 | |||
14 | The "GS" functions need the BQL, and often use | ||
15 | aio_context_acquire/release and/or drain to be sure they | ||
16 | can modify the graph safely. | ||
17 | The I/O function are instead thread safe, and can run in | ||
18 | any AioContext. | ||
19 | "I/O or GS" functions run instead in the main loop or in | ||
20 | a single iothread, and use BDRV_POLL_WHILE(). | ||
21 | |||
22 | By splitting the header in two files, block-io.h | ||
23 | and block-global-state.h we have a clearer view on what | ||
24 | needs what kind of protection. block-common.h | ||
25 | contains common structures shared by both headers. | ||
26 | |||
27 | block.h is left there for legacy and to avoid changing | ||
28 | all includes in all c files that use the block APIs. | ||
29 | |||
30 | Assertions are added in the next patch. | ||
31 | |||
32 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
33 | Message-Id: <20220303151616.325444-4-eesposit@redhat.com> | ||
34 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
35 | --- | ||
36 | include/block/block-common.h | 418 ++++++++++++++ | ||
37 | include/block/block-global-state.h | 253 +++++++++ | ||
38 | include/block/block-io.h | 367 ++++++++++++ | ||
39 | include/block/block.h | 879 +---------------------------- | ||
40 | block.c | 3 + | ||
41 | block/meson.build | 7 +- | ||
42 | 6 files changed, 1069 insertions(+), 858 deletions(-) | ||
43 | create mode 100644 include/block/block-common.h | ||
44 | create mode 100644 include/block/block-global-state.h | ||
45 | create mode 100644 include/block/block-io.h | ||
46 | |||
47 | diff --git a/include/block/block-common.h b/include/block/block-common.h | ||
48 | new file mode 100644 | 15 | new file mode 100644 |
49 | index XXXXXXX..XXXXXXX | 16 | index XXXXXXX..XXXXXXX |
50 | --- /dev/null | 17 | --- /dev/null |
51 | +++ b/include/block/block-common.h | 18 | +++ b/tests/test-bdrv-drain.c |
52 | @@ -XXX,XX +XXX,XX @@ | 19 | @@ -XXX,XX +XXX,XX @@ |
53 | +/* | 20 | +/* |
54 | + * QEMU System Emulator block driver | 21 | + * Block node draining tests |
55 | + * | 22 | + * |
56 | + * Copyright (c) 2003 Fabrice Bellard | 23 | + * Copyright (c) 2017 Kevin Wolf <kwolf@redhat.com> |
57 | + * | 24 | + * |
58 | + * Permission is hereby granted, free of charge, to any person obtaining a copy | 25 | + * Permission is hereby granted, free of charge, to any person obtaining a copy |
59 | + * of this software and associated documentation files (the "Software"), to deal | 26 | + * of this software and associated documentation files (the "Software"), to deal |
60 | + * in the Software without restriction, including without limitation the rights | 27 | + * in the Software without restriction, including without limitation the rights |
61 | + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | 28 | + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
... | ... | ||
71 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | 38 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
72 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | 39 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
73 | + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | 40 | + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
74 | + * THE SOFTWARE. | 41 | + * THE SOFTWARE. |
75 | + */ | 42 | + */ |
76 | +#ifndef BLOCK_COMMON_H | ||
77 | +#define BLOCK_COMMON_H | ||
78 | + | 43 | + |
79 | +#include "block/aio.h" | 44 | +#include "qemu/osdep.h" |
80 | +#include "block/aio-wait.h" | 45 | +#include "block/block.h" |
81 | +#include "qemu/iov.h" | 46 | +#include "sysemu/block-backend.h" |
82 | +#include "qemu/coroutine.h" | 47 | +#include "qapi/error.h" |
83 | +#include "block/accounting.h" | ||
84 | +#include "block/dirty-bitmap.h" | ||
85 | +#include "block/blockjob.h" | ||
86 | +#include "qemu/hbitmap.h" | ||
87 | +#include "qemu/transactions.h" | ||
88 | + | 48 | + |
89 | +/* | 49 | +typedef struct BDRVTestState { |
90 | + * generated_co_wrapper | 50 | + int drain_count; |
91 | + * | 51 | +} BDRVTestState; |
92 | + * Function specifier, which does nothing but mark functions to be | ||
93 | + * generated by scripts/block-coroutine-wrapper.py | ||
94 | + * | ||
95 | + * Read more in docs/devel/block-coroutine-wrapper.rst | ||
96 | + */ | ||
97 | +#define generated_co_wrapper | ||
98 | + | 52 | + |
99 | +/* block.c */ | 53 | +static void coroutine_fn bdrv_test_co_drain_begin(BlockDriverState *bs) |
100 | +typedef struct BlockDriver BlockDriver; | 54 | +{ |
101 | +typedef struct BdrvChild BdrvChild; | 55 | + BDRVTestState *s = bs->opaque; |
102 | +typedef struct BdrvChildClass BdrvChildClass; | 56 | + s->drain_count++; |
57 | +} | ||
103 | + | 58 | + |
104 | +typedef struct BlockDriverInfo { | 59 | +static void coroutine_fn bdrv_test_co_drain_end(BlockDriverState *bs) |
105 | + /* in bytes, 0 if irrelevant */ | 60 | +{ |
106 | + int cluster_size; | 61 | + BDRVTestState *s = bs->opaque; |
107 | + /* offset at which the VM state can be saved (0 if not possible) */ | 62 | + s->drain_count--; |
108 | + int64_t vm_state_offset; | 63 | +} |
109 | + bool is_dirty; | ||
110 | + /* | ||
111 | + * True if this block driver only supports compressed writes | ||
112 | + */ | ||
113 | + bool needs_compressed_writes; | ||
114 | +} BlockDriverInfo; | ||
115 | + | 64 | + |
116 | +typedef struct BlockFragInfo { | 65 | +static void bdrv_test_close(BlockDriverState *bs) |
117 | + uint64_t allocated_clusters; | 66 | +{ |
118 | + uint64_t total_clusters; | 67 | + BDRVTestState *s = bs->opaque; |
119 | + uint64_t fragmented_clusters; | 68 | + g_assert_cmpint(s->drain_count, >, 0); |
120 | + uint64_t compressed_clusters; | 69 | +} |
121 | +} BlockFragInfo; | ||
122 | + | 70 | + |
123 | +typedef enum { | 71 | +static int coroutine_fn bdrv_test_co_preadv(BlockDriverState *bs, |
124 | + BDRV_REQ_COPY_ON_READ = 0x1, | 72 | + uint64_t offset, uint64_t bytes, |
125 | + BDRV_REQ_ZERO_WRITE = 0x2, | 73 | + QEMUIOVector *qiov, int flags) |
74 | +{ | ||
75 | + /* We want this request to stay until the polling loop in drain waits for | ||
76 | + * it to complete. We need to sleep a while as bdrv_drain_invoke() comes | ||
77 | + * first and polls its result, too, but it shouldn't accidentally complete | ||
78 | + * this request yet. */ | ||
79 | + qemu_co_sleep_ns(QEMU_CLOCK_REALTIME, 100000); | ||
126 | + | 80 | + |
127 | + /* | 81 | + return 0; |
128 | + * The BDRV_REQ_MAY_UNMAP flag is used in write_zeroes requests to indicate | 82 | +} |
129 | + * that the block driver should unmap (discard) blocks if it is guaranteed | ||
130 | + * that the result will read back as zeroes. The flag is only passed to the | ||
131 | + * driver if the block device is opened with BDRV_O_UNMAP. | ||
132 | + */ | ||
133 | + BDRV_REQ_MAY_UNMAP = 0x4, | ||
134 | + | 83 | + |
135 | + BDRV_REQ_FUA = 0x10, | 84 | +static BlockDriver bdrv_test = { |
136 | + BDRV_REQ_WRITE_COMPRESSED = 0x20, | 85 | + .format_name = "test", |
86 | + .instance_size = sizeof(BDRVTestState), | ||
137 | + | 87 | + |
138 | + /* | 88 | + .bdrv_close = bdrv_test_close, |
139 | + * Signifies that this write request will not change the visible disk | 89 | + .bdrv_co_preadv = bdrv_test_co_preadv, |
140 | + * content. | ||
141 | + */ | ||
142 | + BDRV_REQ_WRITE_UNCHANGED = 0x40, | ||
143 | + | 90 | + |
144 | + /* | 91 | + .bdrv_co_drain_begin = bdrv_test_co_drain_begin, |
145 | + * Forces request serialisation. Use only with write requests. | 92 | + .bdrv_co_drain_end = bdrv_test_co_drain_end, |
146 | + */ | ||
147 | + BDRV_REQ_SERIALISING = 0x80, | ||
148 | + | ||
149 | + /* | ||
150 | + * Execute the request only if the operation can be offloaded or otherwise | ||
151 | + * be executed efficiently, but return an error instead of using a slow | ||
152 | + * fallback. | ||
153 | + */ | ||
154 | + BDRV_REQ_NO_FALLBACK = 0x100, | ||
155 | + | ||
156 | + /* | ||
157 | + * BDRV_REQ_PREFETCH makes sense only in the context of copy-on-read | ||
158 | + * (i.e., together with the BDRV_REQ_COPY_ON_READ flag or when a COR | ||
159 | + * filter is involved), in which case it signals that the COR operation | ||
160 | + * need not read the data into memory (qiov) but only ensure they are | ||
161 | + * copied to the top layer (i.e., that COR operation is done). | ||
162 | + */ | ||
163 | + BDRV_REQ_PREFETCH = 0x200, | ||
164 | + | ||
165 | + /* | ||
166 | + * If we need to wait for other requests, just fail immediately. Used | ||
167 | + * only together with BDRV_REQ_SERIALISING. | ||
168 | + */ | ||
169 | + BDRV_REQ_NO_WAIT = 0x400, | ||
170 | + | ||
171 | + /* Mask of valid flags */ | ||
172 | + BDRV_REQ_MASK = 0x7ff, | ||
173 | +} BdrvRequestFlags; | ||
174 | + | ||
175 | +#define BDRV_O_NO_SHARE 0x0001 /* don't share permissions */ | ||
176 | +#define BDRV_O_RDWR 0x0002 | ||
177 | +#define BDRV_O_RESIZE 0x0004 /* request permission for resizing the node */ | ||
178 | +#define BDRV_O_SNAPSHOT 0x0008 /* open the file read only and save | ||
179 | + writes in a snapshot */ | ||
180 | +#define BDRV_O_TEMPORARY 0x0010 /* delete the file after use */ | ||
181 | +#define BDRV_O_NOCACHE 0x0020 /* do not use the host page cache */ | ||
182 | +#define BDRV_O_NATIVE_AIO 0x0080 /* use native AIO instead of the | ||
183 | + thread pool */ | ||
184 | +#define BDRV_O_NO_BACKING 0x0100 /* don't open the backing file */ | ||
185 | +#define BDRV_O_NO_FLUSH 0x0200 /* disable flushing on this disk */ | ||
186 | +#define BDRV_O_COPY_ON_READ 0x0400 /* copy read backing sectors into image */ | ||
187 | +#define BDRV_O_INACTIVE 0x0800 /* consistency hint for migration handoff */ | ||
188 | +#define BDRV_O_CHECK 0x1000 /* open solely for consistency check */ | ||
189 | +#define BDRV_O_ALLOW_RDWR 0x2000 /* allow reopen to change from r/o to r/w */ | ||
190 | +#define BDRV_O_UNMAP 0x4000 /* execute guest UNMAP/TRIM operations */ | ||
191 | +#define BDRV_O_PROTOCOL 0x8000 /* if no block driver is explicitly given: | ||
192 | + select an appropriate protocol driver, | ||
193 | + ignoring the format layer */ | ||
194 | +#define BDRV_O_NO_IO 0x10000 /* don't initialize for I/O */ | ||
195 | +#define BDRV_O_AUTO_RDONLY 0x20000 /* degrade to read-only if opening | ||
196 | + read-write fails */ | ||
197 | +#define BDRV_O_IO_URING 0x40000 /* use io_uring instead of the thread pool */ | ||
198 | + | ||
199 | +#define BDRV_O_CACHE_MASK (BDRV_O_NOCACHE | BDRV_O_NO_FLUSH) | ||
200 | + | ||
201 | + | ||
202 | +/* Option names of options parsed by the block layer */ | ||
203 | + | ||
204 | +#define BDRV_OPT_CACHE_WB "cache.writeback" | ||
205 | +#define BDRV_OPT_CACHE_DIRECT "cache.direct" | ||
206 | +#define BDRV_OPT_CACHE_NO_FLUSH "cache.no-flush" | ||
207 | +#define BDRV_OPT_READ_ONLY "read-only" | ||
208 | +#define BDRV_OPT_AUTO_READ_ONLY "auto-read-only" | ||
209 | +#define BDRV_OPT_DISCARD "discard" | ||
210 | +#define BDRV_OPT_FORCE_SHARE "force-share" | ||
211 | + | ||
212 | + | ||
213 | +#define BDRV_SECTOR_BITS 9 | ||
214 | +#define BDRV_SECTOR_SIZE (1ULL << BDRV_SECTOR_BITS) | ||
215 | + | ||
216 | +#define BDRV_REQUEST_MAX_SECTORS MIN_CONST(SIZE_MAX >> BDRV_SECTOR_BITS, \ | ||
217 | + INT_MAX >> BDRV_SECTOR_BITS) | ||
218 | +#define BDRV_REQUEST_MAX_BYTES (BDRV_REQUEST_MAX_SECTORS << BDRV_SECTOR_BITS) | ||
219 | + | ||
220 | +/* | ||
221 | + * We want allow aligning requests and disk length up to any 32bit alignment | ||
222 | + * and don't afraid of overflow. | ||
223 | + * To achieve it, and in the same time use some pretty number as maximum disk | ||
224 | + * size, let's define maximum "length" (a limit for any offset/bytes request and | ||
225 | + * for disk size) to be the greatest power of 2 less than INT64_MAX. | ||
226 | + */ | ||
227 | +#define BDRV_MAX_ALIGNMENT (1L << 30) | ||
228 | +#define BDRV_MAX_LENGTH (QEMU_ALIGN_DOWN(INT64_MAX, BDRV_MAX_ALIGNMENT)) | ||
229 | + | ||
230 | +/* | ||
231 | + * Allocation status flags for bdrv_block_status() and friends. | ||
232 | + * | ||
233 | + * Public flags: | ||
234 | + * BDRV_BLOCK_DATA: allocation for data at offset is tied to this layer | ||
235 | + * BDRV_BLOCK_ZERO: offset reads as zero | ||
236 | + * BDRV_BLOCK_OFFSET_VALID: an associated offset exists for accessing raw data | ||
237 | + * BDRV_BLOCK_ALLOCATED: the content of the block is determined by this | ||
238 | + * layer rather than any backing, set by block layer | ||
239 | + * BDRV_BLOCK_EOF: the returned pnum covers through end of file for this | ||
240 | + * layer, set by block layer | ||
241 | + * | ||
242 | + * Internal flags: | ||
243 | + * BDRV_BLOCK_RAW: for use by passthrough drivers, such as raw, to request | ||
244 | + * that the block layer recompute the answer from the returned | ||
245 | + * BDS; must be accompanied by just BDRV_BLOCK_OFFSET_VALID. | ||
246 | + * BDRV_BLOCK_RECURSE: request that the block layer will recursively search for | ||
247 | + * zeroes in file child of current block node inside | ||
248 | + * returned region. Only valid together with both | ||
249 | + * BDRV_BLOCK_DATA and BDRV_BLOCK_OFFSET_VALID. Should not | ||
250 | + * appear with BDRV_BLOCK_ZERO. | ||
251 | + * | ||
252 | + * If BDRV_BLOCK_OFFSET_VALID is set, the map parameter represents the | ||
253 | + * host offset within the returned BDS that is allocated for the | ||
254 | + * corresponding raw guest data. However, whether that offset | ||
255 | + * actually contains data also depends on BDRV_BLOCK_DATA, as follows: | ||
256 | + * | ||
257 | + * DATA ZERO OFFSET_VALID | ||
258 | + * t t t sectors read as zero, returned file is zero at offset | ||
259 | + * t f t sectors read as valid from file at offset | ||
260 | + * f t t sectors preallocated, read as zero, returned file not | ||
261 | + * necessarily zero at offset | ||
262 | + * f f t sectors preallocated but read from backing_hd, | ||
263 | + * returned file contains garbage at offset | ||
264 | + * t t f sectors preallocated, read as zero, unknown offset | ||
265 | + * t f f sectors read from unknown file or offset | ||
266 | + * f t f not allocated or unknown offset, read as zero | ||
267 | + * f f f not allocated or unknown offset, read from backing_hd | ||
268 | + */ | ||
269 | +#define BDRV_BLOCK_DATA 0x01 | ||
270 | +#define BDRV_BLOCK_ZERO 0x02 | ||
271 | +#define BDRV_BLOCK_OFFSET_VALID 0x04 | ||
272 | +#define BDRV_BLOCK_RAW 0x08 | ||
273 | +#define BDRV_BLOCK_ALLOCATED 0x10 | ||
274 | +#define BDRV_BLOCK_EOF 0x20 | ||
275 | +#define BDRV_BLOCK_RECURSE 0x40 | ||
276 | + | ||
277 | +typedef QTAILQ_HEAD(BlockReopenQueue, BlockReopenQueueEntry) BlockReopenQueue; | ||
278 | + | ||
279 | +typedef struct BDRVReopenState { | ||
280 | + BlockDriverState *bs; | ||
281 | + int flags; | ||
282 | + BlockdevDetectZeroesOptions detect_zeroes; | ||
283 | + bool backing_missing; | ||
284 | + BlockDriverState *old_backing_bs; /* keep pointer for permissions update */ | ||
285 | + BlockDriverState *old_file_bs; /* keep pointer for permissions update */ | ||
286 | + QDict *options; | ||
287 | + QDict *explicit_options; | ||
288 | + void *opaque; | ||
289 | +} BDRVReopenState; | ||
290 | + | ||
291 | +/* | ||
292 | + * Block operation types | ||
293 | + */ | ||
294 | +typedef enum BlockOpType { | ||
295 | + BLOCK_OP_TYPE_BACKUP_SOURCE, | ||
296 | + BLOCK_OP_TYPE_BACKUP_TARGET, | ||
297 | + BLOCK_OP_TYPE_CHANGE, | ||
298 | + BLOCK_OP_TYPE_COMMIT_SOURCE, | ||
299 | + BLOCK_OP_TYPE_COMMIT_TARGET, | ||
300 | + BLOCK_OP_TYPE_DATAPLANE, | ||
301 | + BLOCK_OP_TYPE_DRIVE_DEL, | ||
302 | + BLOCK_OP_TYPE_EJECT, | ||
303 | + BLOCK_OP_TYPE_EXTERNAL_SNAPSHOT, | ||
304 | + BLOCK_OP_TYPE_INTERNAL_SNAPSHOT, | ||
305 | + BLOCK_OP_TYPE_INTERNAL_SNAPSHOT_DELETE, | ||
306 | + BLOCK_OP_TYPE_MIRROR_SOURCE, | ||
307 | + BLOCK_OP_TYPE_MIRROR_TARGET, | ||
308 | + BLOCK_OP_TYPE_RESIZE, | ||
309 | + BLOCK_OP_TYPE_STREAM, | ||
310 | + BLOCK_OP_TYPE_REPLACE, | ||
311 | + BLOCK_OP_TYPE_MAX, | ||
312 | +} BlockOpType; | ||
313 | + | ||
314 | +/* Block node permission constants */ | ||
315 | +enum { | ||
316 | + /** | ||
317 | + * A user that has the "permission" of consistent reads is guaranteed that | ||
318 | + * their view of the contents of the block device is complete and | ||
319 | + * self-consistent, representing the contents of a disk at a specific | ||
320 | + * point. | ||
321 | + * | ||
322 | + * For most block devices (including their backing files) this is true, but | ||
323 | + * the property cannot be maintained in a few situations like for | ||
324 | + * intermediate nodes of a commit block job. | ||
325 | + */ | ||
326 | + BLK_PERM_CONSISTENT_READ = 0x01, | ||
327 | + | ||
328 | + /** This permission is required to change the visible disk contents. */ | ||
329 | + BLK_PERM_WRITE = 0x02, | ||
330 | + | ||
331 | + /** | ||
332 | + * This permission (which is weaker than BLK_PERM_WRITE) is both enough and | ||
333 | + * required for writes to the block node when the caller promises that | ||
334 | + * the visible disk content doesn't change. | ||
335 | + * | ||
336 | + * As the BLK_PERM_WRITE permission is strictly stronger, either is | ||
337 | + * sufficient to perform an unchanging write. | ||
338 | + */ | ||
339 | + BLK_PERM_WRITE_UNCHANGED = 0x04, | ||
340 | + | ||
341 | + /** This permission is required to change the size of a block node. */ | ||
342 | + BLK_PERM_RESIZE = 0x08, | ||
343 | + | ||
344 | + /** | ||
345 | + * There was a now-removed bit BLK_PERM_GRAPH_MOD, with value of 0x10. QEMU | ||
346 | + * 6.1 and earlier may still lock the corresponding byte in block/file-posix | ||
347 | + * locking. So, implementing some new permission should be very careful to | ||
348 | + * not interfere with this old unused thing. | ||
349 | + */ | ||
350 | + | ||
351 | + BLK_PERM_ALL = 0x0f, | ||
352 | + | ||
353 | + DEFAULT_PERM_PASSTHROUGH = BLK_PERM_CONSISTENT_READ | ||
354 | + | BLK_PERM_WRITE | ||
355 | + | BLK_PERM_WRITE_UNCHANGED | ||
356 | + | BLK_PERM_RESIZE, | ||
357 | + | ||
358 | + DEFAULT_PERM_UNCHANGED = BLK_PERM_ALL & ~DEFAULT_PERM_PASSTHROUGH, | ||
359 | +}; | 93 | +}; |
360 | + | 94 | + |
361 | +/* | 95 | +static void aio_ret_cb(void *opaque, int ret) |
362 | + * Flags that parent nodes assign to child nodes to specify what kind of | 96 | +{ |
363 | + * role(s) they take. | 97 | + int *aio_ret = opaque; |
364 | + * | 98 | + *aio_ret = ret; |
365 | + * At least one of DATA, METADATA, FILTERED, or COW must be set for | 99 | +} |
366 | + * every child. | ||
367 | + */ | ||
368 | +enum BdrvChildRoleBits { | ||
369 | + /* | ||
370 | + * This child stores data. | ||
371 | + * Any node may have an arbitrary number of such children. | ||
372 | + */ | ||
373 | + BDRV_CHILD_DATA = (1 << 0), | ||
374 | + | 100 | + |
375 | + /* | 101 | +static void test_drv_cb_drain_all(void) |
376 | + * This child stores metadata. | 102 | +{ |
377 | + * Any node may have an arbitrary number of metadata-storing | ||
378 | + * children. | ||
379 | + */ | ||
380 | + BDRV_CHILD_METADATA = (1 << 1), | ||
381 | + | ||
382 | + /* | ||
383 | + * A child that always presents exactly the same visible data as | ||
384 | + * the parent, e.g. by virtue of the parent forwarding all reads | ||
385 | + * and writes. | ||
386 | + * This flag is mutually exclusive with DATA, METADATA, and COW. | ||
387 | + * Any node may have at most one filtered child at a time. | ||
388 | + */ | ||
389 | + BDRV_CHILD_FILTERED = (1 << 2), | ||
390 | + | ||
391 | + /* | ||
392 | + * Child from which to read all data that isn't allocated in the | ||
393 | + * parent (i.e., the backing child); such data is copied to the | ||
394 | + * parent through COW (and optionally COR). | ||
395 | + * This field is mutually exclusive with DATA, METADATA, and | ||
396 | + * FILTERED. | ||
397 | + * Any node may have at most one such backing child at a time. | ||
398 | + */ | ||
399 | + BDRV_CHILD_COW = (1 << 3), | ||
400 | + | ||
401 | + /* | ||
402 | + * The primary child. For most drivers, this is the child whose | ||
403 | + * filename applies best to the parent node. | ||
404 | + * Any node may have at most one primary child at a time. | ||
405 | + */ | ||
406 | + BDRV_CHILD_PRIMARY = (1 << 4), | ||
407 | + | ||
408 | + /* Useful combination of flags */ | ||
409 | + BDRV_CHILD_IMAGE = BDRV_CHILD_DATA | ||
410 | + | BDRV_CHILD_METADATA | ||
411 | + | BDRV_CHILD_PRIMARY, | ||
412 | +}; | ||
413 | + | ||
414 | +/* Mask of BdrvChildRoleBits values */ | ||
415 | +typedef unsigned int BdrvChildRole; | ||
416 | + | ||
417 | +typedef struct BdrvCheckResult { | ||
418 | + int corruptions; | ||
419 | + int leaks; | ||
420 | + int check_errors; | ||
421 | + int corruptions_fixed; | ||
422 | + int leaks_fixed; | ||
423 | + int64_t image_end_offset; | ||
424 | + BlockFragInfo bfi; | ||
425 | +} BdrvCheckResult; | ||
426 | + | ||
427 | +typedef enum { | ||
428 | + BDRV_FIX_LEAKS = 1, | ||
429 | + BDRV_FIX_ERRORS = 2, | ||
430 | +} BdrvCheckMode; | ||
431 | + | ||
432 | +typedef struct BlockSizes { | ||
433 | + uint32_t phys; | ||
434 | + uint32_t log; | ||
435 | +} BlockSizes; | ||
436 | + | ||
437 | +typedef struct HDGeometry { | ||
438 | + uint32_t heads; | ||
439 | + uint32_t sectors; | ||
440 | + uint32_t cylinders; | ||
441 | +} HDGeometry; | ||
442 | + | ||
443 | +/* | ||
444 | + * Common functions that are neither I/O nor Global State. | ||
445 | + * | ||
446 | + * These functions must never call any function from other categories | ||
447 | + * (I/O, "I/O or GS", Global State) except this one, but can be invoked by | ||
448 | + * all of them. | ||
449 | + */ | ||
450 | + | ||
451 | +char *bdrv_perm_names(uint64_t perm); | ||
452 | +uint64_t bdrv_qapi_perm_to_blk_perm(BlockPermission qapi_perm); | ||
453 | + | ||
454 | +void bdrv_init_with_whitelist(void); | ||
455 | +bool bdrv_uses_whitelist(void); | ||
456 | +int bdrv_is_whitelisted(BlockDriver *drv, bool read_only); | ||
457 | + | ||
458 | +int bdrv_parse_aio(const char *mode, int *flags); | ||
459 | +int bdrv_parse_cache_mode(const char *mode, int *flags, bool *writethrough); | ||
460 | +int bdrv_parse_discard_flags(const char *mode, int *flags); | ||
461 | + | ||
462 | +int path_has_protocol(const char *path); | ||
463 | +int path_is_absolute(const char *path); | ||
464 | +char *path_combine(const char *base_path, const char *filename); | ||
465 | + | ||
466 | +char *bdrv_get_full_backing_filename_from_filename(const char *backed, | ||
467 | + const char *backing, | ||
468 | + Error **errp); | ||
469 | + | ||
470 | +#endif /* BLOCK_COMMON_H */ | ||
471 | diff --git a/include/block/block-global-state.h b/include/block/block-global-state.h | ||
472 | new file mode 100644 | ||
473 | index XXXXXXX..XXXXXXX | ||
474 | --- /dev/null | ||
475 | +++ b/include/block/block-global-state.h | ||
476 | @@ -XXX,XX +XXX,XX @@ | ||
477 | +/* | ||
478 | + * QEMU System Emulator block driver | ||
479 | + * | ||
480 | + * Copyright (c) 2003 Fabrice Bellard | ||
481 | + * | ||
482 | + * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
483 | + * of this software and associated documentation files (the "Software"), to deal | ||
484 | + * in the Software without restriction, including without limitation the rights | ||
485 | + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
486 | + * copies of the Software, and to permit persons to whom the Software is | ||
487 | + * furnished to do so, subject to the following conditions: | ||
488 | + * | ||
489 | + * The above copyright notice and this permission notice shall be included in | ||
490 | + * all copies or substantial portions of the Software. | ||
491 | + * | ||
492 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
493 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
494 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
495 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
496 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
497 | + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
498 | + * THE SOFTWARE. | ||
499 | + */ | ||
500 | +#ifndef BLOCK_GLOBAL_STATE_H | ||
501 | +#define BLOCK_GLOBAL_STATE_H | ||
502 | + | ||
503 | +#include "block-common.h" | ||
504 | + | ||
505 | +/* | ||
506 | + * Global state (GS) API. These functions run under the BQL. | ||
507 | + * | ||
508 | + * If a function modifies the graph, it also uses drain and/or | ||
509 | + * aio_context_acquire/release to be sure it has unique access. | ||
510 | + * aio_context locking is needed together with BQL because of | ||
511 | + * the thread-safe I/O API that concurrently runs and accesses | ||
512 | + * the graph without the BQL. | ||
513 | + * | ||
514 | + * It is important to note that not all of these functions are | ||
515 | + * necessarily limited to running under the BQL, but they would | ||
516 | + * require additional auditing and many small thread-safety changes | ||
517 | + * to move them into the I/O API. Often it's not worth doing that | ||
518 | + * work since the APIs are only used with the BQL held at the | ||
519 | + * moment, so they have been placed in the GS API (for now). | ||
520 | + * | ||
521 | + * These functions can call any function from this and other categories | ||
522 | + * (I/O, "I/O or GS", Common), but must be invoked only by other GS APIs. | ||
523 | + * | ||
524 | + * All functions in this header must use the macro | ||
525 | + * GLOBAL_STATE_CODE(); | ||
526 | + * to catch when they are accidentally called without the BQL. | ||
527 | + */ | ||
528 | + | ||
529 | +void bdrv_init(void); | ||
530 | +BlockDriver *bdrv_find_protocol(const char *filename, | ||
531 | + bool allow_protocol_prefix, | ||
532 | + Error **errp); | ||
533 | +BlockDriver *bdrv_find_format(const char *format_name); | ||
534 | +int bdrv_create(BlockDriver *drv, const char* filename, | ||
535 | + QemuOpts *opts, Error **errp); | ||
536 | +int bdrv_create_file(const char *filename, QemuOpts *opts, Error **errp); | ||
537 | + | ||
538 | +BlockDriverState *bdrv_new(void); | ||
539 | +int bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top, | ||
540 | + Error **errp); | ||
541 | +int bdrv_replace_node(BlockDriverState *from, BlockDriverState *to, | ||
542 | + Error **errp); | ||
543 | +int bdrv_replace_child_bs(BdrvChild *child, BlockDriverState *new_bs, | ||
544 | + Error **errp); | ||
545 | +BlockDriverState *bdrv_insert_node(BlockDriverState *bs, QDict *node_options, | ||
546 | + int flags, Error **errp); | ||
547 | +int bdrv_drop_filter(BlockDriverState *bs, Error **errp); | ||
548 | + | ||
549 | +BdrvChild *bdrv_open_child(const char *filename, | ||
550 | + QDict *options, const char *bdref_key, | ||
551 | + BlockDriverState *parent, | ||
552 | + const BdrvChildClass *child_class, | ||
553 | + BdrvChildRole child_role, | ||
554 | + bool allow_none, Error **errp); | ||
555 | +BlockDriverState *bdrv_open_blockdev_ref(BlockdevRef *ref, Error **errp); | ||
556 | +int bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd, | ||
557 | + Error **errp); | ||
558 | +int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options, | ||
559 | + const char *bdref_key, Error **errp); | ||
560 | +BlockDriverState *bdrv_open(const char *filename, const char *reference, | ||
561 | + QDict *options, int flags, Error **errp); | ||
562 | +BlockDriverState *bdrv_new_open_driver_opts(BlockDriver *drv, | ||
563 | + const char *node_name, | ||
564 | + QDict *options, int flags, | ||
565 | + Error **errp); | ||
566 | +BlockDriverState *bdrv_new_open_driver(BlockDriver *drv, const char *node_name, | ||
567 | + int flags, Error **errp); | ||
568 | +BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue, | ||
569 | + BlockDriverState *bs, QDict *options, | ||
570 | + bool keep_old_opts); | ||
571 | +void bdrv_reopen_queue_free(BlockReopenQueue *bs_queue); | ||
572 | +int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp); | ||
573 | +int bdrv_reopen(BlockDriverState *bs, QDict *opts, bool keep_old_opts, | ||
574 | + Error **errp); | ||
575 | +int bdrv_reopen_set_read_only(BlockDriverState *bs, bool read_only, | ||
576 | + Error **errp); | ||
577 | +BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs, | ||
578 | + const char *backing_file); | ||
579 | +void bdrv_refresh_filename(BlockDriverState *bs); | ||
580 | +void bdrv_refresh_limits(BlockDriverState *bs, Transaction *tran, Error **errp); | ||
581 | +int bdrv_commit(BlockDriverState *bs); | ||
582 | +int bdrv_make_empty(BdrvChild *c, Error **errp); | ||
583 | +int bdrv_change_backing_file(BlockDriverState *bs, const char *backing_file, | ||
584 | + const char *backing_fmt, bool warn); | ||
585 | +void bdrv_register(BlockDriver *bdrv); | ||
586 | +int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base, | ||
587 | + const char *backing_file_str); | ||
588 | +BlockDriverState *bdrv_find_overlay(BlockDriverState *active, | ||
589 | + BlockDriverState *bs); | ||
590 | +BlockDriverState *bdrv_find_base(BlockDriverState *bs); | ||
591 | +bool bdrv_is_backing_chain_frozen(BlockDriverState *bs, BlockDriverState *base, | ||
592 | + Error **errp); | ||
593 | +int bdrv_freeze_backing_chain(BlockDriverState *bs, BlockDriverState *base, | ||
594 | + Error **errp); | ||
595 | +void bdrv_unfreeze_backing_chain(BlockDriverState *bs, BlockDriverState *base); | ||
596 | + | ||
597 | +/* | ||
598 | + * The units of offset and total_work_size may be chosen arbitrarily by the | ||
599 | + * block driver; total_work_size may change during the course of the amendment | ||
600 | + * operation | ||
601 | + */ | ||
602 | +typedef void BlockDriverAmendStatusCB(BlockDriverState *bs, int64_t offset, | ||
603 | + int64_t total_work_size, void *opaque); | ||
604 | +int bdrv_amend_options(BlockDriverState *bs_new, QemuOpts *opts, | ||
605 | + BlockDriverAmendStatusCB *status_cb, void *cb_opaque, | ||
606 | + bool force, | ||
607 | + Error **errp); | ||
608 | + | ||
609 | +/* check if a named node can be replaced when doing drive-mirror */ | ||
610 | +BlockDriverState *check_to_replace_node(BlockDriverState *parent_bs, | ||
611 | + const char *node_name, Error **errp); | ||
612 | + | ||
613 | +int bdrv_activate(BlockDriverState *bs, Error **errp); | ||
614 | +void bdrv_activate_all(Error **errp); | ||
615 | +int bdrv_inactivate_all(void); | ||
616 | + | ||
617 | +int bdrv_flush_all(void); | ||
618 | +void bdrv_close_all(void); | ||
619 | +void bdrv_drain_all_begin(void); | ||
620 | +void bdrv_drain_all_end(void); | ||
621 | +void bdrv_drain_all(void); | ||
622 | + | ||
623 | +int bdrv_has_zero_init_1(BlockDriverState *bs); | ||
624 | +int bdrv_has_zero_init(BlockDriverState *bs); | ||
625 | +BlockDriverState *bdrv_find_node(const char *node_name); | ||
626 | +BlockDeviceInfoList *bdrv_named_nodes_list(bool flat, Error **errp); | ||
627 | +XDbgBlockGraph *bdrv_get_xdbg_block_graph(Error **errp); | ||
628 | +BlockDriverState *bdrv_lookup_bs(const char *device, | ||
629 | + const char *node_name, | ||
630 | + Error **errp); | ||
631 | +bool bdrv_chain_contains(BlockDriverState *top, BlockDriverState *base); | ||
632 | +BlockDriverState *bdrv_next_node(BlockDriverState *bs); | ||
633 | +BlockDriverState *bdrv_next_all_states(BlockDriverState *bs); | ||
634 | + | ||
635 | +typedef struct BdrvNextIterator { | ||
636 | + enum { | ||
637 | + BDRV_NEXT_BACKEND_ROOTS, | ||
638 | + BDRV_NEXT_MONITOR_OWNED, | ||
639 | + } phase; | ||
640 | + BlockBackend *blk; | 103 | + BlockBackend *blk; |
641 | + BlockDriverState *bs; | 104 | + BlockDriverState *bs; |
642 | +} BdrvNextIterator; | 105 | + BDRVTestState *s; |
106 | + BlockAIOCB *acb; | ||
107 | + int aio_ret; | ||
643 | + | 108 | + |
644 | +BlockDriverState *bdrv_first(BdrvNextIterator *it); | 109 | + QEMUIOVector qiov; |
645 | +BlockDriverState *bdrv_next(BdrvNextIterator *it); | 110 | + struct iovec iov = { |
646 | +void bdrv_next_cleanup(BdrvNextIterator *it); | 111 | + .iov_base = NULL, |
112 | + .iov_len = 0, | ||
113 | + }; | ||
114 | + qemu_iovec_init_external(&qiov, &iov, 1); | ||
647 | + | 115 | + |
648 | +BlockDriverState *bdrv_next_monitor_owned(BlockDriverState *bs); | 116 | + blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL); |
649 | +void bdrv_iterate_format(void (*it)(void *opaque, const char *name), | 117 | + bs = bdrv_new_open_driver(&bdrv_test, "test-node", BDRV_O_RDWR, |
650 | + void *opaque, bool read_only); | 118 | + &error_abort); |
651 | +int bdrv_get_flags(BlockDriverState *bs); | 119 | + s = bs->opaque; |
652 | +char *bdrv_get_full_backing_filename(BlockDriverState *bs, Error **errp); | 120 | + blk_insert_bs(blk, bs, &error_abort); |
653 | +char *bdrv_dirname(BlockDriverState *bs, Error **errp); | ||
654 | + | 121 | + |
655 | +void bdrv_img_create(const char *filename, const char *fmt, | 122 | + /* Simple bdrv_drain_all_begin/end pair, check that CBs are called */ |
656 | + const char *base_filename, const char *base_fmt, | 123 | + g_assert_cmpint(s->drain_count, ==, 0); |
657 | + char *options, uint64_t img_size, int flags, | 124 | + bdrv_drain_all_begin(); |
658 | + bool quiet, Error **errp); | 125 | + g_assert_cmpint(s->drain_count, ==, 1); |
126 | + bdrv_drain_all_end(); | ||
127 | + g_assert_cmpint(s->drain_count, ==, 0); | ||
659 | + | 128 | + |
660 | +void bdrv_ref(BlockDriverState *bs); | 129 | + /* Now do the same while a request is pending */ |
661 | +void bdrv_unref(BlockDriverState *bs); | 130 | + aio_ret = -EINPROGRESS; |
662 | +void bdrv_unref_child(BlockDriverState *parent, BdrvChild *child); | 131 | + acb = blk_aio_preadv(blk, 0, &qiov, 0, aio_ret_cb, &aio_ret); |
663 | +BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs, | 132 | + g_assert(acb != NULL); |
664 | + BlockDriverState *child_bs, | 133 | + g_assert_cmpint(aio_ret, ==, -EINPROGRESS); |
665 | + const char *child_name, | ||
666 | + const BdrvChildClass *child_class, | ||
667 | + BdrvChildRole child_role, | ||
668 | + Error **errp); | ||
669 | + | 134 | + |
670 | +bool bdrv_op_is_blocked(BlockDriverState *bs, BlockOpType op, Error **errp); | 135 | + g_assert_cmpint(s->drain_count, ==, 0); |
671 | +void bdrv_op_block(BlockDriverState *bs, BlockOpType op, Error *reason); | 136 | + bdrv_drain_all_begin(); |
672 | +void bdrv_op_unblock(BlockDriverState *bs, BlockOpType op, Error *reason); | 137 | + g_assert_cmpint(aio_ret, ==, 0); |
673 | +void bdrv_op_block_all(BlockDriverState *bs, Error *reason); | 138 | + g_assert_cmpint(s->drain_count, ==, 1); |
674 | +void bdrv_op_unblock_all(BlockDriverState *bs, Error *reason); | 139 | + bdrv_drain_all_end(); |
675 | +bool bdrv_op_blocker_is_empty(BlockDriverState *bs); | 140 | + g_assert_cmpint(s->drain_count, ==, 0); |
676 | + | 141 | + |
677 | +int bdrv_debug_breakpoint(BlockDriverState *bs, const char *event, | 142 | + bdrv_unref(bs); |
678 | + const char *tag); | 143 | + blk_unref(blk); |
679 | +int bdrv_debug_remove_breakpoint(BlockDriverState *bs, const char *tag); | 144 | +} |
680 | +int bdrv_debug_resume(BlockDriverState *bs, const char *tag); | ||
681 | +bool bdrv_debug_is_suspended(BlockDriverState *bs, const char *tag); | ||
682 | + | 145 | + |
683 | +/** | 146 | +int main(int argc, char **argv) |
684 | + * Locks the AioContext of @bs if it's not the current AioContext. This avoids | 147 | +{ |
685 | + * double locking which could lead to deadlocks: This is a coroutine_fn, so we | 148 | + bdrv_init(); |
686 | + * know we already own the lock of the current AioContext. | 149 | + qemu_init_main_loop(&error_abort); |
687 | + * | ||
688 | + * May only be called in the main thread. | ||
689 | + */ | ||
690 | +void coroutine_fn bdrv_co_lock(BlockDriverState *bs); | ||
691 | + | 150 | + |
692 | +/** | 151 | + g_test_init(&argc, &argv, NULL); |
693 | + * Unlocks the AioContext of @bs if it's not the current AioContext. | ||
694 | + */ | ||
695 | +void coroutine_fn bdrv_co_unlock(BlockDriverState *bs); | ||
696 | + | 152 | + |
697 | +void bdrv_set_aio_context_ignore(BlockDriverState *bs, | 153 | + g_test_add_func("/bdrv-drain/driver-cb/drain_all", test_drv_cb_drain_all); |
698 | + AioContext *new_context, GSList **ignore); | ||
699 | +int bdrv_try_set_aio_context(BlockDriverState *bs, AioContext *ctx, | ||
700 | + Error **errp); | ||
701 | +int bdrv_child_try_set_aio_context(BlockDriverState *bs, AioContext *ctx, | ||
702 | + BdrvChild *ignore_child, Error **errp); | ||
703 | +bool bdrv_child_can_set_aio_context(BdrvChild *c, AioContext *ctx, | ||
704 | + GSList **ignore, Error **errp); | ||
705 | +bool bdrv_can_set_aio_context(BlockDriverState *bs, AioContext *ctx, | ||
706 | + GSList **ignore, Error **errp); | ||
707 | +AioContext *bdrv_child_get_parent_aio_context(BdrvChild *c); | ||
708 | + | 154 | + |
709 | +int bdrv_probe_blocksizes(BlockDriverState *bs, BlockSizes *bsz); | 155 | + return g_test_run(); |
710 | +int bdrv_probe_geometry(BlockDriverState *bs, HDGeometry *geo); | 156 | +} |
711 | + | 157 | diff --git a/tests/Makefile.include b/tests/Makefile.include |
712 | +void bdrv_add_child(BlockDriverState *parent, BlockDriverState *child, | ||
713 | + Error **errp); | ||
714 | +void bdrv_del_child(BlockDriverState *parent, BdrvChild *child, Error **errp); | ||
715 | + | ||
716 | +/** | ||
717 | + * | ||
718 | + * bdrv_register_buf/bdrv_unregister_buf: | ||
719 | + * | ||
720 | + * Register/unregister a buffer for I/O. For example, VFIO drivers are | ||
721 | + * interested to know the memory areas that would later be used for I/O, so | ||
722 | + * that they can prepare IOMMU mapping etc., to get better performance. | ||
723 | + */ | ||
724 | +void bdrv_register_buf(BlockDriverState *bs, void *host, size_t size); | ||
725 | +void bdrv_unregister_buf(BlockDriverState *bs, void *host); | ||
726 | + | ||
727 | +void bdrv_cancel_in_flight(BlockDriverState *bs); | ||
728 | + | ||
729 | +#endif /* BLOCK_GLOBAL_STATE_H */ | ||
730 | diff --git a/include/block/block-io.h b/include/block/block-io.h | ||
731 | new file mode 100644 | ||
732 | index XXXXXXX..XXXXXXX | ||
733 | --- /dev/null | ||
734 | +++ b/include/block/block-io.h | ||
735 | @@ -XXX,XX +XXX,XX @@ | ||
736 | +/* | ||
737 | + * QEMU System Emulator block driver | ||
738 | + * | ||
739 | + * Copyright (c) 2003 Fabrice Bellard | ||
740 | + * | ||
741 | + * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
742 | + * of this software and associated documentation files (the "Software"), to deal | ||
743 | + * in the Software without restriction, including without limitation the rights | ||
744 | + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
745 | + * copies of the Software, and to permit persons to whom the Software is | ||
746 | + * furnished to do so, subject to the following conditions: | ||
747 | + * | ||
748 | + * The above copyright notice and this permission notice shall be included in | ||
749 | + * all copies or substantial portions of the Software. | ||
750 | + * | ||
751 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
752 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
753 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
754 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
755 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
756 | + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
757 | + * THE SOFTWARE. | ||
758 | + */ | ||
759 | +#ifndef BLOCK_IO_H | ||
760 | +#define BLOCK_IO_H | ||
761 | + | ||
762 | +#include "block-common.h" | ||
763 | + | ||
764 | +/* | ||
765 | + * I/O API functions. These functions are thread-safe, and therefore | ||
766 | + * can run in any thread as long as the thread has called | ||
767 | + * aio_context_acquire/release(). | ||
768 | + * | ||
769 | + * These functions can only call functions from I/O and Common categories, | ||
770 | + * but can be invoked by GS, "I/O or GS" and I/O APIs. | ||
771 | + * | ||
772 | + * All functions in this category must use the macro | ||
773 | + * IO_CODE(); | ||
774 | + * to catch when they are accidentally called by the wrong API. | ||
775 | + */ | ||
776 | + | ||
777 | +int bdrv_pwrite_zeroes(BdrvChild *child, int64_t offset, | ||
778 | + int64_t bytes, BdrvRequestFlags flags); | ||
779 | +int bdrv_make_zero(BdrvChild *child, BdrvRequestFlags flags); | ||
780 | +int bdrv_pread(BdrvChild *child, int64_t offset, void *buf, int64_t bytes); | ||
781 | +int bdrv_pwrite(BdrvChild *child, int64_t offset, const void *buf, | ||
782 | + int64_t bytes); | ||
783 | +int bdrv_pwrite_sync(BdrvChild *child, int64_t offset, | ||
784 | + const void *buf, int64_t bytes); | ||
785 | +/* | ||
786 | + * Efficiently zero a region of the disk image. Note that this is a regular | ||
787 | + * I/O request like read or write and should have a reasonable size. This | ||
788 | + * function is not suitable for zeroing the entire image in a single request | ||
789 | + * because it may allocate memory for the entire region. | ||
790 | + */ | ||
791 | +int coroutine_fn bdrv_co_pwrite_zeroes(BdrvChild *child, int64_t offset, | ||
792 | + int64_t bytes, BdrvRequestFlags flags); | ||
793 | + | ||
794 | +int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact, | ||
795 | + PreallocMode prealloc, BdrvRequestFlags flags, | ||
796 | + Error **errp); | ||
797 | + | ||
798 | +int64_t bdrv_nb_sectors(BlockDriverState *bs); | ||
799 | +int64_t bdrv_getlength(BlockDriverState *bs); | ||
800 | +int64_t bdrv_get_allocated_file_size(BlockDriverState *bs); | ||
801 | +BlockMeasureInfo *bdrv_measure(BlockDriver *drv, QemuOpts *opts, | ||
802 | + BlockDriverState *in_bs, Error **errp); | ||
803 | +void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr); | ||
804 | +int coroutine_fn bdrv_co_delete_file(BlockDriverState *bs, Error **errp); | ||
805 | +void coroutine_fn bdrv_co_delete_file_noerr(BlockDriverState *bs); | ||
806 | + | ||
807 | + | ||
808 | +/* async block I/O */ | ||
809 | +void bdrv_aio_cancel(BlockAIOCB *acb); | ||
810 | +void bdrv_aio_cancel_async(BlockAIOCB *acb); | ||
811 | + | ||
812 | +/* sg packet commands */ | ||
813 | +int bdrv_co_ioctl(BlockDriverState *bs, int req, void *buf); | ||
814 | + | ||
815 | +/* Ensure contents are flushed to disk. */ | ||
816 | +int coroutine_fn bdrv_co_flush(BlockDriverState *bs); | ||
817 | + | ||
818 | +int bdrv_co_pdiscard(BdrvChild *child, int64_t offset, int64_t bytes); | ||
819 | +bool bdrv_can_write_zeroes_with_unmap(BlockDriverState *bs); | ||
820 | +int bdrv_block_status(BlockDriverState *bs, int64_t offset, | ||
821 | + int64_t bytes, int64_t *pnum, int64_t *map, | ||
822 | + BlockDriverState **file); | ||
823 | +int bdrv_block_status_above(BlockDriverState *bs, BlockDriverState *base, | ||
824 | + int64_t offset, int64_t bytes, int64_t *pnum, | ||
825 | + int64_t *map, BlockDriverState **file); | ||
826 | +int bdrv_is_allocated(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
827 | + int64_t *pnum); | ||
828 | +int bdrv_is_allocated_above(BlockDriverState *top, BlockDriverState *base, | ||
829 | + bool include_base, int64_t offset, int64_t bytes, | ||
830 | + int64_t *pnum); | ||
831 | +int coroutine_fn bdrv_co_is_zero_fast(BlockDriverState *bs, int64_t offset, | ||
832 | + int64_t bytes); | ||
833 | + | ||
834 | +int bdrv_can_set_read_only(BlockDriverState *bs, bool read_only, | ||
835 | + bool ignore_allow_rdw, Error **errp); | ||
836 | +int bdrv_apply_auto_read_only(BlockDriverState *bs, const char *errmsg, | ||
837 | + Error **errp); | ||
838 | +bool bdrv_is_read_only(BlockDriverState *bs); | ||
839 | +bool bdrv_is_writable(BlockDriverState *bs); | ||
840 | +bool bdrv_is_sg(BlockDriverState *bs); | ||
841 | +bool bdrv_is_inserted(BlockDriverState *bs); | ||
842 | +void bdrv_lock_medium(BlockDriverState *bs, bool locked); | ||
843 | +void bdrv_eject(BlockDriverState *bs, bool eject_flag); | ||
844 | +const char *bdrv_get_format_name(BlockDriverState *bs); | ||
845 | + | ||
846 | +bool bdrv_supports_compressed_writes(BlockDriverState *bs); | ||
847 | +const char *bdrv_get_node_name(const BlockDriverState *bs); | ||
848 | +const char *bdrv_get_device_name(const BlockDriverState *bs); | ||
849 | +const char *bdrv_get_device_or_node_name(const BlockDriverState *bs); | ||
850 | +int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi); | ||
851 | +ImageInfoSpecific *bdrv_get_specific_info(BlockDriverState *bs, | ||
852 | + Error **errp); | ||
853 | +BlockStatsSpecific *bdrv_get_specific_stats(BlockDriverState *bs); | ||
854 | +void bdrv_round_to_clusters(BlockDriverState *bs, | ||
855 | + int64_t offset, int64_t bytes, | ||
856 | + int64_t *cluster_offset, | ||
857 | + int64_t *cluster_bytes); | ||
858 | + | ||
859 | +void bdrv_get_backing_filename(BlockDriverState *bs, | ||
860 | + char *filename, int filename_size); | ||
861 | + | ||
862 | +int bdrv_save_vmstate(BlockDriverState *bs, const uint8_t *buf, | ||
863 | + int64_t pos, int size); | ||
864 | + | ||
865 | +int bdrv_load_vmstate(BlockDriverState *bs, uint8_t *buf, | ||
866 | + int64_t pos, int size); | ||
867 | + | ||
868 | +/* | ||
869 | + * Returns the alignment in bytes that is required so that no bounce buffer | ||
870 | + * is required throughout the stack | ||
871 | + */ | ||
872 | +size_t bdrv_min_mem_align(BlockDriverState *bs); | ||
873 | +/* Returns optimal alignment in bytes for bounce buffer */ | ||
874 | +size_t bdrv_opt_mem_align(BlockDriverState *bs); | ||
875 | +void *qemu_blockalign(BlockDriverState *bs, size_t size); | ||
876 | +void *qemu_blockalign0(BlockDriverState *bs, size_t size); | ||
877 | +void *qemu_try_blockalign(BlockDriverState *bs, size_t size); | ||
878 | +void *qemu_try_blockalign0(BlockDriverState *bs, size_t size); | ||
879 | +bool bdrv_qiov_is_aligned(BlockDriverState *bs, QEMUIOVector *qiov); | ||
880 | + | ||
881 | +void bdrv_enable_copy_on_read(BlockDriverState *bs); | ||
882 | +void bdrv_disable_copy_on_read(BlockDriverState *bs); | ||
883 | + | ||
884 | +void bdrv_debug_event(BlockDriverState *bs, BlkdebugEvent event); | ||
885 | + | ||
886 | +#define BLKDBG_EVENT(child, evt) \ | ||
887 | + do { \ | ||
888 | + if (child) { \ | ||
889 | + bdrv_debug_event(child->bs, evt); \ | ||
890 | + } \ | ||
891 | + } while (0) | ||
892 | + | ||
893 | +/** | ||
894 | + * bdrv_get_aio_context: | ||
895 | + * | ||
896 | + * Returns: the currently bound #AioContext | ||
897 | + */ | ||
898 | +AioContext *bdrv_get_aio_context(BlockDriverState *bs); | ||
899 | + | ||
900 | +/** | ||
901 | + * Move the current coroutine to the AioContext of @bs and return the old | ||
902 | + * AioContext of the coroutine. Increase bs->in_flight so that draining @bs | ||
903 | + * will wait for the operation to proceed until the corresponding | ||
904 | + * bdrv_co_leave(). | ||
905 | + * | ||
906 | + * Consequently, you can't call drain inside a bdrv_co_enter/leave() section as | ||
907 | + * this will deadlock. | ||
908 | + */ | ||
909 | +AioContext *coroutine_fn bdrv_co_enter(BlockDriverState *bs); | ||
910 | + | ||
911 | +/** | ||
912 | + * Ends a section started by bdrv_co_enter(). Move the current coroutine back | ||
913 | + * to old_ctx and decrease bs->in_flight again. | ||
914 | + */ | ||
915 | +void coroutine_fn bdrv_co_leave(BlockDriverState *bs, AioContext *old_ctx); | ||
916 | + | ||
917 | +/** | ||
918 | + * Transfer control to @co in the aio context of @bs | ||
919 | + */ | ||
920 | +void bdrv_coroutine_enter(BlockDriverState *bs, Coroutine *co); | ||
921 | + | ||
922 | +AioContext *child_of_bds_get_parent_aio_context(BdrvChild *c); | ||
923 | + | ||
924 | +void bdrv_io_plug(BlockDriverState *bs); | ||
925 | +void bdrv_io_unplug(BlockDriverState *bs); | ||
926 | + | ||
927 | +bool bdrv_can_store_new_dirty_bitmap(BlockDriverState *bs, const char *name, | ||
928 | + uint32_t granularity, Error **errp); | ||
929 | + | ||
930 | +/** | ||
931 | + * | ||
932 | + * bdrv_co_copy_range: | ||
933 | + * | ||
934 | + * Do offloaded copy between two children. If the operation is not implemented | ||
935 | + * by the driver, or if the backend storage doesn't support it, a negative | ||
936 | + * error code will be returned. | ||
937 | + * | ||
938 | + * Note: block layer doesn't emulate or fallback to a bounce buffer approach | ||
939 | + * because usually the caller shouldn't attempt offloaded copy any more (e.g. | ||
940 | + * calling copy_file_range(2)) after the first error, thus it should fall back | ||
941 | + * to a read+write path in the caller level. | ||
942 | + * | ||
943 | + * @src: Source child to copy data from | ||
944 | + * @src_offset: offset in @src image to read data | ||
945 | + * @dst: Destination child to copy data to | ||
946 | + * @dst_offset: offset in @dst image to write data | ||
947 | + * @bytes: number of bytes to copy | ||
948 | + * @flags: request flags. Supported flags: | ||
949 | + * BDRV_REQ_ZERO_WRITE - treat the @src range as zero data and do zero | ||
950 | + * write on @dst as if bdrv_co_pwrite_zeroes is | ||
951 | + * called. Used to simplify caller code, or | ||
952 | + * during BlockDriver.bdrv_co_copy_range_from() | ||
953 | + * recursion. | ||
954 | + * BDRV_REQ_NO_SERIALISING - do not serialize with other overlapping | ||
955 | + * requests currently in flight. | ||
956 | + * | ||
957 | + * Returns: 0 if succeeded; negative error code if failed. | ||
958 | + **/ | ||
959 | +int coroutine_fn bdrv_co_copy_range(BdrvChild *src, int64_t src_offset, | ||
960 | + BdrvChild *dst, int64_t dst_offset, | ||
961 | + int64_t bytes, BdrvRequestFlags read_flags, | ||
962 | + BdrvRequestFlags write_flags); | ||
963 | + | ||
964 | +/** | ||
965 | + * bdrv_drained_end_no_poll: | ||
966 | + * | ||
967 | + * Same as bdrv_drained_end(), but do not poll for the subgraph to | ||
968 | + * actually become unquiesced. Therefore, no graph changes will occur | ||
969 | + * with this function. | ||
970 | + * | ||
971 | + * *drained_end_counter is incremented for every background operation | ||
972 | + * that is scheduled, and will be decremented for every operation once | ||
973 | + * it settles. The caller must poll until it reaches 0. The counter | ||
974 | + * should be accessed using atomic operations only. | ||
975 | + */ | ||
976 | +void bdrv_drained_end_no_poll(BlockDriverState *bs, int *drained_end_counter); | ||
977 | + | ||
978 | + | ||
979 | +/* | ||
980 | + * "I/O or GS" API functions. These functions can run without | ||
981 | + * the BQL, but only in one specific iothread/main loop. | ||
982 | + * | ||
983 | + * More specifically, these functions use BDRV_POLL_WHILE(bs), which | ||
984 | + * requires the caller to be either in the main thread and hold | ||
985 | + * the BlockdriverState (bs) AioContext lock, or directly in the | ||
986 | + * home thread that runs the bs AioContext. Calling them from | ||
987 | + * another thread in another AioContext would cause deadlocks. | ||
988 | + * | ||
989 | + * Therefore, these functions are not proper I/O, because they | ||
990 | + * can't run in *any* iothreads, but only in a specific one. | ||
991 | + * | ||
992 | + * These functions can call any function from I/O, Common and this | ||
993 | + * categories, but must be invoked only by other "I/O or GS" and GS APIs. | ||
994 | + * | ||
995 | + * All functions in this category must use the macro | ||
996 | + * IO_OR_GS_CODE(); | ||
997 | + * to catch when they are accidentally called by the wrong API. | ||
998 | + */ | ||
999 | + | ||
1000 | +#define BDRV_POLL_WHILE(bs, cond) ({ \ | ||
1001 | + BlockDriverState *bs_ = (bs); \ | ||
1002 | + AIO_WAIT_WHILE(bdrv_get_aio_context(bs_), \ | ||
1003 | + cond); }) | ||
1004 | + | ||
1005 | +void bdrv_drain(BlockDriverState *bs); | ||
1006 | +void coroutine_fn bdrv_co_drain(BlockDriverState *bs); | ||
1007 | + | ||
1008 | +int generated_co_wrapper | ||
1009 | +bdrv_truncate(BdrvChild *child, int64_t offset, bool exact, | ||
1010 | + PreallocMode prealloc, BdrvRequestFlags flags, Error **errp); | ||
1011 | + | ||
1012 | +int generated_co_wrapper bdrv_check(BlockDriverState *bs, BdrvCheckResult *res, | ||
1013 | + BdrvCheckMode fix); | ||
1014 | + | ||
1015 | +/* Invalidate any cached metadata used by image formats */ | ||
1016 | +int generated_co_wrapper bdrv_invalidate_cache(BlockDriverState *bs, | ||
1017 | + Error **errp); | ||
1018 | +int generated_co_wrapper bdrv_flush(BlockDriverState *bs); | ||
1019 | +int generated_co_wrapper bdrv_pdiscard(BdrvChild *child, int64_t offset, | ||
1020 | + int64_t bytes); | ||
1021 | +int generated_co_wrapper | ||
1022 | +bdrv_readv_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos); | ||
1023 | +int generated_co_wrapper | ||
1024 | +bdrv_writev_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos); | ||
1025 | + | ||
1026 | +/** | ||
1027 | + * bdrv_parent_drained_begin_single: | ||
1028 | + * | ||
1029 | + * Begin a quiesced section for the parent of @c. If @poll is true, wait for | ||
1030 | + * any pending activity to cease. | ||
1031 | + */ | ||
1032 | +void bdrv_parent_drained_begin_single(BdrvChild *c, bool poll); | ||
1033 | + | ||
1034 | +/** | ||
1035 | + * bdrv_parent_drained_end_single: | ||
1036 | + * | ||
1037 | + * End a quiesced section for the parent of @c. | ||
1038 | + * | ||
1039 | + * This polls @bs's AioContext until all scheduled sub-drained_ends | ||
1040 | + * have settled, which may result in graph changes. | ||
1041 | + */ | ||
1042 | +void bdrv_parent_drained_end_single(BdrvChild *c); | ||
1043 | + | ||
1044 | +/** | ||
1045 | + * bdrv_drain_poll: | ||
1046 | + * | ||
1047 | + * Poll for pending requests in @bs, its parents (except for @ignore_parent), | ||
1048 | + * and if @recursive is true its children as well (used for subtree drain). | ||
1049 | + * | ||
1050 | + * If @ignore_bds_parents is true, parents that are BlockDriverStates must | ||
1051 | + * ignore the drain request because they will be drained separately (used for | ||
1052 | + * drain_all). | ||
1053 | + * | ||
1054 | + * This is part of bdrv_drained_begin. | ||
1055 | + */ | ||
1056 | +bool bdrv_drain_poll(BlockDriverState *bs, bool recursive, | ||
1057 | + BdrvChild *ignore_parent, bool ignore_bds_parents); | ||
1058 | + | ||
1059 | +/** | ||
1060 | + * bdrv_drained_begin: | ||
1061 | + * | ||
1062 | + * Begin a quiesced section for exclusive access to the BDS, by disabling | ||
1063 | + * external request sources including NBD server, block jobs, and device model. | ||
1064 | + * | ||
1065 | + * This function can be recursive. | ||
1066 | + */ | ||
1067 | +void bdrv_drained_begin(BlockDriverState *bs); | ||
1068 | + | ||
1069 | +/** | ||
1070 | + * bdrv_do_drained_begin_quiesce: | ||
1071 | + * | ||
1072 | + * Quiesces a BDS like bdrv_drained_begin(), but does not wait for already | ||
1073 | + * running requests to complete. | ||
1074 | + */ | ||
1075 | +void bdrv_do_drained_begin_quiesce(BlockDriverState *bs, | ||
1076 | + BdrvChild *parent, bool ignore_bds_parents); | ||
1077 | + | ||
1078 | +/** | ||
1079 | + * Like bdrv_drained_begin, but recursively begins a quiesced section for | ||
1080 | + * exclusive access to all child nodes as well. | ||
1081 | + */ | ||
1082 | +void bdrv_subtree_drained_begin(BlockDriverState *bs); | ||
1083 | + | ||
1084 | +/** | ||
1085 | + * bdrv_drained_end: | ||
1086 | + * | ||
1087 | + * End a quiescent section started by bdrv_drained_begin(). | ||
1088 | + * | ||
1089 | + * This polls @bs's AioContext until all scheduled sub-drained_ends | ||
1090 | + * have settled. On one hand, that may result in graph changes. On | ||
1091 | + * the other, this requires that the caller either runs in the main | ||
1092 | + * loop; or that all involved nodes (@bs and all of its parents) are | ||
1093 | + * in the caller's AioContext. | ||
1094 | + */ | ||
1095 | +void bdrv_drained_end(BlockDriverState *bs); | ||
1096 | + | ||
1097 | +/** | ||
1098 | + * End a quiescent section started by bdrv_subtree_drained_begin(). | ||
1099 | + */ | ||
1100 | +void bdrv_subtree_drained_end(BlockDriverState *bs); | ||
1101 | + | ||
1102 | +#endif /* BLOCK_IO_H */ | ||
1103 | diff --git a/include/block/block.h b/include/block/block.h | ||
1104 | index XXXXXXX..XXXXXXX 100644 | 158 | index XXXXXXX..XXXXXXX 100644 |
1105 | --- a/include/block/block.h | 159 | --- a/tests/Makefile.include |
1106 | +++ b/include/block/block.h | 160 | +++ b/tests/Makefile.include |
1107 | @@ -XXX,XX +XXX,XX @@ | 161 | @@ -XXX,XX +XXX,XX @@ gcov-files-test-thread-pool-y = thread-pool.c |
1108 | -#ifndef BLOCK_H | 162 | gcov-files-test-hbitmap-y = util/hbitmap.c |
1109 | -#define BLOCK_H | 163 | check-unit-y += tests/test-hbitmap$(EXESUF) |
1110 | - | 164 | gcov-files-test-hbitmap-y = blockjob.c |
1111 | -#include "block/aio.h" | 165 | +check-unit-y += tests/test-bdrv-drain$(EXESUF) |
1112 | -#include "block/aio-wait.h" | 166 | check-unit-y += tests/test-blockjob$(EXESUF) |
1113 | -#include "qemu/iov.h" | 167 | check-unit-y += tests/test-blockjob-txn$(EXESUF) |
1114 | -#include "qemu/coroutine.h" | 168 | check-unit-y += tests/test-x86-cpuid$(EXESUF) |
1115 | -#include "block/accounting.h" | 169 | @@ -XXX,XX +XXX,XX @@ tests/test-coroutine$(EXESUF): tests/test-coroutine.o $(test-block-obj-y) |
1116 | -#include "block/dirty-bitmap.h" | 170 | tests/test-aio$(EXESUF): tests/test-aio.o $(test-block-obj-y) |
1117 | -#include "block/blockjob.h" | 171 | tests/test-aio-multithread$(EXESUF): tests/test-aio-multithread.o $(test-block-obj-y) |
1118 | -#include "qemu/hbitmap.h" | 172 | tests/test-throttle$(EXESUF): tests/test-throttle.o $(test-block-obj-y) |
1119 | -#include "qemu/transactions.h" | 173 | +tests/test-bdrv-drain$(EXESUF): tests/test-bdrv-drain.o $(test-block-obj-y) $(test-util-obj-y) |
1120 | - | 174 | tests/test-blockjob$(EXESUF): tests/test-blockjob.o $(test-block-obj-y) $(test-util-obj-y) |
1121 | /* | 175 | tests/test-blockjob-txn$(EXESUF): tests/test-blockjob-txn.o $(test-block-obj-y) $(test-util-obj-y) |
1122 | - * generated_co_wrapper | 176 | tests/test-thread-pool$(EXESUF): tests/test-thread-pool.o $(test-block-obj-y) |
1123 | - * | ||
1124 | - * Function specifier, which does nothing but mark functions to be | ||
1125 | - * generated by scripts/block-coroutine-wrapper.py | ||
1126 | - * | ||
1127 | - * Read more in docs/devel/block-coroutine-wrapper.rst | ||
1128 | - */ | ||
1129 | -#define generated_co_wrapper | ||
1130 | - | ||
1131 | -/* block.c */ | ||
1132 | -typedef struct BlockDriver BlockDriver; | ||
1133 | -typedef struct BdrvChild BdrvChild; | ||
1134 | -typedef struct BdrvChildClass BdrvChildClass; | ||
1135 | - | ||
1136 | -typedef struct BlockDriverInfo { | ||
1137 | - /* in bytes, 0 if irrelevant */ | ||
1138 | - int cluster_size; | ||
1139 | - /* offset at which the VM state can be saved (0 if not possible) */ | ||
1140 | - int64_t vm_state_offset; | ||
1141 | - bool is_dirty; | ||
1142 | - /* | ||
1143 | - * True if this block driver only supports compressed writes | ||
1144 | - */ | ||
1145 | - bool needs_compressed_writes; | ||
1146 | -} BlockDriverInfo; | ||
1147 | - | ||
1148 | -typedef struct BlockFragInfo { | ||
1149 | - uint64_t allocated_clusters; | ||
1150 | - uint64_t total_clusters; | ||
1151 | - uint64_t fragmented_clusters; | ||
1152 | - uint64_t compressed_clusters; | ||
1153 | -} BlockFragInfo; | ||
1154 | - | ||
1155 | -typedef enum { | ||
1156 | - BDRV_REQ_COPY_ON_READ = 0x1, | ||
1157 | - BDRV_REQ_ZERO_WRITE = 0x2, | ||
1158 | - | ||
1159 | - /* | ||
1160 | - * The BDRV_REQ_MAY_UNMAP flag is used in write_zeroes requests to indicate | ||
1161 | - * that the block driver should unmap (discard) blocks if it is guaranteed | ||
1162 | - * that the result will read back as zeroes. The flag is only passed to the | ||
1163 | - * driver if the block device is opened with BDRV_O_UNMAP. | ||
1164 | - */ | ||
1165 | - BDRV_REQ_MAY_UNMAP = 0x4, | ||
1166 | - | ||
1167 | - BDRV_REQ_FUA = 0x10, | ||
1168 | - BDRV_REQ_WRITE_COMPRESSED = 0x20, | ||
1169 | - | ||
1170 | - /* Signifies that this write request will not change the visible disk | ||
1171 | - * content. */ | ||
1172 | - BDRV_REQ_WRITE_UNCHANGED = 0x40, | ||
1173 | - | ||
1174 | - /* Forces request serialisation. Use only with write requests. */ | ||
1175 | - BDRV_REQ_SERIALISING = 0x80, | ||
1176 | - | ||
1177 | - /* Execute the request only if the operation can be offloaded or otherwise | ||
1178 | - * be executed efficiently, but return an error instead of using a slow | ||
1179 | - * fallback. */ | ||
1180 | - BDRV_REQ_NO_FALLBACK = 0x100, | ||
1181 | - | ||
1182 | - /* | ||
1183 | - * BDRV_REQ_PREFETCH makes sense only in the context of copy-on-read | ||
1184 | - * (i.e., together with the BDRV_REQ_COPY_ON_READ flag or when a COR | ||
1185 | - * filter is involved), in which case it signals that the COR operation | ||
1186 | - * need not read the data into memory (qiov) but only ensure they are | ||
1187 | - * copied to the top layer (i.e., that COR operation is done). | ||
1188 | - */ | ||
1189 | - BDRV_REQ_PREFETCH = 0x200, | ||
1190 | - | ||
1191 | - /* | ||
1192 | - * If we need to wait for other requests, just fail immediately. Used | ||
1193 | - * only together with BDRV_REQ_SERIALISING. | ||
1194 | - */ | ||
1195 | - BDRV_REQ_NO_WAIT = 0x400, | ||
1196 | - | ||
1197 | - /* Mask of valid flags */ | ||
1198 | - BDRV_REQ_MASK = 0x7ff, | ||
1199 | -} BdrvRequestFlags; | ||
1200 | - | ||
1201 | -typedef struct BlockSizes { | ||
1202 | - uint32_t phys; | ||
1203 | - uint32_t log; | ||
1204 | -} BlockSizes; | ||
1205 | - | ||
1206 | -typedef struct HDGeometry { | ||
1207 | - uint32_t heads; | ||
1208 | - uint32_t sectors; | ||
1209 | - uint32_t cylinders; | ||
1210 | -} HDGeometry; | ||
1211 | - | ||
1212 | -#define BDRV_O_NO_SHARE 0x0001 /* don't share permissions */ | ||
1213 | -#define BDRV_O_RDWR 0x0002 | ||
1214 | -#define BDRV_O_RESIZE 0x0004 /* request permission for resizing the node */ | ||
1215 | -#define BDRV_O_SNAPSHOT 0x0008 /* open the file read only and save writes in a snapshot */ | ||
1216 | -#define BDRV_O_TEMPORARY 0x0010 /* delete the file after use */ | ||
1217 | -#define BDRV_O_NOCACHE 0x0020 /* do not use the host page cache */ | ||
1218 | -#define BDRV_O_NATIVE_AIO 0x0080 /* use native AIO instead of the thread pool */ | ||
1219 | -#define BDRV_O_NO_BACKING 0x0100 /* don't open the backing file */ | ||
1220 | -#define BDRV_O_NO_FLUSH 0x0200 /* disable flushing on this disk */ | ||
1221 | -#define BDRV_O_COPY_ON_READ 0x0400 /* copy read backing sectors into image */ | ||
1222 | -#define BDRV_O_INACTIVE 0x0800 /* consistency hint for migration handoff */ | ||
1223 | -#define BDRV_O_CHECK 0x1000 /* open solely for consistency check */ | ||
1224 | -#define BDRV_O_ALLOW_RDWR 0x2000 /* allow reopen to change from r/o to r/w */ | ||
1225 | -#define BDRV_O_UNMAP 0x4000 /* execute guest UNMAP/TRIM operations */ | ||
1226 | -#define BDRV_O_PROTOCOL 0x8000 /* if no block driver is explicitly given: | ||
1227 | - select an appropriate protocol driver, | ||
1228 | - ignoring the format layer */ | ||
1229 | -#define BDRV_O_NO_IO 0x10000 /* don't initialize for I/O */ | ||
1230 | -#define BDRV_O_AUTO_RDONLY 0x20000 /* degrade to read-only if opening read-write fails */ | ||
1231 | -#define BDRV_O_IO_URING 0x40000 /* use io_uring instead of the thread pool */ | ||
1232 | - | ||
1233 | -#define BDRV_O_CACHE_MASK (BDRV_O_NOCACHE | BDRV_O_NO_FLUSH) | ||
1234 | - | ||
1235 | - | ||
1236 | -/* Option names of options parsed by the block layer */ | ||
1237 | - | ||
1238 | -#define BDRV_OPT_CACHE_WB "cache.writeback" | ||
1239 | -#define BDRV_OPT_CACHE_DIRECT "cache.direct" | ||
1240 | -#define BDRV_OPT_CACHE_NO_FLUSH "cache.no-flush" | ||
1241 | -#define BDRV_OPT_READ_ONLY "read-only" | ||
1242 | -#define BDRV_OPT_AUTO_READ_ONLY "auto-read-only" | ||
1243 | -#define BDRV_OPT_DISCARD "discard" | ||
1244 | -#define BDRV_OPT_FORCE_SHARE "force-share" | ||
1245 | - | ||
1246 | - | ||
1247 | -#define BDRV_SECTOR_BITS 9 | ||
1248 | -#define BDRV_SECTOR_SIZE (1ULL << BDRV_SECTOR_BITS) | ||
1249 | - | ||
1250 | -#define BDRV_REQUEST_MAX_SECTORS MIN_CONST(SIZE_MAX >> BDRV_SECTOR_BITS, \ | ||
1251 | - INT_MAX >> BDRV_SECTOR_BITS) | ||
1252 | -#define BDRV_REQUEST_MAX_BYTES (BDRV_REQUEST_MAX_SECTORS << BDRV_SECTOR_BITS) | ||
1253 | - | ||
1254 | -/* | ||
1255 | - * We want allow aligning requests and disk length up to any 32bit alignment | ||
1256 | - * and don't afraid of overflow. | ||
1257 | - * To achieve it, and in the same time use some pretty number as maximum disk | ||
1258 | - * size, let's define maximum "length" (a limit for any offset/bytes request and | ||
1259 | - * for disk size) to be the greatest power of 2 less than INT64_MAX. | ||
1260 | - */ | ||
1261 | -#define BDRV_MAX_ALIGNMENT (1L << 30) | ||
1262 | -#define BDRV_MAX_LENGTH (QEMU_ALIGN_DOWN(INT64_MAX, BDRV_MAX_ALIGNMENT)) | ||
1263 | - | ||
1264 | -/* | ||
1265 | - * Allocation status flags for bdrv_block_status() and friends. | ||
1266 | - * | ||
1267 | - * Public flags: | ||
1268 | - * BDRV_BLOCK_DATA: allocation for data at offset is tied to this layer | ||
1269 | - * BDRV_BLOCK_ZERO: offset reads as zero | ||
1270 | - * BDRV_BLOCK_OFFSET_VALID: an associated offset exists for accessing raw data | ||
1271 | - * BDRV_BLOCK_ALLOCATED: the content of the block is determined by this | ||
1272 | - * layer rather than any backing, set by block layer | ||
1273 | - * BDRV_BLOCK_EOF: the returned pnum covers through end of file for this | ||
1274 | - * layer, set by block layer | ||
1275 | - * | ||
1276 | - * Internal flags: | ||
1277 | - * BDRV_BLOCK_RAW: for use by passthrough drivers, such as raw, to request | ||
1278 | - * that the block layer recompute the answer from the returned | ||
1279 | - * BDS; must be accompanied by just BDRV_BLOCK_OFFSET_VALID. | ||
1280 | - * BDRV_BLOCK_RECURSE: request that the block layer will recursively search for | ||
1281 | - * zeroes in file child of current block node inside | ||
1282 | - * returned region. Only valid together with both | ||
1283 | - * BDRV_BLOCK_DATA and BDRV_BLOCK_OFFSET_VALID. Should not | ||
1284 | - * appear with BDRV_BLOCK_ZERO. | ||
1285 | - * | ||
1286 | - * If BDRV_BLOCK_OFFSET_VALID is set, the map parameter represents the | ||
1287 | - * host offset within the returned BDS that is allocated for the | ||
1288 | - * corresponding raw guest data. However, whether that offset | ||
1289 | - * actually contains data also depends on BDRV_BLOCK_DATA, as follows: | ||
1290 | - * | ||
1291 | - * DATA ZERO OFFSET_VALID | ||
1292 | - * t t t sectors read as zero, returned file is zero at offset | ||
1293 | - * t f t sectors read as valid from file at offset | ||
1294 | - * f t t sectors preallocated, read as zero, returned file not | ||
1295 | - * necessarily zero at offset | ||
1296 | - * f f t sectors preallocated but read from backing_hd, | ||
1297 | - * returned file contains garbage at offset | ||
1298 | - * t t f sectors preallocated, read as zero, unknown offset | ||
1299 | - * t f f sectors read from unknown file or offset | ||
1300 | - * f t f not allocated or unknown offset, read as zero | ||
1301 | - * f f f not allocated or unknown offset, read from backing_hd | ||
1302 | - */ | ||
1303 | -#define BDRV_BLOCK_DATA 0x01 | ||
1304 | -#define BDRV_BLOCK_ZERO 0x02 | ||
1305 | -#define BDRV_BLOCK_OFFSET_VALID 0x04 | ||
1306 | -#define BDRV_BLOCK_RAW 0x08 | ||
1307 | -#define BDRV_BLOCK_ALLOCATED 0x10 | ||
1308 | -#define BDRV_BLOCK_EOF 0x20 | ||
1309 | -#define BDRV_BLOCK_RECURSE 0x40 | ||
1310 | - | ||
1311 | -typedef QTAILQ_HEAD(BlockReopenQueue, BlockReopenQueueEntry) BlockReopenQueue; | ||
1312 | - | ||
1313 | -typedef struct BDRVReopenState { | ||
1314 | - BlockDriverState *bs; | ||
1315 | - int flags; | ||
1316 | - BlockdevDetectZeroesOptions detect_zeroes; | ||
1317 | - bool backing_missing; | ||
1318 | - BlockDriverState *old_backing_bs; /* keep pointer for permissions update */ | ||
1319 | - BlockDriverState *old_file_bs; /* keep pointer for permissions update */ | ||
1320 | - QDict *options; | ||
1321 | - QDict *explicit_options; | ||
1322 | - void *opaque; | ||
1323 | -} BDRVReopenState; | ||
1324 | - | ||
1325 | -/* | ||
1326 | - * Block operation types | ||
1327 | - */ | ||
1328 | -typedef enum BlockOpType { | ||
1329 | - BLOCK_OP_TYPE_BACKUP_SOURCE, | ||
1330 | - BLOCK_OP_TYPE_BACKUP_TARGET, | ||
1331 | - BLOCK_OP_TYPE_CHANGE, | ||
1332 | - BLOCK_OP_TYPE_COMMIT_SOURCE, | ||
1333 | - BLOCK_OP_TYPE_COMMIT_TARGET, | ||
1334 | - BLOCK_OP_TYPE_DATAPLANE, | ||
1335 | - BLOCK_OP_TYPE_DRIVE_DEL, | ||
1336 | - BLOCK_OP_TYPE_EJECT, | ||
1337 | - BLOCK_OP_TYPE_EXTERNAL_SNAPSHOT, | ||
1338 | - BLOCK_OP_TYPE_INTERNAL_SNAPSHOT, | ||
1339 | - BLOCK_OP_TYPE_INTERNAL_SNAPSHOT_DELETE, | ||
1340 | - BLOCK_OP_TYPE_MIRROR_SOURCE, | ||
1341 | - BLOCK_OP_TYPE_MIRROR_TARGET, | ||
1342 | - BLOCK_OP_TYPE_RESIZE, | ||
1343 | - BLOCK_OP_TYPE_STREAM, | ||
1344 | - BLOCK_OP_TYPE_REPLACE, | ||
1345 | - BLOCK_OP_TYPE_MAX, | ||
1346 | -} BlockOpType; | ||
1347 | - | ||
1348 | -/* Block node permission constants */ | ||
1349 | -enum { | ||
1350 | - /** | ||
1351 | - * A user that has the "permission" of consistent reads is guaranteed that | ||
1352 | - * their view of the contents of the block device is complete and | ||
1353 | - * self-consistent, representing the contents of a disk at a specific | ||
1354 | - * point. | ||
1355 | - * | ||
1356 | - * For most block devices (including their backing files) this is true, but | ||
1357 | - * the property cannot be maintained in a few situations like for | ||
1358 | - * intermediate nodes of a commit block job. | ||
1359 | - */ | ||
1360 | - BLK_PERM_CONSISTENT_READ = 0x01, | ||
1361 | - | ||
1362 | - /** This permission is required to change the visible disk contents. */ | ||
1363 | - BLK_PERM_WRITE = 0x02, | ||
1364 | - | ||
1365 | - /** | ||
1366 | - * This permission (which is weaker than BLK_PERM_WRITE) is both enough and | ||
1367 | - * required for writes to the block node when the caller promises that | ||
1368 | - * the visible disk content doesn't change. | ||
1369 | - * | ||
1370 | - * As the BLK_PERM_WRITE permission is strictly stronger, either is | ||
1371 | - * sufficient to perform an unchanging write. | ||
1372 | - */ | ||
1373 | - BLK_PERM_WRITE_UNCHANGED = 0x04, | ||
1374 | - | ||
1375 | - /** This permission is required to change the size of a block node. */ | ||
1376 | - BLK_PERM_RESIZE = 0x08, | ||
1377 | - | ||
1378 | - /** | ||
1379 | - * There was a now-removed bit BLK_PERM_GRAPH_MOD, with value of 0x10. QEMU | ||
1380 | - * 6.1 and earlier may still lock the corresponding byte in block/file-posix | ||
1381 | - * locking. So, implementing some new permission should be very careful to | ||
1382 | - * not interfere with this old unused thing. | ||
1383 | - */ | ||
1384 | - | ||
1385 | - BLK_PERM_ALL = 0x0f, | ||
1386 | - | ||
1387 | - DEFAULT_PERM_PASSTHROUGH = BLK_PERM_CONSISTENT_READ | ||
1388 | - | BLK_PERM_WRITE | ||
1389 | - | BLK_PERM_WRITE_UNCHANGED | ||
1390 | - | BLK_PERM_RESIZE, | ||
1391 | - | ||
1392 | - DEFAULT_PERM_UNCHANGED = BLK_PERM_ALL & ~DEFAULT_PERM_PASSTHROUGH, | ||
1393 | -}; | ||
1394 | - | ||
1395 | -/* | ||
1396 | - * Flags that parent nodes assign to child nodes to specify what kind of | ||
1397 | - * role(s) they take. | ||
1398 | - * | ||
1399 | - * At least one of DATA, METADATA, FILTERED, or COW must be set for | ||
1400 | - * every child. | ||
1401 | - */ | ||
1402 | -enum BdrvChildRoleBits { | ||
1403 | - /* | ||
1404 | - * This child stores data. | ||
1405 | - * Any node may have an arbitrary number of such children. | ||
1406 | - */ | ||
1407 | - BDRV_CHILD_DATA = (1 << 0), | ||
1408 | - | ||
1409 | - /* | ||
1410 | - * This child stores metadata. | ||
1411 | - * Any node may have an arbitrary number of metadata-storing | ||
1412 | - * children. | ||
1413 | - */ | ||
1414 | - BDRV_CHILD_METADATA = (1 << 1), | ||
1415 | - | ||
1416 | - /* | ||
1417 | - * A child that always presents exactly the same visible data as | ||
1418 | - * the parent, e.g. by virtue of the parent forwarding all reads | ||
1419 | - * and writes. | ||
1420 | - * This flag is mutually exclusive with DATA, METADATA, and COW. | ||
1421 | - * Any node may have at most one filtered child at a time. | ||
1422 | - */ | ||
1423 | - BDRV_CHILD_FILTERED = (1 << 2), | ||
1424 | - | ||
1425 | - /* | ||
1426 | - * Child from which to read all data that isn't allocated in the | ||
1427 | - * parent (i.e., the backing child); such data is copied to the | ||
1428 | - * parent through COW (and optionally COR). | ||
1429 | - * This field is mutually exclusive with DATA, METADATA, and | ||
1430 | - * FILTERED. | ||
1431 | - * Any node may have at most one such backing child at a time. | ||
1432 | - */ | ||
1433 | - BDRV_CHILD_COW = (1 << 3), | ||
1434 | - | ||
1435 | - /* | ||
1436 | - * The primary child. For most drivers, this is the child whose | ||
1437 | - * filename applies best to the parent node. | ||
1438 | - * Any node may have at most one primary child at a time. | ||
1439 | - */ | ||
1440 | - BDRV_CHILD_PRIMARY = (1 << 4), | ||
1441 | - | ||
1442 | - /* Useful combination of flags */ | ||
1443 | - BDRV_CHILD_IMAGE = BDRV_CHILD_DATA | ||
1444 | - | BDRV_CHILD_METADATA | ||
1445 | - | BDRV_CHILD_PRIMARY, | ||
1446 | -}; | ||
1447 | - | ||
1448 | -/* Mask of BdrvChildRoleBits values */ | ||
1449 | -typedef unsigned int BdrvChildRole; | ||
1450 | - | ||
1451 | -char *bdrv_perm_names(uint64_t perm); | ||
1452 | -uint64_t bdrv_qapi_perm_to_blk_perm(BlockPermission qapi_perm); | ||
1453 | - | ||
1454 | -void bdrv_init(void); | ||
1455 | -void bdrv_init_with_whitelist(void); | ||
1456 | -bool bdrv_uses_whitelist(void); | ||
1457 | -int bdrv_is_whitelisted(BlockDriver *drv, bool read_only); | ||
1458 | -BlockDriver *bdrv_find_protocol(const char *filename, | ||
1459 | - bool allow_protocol_prefix, | ||
1460 | - Error **errp); | ||
1461 | -BlockDriver *bdrv_find_format(const char *format_name); | ||
1462 | -int bdrv_create(BlockDriver *drv, const char* filename, | ||
1463 | - QemuOpts *opts, Error **errp); | ||
1464 | -int bdrv_create_file(const char *filename, QemuOpts *opts, Error **errp); | ||
1465 | - | ||
1466 | -BlockDriverState *bdrv_new(void); | ||
1467 | -int bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top, | ||
1468 | - Error **errp); | ||
1469 | -int bdrv_replace_node(BlockDriverState *from, BlockDriverState *to, | ||
1470 | - Error **errp); | ||
1471 | -int bdrv_replace_child_bs(BdrvChild *child, BlockDriverState *new_bs, | ||
1472 | - Error **errp); | ||
1473 | -BlockDriverState *bdrv_insert_node(BlockDriverState *bs, QDict *node_options, | ||
1474 | - int flags, Error **errp); | ||
1475 | -int bdrv_drop_filter(BlockDriverState *bs, Error **errp); | ||
1476 | - | ||
1477 | -int bdrv_parse_aio(const char *mode, int *flags); | ||
1478 | -int bdrv_parse_cache_mode(const char *mode, int *flags, bool *writethrough); | ||
1479 | -int bdrv_parse_discard_flags(const char *mode, int *flags); | ||
1480 | -BdrvChild *bdrv_open_child(const char *filename, | ||
1481 | - QDict *options, const char *bdref_key, | ||
1482 | - BlockDriverState* parent, | ||
1483 | - const BdrvChildClass *child_class, | ||
1484 | - BdrvChildRole child_role, | ||
1485 | - bool allow_none, Error **errp); | ||
1486 | -BlockDriverState *bdrv_open_blockdev_ref(BlockdevRef *ref, Error **errp); | ||
1487 | -int bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd, | ||
1488 | - Error **errp); | ||
1489 | -int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options, | ||
1490 | - const char *bdref_key, Error **errp); | ||
1491 | -BlockDriverState *bdrv_open(const char *filename, const char *reference, | ||
1492 | - QDict *options, int flags, Error **errp); | ||
1493 | -BlockDriverState *bdrv_new_open_driver_opts(BlockDriver *drv, | ||
1494 | - const char *node_name, | ||
1495 | - QDict *options, int flags, | ||
1496 | - Error **errp); | ||
1497 | -BlockDriverState *bdrv_new_open_driver(BlockDriver *drv, const char *node_name, | ||
1498 | - int flags, Error **errp); | ||
1499 | -BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue, | ||
1500 | - BlockDriverState *bs, QDict *options, | ||
1501 | - bool keep_old_opts); | ||
1502 | -void bdrv_reopen_queue_free(BlockReopenQueue *bs_queue); | ||
1503 | -int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp); | ||
1504 | -int bdrv_reopen(BlockDriverState *bs, QDict *opts, bool keep_old_opts, | ||
1505 | - Error **errp); | ||
1506 | -int bdrv_reopen_set_read_only(BlockDriverState *bs, bool read_only, | ||
1507 | - Error **errp); | ||
1508 | -int bdrv_pwrite_zeroes(BdrvChild *child, int64_t offset, | ||
1509 | - int64_t bytes, BdrvRequestFlags flags); | ||
1510 | -int bdrv_make_zero(BdrvChild *child, BdrvRequestFlags flags); | ||
1511 | -int bdrv_pread(BdrvChild *child, int64_t offset, void *buf, int64_t bytes); | ||
1512 | -int bdrv_pwrite(BdrvChild *child, int64_t offset, const void *buf, | ||
1513 | - int64_t bytes); | ||
1514 | -int bdrv_pwrite_sync(BdrvChild *child, int64_t offset, | ||
1515 | - const void *buf, int64_t bytes); | ||
1516 | -/* | ||
1517 | - * Efficiently zero a region of the disk image. Note that this is a regular | ||
1518 | - * I/O request like read or write and should have a reasonable size. This | ||
1519 | - * function is not suitable for zeroing the entire image in a single request | ||
1520 | - * because it may allocate memory for the entire region. | ||
1521 | - */ | ||
1522 | -int coroutine_fn bdrv_co_pwrite_zeroes(BdrvChild *child, int64_t offset, | ||
1523 | - int64_t bytes, BdrvRequestFlags flags); | ||
1524 | -BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs, | ||
1525 | - const char *backing_file); | ||
1526 | -void bdrv_refresh_filename(BlockDriverState *bs); | ||
1527 | - | ||
1528 | -int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact, | ||
1529 | - PreallocMode prealloc, BdrvRequestFlags flags, | ||
1530 | - Error **errp); | ||
1531 | -int generated_co_wrapper | ||
1532 | -bdrv_truncate(BdrvChild *child, int64_t offset, bool exact, | ||
1533 | - PreallocMode prealloc, BdrvRequestFlags flags, Error **errp); | ||
1534 | - | ||
1535 | -int64_t bdrv_nb_sectors(BlockDriverState *bs); | ||
1536 | -int64_t bdrv_getlength(BlockDriverState *bs); | ||
1537 | -int64_t bdrv_get_allocated_file_size(BlockDriverState *bs); | ||
1538 | -BlockMeasureInfo *bdrv_measure(BlockDriver *drv, QemuOpts *opts, | ||
1539 | - BlockDriverState *in_bs, Error **errp); | ||
1540 | -void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr); | ||
1541 | -void bdrv_refresh_limits(BlockDriverState *bs, Transaction *tran, Error **errp); | ||
1542 | -int bdrv_commit(BlockDriverState *bs); | ||
1543 | -int bdrv_make_empty(BdrvChild *c, Error **errp); | ||
1544 | -int bdrv_change_backing_file(BlockDriverState *bs, const char *backing_file, | ||
1545 | - const char *backing_fmt, bool warn); | ||
1546 | -void bdrv_register(BlockDriver *bdrv); | ||
1547 | -int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base, | ||
1548 | - const char *backing_file_str); | ||
1549 | -BlockDriverState *bdrv_find_overlay(BlockDriverState *active, | ||
1550 | - BlockDriverState *bs); | ||
1551 | -BlockDriverState *bdrv_find_base(BlockDriverState *bs); | ||
1552 | -bool bdrv_is_backing_chain_frozen(BlockDriverState *bs, BlockDriverState *base, | ||
1553 | - Error **errp); | ||
1554 | -int bdrv_freeze_backing_chain(BlockDriverState *bs, BlockDriverState *base, | ||
1555 | - Error **errp); | ||
1556 | -void bdrv_unfreeze_backing_chain(BlockDriverState *bs, BlockDriverState *base); | ||
1557 | -int coroutine_fn bdrv_co_delete_file(BlockDriverState *bs, Error **errp); | ||
1558 | -void coroutine_fn bdrv_co_delete_file_noerr(BlockDriverState *bs); | ||
1559 | - | ||
1560 | - | ||
1561 | -typedef struct BdrvCheckResult { | ||
1562 | - int corruptions; | ||
1563 | - int leaks; | ||
1564 | - int check_errors; | ||
1565 | - int corruptions_fixed; | ||
1566 | - int leaks_fixed; | ||
1567 | - int64_t image_end_offset; | ||
1568 | - BlockFragInfo bfi; | ||
1569 | -} BdrvCheckResult; | ||
1570 | - | ||
1571 | -typedef enum { | ||
1572 | - BDRV_FIX_LEAKS = 1, | ||
1573 | - BDRV_FIX_ERRORS = 2, | ||
1574 | -} BdrvCheckMode; | ||
1575 | - | ||
1576 | -int generated_co_wrapper bdrv_check(BlockDriverState *bs, BdrvCheckResult *res, | ||
1577 | - BdrvCheckMode fix); | ||
1578 | - | ||
1579 | -/* The units of offset and total_work_size may be chosen arbitrarily by the | ||
1580 | - * block driver; total_work_size may change during the course of the amendment | ||
1581 | - * operation */ | ||
1582 | -typedef void BlockDriverAmendStatusCB(BlockDriverState *bs, int64_t offset, | ||
1583 | - int64_t total_work_size, void *opaque); | ||
1584 | -int bdrv_amend_options(BlockDriverState *bs_new, QemuOpts *opts, | ||
1585 | - BlockDriverAmendStatusCB *status_cb, void *cb_opaque, | ||
1586 | - bool force, | ||
1587 | - Error **errp); | ||
1588 | - | ||
1589 | -/* check if a named node can be replaced when doing drive-mirror */ | ||
1590 | -BlockDriverState *check_to_replace_node(BlockDriverState *parent_bs, | ||
1591 | - const char *node_name, Error **errp); | ||
1592 | - | ||
1593 | -/* async block I/O */ | ||
1594 | -void bdrv_aio_cancel(BlockAIOCB *acb); | ||
1595 | -void bdrv_aio_cancel_async(BlockAIOCB *acb); | ||
1596 | - | ||
1597 | -/* sg packet commands */ | ||
1598 | -int bdrv_co_ioctl(BlockDriverState *bs, int req, void *buf); | ||
1599 | - | ||
1600 | -/* Invalidate any cached metadata used by image formats */ | ||
1601 | -int generated_co_wrapper bdrv_invalidate_cache(BlockDriverState *bs, | ||
1602 | - Error **errp); | ||
1603 | -int bdrv_activate(BlockDriverState *bs, Error **errp); | ||
1604 | -void bdrv_activate_all(Error **errp); | ||
1605 | -int bdrv_inactivate_all(void); | ||
1606 | - | ||
1607 | -/* Ensure contents are flushed to disk. */ | ||
1608 | -int generated_co_wrapper bdrv_flush(BlockDriverState *bs); | ||
1609 | -int coroutine_fn bdrv_co_flush(BlockDriverState *bs); | ||
1610 | -int bdrv_flush_all(void); | ||
1611 | -void bdrv_close_all(void); | ||
1612 | -void bdrv_drain(BlockDriverState *bs); | ||
1613 | -void coroutine_fn bdrv_co_drain(BlockDriverState *bs); | ||
1614 | -void bdrv_drain_all_begin(void); | ||
1615 | -void bdrv_drain_all_end(void); | ||
1616 | -void bdrv_drain_all(void); | ||
1617 | - | ||
1618 | -#define BDRV_POLL_WHILE(bs, cond) ({ \ | ||
1619 | - BlockDriverState *bs_ = (bs); \ | ||
1620 | - AIO_WAIT_WHILE(bdrv_get_aio_context(bs_), \ | ||
1621 | - cond); }) | ||
1622 | - | ||
1623 | -int generated_co_wrapper bdrv_pdiscard(BdrvChild *child, int64_t offset, | ||
1624 | - int64_t bytes); | ||
1625 | -int bdrv_co_pdiscard(BdrvChild *child, int64_t offset, int64_t bytes); | ||
1626 | -int bdrv_has_zero_init_1(BlockDriverState *bs); | ||
1627 | -int bdrv_has_zero_init(BlockDriverState *bs); | ||
1628 | -bool bdrv_can_write_zeroes_with_unmap(BlockDriverState *bs); | ||
1629 | -int bdrv_block_status(BlockDriverState *bs, int64_t offset, | ||
1630 | - int64_t bytes, int64_t *pnum, int64_t *map, | ||
1631 | - BlockDriverState **file); | ||
1632 | -int bdrv_block_status_above(BlockDriverState *bs, BlockDriverState *base, | ||
1633 | - int64_t offset, int64_t bytes, int64_t *pnum, | ||
1634 | - int64_t *map, BlockDriverState **file); | ||
1635 | -int bdrv_is_allocated(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
1636 | - int64_t *pnum); | ||
1637 | -int bdrv_is_allocated_above(BlockDriverState *top, BlockDriverState *base, | ||
1638 | - bool include_base, int64_t offset, int64_t bytes, | ||
1639 | - int64_t *pnum); | ||
1640 | -int coroutine_fn bdrv_co_is_zero_fast(BlockDriverState *bs, int64_t offset, | ||
1641 | - int64_t bytes); | ||
1642 | - | ||
1643 | -bool bdrv_is_read_only(BlockDriverState *bs); | ||
1644 | -int bdrv_can_set_read_only(BlockDriverState *bs, bool read_only, | ||
1645 | - bool ignore_allow_rdw, Error **errp); | ||
1646 | -int bdrv_apply_auto_read_only(BlockDriverState *bs, const char *errmsg, | ||
1647 | - Error **errp); | ||
1648 | -bool bdrv_is_writable(BlockDriverState *bs); | ||
1649 | -bool bdrv_is_sg(BlockDriverState *bs); | ||
1650 | -bool bdrv_is_inserted(BlockDriverState *bs); | ||
1651 | -void bdrv_lock_medium(BlockDriverState *bs, bool locked); | ||
1652 | -void bdrv_eject(BlockDriverState *bs, bool eject_flag); | ||
1653 | -const char *bdrv_get_format_name(BlockDriverState *bs); | ||
1654 | -BlockDriverState *bdrv_find_node(const char *node_name); | ||
1655 | -BlockDeviceInfoList *bdrv_named_nodes_list(bool flat, Error **errp); | ||
1656 | -XDbgBlockGraph *bdrv_get_xdbg_block_graph(Error **errp); | ||
1657 | -BlockDriverState *bdrv_lookup_bs(const char *device, | ||
1658 | - const char *node_name, | ||
1659 | - Error **errp); | ||
1660 | -bool bdrv_chain_contains(BlockDriverState *top, BlockDriverState *base); | ||
1661 | -BlockDriverState *bdrv_next_node(BlockDriverState *bs); | ||
1662 | -BlockDriverState *bdrv_next_all_states(BlockDriverState *bs); | ||
1663 | - | ||
1664 | -typedef struct BdrvNextIterator { | ||
1665 | - enum { | ||
1666 | - BDRV_NEXT_BACKEND_ROOTS, | ||
1667 | - BDRV_NEXT_MONITOR_OWNED, | ||
1668 | - } phase; | ||
1669 | - BlockBackend *blk; | ||
1670 | - BlockDriverState *bs; | ||
1671 | -} BdrvNextIterator; | ||
1672 | - | ||
1673 | -BlockDriverState *bdrv_first(BdrvNextIterator *it); | ||
1674 | -BlockDriverState *bdrv_next(BdrvNextIterator *it); | ||
1675 | -void bdrv_next_cleanup(BdrvNextIterator *it); | ||
1676 | - | ||
1677 | -BlockDriverState *bdrv_next_monitor_owned(BlockDriverState *bs); | ||
1678 | -bool bdrv_supports_compressed_writes(BlockDriverState *bs); | ||
1679 | -void bdrv_iterate_format(void (*it)(void *opaque, const char *name), | ||
1680 | - void *opaque, bool read_only); | ||
1681 | -const char *bdrv_get_node_name(const BlockDriverState *bs); | ||
1682 | -const char *bdrv_get_device_name(const BlockDriverState *bs); | ||
1683 | -const char *bdrv_get_device_or_node_name(const BlockDriverState *bs); | ||
1684 | -int bdrv_get_flags(BlockDriverState *bs); | ||
1685 | -int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi); | ||
1686 | -ImageInfoSpecific *bdrv_get_specific_info(BlockDriverState *bs, | ||
1687 | - Error **errp); | ||
1688 | -BlockStatsSpecific *bdrv_get_specific_stats(BlockDriverState *bs); | ||
1689 | -void bdrv_round_to_clusters(BlockDriverState *bs, | ||
1690 | - int64_t offset, int64_t bytes, | ||
1691 | - int64_t *cluster_offset, | ||
1692 | - int64_t *cluster_bytes); | ||
1693 | - | ||
1694 | -void bdrv_get_backing_filename(BlockDriverState *bs, | ||
1695 | - char *filename, int filename_size); | ||
1696 | -char *bdrv_get_full_backing_filename(BlockDriverState *bs, Error **errp); | ||
1697 | -char *bdrv_get_full_backing_filename_from_filename(const char *backed, | ||
1698 | - const char *backing, | ||
1699 | - Error **errp); | ||
1700 | -char *bdrv_dirname(BlockDriverState *bs, Error **errp); | ||
1701 | - | ||
1702 | -int path_has_protocol(const char *path); | ||
1703 | -int path_is_absolute(const char *path); | ||
1704 | -char *path_combine(const char *base_path, const char *filename); | ||
1705 | - | ||
1706 | -int generated_co_wrapper | ||
1707 | -bdrv_readv_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos); | ||
1708 | -int generated_co_wrapper | ||
1709 | -bdrv_writev_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos); | ||
1710 | -int bdrv_save_vmstate(BlockDriverState *bs, const uint8_t *buf, | ||
1711 | - int64_t pos, int size); | ||
1712 | - | ||
1713 | -int bdrv_load_vmstate(BlockDriverState *bs, uint8_t *buf, | ||
1714 | - int64_t pos, int size); | ||
1715 | - | ||
1716 | -void bdrv_img_create(const char *filename, const char *fmt, | ||
1717 | - const char *base_filename, const char *base_fmt, | ||
1718 | - char *options, uint64_t img_size, int flags, | ||
1719 | - bool quiet, Error **errp); | ||
1720 | - | ||
1721 | -/* Returns the alignment in bytes that is required so that no bounce buffer | ||
1722 | - * is required throughout the stack */ | ||
1723 | -size_t bdrv_min_mem_align(BlockDriverState *bs); | ||
1724 | -/* Returns optimal alignment in bytes for bounce buffer */ | ||
1725 | -size_t bdrv_opt_mem_align(BlockDriverState *bs); | ||
1726 | -void *qemu_blockalign(BlockDriverState *bs, size_t size); | ||
1727 | -void *qemu_blockalign0(BlockDriverState *bs, size_t size); | ||
1728 | -void *qemu_try_blockalign(BlockDriverState *bs, size_t size); | ||
1729 | -void *qemu_try_blockalign0(BlockDriverState *bs, size_t size); | ||
1730 | -bool bdrv_qiov_is_aligned(BlockDriverState *bs, QEMUIOVector *qiov); | ||
1731 | - | ||
1732 | -void bdrv_enable_copy_on_read(BlockDriverState *bs); | ||
1733 | -void bdrv_disable_copy_on_read(BlockDriverState *bs); | ||
1734 | - | ||
1735 | -void bdrv_ref(BlockDriverState *bs); | ||
1736 | -void bdrv_unref(BlockDriverState *bs); | ||
1737 | -void bdrv_unref_child(BlockDriverState *parent, BdrvChild *child); | ||
1738 | -BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs, | ||
1739 | - BlockDriverState *child_bs, | ||
1740 | - const char *child_name, | ||
1741 | - const BdrvChildClass *child_class, | ||
1742 | - BdrvChildRole child_role, | ||
1743 | - Error **errp); | ||
1744 | - | ||
1745 | -bool bdrv_op_is_blocked(BlockDriverState *bs, BlockOpType op, Error **errp); | ||
1746 | -void bdrv_op_block(BlockDriverState *bs, BlockOpType op, Error *reason); | ||
1747 | -void bdrv_op_unblock(BlockDriverState *bs, BlockOpType op, Error *reason); | ||
1748 | -void bdrv_op_block_all(BlockDriverState *bs, Error *reason); | ||
1749 | -void bdrv_op_unblock_all(BlockDriverState *bs, Error *reason); | ||
1750 | -bool bdrv_op_blocker_is_empty(BlockDriverState *bs); | ||
1751 | - | ||
1752 | -#define BLKDBG_EVENT(child, evt) \ | ||
1753 | - do { \ | ||
1754 | - if (child) { \ | ||
1755 | - bdrv_debug_event(child->bs, evt); \ | ||
1756 | - } \ | ||
1757 | - } while (0) | ||
1758 | - | ||
1759 | -void bdrv_debug_event(BlockDriverState *bs, BlkdebugEvent event); | ||
1760 | - | ||
1761 | -int bdrv_debug_breakpoint(BlockDriverState *bs, const char *event, | ||
1762 | - const char *tag); | ||
1763 | -int bdrv_debug_remove_breakpoint(BlockDriverState *bs, const char *tag); | ||
1764 | -int bdrv_debug_resume(BlockDriverState *bs, const char *tag); | ||
1765 | -bool bdrv_debug_is_suspended(BlockDriverState *bs, const char *tag); | ||
1766 | - | ||
1767 | -/** | ||
1768 | - * bdrv_get_aio_context: | ||
1769 | + * QEMU System Emulator block driver | ||
1770 | * | ||
1771 | - * Returns: the currently bound #AioContext | ||
1772 | - */ | ||
1773 | -AioContext *bdrv_get_aio_context(BlockDriverState *bs); | ||
1774 | - | ||
1775 | -/** | ||
1776 | - * Move the current coroutine to the AioContext of @bs and return the old | ||
1777 | - * AioContext of the coroutine. Increase bs->in_flight so that draining @bs | ||
1778 | - * will wait for the operation to proceed until the corresponding | ||
1779 | - * bdrv_co_leave(). | ||
1780 | + * Copyright (c) 2003 Fabrice Bellard | ||
1781 | * | ||
1782 | - * Consequently, you can't call drain inside a bdrv_co_enter/leave() section as | ||
1783 | - * this will deadlock. | ||
1784 | - */ | ||
1785 | -AioContext *coroutine_fn bdrv_co_enter(BlockDriverState *bs); | ||
1786 | - | ||
1787 | -/** | ||
1788 | - * Ends a section started by bdrv_co_enter(). Move the current coroutine back | ||
1789 | - * to old_ctx and decrease bs->in_flight again. | ||
1790 | - */ | ||
1791 | -void coroutine_fn bdrv_co_leave(BlockDriverState *bs, AioContext *old_ctx); | ||
1792 | - | ||
1793 | -/** | ||
1794 | - * Locks the AioContext of @bs if it's not the current AioContext. This avoids | ||
1795 | - * double locking which could lead to deadlocks: This is a coroutine_fn, so we | ||
1796 | - * know we already own the lock of the current AioContext. | ||
1797 | + * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
1798 | + * of this software and associated documentation files (the "Software"), to deal | ||
1799 | + * in the Software without restriction, including without limitation the rights | ||
1800 | + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
1801 | + * copies of the Software, and to permit persons to whom the Software is | ||
1802 | + * furnished to do so, subject to the following conditions: | ||
1803 | * | ||
1804 | - * May only be called in the main thread. | ||
1805 | - */ | ||
1806 | -void coroutine_fn bdrv_co_lock(BlockDriverState *bs); | ||
1807 | - | ||
1808 | -/** | ||
1809 | - * Unlocks the AioContext of @bs if it's not the current AioContext. | ||
1810 | - */ | ||
1811 | -void coroutine_fn bdrv_co_unlock(BlockDriverState *bs); | ||
1812 | - | ||
1813 | -/** | ||
1814 | - * Transfer control to @co in the aio context of @bs | ||
1815 | - */ | ||
1816 | -void bdrv_coroutine_enter(BlockDriverState *bs, Coroutine *co); | ||
1817 | - | ||
1818 | -void bdrv_set_aio_context_ignore(BlockDriverState *bs, | ||
1819 | - AioContext *new_context, GSList **ignore); | ||
1820 | -int bdrv_try_set_aio_context(BlockDriverState *bs, AioContext *ctx, | ||
1821 | - Error **errp); | ||
1822 | -int bdrv_child_try_set_aio_context(BlockDriverState *bs, AioContext *ctx, | ||
1823 | - BdrvChild *ignore_child, Error **errp); | ||
1824 | -bool bdrv_child_can_set_aio_context(BdrvChild *c, AioContext *ctx, | ||
1825 | - GSList **ignore, Error **errp); | ||
1826 | -bool bdrv_can_set_aio_context(BlockDriverState *bs, AioContext *ctx, | ||
1827 | - GSList **ignore, Error **errp); | ||
1828 | -AioContext *bdrv_child_get_parent_aio_context(BdrvChild *c); | ||
1829 | -AioContext *child_of_bds_get_parent_aio_context(BdrvChild *c); | ||
1830 | - | ||
1831 | -int bdrv_probe_blocksizes(BlockDriverState *bs, BlockSizes *bsz); | ||
1832 | -int bdrv_probe_geometry(BlockDriverState *bs, HDGeometry *geo); | ||
1833 | - | ||
1834 | -void bdrv_io_plug(BlockDriverState *bs); | ||
1835 | -void bdrv_io_unplug(BlockDriverState *bs); | ||
1836 | - | ||
1837 | -/** | ||
1838 | - * bdrv_parent_drained_begin_single: | ||
1839 | + * The above copyright notice and this permission notice shall be included in | ||
1840 | + * all copies or substantial portions of the Software. | ||
1841 | * | ||
1842 | - * Begin a quiesced section for the parent of @c. If @poll is true, wait for | ||
1843 | - * any pending activity to cease. | ||
1844 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
1845 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
1846 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
1847 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
1848 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
1849 | + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
1850 | + * THE SOFTWARE. | ||
1851 | */ | ||
1852 | -void bdrv_parent_drained_begin_single(BdrvChild *c, bool poll); | ||
1853 | - | ||
1854 | -/** | ||
1855 | - * bdrv_parent_drained_end_single: | ||
1856 | - * | ||
1857 | - * End a quiesced section for the parent of @c. | ||
1858 | - * | ||
1859 | - * This polls @bs's AioContext until all scheduled sub-drained_ends | ||
1860 | - * have settled, which may result in graph changes. | ||
1861 | - */ | ||
1862 | -void bdrv_parent_drained_end_single(BdrvChild *c); | ||
1863 | - | ||
1864 | -/** | ||
1865 | - * bdrv_drain_poll: | ||
1866 | - * | ||
1867 | - * Poll for pending requests in @bs, its parents (except for @ignore_parent), | ||
1868 | - * and if @recursive is true its children as well (used for subtree drain). | ||
1869 | - * | ||
1870 | - * If @ignore_bds_parents is true, parents that are BlockDriverStates must | ||
1871 | - * ignore the drain request because they will be drained separately (used for | ||
1872 | - * drain_all). | ||
1873 | - * | ||
1874 | - * This is part of bdrv_drained_begin. | ||
1875 | - */ | ||
1876 | -bool bdrv_drain_poll(BlockDriverState *bs, bool recursive, | ||
1877 | - BdrvChild *ignore_parent, bool ignore_bds_parents); | ||
1878 | - | ||
1879 | -/** | ||
1880 | - * bdrv_drained_begin: | ||
1881 | - * | ||
1882 | - * Begin a quiesced section for exclusive access to the BDS, by disabling | ||
1883 | - * external request sources including NBD server, block jobs, and device model. | ||
1884 | - * | ||
1885 | - * This function can be recursive. | ||
1886 | - */ | ||
1887 | -void bdrv_drained_begin(BlockDriverState *bs); | ||
1888 | - | ||
1889 | -/** | ||
1890 | - * bdrv_do_drained_begin_quiesce: | ||
1891 | - * | ||
1892 | - * Quiesces a BDS like bdrv_drained_begin(), but does not wait for already | ||
1893 | - * running requests to complete. | ||
1894 | - */ | ||
1895 | -void bdrv_do_drained_begin_quiesce(BlockDriverState *bs, | ||
1896 | - BdrvChild *parent, bool ignore_bds_parents); | ||
1897 | - | ||
1898 | -/** | ||
1899 | - * Like bdrv_drained_begin, but recursively begins a quiesced section for | ||
1900 | - * exclusive access to all child nodes as well. | ||
1901 | - */ | ||
1902 | -void bdrv_subtree_drained_begin(BlockDriverState *bs); | ||
1903 | - | ||
1904 | -/** | ||
1905 | - * bdrv_drained_end: | ||
1906 | - * | ||
1907 | - * End a quiescent section started by bdrv_drained_begin(). | ||
1908 | - * | ||
1909 | - * This polls @bs's AioContext until all scheduled sub-drained_ends | ||
1910 | - * have settled. On one hand, that may result in graph changes. On | ||
1911 | - * the other, this requires that the caller either runs in the main | ||
1912 | - * loop; or that all involved nodes (@bs and all of its parents) are | ||
1913 | - * in the caller's AioContext. | ||
1914 | - */ | ||
1915 | -void bdrv_drained_end(BlockDriverState *bs); | ||
1916 | - | ||
1917 | -/** | ||
1918 | - * bdrv_drained_end_no_poll: | ||
1919 | - * | ||
1920 | - * Same as bdrv_drained_end(), but do not poll for the subgraph to | ||
1921 | - * actually become unquiesced. Therefore, no graph changes will occur | ||
1922 | - * with this function. | ||
1923 | - * | ||
1924 | - * *drained_end_counter is incremented for every background operation | ||
1925 | - * that is scheduled, and will be decremented for every operation once | ||
1926 | - * it settles. The caller must poll until it reaches 0. The counter | ||
1927 | - * should be accessed using atomic operations only. | ||
1928 | - */ | ||
1929 | -void bdrv_drained_end_no_poll(BlockDriverState *bs, int *drained_end_counter); | ||
1930 | - | ||
1931 | -/** | ||
1932 | - * End a quiescent section started by bdrv_subtree_drained_begin(). | ||
1933 | - */ | ||
1934 | -void bdrv_subtree_drained_end(BlockDriverState *bs); | ||
1935 | - | ||
1936 | -void bdrv_add_child(BlockDriverState *parent, BlockDriverState *child, | ||
1937 | - Error **errp); | ||
1938 | -void bdrv_del_child(BlockDriverState *parent, BdrvChild *child, Error **errp); | ||
1939 | - | ||
1940 | -bool bdrv_can_store_new_dirty_bitmap(BlockDriverState *bs, const char *name, | ||
1941 | - uint32_t granularity, Error **errp); | ||
1942 | -/** | ||
1943 | - * | ||
1944 | - * bdrv_register_buf/bdrv_unregister_buf: | ||
1945 | - * | ||
1946 | - * Register/unregister a buffer for I/O. For example, VFIO drivers are | ||
1947 | - * interested to know the memory areas that would later be used for I/O, so | ||
1948 | - * that they can prepare IOMMU mapping etc., to get better performance. | ||
1949 | - */ | ||
1950 | -void bdrv_register_buf(BlockDriverState *bs, void *host, size_t size); | ||
1951 | -void bdrv_unregister_buf(BlockDriverState *bs, void *host); | ||
1952 | +#ifndef BLOCK_H | ||
1953 | +#define BLOCK_H | ||
1954 | |||
1955 | -/** | ||
1956 | - * | ||
1957 | - * bdrv_co_copy_range: | ||
1958 | - * | ||
1959 | - * Do offloaded copy between two children. If the operation is not implemented | ||
1960 | - * by the driver, or if the backend storage doesn't support it, a negative | ||
1961 | - * error code will be returned. | ||
1962 | - * | ||
1963 | - * Note: block layer doesn't emulate or fallback to a bounce buffer approach | ||
1964 | - * because usually the caller shouldn't attempt offloaded copy any more (e.g. | ||
1965 | - * calling copy_file_range(2)) after the first error, thus it should fall back | ||
1966 | - * to a read+write path in the caller level. | ||
1967 | - * | ||
1968 | - * @src: Source child to copy data from | ||
1969 | - * @src_offset: offset in @src image to read data | ||
1970 | - * @dst: Destination child to copy data to | ||
1971 | - * @dst_offset: offset in @dst image to write data | ||
1972 | - * @bytes: number of bytes to copy | ||
1973 | - * @flags: request flags. Supported flags: | ||
1974 | - * BDRV_REQ_ZERO_WRITE - treat the @src range as zero data and do zero | ||
1975 | - * write on @dst as if bdrv_co_pwrite_zeroes is | ||
1976 | - * called. Used to simplify caller code, or | ||
1977 | - * during BlockDriver.bdrv_co_copy_range_from() | ||
1978 | - * recursion. | ||
1979 | - * BDRV_REQ_NO_SERIALISING - do not serialize with other overlapping | ||
1980 | - * requests currently in flight. | ||
1981 | - * | ||
1982 | - * Returns: 0 if succeeded; negative error code if failed. | ||
1983 | - **/ | ||
1984 | -int coroutine_fn bdrv_co_copy_range(BdrvChild *src, int64_t src_offset, | ||
1985 | - BdrvChild *dst, int64_t dst_offset, | ||
1986 | - int64_t bytes, BdrvRequestFlags read_flags, | ||
1987 | - BdrvRequestFlags write_flags); | ||
1988 | +#include "block-global-state.h" | ||
1989 | +#include "block-io.h" | ||
1990 | |||
1991 | -void bdrv_cancel_in_flight(BlockDriverState *bs); | ||
1992 | +/* DO NOT ADD ANYTHING IN HERE. USE ONE OF THE HEADERS INCLUDED ABOVE */ | ||
1993 | |||
1994 | -#endif | ||
1995 | +#endif /* BLOCK_H */ | ||
1996 | diff --git a/block.c b/block.c | ||
1997 | index XXXXXXX..XXXXXXX 100644 | ||
1998 | --- a/block.c | ||
1999 | +++ b/block.c | ||
2000 | @@ -XXX,XX +XXX,XX @@ | ||
2001 | |||
2002 | #define NOT_DONE 0x7fffffff /* used while emulated sync operation in progress */ | ||
2003 | |||
2004 | +/* Protected by BQL */ | ||
2005 | static QTAILQ_HEAD(, BlockDriverState) graph_bdrv_states = | ||
2006 | QTAILQ_HEAD_INITIALIZER(graph_bdrv_states); | ||
2007 | |||
2008 | +/* Protected by BQL */ | ||
2009 | static QTAILQ_HEAD(, BlockDriverState) all_bdrv_states = | ||
2010 | QTAILQ_HEAD_INITIALIZER(all_bdrv_states); | ||
2011 | |||
2012 | +/* Protected by BQL */ | ||
2013 | static QLIST_HEAD(, BlockDriver) bdrv_drivers = | ||
2014 | QLIST_HEAD_INITIALIZER(bdrv_drivers); | ||
2015 | |||
2016 | diff --git a/block/meson.build b/block/meson.build | ||
2017 | index XXXXXXX..XXXXXXX 100644 | ||
2018 | --- a/block/meson.build | ||
2019 | +++ b/block/meson.build | ||
2020 | @@ -XXX,XX +XXX,XX @@ block_ss.add(module_block_h) | ||
2021 | wrapper_py = find_program('../scripts/block-coroutine-wrapper.py') | ||
2022 | block_gen_c = custom_target('block-gen.c', | ||
2023 | output: 'block-gen.c', | ||
2024 | - input: files('../include/block/block.h', | ||
2025 | - 'coroutines.h'), | ||
2026 | + input: files( | ||
2027 | + '../include/block/block-io.h', | ||
2028 | + '../include/block/block-global-state.h', | ||
2029 | + 'coroutines.h' | ||
2030 | + ), | ||
2031 | command: [wrapper_py, '@OUTPUT@', '@INPUT@']) | ||
2032 | block_ss.add(block_gen_c) | ||
2033 | |||
2034 | -- | 177 | -- |
2035 | 2.35.1 | 178 | 2.13.6 |
179 | |||
180 | diff view generated by jsdifflib |
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | 1 | Now that the bdrv_drain_invoke() calls are pulled up to the callers of |
---|---|---|---|
2 | bdrv_drain_recurse(), the 'begin' parameter isn't needed any more. | ||
2 | 3 | ||
3 | Mark all I/O functions with IO_CODE, and all "I/O OR GS" with | 4 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
4 | IO_OR_GS_CODE. | 5 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> |
6 | --- | ||
7 | block/io.c | 12 ++++++------ | ||
8 | 1 file changed, 6 insertions(+), 6 deletions(-) | ||
5 | 9 | ||
6 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
7 | Message-Id: <20220303151616.325444-14-eesposit@redhat.com> | ||
8 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
9 | --- | ||
10 | include/block/block_int-io.h | 6 ++++++ | ||
11 | block.c | 14 +++++++++++++- | ||
12 | block/block-backend.c | 2 ++ | ||
13 | block/dirty-bitmap.c | 3 +++ | ||
14 | block/io.c | 13 +++++++++++++ | ||
15 | 5 files changed, 37 insertions(+), 1 deletion(-) | ||
16 | |||
17 | diff --git a/include/block/block_int-io.h b/include/block/block_int-io.h | ||
18 | index XXXXXXX..XXXXXXX 100644 | ||
19 | --- a/include/block/block_int-io.h | ||
20 | +++ b/include/block/block_int-io.h | ||
21 | @@ -XXX,XX +XXX,XX @@ static inline int coroutine_fn bdrv_co_pread(BdrvChild *child, | ||
22 | int64_t offset, unsigned int bytes, void *buf, BdrvRequestFlags flags) | ||
23 | { | ||
24 | QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes); | ||
25 | + IO_CODE(); | ||
26 | |||
27 | return bdrv_co_preadv(child, offset, bytes, &qiov, flags); | ||
28 | } | ||
29 | @@ -XXX,XX +XXX,XX @@ static inline int coroutine_fn bdrv_co_pwrite(BdrvChild *child, | ||
30 | int64_t offset, unsigned int bytes, void *buf, BdrvRequestFlags flags) | ||
31 | { | ||
32 | QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes); | ||
33 | + IO_CODE(); | ||
34 | |||
35 | return bdrv_co_pwritev(child, offset, bytes, &qiov, flags); | ||
36 | } | ||
37 | @@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_backing_chain_next(BlockDriverState *bs); | ||
38 | |||
39 | static inline BlockDriverState *bdrv_cow_bs(BlockDriverState *bs) | ||
40 | { | ||
41 | + IO_CODE(); | ||
42 | return child_bs(bdrv_cow_child(bs)); | ||
43 | } | ||
44 | |||
45 | static inline BlockDriverState *bdrv_filter_bs(BlockDriverState *bs) | ||
46 | { | ||
47 | + IO_CODE(); | ||
48 | return child_bs(bdrv_filter_child(bs)); | ||
49 | } | ||
50 | |||
51 | static inline BlockDriverState *bdrv_filter_or_cow_bs(BlockDriverState *bs) | ||
52 | { | ||
53 | + IO_CODE(); | ||
54 | return child_bs(bdrv_filter_or_cow_child(bs)); | ||
55 | } | ||
56 | |||
57 | static inline BlockDriverState *bdrv_primary_bs(BlockDriverState *bs) | ||
58 | { | ||
59 | + IO_CODE(); | ||
60 | return child_bs(bdrv_primary_child(bs)); | ||
61 | } | ||
62 | |||
63 | diff --git a/block.c b/block.c | ||
64 | index XXXXXXX..XXXXXXX 100644 | ||
65 | --- a/block.c | ||
66 | +++ b/block.c | ||
67 | @@ -XXX,XX +XXX,XX @@ BlockDriver *bdrv_probe_all(const uint8_t *buf, int buf_size, | ||
68 | { | ||
69 | int score_max = 0, score; | ||
70 | BlockDriver *drv = NULL, *d; | ||
71 | + IO_CODE(); | ||
72 | |||
73 | QLIST_FOREACH(d, &bdrv_drivers, list) { | ||
74 | if (d->bdrv_probe) { | ||
75 | @@ -XXX,XX +XXX,XX @@ static int find_image_format(BlockBackend *file, const char *filename, | ||
76 | int refresh_total_sectors(BlockDriverState *bs, int64_t hint) | ||
77 | { | ||
78 | BlockDriver *drv = bs->drv; | ||
79 | + IO_CODE(); | ||
80 | |||
81 | if (!drv) { | ||
82 | return -ENOMEDIUM; | ||
83 | @@ -XXX,XX +XXX,XX @@ const char *bdrv_get_parent_name(const BlockDriverState *bs) | ||
84 | { | ||
85 | BdrvChild *c; | ||
86 | const char *name; | ||
87 | + IO_CODE(); | ||
88 | |||
89 | /* If multiple parents have a name, just pick the first one. */ | ||
90 | QLIST_FOREACH(c, &bs->parents, next_parent) { | ||
91 | @@ -XXX,XX +XXX,XX @@ int bdrv_make_empty(BdrvChild *c, Error **errp) | ||
92 | */ | ||
93 | BdrvChild *bdrv_cow_child(BlockDriverState *bs) | ||
94 | { | ||
95 | + IO_CODE(); | ||
96 | + | ||
97 | if (!bs || !bs->drv) { | ||
98 | return NULL; | ||
99 | } | ||
100 | @@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_cow_child(BlockDriverState *bs) | ||
101 | BdrvChild *bdrv_filter_child(BlockDriverState *bs) | ||
102 | { | ||
103 | BdrvChild *c; | ||
104 | + IO_CODE(); | ||
105 | |||
106 | if (!bs || !bs->drv) { | ||
107 | return NULL; | ||
108 | @@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_filter_or_cow_child(BlockDriverState *bs) | ||
109 | { | ||
110 | BdrvChild *cow_child = bdrv_cow_child(bs); | ||
111 | BdrvChild *filter_child = bdrv_filter_child(bs); | ||
112 | + IO_CODE(); | ||
113 | |||
114 | /* Filter nodes cannot have COW backing files */ | ||
115 | assert(!(cow_child && filter_child)); | ||
116 | @@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_filter_or_cow_child(BlockDriverState *bs) | ||
117 | BdrvChild *bdrv_primary_child(BlockDriverState *bs) | ||
118 | { | ||
119 | BdrvChild *c, *found = NULL; | ||
120 | + IO_CODE(); | ||
121 | |||
122 | QLIST_FOREACH(c, &bs->children, next) { | ||
123 | if (c->role & BDRV_CHILD_PRIMARY) { | ||
124 | @@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_skip_implicit_filters(BlockDriverState *bs) | ||
125 | */ | ||
126 | BlockDriverState *bdrv_skip_filters(BlockDriverState *bs) | ||
127 | { | ||
128 | + IO_CODE(); | ||
129 | return bdrv_do_skip_filters(bs, false); | ||
130 | } | ||
131 | |||
132 | @@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_skip_filters(BlockDriverState *bs) | ||
133 | */ | ||
134 | BlockDriverState *bdrv_backing_chain_next(BlockDriverState *bs) | ||
135 | { | ||
136 | + IO_CODE(); | ||
137 | return bdrv_skip_filters(bdrv_cow_bs(bdrv_skip_filters(bs))); | ||
138 | } | ||
139 | |||
140 | @@ -XXX,XX +XXX,XX @@ static bool bdrv_bsc_range_overlaps_locked(BlockDriverState *bs, | ||
141 | */ | ||
142 | bool bdrv_bsc_is_data(BlockDriverState *bs, int64_t offset, int64_t *pnum) | ||
143 | { | ||
144 | + IO_CODE(); | ||
145 | RCU_READ_LOCK_GUARD(); | ||
146 | - | ||
147 | return bdrv_bsc_range_overlaps_locked(bs, offset, 1, pnum); | ||
148 | } | ||
149 | |||
150 | @@ -XXX,XX +XXX,XX @@ bool bdrv_bsc_is_data(BlockDriverState *bs, int64_t offset, int64_t *pnum) | ||
151 | void bdrv_bsc_invalidate_range(BlockDriverState *bs, | ||
152 | int64_t offset, int64_t bytes) | ||
153 | { | ||
154 | + IO_CODE(); | ||
155 | RCU_READ_LOCK_GUARD(); | ||
156 | |||
157 | if (bdrv_bsc_range_overlaps_locked(bs, offset, bytes, NULL)) { | ||
158 | @@ -XXX,XX +XXX,XX @@ void bdrv_bsc_fill(BlockDriverState *bs, int64_t offset, int64_t bytes) | ||
159 | { | ||
160 | BdrvBlockStatusCache *new_bsc = g_new(BdrvBlockStatusCache, 1); | ||
161 | BdrvBlockStatusCache *old_bsc; | ||
162 | + IO_CODE(); | ||
163 | |||
164 | *new_bsc = (BdrvBlockStatusCache) { | ||
165 | .valid = true, | ||
166 | diff --git a/block/block-backend.c b/block/block-backend.c | ||
167 | index XXXXXXX..XXXXXXX 100644 | ||
168 | --- a/block/block-backend.c | ||
169 | +++ b/block/block-backend.c | ||
170 | @@ -XXX,XX +XXX,XX @@ bool blk_dev_has_removable_media(BlockBackend *blk) | ||
171 | */ | ||
172 | bool blk_dev_has_tray(BlockBackend *blk) | ||
173 | { | ||
174 | + IO_CODE(); | ||
175 | return blk->dev_ops && blk->dev_ops->is_tray_open; | ||
176 | } | ||
177 | |||
178 | @@ -XXX,XX +XXX,XX @@ void blk_dev_eject_request(BlockBackend *blk, bool force) | ||
179 | */ | ||
180 | bool blk_dev_is_tray_open(BlockBackend *blk) | ||
181 | { | ||
182 | + IO_CODE(); | ||
183 | if (blk_dev_has_tray(blk)) { | ||
184 | return blk->dev_ops->is_tray_open(blk->dev_opaque); | ||
185 | } | ||
186 | diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c | ||
187 | index XXXXXXX..XXXXXXX 100644 | ||
188 | --- a/block/dirty-bitmap.c | ||
189 | +++ b/block/dirty-bitmap.c | ||
190 | @@ -XXX,XX +XXX,XX @@ void bdrv_reset_dirty_bitmap(BdrvDirtyBitmap *bitmap, | ||
191 | |||
192 | void bdrv_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap **out) | ||
193 | { | ||
194 | + IO_CODE(); | ||
195 | assert(!bdrv_dirty_bitmap_readonly(bitmap)); | ||
196 | bdrv_dirty_bitmaps_lock(bitmap->bs); | ||
197 | if (!out) { | ||
198 | @@ -XXX,XX +XXX,XX @@ void bdrv_dirty_bitmap_deserialize_finish(BdrvDirtyBitmap *bitmap) | ||
199 | void bdrv_set_dirty(BlockDriverState *bs, int64_t offset, int64_t bytes) | ||
200 | { | ||
201 | BdrvDirtyBitmap *bitmap; | ||
202 | + IO_CODE(); | ||
203 | |||
204 | if (QLIST_EMPTY(&bs->dirty_bitmaps)) { | ||
205 | return; | ||
206 | @@ -XXX,XX +XXX,XX @@ bool bdrv_dirty_bitmap_merge_internal(BdrvDirtyBitmap *dest, | ||
207 | bool lock) | ||
208 | { | ||
209 | bool ret; | ||
210 | + IO_CODE(); | ||
211 | |||
212 | assert(!bdrv_dirty_bitmap_readonly(dest)); | ||
213 | assert(!bdrv_dirty_bitmap_inconsistent(dest)); | ||
214 | diff --git a/block/io.c b/block/io.c | 10 | diff --git a/block/io.c b/block/io.c |
215 | index XXXXXXX..XXXXXXX 100644 | 11 | index XXXXXXX..XXXXXXX 100644 |
216 | --- a/block/io.c | 12 | --- a/block/io.c |
217 | +++ b/block/io.c | 13 | +++ b/block/io.c |
218 | @@ -XXX,XX +XXX,XX @@ void bdrv_subtree_drained_end(BlockDriverState *bs) | 14 | @@ -XXX,XX +XXX,XX @@ static void bdrv_drain_invoke(BlockDriverState *bs, bool begin) |
219 | void bdrv_apply_subtree_drain(BdrvChild *child, BlockDriverState *new_parent) | 15 | } |
16 | } | ||
17 | |||
18 | -static bool bdrv_drain_recurse(BlockDriverState *bs, bool begin) | ||
19 | +static bool bdrv_drain_recurse(BlockDriverState *bs) | ||
220 | { | 20 | { |
221 | int i; | 21 | BdrvChild *child, *tmp; |
222 | + IO_OR_GS_CODE(); | 22 | bool waited; |
223 | 23 | @@ -XXX,XX +XXX,XX @@ static bool bdrv_drain_recurse(BlockDriverState *bs, bool begin) | |
224 | for (i = 0; i < new_parent->recursive_quiesce_counter; i++) { | 24 | */ |
225 | bdrv_do_drained_begin(child->bs, true, child, false, true); | 25 | bdrv_ref(bs); |
226 | @@ -XXX,XX +XXX,XX @@ void bdrv_unapply_subtree_drain(BdrvChild *child, BlockDriverState *old_parent) | 26 | } |
227 | { | 27 | - waited |= bdrv_drain_recurse(bs, begin); |
228 | int drained_end_counter = 0; | 28 | + waited |= bdrv_drain_recurse(bs); |
229 | int i; | 29 | if (in_main_loop) { |
230 | + IO_OR_GS_CODE(); | 30 | bdrv_unref(bs); |
231 | 31 | } | |
232 | for (i = 0; i < old_parent->recursive_quiesce_counter; i++) { | 32 | @@ -XXX,XX +XXX,XX @@ void bdrv_drained_begin(BlockDriverState *bs) |
233 | bdrv_do_drained_end(child->bs, true, child, false, | 33 | } |
234 | @@ -XXX,XX +XXX,XX @@ BdrvTrackedRequest *coroutine_fn bdrv_co_get_self_request(BlockDriverState *bs) | 34 | |
235 | { | 35 | bdrv_drain_invoke(bs, true); |
236 | BdrvTrackedRequest *req; | 36 | - bdrv_drain_recurse(bs, true); |
237 | Coroutine *self = qemu_coroutine_self(); | 37 | + bdrv_drain_recurse(bs); |
238 | + IO_CODE(); | ||
239 | |||
240 | QLIST_FOREACH(req, &bs->tracked_requests, list) { | ||
241 | if (req->co == self) { | ||
242 | @@ -XXX,XX +XXX,XX @@ static int bdrv_get_cluster_size(BlockDriverState *bs) | ||
243 | |||
244 | void bdrv_inc_in_flight(BlockDriverState *bs) | ||
245 | { | ||
246 | + IO_CODE(); | ||
247 | qatomic_inc(&bs->in_flight); | ||
248 | } | 38 | } |
249 | 39 | ||
250 | void bdrv_wakeup(BlockDriverState *bs) | 40 | void bdrv_drained_end(BlockDriverState *bs) |
251 | { | 41 | @@ -XXX,XX +XXX,XX @@ void bdrv_drained_end(BlockDriverState *bs) |
252 | + IO_CODE(); | 42 | |
253 | aio_wait_kick(); | 43 | bdrv_parent_drained_end(bs); |
44 | bdrv_drain_invoke(bs, false); | ||
45 | - bdrv_drain_recurse(bs, false); | ||
46 | + bdrv_drain_recurse(bs); | ||
47 | aio_enable_external(bdrv_get_aio_context(bs)); | ||
254 | } | 48 | } |
255 | 49 | ||
256 | void bdrv_dec_in_flight(BlockDriverState *bs) | 50 | @@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void) |
257 | { | 51 | aio_context_acquire(aio_context); |
258 | + IO_CODE(); | 52 | for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { |
259 | qatomic_dec(&bs->in_flight); | 53 | if (aio_context == bdrv_get_aio_context(bs)) { |
260 | bdrv_wakeup(bs); | 54 | - waited |= bdrv_drain_recurse(bs, true); |
261 | } | 55 | + waited |= bdrv_drain_recurse(bs); |
262 | @@ -XXX,XX +XXX,XX @@ bool coroutine_fn bdrv_make_request_serialising(BdrvTrackedRequest *req, | 56 | } |
263 | uint64_t align) | 57 | } |
264 | { | 58 | aio_context_release(aio_context); |
265 | bool waited; | 59 | @@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_end(void) |
266 | + IO_CODE(); | 60 | aio_enable_external(aio_context); |
267 | 61 | bdrv_parent_drained_end(bs); | |
268 | qemu_co_mutex_lock(&req->bs->reqs_lock); | 62 | bdrv_drain_invoke(bs, false); |
269 | 63 | - bdrv_drain_recurse(bs, false); | |
270 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_preadv(BdrvChild *child, | 64 | + bdrv_drain_recurse(bs); |
271 | int64_t offset, int64_t bytes, QEMUIOVector *qiov, | 65 | aio_context_release(aio_context); |
272 | BdrvRequestFlags flags) | 66 | } |
273 | { | 67 | |
274 | + IO_CODE(); | ||
275 | return bdrv_co_preadv_part(child, offset, bytes, qiov, 0, flags); | ||
276 | } | ||
277 | |||
278 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_preadv_part(BdrvChild *child, | ||
279 | BdrvTrackedRequest req; | ||
280 | BdrvRequestPadding pad; | ||
281 | int ret; | ||
282 | + IO_CODE(); | ||
283 | |||
284 | trace_bdrv_co_preadv_part(bs, offset, bytes, flags); | ||
285 | |||
286 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_pwritev(BdrvChild *child, | ||
287 | int64_t offset, int64_t bytes, QEMUIOVector *qiov, | ||
288 | BdrvRequestFlags flags) | ||
289 | { | ||
290 | + IO_CODE(); | ||
291 | return bdrv_co_pwritev_part(child, offset, bytes, qiov, 0, flags); | ||
292 | } | ||
293 | |||
294 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_pwritev_part(BdrvChild *child, | ||
295 | BdrvRequestPadding pad; | ||
296 | int ret; | ||
297 | bool padded = false; | ||
298 | + IO_CODE(); | ||
299 | |||
300 | trace_bdrv_co_pwritev_part(child->bs, offset, bytes, flags); | ||
301 | |||
302 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_copy_range_from(BdrvChild *src, int64_t src_offset, | ||
303 | BdrvRequestFlags read_flags, | ||
304 | BdrvRequestFlags write_flags) | ||
305 | { | ||
306 | + IO_CODE(); | ||
307 | trace_bdrv_co_copy_range_from(src, src_offset, dst, dst_offset, bytes, | ||
308 | read_flags, write_flags); | ||
309 | return bdrv_co_copy_range_internal(src, src_offset, dst, dst_offset, | ||
310 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_copy_range_to(BdrvChild *src, int64_t src_offset, | ||
311 | BdrvRequestFlags read_flags, | ||
312 | BdrvRequestFlags write_flags) | ||
313 | { | ||
314 | + IO_CODE(); | ||
315 | trace_bdrv_co_copy_range_to(src, src_offset, dst, dst_offset, bytes, | ||
316 | read_flags, write_flags); | ||
317 | return bdrv_co_copy_range_internal(src, src_offset, dst, dst_offset, | ||
318 | -- | 68 | -- |
319 | 2.35.1 | 69 | 2.13.6 |
70 | |||
71 | diff view generated by jsdifflib |
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | 1 | The device is drained, so there is no point in waiting for requests at |
---|---|---|---|
2 | the end of the drained section. Remove the bdrv_drain_recurse() calls | ||
3 | there. | ||
2 | 4 | ||
3 | block coroutines functions run in different aiocontext, and are | 5 | The bdrv_drain_recurse() calls were introduced in commit 481cad48e5e |
4 | not protected by the BQL. Therefore are I/O. | 6 | in order to call the .bdrv_co_drain_end() driver callback. This is now |
7 | done by a separate bdrv_drain_invoke() call. | ||
5 | 8 | ||
6 | On the other side, generated_co_wrapper functions use BDRV_POLL_WHILE, | 9 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
7 | meaning the caller can either be the main loop or a specific iothread. | 10 | Reviewed-by: Paolo Bonzini <pbonzini@redhat.com> |
11 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
12 | --- | ||
13 | block/io.c | 2 -- | ||
14 | 1 file changed, 2 deletions(-) | ||
8 | 15 | ||
9 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
10 | Message-Id: <20220303151616.325444-25-eesposit@redhat.com> | ||
11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
12 | --- | ||
13 | block/coroutines.h | 81 +++++++++++++++++++++++++++---------------- | ||
14 | block.c | 2 ++ | ||
15 | block/block-backend.c | 6 ++++ | ||
16 | block/io.c | 3 ++ | ||
17 | block/nbd.c | 1 + | ||
18 | 5 files changed, 64 insertions(+), 29 deletions(-) | ||
19 | |||
20 | diff --git a/block/coroutines.h b/block/coroutines.h | ||
21 | index XXXXXXX..XXXXXXX 100644 | ||
22 | --- a/block/coroutines.h | ||
23 | +++ b/block/coroutines.h | ||
24 | @@ -XXX,XX +XXX,XX @@ | ||
25 | /* For blk_bs() in generated block/block-gen.c */ | ||
26 | #include "sysemu/block-backend.h" | ||
27 | |||
28 | +/* | ||
29 | + * I/O API functions. These functions are thread-safe. | ||
30 | + * | ||
31 | + * See include/block/block-io.h for more information about | ||
32 | + * the I/O API. | ||
33 | + */ | ||
34 | + | ||
35 | int coroutine_fn bdrv_co_check(BlockDriverState *bs, | ||
36 | BdrvCheckResult *res, BdrvCheckMode fix); | ||
37 | int coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs, Error **errp); | ||
38 | |||
39 | -int generated_co_wrapper | ||
40 | -bdrv_preadv(BdrvChild *child, int64_t offset, unsigned int bytes, | ||
41 | - QEMUIOVector *qiov, BdrvRequestFlags flags); | ||
42 | -int generated_co_wrapper | ||
43 | -bdrv_pwritev(BdrvChild *child, int64_t offset, unsigned int bytes, | ||
44 | - QEMUIOVector *qiov, BdrvRequestFlags flags); | ||
45 | - | ||
46 | int coroutine_fn | ||
47 | bdrv_co_common_block_status_above(BlockDriverState *bs, | ||
48 | BlockDriverState *base, | ||
49 | @@ -XXX,XX +XXX,XX @@ bdrv_co_common_block_status_above(BlockDriverState *bs, | ||
50 | int64_t *map, | ||
51 | BlockDriverState **file, | ||
52 | int *depth); | ||
53 | + | ||
54 | +int coroutine_fn bdrv_co_readv_vmstate(BlockDriverState *bs, | ||
55 | + QEMUIOVector *qiov, int64_t pos); | ||
56 | +int coroutine_fn bdrv_co_writev_vmstate(BlockDriverState *bs, | ||
57 | + QEMUIOVector *qiov, int64_t pos); | ||
58 | + | ||
59 | +int coroutine_fn | ||
60 | +nbd_co_do_establish_connection(BlockDriverState *bs, Error **errp); | ||
61 | + | ||
62 | + | ||
63 | +int coroutine_fn | ||
64 | +blk_co_do_preadv(BlockBackend *blk, int64_t offset, int64_t bytes, | ||
65 | + QEMUIOVector *qiov, BdrvRequestFlags flags); | ||
66 | + | ||
67 | + | ||
68 | +int coroutine_fn | ||
69 | +blk_co_do_pwritev_part(BlockBackend *blk, int64_t offset, int64_t bytes, | ||
70 | + QEMUIOVector *qiov, size_t qiov_offset, | ||
71 | + BdrvRequestFlags flags); | ||
72 | + | ||
73 | +int coroutine_fn | ||
74 | +blk_co_do_ioctl(BlockBackend *blk, unsigned long int req, void *buf); | ||
75 | + | ||
76 | +int coroutine_fn | ||
77 | +blk_co_do_pdiscard(BlockBackend *blk, int64_t offset, int64_t bytes); | ||
78 | + | ||
79 | +int coroutine_fn blk_co_do_flush(BlockBackend *blk); | ||
80 | + | ||
81 | + | ||
82 | +/* | ||
83 | + * "I/O or GS" API functions. These functions can run without | ||
84 | + * the BQL, but only in one specific iothread/main loop. | ||
85 | + * | ||
86 | + * See include/block/block-io.h for more information about | ||
87 | + * the "I/O or GS" API. | ||
88 | + */ | ||
89 | + | ||
90 | +int generated_co_wrapper | ||
91 | +bdrv_preadv(BdrvChild *child, int64_t offset, unsigned int bytes, | ||
92 | + QEMUIOVector *qiov, BdrvRequestFlags flags); | ||
93 | + | ||
94 | +int generated_co_wrapper | ||
95 | +bdrv_pwritev(BdrvChild *child, int64_t offset, unsigned int bytes, | ||
96 | + QEMUIOVector *qiov, BdrvRequestFlags flags); | ||
97 | + | ||
98 | int generated_co_wrapper | ||
99 | bdrv_common_block_status_above(BlockDriverState *bs, | ||
100 | BlockDriverState *base, | ||
101 | @@ -XXX,XX +XXX,XX @@ bdrv_common_block_status_above(BlockDriverState *bs, | ||
102 | int64_t *map, | ||
103 | BlockDriverState **file, | ||
104 | int *depth); | ||
105 | - | ||
106 | -int coroutine_fn bdrv_co_readv_vmstate(BlockDriverState *bs, | ||
107 | - QEMUIOVector *qiov, int64_t pos); | ||
108 | -int coroutine_fn bdrv_co_writev_vmstate(BlockDriverState *bs, | ||
109 | - QEMUIOVector *qiov, int64_t pos); | ||
110 | - | ||
111 | int generated_co_wrapper | ||
112 | nbd_do_establish_connection(BlockDriverState *bs, Error **errp); | ||
113 | -int coroutine_fn | ||
114 | -nbd_co_do_establish_connection(BlockDriverState *bs, Error **errp); | ||
115 | - | ||
116 | |||
117 | int generated_co_wrapper | ||
118 | blk_do_preadv(BlockBackend *blk, int64_t offset, int64_t bytes, | ||
119 | QEMUIOVector *qiov, BdrvRequestFlags flags); | ||
120 | -int coroutine_fn | ||
121 | -blk_co_do_preadv(BlockBackend *blk, int64_t offset, int64_t bytes, | ||
122 | - QEMUIOVector *qiov, BdrvRequestFlags flags); | ||
123 | - | ||
124 | |||
125 | int generated_co_wrapper | ||
126 | blk_do_pwritev_part(BlockBackend *blk, int64_t offset, int64_t bytes, | ||
127 | QEMUIOVector *qiov, size_t qiov_offset, | ||
128 | BdrvRequestFlags flags); | ||
129 | -int coroutine_fn | ||
130 | -blk_co_do_pwritev_part(BlockBackend *blk, int64_t offset, int64_t bytes, | ||
131 | - QEMUIOVector *qiov, size_t qiov_offset, | ||
132 | - BdrvRequestFlags flags); | ||
133 | |||
134 | int generated_co_wrapper | ||
135 | blk_do_ioctl(BlockBackend *blk, unsigned long int req, void *buf); | ||
136 | -int coroutine_fn | ||
137 | -blk_co_do_ioctl(BlockBackend *blk, unsigned long int req, void *buf); | ||
138 | |||
139 | int generated_co_wrapper | ||
140 | blk_do_pdiscard(BlockBackend *blk, int64_t offset, int64_t bytes); | ||
141 | -int coroutine_fn | ||
142 | -blk_co_do_pdiscard(BlockBackend *blk, int64_t offset, int64_t bytes); | ||
143 | |||
144 | int generated_co_wrapper blk_do_flush(BlockBackend *blk); | ||
145 | -int coroutine_fn blk_co_do_flush(BlockBackend *blk); | ||
146 | |||
147 | #endif /* BLOCK_COROUTINES_INT_H */ | ||
148 | diff --git a/block.c b/block.c | ||
149 | index XXXXXXX..XXXXXXX 100644 | ||
150 | --- a/block.c | ||
151 | +++ b/block.c | ||
152 | @@ -XXX,XX +XXX,XX @@ fail: | ||
153 | int coroutine_fn bdrv_co_check(BlockDriverState *bs, | ||
154 | BdrvCheckResult *res, BdrvCheckMode fix) | ||
155 | { | ||
156 | + IO_CODE(); | ||
157 | if (bs->drv == NULL) { | ||
158 | return -ENOMEDIUM; | ||
159 | } | ||
160 | @@ -XXX,XX +XXX,XX @@ int bdrv_activate(BlockDriverState *bs, Error **errp) | ||
161 | int coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs, Error **errp) | ||
162 | { | ||
163 | Error *local_err = NULL; | ||
164 | + IO_CODE(); | ||
165 | |||
166 | assert(!(bs->open_flags & BDRV_O_INACTIVE)); | ||
167 | |||
168 | diff --git a/block/block-backend.c b/block/block-backend.c | ||
169 | index XXXXXXX..XXXXXXX 100644 | ||
170 | --- a/block/block-backend.c | ||
171 | +++ b/block/block-backend.c | ||
172 | @@ -XXX,XX +XXX,XX @@ blk_co_do_preadv(BlockBackend *blk, int64_t offset, int64_t bytes, | ||
173 | { | ||
174 | int ret; | ||
175 | BlockDriverState *bs; | ||
176 | + IO_CODE(); | ||
177 | |||
178 | blk_wait_while_drained(blk); | ||
179 | |||
180 | @@ -XXX,XX +XXX,XX @@ blk_co_do_pwritev_part(BlockBackend *blk, int64_t offset, int64_t bytes, | ||
181 | { | ||
182 | int ret; | ||
183 | BlockDriverState *bs; | ||
184 | + IO_CODE(); | ||
185 | |||
186 | blk_wait_while_drained(blk); | ||
187 | |||
188 | @@ -XXX,XX +XXX,XX @@ void blk_aio_cancel_async(BlockAIOCB *acb) | ||
189 | int coroutine_fn | ||
190 | blk_co_do_ioctl(BlockBackend *blk, unsigned long int req, void *buf) | ||
191 | { | ||
192 | + IO_CODE(); | ||
193 | + | ||
194 | blk_wait_while_drained(blk); | ||
195 | |||
196 | if (!blk_is_available(blk)) { | ||
197 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn | ||
198 | blk_co_do_pdiscard(BlockBackend *blk, int64_t offset, int64_t bytes) | ||
199 | { | ||
200 | int ret; | ||
201 | + IO_CODE(); | ||
202 | |||
203 | blk_wait_while_drained(blk); | ||
204 | |||
205 | @@ -XXX,XX +XXX,XX @@ int blk_pdiscard(BlockBackend *blk, int64_t offset, int64_t bytes) | ||
206 | int coroutine_fn blk_co_do_flush(BlockBackend *blk) | ||
207 | { | ||
208 | blk_wait_while_drained(blk); | ||
209 | + IO_CODE(); | ||
210 | |||
211 | if (!blk_is_available(blk)) { | ||
212 | return -ENOMEDIUM; | ||
213 | diff --git a/block/io.c b/block/io.c | 16 | diff --git a/block/io.c b/block/io.c |
214 | index XXXXXXX..XXXXXXX 100644 | 17 | index XXXXXXX..XXXXXXX 100644 |
215 | --- a/block/io.c | 18 | --- a/block/io.c |
216 | +++ b/block/io.c | 19 | +++ b/block/io.c |
217 | @@ -XXX,XX +XXX,XX @@ bdrv_co_common_block_status_above(BlockDriverState *bs, | 20 | @@ -XXX,XX +XXX,XX @@ void bdrv_drained_end(BlockDriverState *bs) |
218 | BlockDriverState *p; | 21 | |
219 | int64_t eof = 0; | 22 | bdrv_parent_drained_end(bs); |
220 | int dummy; | 23 | bdrv_drain_invoke(bs, false); |
221 | + IO_CODE(); | 24 | - bdrv_drain_recurse(bs); |
222 | 25 | aio_enable_external(bdrv_get_aio_context(bs)); | |
223 | assert(!include_base || base); /* Can't include NULL base */ | 26 | } |
224 | 27 | ||
225 | @@ -XXX,XX +XXX,XX @@ bdrv_co_readv_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos) | 28 | @@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_end(void) |
226 | BlockDriver *drv = bs->drv; | 29 | aio_enable_external(aio_context); |
227 | BlockDriverState *child_bs = bdrv_primary_bs(bs); | 30 | bdrv_parent_drained_end(bs); |
228 | int ret; | 31 | bdrv_drain_invoke(bs, false); |
229 | + IO_CODE(); | 32 | - bdrv_drain_recurse(bs); |
230 | 33 | aio_context_release(aio_context); | |
231 | ret = bdrv_check_qiov_request(pos, qiov->size, qiov, 0, NULL); | 34 | } |
232 | if (ret < 0) { | ||
233 | @@ -XXX,XX +XXX,XX @@ bdrv_co_writev_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos) | ||
234 | BlockDriver *drv = bs->drv; | ||
235 | BlockDriverState *child_bs = bdrv_primary_bs(bs); | ||
236 | int ret; | ||
237 | + IO_CODE(); | ||
238 | |||
239 | ret = bdrv_check_qiov_request(pos, qiov->size, qiov, 0, NULL); | ||
240 | if (ret < 0) { | ||
241 | diff --git a/block/nbd.c b/block/nbd.c | ||
242 | index XXXXXXX..XXXXXXX 100644 | ||
243 | --- a/block/nbd.c | ||
244 | +++ b/block/nbd.c | ||
245 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn nbd_co_do_establish_connection(BlockDriverState *bs, | ||
246 | BDRVNBDState *s = (BDRVNBDState *)bs->opaque; | ||
247 | int ret; | ||
248 | bool blocking = nbd_client_connecting_wait(s); | ||
249 | + IO_CODE(); | ||
250 | |||
251 | assert(!s->ioc); | ||
252 | 35 | ||
253 | -- | 36 | -- |
254 | 2.35.1 | 37 | 2.13.6 |
38 | |||
39 | diff view generated by jsdifflib |
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | 1 | Drain requests are propagated to child nodes, parent nodes and directly |
---|---|---|---|
2 | to the AioContext. The order in which this happened was different | ||
3 | between all combinations of drain/drain_all and begin/end. | ||
2 | 4 | ||
3 | All the global state (GS) API functions will check that | 5 | The correct order is to keep children only drained when their parents |
4 | qemu_in_main_thread() returns true. If not, it means | 6 | are also drained. This means that at the start of a drained section, the |
5 | that the safety of BQL cannot be guaranteed, and | 7 | AioContext needs to be drained first, the parents second and only then |
6 | they need to be moved to I/O. | 8 | the children. The correct order for the end of a drained section is the |
9 | opposite. | ||
7 | 10 | ||
8 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | 11 | This patch changes the three other functions to follow the example of |
9 | Message-Id: <20220303151616.325444-9-eesposit@redhat.com> | 12 | bdrv_drained_begin(), which is the only one that got it right. |
13 | |||
10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 14 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
15 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
11 | --- | 16 | --- |
12 | block/block-backend.c | 78 ++++++++++++++++++++++++++++++++++++++++++ | 17 | block/io.c | 12 ++++++++---- |
13 | softmmu/qdev-monitor.c | 2 ++ | 18 | 1 file changed, 8 insertions(+), 4 deletions(-) |
14 | 2 files changed, 80 insertions(+) | ||
15 | 19 | ||
16 | diff --git a/block/block-backend.c b/block/block-backend.c | 20 | diff --git a/block/io.c b/block/io.c |
17 | index XXXXXXX..XXXXXXX 100644 | 21 | index XXXXXXX..XXXXXXX 100644 |
18 | --- a/block/block-backend.c | 22 | --- a/block/io.c |
19 | +++ b/block/block-backend.c | 23 | +++ b/block/io.c |
20 | @@ -XXX,XX +XXX,XX @@ static void blk_root_activate(BdrvChild *child, Error **errp) | 24 | @@ -XXX,XX +XXX,XX @@ void bdrv_drained_begin(BlockDriverState *bs) |
21 | |||
22 | void blk_set_force_allow_inactivate(BlockBackend *blk) | ||
23 | { | ||
24 | + GLOBAL_STATE_CODE(); | ||
25 | blk->force_allow_inactivate = true; | ||
26 | } | ||
27 | |||
28 | @@ -XXX,XX +XXX,XX @@ BlockBackend *blk_new(AioContext *ctx, uint64_t perm, uint64_t shared_perm) | ||
29 | { | ||
30 | BlockBackend *blk; | ||
31 | |||
32 | + GLOBAL_STATE_CODE(); | ||
33 | + | ||
34 | blk = g_new0(BlockBackend, 1); | ||
35 | blk->refcnt = 1; | ||
36 | blk->ctx = ctx; | ||
37 | @@ -XXX,XX +XXX,XX @@ BlockBackend *blk_new_with_bs(BlockDriverState *bs, uint64_t perm, | ||
38 | { | ||
39 | BlockBackend *blk = blk_new(bdrv_get_aio_context(bs), perm, shared_perm); | ||
40 | |||
41 | + GLOBAL_STATE_CODE(); | ||
42 | + | ||
43 | if (blk_insert_bs(blk, bs, errp) < 0) { | ||
44 | blk_unref(blk); | ||
45 | return NULL; | ||
46 | @@ -XXX,XX +XXX,XX @@ BlockBackend *blk_new_open(const char *filename, const char *reference, | ||
47 | uint64_t perm = 0; | ||
48 | uint64_t shared = BLK_PERM_ALL; | ||
49 | |||
50 | + GLOBAL_STATE_CODE(); | ||
51 | + | ||
52 | /* | ||
53 | * blk_new_open() is mainly used in .bdrv_create implementations and the | ||
54 | * tools where sharing isn't a major concern because the BDS stays private | ||
55 | @@ -XXX,XX +XXX,XX @@ static void drive_info_del(DriveInfo *dinfo) | ||
56 | |||
57 | int blk_get_refcnt(BlockBackend *blk) | ||
58 | { | ||
59 | + GLOBAL_STATE_CODE(); | ||
60 | return blk ? blk->refcnt : 0; | ||
61 | } | ||
62 | |||
63 | @@ -XXX,XX +XXX,XX @@ int blk_get_refcnt(BlockBackend *blk) | ||
64 | void blk_ref(BlockBackend *blk) | ||
65 | { | ||
66 | assert(blk->refcnt > 0); | ||
67 | + GLOBAL_STATE_CODE(); | ||
68 | blk->refcnt++; | ||
69 | } | ||
70 | |||
71 | @@ -XXX,XX +XXX,XX @@ void blk_ref(BlockBackend *blk) | ||
72 | */ | ||
73 | void blk_unref(BlockBackend *blk) | ||
74 | { | ||
75 | + GLOBAL_STATE_CODE(); | ||
76 | if (blk) { | ||
77 | assert(blk->refcnt > 0); | ||
78 | if (blk->refcnt > 1) { | ||
79 | @@ -XXX,XX +XXX,XX @@ void blk_unref(BlockBackend *blk) | ||
80 | */ | ||
81 | BlockBackend *blk_all_next(BlockBackend *blk) | ||
82 | { | ||
83 | + GLOBAL_STATE_CODE(); | ||
84 | return blk ? QTAILQ_NEXT(blk, link) | ||
85 | : QTAILQ_FIRST(&block_backends); | ||
86 | } | ||
87 | @@ -XXX,XX +XXX,XX @@ void blk_remove_all_bs(void) | ||
88 | { | ||
89 | BlockBackend *blk = NULL; | ||
90 | |||
91 | + GLOBAL_STATE_CODE(); | ||
92 | + | ||
93 | while ((blk = blk_all_next(blk)) != NULL) { | ||
94 | AioContext *ctx = blk_get_aio_context(blk); | ||
95 | |||
96 | @@ -XXX,XX +XXX,XX @@ void blk_remove_all_bs(void) | ||
97 | */ | ||
98 | BlockBackend *blk_next(BlockBackend *blk) | ||
99 | { | ||
100 | + GLOBAL_STATE_CODE(); | ||
101 | return blk ? QTAILQ_NEXT(blk, monitor_link) | ||
102 | : QTAILQ_FIRST(&monitor_block_backends); | ||
103 | } | ||
104 | @@ -XXX,XX +XXX,XX @@ static void bdrv_next_reset(BdrvNextIterator *it) | ||
105 | |||
106 | BlockDriverState *bdrv_first(BdrvNextIterator *it) | ||
107 | { | ||
108 | + GLOBAL_STATE_CODE(); | ||
109 | bdrv_next_reset(it); | ||
110 | return bdrv_next(it); | ||
111 | } | ||
112 | @@ -XXX,XX +XXX,XX @@ bool monitor_add_blk(BlockBackend *blk, const char *name, Error **errp) | ||
113 | { | ||
114 | assert(!blk->name); | ||
115 | assert(name && name[0]); | ||
116 | + GLOBAL_STATE_CODE(); | ||
117 | |||
118 | if (!id_wellformed(name)) { | ||
119 | error_setg(errp, "Invalid device name"); | ||
120 | @@ -XXX,XX +XXX,XX @@ bool monitor_add_blk(BlockBackend *blk, const char *name, Error **errp) | ||
121 | */ | ||
122 | void monitor_remove_blk(BlockBackend *blk) | ||
123 | { | ||
124 | + GLOBAL_STATE_CODE(); | ||
125 | + | ||
126 | if (!blk->name) { | ||
127 | return; | 25 | return; |
128 | } | 26 | } |
129 | @@ -XXX,XX +XXX,XX @@ BlockBackend *blk_by_name(const char *name) | 27 | |
130 | { | 28 | + /* Stop things in parent-to-child order */ |
131 | BlockBackend *blk = NULL; | 29 | if (atomic_fetch_inc(&bs->quiesce_counter) == 0) { |
132 | 30 | aio_disable_external(bdrv_get_aio_context(bs)); | |
133 | + GLOBAL_STATE_CODE(); | 31 | bdrv_parent_drained_begin(bs); |
134 | assert(name); | 32 | @@ -XXX,XX +XXX,XX @@ void bdrv_drained_end(BlockDriverState *bs) |
135 | while ((blk = blk_next(blk)) != NULL) { | 33 | return; |
136 | if (!strcmp(name, blk->name)) { | 34 | } |
137 | @@ -XXX,XX +XXX,XX @@ static BlockBackend *bdrv_first_blk(BlockDriverState *bs) | 35 | |
138 | */ | 36 | - bdrv_parent_drained_end(bs); |
139 | bool bdrv_has_blk(BlockDriverState *bs) | 37 | + /* Re-enable things in child-to-parent order */ |
140 | { | 38 | bdrv_drain_invoke(bs, false); |
141 | + GLOBAL_STATE_CODE(); | 39 | + bdrv_parent_drained_end(bs); |
142 | return bdrv_first_blk(bs) != NULL; | 40 | aio_enable_external(bdrv_get_aio_context(bs)); |
143 | } | 41 | } |
144 | 42 | ||
145 | @@ -XXX,XX +XXX,XX @@ bool bdrv_is_root_node(BlockDriverState *bs) | 43 | @@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void) |
146 | { | 44 | for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { |
147 | BdrvChild *c; | 45 | AioContext *aio_context = bdrv_get_aio_context(bs); |
148 | 46 | ||
149 | + GLOBAL_STATE_CODE(); | 47 | + /* Stop things in parent-to-child order */ |
150 | QLIST_FOREACH(c, &bs->parents, next_parent) { | 48 | aio_context_acquire(aio_context); |
151 | if (c->klass != &child_root) { | 49 | - bdrv_parent_drained_begin(bs); |
152 | return false; | 50 | aio_disable_external(aio_context); |
153 | @@ -XXX,XX +XXX,XX @@ BlockBackend *blk_by_legacy_dinfo(DriveInfo *dinfo) | 51 | + bdrv_parent_drained_begin(bs); |
154 | */ | 52 | bdrv_drain_invoke(bs, true); |
155 | BlockBackendPublic *blk_get_public(BlockBackend *blk) | 53 | aio_context_release(aio_context); |
156 | { | 54 | |
157 | + GLOBAL_STATE_CODE(); | 55 | @@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_end(void) |
158 | return &blk->public; | 56 | for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { |
159 | } | 57 | AioContext *aio_context = bdrv_get_aio_context(bs); |
160 | 58 | ||
161 | @@ -XXX,XX +XXX,XX @@ BlockBackendPublic *blk_get_public(BlockBackend *blk) | 59 | + /* Re-enable things in child-to-parent order */ |
162 | */ | 60 | aio_context_acquire(aio_context); |
163 | BlockBackend *blk_by_public(BlockBackendPublic *public) | 61 | - aio_enable_external(aio_context); |
164 | { | 62 | - bdrv_parent_drained_end(bs); |
165 | + GLOBAL_STATE_CODE(); | 63 | bdrv_drain_invoke(bs, false); |
166 | return container_of(public, BlockBackend, public); | 64 | + bdrv_parent_drained_end(bs); |
167 | } | 65 | + aio_enable_external(aio_context); |
168 | 66 | aio_context_release(aio_context); | |
169 | @@ -XXX,XX +XXX,XX @@ void blk_remove_bs(BlockBackend *blk) | ||
170 | ThrottleGroupMember *tgm = &blk->public.throttle_group_member; | ||
171 | BdrvChild *root; | ||
172 | |||
173 | + GLOBAL_STATE_CODE(); | ||
174 | + | ||
175 | notifier_list_notify(&blk->remove_bs_notifiers, blk); | ||
176 | if (tgm->throttle_state) { | ||
177 | BlockDriverState *bs = blk_bs(blk); | ||
178 | @@ -XXX,XX +XXX,XX @@ void blk_remove_bs(BlockBackend *blk) | ||
179 | int blk_insert_bs(BlockBackend *blk, BlockDriverState *bs, Error **errp) | ||
180 | { | ||
181 | ThrottleGroupMember *tgm = &blk->public.throttle_group_member; | ||
182 | + GLOBAL_STATE_CODE(); | ||
183 | bdrv_ref(bs); | ||
184 | blk->root = bdrv_root_attach_child(bs, "root", &child_root, | ||
185 | BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, | ||
186 | @@ -XXX,XX +XXX,XX @@ int blk_insert_bs(BlockBackend *blk, BlockDriverState *bs, Error **errp) | ||
187 | */ | ||
188 | int blk_replace_bs(BlockBackend *blk, BlockDriverState *new_bs, Error **errp) | ||
189 | { | ||
190 | + GLOBAL_STATE_CODE(); | ||
191 | return bdrv_replace_child_bs(blk->root, new_bs, errp); | ||
192 | } | ||
193 | |||
194 | @@ -XXX,XX +XXX,XX @@ int blk_set_perm(BlockBackend *blk, uint64_t perm, uint64_t shared_perm, | ||
195 | Error **errp) | ||
196 | { | ||
197 | int ret; | ||
198 | + GLOBAL_STATE_CODE(); | ||
199 | |||
200 | if (blk->root && !blk->disable_perm) { | ||
201 | ret = bdrv_child_try_set_perm(blk->root, perm, shared_perm, errp); | ||
202 | @@ -XXX,XX +XXX,XX @@ int blk_set_perm(BlockBackend *blk, uint64_t perm, uint64_t shared_perm, | ||
203 | |||
204 | void blk_get_perm(BlockBackend *blk, uint64_t *perm, uint64_t *shared_perm) | ||
205 | { | ||
206 | + GLOBAL_STATE_CODE(); | ||
207 | *perm = blk->perm; | ||
208 | *shared_perm = blk->shared_perm; | ||
209 | } | ||
210 | @@ -XXX,XX +XXX,XX @@ void blk_get_perm(BlockBackend *blk, uint64_t *perm, uint64_t *shared_perm) | ||
211 | */ | ||
212 | int blk_attach_dev(BlockBackend *blk, DeviceState *dev) | ||
213 | { | ||
214 | + GLOBAL_STATE_CODE(); | ||
215 | if (blk->dev) { | ||
216 | return -EBUSY; | ||
217 | } | 67 | } |
218 | @@ -XXX,XX +XXX,XX @@ int blk_attach_dev(BlockBackend *blk, DeviceState *dev) | 68 | |
219 | void blk_detach_dev(BlockBackend *blk, DeviceState *dev) | ||
220 | { | ||
221 | assert(blk->dev == dev); | ||
222 | + GLOBAL_STATE_CODE(); | ||
223 | blk->dev = NULL; | ||
224 | blk->dev_ops = NULL; | ||
225 | blk->dev_opaque = NULL; | ||
226 | @@ -XXX,XX +XXX,XX @@ void blk_detach_dev(BlockBackend *blk, DeviceState *dev) | ||
227 | */ | ||
228 | DeviceState *blk_get_attached_dev(BlockBackend *blk) | ||
229 | { | ||
230 | + GLOBAL_STATE_CODE(); | ||
231 | return blk->dev; | ||
232 | } | ||
233 | |||
234 | @@ -XXX,XX +XXX,XX @@ BlockBackend *blk_by_dev(void *dev) | ||
235 | { | ||
236 | BlockBackend *blk = NULL; | ||
237 | |||
238 | + GLOBAL_STATE_CODE(); | ||
239 | + | ||
240 | assert(dev != NULL); | ||
241 | while ((blk = blk_all_next(blk)) != NULL) { | ||
242 | if (blk->dev == dev) { | ||
243 | @@ -XXX,XX +XXX,XX @@ BlockBackend *blk_by_dev(void *dev) | ||
244 | void blk_set_dev_ops(BlockBackend *blk, const BlockDevOps *ops, | ||
245 | void *opaque) | ||
246 | { | ||
247 | + GLOBAL_STATE_CODE(); | ||
248 | blk->dev_ops = ops; | ||
249 | blk->dev_opaque = opaque; | ||
250 | |||
251 | @@ -XXX,XX +XXX,XX @@ void blk_set_dev_ops(BlockBackend *blk, const BlockDevOps *ops, | ||
252 | */ | ||
253 | void blk_dev_change_media_cb(BlockBackend *blk, bool load, Error **errp) | ||
254 | { | ||
255 | + GLOBAL_STATE_CODE(); | ||
256 | if (blk->dev_ops && blk->dev_ops->change_media_cb) { | ||
257 | bool tray_was_open, tray_is_open; | ||
258 | Error *local_err = NULL; | ||
259 | @@ -XXX,XX +XXX,XX @@ static void blk_root_resize(BdrvChild *child) | ||
260 | |||
261 | void blk_iostatus_enable(BlockBackend *blk) | ||
262 | { | ||
263 | + GLOBAL_STATE_CODE(); | ||
264 | blk->iostatus_enabled = true; | ||
265 | blk->iostatus = BLOCK_DEVICE_IO_STATUS_OK; | ||
266 | } | ||
267 | @@ -XXX,XX +XXX,XX @@ bool blk_iostatus_is_enabled(const BlockBackend *blk) | ||
268 | |||
269 | BlockDeviceIoStatus blk_iostatus(const BlockBackend *blk) | ||
270 | { | ||
271 | + GLOBAL_STATE_CODE(); | ||
272 | return blk->iostatus; | ||
273 | } | ||
274 | |||
275 | void blk_iostatus_disable(BlockBackend *blk) | ||
276 | { | ||
277 | + GLOBAL_STATE_CODE(); | ||
278 | blk->iostatus_enabled = false; | ||
279 | } | ||
280 | |||
281 | void blk_iostatus_reset(BlockBackend *blk) | ||
282 | { | ||
283 | + GLOBAL_STATE_CODE(); | ||
284 | if (blk_iostatus_is_enabled(blk)) { | ||
285 | blk->iostatus = BLOCK_DEVICE_IO_STATUS_OK; | ||
286 | } | ||
287 | @@ -XXX,XX +XXX,XX @@ int blk_pwrite_zeroes(BlockBackend *blk, int64_t offset, | ||
288 | |||
289 | int blk_make_zero(BlockBackend *blk, BdrvRequestFlags flags) | ||
290 | { | ||
291 | + GLOBAL_STATE_CODE(); | ||
292 | return bdrv_make_zero(blk->root, flags); | ||
293 | } | ||
294 | |||
295 | @@ -XXX,XX +XXX,XX @@ BlockAIOCB *blk_aio_pwritev(BlockBackend *blk, int64_t offset, | ||
296 | |||
297 | void blk_aio_cancel(BlockAIOCB *acb) | ||
298 | { | ||
299 | + GLOBAL_STATE_CODE(); | ||
300 | bdrv_aio_cancel(acb); | ||
301 | } | ||
302 | |||
303 | @@ -XXX,XX +XXX,XX @@ int blk_flush(BlockBackend *blk) | ||
304 | void blk_drain(BlockBackend *blk) | ||
305 | { | ||
306 | BlockDriverState *bs = blk_bs(blk); | ||
307 | + GLOBAL_STATE_CODE(); | ||
308 | |||
309 | if (bs) { | ||
310 | bdrv_ref(bs); | ||
311 | @@ -XXX,XX +XXX,XX @@ void blk_drain_all(void) | ||
312 | { | ||
313 | BlockBackend *blk = NULL; | ||
314 | |||
315 | + GLOBAL_STATE_CODE(); | ||
316 | + | ||
317 | bdrv_drain_all_begin(); | ||
318 | |||
319 | while ((blk = blk_all_next(blk)) != NULL) { | ||
320 | @@ -XXX,XX +XXX,XX @@ void blk_drain_all(void) | ||
321 | void blk_set_on_error(BlockBackend *blk, BlockdevOnError on_read_error, | ||
322 | BlockdevOnError on_write_error) | ||
323 | { | ||
324 | + GLOBAL_STATE_CODE(); | ||
325 | blk->on_read_error = on_read_error; | ||
326 | blk->on_write_error = on_write_error; | ||
327 | } | ||
328 | @@ -XXX,XX +XXX,XX @@ void blk_error_action(BlockBackend *blk, BlockErrorAction action, | ||
329 | bool blk_supports_write_perm(BlockBackend *blk) | ||
330 | { | ||
331 | BlockDriverState *bs = blk_bs(blk); | ||
332 | + GLOBAL_STATE_CODE(); | ||
333 | |||
334 | if (bs) { | ||
335 | return !bdrv_is_read_only(bs); | ||
336 | @@ -XXX,XX +XXX,XX @@ bool blk_is_writable(BlockBackend *blk) | ||
337 | bool blk_is_sg(BlockBackend *blk) | ||
338 | { | ||
339 | BlockDriverState *bs = blk_bs(blk); | ||
340 | + GLOBAL_STATE_CODE(); | ||
341 | |||
342 | if (!bs) { | ||
343 | return false; | ||
344 | @@ -XXX,XX +XXX,XX @@ bool blk_enable_write_cache(BlockBackend *blk) | ||
345 | |||
346 | void blk_set_enable_write_cache(BlockBackend *blk, bool wce) | ||
347 | { | ||
348 | + GLOBAL_STATE_CODE(); | ||
349 | blk->enable_write_cache = wce; | ||
350 | } | ||
351 | |||
352 | void blk_activate(BlockBackend *blk, Error **errp) | ||
353 | { | ||
354 | BlockDriverState *bs = blk_bs(blk); | ||
355 | + GLOBAL_STATE_CODE(); | ||
356 | |||
357 | if (!bs) { | ||
358 | error_setg(errp, "Device '%s' has no medium", blk->name); | ||
359 | @@ -XXX,XX +XXX,XX @@ void blk_eject(BlockBackend *blk, bool eject_flag) | ||
360 | int blk_get_flags(BlockBackend *blk) | ||
361 | { | ||
362 | BlockDriverState *bs = blk_bs(blk); | ||
363 | + GLOBAL_STATE_CODE(); | ||
364 | |||
365 | if (bs) { | ||
366 | return bdrv_get_flags(bs); | ||
367 | @@ -XXX,XX +XXX,XX @@ void *blk_blockalign(BlockBackend *blk, size_t size) | ||
368 | bool blk_op_is_blocked(BlockBackend *blk, BlockOpType op, Error **errp) | ||
369 | { | ||
370 | BlockDriverState *bs = blk_bs(blk); | ||
371 | + GLOBAL_STATE_CODE(); | ||
372 | |||
373 | if (!bs) { | ||
374 | return false; | ||
375 | @@ -XXX,XX +XXX,XX @@ bool blk_op_is_blocked(BlockBackend *blk, BlockOpType op, Error **errp) | ||
376 | void blk_op_unblock(BlockBackend *blk, BlockOpType op, Error *reason) | ||
377 | { | ||
378 | BlockDriverState *bs = blk_bs(blk); | ||
379 | + GLOBAL_STATE_CODE(); | ||
380 | |||
381 | if (bs) { | ||
382 | bdrv_op_unblock(bs, op, reason); | ||
383 | @@ -XXX,XX +XXX,XX @@ void blk_op_unblock(BlockBackend *blk, BlockOpType op, Error *reason) | ||
384 | void blk_op_block_all(BlockBackend *blk, Error *reason) | ||
385 | { | ||
386 | BlockDriverState *bs = blk_bs(blk); | ||
387 | + GLOBAL_STATE_CODE(); | ||
388 | |||
389 | if (bs) { | ||
390 | bdrv_op_block_all(bs, reason); | ||
391 | @@ -XXX,XX +XXX,XX @@ void blk_op_block_all(BlockBackend *blk, Error *reason) | ||
392 | void blk_op_unblock_all(BlockBackend *blk, Error *reason) | ||
393 | { | ||
394 | BlockDriverState *bs = blk_bs(blk); | ||
395 | + GLOBAL_STATE_CODE(); | ||
396 | |||
397 | if (bs) { | ||
398 | bdrv_op_unblock_all(bs, reason); | ||
399 | @@ -XXX,XX +XXX,XX @@ static int blk_do_set_aio_context(BlockBackend *blk, AioContext *new_context, | ||
400 | int blk_set_aio_context(BlockBackend *blk, AioContext *new_context, | ||
401 | Error **errp) | ||
402 | { | ||
403 | + GLOBAL_STATE_CODE(); | ||
404 | return blk_do_set_aio_context(blk, new_context, true, errp); | ||
405 | } | ||
406 | |||
407 | @@ -XXX,XX +XXX,XX @@ void blk_add_aio_context_notifier(BlockBackend *blk, | ||
408 | { | ||
409 | BlockBackendAioNotifier *notifier; | ||
410 | BlockDriverState *bs = blk_bs(blk); | ||
411 | + GLOBAL_STATE_CODE(); | ||
412 | |||
413 | notifier = g_new(BlockBackendAioNotifier, 1); | ||
414 | notifier->attached_aio_context = attached_aio_context; | ||
415 | @@ -XXX,XX +XXX,XX @@ void blk_remove_aio_context_notifier(BlockBackend *blk, | ||
416 | BlockBackendAioNotifier *notifier; | ||
417 | BlockDriverState *bs = blk_bs(blk); | ||
418 | |||
419 | + GLOBAL_STATE_CODE(); | ||
420 | + | ||
421 | if (bs) { | ||
422 | bdrv_remove_aio_context_notifier(bs, attached_aio_context, | ||
423 | detach_aio_context, opaque); | ||
424 | @@ -XXX,XX +XXX,XX @@ void blk_remove_aio_context_notifier(BlockBackend *blk, | ||
425 | |||
426 | void blk_add_remove_bs_notifier(BlockBackend *blk, Notifier *notify) | ||
427 | { | ||
428 | + GLOBAL_STATE_CODE(); | ||
429 | notifier_list_add(&blk->remove_bs_notifiers, notify); | ||
430 | } | ||
431 | |||
432 | void blk_add_insert_bs_notifier(BlockBackend *blk, Notifier *notify) | ||
433 | { | ||
434 | + GLOBAL_STATE_CODE(); | ||
435 | notifier_list_add(&blk->insert_bs_notifiers, notify); | ||
436 | } | ||
437 | |||
438 | @@ -XXX,XX +XXX,XX @@ int blk_save_vmstate(BlockBackend *blk, const uint8_t *buf, | ||
439 | int64_t pos, int size) | ||
440 | { | ||
441 | int ret; | ||
442 | + GLOBAL_STATE_CODE(); | ||
443 | |||
444 | if (!blk_is_available(blk)) { | ||
445 | return -ENOMEDIUM; | ||
446 | @@ -XXX,XX +XXX,XX @@ int blk_save_vmstate(BlockBackend *blk, const uint8_t *buf, | ||
447 | |||
448 | int blk_load_vmstate(BlockBackend *blk, uint8_t *buf, int64_t pos, int size) | ||
449 | { | ||
450 | + GLOBAL_STATE_CODE(); | ||
451 | if (!blk_is_available(blk)) { | ||
452 | return -ENOMEDIUM; | ||
453 | } | ||
454 | @@ -XXX,XX +XXX,XX @@ int blk_load_vmstate(BlockBackend *blk, uint8_t *buf, int64_t pos, int size) | ||
455 | |||
456 | int blk_probe_blocksizes(BlockBackend *blk, BlockSizes *bsz) | ||
457 | { | ||
458 | + GLOBAL_STATE_CODE(); | ||
459 | if (!blk_is_available(blk)) { | ||
460 | return -ENOMEDIUM; | ||
461 | } | ||
462 | @@ -XXX,XX +XXX,XX @@ int blk_probe_blocksizes(BlockBackend *blk, BlockSizes *bsz) | ||
463 | |||
464 | int blk_probe_geometry(BlockBackend *blk, HDGeometry *geo) | ||
465 | { | ||
466 | + GLOBAL_STATE_CODE(); | ||
467 | if (!blk_is_available(blk)) { | ||
468 | return -ENOMEDIUM; | ||
469 | } | ||
470 | @@ -XXX,XX +XXX,XX @@ int blk_probe_geometry(BlockBackend *blk, HDGeometry *geo) | ||
471 | */ | ||
472 | void blk_update_root_state(BlockBackend *blk) | ||
473 | { | ||
474 | + GLOBAL_STATE_CODE(); | ||
475 | assert(blk->root); | ||
476 | |||
477 | blk->root_state.open_flags = blk->root->bs->open_flags; | ||
478 | @@ -XXX,XX +XXX,XX @@ void blk_update_root_state(BlockBackend *blk) | ||
479 | */ | ||
480 | bool blk_get_detect_zeroes_from_root_state(BlockBackend *blk) | ||
481 | { | ||
482 | + GLOBAL_STATE_CODE(); | ||
483 | return blk->root_state.detect_zeroes; | ||
484 | } | ||
485 | |||
486 | @@ -XXX,XX +XXX,XX @@ bool blk_get_detect_zeroes_from_root_state(BlockBackend *blk) | ||
487 | */ | ||
488 | int blk_get_open_flags_from_root_state(BlockBackend *blk) | ||
489 | { | ||
490 | + GLOBAL_STATE_CODE(); | ||
491 | return blk->root_state.open_flags; | ||
492 | } | ||
493 | |||
494 | BlockBackendRootState *blk_get_root_state(BlockBackend *blk) | ||
495 | { | ||
496 | + GLOBAL_STATE_CODE(); | ||
497 | return &blk->root_state; | ||
498 | } | ||
499 | |||
500 | int blk_commit_all(void) | ||
501 | { | ||
502 | BlockBackend *blk = NULL; | ||
503 | + GLOBAL_STATE_CODE(); | ||
504 | |||
505 | while ((blk = blk_all_next(blk)) != NULL) { | ||
506 | AioContext *aio_context = blk_get_aio_context(blk); | ||
507 | @@ -XXX,XX +XXX,XX @@ int blk_commit_all(void) | ||
508 | /* throttling disk I/O limits */ | ||
509 | void blk_set_io_limits(BlockBackend *blk, ThrottleConfig *cfg) | ||
510 | { | ||
511 | + GLOBAL_STATE_CODE(); | ||
512 | throttle_group_config(&blk->public.throttle_group_member, cfg); | ||
513 | } | ||
514 | |||
515 | @@ -XXX,XX +XXX,XX @@ void blk_io_limits_disable(BlockBackend *blk) | ||
516 | BlockDriverState *bs = blk_bs(blk); | ||
517 | ThrottleGroupMember *tgm = &blk->public.throttle_group_member; | ||
518 | assert(tgm->throttle_state); | ||
519 | + GLOBAL_STATE_CODE(); | ||
520 | if (bs) { | ||
521 | bdrv_ref(bs); | ||
522 | bdrv_drained_begin(bs); | ||
523 | @@ -XXX,XX +XXX,XX @@ void blk_io_limits_disable(BlockBackend *blk) | ||
524 | void blk_io_limits_enable(BlockBackend *blk, const char *group) | ||
525 | { | ||
526 | assert(!blk->public.throttle_group_member.throttle_state); | ||
527 | + GLOBAL_STATE_CODE(); | ||
528 | throttle_group_register_tgm(&blk->public.throttle_group_member, | ||
529 | group, blk_get_aio_context(blk)); | ||
530 | } | ||
531 | |||
532 | void blk_io_limits_update_group(BlockBackend *blk, const char *group) | ||
533 | { | ||
534 | + GLOBAL_STATE_CODE(); | ||
535 | /* this BB is not part of any group */ | ||
536 | if (!blk->public.throttle_group_member.throttle_state) { | ||
537 | return; | ||
538 | @@ -XXX,XX +XXX,XX @@ static void blk_root_drained_end(BdrvChild *child, int *drained_end_counter) | ||
539 | |||
540 | void blk_register_buf(BlockBackend *blk, void *host, size_t size) | ||
541 | { | ||
542 | + GLOBAL_STATE_CODE(); | ||
543 | bdrv_register_buf(blk_bs(blk), host, size); | ||
544 | } | ||
545 | |||
546 | void blk_unregister_buf(BlockBackend *blk, void *host) | ||
547 | { | ||
548 | + GLOBAL_STATE_CODE(); | ||
549 | bdrv_unregister_buf(blk_bs(blk), host); | ||
550 | } | ||
551 | |||
552 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn blk_co_copy_range(BlockBackend *blk_in, int64_t off_in, | ||
553 | |||
554 | const BdrvChild *blk_root(BlockBackend *blk) | ||
555 | { | ||
556 | + GLOBAL_STATE_CODE(); | ||
557 | return blk->root; | ||
558 | } | ||
559 | |||
560 | int blk_make_empty(BlockBackend *blk, Error **errp) | ||
561 | { | ||
562 | + GLOBAL_STATE_CODE(); | ||
563 | if (!blk_is_available(blk)) { | ||
564 | error_setg(errp, "No medium inserted"); | ||
565 | return -ENOMEDIUM; | ||
566 | diff --git a/softmmu/qdev-monitor.c b/softmmu/qdev-monitor.c | ||
567 | index XXXXXXX..XXXXXXX 100644 | ||
568 | --- a/softmmu/qdev-monitor.c | ||
569 | +++ b/softmmu/qdev-monitor.c | ||
570 | @@ -XXX,XX +XXX,XX @@ BlockBackend *blk_by_qdev_id(const char *id, Error **errp) | ||
571 | DeviceState *dev; | ||
572 | BlockBackend *blk; | ||
573 | |||
574 | + GLOBAL_STATE_CODE(); | ||
575 | + | ||
576 | dev = find_device_state(id, errp); | ||
577 | if (dev == NULL) { | ||
578 | return NULL; | ||
579 | -- | 69 | -- |
580 | 2.35.1 | 70 | 2.13.6 |
71 | |||
72 | diff view generated by jsdifflib |
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | 1 | Commit 15afd94a047 added code to acquire and release the AioContext in |
---|---|---|---|
2 | qemuio_command(). This means that the lock is taken twice now in the | ||
3 | call path from hmp_qemu_io(). This causes BDRV_POLL_WHILE() to hang for | ||
4 | any requests issued to nodes in a non-mainloop AioContext. | ||
2 | 5 | ||
3 | Similar to the header split, also the function pointers in BlockDriver | 6 | Dropping the first locking from hmp_qemu_io() fixes the problem. |
4 | can be split in I/O and global state. | ||
5 | 7 | ||
6 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
7 | Message-Id: <20220303151616.325444-26-eesposit@redhat.com> | ||
8 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 8 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
9 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
9 | --- | 10 | --- |
10 | include/block/block_int-common.h | 445 ++++++++++++++++--------------- | 11 | hmp.c | 6 ------ |
11 | 1 file changed, 237 insertions(+), 208 deletions(-) | 12 | 1 file changed, 6 deletions(-) |
12 | 13 | ||
13 | diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h | 14 | diff --git a/hmp.c b/hmp.c |
14 | index XXXXXXX..XXXXXXX 100644 | 15 | index XXXXXXX..XXXXXXX 100644 |
15 | --- a/include/block/block_int-common.h | 16 | --- a/hmp.c |
16 | +++ b/include/block/block_int-common.h | 17 | +++ b/hmp.c |
17 | @@ -XXX,XX +XXX,XX @@ typedef struct BdrvTrackedRequest { | 18 | @@ -XXX,XX +XXX,XX @@ void hmp_qemu_io(Monitor *mon, const QDict *qdict) |
18 | 19 | { | |
19 | 20 | BlockBackend *blk; | |
20 | struct BlockDriver { | 21 | BlockBackend *local_blk = NULL; |
21 | + /* | 22 | - AioContext *aio_context; |
22 | + * These fields are initialized when this object is created, | 23 | const char* device = qdict_get_str(qdict, "device"); |
23 | + * and are never changed afterwards. | 24 | const char* command = qdict_get_str(qdict, "command"); |
24 | + */ | 25 | Error *err = NULL; |
25 | + | 26 | @@ -XXX,XX +XXX,XX @@ void hmp_qemu_io(Monitor *mon, const QDict *qdict) |
26 | const char *format_name; | 27 | } |
27 | int instance_size; | 28 | } |
28 | 29 | ||
29 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { | 30 | - aio_context = blk_get_aio_context(blk); |
30 | */ | 31 | - aio_context_acquire(aio_context); |
31 | bool is_format; | ||
32 | |||
33 | + /* | ||
34 | + * Drivers not implementing bdrv_parse_filename nor bdrv_open should have | ||
35 | + * this field set to true, except ones that are defined only by their | ||
36 | + * child's bs. | ||
37 | + * An example of the last type will be the quorum block driver. | ||
38 | + */ | ||
39 | + bool bdrv_needs_filename; | ||
40 | + | ||
41 | + /* | ||
42 | + * Set if a driver can support backing files. This also implies the | ||
43 | + * following semantics: | ||
44 | + * | ||
45 | + * - Return status 0 of .bdrv_co_block_status means that corresponding | ||
46 | + * blocks are not allocated in this layer of backing-chain | ||
47 | + * - For such (unallocated) blocks, read will: | ||
48 | + * - fill buffer with zeros if there is no backing file | ||
49 | + * - read from the backing file otherwise, where the block layer | ||
50 | + * takes care of reading zeros beyond EOF if backing file is short | ||
51 | + */ | ||
52 | + bool supports_backing; | ||
53 | + | ||
54 | + bool has_variable_length; | ||
55 | + | ||
56 | + /* | ||
57 | + * Drivers setting this field must be able to work with just a plain | ||
58 | + * filename with '<protocol_name>:' as a prefix, and no other options. | ||
59 | + * Options may be extracted from the filename by implementing | ||
60 | + * bdrv_parse_filename. | ||
61 | + */ | ||
62 | + const char *protocol_name; | ||
63 | + | ||
64 | + /* List of options for creating images, terminated by name == NULL */ | ||
65 | + QemuOptsList *create_opts; | ||
66 | + | ||
67 | + /* List of options for image amend */ | ||
68 | + QemuOptsList *amend_opts; | ||
69 | + | ||
70 | + /* | ||
71 | + * If this driver supports reopening images this contains a | ||
72 | + * NULL-terminated list of the runtime options that can be | ||
73 | + * modified. If an option in this list is unspecified during | ||
74 | + * reopen then it _must_ be reset to its default value or return | ||
75 | + * an error. | ||
76 | + */ | ||
77 | + const char *const *mutable_opts; | ||
78 | + | ||
79 | + /* | ||
80 | + * Pointer to a NULL-terminated array of names of strong options | ||
81 | + * that can be specified for bdrv_open(). A strong option is one | ||
82 | + * that changes the data of a BDS. | ||
83 | + * If this pointer is NULL, the array is considered empty. | ||
84 | + * "filename" and "driver" are always considered strong. | ||
85 | + */ | ||
86 | + const char *const *strong_runtime_opts; | ||
87 | + | ||
88 | + | ||
89 | + /* | ||
90 | + * Global state (GS) API. These functions run under the BQL. | ||
91 | + * | ||
92 | + * See include/block/block-global-state.h for more information about | ||
93 | + * the GS API. | ||
94 | + */ | ||
95 | + | ||
96 | /* | ||
97 | * This function is invoked under BQL before .bdrv_co_amend() | ||
98 | * (which in contrast does not necessarily run under the BQL) | ||
99 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { | ||
100 | bool (*bdrv_recurse_can_replace)(BlockDriverState *bs, | ||
101 | BlockDriverState *to_replace); | ||
102 | |||
103 | - int (*bdrv_probe)(const uint8_t *buf, int buf_size, const char *filename); | ||
104 | int (*bdrv_probe_device)(const char *filename); | ||
105 | |||
106 | /* | ||
107 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { | ||
108 | */ | ||
109 | void (*bdrv_parse_filename)(const char *filename, QDict *options, | ||
110 | Error **errp); | ||
111 | - /* | ||
112 | - * Drivers not implementing bdrv_parse_filename nor bdrv_open should have | ||
113 | - * this field set to true, except ones that are defined only by their | ||
114 | - * child's bs. | ||
115 | - * An example of the last type will be the quorum block driver. | ||
116 | - */ | ||
117 | - bool bdrv_needs_filename; | ||
118 | - | ||
119 | - /* | ||
120 | - * Set if a driver can support backing files. This also implies the | ||
121 | - * following semantics: | ||
122 | - * | ||
123 | - * - Return status 0 of .bdrv_co_block_status means that corresponding | ||
124 | - * blocks are not allocated in this layer of backing-chain | ||
125 | - * - For such (unallocated) blocks, read will: | ||
126 | - * - fill buffer with zeros if there is no backing file | ||
127 | - * - read from the backing file otherwise, where the block layer | ||
128 | - * takes care of reading zeros beyond EOF if backing file is short | ||
129 | - */ | ||
130 | - bool supports_backing; | ||
131 | |||
132 | - /* For handling image reopen for split or non-split files */ | ||
133 | + /* For handling image reopen for split or non-split files. */ | ||
134 | int (*bdrv_reopen_prepare)(BDRVReopenState *reopen_state, | ||
135 | BlockReopenQueue *queue, Error **errp); | ||
136 | void (*bdrv_reopen_commit)(BDRVReopenState *reopen_state); | ||
137 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { | ||
138 | Error **errp); | ||
139 | void (*bdrv_close)(BlockDriverState *bs); | ||
140 | |||
141 | - | ||
142 | int coroutine_fn (*bdrv_co_create)(BlockdevCreateOptions *opts, | ||
143 | Error **errp); | ||
144 | int coroutine_fn (*bdrv_co_create_opts)(BlockDriver *drv, | ||
145 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { | ||
146 | QemuOpts *opts, | ||
147 | Error **errp); | ||
148 | |||
149 | - int coroutine_fn (*bdrv_co_amend)(BlockDriverState *bs, | ||
150 | - BlockdevAmendOptions *opts, | ||
151 | - bool force, | ||
152 | - Error **errp); | ||
153 | - | ||
154 | int (*bdrv_amend_options)(BlockDriverState *bs, | ||
155 | QemuOpts *opts, | ||
156 | BlockDriverAmendStatusCB *status_cb, | ||
157 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { | ||
158 | */ | ||
159 | char *(*bdrv_dirname)(BlockDriverState *bs, Error **errp); | ||
160 | |||
161 | + /* | ||
162 | + * This informs the driver that we are no longer interested in the result | ||
163 | + * of in-flight requests, so don't waste the time if possible. | ||
164 | + * | ||
165 | + * One example usage is to avoid waiting for an nbd target node reconnect | ||
166 | + * timeout during job-cancel with force=true. | ||
167 | + */ | ||
168 | + void (*bdrv_cancel_in_flight)(BlockDriverState *bs); | ||
169 | + | ||
170 | + int (*bdrv_inactivate)(BlockDriverState *bs); | ||
171 | + | ||
172 | + int (*bdrv_snapshot_create)(BlockDriverState *bs, | ||
173 | + QEMUSnapshotInfo *sn_info); | ||
174 | + int (*bdrv_snapshot_goto)(BlockDriverState *bs, | ||
175 | + const char *snapshot_id); | ||
176 | + int (*bdrv_snapshot_delete)(BlockDriverState *bs, | ||
177 | + const char *snapshot_id, | ||
178 | + const char *name, | ||
179 | + Error **errp); | ||
180 | + int (*bdrv_snapshot_list)(BlockDriverState *bs, | ||
181 | + QEMUSnapshotInfo **psn_info); | ||
182 | + int (*bdrv_snapshot_load_tmp)(BlockDriverState *bs, | ||
183 | + const char *snapshot_id, | ||
184 | + const char *name, | ||
185 | + Error **errp); | ||
186 | + | ||
187 | + int (*bdrv_change_backing_file)(BlockDriverState *bs, | ||
188 | + const char *backing_file, const char *backing_fmt); | ||
189 | + | ||
190 | + /* TODO Better pass a option string/QDict/QemuOpts to add any rule? */ | ||
191 | + int (*bdrv_debug_breakpoint)(BlockDriverState *bs, const char *event, | ||
192 | + const char *tag); | ||
193 | + int (*bdrv_debug_remove_breakpoint)(BlockDriverState *bs, | ||
194 | + const char *tag); | ||
195 | + int (*bdrv_debug_resume)(BlockDriverState *bs, const char *tag); | ||
196 | + bool (*bdrv_debug_is_suspended)(BlockDriverState *bs, const char *tag); | ||
197 | + | ||
198 | + void (*bdrv_refresh_limits)(BlockDriverState *bs, Error **errp); | ||
199 | + | ||
200 | + /* | ||
201 | + * Returns 1 if newly created images are guaranteed to contain only | ||
202 | + * zeros, 0 otherwise. | ||
203 | + */ | ||
204 | + int (*bdrv_has_zero_init)(BlockDriverState *bs); | ||
205 | + | ||
206 | + /* | ||
207 | + * Remove fd handlers, timers, and other event loop callbacks so the event | ||
208 | + * loop is no longer in use. Called with no in-flight requests and in | ||
209 | + * depth-first traversal order with parents before child nodes. | ||
210 | + */ | ||
211 | + void (*bdrv_detach_aio_context)(BlockDriverState *bs); | ||
212 | + | ||
213 | + /* | ||
214 | + * Add fd handlers, timers, and other event loop callbacks so I/O requests | ||
215 | + * can be processed again. Called with no in-flight requests and in | ||
216 | + * depth-first traversal order with child nodes before parent nodes. | ||
217 | + */ | ||
218 | + void (*bdrv_attach_aio_context)(BlockDriverState *bs, | ||
219 | + AioContext *new_context); | ||
220 | + | ||
221 | + /** | ||
222 | + * Try to get @bs's logical and physical block size. | ||
223 | + * On success, store them in @bsz and return zero. | ||
224 | + * On failure, return negative errno. | ||
225 | + */ | ||
226 | + int (*bdrv_probe_blocksizes)(BlockDriverState *bs, BlockSizes *bsz); | ||
227 | + /** | ||
228 | + * Try to get @bs's geometry (cyls, heads, sectors) | ||
229 | + * On success, store them in @geo and return 0. | ||
230 | + * On failure return -errno. | ||
231 | + * Only drivers that want to override guest geometry implement this | ||
232 | + * callback; see hd_geometry_guess(). | ||
233 | + */ | ||
234 | + int (*bdrv_probe_geometry)(BlockDriverState *bs, HDGeometry *geo); | ||
235 | + | ||
236 | + void (*bdrv_add_child)(BlockDriverState *parent, BlockDriverState *child, | ||
237 | + Error **errp); | ||
238 | + void (*bdrv_del_child)(BlockDriverState *parent, BdrvChild *child, | ||
239 | + Error **errp); | ||
240 | + | ||
241 | + /** | ||
242 | + * Informs the block driver that a permission change is intended. The | ||
243 | + * driver checks whether the change is permissible and may take other | ||
244 | + * preparations for the change (e.g. get file system locks). This operation | ||
245 | + * is always followed either by a call to either .bdrv_set_perm or | ||
246 | + * .bdrv_abort_perm_update. | ||
247 | + * | ||
248 | + * Checks whether the requested set of cumulative permissions in @perm | ||
249 | + * can be granted for accessing @bs and whether no other users are using | ||
250 | + * permissions other than those given in @shared (both arguments take | ||
251 | + * BLK_PERM_* bitmasks). | ||
252 | + * | ||
253 | + * If both conditions are met, 0 is returned. Otherwise, -errno is returned | ||
254 | + * and errp is set to an error describing the conflict. | ||
255 | + */ | ||
256 | + int (*bdrv_check_perm)(BlockDriverState *bs, uint64_t perm, | ||
257 | + uint64_t shared, Error **errp); | ||
258 | + | ||
259 | + /** | ||
260 | + * Called to inform the driver that the set of cumulative set of used | ||
261 | + * permissions for @bs has changed to @perm, and the set of sharable | ||
262 | + * permission to @shared. The driver can use this to propagate changes to | ||
263 | + * its children (i.e. request permissions only if a parent actually needs | ||
264 | + * them). | ||
265 | + * | ||
266 | + * This function is only invoked after bdrv_check_perm(), so block drivers | ||
267 | + * may rely on preparations made in their .bdrv_check_perm implementation. | ||
268 | + */ | ||
269 | + void (*bdrv_set_perm)(BlockDriverState *bs, uint64_t perm, uint64_t shared); | ||
270 | + | ||
271 | + /* | ||
272 | + * Called to inform the driver that after a previous bdrv_check_perm() | ||
273 | + * call, the permission update is not performed and any preparations made | ||
274 | + * for it (e.g. taken file locks) need to be undone. | ||
275 | + * | ||
276 | + * This function can be called even for nodes that never saw a | ||
277 | + * bdrv_check_perm() call. It is a no-op then. | ||
278 | + */ | ||
279 | + void (*bdrv_abort_perm_update)(BlockDriverState *bs); | ||
280 | + | ||
281 | + /** | ||
282 | + * Returns in @nperm and @nshared the permissions that the driver for @bs | ||
283 | + * needs on its child @c, based on the cumulative permissions requested by | ||
284 | + * the parents in @parent_perm and @parent_shared. | ||
285 | + * | ||
286 | + * If @c is NULL, return the permissions for attaching a new child for the | ||
287 | + * given @child_class and @role. | ||
288 | + * | ||
289 | + * If @reopen_queue is non-NULL, don't return the currently needed | ||
290 | + * permissions, but those that will be needed after applying the | ||
291 | + * @reopen_queue. | ||
292 | + */ | ||
293 | + void (*bdrv_child_perm)(BlockDriverState *bs, BdrvChild *c, | ||
294 | + BdrvChildRole role, | ||
295 | + BlockReopenQueue *reopen_queue, | ||
296 | + uint64_t parent_perm, uint64_t parent_shared, | ||
297 | + uint64_t *nperm, uint64_t *nshared); | ||
298 | + | ||
299 | + /** | ||
300 | + * Register/unregister a buffer for I/O. For example, when the driver is | ||
301 | + * interested to know the memory areas that will later be used in iovs, so | ||
302 | + * that it can do IOMMU mapping with VFIO etc., in order to get better | ||
303 | + * performance. In the case of VFIO drivers, this callback is used to do | ||
304 | + * DMA mapping for hot buffers. | ||
305 | + */ | ||
306 | + void (*bdrv_register_buf)(BlockDriverState *bs, void *host, size_t size); | ||
307 | + void (*bdrv_unregister_buf)(BlockDriverState *bs, void *host); | ||
308 | + | ||
309 | + /* | ||
310 | + * This field is modified only under the BQL, and is part of | ||
311 | + * the global state. | ||
312 | + */ | ||
313 | + QLIST_ENTRY(BlockDriver) list; | ||
314 | + | ||
315 | + /* | ||
316 | + * I/O API functions. These functions are thread-safe. | ||
317 | + * | ||
318 | + * See include/block/block-io.h for more information about | ||
319 | + * the I/O API. | ||
320 | + */ | ||
321 | + | ||
322 | + int (*bdrv_probe)(const uint8_t *buf, int buf_size, const char *filename); | ||
323 | + | ||
324 | + int coroutine_fn (*bdrv_co_amend)(BlockDriverState *bs, | ||
325 | + BlockdevAmendOptions *opts, | ||
326 | + bool force, | ||
327 | + Error **errp); | ||
328 | + | ||
329 | /* aio */ | ||
330 | BlockAIOCB *(*bdrv_aio_preadv)(BlockDriverState *bs, | ||
331 | int64_t offset, int64_t bytes, QEMUIOVector *qiov, | ||
332 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { | ||
333 | bool want_zero, int64_t offset, int64_t bytes, int64_t *pnum, | ||
334 | int64_t *map, BlockDriverState **file); | ||
335 | |||
336 | - /* | ||
337 | - * This informs the driver that we are no longer interested in the result | ||
338 | - * of in-flight requests, so don't waste the time if possible. | ||
339 | - * | ||
340 | - * One example usage is to avoid waiting for an nbd target node reconnect | ||
341 | - * timeout during job-cancel with force=true. | ||
342 | - */ | ||
343 | - void (*bdrv_cancel_in_flight)(BlockDriverState *bs); | ||
344 | - | 32 | - |
345 | /* | 33 | /* |
346 | * Invalidate any cached meta-data. | 34 | * Notably absent: Proper permission management. This is sad, but it seems |
35 | * almost impossible to achieve without changing the semantics and thereby | ||
36 | @@ -XXX,XX +XXX,XX @@ void hmp_qemu_io(Monitor *mon, const QDict *qdict) | ||
347 | */ | 37 | */ |
348 | void coroutine_fn (*bdrv_co_invalidate_cache)(BlockDriverState *bs, | 38 | qemuio_command(blk, command); |
349 | Error **errp); | 39 | |
350 | - int (*bdrv_inactivate)(BlockDriverState *bs); | 40 | - aio_context_release(aio_context); |
351 | |||
352 | /* | ||
353 | * Flushes all data for all layers by calling bdrv_co_flush for underlying | ||
354 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { | ||
355 | */ | ||
356 | int coroutine_fn (*bdrv_co_flush_to_os)(BlockDriverState *bs); | ||
357 | |||
358 | - /* | ||
359 | - * Drivers setting this field must be able to work with just a plain | ||
360 | - * filename with '<protocol_name>:' as a prefix, and no other options. | ||
361 | - * Options may be extracted from the filename by implementing | ||
362 | - * bdrv_parse_filename. | ||
363 | - */ | ||
364 | - const char *protocol_name; | ||
365 | - | 41 | - |
366 | /* | 42 | fail: |
367 | * Truncate @bs to @offset bytes using the given @prealloc mode | 43 | blk_unref(local_blk); |
368 | * when growing. Modes other than PREALLOC_MODE_OFF should be | 44 | hmp_handle_error(mon, &err); |
369 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { | ||
370 | bool exact, PreallocMode prealloc, | ||
371 | BdrvRequestFlags flags, Error **errp); | ||
372 | int64_t (*bdrv_getlength)(BlockDriverState *bs); | ||
373 | - bool has_variable_length; | ||
374 | int64_t (*bdrv_get_allocated_file_size)(BlockDriverState *bs); | ||
375 | BlockMeasureInfo *(*bdrv_measure)(QemuOpts *opts, BlockDriverState *in_bs, | ||
376 | Error **errp); | ||
377 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { | ||
378 | int64_t offset, int64_t bytes, QEMUIOVector *qiov, | ||
379 | size_t qiov_offset); | ||
380 | |||
381 | - int (*bdrv_snapshot_create)(BlockDriverState *bs, | ||
382 | - QEMUSnapshotInfo *sn_info); | ||
383 | - int (*bdrv_snapshot_goto)(BlockDriverState *bs, | ||
384 | - const char *snapshot_id); | ||
385 | - int (*bdrv_snapshot_delete)(BlockDriverState *bs, | ||
386 | - const char *snapshot_id, | ||
387 | - const char *name, | ||
388 | - Error **errp); | ||
389 | - int (*bdrv_snapshot_list)(BlockDriverState *bs, | ||
390 | - QEMUSnapshotInfo **psn_info); | ||
391 | - int (*bdrv_snapshot_load_tmp)(BlockDriverState *bs, | ||
392 | - const char *snapshot_id, | ||
393 | - const char *name, | ||
394 | - Error **errp); | ||
395 | int (*bdrv_get_info)(BlockDriverState *bs, BlockDriverInfo *bdi); | ||
396 | |||
397 | ImageInfoSpecific *(*bdrv_get_specific_info)(BlockDriverState *bs, | ||
398 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { | ||
399 | QEMUIOVector *qiov, | ||
400 | int64_t pos); | ||
401 | |||
402 | - int (*bdrv_change_backing_file)(BlockDriverState *bs, | ||
403 | - const char *backing_file, const char *backing_fmt); | ||
404 | - | ||
405 | /* removable device specific */ | ||
406 | bool (*bdrv_is_inserted)(BlockDriverState *bs); | ||
407 | void (*bdrv_eject)(BlockDriverState *bs, bool eject_flag); | ||
408 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { | ||
409 | int coroutine_fn (*bdrv_co_ioctl)(BlockDriverState *bs, | ||
410 | unsigned long int req, void *buf); | ||
411 | |||
412 | - /* List of options for creating images, terminated by name == NULL */ | ||
413 | - QemuOptsList *create_opts; | ||
414 | - | ||
415 | - /* List of options for image amend */ | ||
416 | - QemuOptsList *amend_opts; | ||
417 | - | ||
418 | - /* | ||
419 | - * If this driver supports reopening images this contains a | ||
420 | - * NULL-terminated list of the runtime options that can be | ||
421 | - * modified. If an option in this list is unspecified during | ||
422 | - * reopen then it _must_ be reset to its default value or return | ||
423 | - * an error. | ||
424 | - */ | ||
425 | - const char *const *mutable_opts; | ||
426 | - | ||
427 | /* | ||
428 | * Returns 0 for completed check, -errno for internal errors. | ||
429 | * The check results are stored in result. | ||
430 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { | ||
431 | |||
432 | void (*bdrv_debug_event)(BlockDriverState *bs, BlkdebugEvent event); | ||
433 | |||
434 | - /* TODO Better pass a option string/QDict/QemuOpts to add any rule? */ | ||
435 | - int (*bdrv_debug_breakpoint)(BlockDriverState *bs, const char *event, | ||
436 | - const char *tag); | ||
437 | - int (*bdrv_debug_remove_breakpoint)(BlockDriverState *bs, | ||
438 | - const char *tag); | ||
439 | - int (*bdrv_debug_resume)(BlockDriverState *bs, const char *tag); | ||
440 | - bool (*bdrv_debug_is_suspended)(BlockDriverState *bs, const char *tag); | ||
441 | - | ||
442 | - void (*bdrv_refresh_limits)(BlockDriverState *bs, Error **errp); | ||
443 | - | ||
444 | - /* | ||
445 | - * Returns 1 if newly created images are guaranteed to contain only | ||
446 | - * zeros, 0 otherwise. | ||
447 | - */ | ||
448 | - int (*bdrv_has_zero_init)(BlockDriverState *bs); | ||
449 | - | ||
450 | - /* | ||
451 | - * Remove fd handlers, timers, and other event loop callbacks so the event | ||
452 | - * loop is no longer in use. Called with no in-flight requests and in | ||
453 | - * depth-first traversal order with parents before child nodes. | ||
454 | - */ | ||
455 | - void (*bdrv_detach_aio_context)(BlockDriverState *bs); | ||
456 | - | ||
457 | - /* | ||
458 | - * Add fd handlers, timers, and other event loop callbacks so I/O requests | ||
459 | - * can be processed again. Called with no in-flight requests and in | ||
460 | - * depth-first traversal order with child nodes before parent nodes. | ||
461 | - */ | ||
462 | - void (*bdrv_attach_aio_context)(BlockDriverState *bs, | ||
463 | - AioContext *new_context); | ||
464 | - | ||
465 | /* io queue for linux-aio */ | ||
466 | void (*bdrv_io_plug)(BlockDriverState *bs); | ||
467 | void (*bdrv_io_unplug)(BlockDriverState *bs); | ||
468 | |||
469 | - /** | ||
470 | - * Try to get @bs's logical and physical block size. | ||
471 | - * On success, store them in @bsz and return zero. | ||
472 | - * On failure, return negative errno. | ||
473 | - */ | ||
474 | - int (*bdrv_probe_blocksizes)(BlockDriverState *bs, BlockSizes *bsz); | ||
475 | - /** | ||
476 | - * Try to get @bs's geometry (cyls, heads, sectors) | ||
477 | - * On success, store them in @geo and return 0. | ||
478 | - * On failure return -errno. | ||
479 | - * Only drivers that want to override guest geometry implement this | ||
480 | - * callback; see hd_geometry_guess(). | ||
481 | - */ | ||
482 | - int (*bdrv_probe_geometry)(BlockDriverState *bs, HDGeometry *geo); | ||
483 | - | ||
484 | /** | ||
485 | * bdrv_co_drain_begin is called if implemented in the beginning of a | ||
486 | * drain operation to drain and stop any internal sources of requests in | ||
487 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { | ||
488 | void coroutine_fn (*bdrv_co_drain_begin)(BlockDriverState *bs); | ||
489 | void coroutine_fn (*bdrv_co_drain_end)(BlockDriverState *bs); | ||
490 | |||
491 | - void (*bdrv_add_child)(BlockDriverState *parent, BlockDriverState *child, | ||
492 | - Error **errp); | ||
493 | - void (*bdrv_del_child)(BlockDriverState *parent, BdrvChild *child, | ||
494 | - Error **errp); | ||
495 | - | ||
496 | - /** | ||
497 | - * Informs the block driver that a permission change is intended. The | ||
498 | - * driver checks whether the change is permissible and may take other | ||
499 | - * preparations for the change (e.g. get file system locks). This operation | ||
500 | - * is always followed either by a call to either .bdrv_set_perm or | ||
501 | - * .bdrv_abort_perm_update. | ||
502 | - * | ||
503 | - * Checks whether the requested set of cumulative permissions in @perm | ||
504 | - * can be granted for accessing @bs and whether no other users are using | ||
505 | - * permissions other than those given in @shared (both arguments take | ||
506 | - * BLK_PERM_* bitmasks). | ||
507 | - * | ||
508 | - * If both conditions are met, 0 is returned. Otherwise, -errno is returned | ||
509 | - * and errp is set to an error describing the conflict. | ||
510 | - */ | ||
511 | - int (*bdrv_check_perm)(BlockDriverState *bs, uint64_t perm, | ||
512 | - uint64_t shared, Error **errp); | ||
513 | - | ||
514 | - /** | ||
515 | - * Called to inform the driver that the set of cumulative set of used | ||
516 | - * permissions for @bs has changed to @perm, and the set of sharable | ||
517 | - * permission to @shared. The driver can use this to propagate changes to | ||
518 | - * its children (i.e. request permissions only if a parent actually needs | ||
519 | - * them). | ||
520 | - * | ||
521 | - * This function is only invoked after bdrv_check_perm(), so block drivers | ||
522 | - * may rely on preparations made in their .bdrv_check_perm implementation. | ||
523 | - */ | ||
524 | - void (*bdrv_set_perm)(BlockDriverState *bs, uint64_t perm, uint64_t shared); | ||
525 | - | ||
526 | - /* | ||
527 | - * Called to inform the driver that after a previous bdrv_check_perm() | ||
528 | - * call, the permission update is not performed and any preparations made | ||
529 | - * for it (e.g. taken file locks) need to be undone. | ||
530 | - * | ||
531 | - * This function can be called even for nodes that never saw a | ||
532 | - * bdrv_check_perm() call. It is a no-op then. | ||
533 | - */ | ||
534 | - void (*bdrv_abort_perm_update)(BlockDriverState *bs); | ||
535 | - | ||
536 | - /** | ||
537 | - * Returns in @nperm and @nshared the permissions that the driver for @bs | ||
538 | - * needs on its child @c, based on the cumulative permissions requested by | ||
539 | - * the parents in @parent_perm and @parent_shared. | ||
540 | - * | ||
541 | - * If @c is NULL, return the permissions for attaching a new child for the | ||
542 | - * given @child_class and @role. | ||
543 | - * | ||
544 | - * If @reopen_queue is non-NULL, don't return the currently needed | ||
545 | - * permissions, but those that will be needed after applying the | ||
546 | - * @reopen_queue. | ||
547 | - */ | ||
548 | - void (*bdrv_child_perm)(BlockDriverState *bs, BdrvChild *c, | ||
549 | - BdrvChildRole role, | ||
550 | - BlockReopenQueue *reopen_queue, | ||
551 | - uint64_t parent_perm, uint64_t parent_shared, | ||
552 | - uint64_t *nperm, uint64_t *nshared); | ||
553 | - | ||
554 | bool (*bdrv_supports_persistent_dirty_bitmap)(BlockDriverState *bs); | ||
555 | bool (*bdrv_co_can_store_new_dirty_bitmap)(BlockDriverState *bs, | ||
556 | const char *name, | ||
557 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { | ||
558 | int (*bdrv_co_remove_persistent_dirty_bitmap)(BlockDriverState *bs, | ||
559 | const char *name, | ||
560 | Error **errp); | ||
561 | - | ||
562 | - /** | ||
563 | - * Register/unregister a buffer for I/O. For example, when the driver is | ||
564 | - * interested to know the memory areas that will later be used in iovs, so | ||
565 | - * that it can do IOMMU mapping with VFIO etc., in order to get better | ||
566 | - * performance. In the case of VFIO drivers, this callback is used to do | ||
567 | - * DMA mapping for hot buffers. | ||
568 | - */ | ||
569 | - void (*bdrv_register_buf)(BlockDriverState *bs, void *host, size_t size); | ||
570 | - void (*bdrv_unregister_buf)(BlockDriverState *bs, void *host); | ||
571 | - QLIST_ENTRY(BlockDriver) list; | ||
572 | - | ||
573 | - /* | ||
574 | - * Pointer to a NULL-terminated array of names of strong options | ||
575 | - * that can be specified for bdrv_open(). A strong option is one | ||
576 | - * that changes the data of a BDS. | ||
577 | - * If this pointer is NULL, the array is considered empty. | ||
578 | - * "filename" and "driver" are always considered strong. | ||
579 | - */ | ||
580 | - const char *const *strong_runtime_opts; | ||
581 | }; | ||
582 | |||
583 | static inline bool block_driver_can_compress(BlockDriver *drv) | ||
584 | -- | 45 | -- |
585 | 2.35.1 | 46 | 2.13.6 |
47 | |||
48 | diff view generated by jsdifflib |
1 | From: Hanna Reitz <hreitz@redhat.com> | 1 | From: Edgar Kaziakhmedov <edgar.kaziakhmedov@virtuozzo.com> |
---|---|---|---|
2 | 2 | ||
3 | .bdrv_amend_clean() says block drivers can use it to clean up what was | 3 | Since bdrv_co_preadv does all neccessary checks including |
4 | done in .bdrv_amend_pre_run(). Therefore, it should always be called | 4 | reading after the end of the backing file, avoid duplication |
5 | after .bdrv_amend_pre_run(), which means we need it to call it in the | 5 | of verification before bdrv_co_preadv call. |
6 | JobDriver.free() callback, not in JobDriver.clean(). | ||
7 | 6 | ||
8 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | 7 | Signed-off-by: Edgar Kaziakhmedov <edgar.kaziakhmedov@virtuozzo.com> |
9 | Message-Id: <20220304153729.711387-3-hreitz@redhat.com> | 8 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> |
9 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
11 | --- | 11 | --- |
12 | block/amend.c | 4 ++-- | 12 | block/qcow2.h | 3 --- |
13 | 1 file changed, 2 insertions(+), 2 deletions(-) | 13 | block/qcow2.c | 51 ++++++++------------------------------------------- |
14 | 2 files changed, 8 insertions(+), 46 deletions(-) | ||
14 | 15 | ||
15 | diff --git a/block/amend.c b/block/amend.c | 16 | diff --git a/block/qcow2.h b/block/qcow2.h |
16 | index XXXXXXX..XXXXXXX 100644 | 17 | index XXXXXXX..XXXXXXX 100644 |
17 | --- a/block/amend.c | 18 | --- a/block/qcow2.h |
18 | +++ b/block/amend.c | 19 | +++ b/block/qcow2.h |
19 | @@ -XXX,XX +XXX,XX @@ static int blockdev_amend_pre_run(BlockdevAmendJob *s, Error **errp) | 20 | @@ -XXX,XX +XXX,XX @@ uint32_t offset_to_reftable_index(BDRVQcow2State *s, uint64_t offset) |
20 | return 0; | ||
21 | } | 21 | } |
22 | 22 | ||
23 | -static void blockdev_amend_clean(Job *job) | 23 | /* qcow2.c functions */ |
24 | +static void blockdev_amend_free(Job *job) | 24 | -int qcow2_backing_read1(BlockDriverState *bs, QEMUIOVector *qiov, |
25 | - int64_t sector_num, int nb_sectors); | ||
26 | - | ||
27 | int64_t qcow2_refcount_metadata_size(int64_t clusters, size_t cluster_size, | ||
28 | int refcount_order, bool generous_increase, | ||
29 | uint64_t *refblock_count); | ||
30 | diff --git a/block/qcow2.c b/block/qcow2.c | ||
31 | index XXXXXXX..XXXXXXX 100644 | ||
32 | --- a/block/qcow2.c | ||
33 | +++ b/block/qcow2.c | ||
34 | @@ -XXX,XX +XXX,XX @@ static int64_t coroutine_fn qcow2_co_get_block_status(BlockDriverState *bs, | ||
35 | return status; | ||
36 | } | ||
37 | |||
38 | -/* handle reading after the end of the backing file */ | ||
39 | -int qcow2_backing_read1(BlockDriverState *bs, QEMUIOVector *qiov, | ||
40 | - int64_t offset, int bytes) | ||
41 | -{ | ||
42 | - uint64_t bs_size = bs->total_sectors * BDRV_SECTOR_SIZE; | ||
43 | - int n1; | ||
44 | - | ||
45 | - if ((offset + bytes) <= bs_size) { | ||
46 | - return bytes; | ||
47 | - } | ||
48 | - | ||
49 | - if (offset >= bs_size) { | ||
50 | - n1 = 0; | ||
51 | - } else { | ||
52 | - n1 = bs_size - offset; | ||
53 | - } | ||
54 | - | ||
55 | - qemu_iovec_memset(qiov, n1, 0, bytes - n1); | ||
56 | - | ||
57 | - return n1; | ||
58 | -} | ||
59 | - | ||
60 | static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset, | ||
61 | uint64_t bytes, QEMUIOVector *qiov, | ||
62 | int flags) | ||
25 | { | 63 | { |
26 | BlockdevAmendJob *s = container_of(job, BlockdevAmendJob, common); | 64 | BDRVQcow2State *s = bs->opaque; |
27 | 65 | - int offset_in_cluster, n1; | |
28 | @@ -XXX,XX +XXX,XX @@ static const JobDriver blockdev_amend_job_driver = { | 66 | + int offset_in_cluster; |
29 | .instance_size = sizeof(BlockdevAmendJob), | 67 | int ret; |
30 | .job_type = JOB_TYPE_AMEND, | 68 | unsigned int cur_bytes; /* number of bytes in current iteration */ |
31 | .run = blockdev_amend_run, | 69 | uint64_t cluster_offset = 0; |
32 | - .clean = blockdev_amend_clean, | 70 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset, |
33 | + .free = blockdev_amend_free, | 71 | case QCOW2_CLUSTER_UNALLOCATED: |
34 | }; | 72 | |
35 | 73 | if (bs->backing) { | |
36 | void qmp_x_blockdev_amend(const char *job_id, | 74 | - /* read from the base image */ |
75 | - n1 = qcow2_backing_read1(bs->backing->bs, &hd_qiov, | ||
76 | - offset, cur_bytes); | ||
77 | - if (n1 > 0) { | ||
78 | - QEMUIOVector local_qiov; | ||
79 | - | ||
80 | - qemu_iovec_init(&local_qiov, hd_qiov.niov); | ||
81 | - qemu_iovec_concat(&local_qiov, &hd_qiov, 0, n1); | ||
82 | - | ||
83 | - BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO); | ||
84 | - qemu_co_mutex_unlock(&s->lock); | ||
85 | - ret = bdrv_co_preadv(bs->backing, offset, n1, | ||
86 | - &local_qiov, 0); | ||
87 | - qemu_co_mutex_lock(&s->lock); | ||
88 | - | ||
89 | - qemu_iovec_destroy(&local_qiov); | ||
90 | - | ||
91 | - if (ret < 0) { | ||
92 | - goto fail; | ||
93 | - } | ||
94 | + BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO); | ||
95 | + qemu_co_mutex_unlock(&s->lock); | ||
96 | + ret = bdrv_co_preadv(bs->backing, offset, cur_bytes, | ||
97 | + &hd_qiov, 0); | ||
98 | + qemu_co_mutex_lock(&s->lock); | ||
99 | + if (ret < 0) { | ||
100 | + goto fail; | ||
101 | } | ||
102 | } else { | ||
103 | /* Note: in this case, no need to wait */ | ||
37 | -- | 104 | -- |
38 | 2.35.1 | 105 | 2.13.6 |
106 | |||
107 | diff view generated by jsdifflib |
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | 1 | Removing a quorum child node with x-blockdev-change results in a quorum |
---|---|---|---|
2 | driver state that cannot be recreated with create options because it | ||
3 | would require a list with gaps. This causes trouble in at least | ||
4 | .bdrv_refresh_filename(). | ||
2 | 5 | ||
3 | Assertions in the callers of the function pointrs are already | 6 | Document this problem so that we won't accidentally mark the command |
4 | added by previous patches. | 7 | stable without having addressed it. |
5 | 8 | ||
6 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
7 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
8 | Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> | ||
9 | Message-Id: <20220303151616.325444-30-eesposit@redhat.com> | ||
10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 9 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
10 | Reviewed-by: Alberto Garcia <berto@igalia.com> | ||
11 | --- | 11 | --- |
12 | include/sysemu/block-backend-common.h | 28 ++++++++++++++++++++++----- | 12 | qapi/block-core.json | 4 ++++ |
13 | 1 file changed, 23 insertions(+), 5 deletions(-) | 13 | 1 file changed, 4 insertions(+) |
14 | 14 | ||
15 | diff --git a/include/sysemu/block-backend-common.h b/include/sysemu/block-backend-common.h | 15 | diff --git a/qapi/block-core.json b/qapi/block-core.json |
16 | index XXXXXXX..XXXXXXX 100644 | 16 | index XXXXXXX..XXXXXXX 100644 |
17 | --- a/include/sysemu/block-backend-common.h | 17 | --- a/qapi/block-core.json |
18 | +++ b/include/sysemu/block-backend-common.h | 18 | +++ b/qapi/block-core.json |
19 | @@ -XXX,XX +XXX,XX @@ | 19 | @@ -XXX,XX +XXX,XX @@ |
20 | 20 | # does not support all kinds of operations, all kinds of children, nor | |
21 | /* Callbacks for block device models */ | 21 | # all block drivers. |
22 | typedef struct BlockDevOps { | 22 | # |
23 | + | 23 | +# FIXME Removing children from a quorum node means introducing gaps in the |
24 | + /* | 24 | +# child indices. This cannot be represented in the 'children' list of |
25 | + * Global state (GS) API. These functions run under the BQL. | 25 | +# BlockdevOptionsQuorum, as returned by .bdrv_refresh_filename(). |
26 | + * | 26 | +# |
27 | + * See include/block/block-global-state.h for more information about | 27 | # Warning: The data in a new quorum child MUST be consistent with that of |
28 | + * the GS API. | 28 | # the rest of the array. |
29 | + */ | 29 | # |
30 | + | ||
31 | /* | ||
32 | * Runs when virtual media changed (monitor commands eject, change) | ||
33 | * Argument load is true on load and false on eject. | ||
34 | @@ -XXX,XX +XXX,XX @@ typedef struct BlockDevOps { | ||
35 | * true, even if they do not support eject requests. | ||
36 | */ | ||
37 | void (*eject_request_cb)(void *opaque, bool force); | ||
38 | - /* | ||
39 | - * Is the virtual tray open? | ||
40 | - * Device models implement this only when the device has a tray. | ||
41 | - */ | ||
42 | - bool (*is_tray_open)(void *opaque); | ||
43 | + | ||
44 | /* | ||
45 | * Is the virtual medium locked into the device? | ||
46 | * Device models implement this only when device has such a lock. | ||
47 | */ | ||
48 | bool (*is_medium_locked)(void *opaque); | ||
49 | + | ||
50 | + /* | ||
51 | + * I/O API functions. These functions are thread-safe. | ||
52 | + * | ||
53 | + * See include/block/block-io.h for more information about | ||
54 | + * the I/O API. | ||
55 | + */ | ||
56 | + | ||
57 | + /* | ||
58 | + * Is the virtual tray open? | ||
59 | + * Device models implement this only when the device has a tray. | ||
60 | + */ | ||
61 | + bool (*is_tray_open)(void *opaque); | ||
62 | + | ||
63 | /* | ||
64 | * Runs when the size changed (e.g. monitor command block_resize) | ||
65 | */ | ||
66 | -- | 30 | -- |
67 | 2.35.1 | 31 | 2.13.6 |
68 | 32 | ||
69 | 33 | diff view generated by jsdifflib |
1 | From: Hanna Reitz <hreitz@redhat.com> | 1 | From: Doug Gale <doug16k@gmail.com> |
---|---|---|---|
2 | 2 | ||
3 | Otherwise, the BDS might be freed while the job is running, which would | 3 | Add trace output for commands, errors, and undefined behavior. |
4 | cause a use-after-free. | 4 | Add guest error log output for undefined behavior. |
5 | Report invalid undefined accesses to MMIO. | ||
6 | Annotate unlikely error checks with unlikely. | ||
5 | 7 | ||
6 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | 8 | Signed-off-by: Doug Gale <doug16k@gmail.com> |
7 | Message-Id: <20220304153729.711387-5-hreitz@redhat.com> | 9 | Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org> |
10 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
8 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
9 | --- | 12 | --- |
10 | block/amend.c | 3 +++ | 13 | hw/block/nvme.c | 349 ++++++++++++++++++++++++++++++++++++++++++-------- |
11 | 1 file changed, 3 insertions(+) | 14 | hw/block/trace-events | 93 ++++++++++++++ |
15 | 2 files changed, 390 insertions(+), 52 deletions(-) | ||
12 | 16 | ||
13 | diff --git a/block/amend.c b/block/amend.c | 17 | diff --git a/hw/block/nvme.c b/hw/block/nvme.c |
14 | index XXXXXXX..XXXXXXX 100644 | 18 | index XXXXXXX..XXXXXXX 100644 |
15 | --- a/block/amend.c | 19 | --- a/hw/block/nvme.c |
16 | +++ b/block/amend.c | 20 | +++ b/hw/block/nvme.c |
17 | @@ -XXX,XX +XXX,XX @@ static void blockdev_amend_free(Job *job) | 21 | @@ -XXX,XX +XXX,XX @@ |
18 | if (s->bs->drv->bdrv_amend_clean) { | 22 | #include "qapi/visitor.h" |
19 | s->bs->drv->bdrv_amend_clean(s->bs); | 23 | #include "sysemu/block-backend.h" |
20 | } | 24 | |
21 | + | 25 | +#include "qemu/log.h" |
22 | + bdrv_unref(s->bs); | 26 | +#include "trace.h" |
23 | } | 27 | #include "nvme.h" |
24 | 28 | ||
25 | static const JobDriver blockdev_amend_job_driver = { | 29 | +#define NVME_GUEST_ERR(trace, fmt, ...) \ |
26 | @@ -XXX,XX +XXX,XX @@ void qmp_x_blockdev_amend(const char *job_id, | 30 | + do { \ |
31 | + (trace_##trace)(__VA_ARGS__); \ | ||
32 | + qemu_log_mask(LOG_GUEST_ERROR, #trace \ | ||
33 | + " in %s: " fmt "\n", __func__, ## __VA_ARGS__); \ | ||
34 | + } while (0) | ||
35 | + | ||
36 | static void nvme_process_sq(void *opaque); | ||
37 | |||
38 | static void nvme_addr_read(NvmeCtrl *n, hwaddr addr, void *buf, int size) | ||
39 | @@ -XXX,XX +XXX,XX @@ static void nvme_isr_notify(NvmeCtrl *n, NvmeCQueue *cq) | ||
40 | { | ||
41 | if (cq->irq_enabled) { | ||
42 | if (msix_enabled(&(n->parent_obj))) { | ||
43 | + trace_nvme_irq_msix(cq->vector); | ||
44 | msix_notify(&(n->parent_obj), cq->vector); | ||
45 | } else { | ||
46 | + trace_nvme_irq_pin(); | ||
47 | pci_irq_pulse(&n->parent_obj); | ||
48 | } | ||
49 | + } else { | ||
50 | + trace_nvme_irq_masked(); | ||
51 | } | ||
52 | } | ||
53 | |||
54 | @@ -XXX,XX +XXX,XX @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector *iov, uint64_t prp1, | ||
55 | trans_len = MIN(len, trans_len); | ||
56 | int num_prps = (len >> n->page_bits) + 1; | ||
57 | |||
58 | - if (!prp1) { | ||
59 | + if (unlikely(!prp1)) { | ||
60 | + trace_nvme_err_invalid_prp(); | ||
61 | return NVME_INVALID_FIELD | NVME_DNR; | ||
62 | } else if (n->cmbsz && prp1 >= n->ctrl_mem.addr && | ||
63 | prp1 < n->ctrl_mem.addr + int128_get64(n->ctrl_mem.size)) { | ||
64 | @@ -XXX,XX +XXX,XX @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector *iov, uint64_t prp1, | ||
65 | } | ||
66 | len -= trans_len; | ||
67 | if (len) { | ||
68 | - if (!prp2) { | ||
69 | + if (unlikely(!prp2)) { | ||
70 | + trace_nvme_err_invalid_prp2_missing(); | ||
71 | goto unmap; | ||
72 | } | ||
73 | if (len > n->page_size) { | ||
74 | @@ -XXX,XX +XXX,XX @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector *iov, uint64_t prp1, | ||
75 | uint64_t prp_ent = le64_to_cpu(prp_list[i]); | ||
76 | |||
77 | if (i == n->max_prp_ents - 1 && len > n->page_size) { | ||
78 | - if (!prp_ent || prp_ent & (n->page_size - 1)) { | ||
79 | + if (unlikely(!prp_ent || prp_ent & (n->page_size - 1))) { | ||
80 | + trace_nvme_err_invalid_prplist_ent(prp_ent); | ||
81 | goto unmap; | ||
82 | } | ||
83 | |||
84 | @@ -XXX,XX +XXX,XX @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector *iov, uint64_t prp1, | ||
85 | prp_ent = le64_to_cpu(prp_list[i]); | ||
86 | } | ||
87 | |||
88 | - if (!prp_ent || prp_ent & (n->page_size - 1)) { | ||
89 | + if (unlikely(!prp_ent || prp_ent & (n->page_size - 1))) { | ||
90 | + trace_nvme_err_invalid_prplist_ent(prp_ent); | ||
91 | goto unmap; | ||
92 | } | ||
93 | |||
94 | @@ -XXX,XX +XXX,XX @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector *iov, uint64_t prp1, | ||
95 | i++; | ||
96 | } | ||
97 | } else { | ||
98 | - if (prp2 & (n->page_size - 1)) { | ||
99 | + if (unlikely(prp2 & (n->page_size - 1))) { | ||
100 | + trace_nvme_err_invalid_prp2_align(prp2); | ||
101 | goto unmap; | ||
102 | } | ||
103 | if (qsg->nsg) { | ||
104 | @@ -XXX,XX +XXX,XX @@ static uint16_t nvme_dma_read_prp(NvmeCtrl *n, uint8_t *ptr, uint32_t len, | ||
105 | QEMUIOVector iov; | ||
106 | uint16_t status = NVME_SUCCESS; | ||
107 | |||
108 | + trace_nvme_dma_read(prp1, prp2); | ||
109 | + | ||
110 | if (nvme_map_prp(&qsg, &iov, prp1, prp2, len, n)) { | ||
111 | return NVME_INVALID_FIELD | NVME_DNR; | ||
112 | } | ||
113 | if (qsg.nsg > 0) { | ||
114 | - if (dma_buf_read(ptr, len, &qsg)) { | ||
115 | + if (unlikely(dma_buf_read(ptr, len, &qsg))) { | ||
116 | + trace_nvme_err_invalid_dma(); | ||
117 | status = NVME_INVALID_FIELD | NVME_DNR; | ||
118 | } | ||
119 | qemu_sglist_destroy(&qsg); | ||
120 | } else { | ||
121 | - if (qemu_iovec_to_buf(&iov, 0, ptr, len) != len) { | ||
122 | + if (unlikely(qemu_iovec_to_buf(&iov, 0, ptr, len) != len)) { | ||
123 | + trace_nvme_err_invalid_dma(); | ||
124 | status = NVME_INVALID_FIELD | NVME_DNR; | ||
125 | } | ||
126 | qemu_iovec_destroy(&iov); | ||
127 | @@ -XXX,XX +XXX,XX @@ static uint16_t nvme_write_zeros(NvmeCtrl *n, NvmeNamespace *ns, NvmeCmd *cmd, | ||
128 | uint64_t aio_slba = slba << (data_shift - BDRV_SECTOR_BITS); | ||
129 | uint32_t aio_nlb = nlb << (data_shift - BDRV_SECTOR_BITS); | ||
130 | |||
131 | - if (slba + nlb > ns->id_ns.nsze) { | ||
132 | + if (unlikely(slba + nlb > ns->id_ns.nsze)) { | ||
133 | + trace_nvme_err_invalid_lba_range(slba, nlb, ns->id_ns.nsze); | ||
134 | return NVME_LBA_RANGE | NVME_DNR; | ||
135 | } | ||
136 | |||
137 | @@ -XXX,XX +XXX,XX @@ static uint16_t nvme_rw(NvmeCtrl *n, NvmeNamespace *ns, NvmeCmd *cmd, | ||
138 | int is_write = rw->opcode == NVME_CMD_WRITE ? 1 : 0; | ||
139 | enum BlockAcctType acct = is_write ? BLOCK_ACCT_WRITE : BLOCK_ACCT_READ; | ||
140 | |||
141 | - if ((slba + nlb) > ns->id_ns.nsze) { | ||
142 | + trace_nvme_rw(is_write ? "write" : "read", nlb, data_size, slba); | ||
143 | + | ||
144 | + if (unlikely((slba + nlb) > ns->id_ns.nsze)) { | ||
145 | block_acct_invalid(blk_get_stats(n->conf.blk), acct); | ||
146 | + trace_nvme_err_invalid_lba_range(slba, nlb, ns->id_ns.nsze); | ||
147 | return NVME_LBA_RANGE | NVME_DNR; | ||
148 | } | ||
149 | |||
150 | @@ -XXX,XX +XXX,XX @@ static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req) | ||
151 | NvmeNamespace *ns; | ||
152 | uint32_t nsid = le32_to_cpu(cmd->nsid); | ||
153 | |||
154 | - if (nsid == 0 || nsid > n->num_namespaces) { | ||
155 | + if (unlikely(nsid == 0 || nsid > n->num_namespaces)) { | ||
156 | + trace_nvme_err_invalid_ns(nsid, n->num_namespaces); | ||
157 | return NVME_INVALID_NSID | NVME_DNR; | ||
158 | } | ||
159 | |||
160 | @@ -XXX,XX +XXX,XX @@ static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req) | ||
161 | case NVME_CMD_READ: | ||
162 | return nvme_rw(n, ns, cmd, req); | ||
163 | default: | ||
164 | + trace_nvme_err_invalid_opc(cmd->opcode); | ||
165 | return NVME_INVALID_OPCODE | NVME_DNR; | ||
166 | } | ||
167 | } | ||
168 | @@ -XXX,XX +XXX,XX @@ static uint16_t nvme_del_sq(NvmeCtrl *n, NvmeCmd *cmd) | ||
169 | NvmeCQueue *cq; | ||
170 | uint16_t qid = le16_to_cpu(c->qid); | ||
171 | |||
172 | - if (!qid || nvme_check_sqid(n, qid)) { | ||
173 | + if (unlikely(!qid || nvme_check_sqid(n, qid))) { | ||
174 | + trace_nvme_err_invalid_del_sq(qid); | ||
175 | return NVME_INVALID_QID | NVME_DNR; | ||
176 | } | ||
177 | |||
178 | + trace_nvme_del_sq(qid); | ||
179 | + | ||
180 | sq = n->sq[qid]; | ||
181 | while (!QTAILQ_EMPTY(&sq->out_req_list)) { | ||
182 | req = QTAILQ_FIRST(&sq->out_req_list); | ||
183 | @@ -XXX,XX +XXX,XX @@ static uint16_t nvme_create_sq(NvmeCtrl *n, NvmeCmd *cmd) | ||
184 | uint16_t qflags = le16_to_cpu(c->sq_flags); | ||
185 | uint64_t prp1 = le64_to_cpu(c->prp1); | ||
186 | |||
187 | - if (!cqid || nvme_check_cqid(n, cqid)) { | ||
188 | + trace_nvme_create_sq(prp1, sqid, cqid, qsize, qflags); | ||
189 | + | ||
190 | + if (unlikely(!cqid || nvme_check_cqid(n, cqid))) { | ||
191 | + trace_nvme_err_invalid_create_sq_cqid(cqid); | ||
192 | return NVME_INVALID_CQID | NVME_DNR; | ||
193 | } | ||
194 | - if (!sqid || !nvme_check_sqid(n, sqid)) { | ||
195 | + if (unlikely(!sqid || !nvme_check_sqid(n, sqid))) { | ||
196 | + trace_nvme_err_invalid_create_sq_sqid(sqid); | ||
197 | return NVME_INVALID_QID | NVME_DNR; | ||
198 | } | ||
199 | - if (!qsize || qsize > NVME_CAP_MQES(n->bar.cap)) { | ||
200 | + if (unlikely(!qsize || qsize > NVME_CAP_MQES(n->bar.cap))) { | ||
201 | + trace_nvme_err_invalid_create_sq_size(qsize); | ||
202 | return NVME_MAX_QSIZE_EXCEEDED | NVME_DNR; | ||
203 | } | ||
204 | - if (!prp1 || prp1 & (n->page_size - 1)) { | ||
205 | + if (unlikely(!prp1 || prp1 & (n->page_size - 1))) { | ||
206 | + trace_nvme_err_invalid_create_sq_addr(prp1); | ||
207 | return NVME_INVALID_FIELD | NVME_DNR; | ||
208 | } | ||
209 | - if (!(NVME_SQ_FLAGS_PC(qflags))) { | ||
210 | + if (unlikely(!(NVME_SQ_FLAGS_PC(qflags)))) { | ||
211 | + trace_nvme_err_invalid_create_sq_qflags(NVME_SQ_FLAGS_PC(qflags)); | ||
212 | return NVME_INVALID_FIELD | NVME_DNR; | ||
213 | } | ||
214 | sq = g_malloc0(sizeof(*sq)); | ||
215 | @@ -XXX,XX +XXX,XX @@ static uint16_t nvme_del_cq(NvmeCtrl *n, NvmeCmd *cmd) | ||
216 | NvmeCQueue *cq; | ||
217 | uint16_t qid = le16_to_cpu(c->qid); | ||
218 | |||
219 | - if (!qid || nvme_check_cqid(n, qid)) { | ||
220 | + if (unlikely(!qid || nvme_check_cqid(n, qid))) { | ||
221 | + trace_nvme_err_invalid_del_cq_cqid(qid); | ||
222 | return NVME_INVALID_CQID | NVME_DNR; | ||
223 | } | ||
224 | |||
225 | cq = n->cq[qid]; | ||
226 | - if (!QTAILQ_EMPTY(&cq->sq_list)) { | ||
227 | + if (unlikely(!QTAILQ_EMPTY(&cq->sq_list))) { | ||
228 | + trace_nvme_err_invalid_del_cq_notempty(qid); | ||
229 | return NVME_INVALID_QUEUE_DEL; | ||
230 | } | ||
231 | + trace_nvme_del_cq(qid); | ||
232 | nvme_free_cq(cq, n); | ||
233 | return NVME_SUCCESS; | ||
234 | } | ||
235 | @@ -XXX,XX +XXX,XX @@ static uint16_t nvme_create_cq(NvmeCtrl *n, NvmeCmd *cmd) | ||
236 | uint16_t qflags = le16_to_cpu(c->cq_flags); | ||
237 | uint64_t prp1 = le64_to_cpu(c->prp1); | ||
238 | |||
239 | - if (!cqid || !nvme_check_cqid(n, cqid)) { | ||
240 | + trace_nvme_create_cq(prp1, cqid, vector, qsize, qflags, | ||
241 | + NVME_CQ_FLAGS_IEN(qflags) != 0); | ||
242 | + | ||
243 | + if (unlikely(!cqid || !nvme_check_cqid(n, cqid))) { | ||
244 | + trace_nvme_err_invalid_create_cq_cqid(cqid); | ||
245 | return NVME_INVALID_CQID | NVME_DNR; | ||
246 | } | ||
247 | - if (!qsize || qsize > NVME_CAP_MQES(n->bar.cap)) { | ||
248 | + if (unlikely(!qsize || qsize > NVME_CAP_MQES(n->bar.cap))) { | ||
249 | + trace_nvme_err_invalid_create_cq_size(qsize); | ||
250 | return NVME_MAX_QSIZE_EXCEEDED | NVME_DNR; | ||
251 | } | ||
252 | - if (!prp1) { | ||
253 | + if (unlikely(!prp1)) { | ||
254 | + trace_nvme_err_invalid_create_cq_addr(prp1); | ||
255 | return NVME_INVALID_FIELD | NVME_DNR; | ||
256 | } | ||
257 | - if (vector > n->num_queues) { | ||
258 | + if (unlikely(vector > n->num_queues)) { | ||
259 | + trace_nvme_err_invalid_create_cq_vector(vector); | ||
260 | return NVME_INVALID_IRQ_VECTOR | NVME_DNR; | ||
261 | } | ||
262 | - if (!(NVME_CQ_FLAGS_PC(qflags))) { | ||
263 | + if (unlikely(!(NVME_CQ_FLAGS_PC(qflags)))) { | ||
264 | + trace_nvme_err_invalid_create_cq_qflags(NVME_CQ_FLAGS_PC(qflags)); | ||
265 | return NVME_INVALID_FIELD | NVME_DNR; | ||
266 | } | ||
267 | |||
268 | @@ -XXX,XX +XXX,XX @@ static uint16_t nvme_identify_ctrl(NvmeCtrl *n, NvmeIdentify *c) | ||
269 | uint64_t prp1 = le64_to_cpu(c->prp1); | ||
270 | uint64_t prp2 = le64_to_cpu(c->prp2); | ||
271 | |||
272 | + trace_nvme_identify_ctrl(); | ||
273 | + | ||
274 | return nvme_dma_read_prp(n, (uint8_t *)&n->id_ctrl, sizeof(n->id_ctrl), | ||
275 | prp1, prp2); | ||
276 | } | ||
277 | @@ -XXX,XX +XXX,XX @@ static uint16_t nvme_identify_ns(NvmeCtrl *n, NvmeIdentify *c) | ||
278 | uint64_t prp1 = le64_to_cpu(c->prp1); | ||
279 | uint64_t prp2 = le64_to_cpu(c->prp2); | ||
280 | |||
281 | - if (nsid == 0 || nsid > n->num_namespaces) { | ||
282 | + trace_nvme_identify_ns(nsid); | ||
283 | + | ||
284 | + if (unlikely(nsid == 0 || nsid > n->num_namespaces)) { | ||
285 | + trace_nvme_err_invalid_ns(nsid, n->num_namespaces); | ||
286 | return NVME_INVALID_NSID | NVME_DNR; | ||
287 | } | ||
288 | |||
289 | ns = &n->namespaces[nsid - 1]; | ||
290 | + | ||
291 | return nvme_dma_read_prp(n, (uint8_t *)&ns->id_ns, sizeof(ns->id_ns), | ||
292 | prp1, prp2); | ||
293 | } | ||
294 | @@ -XXX,XX +XXX,XX @@ static uint16_t nvme_identify_nslist(NvmeCtrl *n, NvmeIdentify *c) | ||
295 | uint16_t ret; | ||
296 | int i, j = 0; | ||
297 | |||
298 | + trace_nvme_identify_nslist(min_nsid); | ||
299 | + | ||
300 | list = g_malloc0(data_len); | ||
301 | for (i = 0; i < n->num_namespaces; i++) { | ||
302 | if (i < min_nsid) { | ||
303 | @@ -XXX,XX +XXX,XX @@ static uint16_t nvme_identify(NvmeCtrl *n, NvmeCmd *cmd) | ||
304 | case 0x02: | ||
305 | return nvme_identify_nslist(n, c); | ||
306 | default: | ||
307 | + trace_nvme_err_invalid_identify_cns(le32_to_cpu(c->cns)); | ||
308 | return NVME_INVALID_FIELD | NVME_DNR; | ||
309 | } | ||
310 | } | ||
311 | @@ -XXX,XX +XXX,XX @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req) | ||
312 | switch (dw10) { | ||
313 | case NVME_VOLATILE_WRITE_CACHE: | ||
314 | result = blk_enable_write_cache(n->conf.blk); | ||
315 | + trace_nvme_getfeat_vwcache(result ? "enabled" : "disabled"); | ||
316 | break; | ||
317 | case NVME_NUMBER_OF_QUEUES: | ||
318 | result = cpu_to_le32((n->num_queues - 2) | ((n->num_queues - 2) << 16)); | ||
319 | + trace_nvme_getfeat_numq(result); | ||
320 | break; | ||
321 | default: | ||
322 | + trace_nvme_err_invalid_getfeat(dw10); | ||
323 | return NVME_INVALID_FIELD | NVME_DNR; | ||
324 | } | ||
325 | |||
326 | @@ -XXX,XX +XXX,XX @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req) | ||
327 | blk_set_enable_write_cache(n->conf.blk, dw11 & 1); | ||
328 | break; | ||
329 | case NVME_NUMBER_OF_QUEUES: | ||
330 | + trace_nvme_setfeat_numq((dw11 & 0xFFFF) + 1, | ||
331 | + ((dw11 >> 16) & 0xFFFF) + 1, | ||
332 | + n->num_queues - 1, n->num_queues - 1); | ||
333 | req->cqe.result = | ||
334 | cpu_to_le32((n->num_queues - 2) | ((n->num_queues - 2) << 16)); | ||
335 | break; | ||
336 | default: | ||
337 | + trace_nvme_err_invalid_setfeat(dw10); | ||
338 | return NVME_INVALID_FIELD | NVME_DNR; | ||
339 | } | ||
340 | return NVME_SUCCESS; | ||
341 | @@ -XXX,XX +XXX,XX @@ static uint16_t nvme_admin_cmd(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req) | ||
342 | case NVME_ADM_CMD_GET_FEATURES: | ||
343 | return nvme_get_feature(n, cmd, req); | ||
344 | default: | ||
345 | + trace_nvme_err_invalid_admin_opc(cmd->opcode); | ||
346 | return NVME_INVALID_OPCODE | NVME_DNR; | ||
347 | } | ||
348 | } | ||
349 | @@ -XXX,XX +XXX,XX @@ static int nvme_start_ctrl(NvmeCtrl *n) | ||
350 | uint32_t page_bits = NVME_CC_MPS(n->bar.cc) + 12; | ||
351 | uint32_t page_size = 1 << page_bits; | ||
352 | |||
353 | - if (n->cq[0] || n->sq[0] || !n->bar.asq || !n->bar.acq || | ||
354 | - n->bar.asq & (page_size - 1) || n->bar.acq & (page_size - 1) || | ||
355 | - NVME_CC_MPS(n->bar.cc) < NVME_CAP_MPSMIN(n->bar.cap) || | ||
356 | - NVME_CC_MPS(n->bar.cc) > NVME_CAP_MPSMAX(n->bar.cap) || | ||
357 | - NVME_CC_IOCQES(n->bar.cc) < NVME_CTRL_CQES_MIN(n->id_ctrl.cqes) || | ||
358 | - NVME_CC_IOCQES(n->bar.cc) > NVME_CTRL_CQES_MAX(n->id_ctrl.cqes) || | ||
359 | - NVME_CC_IOSQES(n->bar.cc) < NVME_CTRL_SQES_MIN(n->id_ctrl.sqes) || | ||
360 | - NVME_CC_IOSQES(n->bar.cc) > NVME_CTRL_SQES_MAX(n->id_ctrl.sqes) || | ||
361 | - !NVME_AQA_ASQS(n->bar.aqa) || !NVME_AQA_ACQS(n->bar.aqa)) { | ||
362 | + if (unlikely(n->cq[0])) { | ||
363 | + trace_nvme_err_startfail_cq(); | ||
364 | + return -1; | ||
365 | + } | ||
366 | + if (unlikely(n->sq[0])) { | ||
367 | + trace_nvme_err_startfail_sq(); | ||
368 | + return -1; | ||
369 | + } | ||
370 | + if (unlikely(!n->bar.asq)) { | ||
371 | + trace_nvme_err_startfail_nbarasq(); | ||
372 | + return -1; | ||
373 | + } | ||
374 | + if (unlikely(!n->bar.acq)) { | ||
375 | + trace_nvme_err_startfail_nbaracq(); | ||
376 | + return -1; | ||
377 | + } | ||
378 | + if (unlikely(n->bar.asq & (page_size - 1))) { | ||
379 | + trace_nvme_err_startfail_asq_misaligned(n->bar.asq); | ||
380 | + return -1; | ||
381 | + } | ||
382 | + if (unlikely(n->bar.acq & (page_size - 1))) { | ||
383 | + trace_nvme_err_startfail_acq_misaligned(n->bar.acq); | ||
384 | + return -1; | ||
385 | + } | ||
386 | + if (unlikely(NVME_CC_MPS(n->bar.cc) < | ||
387 | + NVME_CAP_MPSMIN(n->bar.cap))) { | ||
388 | + trace_nvme_err_startfail_page_too_small( | ||
389 | + NVME_CC_MPS(n->bar.cc), | ||
390 | + NVME_CAP_MPSMIN(n->bar.cap)); | ||
391 | + return -1; | ||
392 | + } | ||
393 | + if (unlikely(NVME_CC_MPS(n->bar.cc) > | ||
394 | + NVME_CAP_MPSMAX(n->bar.cap))) { | ||
395 | + trace_nvme_err_startfail_page_too_large( | ||
396 | + NVME_CC_MPS(n->bar.cc), | ||
397 | + NVME_CAP_MPSMAX(n->bar.cap)); | ||
398 | + return -1; | ||
399 | + } | ||
400 | + if (unlikely(NVME_CC_IOCQES(n->bar.cc) < | ||
401 | + NVME_CTRL_CQES_MIN(n->id_ctrl.cqes))) { | ||
402 | + trace_nvme_err_startfail_cqent_too_small( | ||
403 | + NVME_CC_IOCQES(n->bar.cc), | ||
404 | + NVME_CTRL_CQES_MIN(n->bar.cap)); | ||
405 | + return -1; | ||
406 | + } | ||
407 | + if (unlikely(NVME_CC_IOCQES(n->bar.cc) > | ||
408 | + NVME_CTRL_CQES_MAX(n->id_ctrl.cqes))) { | ||
409 | + trace_nvme_err_startfail_cqent_too_large( | ||
410 | + NVME_CC_IOCQES(n->bar.cc), | ||
411 | + NVME_CTRL_CQES_MAX(n->bar.cap)); | ||
412 | + return -1; | ||
413 | + } | ||
414 | + if (unlikely(NVME_CC_IOSQES(n->bar.cc) < | ||
415 | + NVME_CTRL_SQES_MIN(n->id_ctrl.sqes))) { | ||
416 | + trace_nvme_err_startfail_sqent_too_small( | ||
417 | + NVME_CC_IOSQES(n->bar.cc), | ||
418 | + NVME_CTRL_SQES_MIN(n->bar.cap)); | ||
419 | + return -1; | ||
420 | + } | ||
421 | + if (unlikely(NVME_CC_IOSQES(n->bar.cc) > | ||
422 | + NVME_CTRL_SQES_MAX(n->id_ctrl.sqes))) { | ||
423 | + trace_nvme_err_startfail_sqent_too_large( | ||
424 | + NVME_CC_IOSQES(n->bar.cc), | ||
425 | + NVME_CTRL_SQES_MAX(n->bar.cap)); | ||
426 | + return -1; | ||
427 | + } | ||
428 | + if (unlikely(!NVME_AQA_ASQS(n->bar.aqa))) { | ||
429 | + trace_nvme_err_startfail_asqent_sz_zero(); | ||
430 | + return -1; | ||
431 | + } | ||
432 | + if (unlikely(!NVME_AQA_ACQS(n->bar.aqa))) { | ||
433 | + trace_nvme_err_startfail_acqent_sz_zero(); | ||
434 | return -1; | ||
435 | } | ||
436 | |||
437 | @@ -XXX,XX +XXX,XX @@ static int nvme_start_ctrl(NvmeCtrl *n) | ||
438 | static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data, | ||
439 | unsigned size) | ||
440 | { | ||
441 | + if (unlikely(offset & (sizeof(uint32_t) - 1))) { | ||
442 | + NVME_GUEST_ERR(nvme_ub_mmiowr_misaligned32, | ||
443 | + "MMIO write not 32-bit aligned," | ||
444 | + " offset=0x%"PRIx64"", offset); | ||
445 | + /* should be ignored, fall through for now */ | ||
446 | + } | ||
447 | + | ||
448 | + if (unlikely(size < sizeof(uint32_t))) { | ||
449 | + NVME_GUEST_ERR(nvme_ub_mmiowr_toosmall, | ||
450 | + "MMIO write smaller than 32-bits," | ||
451 | + " offset=0x%"PRIx64", size=%u", | ||
452 | + offset, size); | ||
453 | + /* should be ignored, fall through for now */ | ||
454 | + } | ||
455 | + | ||
456 | switch (offset) { | ||
457 | - case 0xc: | ||
458 | + case 0xc: /* INTMS */ | ||
459 | + if (unlikely(msix_enabled(&(n->parent_obj)))) { | ||
460 | + NVME_GUEST_ERR(nvme_ub_mmiowr_intmask_with_msix, | ||
461 | + "undefined access to interrupt mask set" | ||
462 | + " when MSI-X is enabled"); | ||
463 | + /* should be ignored, fall through for now */ | ||
464 | + } | ||
465 | n->bar.intms |= data & 0xffffffff; | ||
466 | n->bar.intmc = n->bar.intms; | ||
467 | + trace_nvme_mmio_intm_set(data & 0xffffffff, | ||
468 | + n->bar.intmc); | ||
469 | break; | ||
470 | - case 0x10: | ||
471 | + case 0x10: /* INTMC */ | ||
472 | + if (unlikely(msix_enabled(&(n->parent_obj)))) { | ||
473 | + NVME_GUEST_ERR(nvme_ub_mmiowr_intmask_with_msix, | ||
474 | + "undefined access to interrupt mask clr" | ||
475 | + " when MSI-X is enabled"); | ||
476 | + /* should be ignored, fall through for now */ | ||
477 | + } | ||
478 | n->bar.intms &= ~(data & 0xffffffff); | ||
479 | n->bar.intmc = n->bar.intms; | ||
480 | + trace_nvme_mmio_intm_clr(data & 0xffffffff, | ||
481 | + n->bar.intmc); | ||
482 | break; | ||
483 | - case 0x14: | ||
484 | + case 0x14: /* CC */ | ||
485 | + trace_nvme_mmio_cfg(data & 0xffffffff); | ||
486 | /* Windows first sends data, then sends enable bit */ | ||
487 | if (!NVME_CC_EN(data) && !NVME_CC_EN(n->bar.cc) && | ||
488 | !NVME_CC_SHN(data) && !NVME_CC_SHN(n->bar.cc)) | ||
489 | @@ -XXX,XX +XXX,XX @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data, | ||
490 | |||
491 | if (NVME_CC_EN(data) && !NVME_CC_EN(n->bar.cc)) { | ||
492 | n->bar.cc = data; | ||
493 | - if (nvme_start_ctrl(n)) { | ||
494 | + if (unlikely(nvme_start_ctrl(n))) { | ||
495 | + trace_nvme_err_startfail(); | ||
496 | n->bar.csts = NVME_CSTS_FAILED; | ||
497 | } else { | ||
498 | + trace_nvme_mmio_start_success(); | ||
499 | n->bar.csts = NVME_CSTS_READY; | ||
500 | } | ||
501 | } else if (!NVME_CC_EN(data) && NVME_CC_EN(n->bar.cc)) { | ||
502 | + trace_nvme_mmio_stopped(); | ||
503 | nvme_clear_ctrl(n); | ||
504 | n->bar.csts &= ~NVME_CSTS_READY; | ||
505 | } | ||
506 | if (NVME_CC_SHN(data) && !(NVME_CC_SHN(n->bar.cc))) { | ||
507 | - nvme_clear_ctrl(n); | ||
508 | - n->bar.cc = data; | ||
509 | - n->bar.csts |= NVME_CSTS_SHST_COMPLETE; | ||
510 | + trace_nvme_mmio_shutdown_set(); | ||
511 | + nvme_clear_ctrl(n); | ||
512 | + n->bar.cc = data; | ||
513 | + n->bar.csts |= NVME_CSTS_SHST_COMPLETE; | ||
514 | } else if (!NVME_CC_SHN(data) && NVME_CC_SHN(n->bar.cc)) { | ||
515 | - n->bar.csts &= ~NVME_CSTS_SHST_COMPLETE; | ||
516 | - n->bar.cc = data; | ||
517 | + trace_nvme_mmio_shutdown_cleared(); | ||
518 | + n->bar.csts &= ~NVME_CSTS_SHST_COMPLETE; | ||
519 | + n->bar.cc = data; | ||
520 | + } | ||
521 | + break; | ||
522 | + case 0x1C: /* CSTS */ | ||
523 | + if (data & (1 << 4)) { | ||
524 | + NVME_GUEST_ERR(nvme_ub_mmiowr_ssreset_w1c_unsupported, | ||
525 | + "attempted to W1C CSTS.NSSRO" | ||
526 | + " but CAP.NSSRS is zero (not supported)"); | ||
527 | + } else if (data != 0) { | ||
528 | + NVME_GUEST_ERR(nvme_ub_mmiowr_ro_csts, | ||
529 | + "attempted to set a read only bit" | ||
530 | + " of controller status"); | ||
531 | + } | ||
532 | + break; | ||
533 | + case 0x20: /* NSSR */ | ||
534 | + if (data == 0x4E564D65) { | ||
535 | + trace_nvme_ub_mmiowr_ssreset_unsupported(); | ||
536 | + } else { | ||
537 | + /* The spec says that writes of other values have no effect */ | ||
538 | + return; | ||
539 | } | ||
540 | break; | ||
541 | - case 0x24: | ||
542 | + case 0x24: /* AQA */ | ||
543 | n->bar.aqa = data & 0xffffffff; | ||
544 | + trace_nvme_mmio_aqattr(data & 0xffffffff); | ||
545 | break; | ||
546 | - case 0x28: | ||
547 | + case 0x28: /* ASQ */ | ||
548 | n->bar.asq = data; | ||
549 | + trace_nvme_mmio_asqaddr(data); | ||
550 | break; | ||
551 | - case 0x2c: | ||
552 | + case 0x2c: /* ASQ hi */ | ||
553 | n->bar.asq |= data << 32; | ||
554 | + trace_nvme_mmio_asqaddr_hi(data, n->bar.asq); | ||
555 | break; | ||
556 | - case 0x30: | ||
557 | + case 0x30: /* ACQ */ | ||
558 | + trace_nvme_mmio_acqaddr(data); | ||
559 | n->bar.acq = data; | ||
560 | break; | ||
561 | - case 0x34: | ||
562 | + case 0x34: /* ACQ hi */ | ||
563 | n->bar.acq |= data << 32; | ||
564 | + trace_nvme_mmio_acqaddr_hi(data, n->bar.acq); | ||
565 | break; | ||
566 | + case 0x38: /* CMBLOC */ | ||
567 | + NVME_GUEST_ERR(nvme_ub_mmiowr_cmbloc_reserved, | ||
568 | + "invalid write to reserved CMBLOC" | ||
569 | + " when CMBSZ is zero, ignored"); | ||
570 | + return; | ||
571 | + case 0x3C: /* CMBSZ */ | ||
572 | + NVME_GUEST_ERR(nvme_ub_mmiowr_cmbsz_readonly, | ||
573 | + "invalid write to read only CMBSZ, ignored"); | ||
574 | + return; | ||
575 | default: | ||
576 | + NVME_GUEST_ERR(nvme_ub_mmiowr_invalid, | ||
577 | + "invalid MMIO write," | ||
578 | + " offset=0x%"PRIx64", data=%"PRIx64"", | ||
579 | + offset, data); | ||
580 | break; | ||
581 | } | ||
582 | } | ||
583 | @@ -XXX,XX +XXX,XX @@ static uint64_t nvme_mmio_read(void *opaque, hwaddr addr, unsigned size) | ||
584 | uint8_t *ptr = (uint8_t *)&n->bar; | ||
585 | uint64_t val = 0; | ||
586 | |||
587 | + if (unlikely(addr & (sizeof(uint32_t) - 1))) { | ||
588 | + NVME_GUEST_ERR(nvme_ub_mmiord_misaligned32, | ||
589 | + "MMIO read not 32-bit aligned," | ||
590 | + " offset=0x%"PRIx64"", addr); | ||
591 | + /* should RAZ, fall through for now */ | ||
592 | + } else if (unlikely(size < sizeof(uint32_t))) { | ||
593 | + NVME_GUEST_ERR(nvme_ub_mmiord_toosmall, | ||
594 | + "MMIO read smaller than 32-bits," | ||
595 | + " offset=0x%"PRIx64"", addr); | ||
596 | + /* should RAZ, fall through for now */ | ||
597 | + } | ||
598 | + | ||
599 | if (addr < sizeof(n->bar)) { | ||
600 | memcpy(&val, ptr + addr, size); | ||
601 | + } else { | ||
602 | + NVME_GUEST_ERR(nvme_ub_mmiord_invalid_ofs, | ||
603 | + "MMIO read beyond last register," | ||
604 | + " offset=0x%"PRIx64", returning 0", addr); | ||
605 | } | ||
606 | + | ||
607 | return val; | ||
608 | } | ||
609 | |||
610 | @@ -XXX,XX +XXX,XX @@ static void nvme_process_db(NvmeCtrl *n, hwaddr addr, int val) | ||
611 | { | ||
612 | uint32_t qid; | ||
613 | |||
614 | - if (addr & ((1 << 2) - 1)) { | ||
615 | + if (unlikely(addr & ((1 << 2) - 1))) { | ||
616 | + NVME_GUEST_ERR(nvme_ub_db_wr_misaligned, | ||
617 | + "doorbell write not 32-bit aligned," | ||
618 | + " offset=0x%"PRIx64", ignoring", addr); | ||
27 | return; | 619 | return; |
28 | } | 620 | } |
29 | 621 | ||
30 | + bdrv_ref(bs); | 622 | if (((addr - 0x1000) >> 2) & 1) { |
31 | s->bs = bs, | 623 | + /* Completion queue doorbell write */ |
32 | s->opts = QAPI_CLONE(BlockdevAmendOptions, options), | 624 | + |
33 | s->force = has_force ? force : false; | 625 | uint16_t new_head = val & 0xffff; |
626 | int start_sqs; | ||
627 | NvmeCQueue *cq; | ||
628 | |||
629 | qid = (addr - (0x1000 + (1 << 2))) >> 3; | ||
630 | - if (nvme_check_cqid(n, qid)) { | ||
631 | + if (unlikely(nvme_check_cqid(n, qid))) { | ||
632 | + NVME_GUEST_ERR(nvme_ub_db_wr_invalid_cq, | ||
633 | + "completion queue doorbell write" | ||
634 | + " for nonexistent queue," | ||
635 | + " sqid=%"PRIu32", ignoring", qid); | ||
636 | return; | ||
637 | } | ||
638 | |||
639 | cq = n->cq[qid]; | ||
640 | - if (new_head >= cq->size) { | ||
641 | + if (unlikely(new_head >= cq->size)) { | ||
642 | + NVME_GUEST_ERR(nvme_ub_db_wr_invalid_cqhead, | ||
643 | + "completion queue doorbell write value" | ||
644 | + " beyond queue size, sqid=%"PRIu32"," | ||
645 | + " new_head=%"PRIu16", ignoring", | ||
646 | + qid, new_head); | ||
647 | return; | ||
648 | } | ||
649 | |||
650 | @@ -XXX,XX +XXX,XX @@ static void nvme_process_db(NvmeCtrl *n, hwaddr addr, int val) | ||
651 | nvme_isr_notify(n, cq); | ||
652 | } | ||
653 | } else { | ||
654 | + /* Submission queue doorbell write */ | ||
655 | + | ||
656 | uint16_t new_tail = val & 0xffff; | ||
657 | NvmeSQueue *sq; | ||
658 | |||
659 | qid = (addr - 0x1000) >> 3; | ||
660 | - if (nvme_check_sqid(n, qid)) { | ||
661 | + if (unlikely(nvme_check_sqid(n, qid))) { | ||
662 | + NVME_GUEST_ERR(nvme_ub_db_wr_invalid_sq, | ||
663 | + "submission queue doorbell write" | ||
664 | + " for nonexistent queue," | ||
665 | + " sqid=%"PRIu32", ignoring", qid); | ||
666 | return; | ||
667 | } | ||
668 | |||
669 | sq = n->sq[qid]; | ||
670 | - if (new_tail >= sq->size) { | ||
671 | + if (unlikely(new_tail >= sq->size)) { | ||
672 | + NVME_GUEST_ERR(nvme_ub_db_wr_invalid_sqtail, | ||
673 | + "submission queue doorbell write value" | ||
674 | + " beyond queue size, sqid=%"PRIu32"," | ||
675 | + " new_tail=%"PRIu16", ignoring", | ||
676 | + qid, new_tail); | ||
677 | return; | ||
678 | } | ||
679 | |||
680 | diff --git a/hw/block/trace-events b/hw/block/trace-events | ||
681 | index XXXXXXX..XXXXXXX 100644 | ||
682 | --- a/hw/block/trace-events | ||
683 | +++ b/hw/block/trace-events | ||
684 | @@ -XXX,XX +XXX,XX @@ virtio_blk_submit_multireq(void *vdev, void *mrb, int start, int num_reqs, uint6 | ||
685 | hd_geometry_lchs_guess(void *blk, int cyls, int heads, int secs) "blk %p LCHS %d %d %d" | ||
686 | hd_geometry_guess(void *blk, uint32_t cyls, uint32_t heads, uint32_t secs, int trans) "blk %p CHS %u %u %u trans %d" | ||
687 | |||
688 | +# hw/block/nvme.c | ||
689 | +# nvme traces for successful events | ||
690 | +nvme_irq_msix(uint32_t vector) "raising MSI-X IRQ vector %u" | ||
691 | +nvme_irq_pin(void) "pulsing IRQ pin" | ||
692 | +nvme_irq_masked(void) "IRQ is masked" | ||
693 | +nvme_dma_read(uint64_t prp1, uint64_t prp2) "DMA read, prp1=0x%"PRIx64" prp2=0x%"PRIx64"" | ||
694 | +nvme_rw(char const *verb, uint32_t blk_count, uint64_t byte_count, uint64_t lba) "%s %"PRIu32" blocks (%"PRIu64" bytes) from LBA %"PRIu64"" | ||
695 | +nvme_create_sq(uint64_t addr, uint16_t sqid, uint16_t cqid, uint16_t qsize, uint16_t qflags) "create submission queue, addr=0x%"PRIx64", sqid=%"PRIu16", cqid=%"PRIu16", qsize=%"PRIu16", qflags=%"PRIu16"" | ||
696 | +nvme_create_cq(uint64_t addr, uint16_t cqid, uint16_t vector, uint16_t size, uint16_t qflags, int ien) "create completion queue, addr=0x%"PRIx64", cqid=%"PRIu16", vector=%"PRIu16", qsize=%"PRIu16", qflags=%"PRIu16", ien=%d" | ||
697 | +nvme_del_sq(uint16_t qid) "deleting submission queue sqid=%"PRIu16"" | ||
698 | +nvme_del_cq(uint16_t cqid) "deleted completion queue, sqid=%"PRIu16"" | ||
699 | +nvme_identify_ctrl(void) "identify controller" | ||
700 | +nvme_identify_ns(uint16_t ns) "identify namespace, nsid=%"PRIu16"" | ||
701 | +nvme_identify_nslist(uint16_t ns) "identify namespace list, nsid=%"PRIu16"" | ||
702 | +nvme_getfeat_vwcache(char const* result) "get feature volatile write cache, result=%s" | ||
703 | +nvme_getfeat_numq(int result) "get feature number of queues, result=%d" | ||
704 | +nvme_setfeat_numq(int reqcq, int reqsq, int gotcq, int gotsq) "requested cq_count=%d sq_count=%d, responding with cq_count=%d sq_count=%d" | ||
705 | +nvme_mmio_intm_set(uint64_t data, uint64_t new_mask) "wrote MMIO, interrupt mask set, data=0x%"PRIx64", new_mask=0x%"PRIx64"" | ||
706 | +nvme_mmio_intm_clr(uint64_t data, uint64_t new_mask) "wrote MMIO, interrupt mask clr, data=0x%"PRIx64", new_mask=0x%"PRIx64"" | ||
707 | +nvme_mmio_cfg(uint64_t data) "wrote MMIO, config controller config=0x%"PRIx64"" | ||
708 | +nvme_mmio_aqattr(uint64_t data) "wrote MMIO, admin queue attributes=0x%"PRIx64"" | ||
709 | +nvme_mmio_asqaddr(uint64_t data) "wrote MMIO, admin submission queue address=0x%"PRIx64"" | ||
710 | +nvme_mmio_acqaddr(uint64_t data) "wrote MMIO, admin completion queue address=0x%"PRIx64"" | ||
711 | +nvme_mmio_asqaddr_hi(uint64_t data, uint64_t new_addr) "wrote MMIO, admin submission queue high half=0x%"PRIx64", new_address=0x%"PRIx64"" | ||
712 | +nvme_mmio_acqaddr_hi(uint64_t data, uint64_t new_addr) "wrote MMIO, admin completion queue high half=0x%"PRIx64", new_address=0x%"PRIx64"" | ||
713 | +nvme_mmio_start_success(void) "setting controller enable bit succeeded" | ||
714 | +nvme_mmio_stopped(void) "cleared controller enable bit" | ||
715 | +nvme_mmio_shutdown_set(void) "shutdown bit set" | ||
716 | +nvme_mmio_shutdown_cleared(void) "shutdown bit cleared" | ||
717 | + | ||
718 | +# nvme traces for error conditions | ||
719 | +nvme_err_invalid_dma(void) "PRP/SGL is too small for transfer size" | ||
720 | +nvme_err_invalid_prplist_ent(uint64_t prplist) "PRP list entry is null or not page aligned: 0x%"PRIx64"" | ||
721 | +nvme_err_invalid_prp2_align(uint64_t prp2) "PRP2 is not page aligned: 0x%"PRIx64"" | ||
722 | +nvme_err_invalid_prp2_missing(void) "PRP2 is null and more data to be transferred" | ||
723 | +nvme_err_invalid_field(void) "invalid field" | ||
724 | +nvme_err_invalid_prp(void) "invalid PRP" | ||
725 | +nvme_err_invalid_sgl(void) "invalid SGL" | ||
726 | +nvme_err_invalid_ns(uint32_t ns, uint32_t limit) "invalid namespace %u not within 1-%u" | ||
727 | +nvme_err_invalid_opc(uint8_t opc) "invalid opcode 0x%"PRIx8"" | ||
728 | +nvme_err_invalid_admin_opc(uint8_t opc) "invalid admin opcode 0x%"PRIx8"" | ||
729 | +nvme_err_invalid_lba_range(uint64_t start, uint64_t len, uint64_t limit) "Invalid LBA start=%"PRIu64" len=%"PRIu64" limit=%"PRIu64"" | ||
730 | +nvme_err_invalid_del_sq(uint16_t qid) "invalid submission queue deletion, sid=%"PRIu16"" | ||
731 | +nvme_err_invalid_create_sq_cqid(uint16_t cqid) "failed creating submission queue, invalid cqid=%"PRIu16"" | ||
732 | +nvme_err_invalid_create_sq_sqid(uint16_t sqid) "failed creating submission queue, invalid sqid=%"PRIu16"" | ||
733 | +nvme_err_invalid_create_sq_size(uint16_t qsize) "failed creating submission queue, invalid qsize=%"PRIu16"" | ||
734 | +nvme_err_invalid_create_sq_addr(uint64_t addr) "failed creating submission queue, addr=0x%"PRIx64"" | ||
735 | +nvme_err_invalid_create_sq_qflags(uint16_t qflags) "failed creating submission queue, qflags=%"PRIu16"" | ||
736 | +nvme_err_invalid_del_cq_cqid(uint16_t cqid) "failed deleting completion queue, cqid=%"PRIu16"" | ||
737 | +nvme_err_invalid_del_cq_notempty(uint16_t cqid) "failed deleting completion queue, it is not empty, cqid=%"PRIu16"" | ||
738 | +nvme_err_invalid_create_cq_cqid(uint16_t cqid) "failed creating completion queue, cqid=%"PRIu16"" | ||
739 | +nvme_err_invalid_create_cq_size(uint16_t size) "failed creating completion queue, size=%"PRIu16"" | ||
740 | +nvme_err_invalid_create_cq_addr(uint64_t addr) "failed creating completion queue, addr=0x%"PRIx64"" | ||
741 | +nvme_err_invalid_create_cq_vector(uint16_t vector) "failed creating completion queue, vector=%"PRIu16"" | ||
742 | +nvme_err_invalid_create_cq_qflags(uint16_t qflags) "failed creating completion queue, qflags=%"PRIu16"" | ||
743 | +nvme_err_invalid_identify_cns(uint16_t cns) "identify, invalid cns=0x%"PRIx16"" | ||
744 | +nvme_err_invalid_getfeat(int dw10) "invalid get features, dw10=0x%"PRIx32"" | ||
745 | +nvme_err_invalid_setfeat(uint32_t dw10) "invalid set features, dw10=0x%"PRIx32"" | ||
746 | +nvme_err_startfail_cq(void) "nvme_start_ctrl failed because there are non-admin completion queues" | ||
747 | +nvme_err_startfail_sq(void) "nvme_start_ctrl failed because there are non-admin submission queues" | ||
748 | +nvme_err_startfail_nbarasq(void) "nvme_start_ctrl failed because the admin submission queue address is null" | ||
749 | +nvme_err_startfail_nbaracq(void) "nvme_start_ctrl failed because the admin completion queue address is null" | ||
750 | +nvme_err_startfail_asq_misaligned(uint64_t addr) "nvme_start_ctrl failed because the admin submission queue address is misaligned: 0x%"PRIx64"" | ||
751 | +nvme_err_startfail_acq_misaligned(uint64_t addr) "nvme_start_ctrl failed because the admin completion queue address is misaligned: 0x%"PRIx64"" | ||
752 | +nvme_err_startfail_page_too_small(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the page size is too small: log2size=%u, min=%u" | ||
753 | +nvme_err_startfail_page_too_large(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the page size is too large: log2size=%u, max=%u" | ||
754 | +nvme_err_startfail_cqent_too_small(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the completion queue entry size is too small: log2size=%u, min=%u" | ||
755 | +nvme_err_startfail_cqent_too_large(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the completion queue entry size is too large: log2size=%u, max=%u" | ||
756 | +nvme_err_startfail_sqent_too_small(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the submission queue entry size is too small: log2size=%u, min=%u" | ||
757 | +nvme_err_startfail_sqent_too_large(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the submission queue entry size is too large: log2size=%u, max=%u" | ||
758 | +nvme_err_startfail_asqent_sz_zero(void) "nvme_start_ctrl failed because the admin submission queue size is zero" | ||
759 | +nvme_err_startfail_acqent_sz_zero(void) "nvme_start_ctrl failed because the admin completion queue size is zero" | ||
760 | +nvme_err_startfail(void) "setting controller enable bit failed" | ||
761 | + | ||
762 | +# Traces for undefined behavior | ||
763 | +nvme_ub_mmiowr_misaligned32(uint64_t offset) "MMIO write not 32-bit aligned, offset=0x%"PRIx64"" | ||
764 | +nvme_ub_mmiowr_toosmall(uint64_t offset, unsigned size) "MMIO write smaller than 32 bits, offset=0x%"PRIx64", size=%u" | ||
765 | +nvme_ub_mmiowr_intmask_with_msix(void) "undefined access to interrupt mask set when MSI-X is enabled" | ||
766 | +nvme_ub_mmiowr_ro_csts(void) "attempted to set a read only bit of controller status" | ||
767 | +nvme_ub_mmiowr_ssreset_w1c_unsupported(void) "attempted to W1C CSTS.NSSRO but CAP.NSSRS is zero (not supported)" | ||
768 | +nvme_ub_mmiowr_ssreset_unsupported(void) "attempted NVM subsystem reset but CAP.NSSRS is zero (not supported)" | ||
769 | +nvme_ub_mmiowr_cmbloc_reserved(void) "invalid write to reserved CMBLOC when CMBSZ is zero, ignored" | ||
770 | +nvme_ub_mmiowr_cmbsz_readonly(void) "invalid write to read only CMBSZ, ignored" | ||
771 | +nvme_ub_mmiowr_invalid(uint64_t offset, uint64_t data) "invalid MMIO write, offset=0x%"PRIx64", data=0x%"PRIx64"" | ||
772 | +nvme_ub_mmiord_misaligned32(uint64_t offset) "MMIO read not 32-bit aligned, offset=0x%"PRIx64"" | ||
773 | +nvme_ub_mmiord_toosmall(uint64_t offset) "MMIO read smaller than 32-bits, offset=0x%"PRIx64"" | ||
774 | +nvme_ub_mmiord_invalid_ofs(uint64_t offset) "MMIO read beyond last register, offset=0x%"PRIx64", returning 0" | ||
775 | +nvme_ub_db_wr_misaligned(uint64_t offset) "doorbell write not 32-bit aligned, offset=0x%"PRIx64", ignoring" | ||
776 | +nvme_ub_db_wr_invalid_cq(uint32_t qid) "completion queue doorbell write for nonexistent queue, cqid=%"PRIu32", ignoring" | ||
777 | +nvme_ub_db_wr_invalid_cqhead(uint32_t qid, uint16_t new_head) "completion queue doorbell write value beyond queue size, cqid=%"PRIu32", new_head=%"PRIu16", ignoring" | ||
778 | +nvme_ub_db_wr_invalid_sq(uint32_t qid) "submission queue doorbell write for nonexistent queue, sqid=%"PRIu32", ignoring" | ||
779 | +nvme_ub_db_wr_invalid_sqtail(uint32_t qid, uint16_t new_tail) "submission queue doorbell write value beyond queue size, sqid=%"PRIu32", new_head=%"PRIu16", ignoring" | ||
780 | + | ||
781 | # hw/block/xen_disk.c | ||
782 | xen_disk_alloc(char *name) "%s" | ||
783 | xen_disk_init(char *name) "%s" | ||
34 | -- | 784 | -- |
35 | 2.35.1 | 785 | 2.13.6 |
786 | |||
787 | diff view generated by jsdifflib |
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | 1 | From: Fam Zheng <famz@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Following the assertion derived from the API split, | 3 | Management tools create overlays of running guests with qemu-img: |
4 | propagate the assertion also in the static functions. | ||
5 | 4 | ||
6 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | 5 | $ qemu-img create -b /image/in/use.qcow2 -f qcow2 /overlay/image.qcow2 |
7 | Message-Id: <20220303151616.325444-18-eesposit@redhat.com> | 6 | |
7 | but this doesn't work anymore due to image locking: | ||
8 | |||
9 | qemu-img: /overlay/image.qcow2: Failed to get shared "write" lock | ||
10 | Is another process using the image? | ||
11 | Could not open backing image to determine size. | ||
12 | Use the force share option to allow this use case again. | ||
13 | |||
14 | Cc: qemu-stable@nongnu.org | ||
15 | Signed-off-by: Fam Zheng <famz@redhat.com> | ||
16 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
8 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 17 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
9 | --- | 18 | --- |
10 | block.c | 46 ++++++++++++++++++++++++++++++++++++++++++- | 19 | block.c | 3 ++- |
11 | block/block-backend.c | 3 +++ | 20 | 1 file changed, 2 insertions(+), 1 deletion(-) |
12 | 2 files changed, 48 insertions(+), 1 deletion(-) | ||
13 | 21 | ||
14 | diff --git a/block.c b/block.c | 22 | diff --git a/block.c b/block.c |
15 | index XXXXXXX..XXXXXXX 100644 | 23 | index XXXXXXX..XXXXXXX 100644 |
16 | --- a/block.c | 24 | --- a/block.c |
17 | +++ b/block.c | 25 | +++ b/block.c |
18 | @@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_new(void) | 26 | @@ -XXX,XX +XXX,XX @@ void bdrv_img_create(const char *filename, const char *fmt, |
19 | static BlockDriver *bdrv_do_find_format(const char *format_name) | 27 | back_flags = flags; |
20 | { | 28 | back_flags &= ~(BDRV_O_RDWR | BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING); |
21 | BlockDriver *drv1; | 29 | |
22 | + GLOBAL_STATE_CODE(); | 30 | + backing_options = qdict_new(); |
23 | 31 | if (backing_fmt) { | |
24 | QLIST_FOREACH(drv1, &bdrv_drivers, list) { | 32 | - backing_options = qdict_new(); |
25 | if (!strcmp(drv1->format_name, format_name)) { | 33 | qdict_put_str(backing_options, "driver", backing_fmt); |
26 | @@ -XXX,XX +XXX,XX @@ static int64_t create_file_fallback_truncate(BlockBackend *blk, | 34 | } |
27 | int64_t size; | 35 | + qdict_put_bool(backing_options, BDRV_OPT_FORCE_SHARE, true); |
28 | int ret; | 36 | |
29 | 37 | bs = bdrv_open(full_backing, NULL, backing_options, back_flags, | |
30 | + GLOBAL_STATE_CODE(); | ||
31 | + | ||
32 | ret = blk_truncate(blk, minimum_size, false, PREALLOC_MODE_OFF, 0, | ||
33 | &local_err); | 38 | &local_err); |
34 | if (ret < 0 && ret != -ENOTSUP) { | ||
35 | @@ -XXX,XX +XXX,XX @@ static int create_file_fallback_zero_first_sector(BlockBackend *blk, | ||
36 | int64_t bytes_to_clear; | ||
37 | int ret; | ||
38 | |||
39 | + GLOBAL_STATE_CODE(); | ||
40 | + | ||
41 | bytes_to_clear = MIN(current_size, BDRV_SECTOR_SIZE); | ||
42 | if (bytes_to_clear) { | ||
43 | ret = blk_pwrite_zeroes(blk, 0, bytes_to_clear, BDRV_REQ_MAY_UNMAP); | ||
44 | @@ -XXX,XX +XXX,XX @@ static BlockDriver *find_hdev_driver(const char *filename) | ||
45 | { | ||
46 | int score_max = 0, score; | ||
47 | BlockDriver *drv = NULL, *d; | ||
48 | + GLOBAL_STATE_CODE(); | ||
49 | |||
50 | QLIST_FOREACH(d, &bdrv_drivers, list) { | ||
51 | if (d->bdrv_probe_device) { | ||
52 | @@ -XXX,XX +XXX,XX @@ static BlockDriver *find_hdev_driver(const char *filename) | ||
53 | static BlockDriver *bdrv_do_find_protocol(const char *protocol) | ||
54 | { | ||
55 | BlockDriver *drv1; | ||
56 | + GLOBAL_STATE_CODE(); | ||
57 | |||
58 | QLIST_FOREACH(drv1, &bdrv_drivers, list) { | ||
59 | if (drv1->protocol_name && !strcmp(drv1->protocol_name, protocol)) { | ||
60 | @@ -XXX,XX +XXX,XX @@ static int find_image_format(BlockBackend *file, const char *filename, | ||
61 | uint8_t buf[BLOCK_PROBE_BUF_SIZE]; | ||
62 | int ret = 0; | ||
63 | |||
64 | + GLOBAL_STATE_CODE(); | ||
65 | + | ||
66 | /* Return the raw BlockDriver * to scsi-generic devices or empty drives */ | ||
67 | if (blk_is_sg(file) || !blk_is_inserted(file) || blk_getlength(file) == 0) { | ||
68 | *pdrv = &bdrv_raw; | ||
69 | @@ -XXX,XX +XXX,XX @@ static BlockdevDetectZeroesOptions bdrv_parse_detect_zeroes(QemuOpts *opts, | ||
70 | BlockdevDetectZeroesOptions detect_zeroes = | ||
71 | qapi_enum_parse(&BlockdevDetectZeroesOptions_lookup, value, | ||
72 | BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF, &local_err); | ||
73 | + GLOBAL_STATE_CODE(); | ||
74 | g_free(value); | ||
75 | if (local_err) { | ||
76 | error_propagate(errp, local_err); | ||
77 | @@ -XXX,XX +XXX,XX @@ static void bdrv_child_cb_drained_end(BdrvChild *child, | ||
78 | static int bdrv_child_cb_inactivate(BdrvChild *child) | ||
79 | { | ||
80 | BlockDriverState *bs = child->opaque; | ||
81 | + GLOBAL_STATE_CODE(); | ||
82 | assert(bs->open_flags & BDRV_O_INACTIVE); | ||
83 | return 0; | ||
84 | } | ||
85 | @@ -XXX,XX +XXX,XX @@ static void bdrv_child_cb_set_aio_ctx(BdrvChild *child, AioContext *ctx, | ||
86 | static void bdrv_temp_snapshot_options(int *child_flags, QDict *child_options, | ||
87 | int parent_flags, QDict *parent_options) | ||
88 | { | ||
89 | + GLOBAL_STATE_CODE(); | ||
90 | *child_flags = (parent_flags & ~BDRV_O_SNAPSHOT) | BDRV_O_TEMPORARY; | ||
91 | |||
92 | /* For temporary files, unconditional cache=unsafe is fine */ | ||
93 | @@ -XXX,XX +XXX,XX @@ static void bdrv_backing_attach(BdrvChild *c) | ||
94 | BlockDriverState *parent = c->opaque; | ||
95 | BlockDriverState *backing_hd = c->bs; | ||
96 | |||
97 | + GLOBAL_STATE_CODE(); | ||
98 | assert(!parent->backing_blocker); | ||
99 | error_setg(&parent->backing_blocker, | ||
100 | "node is used as backing hd of '%s'", | ||
101 | @@ -XXX,XX +XXX,XX @@ static void bdrv_backing_detach(BdrvChild *c) | ||
102 | { | ||
103 | BlockDriverState *parent = c->opaque; | ||
104 | |||
105 | + GLOBAL_STATE_CODE(); | ||
106 | assert(parent->backing_blocker); | ||
107 | bdrv_op_unblock_all(c->bs, parent->backing_blocker); | ||
108 | error_free(parent->backing_blocker); | ||
109 | @@ -XXX,XX +XXX,XX @@ static int bdrv_backing_update_filename(BdrvChild *c, BlockDriverState *base, | ||
110 | BlockDriverState *parent = c->opaque; | ||
111 | bool read_only = bdrv_is_read_only(parent); | ||
112 | int ret; | ||
113 | + GLOBAL_STATE_CODE(); | ||
114 | |||
115 | if (read_only) { | ||
116 | ret = bdrv_reopen_set_read_only(parent, false, errp); | ||
117 | @@ -XXX,XX +XXX,XX @@ static void bdrv_inherited_options(BdrvChildRole role, bool parent_is_format, | ||
118 | int parent_flags, QDict *parent_options) | ||
119 | { | ||
120 | int flags = parent_flags; | ||
121 | + GLOBAL_STATE_CODE(); | ||
122 | |||
123 | /* | ||
124 | * First, decide whether to set, clear, or leave BDRV_O_PROTOCOL. | ||
125 | @@ -XXX,XX +XXX,XX @@ AioContext *bdrv_child_get_parent_aio_context(BdrvChild *c) | ||
126 | static int bdrv_open_flags(BlockDriverState *bs, int flags) | ||
127 | { | ||
128 | int open_flags = flags; | ||
129 | + GLOBAL_STATE_CODE(); | ||
130 | |||
131 | /* | ||
132 | * Clear flags that are internal to the block layer before opening the | ||
133 | @@ -XXX,XX +XXX,XX @@ static int bdrv_open_flags(BlockDriverState *bs, int flags) | ||
134 | |||
135 | static void update_flags_from_options(int *flags, QemuOpts *opts) | ||
136 | { | ||
137 | + GLOBAL_STATE_CODE(); | ||
138 | + | ||
139 | *flags &= ~(BDRV_O_CACHE_MASK | BDRV_O_RDWR | BDRV_O_AUTO_RDONLY); | ||
140 | |||
141 | if (qemu_opt_get_bool_del(opts, BDRV_OPT_CACHE_NO_FLUSH, false)) { | ||
142 | @@ -XXX,XX +XXX,XX @@ static void update_flags_from_options(int *flags, QemuOpts *opts) | ||
143 | |||
144 | static void update_options_from_flags(QDict *options, int flags) | ||
145 | { | ||
146 | + GLOBAL_STATE_CODE(); | ||
147 | if (!qdict_haskey(options, BDRV_OPT_CACHE_DIRECT)) { | ||
148 | qdict_put_bool(options, BDRV_OPT_CACHE_DIRECT, flags & BDRV_O_NOCACHE); | ||
149 | } | ||
150 | @@ -XXX,XX +XXX,XX @@ static void bdrv_assign_node_name(BlockDriverState *bs, | ||
151 | Error **errp) | ||
152 | { | ||
153 | char *gen_node_name = NULL; | ||
154 | + GLOBAL_STATE_CODE(); | ||
155 | |||
156 | if (!node_name) { | ||
157 | node_name = gen_node_name = id_generate(ID_BLOCK); | ||
158 | @@ -XXX,XX +XXX,XX @@ static int bdrv_open_common(BlockDriverState *bs, BlockBackend *file, | ||
159 | |||
160 | assert(bs->file == NULL); | ||
161 | assert(options != NULL && bs->options != options); | ||
162 | + GLOBAL_STATE_CODE(); | ||
163 | |||
164 | opts = qemu_opts_create(&bdrv_runtime_opts, NULL, 0, &error_abort); | ||
165 | if (!qemu_opts_absorb_qdict(opts, options, errp)) { | ||
166 | @@ -XXX,XX +XXX,XX @@ static QDict *parse_json_filename(const char *filename, Error **errp) | ||
167 | QObject *options_obj; | ||
168 | QDict *options; | ||
169 | int ret; | ||
170 | + GLOBAL_STATE_CODE(); | ||
171 | |||
172 | ret = strstart(filename, "json:", &filename); | ||
173 | assert(ret); | ||
174 | @@ -XXX,XX +XXX,XX @@ static void parse_json_protocol(QDict *options, const char **pfilename, | ||
175 | { | ||
176 | QDict *json_options; | ||
177 | Error *local_err = NULL; | ||
178 | + GLOBAL_STATE_CODE(); | ||
179 | |||
180 | /* Parse json: pseudo-protocol */ | ||
181 | if (!*pfilename || !g_str_has_prefix(*pfilename, "json:")) { | ||
182 | @@ -XXX,XX +XXX,XX @@ static GSList *bdrv_topological_dfs(GSList *list, GHashTable *found, | ||
183 | BdrvChild *child; | ||
184 | g_autoptr(GHashTable) local_found = NULL; | ||
185 | |||
186 | + GLOBAL_STATE_CODE(); | ||
187 | + | ||
188 | if (!found) { | ||
189 | assert(!list); | ||
190 | found = local_found = g_hash_table_new(NULL, NULL); | ||
191 | @@ -XXX,XX +XXX,XX @@ typedef struct BdrvReplaceChildState { | ||
192 | static void bdrv_replace_child_commit(void *opaque) | ||
193 | { | ||
194 | BdrvReplaceChildState *s = opaque; | ||
195 | + GLOBAL_STATE_CODE(); | ||
196 | |||
197 | if (s->free_empty_child && !s->child->bs) { | ||
198 | bdrv_child_free(s->child); | ||
199 | @@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_abort(void *opaque) | ||
200 | BdrvReplaceChildState *s = opaque; | ||
201 | BlockDriverState *new_bs = s->child->bs; | ||
202 | |||
203 | + GLOBAL_STATE_CODE(); | ||
204 | /* | ||
205 | * old_bs reference is transparently moved from @s to s->child. | ||
206 | * | ||
207 | @@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_noperm(BdrvChild **childp, | ||
208 | static void bdrv_child_free(BdrvChild *child) | ||
209 | { | ||
210 | assert(!child->bs); | ||
211 | + GLOBAL_STATE_CODE(); | ||
212 | assert(!child->next.le_prev); /* not in children list */ | ||
213 | |||
214 | g_free(child->name); | ||
215 | @@ -XXX,XX +XXX,XX @@ static int bdrv_attach_child_common(BlockDriverState *child_bs, | ||
216 | assert(child); | ||
217 | assert(*child == NULL); | ||
218 | assert(child_class->get_parent_desc); | ||
219 | + GLOBAL_STATE_CODE(); | ||
220 | |||
221 | new_child = g_new(BdrvChild, 1); | ||
222 | *new_child = (BdrvChild) { | ||
223 | @@ -XXX,XX +XXX,XX @@ static int bdrv_attach_child_noperm(BlockDriverState *parent_bs, | ||
224 | uint64_t perm, shared_perm; | ||
225 | |||
226 | assert(parent_bs->drv); | ||
227 | + GLOBAL_STATE_CODE(); | ||
228 | |||
229 | if (bdrv_recurse_has_child(child_bs, parent_bs)) { | ||
230 | error_setg(errp, "Making '%s' a %s child of '%s' would create a cycle", | ||
231 | @@ -XXX,XX +XXX,XX @@ static void bdrv_detach_child(BdrvChild **childp) | ||
232 | { | ||
233 | BlockDriverState *old_bs = (*childp)->bs; | ||
234 | |||
235 | + GLOBAL_STATE_CODE(); | ||
236 | bdrv_replace_child_noperm(childp, NULL, true); | ||
237 | |||
238 | if (old_bs) { | ||
239 | @@ -XXX,XX +XXX,XX @@ static int bdrv_set_file_or_backing_noperm(BlockDriverState *parent_bs, | ||
240 | BdrvChild *child = is_backing ? parent_bs->backing : parent_bs->file; | ||
241 | BdrvChildRole role; | ||
242 | |||
243 | + GLOBAL_STATE_CODE(); | ||
244 | + | ||
245 | if (!parent_bs->drv) { | ||
246 | /* | ||
247 | * Node without drv is an object without a class :/. TODO: finally fix | ||
248 | @@ -XXX,XX +XXX,XX @@ static int bdrv_set_backing_noperm(BlockDriverState *bs, | ||
249 | BlockDriverState *backing_hd, | ||
250 | Transaction *tran, Error **errp) | ||
251 | { | ||
252 | + GLOBAL_STATE_CODE(); | ||
253 | return bdrv_set_file_or_backing_noperm(bs, backing_hd, true, tran, errp); | ||
254 | } | ||
255 | |||
256 | @@ -XXX,XX +XXX,XX @@ static BlockDriverState *bdrv_append_temp_snapshot(BlockDriverState *bs, | ||
257 | BlockDriverState *bs_snapshot = NULL; | ||
258 | int ret; | ||
259 | |||
260 | + GLOBAL_STATE_CODE(); | ||
261 | + | ||
262 | /* if snapshot, we create a temporary backing file and open it | ||
263 | instead of opening 'filename' directly */ | ||
264 | |||
265 | @@ -XXX,XX +XXX,XX @@ static int bdrv_reopen_parse_file_or_backing(BDRVReopenState *reopen_state, | ||
266 | QObject *value; | ||
267 | const char *str; | ||
268 | |||
269 | + GLOBAL_STATE_CODE(); | ||
270 | + | ||
271 | value = qdict_get(reopen_state->options, child_name); | ||
272 | if (value == NULL) { | ||
273 | return 0; | ||
274 | @@ -XXX,XX +XXX,XX @@ static void bdrv_remove_filter_or_cow_child_abort(void *opaque) | ||
275 | static void bdrv_remove_filter_or_cow_child_commit(void *opaque) | ||
276 | { | ||
277 | BdrvRemoveFilterOrCowChild *s = opaque; | ||
278 | - | ||
279 | + GLOBAL_STATE_CODE(); | ||
280 | bdrv_child_free(s->child); | ||
281 | } | ||
282 | |||
283 | @@ -XXX,XX +XXX,XX @@ static int bdrv_replace_node_noperm(BlockDriverState *from, | ||
284 | BdrvChild *c, *next; | ||
285 | |||
286 | assert(to != NULL); | ||
287 | + GLOBAL_STATE_CODE(); | ||
288 | |||
289 | QLIST_FOREACH_SAFE(c, &from->parents, next_parent, next) { | ||
290 | assert(c->bs == from); | ||
291 | @@ -XXX,XX +XXX,XX @@ static int bdrv_replace_node_common(BlockDriverState *from, | ||
292 | BlockDriverState *to_cow_parent = NULL; | ||
293 | int ret; | ||
294 | |||
295 | + GLOBAL_STATE_CODE(); | ||
296 | assert(to != NULL); | ||
297 | |||
298 | if (detach_subchain) { | ||
299 | @@ -XXX,XX +XXX,XX @@ void bdrv_debug_event(BlockDriverState *bs, BlkdebugEvent event) | ||
300 | |||
301 | static BlockDriverState *bdrv_find_debug_node(BlockDriverState *bs) | ||
302 | { | ||
303 | + GLOBAL_STATE_CODE(); | ||
304 | while (bs && bs->drv && !bs->drv->bdrv_debug_breakpoint) { | ||
305 | bs = bdrv_primary_bs(bs); | ||
306 | } | ||
307 | @@ -XXX,XX +XXX,XX @@ void bdrv_activate_all(Error **errp) | ||
308 | static bool bdrv_has_bds_parent(BlockDriverState *bs, bool only_active) | ||
309 | { | ||
310 | BdrvChild *parent; | ||
311 | + GLOBAL_STATE_CODE(); | ||
312 | |||
313 | QLIST_FOREACH(parent, &bs->parents, next_parent) { | ||
314 | if (parent->klass->parent_is_bds) { | ||
315 | @@ -XXX,XX +XXX,XX @@ void bdrv_coroutine_enter(BlockDriverState *bs, Coroutine *co) | ||
316 | |||
317 | static void bdrv_do_remove_aio_context_notifier(BdrvAioNotifier *ban) | ||
318 | { | ||
319 | + GLOBAL_STATE_CODE(); | ||
320 | QLIST_REMOVE(ban, list); | ||
321 | g_free(ban); | ||
322 | } | ||
323 | diff --git a/block/block-backend.c b/block/block-backend.c | ||
324 | index XXXXXXX..XXXXXXX 100644 | ||
325 | --- a/block/block-backend.c | ||
326 | +++ b/block/block-backend.c | ||
327 | @@ -XXX,XX +XXX,XX @@ BlockDriverState *blk_bs(BlockBackend *blk) | ||
328 | static BlockBackend *bdrv_first_blk(BlockDriverState *bs) | ||
329 | { | ||
330 | BdrvChild *child; | ||
331 | + | ||
332 | + GLOBAL_STATE_CODE(); | ||
333 | + | ||
334 | QLIST_FOREACH(child, &bs->parents, next_parent) { | ||
335 | if (child->klass == &child_root) { | ||
336 | return child->opaque; | ||
337 | -- | 39 | -- |
338 | 2.35.1 | 40 | 2.13.6 |
41 | |||
42 | diff view generated by jsdifflib |
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | 1 | From: Thomas Huth <thuth@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | 3 | It's not working anymore since QEMU v1.3.0 - time to remove it now. |
4 | Message-Id: <20220303151616.325444-22-eesposit@redhat.com> | 4 | |
5 | Signed-off-by: Thomas Huth <thuth@redhat.com> | ||
6 | Reviewed-by: John Snow <jsnow@redhat.com> | ||
7 | Reviewed-by: Markus Armbruster <armbru@redhat.com> | ||
5 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 8 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
6 | --- | 9 | --- |
7 | block/block-backend.c | 3 +++ | 10 | blockdev.c | 11 ----------- |
8 | blockdev.c | 16 ++++++++++++++++ | 11 | qemu-doc.texi | 6 ------ |
9 | 2 files changed, 19 insertions(+) | 12 | 2 files changed, 17 deletions(-) |
10 | 13 | ||
11 | diff --git a/block/block-backend.c b/block/block-backend.c | ||
12 | index XXXXXXX..XXXXXXX 100644 | ||
13 | --- a/block/block-backend.c | ||
14 | +++ b/block/block-backend.c | ||
15 | @@ -XXX,XX +XXX,XX @@ bool bdrv_is_root_node(BlockDriverState *bs) | ||
16 | */ | ||
17 | DriveInfo *blk_legacy_dinfo(BlockBackend *blk) | ||
18 | { | ||
19 | + GLOBAL_STATE_CODE(); | ||
20 | return blk->legacy_dinfo; | ||
21 | } | ||
22 | |||
23 | @@ -XXX,XX +XXX,XX @@ DriveInfo *blk_legacy_dinfo(BlockBackend *blk) | ||
24 | DriveInfo *blk_set_legacy_dinfo(BlockBackend *blk, DriveInfo *dinfo) | ||
25 | { | ||
26 | assert(!blk->legacy_dinfo); | ||
27 | + GLOBAL_STATE_CODE(); | ||
28 | return blk->legacy_dinfo = dinfo; | ||
29 | } | ||
30 | |||
31 | @@ -XXX,XX +XXX,XX @@ DriveInfo *blk_set_legacy_dinfo(BlockBackend *blk, DriveInfo *dinfo) | ||
32 | BlockBackend *blk_by_legacy_dinfo(DriveInfo *dinfo) | ||
33 | { | ||
34 | BlockBackend *blk = NULL; | ||
35 | + GLOBAL_STATE_CODE(); | ||
36 | |||
37 | while ((blk = blk_next(blk)) != NULL) { | ||
38 | if (blk->legacy_dinfo == dinfo) { | ||
39 | diff --git a/blockdev.c b/blockdev.c | 14 | diff --git a/blockdev.c b/blockdev.c |
40 | index XXXXXXX..XXXXXXX 100644 | 15 | index XXXXXXX..XXXXXXX 100644 |
41 | --- a/blockdev.c | 16 | --- a/blockdev.c |
42 | +++ b/blockdev.c | 17 | +++ b/blockdev.c |
43 | @@ -XXX,XX +XXX,XX @@ void override_max_devs(BlockInterfaceType type, int max_devs) | 18 | @@ -XXX,XX +XXX,XX @@ QemuOptsList qemu_legacy_drive_opts = { |
44 | BlockBackend *blk; | 19 | .type = QEMU_OPT_STRING, |
45 | DriveInfo *dinfo; | 20 | .help = "chs translation (auto, lba, none)", |
46 | 21 | },{ | |
47 | + GLOBAL_STATE_CODE(); | 22 | - .name = "boot", |
48 | + | 23 | - .type = QEMU_OPT_BOOL, |
49 | if (max_devs <= 0) { | 24 | - .help = "(deprecated, ignored)", |
50 | return; | 25 | - },{ |
26 | .name = "addr", | ||
27 | .type = QEMU_OPT_STRING, | ||
28 | .help = "pci address (virtio only)", | ||
29 | @@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type) | ||
30 | goto fail; | ||
51 | } | 31 | } |
52 | @@ -XXX,XX +XXX,XX @@ void blockdev_mark_auto_del(BlockBackend *blk) | 32 | |
53 | DriveInfo *dinfo = blk_legacy_dinfo(blk); | 33 | - /* Deprecated option boot=[on|off] */ |
54 | BlockJob *job; | 34 | - if (qemu_opt_get(legacy_opts, "boot") != NULL) { |
55 | 35 | - fprintf(stderr, "qemu-kvm: boot=on|off is deprecated and will be " | |
56 | + GLOBAL_STATE_CODE(); | 36 | - "ignored. Future versions will reject this parameter. Please " |
57 | + | 37 | - "update your scripts.\n"); |
58 | if (!dinfo) { | 38 | - } |
59 | return; | 39 | - |
60 | } | 40 | /* Other deprecated options */ |
61 | @@ -XXX,XX +XXX,XX @@ void blockdev_mark_auto_del(BlockBackend *blk) | 41 | if (!qtest_enabled()) { |
62 | void blockdev_auto_del(BlockBackend *blk) | 42 | for (i = 0; i < ARRAY_SIZE(deprecated); i++) { |
63 | { | 43 | diff --git a/qemu-doc.texi b/qemu-doc.texi |
64 | DriveInfo *dinfo = blk_legacy_dinfo(blk); | 44 | index XXXXXXX..XXXXXXX 100644 |
65 | + GLOBAL_STATE_CODE(); | 45 | --- a/qemu-doc.texi |
66 | 46 | +++ b/qemu-doc.texi | |
67 | if (dinfo && dinfo->auto_del) { | 47 | @@ -XXX,XX +XXX,XX @@ deprecated. |
68 | monitor_remove_blk(blk); | 48 | |
69 | @@ -XXX,XX +XXX,XX @@ QemuOpts *drive_add(BlockInterfaceType type, int index, const char *file, | 49 | @section System emulator command line arguments |
70 | { | 50 | |
71 | QemuOpts *opts; | 51 | -@subsection -drive boot=on|off (since 1.3.0) |
72 | 52 | - | |
73 | + GLOBAL_STATE_CODE(); | 53 | -The ``boot=on|off'' option to the ``-drive'' argument is |
74 | + | 54 | -ignored. Applications should use the ``bootindex=N'' parameter |
75 | opts = qemu_opts_parse_noisily(qemu_find_opts("drive"), optstr, false); | 55 | -to set an absolute ordering between devices instead. |
76 | if (!opts) { | 56 | - |
77 | return NULL; | 57 | @subsection -tdf (since 1.3.0) |
78 | @@ -XXX,XX +XXX,XX @@ DriveInfo *drive_get(BlockInterfaceType type, int bus, int unit) | 58 | |
79 | BlockBackend *blk; | 59 | The ``-tdf'' argument is ignored. The behaviour implemented |
80 | DriveInfo *dinfo; | ||
81 | |||
82 | + GLOBAL_STATE_CODE(); | ||
83 | + | ||
84 | for (blk = blk_next(NULL); blk; blk = blk_next(blk)) { | ||
85 | dinfo = blk_legacy_dinfo(blk); | ||
86 | if (dinfo && dinfo->type == type | ||
87 | @@ -XXX,XX +XXX,XX @@ void drive_check_orphaned(void) | ||
88 | Location loc; | ||
89 | bool orphans = false; | ||
90 | |||
91 | + GLOBAL_STATE_CODE(); | ||
92 | + | ||
93 | for (blk = blk_next(NULL); blk; blk = blk_next(blk)) { | ||
94 | dinfo = blk_legacy_dinfo(blk); | ||
95 | /* | ||
96 | @@ -XXX,XX +XXX,XX @@ void drive_check_orphaned(void) | ||
97 | |||
98 | DriveInfo *drive_get_by_index(BlockInterfaceType type, int index) | ||
99 | { | ||
100 | + GLOBAL_STATE_CODE(); | ||
101 | return drive_get(type, | ||
102 | drive_index_to_bus_id(type, index), | ||
103 | drive_index_to_unit_id(type, index)); | ||
104 | @@ -XXX,XX +XXX,XX @@ int drive_get_max_bus(BlockInterfaceType type) | ||
105 | BlockBackend *blk; | ||
106 | DriveInfo *dinfo; | ||
107 | |||
108 | + GLOBAL_STATE_CODE(); | ||
109 | + | ||
110 | max_bus = -1; | ||
111 | for (blk = blk_next(NULL); blk; blk = blk_next(blk)) { | ||
112 | dinfo = blk_legacy_dinfo(blk); | ||
113 | @@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type, | ||
114 | const char *filename; | ||
115 | int i; | ||
116 | |||
117 | + GLOBAL_STATE_CODE(); | ||
118 | + | ||
119 | /* Change legacy command line options into QMP ones */ | ||
120 | static const struct { | ||
121 | const char *from; | ||
122 | -- | 60 | -- |
123 | 2.35.1 | 61 | 2.13.6 |
62 | |||
63 | diff view generated by jsdifflib |
1 | From: Hanna Reitz <hreitz@redhat.com> | 1 | From: Thomas Huth <thuth@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Test the following scenario: | 3 | It's been marked as deprecated since QEMU v2.10.0, and so far nobody |
4 | 1. Some block node (null-co) attached to a user (here: NBD server) that | 4 | complained that we should keep it, so let's remove this legacy option |
5 | performs I/O and keeps the node in an I/O thread | 5 | now to simplify the code quite a bit. |
6 | 2. Repeatedly run blockdev-add/blockdev-del to add/remove an overlay | 6 | |
7 | to/from that node | 7 | Signed-off-by: Thomas Huth <thuth@redhat.com> |
8 | 8 | Reviewed-by: John Snow <jsnow@redhat.com> | |
9 | Each blockdev-add triggers bdrv_refresh_limits(), and because | 9 | Reviewed-by: Markus Armbruster <armbru@redhat.com> |
10 | blockdev-add runs in the main thread, it does not stop the I/O requests. | ||
11 | I/O can thus happen while the limits are refreshed, and when such a | ||
12 | request sees a temporarily invalid block limit (e.g. alignment is 0), | ||
13 | this may easily crash qemu (or the storage daemon in this case). | ||
14 | |||
15 | The block layer needs to ensure that I/O requests to a node are paused | ||
16 | while that node's BlockLimits are refreshed. | ||
17 | |||
18 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
19 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
20 | Message-Id: <20220216105355.30729-4-hreitz@redhat.com> | ||
21 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
22 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
23 | --- | 11 | --- |
24 | .../qemu-iotests/tests/graph-changes-while-io | 91 +++++++++++++++++++ | 12 | vl.c | 86 ++------------------------------------------------------- |
25 | .../tests/graph-changes-while-io.out | 5 + | 13 | qemu-doc.texi | 8 ------ |
26 | 2 files changed, 96 insertions(+) | 14 | qemu-options.hx | 19 ++----------- |
27 | create mode 100755 tests/qemu-iotests/tests/graph-changes-while-io | 15 | 3 files changed, 4 insertions(+), 109 deletions(-) |
28 | create mode 100644 tests/qemu-iotests/tests/graph-changes-while-io.out | 16 | |
29 | 17 | diff --git a/vl.c b/vl.c | |
30 | diff --git a/tests/qemu-iotests/tests/graph-changes-while-io b/tests/qemu-iotests/tests/graph-changes-while-io | 18 | index XXXXXXX..XXXXXXX 100644 |
31 | new file mode 100755 | 19 | --- a/vl.c |
32 | index XXXXXXX..XXXXXXX | 20 | +++ b/vl.c |
33 | --- /dev/null | 21 | @@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv, char **envp) |
34 | +++ b/tests/qemu-iotests/tests/graph-changes-while-io | 22 | const char *boot_order = NULL; |
35 | @@ -XXX,XX +XXX,XX @@ | 23 | const char *boot_once = NULL; |
36 | +#!/usr/bin/env python3 | 24 | DisplayState *ds; |
37 | +# group: rw | 25 | - int cyls, heads, secs, translation; |
38 | +# | 26 | QemuOpts *opts, *machine_opts; |
39 | +# Test graph changes while I/O is happening | 27 | - QemuOpts *hda_opts = NULL, *icount_opts = NULL, *accel_opts = NULL; |
40 | +# | 28 | + QemuOpts *icount_opts = NULL, *accel_opts = NULL; |
41 | +# Copyright (C) 2022 Red Hat, Inc. | 29 | QemuOptsList *olist; |
42 | +# | 30 | int optind; |
43 | +# This program is free software; you can redistribute it and/or modify | 31 | const char *optarg; |
44 | +# it under the terms of the GNU General Public License as published by | 32 | @@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv, char **envp) |
45 | +# the Free Software Foundation; either version 2 of the License, or | 33 | |
46 | +# (at your option) any later version. | 34 | cpu_model = NULL; |
47 | +# | 35 | snapshot = 0; |
48 | +# This program is distributed in the hope that it will be useful, | 36 | - cyls = heads = secs = 0; |
49 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of | 37 | - translation = BIOS_ATA_TRANSLATION_AUTO; |
50 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 38 | |
51 | +# GNU General Public License for more details. | 39 | nb_nics = 0; |
52 | +# | 40 | |
53 | +# You should have received a copy of the GNU General Public License | 41 | @@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv, char **envp) |
54 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. | 42 | if (optind >= argc) |
55 | +# | 43 | break; |
56 | + | 44 | if (argv[optind][0] != '-') { |
57 | +import os | 45 | - hda_opts = drive_add(IF_DEFAULT, 0, argv[optind++], HD_OPTS); |
58 | +from threading import Thread | 46 | + drive_add(IF_DEFAULT, 0, argv[optind++], HD_OPTS); |
59 | +import iotests | 47 | } else { |
60 | +from iotests import imgfmt, qemu_img, qemu_img_create, QMPTestCase, \ | 48 | const QEMUOption *popt; |
61 | + QemuStorageDaemon | 49 | |
62 | + | 50 | @@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv, char **envp) |
63 | + | 51 | cpu_model = optarg; |
64 | +top = os.path.join(iotests.test_dir, 'top.img') | 52 | break; |
65 | +nbd_sock = os.path.join(iotests.sock_dir, 'nbd.sock') | 53 | case QEMU_OPTION_hda: |
66 | + | 54 | - { |
67 | + | 55 | - char buf[256]; |
68 | +def do_qemu_img_bench() -> None: | 56 | - if (cyls == 0) |
69 | + """ | 57 | - snprintf(buf, sizeof(buf), "%s", HD_OPTS); |
70 | + Do some I/O requests on `nbd_sock`. | 58 | - else |
71 | + """ | 59 | - snprintf(buf, sizeof(buf), |
72 | + assert qemu_img('bench', '-f', 'raw', '-c', '2000000', | 60 | - "%s,cyls=%d,heads=%d,secs=%d%s", |
73 | + f'nbd+unix:///node0?socket={nbd_sock}') == 0 | 61 | - HD_OPTS , cyls, heads, secs, |
74 | + | 62 | - translation == BIOS_ATA_TRANSLATION_LBA ? |
75 | + | 63 | - ",trans=lba" : |
76 | +class TestGraphChangesWhileIO(QMPTestCase): | 64 | - translation == BIOS_ATA_TRANSLATION_NONE ? |
77 | + def setUp(self) -> None: | 65 | - ",trans=none" : ""); |
78 | + # Create an overlay that can be added at runtime on top of the | 66 | - drive_add(IF_DEFAULT, 0, optarg, buf); |
79 | + # null-co block node that will receive I/O | 67 | - break; |
80 | + assert qemu_img_create('-f', imgfmt, '-F', 'raw', '-b', 'null-co://', | 68 | - } |
81 | + top) == 0 | 69 | case QEMU_OPTION_hdb: |
82 | + | 70 | case QEMU_OPTION_hdc: |
83 | + # QSD instance with a null-co block node in an I/O thread, | 71 | case QEMU_OPTION_hdd: |
84 | + # exported over NBD (on `nbd_sock`, export name "node0") | 72 | @@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv, char **envp) |
85 | + self.qsd = QemuStorageDaemon( | 73 | case QEMU_OPTION_snapshot: |
86 | + '--object', 'iothread,id=iothread0', | 74 | snapshot = 1; |
87 | + '--blockdev', 'null-co,node-name=node0,read-zeroes=true', | 75 | break; |
88 | + '--nbd-server', f'addr.type=unix,addr.path={nbd_sock}', | 76 | - case QEMU_OPTION_hdachs: |
89 | + '--export', 'nbd,id=exp0,node-name=node0,iothread=iothread0,' + | 77 | - { |
90 | + 'fixed-iothread=true,writable=true', | 78 | - const char *p; |
91 | + qmp=True | 79 | - p = optarg; |
92 | + ) | 80 | - cyls = strtol(p, (char **)&p, 0); |
93 | + | 81 | - if (cyls < 1 || cyls > 16383) |
94 | + def tearDown(self) -> None: | 82 | - goto chs_fail; |
95 | + self.qsd.stop() | 83 | - if (*p != ',') |
96 | + | 84 | - goto chs_fail; |
97 | + def test_blockdev_add_while_io(self) -> None: | 85 | - p++; |
98 | + # Run qemu-img bench in the background | 86 | - heads = strtol(p, (char **)&p, 0); |
99 | + bench_thr = Thread(target=do_qemu_img_bench) | 87 | - if (heads < 1 || heads > 16) |
100 | + bench_thr.start() | 88 | - goto chs_fail; |
101 | + | 89 | - if (*p != ',') |
102 | + # While qemu-img bench is running, repeatedly add and remove an | 90 | - goto chs_fail; |
103 | + # overlay to/from node0 | 91 | - p++; |
104 | + while bench_thr.is_alive(): | 92 | - secs = strtol(p, (char **)&p, 0); |
105 | + result = self.qsd.qmp('blockdev-add', { | 93 | - if (secs < 1 || secs > 63) |
106 | + 'driver': imgfmt, | 94 | - goto chs_fail; |
107 | + 'node-name': 'overlay', | 95 | - if (*p == ',') { |
108 | + 'backing': 'node0', | 96 | - p++; |
109 | + 'file': { | 97 | - if (!strcmp(p, "large")) { |
110 | + 'driver': 'file', | 98 | - translation = BIOS_ATA_TRANSLATION_LARGE; |
111 | + 'filename': top | 99 | - } else if (!strcmp(p, "rechs")) { |
112 | + } | 100 | - translation = BIOS_ATA_TRANSLATION_RECHS; |
113 | + }) | 101 | - } else if (!strcmp(p, "none")) { |
114 | + self.assert_qmp(result, 'return', {}) | 102 | - translation = BIOS_ATA_TRANSLATION_NONE; |
115 | + | 103 | - } else if (!strcmp(p, "lba")) { |
116 | + result = self.qsd.qmp('blockdev-del', { | 104 | - translation = BIOS_ATA_TRANSLATION_LBA; |
117 | + 'node-name': 'overlay' | 105 | - } else if (!strcmp(p, "auto")) { |
118 | + }) | 106 | - translation = BIOS_ATA_TRANSLATION_AUTO; |
119 | + self.assert_qmp(result, 'return', {}) | 107 | - } else { |
120 | + | 108 | - goto chs_fail; |
121 | + bench_thr.join() | 109 | - } |
122 | + | 110 | - } else if (*p != '\0') { |
123 | +if __name__ == '__main__': | 111 | - chs_fail: |
124 | + # Format must support raw backing files | 112 | - error_report("invalid physical CHS format"); |
125 | + iotests.main(supported_fmts=['qcow', 'qcow2', 'qed'], | 113 | - exit(1); |
126 | + supported_protocols=['file']) | 114 | - } |
127 | diff --git a/tests/qemu-iotests/tests/graph-changes-while-io.out b/tests/qemu-iotests/tests/graph-changes-while-io.out | 115 | - if (hda_opts != NULL) { |
128 | new file mode 100644 | 116 | - qemu_opt_set_number(hda_opts, "cyls", cyls, |
129 | index XXXXXXX..XXXXXXX | 117 | - &error_abort); |
130 | --- /dev/null | 118 | - qemu_opt_set_number(hda_opts, "heads", heads, |
131 | +++ b/tests/qemu-iotests/tests/graph-changes-while-io.out | 119 | - &error_abort); |
132 | @@ -XXX,XX +XXX,XX @@ | 120 | - qemu_opt_set_number(hda_opts, "secs", secs, |
133 | +. | 121 | - &error_abort); |
134 | +---------------------------------------------------------------------- | 122 | - if (translation == BIOS_ATA_TRANSLATION_LARGE) { |
135 | +Ran 1 tests | 123 | - qemu_opt_set(hda_opts, "trans", "large", |
136 | + | 124 | - &error_abort); |
137 | +OK | 125 | - } else if (translation == BIOS_ATA_TRANSLATION_RECHS) { |
126 | - qemu_opt_set(hda_opts, "trans", "rechs", | ||
127 | - &error_abort); | ||
128 | - } else if (translation == BIOS_ATA_TRANSLATION_LBA) { | ||
129 | - qemu_opt_set(hda_opts, "trans", "lba", | ||
130 | - &error_abort); | ||
131 | - } else if (translation == BIOS_ATA_TRANSLATION_NONE) { | ||
132 | - qemu_opt_set(hda_opts, "trans", "none", | ||
133 | - &error_abort); | ||
134 | - } | ||
135 | - } | ||
136 | - } | ||
137 | - error_report("'-hdachs' is deprecated, please use '-device" | ||
138 | - " ide-hd,cyls=c,heads=h,secs=s,...' instead"); | ||
139 | - break; | ||
140 | case QEMU_OPTION_numa: | ||
141 | opts = qemu_opts_parse_noisily(qemu_find_opts("numa"), | ||
142 | optarg, true); | ||
143 | diff --git a/qemu-doc.texi b/qemu-doc.texi | ||
144 | index XXXXXXX..XXXXXXX 100644 | ||
145 | --- a/qemu-doc.texi | ||
146 | +++ b/qemu-doc.texi | ||
147 | @@ -XXX,XX +XXX,XX @@ The ``--net dump'' argument is now replaced with the | ||
148 | ``-object filter-dump'' argument which works in combination | ||
149 | with the modern ``-netdev`` backends instead. | ||
150 | |||
151 | -@subsection -hdachs (since 2.10.0) | ||
152 | - | ||
153 | -The ``-hdachs'' argument is now a synonym for setting | ||
154 | -the ``cyls'', ``heads'', ``secs'', and ``trans'' properties | ||
155 | -on the ``ide-hd'' device using the ``-device'' argument. | ||
156 | -The new syntax allows different settings to be provided | ||
157 | -per disk. | ||
158 | - | ||
159 | @subsection -usbdevice (since 2.10.0) | ||
160 | |||
161 | The ``-usbdevice DEV'' argument is now a synonym for setting | ||
162 | diff --git a/qemu-options.hx b/qemu-options.hx | ||
163 | index XXXXXXX..XXXXXXX 100644 | ||
164 | --- a/qemu-options.hx | ||
165 | +++ b/qemu-options.hx | ||
166 | @@ -XXX,XX +XXX,XX @@ of available connectors of a given interface type. | ||
167 | @item media=@var{media} | ||
168 | This option defines the type of the media: disk or cdrom. | ||
169 | @item cyls=@var{c},heads=@var{h},secs=@var{s}[,trans=@var{t}] | ||
170 | -These options have the same definition as they have in @option{-hdachs}. | ||
171 | -These parameters are deprecated, use the corresponding parameters | ||
172 | +Force disk physical geometry and the optional BIOS translation (trans=none or | ||
173 | +lba). These parameters are deprecated, use the corresponding parameters | ||
174 | of @code{-device} instead. | ||
175 | @item snapshot=@var{snapshot} | ||
176 | @var{snapshot} is "on" or "off" and controls snapshot mode for the given drive | ||
177 | @@ -XXX,XX +XXX,XX @@ the raw disk image you use is not written back. You can however force | ||
178 | the write back by pressing @key{C-a s} (@pxref{disk_images}). | ||
179 | ETEXI | ||
180 | |||
181 | -DEF("hdachs", HAS_ARG, QEMU_OPTION_hdachs, \ | ||
182 | - "-hdachs c,h,s[,t]\n" \ | ||
183 | - " force hard disk 0 physical geometry and the optional BIOS\n" \ | ||
184 | - " translation (t=none or lba) (usually QEMU can guess them)\n", | ||
185 | - QEMU_ARCH_ALL) | ||
186 | -STEXI | ||
187 | -@item -hdachs @var{c},@var{h},@var{s},[,@var{t}] | ||
188 | -@findex -hdachs | ||
189 | -Force hard disk 0 physical geometry (1 <= @var{c} <= 16383, 1 <= | ||
190 | -@var{h} <= 16, 1 <= @var{s} <= 63) and optionally force the BIOS | ||
191 | -translation mode (@var{t}=none, lba or auto). Usually QEMU can guess | ||
192 | -all those parameters. This option is deprecated, please use | ||
193 | -@code{-device ide-hd,cyls=c,heads=h,secs=s,...} instead. | ||
194 | -ETEXI | ||
195 | - | ||
196 | DEF("fsdev", HAS_ARG, QEMU_OPTION_fsdev, | ||
197 | "-fsdev fsdriver,id=id[,path=path,][security_model={mapped-xattr|mapped-file|passthrough|none}]\n" | ||
198 | " [,writeout=immediate][,readonly][,socket=socket|sock_fd=sock_fd][,fmode=fmode][,dmode=dmode]\n" | ||
138 | -- | 199 | -- |
139 | 2.35.1 | 200 | 2.13.6 |
201 | |||
202 | diff view generated by jsdifflib |
1 | From: Thomas Huth <thuth@redhat.com> | 1 | From: Thomas Huth <thuth@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Instead of failing the iotests if GNU sed is not available (or skipping | 3 | Looks like we forgot to announce the deprecation of these options in |
4 | them completely in the check-block.sh script), it would be better to | 4 | the corresponding chapter of the qemu-doc text, so let's do that now. |
5 | simply skip the bash-based tests that rely on GNU sed, so that the other | ||
6 | tests could still be run. Thus we now explicitely use "gsed" (either as | ||
7 | direct program or as a wrapper around "sed" if it's the GNU version) | ||
8 | in the spots that rely on the GNU sed behavior. Statements that use the | ||
9 | "-r" parameter of sed have been switched to use "-E" instead, since this | ||
10 | switch is supported by all sed versions on our supported build hosts | ||
11 | (most also support "-r", but macOS' sed only supports "-E"). With all | ||
12 | these changes in place, we then can also remove the sed checks from the | ||
13 | check-block.sh script, so that "make check-block" can now be run on | ||
14 | systems without GNU sed, too. | ||
15 | 5 | ||
16 | Signed-off-by: Thomas Huth <thuth@redhat.com> | 6 | Signed-off-by: Thomas Huth <thuth@redhat.com> |
17 | Message-Id: <20220216125454.465041-1-thuth@redhat.com> | 7 | Reviewed-by: John Snow <jsnow@redhat.com> |
18 | Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org> | 8 | Reviewed-by: Markus Armbruster <armbru@redhat.com> |
19 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
20 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 9 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
21 | --- | 10 | --- |
22 | tests/check-block.sh | 12 ------ | 11 | qemu-doc.texi | 15 +++++++++++++++ |
23 | tests/qemu-iotests/271 | 2 +- | 12 | 1 file changed, 15 insertions(+) |
24 | tests/qemu-iotests/common.filter | 65 ++++++++++++++++---------------- | ||
25 | tests/qemu-iotests/common.rc | 45 +++++++++++----------- | ||
26 | 4 files changed, 57 insertions(+), 67 deletions(-) | ||
27 | 13 | ||
28 | diff --git a/tests/check-block.sh b/tests/check-block.sh | 14 | diff --git a/qemu-doc.texi b/qemu-doc.texi |
29 | index XXXXXXX..XXXXXXX 100755 | ||
30 | --- a/tests/check-block.sh | ||
31 | +++ b/tests/check-block.sh | ||
32 | @@ -XXX,XX +XXX,XX @@ if LANG=C bash --version | grep -q 'GNU bash, version [123]' ; then | ||
33 | skip "bash version too old ==> Not running the qemu-iotests." | ||
34 | fi | ||
35 | |||
36 | -if ! (sed --version | grep 'GNU sed') > /dev/null 2>&1 ; then | ||
37 | - if ! command -v gsed >/dev/null 2>&1; then | ||
38 | - skip "GNU sed not available ==> Not running the qemu-iotests." | ||
39 | - fi | ||
40 | -else | ||
41 | - # Double-check that we're not using BusyBox' sed which says | ||
42 | - # that "This is not GNU sed version 4.0" ... | ||
43 | - if sed --version | grep -q 'not GNU sed' ; then | ||
44 | - skip "BusyBox sed not supported ==> Not running the qemu-iotests." | ||
45 | - fi | ||
46 | -fi | ||
47 | - | ||
48 | cd tests/qemu-iotests | ||
49 | |||
50 | # QEMU_CHECK_BLOCK_AUTO is used to disable some unstable sub-tests | ||
51 | diff --git a/tests/qemu-iotests/271 b/tests/qemu-iotests/271 | ||
52 | index XXXXXXX..XXXXXXX 100755 | ||
53 | --- a/tests/qemu-iotests/271 | ||
54 | +++ b/tests/qemu-iotests/271 | ||
55 | @@ -XXX,XX +XXX,XX @@ _make_test_img -o extended_l2=on 1M | ||
56 | # Second and third writes in _concurrent_io() are independent and may finish in | ||
57 | # different order. So, filter offset out to match both possible variants. | ||
58 | _concurrent_io | $QEMU_IO | _filter_qemu_io | \ | ||
59 | - $SED -e 's/\(20480\|40960\)/OFFSET/' | ||
60 | + sed -e 's/\(20480\|40960\)/OFFSET/' | ||
61 | _concurrent_verify | $QEMU_IO | _filter_qemu_io | ||
62 | |||
63 | # success, all done | ||
64 | diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter | ||
65 | index XXXXXXX..XXXXXXX 100644 | 15 | index XXXXXXX..XXXXXXX 100644 |
66 | --- a/tests/qemu-iotests/common.filter | 16 | --- a/qemu-doc.texi |
67 | +++ b/tests/qemu-iotests/common.filter | 17 | +++ b/qemu-doc.texi |
68 | @@ -XXX,XX +XXX,XX @@ | 18 | @@ -XXX,XX +XXX,XX @@ longer be directly supported in QEMU. |
69 | 19 | The ``-drive if=scsi'' argument is replaced by the the | |
70 | _filter_date() | 20 | ``-device BUS-TYPE'' argument combined with ``-drive if=none''. |
71 | { | 21 | |
72 | - $SED -re 's/[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}/yyyy-mm-dd hh:mm:ss/' | 22 | +@subsection -drive cyls=...,heads=...,secs=...,trans=... (since 2.10.0) |
73 | + sed -Ee 's/[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}/yyyy-mm-dd hh:mm:ss/' | ||
74 | } | ||
75 | |||
76 | _filter_vmstate_size() | ||
77 | { | ||
78 | - $SED -r -e 's/[0-9. ]{5} [KMGT]iB/ SIZE/' \ | ||
79 | - -e 's/[0-9. ]{5} B/ SIZE/' | ||
80 | + sed -E -e 's/[0-9. ]{5} [KMGT]iB/ SIZE/' \ | ||
81 | + -e 's/[0-9. ]{5} B/ SIZE/' | ||
82 | } | ||
83 | |||
84 | _filter_generated_node_ids() | ||
85 | { | ||
86 | - $SED -re 's/\#block[0-9]{3,}/NODE_NAME/' | ||
87 | + sed -Ee 's/\#block[0-9]{3,}/NODE_NAME/' | ||
88 | } | ||
89 | |||
90 | _filter_qom_path() | ||
91 | { | ||
92 | - $SED -e '/Attached to:/s/\device[[0-9]\+\]/device[N]/g' | ||
93 | + gsed -e '/Attached to:/s/\device[[0-9]\+\]/device[N]/g' | ||
94 | } | ||
95 | |||
96 | # replace occurrences of the actual TEST_DIR value with TEST_DIR | ||
97 | _filter_testdir() | ||
98 | { | ||
99 | - $SED -e "s#$TEST_DIR/#TEST_DIR/#g" \ | ||
100 | - -e "s#$SOCK_DIR/#SOCK_DIR/#g" \ | ||
101 | - -e "s#SOCK_DIR/fuse-#TEST_DIR/#g" | ||
102 | + sed -e "s#$TEST_DIR/#TEST_DIR/#g" \ | ||
103 | + -e "s#$SOCK_DIR/#SOCK_DIR/#g" \ | ||
104 | + -e "s#SOCK_DIR/fuse-#TEST_DIR/#g" | ||
105 | } | ||
106 | |||
107 | # replace occurrences of the actual IMGFMT value with IMGFMT | ||
108 | _filter_imgfmt() | ||
109 | { | ||
110 | - $SED -e "s#$IMGFMT#IMGFMT#g" | ||
111 | + sed -e "s#$IMGFMT#IMGFMT#g" | ||
112 | } | ||
113 | |||
114 | # Replace error message when the format is not supported and delete | ||
115 | # the output lines after the first one | ||
116 | _filter_qemu_img_check() | ||
117 | { | ||
118 | - $SED -e '/allocated.*fragmented.*compressed clusters/d' \ | ||
119 | + gsed -e '/allocated.*fragmented.*compressed clusters/d' \ | ||
120 | -e 's/qemu-img: This image format does not support checks/No errors were found on the image./' \ | ||
121 | -e '/Image end offset: [0-9]\+/d' | ||
122 | } | ||
123 | @@ -XXX,XX +XXX,XX @@ _filter_qemu_img_check() | ||
124 | # Removes \r from messages | ||
125 | _filter_win32() | ||
126 | { | ||
127 | - $SED -e 's/\r//g' | ||
128 | + gsed -e 's/\r//g' | ||
129 | } | ||
130 | |||
131 | # sanitize qemu-io output | ||
132 | _filter_qemu_io() | ||
133 | { | ||
134 | - _filter_win32 | $SED -e "s/[0-9]* ops\; [0-9/:. sec]* ([0-9/.inf]* [EPTGMKiBbytes]*\/sec and [0-9/.inf]* ops\/sec)/X ops\; XX:XX:XX.X (XXX YYY\/sec and XXX ops\/sec)/" \ | ||
135 | + _filter_win32 | \ | ||
136 | + gsed -e "s/[0-9]* ops\; [0-9/:. sec]* ([0-9/.inf]* [EPTGMKiBbytes]*\/sec and [0-9/.inf]* ops\/sec)/X ops\; XX:XX:XX.X (XXX YYY\/sec and XXX ops\/sec)/" \ | ||
137 | -e "s/: line [0-9][0-9]*: *[0-9][0-9]*\( Aborted\| Killed\)/:\1/" \ | ||
138 | -e "s/qemu-io> //g" | ||
139 | } | ||
140 | @@ -XXX,XX +XXX,XX @@ _filter_qemu_io() | ||
141 | # replace occurrences of QEMU_PROG with "qemu" | ||
142 | _filter_qemu() | ||
143 | { | ||
144 | - $SED -e "s#\\(^\\|(qemu) \\)$(basename $QEMU_PROG):#\1QEMU_PROG:#" \ | ||
145 | + gsed -e "s#\\(^\\|(qemu) \\)$(basename $QEMU_PROG):#\1QEMU_PROG:#" \ | ||
146 | -e 's#^QEMU [0-9]\+\.[0-9]\+\.[0-9]\+ monitor#QEMU X.Y.Z monitor#' \ | ||
147 | -e $'s#\r##' # QEMU monitor uses \r\n line endings | ||
148 | } | ||
149 | @@ -XXX,XX +XXX,XX @@ _filter_qemu() | ||
150 | _filter_qmp() | ||
151 | { | ||
152 | _filter_win32 | \ | ||
153 | - $SED -e 's#\("\(micro\)\?seconds": \)[0-9]\+#\1 TIMESTAMP#g' \ | ||
154 | + gsed -e 's#\("\(micro\)\?seconds": \)[0-9]\+#\1 TIMESTAMP#g' \ | ||
155 | -e 's#^{"QMP":.*}$#QMP_VERSION#' \ | ||
156 | -e '/^ "QMP": {\s*$/, /^ }\s*$/ c\' \ | ||
157 | -e ' QMP_VERSION' | ||
158 | @@ -XXX,XX +XXX,XX @@ _filter_qmp() | ||
159 | # readline makes HMP command strings so long that git complains | ||
160 | _filter_hmp() | ||
161 | { | ||
162 | - $SED -e $'s/^\\((qemu) \\)\\?.*\e\\[D/\\1/g' \ | ||
163 | + gsed -e $'s/^\\((qemu) \\)\\?.*\e\\[D/\\1/g' \ | ||
164 | -e $'s/\e\\[K//g' | ||
165 | } | ||
166 | |||
167 | # replace block job offset | ||
168 | _filter_block_job_offset() | ||
169 | { | ||
170 | - $SED -e 's/, "offset": [0-9]\+,/, "offset": OFFSET,/' | ||
171 | + sed -e 's/, "offset": [0-9]\+,/, "offset": OFFSET,/' | ||
172 | } | ||
173 | |||
174 | # replace block job len | ||
175 | _filter_block_job_len() | ||
176 | { | ||
177 | - $SED -e 's/, "len": [0-9]\+,/, "len": LEN,/g' | ||
178 | + sed -e 's/, "len": [0-9]\+,/, "len": LEN,/g' | ||
179 | } | ||
180 | |||
181 | # replace actual image size (depends on the host filesystem) | ||
182 | _filter_actual_image_size() | ||
183 | { | ||
184 | - $SED -s 's/\("actual-size":\s*\)[0-9]\+/\1SIZE/g' | ||
185 | + gsed -s 's/\("actual-size":\s*\)[0-9]\+/\1SIZE/g' | ||
186 | } | ||
187 | |||
188 | # Filename filters for qemu-img create | ||
189 | _filter_img_create_filenames() | ||
190 | { | ||
191 | - $SED \ | ||
192 | + sed \ | ||
193 | -e "s#$REMOTE_TEST_DIR#TEST_DIR#g" \ | ||
194 | -e "s#$IMGPROTO:$TEST_DIR#TEST_DIR#g" \ | ||
195 | -e "s#$TEST_DIR#TEST_DIR#g" \ | ||
196 | @@ -XXX,XX +XXX,XX @@ _do_filter_img_create() | ||
197 | # precedes ", fmt=") and the options part ($options, which starts | ||
198 | # with "fmt=") | ||
199 | # (And just echo everything before the first "^Formatting") | ||
200 | - readarray formatting_line < <($SED -e 's/, fmt=/\n/') | ||
201 | + readarray formatting_line < <(gsed -e 's/, fmt=/\n/') | ||
202 | |||
203 | filename_part=${formatting_line[0]} | ||
204 | unset formatting_line[0] | ||
205 | @@ -XXX,XX +XXX,XX @@ _do_filter_img_create() | ||
206 | options=$( | ||
207 | echo "$options" \ | ||
208 | | tr '\n' '\0' \ | ||
209 | - | $SED -e 's/ \([a-z0-9_.-]*\)=/\n\1=/g' \ | ||
210 | + | gsed -e 's/ \([a-z0-9_.-]*\)=/\n\1=/g' \ | ||
211 | | grep -a -e '^fmt' -e '^size' -e '^backing' -e '^preallocation' \ | ||
212 | -e '^encryption' "${grep_data_file[@]}" \ | ||
213 | | _filter_img_create_filenames \ | ||
214 | - | $SED \ | ||
215 | + | sed \ | ||
216 | -e 's/^\(fmt\)/0-\1/' \ | ||
217 | -e 's/^\(size\)/1-\1/' \ | ||
218 | -e 's/^\(backing\)/2-\1/' \ | ||
219 | @@ -XXX,XX +XXX,XX @@ _do_filter_img_create() | ||
220 | -e 's/^\(encryption\)/4-\1/' \ | ||
221 | -e 's/^\(preallocation\)/8-\1/' \ | ||
222 | | LC_ALL=C sort \ | ||
223 | - | $SED -e 's/^[0-9]-//' \ | ||
224 | + | sed -e 's/^[0-9]-//' \ | ||
225 | | tr '\n\0' ' \n' \ | ||
226 | - | $SED -e 's/^ *$//' -e 's/ *$//' | ||
227 | + | sed -e 's/^ *$//' -e 's/ *$//' | ||
228 | ) | ||
229 | |||
230 | if [ -n "$options" ]; then | ||
231 | @@ -XXX,XX +XXX,XX @@ _filter_img_create() | ||
232 | |||
233 | _filter_img_create_size() | ||
234 | { | ||
235 | - $SED -e "s# size=[0-9]\\+# size=SIZE#g" | ||
236 | + gsed -e "s# size=[0-9]\\+# size=SIZE#g" | ||
237 | } | ||
238 | |||
239 | _filter_img_info() | ||
240 | @@ -XXX,XX +XXX,XX @@ _filter_img_info() | ||
241 | |||
242 | discard=0 | ||
243 | regex_json_spec_start='^ *"format-specific": \{' | ||
244 | - $SED -e "s#$REMOTE_TEST_DIR#TEST_DIR#g" \ | ||
245 | + gsed -e "s#$REMOTE_TEST_DIR#TEST_DIR#g" \ | ||
246 | -e "s#$IMGPROTO:$TEST_DIR#TEST_DIR#g" \ | ||
247 | -e "s#$TEST_DIR#TEST_DIR#g" \ | ||
248 | -e "s#$SOCK_DIR#SOCK_DIR#g" \ | ||
249 | @@ -XXX,XX +XXX,XX @@ _filter_qemu_img_map() | ||
250 | data_file_filter=(-e "s#$data_file_pattern#\\1#") | ||
251 | fi | ||
252 | |||
253 | - $SED -e 's/\([0-9a-fx]* *[0-9a-fx]* *\)[0-9a-fx]* */\1/g' \ | ||
254 | + sed -e 's/\([0-9a-fx]* *[0-9a-fx]* *\)[0-9a-fx]* */\1/g' \ | ||
255 | -e 's/"offset": [0-9]\+/"offset": OFFSET/g' \ | ||
256 | -e 's/Mapped to *//' \ | ||
257 | "${data_file_filter[@]}" \ | ||
258 | @@ -XXX,XX +XXX,XX @@ _filter_nbd() | ||
259 | # receive callbacks sometimes, making them unreliable. | ||
260 | # | ||
261 | # Filter out the TCP port number since this changes between runs. | ||
262 | - $SED -e '/nbd\/.*\.c:/d' \ | ||
263 | + sed -e '/nbd\/.*\.c:/d' \ | ||
264 | -e 's#127\.0\.0\.1:[0-9]*#127.0.0.1:PORT#g' \ | ||
265 | -e "s#?socket=$SOCK_DIR#?socket=SOCK_DIR#g" \ | ||
266 | -e 's#\(foo\|PORT/\?\|.sock\): Failed to .*$#\1#' | ||
267 | @@ -XXX,XX +XXX,XX @@ sys.stdout.write(result)' | ||
268 | |||
269 | _filter_authz_check_tls() | ||
270 | { | ||
271 | - $SED -e 's/TLS x509 authz check for .* is denied/TLS x509 authz check for DISTINGUISHED-NAME is denied/' | ||
272 | + sed -e 's/TLS x509 authz check for .* is denied/TLS x509 authz check for DISTINGUISHED-NAME is denied/' | ||
273 | } | ||
274 | |||
275 | _filter_qcow2_compression_type_bit() | ||
276 | { | ||
277 | - $SED -e 's/\(incompatible_features\s\+\)\[3\(, \)\?/\1[/' \ | ||
278 | - -e 's/\(incompatible_features.*\), 3\]/\1]/' \ | ||
279 | - -e 's/\(incompatible_features.*\), 3\(,.*\)/\1\2/' | ||
280 | + gsed -e 's/\(incompatible_features\s\+\)\[3\(, \)\?/\1[/' \ | ||
281 | + -e 's/\(incompatible_features.*\), 3\]/\1]/' \ | ||
282 | + -e 's/\(incompatible_features.*\), 3\(,.*\)/\1\2/' | ||
283 | } | ||
284 | |||
285 | # make sure this script returns success | ||
286 | diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc | ||
287 | index XXXXXXX..XXXXXXX 100644 | ||
288 | --- a/tests/qemu-iotests/common.rc | ||
289 | +++ b/tests/qemu-iotests/common.rc | ||
290 | @@ -XXX,XX +XXX,XX @@ | ||
291 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
292 | # | ||
293 | |||
294 | -SED= | ||
295 | -for sed in sed gsed; do | ||
296 | - ($sed --version | grep 'GNU sed') > /dev/null 2>&1 | ||
297 | - if [ "$?" -eq 0 ]; then | ||
298 | - SED=$sed | ||
299 | - break | ||
300 | - fi | ||
301 | -done | ||
302 | -if [ -z "$SED" ]; then | ||
303 | - echo "$0: GNU sed not found" | ||
304 | - exit 1 | ||
305 | +# bail out, setting up .notrun file | ||
306 | +_notrun() | ||
307 | +{ | ||
308 | + echo "$*" >"$OUTPUT_DIR/$seq.notrun" | ||
309 | + echo "$seq not run: $*" | ||
310 | + status=0 | ||
311 | + exit | ||
312 | +} | ||
313 | + | 23 | + |
314 | +if ! command -v gsed >/dev/null 2>&1; then | 24 | +The drive geometry arguments are replaced by the the geometry arguments |
315 | + if sed --version 2>&1 | grep -v 'not GNU sed' | grep 'GNU sed' > /dev/null; | 25 | +that can be specified with the ``-device'' parameter. |
316 | + then | 26 | + |
317 | + gsed() | 27 | +@subsection -drive serial=... (since 2.10.0) |
318 | + { | 28 | + |
319 | + sed "$@" | 29 | +The drive serial argument is replaced by the the serial argument |
320 | + } | 30 | +that can be specified with the ``-device'' parameter. |
321 | + else | 31 | + |
322 | + gsed() | 32 | +@subsection -drive addr=... (since 2.10.0) |
323 | + { | 33 | + |
324 | + _notrun "GNU sed not available" | 34 | +The drive addr argument is replaced by the the addr argument |
325 | + } | 35 | +that can be specified with the ``-device'' parameter. |
326 | + fi | 36 | + |
327 | fi | 37 | @subsection -net dump (since 2.10.0) |
328 | 38 | ||
329 | dd() | 39 | The ``--net dump'' argument is now replaced with the |
330 | @@ -XXX,XX +XXX,XX @@ _img_info() | ||
331 | done | ||
332 | } | ||
333 | |||
334 | -# bail out, setting up .notrun file | ||
335 | -# | ||
336 | -_notrun() | ||
337 | -{ | ||
338 | - echo "$*" >"$OUTPUT_DIR/$seq.notrun" | ||
339 | - echo "$seq not run: $*" | ||
340 | - status=0 | ||
341 | - exit | ||
342 | -} | ||
343 | - | ||
344 | # bail out, setting up .casenotrun file | ||
345 | # The function _casenotrun() is used as a notifier. It is the | ||
346 | # caller's responsibility to make skipped a particular test. | ||
347 | @@ -XXX,XX +XXX,XX @@ _require_working_luks() | ||
348 | IMGFMT='luks' _rm_test_img "$file" | ||
349 | |||
350 | if [ $status != 0 ]; then | ||
351 | - reason=$(echo "$output" | grep "$file:" | $SED -e "s#.*$file: *##") | ||
352 | + reason=$(echo "$output" | grep "$file:" | sed -e "s#.*$file: *##") | ||
353 | if [ -z "$reason" ]; then | ||
354 | reason="Failed to create a LUKS image" | ||
355 | fi | ||
356 | -- | 40 | -- |
357 | 2.35.1 | 41 | 2.13.6 |
358 | 42 | ||
359 | 43 | diff view generated by jsdifflib |
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | 1 | From: Fam Zheng <famz@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Mark all I/O functions with IO_CODE, and all "I/O OR GS" with | 3 | Signed-off-by: Fam Zheng <famz@redhat.com> |
4 | IO_OR_GS_CODE. | ||
5 | |||
6 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
7 | Message-Id: <20220303151616.325444-6-eesposit@redhat.com> | ||
8 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 4 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
9 | --- | 5 | --- |
10 | include/block/block-io.h | 1 + | 6 | include/block/block_int.h | 1 - |
11 | block.c | 37 +++++++++++++++++++++++++++++++++- | 7 | block/io.c | 18 ------------------ |
12 | block/dirty-bitmap.c | 1 + | 8 | 2 files changed, 19 deletions(-) |
13 | block/io.c | 43 ++++++++++++++++++++++++++++++++++++++-- | ||
14 | 4 files changed, 79 insertions(+), 3 deletions(-) | ||
15 | 9 | ||
16 | diff --git a/include/block/block-io.h b/include/block/block-io.h | 10 | diff --git a/include/block/block_int.h b/include/block/block_int.h |
17 | index XXXXXXX..XXXXXXX 100644 | 11 | index XXXXXXX..XXXXXXX 100644 |
18 | --- a/include/block/block-io.h | 12 | --- a/include/block/block_int.h |
19 | +++ b/include/block/block-io.h | 13 | +++ b/include/block/block_int.h |
20 | @@ -XXX,XX +XXX,XX @@ void bdrv_drained_end_no_poll(BlockDriverState *bs, int *drained_end_counter); | 14 | @@ -XXX,XX +XXX,XX @@ bool blk_dev_is_tray_open(BlockBackend *blk); |
21 | 15 | bool blk_dev_is_medium_locked(BlockBackend *blk); | |
22 | #define BDRV_POLL_WHILE(bs, cond) ({ \ | 16 | |
23 | BlockDriverState *bs_ = (bs); \ | 17 | void bdrv_set_dirty(BlockDriverState *bs, int64_t offset, int64_t bytes); |
24 | + IO_OR_GS_CODE(); \ | 18 | -bool bdrv_requests_pending(BlockDriverState *bs); |
25 | AIO_WAIT_WHILE(bdrv_get_aio_context(bs_), \ | 19 | |
26 | cond); }) | 20 | void bdrv_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap **out); |
27 | 21 | void bdrv_undo_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap *in); | |
28 | diff --git a/block.c b/block.c | ||
29 | index XXXXXXX..XXXXXXX 100644 | ||
30 | --- a/block.c | ||
31 | +++ b/block.c | ||
32 | @@ -XXX,XX +XXX,XX @@ size_t bdrv_opt_mem_align(BlockDriverState *bs) | ||
33 | /* page size or 4k (hdd sector size) should be on the safe side */ | ||
34 | return MAX(4096, qemu_real_host_page_size); | ||
35 | } | ||
36 | + IO_CODE(); | ||
37 | |||
38 | return bs->bl.opt_mem_alignment; | ||
39 | } | ||
40 | @@ -XXX,XX +XXX,XX @@ size_t bdrv_min_mem_align(BlockDriverState *bs) | ||
41 | /* page size or 4k (hdd sector size) should be on the safe side */ | ||
42 | return MAX(4096, qemu_real_host_page_size); | ||
43 | } | ||
44 | + IO_CODE(); | ||
45 | |||
46 | return bs->bl.min_mem_alignment; | ||
47 | } | ||
48 | @@ -XXX,XX +XXX,XX @@ void bdrv_parse_filename_strip_prefix(const char *filename, const char *prefix, | ||
49 | * image is inactivated. */ | ||
50 | bool bdrv_is_read_only(BlockDriverState *bs) | ||
51 | { | ||
52 | + IO_CODE(); | ||
53 | return !(bs->open_flags & BDRV_O_RDWR); | ||
54 | } | ||
55 | |||
56 | int bdrv_can_set_read_only(BlockDriverState *bs, bool read_only, | ||
57 | bool ignore_allow_rdw, Error **errp) | ||
58 | { | ||
59 | + IO_CODE(); | ||
60 | + | ||
61 | /* Do not set read_only if copy_on_read is enabled */ | ||
62 | if (bs->copy_on_read && read_only) { | ||
63 | error_setg(errp, "Can't set node '%s' to r/o with copy-on-read enabled", | ||
64 | @@ -XXX,XX +XXX,XX @@ int bdrv_apply_auto_read_only(BlockDriverState *bs, const char *errmsg, | ||
65 | Error **errp) | ||
66 | { | ||
67 | int ret = 0; | ||
68 | + IO_CODE(); | ||
69 | |||
70 | if (!(bs->open_flags & BDRV_O_RDWR)) { | ||
71 | return 0; | ||
72 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_delete_file(BlockDriverState *bs, Error **errp) | ||
73 | Error *local_err = NULL; | ||
74 | int ret; | ||
75 | |||
76 | + IO_CODE(); | ||
77 | assert(bs != NULL); | ||
78 | |||
79 | if (!bs->drv) { | ||
80 | @@ -XXX,XX +XXX,XX @@ void coroutine_fn bdrv_co_delete_file_noerr(BlockDriverState *bs) | ||
81 | { | ||
82 | Error *local_err = NULL; | ||
83 | int ret; | ||
84 | + IO_CODE(); | ||
85 | |||
86 | if (!bs) { | ||
87 | return; | ||
88 | @@ -XXX,XX +XXX,XX @@ static int bdrv_child_cb_update_filename(BdrvChild *c, BlockDriverState *base, | ||
89 | AioContext *child_of_bds_get_parent_aio_context(BdrvChild *c) | ||
90 | { | ||
91 | BlockDriverState *bs = c->opaque; | ||
92 | + IO_CODE(); | ||
93 | |||
94 | return bdrv_get_aio_context(bs); | ||
95 | } | ||
96 | @@ -XXX,XX +XXX,XX @@ const BdrvChildClass child_of_bds = { | ||
97 | |||
98 | AioContext *bdrv_child_get_parent_aio_context(BdrvChild *c) | ||
99 | { | ||
100 | + IO_CODE(); | ||
101 | return c->klass->get_parent_aio_context(c); | ||
102 | } | ||
103 | |||
104 | @@ -XXX,XX +XXX,XX @@ static bool bdrv_is_writable_after_reopen(BlockDriverState *bs, | ||
105 | */ | ||
106 | bool bdrv_is_writable(BlockDriverState *bs) | ||
107 | { | ||
108 | + IO_CODE(); | ||
109 | return bdrv_is_writable_after_reopen(bs, NULL); | ||
110 | } | ||
111 | |||
112 | @@ -XXX,XX +XXX,XX @@ static int64_t bdrv_sum_allocated_file_size(BlockDriverState *bs) | ||
113 | int64_t bdrv_get_allocated_file_size(BlockDriverState *bs) | ||
114 | { | ||
115 | BlockDriver *drv = bs->drv; | ||
116 | + IO_CODE(); | ||
117 | + | ||
118 | if (!drv) { | ||
119 | return -ENOMEDIUM; | ||
120 | } | ||
121 | @@ -XXX,XX +XXX,XX @@ int64_t bdrv_get_allocated_file_size(BlockDriverState *bs) | ||
122 | BlockMeasureInfo *bdrv_measure(BlockDriver *drv, QemuOpts *opts, | ||
123 | BlockDriverState *in_bs, Error **errp) | ||
124 | { | ||
125 | + IO_CODE(); | ||
126 | if (!drv->bdrv_measure) { | ||
127 | error_setg(errp, "Block driver '%s' does not support size measurement", | ||
128 | drv->format_name); | ||
129 | @@ -XXX,XX +XXX,XX @@ BlockMeasureInfo *bdrv_measure(BlockDriver *drv, QemuOpts *opts, | ||
130 | int64_t bdrv_nb_sectors(BlockDriverState *bs) | ||
131 | { | ||
132 | BlockDriver *drv = bs->drv; | ||
133 | + IO_CODE(); | ||
134 | |||
135 | if (!drv) | ||
136 | return -ENOMEDIUM; | ||
137 | @@ -XXX,XX +XXX,XX @@ int64_t bdrv_nb_sectors(BlockDriverState *bs) | ||
138 | int64_t bdrv_getlength(BlockDriverState *bs) | ||
139 | { | ||
140 | int64_t ret = bdrv_nb_sectors(bs); | ||
141 | + IO_CODE(); | ||
142 | |||
143 | if (ret < 0) { | ||
144 | return ret; | ||
145 | @@ -XXX,XX +XXX,XX @@ int64_t bdrv_getlength(BlockDriverState *bs) | ||
146 | void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr) | ||
147 | { | ||
148 | int64_t nb_sectors = bdrv_nb_sectors(bs); | ||
149 | + IO_CODE(); | ||
150 | |||
151 | *nb_sectors_ptr = nb_sectors < 0 ? 0 : nb_sectors; | ||
152 | } | ||
153 | |||
154 | bool bdrv_is_sg(BlockDriverState *bs) | ||
155 | { | ||
156 | + IO_CODE(); | ||
157 | return bs->sg; | ||
158 | } | ||
159 | |||
160 | @@ -XXX,XX +XXX,XX @@ bool bdrv_is_sg(BlockDriverState *bs) | ||
161 | bool bdrv_supports_compressed_writes(BlockDriverState *bs) | ||
162 | { | ||
163 | BlockDriverState *filtered; | ||
164 | + IO_CODE(); | ||
165 | |||
166 | if (!bs->drv || !block_driver_can_compress(bs->drv)) { | ||
167 | return false; | ||
168 | @@ -XXX,XX +XXX,XX @@ bool bdrv_supports_compressed_writes(BlockDriverState *bs) | ||
169 | |||
170 | const char *bdrv_get_format_name(BlockDriverState *bs) | ||
171 | { | ||
172 | + IO_CODE(); | ||
173 | return bs->drv ? bs->drv->format_name : NULL; | ||
174 | } | ||
175 | |||
176 | @@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_next_all_states(BlockDriverState *bs) | ||
177 | |||
178 | const char *bdrv_get_node_name(const BlockDriverState *bs) | ||
179 | { | ||
180 | + IO_CODE(); | ||
181 | return bs->node_name; | ||
182 | } | ||
183 | |||
184 | @@ -XXX,XX +XXX,XX @@ const char *bdrv_get_parent_name(const BlockDriverState *bs) | ||
185 | /* TODO check what callers really want: bs->node_name or blk_name() */ | ||
186 | const char *bdrv_get_device_name(const BlockDriverState *bs) | ||
187 | { | ||
188 | + IO_CODE(); | ||
189 | return bdrv_get_parent_name(bs) ?: ""; | ||
190 | } | ||
191 | |||
192 | @@ -XXX,XX +XXX,XX @@ const char *bdrv_get_device_name(const BlockDriverState *bs) | ||
193 | * absent, then this returns an empty (non-null) string. */ | ||
194 | const char *bdrv_get_device_or_node_name(const BlockDriverState *bs) | ||
195 | { | ||
196 | + IO_CODE(); | ||
197 | return bdrv_get_parent_name(bs) ?: bs->node_name; | ||
198 | } | ||
199 | |||
200 | @@ -XXX,XX +XXX,XX @@ int bdrv_has_zero_init(BlockDriverState *bs) | ||
201 | |||
202 | bool bdrv_can_write_zeroes_with_unmap(BlockDriverState *bs) | ||
203 | { | ||
204 | + IO_CODE(); | ||
205 | if (!(bs->open_flags & BDRV_O_UNMAP)) { | ||
206 | return false; | ||
207 | } | ||
208 | @@ -XXX,XX +XXX,XX @@ bool bdrv_can_write_zeroes_with_unmap(BlockDriverState *bs) | ||
209 | void bdrv_get_backing_filename(BlockDriverState *bs, | ||
210 | char *filename, int filename_size) | ||
211 | { | ||
212 | + IO_CODE(); | ||
213 | pstrcpy(filename, filename_size, bs->backing_file); | ||
214 | } | ||
215 | |||
216 | @@ -XXX,XX +XXX,XX @@ int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) | ||
217 | { | ||
218 | int ret; | ||
219 | BlockDriver *drv = bs->drv; | ||
220 | + IO_CODE(); | ||
221 | /* if bs->drv == NULL, bs is closed, so there's nothing to do here */ | ||
222 | if (!drv) { | ||
223 | return -ENOMEDIUM; | ||
224 | @@ -XXX,XX +XXX,XX @@ ImageInfoSpecific *bdrv_get_specific_info(BlockDriverState *bs, | ||
225 | Error **errp) | ||
226 | { | ||
227 | BlockDriver *drv = bs->drv; | ||
228 | + IO_CODE(); | ||
229 | if (drv && drv->bdrv_get_specific_info) { | ||
230 | return drv->bdrv_get_specific_info(bs, errp); | ||
231 | } | ||
232 | @@ -XXX,XX +XXX,XX @@ ImageInfoSpecific *bdrv_get_specific_info(BlockDriverState *bs, | ||
233 | BlockStatsSpecific *bdrv_get_specific_stats(BlockDriverState *bs) | ||
234 | { | ||
235 | BlockDriver *drv = bs->drv; | ||
236 | + IO_CODE(); | ||
237 | if (!drv || !drv->bdrv_get_specific_stats) { | ||
238 | return NULL; | ||
239 | } | ||
240 | @@ -XXX,XX +XXX,XX @@ BlockStatsSpecific *bdrv_get_specific_stats(BlockDriverState *bs) | ||
241 | |||
242 | void bdrv_debug_event(BlockDriverState *bs, BlkdebugEvent event) | ||
243 | { | ||
244 | + IO_CODE(); | ||
245 | if (!bs || !bs->drv || !bs->drv->bdrv_debug_event) { | ||
246 | return; | ||
247 | } | ||
248 | @@ -XXX,XX +XXX,XX @@ bool bdrv_is_inserted(BlockDriverState *bs) | ||
249 | { | ||
250 | BlockDriver *drv = bs->drv; | ||
251 | BdrvChild *child; | ||
252 | + IO_CODE(); | ||
253 | |||
254 | if (!drv) { | ||
255 | return false; | ||
256 | @@ -XXX,XX +XXX,XX @@ bool bdrv_is_inserted(BlockDriverState *bs) | ||
257 | void bdrv_eject(BlockDriverState *bs, bool eject_flag) | ||
258 | { | ||
259 | BlockDriver *drv = bs->drv; | ||
260 | + IO_CODE(); | ||
261 | |||
262 | if (drv && drv->bdrv_eject) { | ||
263 | drv->bdrv_eject(bs, eject_flag); | ||
264 | @@ -XXX,XX +XXX,XX @@ void bdrv_eject(BlockDriverState *bs, bool eject_flag) | ||
265 | void bdrv_lock_medium(BlockDriverState *bs, bool locked) | ||
266 | { | ||
267 | BlockDriver *drv = bs->drv; | ||
268 | - | ||
269 | + IO_CODE(); | ||
270 | trace_bdrv_lock_medium(bs, locked); | ||
271 | |||
272 | if (drv && drv->bdrv_lock_medium) { | ||
273 | @@ -XXX,XX +XXX,XX @@ out: | ||
274 | |||
275 | AioContext *bdrv_get_aio_context(BlockDriverState *bs) | ||
276 | { | ||
277 | + IO_CODE(); | ||
278 | return bs ? bs->aio_context : qemu_get_aio_context(); | ||
279 | } | ||
280 | |||
281 | @@ -XXX,XX +XXX,XX @@ AioContext *coroutine_fn bdrv_co_enter(BlockDriverState *bs) | ||
282 | Coroutine *self = qemu_coroutine_self(); | ||
283 | AioContext *old_ctx = qemu_coroutine_get_aio_context(self); | ||
284 | AioContext *new_ctx; | ||
285 | + IO_CODE(); | ||
286 | |||
287 | /* | ||
288 | * Increase bs->in_flight to ensure that this operation is completed before | ||
289 | @@ -XXX,XX +XXX,XX @@ AioContext *coroutine_fn bdrv_co_enter(BlockDriverState *bs) | ||
290 | |||
291 | void coroutine_fn bdrv_co_leave(BlockDriverState *bs, AioContext *old_ctx) | ||
292 | { | ||
293 | + IO_CODE(); | ||
294 | aio_co_reschedule_self(old_ctx); | ||
295 | bdrv_dec_in_flight(bs); | ||
296 | } | ||
297 | @@ -XXX,XX +XXX,XX @@ void coroutine_fn bdrv_co_unlock(BlockDriverState *bs) | ||
298 | |||
299 | void bdrv_coroutine_enter(BlockDriverState *bs, Coroutine *co) | ||
300 | { | ||
301 | + IO_CODE(); | ||
302 | aio_co_enter(bdrv_get_aio_context(bs), co); | ||
303 | } | ||
304 | |||
305 | diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c | ||
306 | index XXXXXXX..XXXXXXX 100644 | ||
307 | --- a/block/dirty-bitmap.c | ||
308 | +++ b/block/dirty-bitmap.c | ||
309 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_co_can_store_new_dirty_bitmap_entry(void *opaque) | ||
310 | bool bdrv_can_store_new_dirty_bitmap(BlockDriverState *bs, const char *name, | ||
311 | uint32_t granularity, Error **errp) | ||
312 | { | ||
313 | + IO_CODE(); | ||
314 | if (qemu_in_coroutine()) { | ||
315 | return bdrv_co_can_store_new_dirty_bitmap(bs, name, granularity, errp); | ||
316 | } else { | ||
317 | diff --git a/block/io.c b/block/io.c | 22 | diff --git a/block/io.c b/block/io.c |
318 | index XXXXXXX..XXXXXXX 100644 | 23 | index XXXXXXX..XXXXXXX 100644 |
319 | --- a/block/io.c | 24 | --- a/block/io.c |
320 | +++ b/block/io.c | 25 | +++ b/block/io.c |
321 | @@ -XXX,XX +XXX,XX @@ static void bdrv_parent_drained_end_single_no_poll(BdrvChild *c, | 26 | @@ -XXX,XX +XXX,XX @@ void bdrv_disable_copy_on_read(BlockDriverState *bs) |
322 | void bdrv_parent_drained_end_single(BdrvChild *c) | ||
323 | { | ||
324 | int drained_end_counter = 0; | ||
325 | + IO_OR_GS_CODE(); | ||
326 | bdrv_parent_drained_end_single_no_poll(c, &drained_end_counter); | ||
327 | BDRV_POLL_WHILE(c->bs, qatomic_read(&drained_end_counter) > 0); | ||
328 | } | ||
329 | @@ -XXX,XX +XXX,XX @@ static bool bdrv_parent_drained_poll(BlockDriverState *bs, BdrvChild *ignore, | ||
330 | |||
331 | void bdrv_parent_drained_begin_single(BdrvChild *c, bool poll) | ||
332 | { | ||
333 | + IO_OR_GS_CODE(); | ||
334 | c->parent_quiesce_counter++; | ||
335 | if (c->klass->drained_begin) { | ||
336 | c->klass->drained_begin(c); | ||
337 | @@ -XXX,XX +XXX,XX @@ void bdrv_refresh_limits(BlockDriverState *bs, Transaction *tran, Error **errp) | ||
338 | */ | ||
339 | void bdrv_enable_copy_on_read(BlockDriverState *bs) | ||
340 | { | ||
341 | + IO_CODE(); | ||
342 | qatomic_inc(&bs->copy_on_read); | ||
343 | } | ||
344 | |||
345 | void bdrv_disable_copy_on_read(BlockDriverState *bs) | ||
346 | { | ||
347 | int old = qatomic_fetch_dec(&bs->copy_on_read); | ||
348 | + IO_CODE(); | ||
349 | assert(old >= 1); | 27 | assert(old >= 1); |
350 | } | 28 | } |
351 | 29 | ||
352 | @@ -XXX,XX +XXX,XX @@ bool bdrv_drain_poll(BlockDriverState *bs, bool recursive, | 30 | -/* Check if any requests are in-flight (including throttled requests) */ |
353 | BdrvChild *ignore_parent, bool ignore_bds_parents) | 31 | -bool bdrv_requests_pending(BlockDriverState *bs) |
354 | { | 32 | -{ |
355 | BdrvChild *child, *next; | 33 | - BdrvChild *child; |
356 | + IO_OR_GS_CODE(); | ||
357 | |||
358 | if (bdrv_parent_drained_poll(bs, ignore_parent, ignore_bds_parents)) { | ||
359 | return true; | ||
360 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs, | ||
361 | void bdrv_do_drained_begin_quiesce(BlockDriverState *bs, | ||
362 | BdrvChild *parent, bool ignore_bds_parents) | ||
363 | { | ||
364 | + IO_OR_GS_CODE(); | ||
365 | assert(!qemu_in_coroutine()); | ||
366 | |||
367 | /* Stop things in parent-to-child order */ | ||
368 | @@ -XXX,XX +XXX,XX @@ static void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive, | ||
369 | |||
370 | void bdrv_drained_begin(BlockDriverState *bs) | ||
371 | { | ||
372 | + IO_OR_GS_CODE(); | ||
373 | bdrv_do_drained_begin(bs, false, NULL, false, true); | ||
374 | } | ||
375 | |||
376 | void bdrv_subtree_drained_begin(BlockDriverState *bs) | ||
377 | { | ||
378 | + IO_OR_GS_CODE(); | ||
379 | bdrv_do_drained_begin(bs, true, NULL, false, true); | ||
380 | } | ||
381 | |||
382 | @@ -XXX,XX +XXX,XX @@ static void bdrv_do_drained_end(BlockDriverState *bs, bool recursive, | ||
383 | void bdrv_drained_end(BlockDriverState *bs) | ||
384 | { | ||
385 | int drained_end_counter = 0; | ||
386 | + IO_OR_GS_CODE(); | ||
387 | bdrv_do_drained_end(bs, false, NULL, false, &drained_end_counter); | ||
388 | BDRV_POLL_WHILE(bs, qatomic_read(&drained_end_counter) > 0); | ||
389 | } | ||
390 | |||
391 | void bdrv_drained_end_no_poll(BlockDriverState *bs, int *drained_end_counter) | ||
392 | { | ||
393 | + IO_CODE(); | ||
394 | bdrv_do_drained_end(bs, false, NULL, false, drained_end_counter); | ||
395 | } | ||
396 | |||
397 | void bdrv_subtree_drained_end(BlockDriverState *bs) | ||
398 | { | ||
399 | int drained_end_counter = 0; | ||
400 | + IO_OR_GS_CODE(); | ||
401 | bdrv_do_drained_end(bs, true, NULL, false, &drained_end_counter); | ||
402 | BDRV_POLL_WHILE(bs, qatomic_read(&drained_end_counter) > 0); | ||
403 | } | ||
404 | @@ -XXX,XX +XXX,XX @@ void bdrv_unapply_subtree_drain(BdrvChild *child, BlockDriverState *old_parent) | ||
405 | */ | ||
406 | void coroutine_fn bdrv_co_drain(BlockDriverState *bs) | ||
407 | { | ||
408 | + IO_OR_GS_CODE(); | ||
409 | assert(qemu_in_coroutine()); | ||
410 | bdrv_drained_begin(bs); | ||
411 | bdrv_drained_end(bs); | ||
412 | @@ -XXX,XX +XXX,XX @@ void coroutine_fn bdrv_co_drain(BlockDriverState *bs) | ||
413 | |||
414 | void bdrv_drain(BlockDriverState *bs) | ||
415 | { | ||
416 | + IO_OR_GS_CODE(); | ||
417 | bdrv_drained_begin(bs); | ||
418 | bdrv_drained_end(bs); | ||
419 | } | ||
420 | @@ -XXX,XX +XXX,XX @@ void bdrv_round_to_clusters(BlockDriverState *bs, | ||
421 | int64_t *cluster_bytes) | ||
422 | { | ||
423 | BlockDriverInfo bdi; | ||
424 | - | 34 | - |
425 | + IO_CODE(); | 35 | - if (atomic_read(&bs->in_flight)) { |
426 | if (bdrv_get_info(bs, &bdi) < 0 || bdi.cluster_size == 0) { | 36 | - return true; |
427 | *cluster_offset = offset; | 37 | - } |
428 | *cluster_bytes = bytes; | ||
429 | @@ -XXX,XX +XXX,XX @@ static int bdrv_check_request32(int64_t offset, int64_t bytes, | ||
430 | int bdrv_pwrite_zeroes(BdrvChild *child, int64_t offset, | ||
431 | int64_t bytes, BdrvRequestFlags flags) | ||
432 | { | ||
433 | + IO_CODE(); | ||
434 | return bdrv_pwritev(child, offset, bytes, NULL, | ||
435 | BDRV_REQ_ZERO_WRITE | flags); | ||
436 | } | ||
437 | @@ -XXX,XX +XXX,XX @@ int bdrv_make_zero(BdrvChild *child, BdrvRequestFlags flags) | ||
438 | int ret; | ||
439 | int64_t target_size, bytes, offset = 0; | ||
440 | BlockDriverState *bs = child->bs; | ||
441 | + IO_CODE(); | ||
442 | |||
443 | target_size = bdrv_getlength(bs); | ||
444 | if (target_size < 0) { | ||
445 | @@ -XXX,XX +XXX,XX @@ int bdrv_pread(BdrvChild *child, int64_t offset, void *buf, int64_t bytes) | ||
446 | { | ||
447 | int ret; | ||
448 | QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes); | ||
449 | + IO_CODE(); | ||
450 | |||
451 | if (bytes < 0) { | ||
452 | return -EINVAL; | ||
453 | @@ -XXX,XX +XXX,XX @@ int bdrv_pwrite(BdrvChild *child, int64_t offset, const void *buf, | ||
454 | { | ||
455 | int ret; | ||
456 | QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes); | ||
457 | + IO_CODE(); | ||
458 | |||
459 | if (bytes < 0) { | ||
460 | return -EINVAL; | ||
461 | @@ -XXX,XX +XXX,XX @@ int bdrv_pwrite_sync(BdrvChild *child, int64_t offset, | ||
462 | const void *buf, int64_t count) | ||
463 | { | ||
464 | int ret; | ||
465 | + IO_CODE(); | ||
466 | |||
467 | ret = bdrv_pwrite(child, offset, buf, count); | ||
468 | if (ret < 0) { | ||
469 | @@ -XXX,XX +XXX,XX @@ out: | ||
470 | int coroutine_fn bdrv_co_pwrite_zeroes(BdrvChild *child, int64_t offset, | ||
471 | int64_t bytes, BdrvRequestFlags flags) | ||
472 | { | ||
473 | + IO_CODE(); | ||
474 | trace_bdrv_co_pwrite_zeroes(child->bs, offset, bytes, flags); | ||
475 | |||
476 | if (!(child->bs->open_flags & BDRV_O_UNMAP)) { | ||
477 | @@ -XXX,XX +XXX,XX @@ int bdrv_block_status_above(BlockDriverState *bs, BlockDriverState *base, | ||
478 | int64_t offset, int64_t bytes, int64_t *pnum, | ||
479 | int64_t *map, BlockDriverState **file) | ||
480 | { | ||
481 | + IO_CODE(); | ||
482 | return bdrv_common_block_status_above(bs, base, false, true, offset, bytes, | ||
483 | pnum, map, file, NULL); | ||
484 | } | ||
485 | @@ -XXX,XX +XXX,XX @@ int bdrv_block_status_above(BlockDriverState *bs, BlockDriverState *base, | ||
486 | int bdrv_block_status(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
487 | int64_t *pnum, int64_t *map, BlockDriverState **file) | ||
488 | { | ||
489 | + IO_CODE(); | ||
490 | return bdrv_block_status_above(bs, bdrv_filter_or_cow_bs(bs), | ||
491 | offset, bytes, pnum, map, file); | ||
492 | } | ||
493 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_is_zero_fast(BlockDriverState *bs, int64_t offset, | ||
494 | { | ||
495 | int ret; | ||
496 | int64_t pnum = bytes; | ||
497 | + IO_CODE(); | ||
498 | |||
499 | if (!bytes) { | ||
500 | return 1; | ||
501 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_is_allocated(BlockDriverState *bs, int64_t offset, | ||
502 | { | ||
503 | int ret; | ||
504 | int64_t dummy; | ||
505 | + IO_CODE(); | ||
506 | |||
507 | ret = bdrv_common_block_status_above(bs, bs, true, false, offset, | ||
508 | bytes, pnum ? pnum : &dummy, NULL, | ||
509 | @@ -XXX,XX +XXX,XX @@ int bdrv_is_allocated_above(BlockDriverState *top, | ||
510 | int ret = bdrv_common_block_status_above(top, base, include_base, false, | ||
511 | offset, bytes, pnum, NULL, NULL, | ||
512 | &depth); | ||
513 | + IO_CODE(); | ||
514 | if (ret < 0) { | ||
515 | return ret; | ||
516 | } | ||
517 | @@ -XXX,XX +XXX,XX @@ int bdrv_save_vmstate(BlockDriverState *bs, const uint8_t *buf, | ||
518 | { | ||
519 | QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, size); | ||
520 | int ret = bdrv_writev_vmstate(bs, &qiov, pos); | ||
521 | + IO_CODE(); | ||
522 | |||
523 | return ret < 0 ? ret : size; | ||
524 | } | ||
525 | @@ -XXX,XX +XXX,XX @@ int bdrv_load_vmstate(BlockDriverState *bs, uint8_t *buf, | ||
526 | { | ||
527 | QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, size); | ||
528 | int ret = bdrv_readv_vmstate(bs, &qiov, pos); | ||
529 | + IO_CODE(); | ||
530 | |||
531 | return ret < 0 ? ret : size; | ||
532 | } | ||
533 | @@ -XXX,XX +XXX,XX @@ int bdrv_load_vmstate(BlockDriverState *bs, uint8_t *buf, | ||
534 | |||
535 | void bdrv_aio_cancel(BlockAIOCB *acb) | ||
536 | { | ||
537 | + IO_CODE(); | ||
538 | qemu_aio_ref(acb); | ||
539 | bdrv_aio_cancel_async(acb); | ||
540 | while (acb->refcnt > 1) { | ||
541 | @@ -XXX,XX +XXX,XX @@ void bdrv_aio_cancel(BlockAIOCB *acb) | ||
542 | * In either case the completion callback must be called. */ | ||
543 | void bdrv_aio_cancel_async(BlockAIOCB *acb) | ||
544 | { | ||
545 | + IO_CODE(); | ||
546 | if (acb->aiocb_info->cancel_async) { | ||
547 | acb->aiocb_info->cancel_async(acb); | ||
548 | } | ||
549 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_flush(BlockDriverState *bs) | ||
550 | BdrvChild *child; | ||
551 | int current_gen; | ||
552 | int ret = 0; | ||
553 | + IO_CODE(); | ||
554 | |||
555 | bdrv_inc_in_flight(bs); | ||
556 | |||
557 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_pdiscard(BdrvChild *child, int64_t offset, | ||
558 | int64_t max_pdiscard; | ||
559 | int head, tail, align; | ||
560 | BlockDriverState *bs = child->bs; | ||
561 | + IO_CODE(); | ||
562 | |||
563 | if (!bs || !bs->drv || !bdrv_is_inserted(bs)) { | ||
564 | return -ENOMEDIUM; | ||
565 | @@ -XXX,XX +XXX,XX @@ int bdrv_co_ioctl(BlockDriverState *bs, int req, void *buf) | ||
566 | .coroutine = qemu_coroutine_self(), | ||
567 | }; | ||
568 | BlockAIOCB *acb; | ||
569 | + IO_CODE(); | ||
570 | |||
571 | bdrv_inc_in_flight(bs); | ||
572 | if (!drv || (!drv->bdrv_aio_ioctl && !drv->bdrv_co_ioctl)) { | ||
573 | @@ -XXX,XX +XXX,XX @@ out: | ||
574 | |||
575 | void *qemu_blockalign(BlockDriverState *bs, size_t size) | ||
576 | { | ||
577 | + IO_CODE(); | ||
578 | return qemu_memalign(bdrv_opt_mem_align(bs), size); | ||
579 | } | ||
580 | |||
581 | void *qemu_blockalign0(BlockDriverState *bs, size_t size) | ||
582 | { | ||
583 | + IO_CODE(); | ||
584 | return memset(qemu_blockalign(bs, size), 0, size); | ||
585 | } | ||
586 | |||
587 | void *qemu_try_blockalign(BlockDriverState *bs, size_t size) | ||
588 | { | ||
589 | size_t align = bdrv_opt_mem_align(bs); | ||
590 | + IO_CODE(); | ||
591 | |||
592 | /* Ensure that NULL is never returned on success */ | ||
593 | assert(align > 0); | ||
594 | @@ -XXX,XX +XXX,XX @@ void *qemu_try_blockalign(BlockDriverState *bs, size_t size) | ||
595 | void *qemu_try_blockalign0(BlockDriverState *bs, size_t size) | ||
596 | { | ||
597 | void *mem = qemu_try_blockalign(bs, size); | ||
598 | + IO_CODE(); | ||
599 | |||
600 | if (mem) { | ||
601 | memset(mem, 0, size); | ||
602 | @@ -XXX,XX +XXX,XX @@ bool bdrv_qiov_is_aligned(BlockDriverState *bs, QEMUIOVector *qiov) | ||
603 | { | ||
604 | int i; | ||
605 | size_t alignment = bdrv_min_mem_align(bs); | ||
606 | + IO_CODE(); | ||
607 | |||
608 | for (i = 0; i < qiov->niov; i++) { | ||
609 | if ((uintptr_t) qiov->iov[i].iov_base % alignment) { | ||
610 | @@ -XXX,XX +XXX,XX @@ bool bdrv_qiov_is_aligned(BlockDriverState *bs, QEMUIOVector *qiov) | ||
611 | void bdrv_io_plug(BlockDriverState *bs) | ||
612 | { | ||
613 | BdrvChild *child; | ||
614 | + IO_CODE(); | ||
615 | |||
616 | QLIST_FOREACH(child, &bs->children, next) { | ||
617 | bdrv_io_plug(child->bs); | ||
618 | @@ -XXX,XX +XXX,XX @@ void bdrv_io_plug(BlockDriverState *bs) | ||
619 | void bdrv_io_unplug(BlockDriverState *bs) | ||
620 | { | ||
621 | BdrvChild *child; | ||
622 | + IO_CODE(); | ||
623 | |||
624 | assert(bs->io_plugged); | ||
625 | if (qatomic_fetch_dec(&bs->io_plugged) == 1) { | ||
626 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_copy_range(BdrvChild *src, int64_t src_offset, | ||
627 | int64_t bytes, BdrvRequestFlags read_flags, | ||
628 | BdrvRequestFlags write_flags) | ||
629 | { | ||
630 | + IO_CODE(); | ||
631 | return bdrv_co_copy_range_from(src, src_offset, | ||
632 | dst, dst_offset, | ||
633 | bytes, read_flags, write_flags); | ||
634 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact, | ||
635 | BdrvTrackedRequest req; | ||
636 | int64_t old_size, new_bytes; | ||
637 | int ret; | ||
638 | - | 38 | - |
639 | + IO_CODE(); | 39 | - QLIST_FOREACH(child, &bs->children, next) { |
640 | 40 | - if (bdrv_requests_pending(child->bs)) { | |
641 | /* if bs->drv == NULL, bs is closed, so there's nothing to do here */ | 41 | - return true; |
642 | if (!drv) { | 42 | - } |
43 | - } | ||
44 | - | ||
45 | - return false; | ||
46 | -} | ||
47 | - | ||
48 | typedef struct { | ||
49 | Coroutine *co; | ||
50 | BlockDriverState *bs; | ||
643 | -- | 51 | -- |
644 | 2.35.1 | 52 | 2.13.6 |
53 | |||
54 | diff view generated by jsdifflib |
1 | From: Hanna Reitz <hreitz@redhat.com> | ||
---|---|---|---|
2 | |||
3 | bdrv_refresh_limits() recurses down to the node's children. That does | ||
4 | not seem necessary: When we refresh limits on some node, and then | ||
5 | recurse down and were to change one of its children's BlockLimits, then | ||
6 | that would mean we noticed the changed limits by pure chance. The fact | ||
7 | that we refresh the parent's limits has nothing to do with it, so the | ||
8 | reason for the change probably happened before this point in time, and | ||
9 | we should have refreshed the limits then. | ||
10 | |||
11 | Consequently, we should actually propagate block limits changes upwards, | ||
12 | not downwards. That is a separate and pre-existing issue, though, and | ||
13 | so will not be addressed in this patch. | ||
14 | |||
15 | The problem with recursing is that bdrv_refresh_limits() is not atomic. | ||
16 | It begins with zeroing BDS.bl, and only then sets proper, valid limits. | ||
17 | If we do not drain all nodes whose limits are refreshed, then concurrent | ||
18 | I/O requests can encounter invalid request_alignment values and crash | ||
19 | qemu. Therefore, a recursing bdrv_refresh_limits() requires the whole | ||
20 | subtree to be drained, which is currently not ensured by most callers. | ||
21 | |||
22 | A non-recursive bdrv_refresh_limits() only requires the node in question | ||
23 | to not receive I/O requests, and this is done by most callers in some | ||
24 | way or another: | ||
25 | - bdrv_open_driver() deals with a new node with no parents yet | ||
26 | - bdrv_set_file_or_backing_noperm() acts on a drained node | ||
27 | - bdrv_reopen_commit() acts only on drained nodes | ||
28 | - bdrv_append() should in theory require the node to be drained; in | ||
29 | practice most callers just lock the AioContext, which should at least | ||
30 | be enough to prevent concurrent I/O requests from accessing invalid | ||
31 | limits | ||
32 | |||
33 | So we can resolve the bug by making bdrv_refresh_limits() non-recursive. | ||
34 | |||
35 | Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=1879437 | ||
36 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
37 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
38 | Message-Id: <20220216105355.30729-2-hreitz@redhat.com> | ||
39 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
40 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 1 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
2 | Reviewed-by: Fam Zheng <famz@redhat.com> | ||
41 | --- | 3 | --- |
42 | block/io.c | 4 ---- | 4 | block/io.c | 6 ++++++ |
43 | 1 file changed, 4 deletions(-) | 5 | 1 file changed, 6 insertions(+) |
44 | 6 | ||
45 | diff --git a/block/io.c b/block/io.c | 7 | diff --git a/block/io.c b/block/io.c |
46 | index XXXXXXX..XXXXXXX 100644 | 8 | index XXXXXXX..XXXXXXX 100644 |
47 | --- a/block/io.c | 9 | --- a/block/io.c |
48 | +++ b/block/io.c | 10 | +++ b/block/io.c |
49 | @@ -XXX,XX +XXX,XX @@ void bdrv_refresh_limits(BlockDriverState *bs, Transaction *tran, Error **errp) | 11 | @@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void) |
50 | QLIST_FOREACH(c, &bs->children, next) { | 12 | BdrvNextIterator it; |
51 | if (c->role & (BDRV_CHILD_DATA | BDRV_CHILD_FILTERED | BDRV_CHILD_COW)) | 13 | GSList *aio_ctxs = NULL, *ctx; |
52 | { | 14 | |
53 | - bdrv_refresh_limits(c->bs, tran, errp); | 15 | + /* BDRV_POLL_WHILE() for a node can only be called from its own I/O thread |
54 | - if (*errp) { | 16 | + * or the main loop AioContext. We potentially use BDRV_POLL_WHILE() on |
55 | - return; | 17 | + * nodes in several different AioContexts, so make sure we're in the main |
56 | - } | 18 | + * context. */ |
57 | bdrv_merge_limits(&bs->bl, &c->bs->bl); | 19 | + assert(qemu_get_current_aio_context() == qemu_get_aio_context()); |
58 | have_limits = true; | 20 | + |
59 | } | 21 | block_job_pause_all(); |
22 | |||
23 | for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { | ||
60 | -- | 24 | -- |
61 | 2.35.1 | 25 | 2.13.6 |
62 | 26 | ||
63 | 27 | diff view generated by jsdifflib |
1 | From: Stefan Hajnoczi <stefanha@redhat.com> | 1 | bdrv_drained_begin() doesn't increase bs->quiesce_counter recursively |
---|---|---|---|
2 | and also doesn't notify other parent nodes of children, which both means | ||
3 | that the child nodes are not actually drained, and bdrv_drained_begin() | ||
4 | is providing useful functionality only on a single node. | ||
2 | 5 | ||
3 | qemu_mutex_iothread_locked() may be used from coroutines. Standard | 6 | To keep things consistent, we also shouldn't call the block driver |
4 | __thread variables cannot be used by coroutines. Use the coroutine TLS | 7 | callbacks recursively. |
5 | macros instead. | ||
6 | 8 | ||
7 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> | 9 | A proper recursive drain version that provides an actually working |
8 | Message-Id: <20220222140150.27240-5-stefanha@redhat.com> | 10 | drained section for child nodes will be introduced later. |
11 | |||
9 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
13 | Reviewed-by: Fam Zheng <famz@redhat.com> | ||
10 | --- | 14 | --- |
11 | softmmu/cpus.c | 9 +++++---- | 15 | block/io.c | 16 +++++++++------- |
12 | 1 file changed, 5 insertions(+), 4 deletions(-) | 16 | 1 file changed, 9 insertions(+), 7 deletions(-) |
13 | 17 | ||
14 | diff --git a/softmmu/cpus.c b/softmmu/cpus.c | 18 | diff --git a/block/io.c b/block/io.c |
15 | index XXXXXXX..XXXXXXX 100644 | 19 | index XXXXXXX..XXXXXXX 100644 |
16 | --- a/softmmu/cpus.c | 20 | --- a/block/io.c |
17 | +++ b/softmmu/cpus.c | 21 | +++ b/block/io.c |
18 | @@ -XXX,XX +XXX,XX @@ | 22 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_drain_invoke_entry(void *opaque) |
19 | #include "qemu/osdep.h" | ||
20 | #include "qemu-common.h" | ||
21 | #include "monitor/monitor.h" | ||
22 | +#include "qemu/coroutine-tls.h" | ||
23 | #include "qapi/error.h" | ||
24 | #include "qapi/qapi-commands-machine.h" | ||
25 | #include "qapi/qapi-commands-misc.h" | ||
26 | @@ -XXX,XX +XXX,XX @@ bool qemu_in_vcpu_thread(void) | ||
27 | return current_cpu && qemu_cpu_is_self(current_cpu); | ||
28 | } | 23 | } |
29 | 24 | ||
30 | -static __thread bool iothread_locked = false; | 25 | /* Recursively call BlockDriver.bdrv_co_drain_begin/end callbacks */ |
31 | +QEMU_DEFINE_STATIC_CO_TLS(bool, iothread_locked) | 26 | -static void bdrv_drain_invoke(BlockDriverState *bs, bool begin) |
32 | 27 | +static void bdrv_drain_invoke(BlockDriverState *bs, bool begin, bool recursive) | |
33 | bool qemu_mutex_iothread_locked(void) | ||
34 | { | 28 | { |
35 | - return iothread_locked; | 29 | BdrvChild *child, *tmp; |
36 | + return get_iothread_locked(); | 30 | BdrvCoDrainData data = { .bs = bs, .done = false, .begin = begin}; |
31 | @@ -XXX,XX +XXX,XX @@ static void bdrv_drain_invoke(BlockDriverState *bs, bool begin) | ||
32 | bdrv_coroutine_enter(bs, data.co); | ||
33 | BDRV_POLL_WHILE(bs, !data.done); | ||
34 | |||
35 | - QLIST_FOREACH_SAFE(child, &bs->children, next, tmp) { | ||
36 | - bdrv_drain_invoke(child->bs, begin); | ||
37 | + if (recursive) { | ||
38 | + QLIST_FOREACH_SAFE(child, &bs->children, next, tmp) { | ||
39 | + bdrv_drain_invoke(child->bs, begin, true); | ||
40 | + } | ||
41 | } | ||
37 | } | 42 | } |
38 | 43 | ||
39 | /* | 44 | @@ -XXX,XX +XXX,XX @@ void bdrv_drained_begin(BlockDriverState *bs) |
40 | @@ -XXX,XX +XXX,XX @@ void qemu_mutex_lock_iothread_impl(const char *file, int line) | 45 | bdrv_parent_drained_begin(bs); |
41 | 46 | } | |
42 | g_assert(!qemu_mutex_iothread_locked()); | 47 | |
43 | bql_lock(&qemu_global_mutex, file, line); | 48 | - bdrv_drain_invoke(bs, true); |
44 | - iothread_locked = true; | 49 | + bdrv_drain_invoke(bs, true, false); |
45 | + set_iothread_locked(true); | 50 | bdrv_drain_recurse(bs); |
46 | } | 51 | } |
47 | 52 | ||
48 | void qemu_mutex_unlock_iothread(void) | 53 | @@ -XXX,XX +XXX,XX @@ void bdrv_drained_end(BlockDriverState *bs) |
49 | { | 54 | } |
50 | g_assert(qemu_mutex_iothread_locked()); | 55 | |
51 | - iothread_locked = false; | 56 | /* Re-enable things in child-to-parent order */ |
52 | + set_iothread_locked(false); | 57 | - bdrv_drain_invoke(bs, false); |
53 | qemu_mutex_unlock(&qemu_global_mutex); | 58 | + bdrv_drain_invoke(bs, false, false); |
59 | bdrv_parent_drained_end(bs); | ||
60 | aio_enable_external(bdrv_get_aio_context(bs)); | ||
54 | } | 61 | } |
55 | 62 | @@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void) | |
63 | aio_context_acquire(aio_context); | ||
64 | aio_disable_external(aio_context); | ||
65 | bdrv_parent_drained_begin(bs); | ||
66 | - bdrv_drain_invoke(bs, true); | ||
67 | + bdrv_drain_invoke(bs, true, true); | ||
68 | aio_context_release(aio_context); | ||
69 | |||
70 | if (!g_slist_find(aio_ctxs, aio_context)) { | ||
71 | @@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_end(void) | ||
72 | |||
73 | /* Re-enable things in child-to-parent order */ | ||
74 | aio_context_acquire(aio_context); | ||
75 | - bdrv_drain_invoke(bs, false); | ||
76 | + bdrv_drain_invoke(bs, false, true); | ||
77 | bdrv_parent_drained_end(bs); | ||
78 | aio_enable_external(aio_context); | ||
79 | aio_context_release(aio_context); | ||
56 | -- | 80 | -- |
57 | 2.35.1 | 81 | 2.13.6 |
82 | |||
83 | diff view generated by jsdifflib |
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | 1 | The existing test is for bdrv_drain_all_begin/end() only. Generalise the |
---|---|---|---|
2 | test case so that it can be run for the other variants as well. At the | ||
3 | moment this is only bdrv_drain_begin/end(), but in a while, we'll add | ||
4 | another one. | ||
2 | 5 | ||
3 | Similarly to the previous patch, split block_int.h | 6 | Also, add a backing file to the test node to test whether the operations |
4 | in block_int-io.h and block_int-global-state.h | 7 | work recursively. |
5 | 8 | ||
6 | block_int-common.h contains the structures shared between | ||
7 | the two headers, and the functions that can't be categorized as | ||
8 | I/O or global state. | ||
9 | |||
10 | Assertions are added in the next patch. | ||
11 | |||
12 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
13 | Message-Id: <20220303151616.325444-12-eesposit@redhat.com> | ||
14 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 9 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
15 | --- | 10 | --- |
16 | include/block/block_int-common.h | 1180 +++++++++++++++++++ | 11 | tests/test-bdrv-drain.c | 69 ++++++++++++++++++++++++++++++++++++++++++++----- |
17 | include/block/block_int-global-state.h | 312 +++++ | 12 | 1 file changed, 62 insertions(+), 7 deletions(-) |
18 | include/block/block_int-io.h | 179 +++ | ||
19 | include/block/block_int.h | 1489 +----------------------- | ||
20 | blockdev.c | 5 + | ||
21 | 5 files changed, 1679 insertions(+), 1486 deletions(-) | ||
22 | create mode 100644 include/block/block_int-common.h | ||
23 | create mode 100644 include/block/block_int-global-state.h | ||
24 | create mode 100644 include/block/block_int-io.h | ||
25 | 13 | ||
26 | diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h | 14 | diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c |
27 | new file mode 100644 | 15 | index XXXXXXX..XXXXXXX 100644 |
28 | index XXXXXXX..XXXXXXX | 16 | --- a/tests/test-bdrv-drain.c |
29 | --- /dev/null | 17 | +++ b/tests/test-bdrv-drain.c |
30 | +++ b/include/block/block_int-common.h | 18 | @@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_test = { |
31 | @@ -XXX,XX +XXX,XX @@ | 19 | |
32 | +/* | 20 | .bdrv_co_drain_begin = bdrv_test_co_drain_begin, |
33 | + * QEMU System Emulator block driver | 21 | .bdrv_co_drain_end = bdrv_test_co_drain_end, |
34 | + * | ||
35 | + * Copyright (c) 2003 Fabrice Bellard | ||
36 | + * | ||
37 | + * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
38 | + * of this software and associated documentation files (the "Software"), to deal | ||
39 | + * in the Software without restriction, including without limitation the rights | ||
40 | + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
41 | + * copies of the Software, and to permit persons to whom the Software is | ||
42 | + * furnished to do so, subject to the following conditions: | ||
43 | + * | ||
44 | + * The above copyright notice and this permission notice shall be included in | ||
45 | + * all copies or substantial portions of the Software. | ||
46 | + * | ||
47 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
48 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
49 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
50 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
51 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
52 | + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
53 | + * THE SOFTWARE. | ||
54 | + */ | ||
55 | +#ifndef BLOCK_INT_COMMON_H | ||
56 | +#define BLOCK_INT_COMMON_H | ||
57 | + | 22 | + |
58 | +#include "block/accounting.h" | 23 | + .bdrv_child_perm = bdrv_format_default_perms, |
59 | +#include "block/block.h" | 24 | }; |
60 | +#include "block/aio-wait.h" | 25 | |
61 | +#include "qemu/queue.h" | 26 | static void aio_ret_cb(void *opaque, int ret) |
62 | +#include "qemu/coroutine.h" | 27 | @@ -XXX,XX +XXX,XX @@ static void aio_ret_cb(void *opaque, int ret) |
63 | +#include "qemu/stats64.h" | 28 | *aio_ret = ret; |
64 | +#include "qemu/timer.h" | 29 | } |
65 | +#include "qemu/hbitmap.h" | 30 | |
66 | +#include "block/snapshot.h" | 31 | -static void test_drv_cb_drain_all(void) |
67 | +#include "qemu/throttle.h" | 32 | +enum drain_type { |
68 | +#include "qemu/rcu.h" | 33 | + BDRV_DRAIN_ALL, |
69 | + | 34 | + BDRV_DRAIN, |
70 | +#define BLOCK_FLAG_LAZY_REFCOUNTS 8 | ||
71 | + | ||
72 | +#define BLOCK_OPT_SIZE "size" | ||
73 | +#define BLOCK_OPT_ENCRYPT "encryption" | ||
74 | +#define BLOCK_OPT_ENCRYPT_FORMAT "encrypt.format" | ||
75 | +#define BLOCK_OPT_COMPAT6 "compat6" | ||
76 | +#define BLOCK_OPT_HWVERSION "hwversion" | ||
77 | +#define BLOCK_OPT_BACKING_FILE "backing_file" | ||
78 | +#define BLOCK_OPT_BACKING_FMT "backing_fmt" | ||
79 | +#define BLOCK_OPT_CLUSTER_SIZE "cluster_size" | ||
80 | +#define BLOCK_OPT_TABLE_SIZE "table_size" | ||
81 | +#define BLOCK_OPT_PREALLOC "preallocation" | ||
82 | +#define BLOCK_OPT_SUBFMT "subformat" | ||
83 | +#define BLOCK_OPT_COMPAT_LEVEL "compat" | ||
84 | +#define BLOCK_OPT_LAZY_REFCOUNTS "lazy_refcounts" | ||
85 | +#define BLOCK_OPT_ADAPTER_TYPE "adapter_type" | ||
86 | +#define BLOCK_OPT_REDUNDANCY "redundancy" | ||
87 | +#define BLOCK_OPT_NOCOW "nocow" | ||
88 | +#define BLOCK_OPT_EXTENT_SIZE_HINT "extent_size_hint" | ||
89 | +#define BLOCK_OPT_OBJECT_SIZE "object_size" | ||
90 | +#define BLOCK_OPT_REFCOUNT_BITS "refcount_bits" | ||
91 | +#define BLOCK_OPT_DATA_FILE "data_file" | ||
92 | +#define BLOCK_OPT_DATA_FILE_RAW "data_file_raw" | ||
93 | +#define BLOCK_OPT_COMPRESSION_TYPE "compression_type" | ||
94 | +#define BLOCK_OPT_EXTL2 "extended_l2" | ||
95 | + | ||
96 | +#define BLOCK_PROBE_BUF_SIZE 512 | ||
97 | + | ||
98 | +enum BdrvTrackedRequestType { | ||
99 | + BDRV_TRACKED_READ, | ||
100 | + BDRV_TRACKED_WRITE, | ||
101 | + BDRV_TRACKED_DISCARD, | ||
102 | + BDRV_TRACKED_TRUNCATE, | ||
103 | +}; | 35 | +}; |
104 | + | 36 | + |
105 | +/* | 37 | +static void do_drain_begin(enum drain_type drain_type, BlockDriverState *bs) |
106 | + * That is not quite good that BdrvTrackedRequest structure is public, | ||
107 | + * as block/io.c is very careful about incoming offset/bytes being | ||
108 | + * correct. Be sure to assert bdrv_check_request() succeeded after any | ||
109 | + * modification of BdrvTrackedRequest object out of block/io.c | ||
110 | + */ | ||
111 | +typedef struct BdrvTrackedRequest { | ||
112 | + BlockDriverState *bs; | ||
113 | + int64_t offset; | ||
114 | + int64_t bytes; | ||
115 | + enum BdrvTrackedRequestType type; | ||
116 | + | ||
117 | + bool serialising; | ||
118 | + int64_t overlap_offset; | ||
119 | + int64_t overlap_bytes; | ||
120 | + | ||
121 | + QLIST_ENTRY(BdrvTrackedRequest) list; | ||
122 | + Coroutine *co; /* owner, used for deadlock detection */ | ||
123 | + CoQueue wait_queue; /* coroutines blocked on this request */ | ||
124 | + | ||
125 | + struct BdrvTrackedRequest *waiting_for; | ||
126 | +} BdrvTrackedRequest; | ||
127 | + | ||
128 | + | ||
129 | +struct BlockDriver { | ||
130 | + const char *format_name; | ||
131 | + int instance_size; | ||
132 | + | ||
133 | + /* | ||
134 | + * Set to true if the BlockDriver is a block filter. Block filters pass | ||
135 | + * certain callbacks that refer to data (see block.c) to their bs->file | ||
136 | + * or bs->backing (whichever one exists) if the driver doesn't implement | ||
137 | + * them. Drivers that do not wish to forward must implement them and return | ||
138 | + * -ENOTSUP. | ||
139 | + * Note that filters are not allowed to modify data. | ||
140 | + * | ||
141 | + * Filters generally cannot have more than a single filtered child, | ||
142 | + * because the data they present must at all times be the same as | ||
143 | + * that on their filtered child. That would be impossible to | ||
144 | + * achieve for multiple filtered children. | ||
145 | + * (And this filtered child must then be bs->file or bs->backing.) | ||
146 | + */ | ||
147 | + bool is_filter; | ||
148 | + /* | ||
149 | + * Set to true if the BlockDriver is a format driver. Format nodes | ||
150 | + * generally do not expect their children to be other format nodes | ||
151 | + * (except for backing files), and so format probing is disabled | ||
152 | + * on those children. | ||
153 | + */ | ||
154 | + bool is_format; | ||
155 | + | ||
156 | + /* | ||
157 | + * This function is invoked under BQL before .bdrv_co_amend() | ||
158 | + * (which in contrast does not necessarily run under the BQL) | ||
159 | + * to allow driver-specific initialization code that requires | ||
160 | + * the BQL, like setting up specific permission flags. | ||
161 | + */ | ||
162 | + int (*bdrv_amend_pre_run)(BlockDriverState *bs, Error **errp); | ||
163 | + /* | ||
164 | + * This function is invoked under BQL after .bdrv_co_amend() | ||
165 | + * to allow cleaning up what was done in .bdrv_amend_pre_run(). | ||
166 | + */ | ||
167 | + void (*bdrv_amend_clean)(BlockDriverState *bs); | ||
168 | + | ||
169 | + /* | ||
170 | + * Return true if @to_replace can be replaced by a BDS with the | ||
171 | + * same data as @bs without it affecting @bs's behavior (that is, | ||
172 | + * without it being visible to @bs's parents). | ||
173 | + */ | ||
174 | + bool (*bdrv_recurse_can_replace)(BlockDriverState *bs, | ||
175 | + BlockDriverState *to_replace); | ||
176 | + | ||
177 | + int (*bdrv_probe)(const uint8_t *buf, int buf_size, const char *filename); | ||
178 | + int (*bdrv_probe_device)(const char *filename); | ||
179 | + | ||
180 | + /* | ||
181 | + * Any driver implementing this callback is expected to be able to handle | ||
182 | + * NULL file names in its .bdrv_open() implementation. | ||
183 | + */ | ||
184 | + void (*bdrv_parse_filename)(const char *filename, QDict *options, | ||
185 | + Error **errp); | ||
186 | + /* | ||
187 | + * Drivers not implementing bdrv_parse_filename nor bdrv_open should have | ||
188 | + * this field set to true, except ones that are defined only by their | ||
189 | + * child's bs. | ||
190 | + * An example of the last type will be the quorum block driver. | ||
191 | + */ | ||
192 | + bool bdrv_needs_filename; | ||
193 | + | ||
194 | + /* | ||
195 | + * Set if a driver can support backing files. This also implies the | ||
196 | + * following semantics: | ||
197 | + * | ||
198 | + * - Return status 0 of .bdrv_co_block_status means that corresponding | ||
199 | + * blocks are not allocated in this layer of backing-chain | ||
200 | + * - For such (unallocated) blocks, read will: | ||
201 | + * - fill buffer with zeros if there is no backing file | ||
202 | + * - read from the backing file otherwise, where the block layer | ||
203 | + * takes care of reading zeros beyond EOF if backing file is short | ||
204 | + */ | ||
205 | + bool supports_backing; | ||
206 | + | ||
207 | + /* For handling image reopen for split or non-split files */ | ||
208 | + int (*bdrv_reopen_prepare)(BDRVReopenState *reopen_state, | ||
209 | + BlockReopenQueue *queue, Error **errp); | ||
210 | + void (*bdrv_reopen_commit)(BDRVReopenState *reopen_state); | ||
211 | + void (*bdrv_reopen_commit_post)(BDRVReopenState *reopen_state); | ||
212 | + void (*bdrv_reopen_abort)(BDRVReopenState *reopen_state); | ||
213 | + void (*bdrv_join_options)(QDict *options, QDict *old_options); | ||
214 | + | ||
215 | + int (*bdrv_open)(BlockDriverState *bs, QDict *options, int flags, | ||
216 | + Error **errp); | ||
217 | + | ||
218 | + /* Protocol drivers should implement this instead of bdrv_open */ | ||
219 | + int (*bdrv_file_open)(BlockDriverState *bs, QDict *options, int flags, | ||
220 | + Error **errp); | ||
221 | + void (*bdrv_close)(BlockDriverState *bs); | ||
222 | + | ||
223 | + | ||
224 | + int coroutine_fn (*bdrv_co_create)(BlockdevCreateOptions *opts, | ||
225 | + Error **errp); | ||
226 | + int coroutine_fn (*bdrv_co_create_opts)(BlockDriver *drv, | ||
227 | + const char *filename, | ||
228 | + QemuOpts *opts, | ||
229 | + Error **errp); | ||
230 | + | ||
231 | + int coroutine_fn (*bdrv_co_amend)(BlockDriverState *bs, | ||
232 | + BlockdevAmendOptions *opts, | ||
233 | + bool force, | ||
234 | + Error **errp); | ||
235 | + | ||
236 | + int (*bdrv_amend_options)(BlockDriverState *bs, | ||
237 | + QemuOpts *opts, | ||
238 | + BlockDriverAmendStatusCB *status_cb, | ||
239 | + void *cb_opaque, | ||
240 | + bool force, | ||
241 | + Error **errp); | ||
242 | + | ||
243 | + int (*bdrv_make_empty)(BlockDriverState *bs); | ||
244 | + | ||
245 | + /* | ||
246 | + * Refreshes the bs->exact_filename field. If that is impossible, | ||
247 | + * bs->exact_filename has to be left empty. | ||
248 | + */ | ||
249 | + void (*bdrv_refresh_filename)(BlockDriverState *bs); | ||
250 | + | ||
251 | + /* | ||
252 | + * Gathers the open options for all children into @target. | ||
253 | + * A simple format driver (without backing file support) might | ||
254 | + * implement this function like this: | ||
255 | + * | ||
256 | + * QINCREF(bs->file->bs->full_open_options); | ||
257 | + * qdict_put(target, "file", bs->file->bs->full_open_options); | ||
258 | + * | ||
259 | + * If not specified, the generic implementation will simply put | ||
260 | + * all children's options under their respective name. | ||
261 | + * | ||
262 | + * @backing_overridden is true when bs->backing seems not to be | ||
263 | + * the child that would result from opening bs->backing_file. | ||
264 | + * Therefore, if it is true, the backing child's options should be | ||
265 | + * gathered; otherwise, there is no need since the backing child | ||
266 | + * is the one implied by the image header. | ||
267 | + * | ||
268 | + * Note that ideally this function would not be needed. Every | ||
269 | + * block driver which implements it is probably doing something | ||
270 | + * shady regarding its runtime option structure. | ||
271 | + */ | ||
272 | + void (*bdrv_gather_child_options)(BlockDriverState *bs, QDict *target, | ||
273 | + bool backing_overridden); | ||
274 | + | ||
275 | + /* | ||
276 | + * Returns an allocated string which is the directory name of this BDS: It | ||
277 | + * will be used to make relative filenames absolute by prepending this | ||
278 | + * function's return value to them. | ||
279 | + */ | ||
280 | + char *(*bdrv_dirname)(BlockDriverState *bs, Error **errp); | ||
281 | + | ||
282 | + /* aio */ | ||
283 | + BlockAIOCB *(*bdrv_aio_preadv)(BlockDriverState *bs, | ||
284 | + int64_t offset, int64_t bytes, QEMUIOVector *qiov, | ||
285 | + BdrvRequestFlags flags, BlockCompletionFunc *cb, void *opaque); | ||
286 | + BlockAIOCB *(*bdrv_aio_pwritev)(BlockDriverState *bs, | ||
287 | + int64_t offset, int64_t bytes, QEMUIOVector *qiov, | ||
288 | + BdrvRequestFlags flags, BlockCompletionFunc *cb, void *opaque); | ||
289 | + BlockAIOCB *(*bdrv_aio_flush)(BlockDriverState *bs, | ||
290 | + BlockCompletionFunc *cb, void *opaque); | ||
291 | + BlockAIOCB *(*bdrv_aio_pdiscard)(BlockDriverState *bs, | ||
292 | + int64_t offset, int bytes, | ||
293 | + BlockCompletionFunc *cb, void *opaque); | ||
294 | + | ||
295 | + int coroutine_fn (*bdrv_co_readv)(BlockDriverState *bs, | ||
296 | + int64_t sector_num, int nb_sectors, QEMUIOVector *qiov); | ||
297 | + | ||
298 | + /** | ||
299 | + * @offset: position in bytes to read at | ||
300 | + * @bytes: number of bytes to read | ||
301 | + * @qiov: the buffers to fill with read data | ||
302 | + * @flags: currently unused, always 0 | ||
303 | + * | ||
304 | + * @offset and @bytes will be a multiple of 'request_alignment', | ||
305 | + * but the length of individual @qiov elements does not have to | ||
306 | + * be a multiple. | ||
307 | + * | ||
308 | + * @bytes will always equal the total size of @qiov, and will be | ||
309 | + * no larger than 'max_transfer'. | ||
310 | + * | ||
311 | + * The buffer in @qiov may point directly to guest memory. | ||
312 | + */ | ||
313 | + int coroutine_fn (*bdrv_co_preadv)(BlockDriverState *bs, | ||
314 | + int64_t offset, int64_t bytes, QEMUIOVector *qiov, | ||
315 | + BdrvRequestFlags flags); | ||
316 | + | ||
317 | + int coroutine_fn (*bdrv_co_preadv_part)(BlockDriverState *bs, | ||
318 | + int64_t offset, int64_t bytes, | ||
319 | + QEMUIOVector *qiov, size_t qiov_offset, | ||
320 | + BdrvRequestFlags flags); | ||
321 | + | ||
322 | + int coroutine_fn (*bdrv_co_writev)(BlockDriverState *bs, | ||
323 | + int64_t sector_num, int nb_sectors, QEMUIOVector *qiov, | ||
324 | + int flags); | ||
325 | + /** | ||
326 | + * @offset: position in bytes to write at | ||
327 | + * @bytes: number of bytes to write | ||
328 | + * @qiov: the buffers containing data to write | ||
329 | + * @flags: zero or more bits allowed by 'supported_write_flags' | ||
330 | + * | ||
331 | + * @offset and @bytes will be a multiple of 'request_alignment', | ||
332 | + * but the length of individual @qiov elements does not have to | ||
333 | + * be a multiple. | ||
334 | + * | ||
335 | + * @bytes will always equal the total size of @qiov, and will be | ||
336 | + * no larger than 'max_transfer'. | ||
337 | + * | ||
338 | + * The buffer in @qiov may point directly to guest memory. | ||
339 | + */ | ||
340 | + int coroutine_fn (*bdrv_co_pwritev)(BlockDriverState *bs, | ||
341 | + int64_t offset, int64_t bytes, QEMUIOVector *qiov, | ||
342 | + BdrvRequestFlags flags); | ||
343 | + int coroutine_fn (*bdrv_co_pwritev_part)(BlockDriverState *bs, | ||
344 | + int64_t offset, int64_t bytes, QEMUIOVector *qiov, size_t qiov_offset, | ||
345 | + BdrvRequestFlags flags); | ||
346 | + | ||
347 | + /* | ||
348 | + * Efficiently zero a region of the disk image. Typically an image format | ||
349 | + * would use a compact metadata representation to implement this. This | ||
350 | + * function pointer may be NULL or return -ENOSUP and .bdrv_co_writev() | ||
351 | + * will be called instead. | ||
352 | + */ | ||
353 | + int coroutine_fn (*bdrv_co_pwrite_zeroes)(BlockDriverState *bs, | ||
354 | + int64_t offset, int64_t bytes, BdrvRequestFlags flags); | ||
355 | + int coroutine_fn (*bdrv_co_pdiscard)(BlockDriverState *bs, | ||
356 | + int64_t offset, int64_t bytes); | ||
357 | + | ||
358 | + /* | ||
359 | + * Map [offset, offset + nbytes) range onto a child of @bs to copy from, | ||
360 | + * and invoke bdrv_co_copy_range_from(child, ...), or invoke | ||
361 | + * bdrv_co_copy_range_to() if @bs is the leaf child to copy data from. | ||
362 | + * | ||
363 | + * See the comment of bdrv_co_copy_range for the parameter and return value | ||
364 | + * semantics. | ||
365 | + */ | ||
366 | + int coroutine_fn (*bdrv_co_copy_range_from)(BlockDriverState *bs, | ||
367 | + BdrvChild *src, | ||
368 | + int64_t offset, | ||
369 | + BdrvChild *dst, | ||
370 | + int64_t dst_offset, | ||
371 | + int64_t bytes, | ||
372 | + BdrvRequestFlags read_flags, | ||
373 | + BdrvRequestFlags write_flags); | ||
374 | + | ||
375 | + /* | ||
376 | + * Map [offset, offset + nbytes) range onto a child of bs to copy data to, | ||
377 | + * and invoke bdrv_co_copy_range_to(child, src, ...), or perform the copy | ||
378 | + * operation if @bs is the leaf and @src has the same BlockDriver. Return | ||
379 | + * -ENOTSUP if @bs is the leaf but @src has a different BlockDriver. | ||
380 | + * | ||
381 | + * See the comment of bdrv_co_copy_range for the parameter and return value | ||
382 | + * semantics. | ||
383 | + */ | ||
384 | + int coroutine_fn (*bdrv_co_copy_range_to)(BlockDriverState *bs, | ||
385 | + BdrvChild *src, | ||
386 | + int64_t src_offset, | ||
387 | + BdrvChild *dst, | ||
388 | + int64_t dst_offset, | ||
389 | + int64_t bytes, | ||
390 | + BdrvRequestFlags read_flags, | ||
391 | + BdrvRequestFlags write_flags); | ||
392 | + | ||
393 | + /* | ||
394 | + * Building block for bdrv_block_status[_above] and | ||
395 | + * bdrv_is_allocated[_above]. The driver should answer only | ||
396 | + * according to the current layer, and should only need to set | ||
397 | + * BDRV_BLOCK_DATA, BDRV_BLOCK_ZERO, BDRV_BLOCK_OFFSET_VALID, | ||
398 | + * and/or BDRV_BLOCK_RAW; if the current layer defers to a backing | ||
399 | + * layer, the result should be 0 (and not BDRV_BLOCK_ZERO). See | ||
400 | + * block.h for the overall meaning of the bits. As a hint, the | ||
401 | + * flag want_zero is true if the caller cares more about precise | ||
402 | + * mappings (favor accurate _OFFSET_VALID/_ZERO) or false for | ||
403 | + * overall allocation (favor larger *pnum, perhaps by reporting | ||
404 | + * _DATA instead of _ZERO). The block layer guarantees input | ||
405 | + * clamped to bdrv_getlength() and aligned to request_alignment, | ||
406 | + * as well as non-NULL pnum, map, and file; in turn, the driver | ||
407 | + * must return an error or set pnum to an aligned non-zero value. | ||
408 | + * | ||
409 | + * Note that @bytes is just a hint on how big of a region the | ||
410 | + * caller wants to inspect. It is not a limit on *pnum. | ||
411 | + * Implementations are free to return larger values of *pnum if | ||
412 | + * doing so does not incur a performance penalty. | ||
413 | + * | ||
414 | + * block/io.c's bdrv_co_block_status() will utilize an unclamped | ||
415 | + * *pnum value for the block-status cache on protocol nodes, prior | ||
416 | + * to clamping *pnum for return to its caller. | ||
417 | + */ | ||
418 | + int coroutine_fn (*bdrv_co_block_status)(BlockDriverState *bs, | ||
419 | + bool want_zero, int64_t offset, int64_t bytes, int64_t *pnum, | ||
420 | + int64_t *map, BlockDriverState **file); | ||
421 | + | ||
422 | + /* | ||
423 | + * This informs the driver that we are no longer interested in the result | ||
424 | + * of in-flight requests, so don't waste the time if possible. | ||
425 | + * | ||
426 | + * One example usage is to avoid waiting for an nbd target node reconnect | ||
427 | + * timeout during job-cancel with force=true. | ||
428 | + */ | ||
429 | + void (*bdrv_cancel_in_flight)(BlockDriverState *bs); | ||
430 | + | ||
431 | + /* | ||
432 | + * Invalidate any cached meta-data. | ||
433 | + */ | ||
434 | + void coroutine_fn (*bdrv_co_invalidate_cache)(BlockDriverState *bs, | ||
435 | + Error **errp); | ||
436 | + int (*bdrv_inactivate)(BlockDriverState *bs); | ||
437 | + | ||
438 | + /* | ||
439 | + * Flushes all data for all layers by calling bdrv_co_flush for underlying | ||
440 | + * layers, if needed. This function is needed for deterministic | ||
441 | + * synchronization of the flush finishing callback. | ||
442 | + */ | ||
443 | + int coroutine_fn (*bdrv_co_flush)(BlockDriverState *bs); | ||
444 | + | ||
445 | + /* Delete a created file. */ | ||
446 | + int coroutine_fn (*bdrv_co_delete_file)(BlockDriverState *bs, | ||
447 | + Error **errp); | ||
448 | + | ||
449 | + /* | ||
450 | + * Flushes all data that was already written to the OS all the way down to | ||
451 | + * the disk (for example file-posix.c calls fsync()). | ||
452 | + */ | ||
453 | + int coroutine_fn (*bdrv_co_flush_to_disk)(BlockDriverState *bs); | ||
454 | + | ||
455 | + /* | ||
456 | + * Flushes all internal caches to the OS. The data may still sit in a | ||
457 | + * writeback cache of the host OS, but it will survive a crash of the qemu | ||
458 | + * process. | ||
459 | + */ | ||
460 | + int coroutine_fn (*bdrv_co_flush_to_os)(BlockDriverState *bs); | ||
461 | + | ||
462 | + /* | ||
463 | + * Drivers setting this field must be able to work with just a plain | ||
464 | + * filename with '<protocol_name>:' as a prefix, and no other options. | ||
465 | + * Options may be extracted from the filename by implementing | ||
466 | + * bdrv_parse_filename. | ||
467 | + */ | ||
468 | + const char *protocol_name; | ||
469 | + | ||
470 | + /* | ||
471 | + * Truncate @bs to @offset bytes using the given @prealloc mode | ||
472 | + * when growing. Modes other than PREALLOC_MODE_OFF should be | ||
473 | + * rejected when shrinking @bs. | ||
474 | + * | ||
475 | + * If @exact is true, @bs must be resized to exactly @offset. | ||
476 | + * Otherwise, it is sufficient for @bs (if it is a host block | ||
477 | + * device and thus there is no way to resize it) to be at least | ||
478 | + * @offset bytes in length. | ||
479 | + * | ||
480 | + * If @exact is true and this function fails but would succeed | ||
481 | + * with @exact = false, it should return -ENOTSUP. | ||
482 | + */ | ||
483 | + int coroutine_fn (*bdrv_co_truncate)(BlockDriverState *bs, int64_t offset, | ||
484 | + bool exact, PreallocMode prealloc, | ||
485 | + BdrvRequestFlags flags, Error **errp); | ||
486 | + int64_t (*bdrv_getlength)(BlockDriverState *bs); | ||
487 | + bool has_variable_length; | ||
488 | + int64_t (*bdrv_get_allocated_file_size)(BlockDriverState *bs); | ||
489 | + BlockMeasureInfo *(*bdrv_measure)(QemuOpts *opts, BlockDriverState *in_bs, | ||
490 | + Error **errp); | ||
491 | + | ||
492 | + int coroutine_fn (*bdrv_co_pwritev_compressed)(BlockDriverState *bs, | ||
493 | + int64_t offset, int64_t bytes, QEMUIOVector *qiov); | ||
494 | + int coroutine_fn (*bdrv_co_pwritev_compressed_part)(BlockDriverState *bs, | ||
495 | + int64_t offset, int64_t bytes, QEMUIOVector *qiov, | ||
496 | + size_t qiov_offset); | ||
497 | + | ||
498 | + int (*bdrv_snapshot_create)(BlockDriverState *bs, | ||
499 | + QEMUSnapshotInfo *sn_info); | ||
500 | + int (*bdrv_snapshot_goto)(BlockDriverState *bs, | ||
501 | + const char *snapshot_id); | ||
502 | + int (*bdrv_snapshot_delete)(BlockDriverState *bs, | ||
503 | + const char *snapshot_id, | ||
504 | + const char *name, | ||
505 | + Error **errp); | ||
506 | + int (*bdrv_snapshot_list)(BlockDriverState *bs, | ||
507 | + QEMUSnapshotInfo **psn_info); | ||
508 | + int (*bdrv_snapshot_load_tmp)(BlockDriverState *bs, | ||
509 | + const char *snapshot_id, | ||
510 | + const char *name, | ||
511 | + Error **errp); | ||
512 | + int (*bdrv_get_info)(BlockDriverState *bs, BlockDriverInfo *bdi); | ||
513 | + | ||
514 | + ImageInfoSpecific *(*bdrv_get_specific_info)(BlockDriverState *bs, | ||
515 | + Error **errp); | ||
516 | + BlockStatsSpecific *(*bdrv_get_specific_stats)(BlockDriverState *bs); | ||
517 | + | ||
518 | + int coroutine_fn (*bdrv_save_vmstate)(BlockDriverState *bs, | ||
519 | + QEMUIOVector *qiov, | ||
520 | + int64_t pos); | ||
521 | + int coroutine_fn (*bdrv_load_vmstate)(BlockDriverState *bs, | ||
522 | + QEMUIOVector *qiov, | ||
523 | + int64_t pos); | ||
524 | + | ||
525 | + int (*bdrv_change_backing_file)(BlockDriverState *bs, | ||
526 | + const char *backing_file, const char *backing_fmt); | ||
527 | + | ||
528 | + /* removable device specific */ | ||
529 | + bool (*bdrv_is_inserted)(BlockDriverState *bs); | ||
530 | + void (*bdrv_eject)(BlockDriverState *bs, bool eject_flag); | ||
531 | + void (*bdrv_lock_medium)(BlockDriverState *bs, bool locked); | ||
532 | + | ||
533 | + /* to control generic scsi devices */ | ||
534 | + BlockAIOCB *(*bdrv_aio_ioctl)(BlockDriverState *bs, | ||
535 | + unsigned long int req, void *buf, | ||
536 | + BlockCompletionFunc *cb, void *opaque); | ||
537 | + int coroutine_fn (*bdrv_co_ioctl)(BlockDriverState *bs, | ||
538 | + unsigned long int req, void *buf); | ||
539 | + | ||
540 | + /* List of options for creating images, terminated by name == NULL */ | ||
541 | + QemuOptsList *create_opts; | ||
542 | + | ||
543 | + /* List of options for image amend */ | ||
544 | + QemuOptsList *amend_opts; | ||
545 | + | ||
546 | + /* | ||
547 | + * If this driver supports reopening images this contains a | ||
548 | + * NULL-terminated list of the runtime options that can be | ||
549 | + * modified. If an option in this list is unspecified during | ||
550 | + * reopen then it _must_ be reset to its default value or return | ||
551 | + * an error. | ||
552 | + */ | ||
553 | + const char *const *mutable_opts; | ||
554 | + | ||
555 | + /* | ||
556 | + * Returns 0 for completed check, -errno for internal errors. | ||
557 | + * The check results are stored in result. | ||
558 | + */ | ||
559 | + int coroutine_fn (*bdrv_co_check)(BlockDriverState *bs, | ||
560 | + BdrvCheckResult *result, | ||
561 | + BdrvCheckMode fix); | ||
562 | + | ||
563 | + void (*bdrv_debug_event)(BlockDriverState *bs, BlkdebugEvent event); | ||
564 | + | ||
565 | + /* TODO Better pass a option string/QDict/QemuOpts to add any rule? */ | ||
566 | + int (*bdrv_debug_breakpoint)(BlockDriverState *bs, const char *event, | ||
567 | + const char *tag); | ||
568 | + int (*bdrv_debug_remove_breakpoint)(BlockDriverState *bs, | ||
569 | + const char *tag); | ||
570 | + int (*bdrv_debug_resume)(BlockDriverState *bs, const char *tag); | ||
571 | + bool (*bdrv_debug_is_suspended)(BlockDriverState *bs, const char *tag); | ||
572 | + | ||
573 | + void (*bdrv_refresh_limits)(BlockDriverState *bs, Error **errp); | ||
574 | + | ||
575 | + /* | ||
576 | + * Returns 1 if newly created images are guaranteed to contain only | ||
577 | + * zeros, 0 otherwise. | ||
578 | + */ | ||
579 | + int (*bdrv_has_zero_init)(BlockDriverState *bs); | ||
580 | + | ||
581 | + /* | ||
582 | + * Remove fd handlers, timers, and other event loop callbacks so the event | ||
583 | + * loop is no longer in use. Called with no in-flight requests and in | ||
584 | + * depth-first traversal order with parents before child nodes. | ||
585 | + */ | ||
586 | + void (*bdrv_detach_aio_context)(BlockDriverState *bs); | ||
587 | + | ||
588 | + /* | ||
589 | + * Add fd handlers, timers, and other event loop callbacks so I/O requests | ||
590 | + * can be processed again. Called with no in-flight requests and in | ||
591 | + * depth-first traversal order with child nodes before parent nodes. | ||
592 | + */ | ||
593 | + void (*bdrv_attach_aio_context)(BlockDriverState *bs, | ||
594 | + AioContext *new_context); | ||
595 | + | ||
596 | + /* io queue for linux-aio */ | ||
597 | + void (*bdrv_io_plug)(BlockDriverState *bs); | ||
598 | + void (*bdrv_io_unplug)(BlockDriverState *bs); | ||
599 | + | ||
600 | + /** | ||
601 | + * Try to get @bs's logical and physical block size. | ||
602 | + * On success, store them in @bsz and return zero. | ||
603 | + * On failure, return negative errno. | ||
604 | + */ | ||
605 | + int (*bdrv_probe_blocksizes)(BlockDriverState *bs, BlockSizes *bsz); | ||
606 | + /** | ||
607 | + * Try to get @bs's geometry (cyls, heads, sectors) | ||
608 | + * On success, store them in @geo and return 0. | ||
609 | + * On failure return -errno. | ||
610 | + * Only drivers that want to override guest geometry implement this | ||
611 | + * callback; see hd_geometry_guess(). | ||
612 | + */ | ||
613 | + int (*bdrv_probe_geometry)(BlockDriverState *bs, HDGeometry *geo); | ||
614 | + | ||
615 | + /** | ||
616 | + * bdrv_co_drain_begin is called if implemented in the beginning of a | ||
617 | + * drain operation to drain and stop any internal sources of requests in | ||
618 | + * the driver. | ||
619 | + * bdrv_co_drain_end is called if implemented at the end of the drain. | ||
620 | + * | ||
621 | + * They should be used by the driver to e.g. manage scheduled I/O | ||
622 | + * requests, or toggle an internal state. After the end of the drain new | ||
623 | + * requests will continue normally. | ||
624 | + */ | ||
625 | + void coroutine_fn (*bdrv_co_drain_begin)(BlockDriverState *bs); | ||
626 | + void coroutine_fn (*bdrv_co_drain_end)(BlockDriverState *bs); | ||
627 | + | ||
628 | + void (*bdrv_add_child)(BlockDriverState *parent, BlockDriverState *child, | ||
629 | + Error **errp); | ||
630 | + void (*bdrv_del_child)(BlockDriverState *parent, BdrvChild *child, | ||
631 | + Error **errp); | ||
632 | + | ||
633 | + /** | ||
634 | + * Informs the block driver that a permission change is intended. The | ||
635 | + * driver checks whether the change is permissible and may take other | ||
636 | + * preparations for the change (e.g. get file system locks). This operation | ||
637 | + * is always followed either by a call to either .bdrv_set_perm or | ||
638 | + * .bdrv_abort_perm_update. | ||
639 | + * | ||
640 | + * Checks whether the requested set of cumulative permissions in @perm | ||
641 | + * can be granted for accessing @bs and whether no other users are using | ||
642 | + * permissions other than those given in @shared (both arguments take | ||
643 | + * BLK_PERM_* bitmasks). | ||
644 | + * | ||
645 | + * If both conditions are met, 0 is returned. Otherwise, -errno is returned | ||
646 | + * and errp is set to an error describing the conflict. | ||
647 | + */ | ||
648 | + int (*bdrv_check_perm)(BlockDriverState *bs, uint64_t perm, | ||
649 | + uint64_t shared, Error **errp); | ||
650 | + | ||
651 | + /** | ||
652 | + * Called to inform the driver that the set of cumulative set of used | ||
653 | + * permissions for @bs has changed to @perm, and the set of sharable | ||
654 | + * permission to @shared. The driver can use this to propagate changes to | ||
655 | + * its children (i.e. request permissions only if a parent actually needs | ||
656 | + * them). | ||
657 | + * | ||
658 | + * This function is only invoked after bdrv_check_perm(), so block drivers | ||
659 | + * may rely on preparations made in their .bdrv_check_perm implementation. | ||
660 | + */ | ||
661 | + void (*bdrv_set_perm)(BlockDriverState *bs, uint64_t perm, uint64_t shared); | ||
662 | + | ||
663 | + /* | ||
664 | + * Called to inform the driver that after a previous bdrv_check_perm() | ||
665 | + * call, the permission update is not performed and any preparations made | ||
666 | + * for it (e.g. taken file locks) need to be undone. | ||
667 | + * | ||
668 | + * This function can be called even for nodes that never saw a | ||
669 | + * bdrv_check_perm() call. It is a no-op then. | ||
670 | + */ | ||
671 | + void (*bdrv_abort_perm_update)(BlockDriverState *bs); | ||
672 | + | ||
673 | + /** | ||
674 | + * Returns in @nperm and @nshared the permissions that the driver for @bs | ||
675 | + * needs on its child @c, based on the cumulative permissions requested by | ||
676 | + * the parents in @parent_perm and @parent_shared. | ||
677 | + * | ||
678 | + * If @c is NULL, return the permissions for attaching a new child for the | ||
679 | + * given @child_class and @role. | ||
680 | + * | ||
681 | + * If @reopen_queue is non-NULL, don't return the currently needed | ||
682 | + * permissions, but those that will be needed after applying the | ||
683 | + * @reopen_queue. | ||
684 | + */ | ||
685 | + void (*bdrv_child_perm)(BlockDriverState *bs, BdrvChild *c, | ||
686 | + BdrvChildRole role, | ||
687 | + BlockReopenQueue *reopen_queue, | ||
688 | + uint64_t parent_perm, uint64_t parent_shared, | ||
689 | + uint64_t *nperm, uint64_t *nshared); | ||
690 | + | ||
691 | + bool (*bdrv_supports_persistent_dirty_bitmap)(BlockDriverState *bs); | ||
692 | + bool (*bdrv_co_can_store_new_dirty_bitmap)(BlockDriverState *bs, | ||
693 | + const char *name, | ||
694 | + uint32_t granularity, | ||
695 | + Error **errp); | ||
696 | + int (*bdrv_co_remove_persistent_dirty_bitmap)(BlockDriverState *bs, | ||
697 | + const char *name, | ||
698 | + Error **errp); | ||
699 | + | ||
700 | + /** | ||
701 | + * Register/unregister a buffer for I/O. For example, when the driver is | ||
702 | + * interested to know the memory areas that will later be used in iovs, so | ||
703 | + * that it can do IOMMU mapping with VFIO etc., in order to get better | ||
704 | + * performance. In the case of VFIO drivers, this callback is used to do | ||
705 | + * DMA mapping for hot buffers. | ||
706 | + */ | ||
707 | + void (*bdrv_register_buf)(BlockDriverState *bs, void *host, size_t size); | ||
708 | + void (*bdrv_unregister_buf)(BlockDriverState *bs, void *host); | ||
709 | + QLIST_ENTRY(BlockDriver) list; | ||
710 | + | ||
711 | + /* | ||
712 | + * Pointer to a NULL-terminated array of names of strong options | ||
713 | + * that can be specified for bdrv_open(). A strong option is one | ||
714 | + * that changes the data of a BDS. | ||
715 | + * If this pointer is NULL, the array is considered empty. | ||
716 | + * "filename" and "driver" are always considered strong. | ||
717 | + */ | ||
718 | + const char *const *strong_runtime_opts; | ||
719 | +}; | ||
720 | + | ||
721 | +static inline bool block_driver_can_compress(BlockDriver *drv) | ||
722 | +{ | 38 | +{ |
723 | + return drv->bdrv_co_pwritev_compressed || | 39 | + switch (drain_type) { |
724 | + drv->bdrv_co_pwritev_compressed_part; | 40 | + case BDRV_DRAIN_ALL: bdrv_drain_all_begin(); break; |
41 | + case BDRV_DRAIN: bdrv_drained_begin(bs); break; | ||
42 | + default: g_assert_not_reached(); | ||
43 | + } | ||
725 | +} | 44 | +} |
726 | + | 45 | + |
727 | +typedef struct BlockLimits { | 46 | +static void do_drain_end(enum drain_type drain_type, BlockDriverState *bs) |
728 | + /* | ||
729 | + * Alignment requirement, in bytes, for offset/length of I/O | ||
730 | + * requests. Must be a power of 2 less than INT_MAX; defaults to | ||
731 | + * 1 for drivers with modern byte interfaces, and to 512 | ||
732 | + * otherwise. | ||
733 | + */ | ||
734 | + uint32_t request_alignment; | ||
735 | + | ||
736 | + /* | ||
737 | + * Maximum number of bytes that can be discarded at once. Must be multiple | ||
738 | + * of pdiscard_alignment, but need not be power of 2. May be 0 if no | ||
739 | + * inherent 64-bit limit. | ||
740 | + */ | ||
741 | + int64_t max_pdiscard; | ||
742 | + | ||
743 | + /* | ||
744 | + * Optimal alignment for discard requests in bytes. A power of 2 | ||
745 | + * is best but not mandatory. Must be a multiple of | ||
746 | + * bl.request_alignment, and must be less than max_pdiscard if | ||
747 | + * that is set. May be 0 if bl.request_alignment is good enough | ||
748 | + */ | ||
749 | + uint32_t pdiscard_alignment; | ||
750 | + | ||
751 | + /* | ||
752 | + * Maximum number of bytes that can zeroized at once. Must be multiple of | ||
753 | + * pwrite_zeroes_alignment. 0 means no limit. | ||
754 | + */ | ||
755 | + int64_t max_pwrite_zeroes; | ||
756 | + | ||
757 | + /* | ||
758 | + * Optimal alignment for write zeroes requests in bytes. A power | ||
759 | + * of 2 is best but not mandatory. Must be a multiple of | ||
760 | + * bl.request_alignment, and must be less than max_pwrite_zeroes | ||
761 | + * if that is set. May be 0 if bl.request_alignment is good | ||
762 | + * enough | ||
763 | + */ | ||
764 | + uint32_t pwrite_zeroes_alignment; | ||
765 | + | ||
766 | + /* | ||
767 | + * Optimal transfer length in bytes. A power of 2 is best but not | ||
768 | + * mandatory. Must be a multiple of bl.request_alignment, or 0 if | ||
769 | + * no preferred size | ||
770 | + */ | ||
771 | + uint32_t opt_transfer; | ||
772 | + | ||
773 | + /* | ||
774 | + * Maximal transfer length in bytes. Need not be power of 2, but | ||
775 | + * must be multiple of opt_transfer and bl.request_alignment, or 0 | ||
776 | + * for no 32-bit limit. For now, anything larger than INT_MAX is | ||
777 | + * clamped down. | ||
778 | + */ | ||
779 | + uint32_t max_transfer; | ||
780 | + | ||
781 | + /* | ||
782 | + * Maximal hardware transfer length in bytes. Applies whenever | ||
783 | + * transfers to the device bypass the kernel I/O scheduler, for | ||
784 | + * example with SG_IO. If larger than max_transfer or if zero, | ||
785 | + * blk_get_max_hw_transfer will fall back to max_transfer. | ||
786 | + */ | ||
787 | + uint64_t max_hw_transfer; | ||
788 | + | ||
789 | + /* | ||
790 | + * Maximal number of scatter/gather elements allowed by the hardware. | ||
791 | + * Applies whenever transfers to the device bypass the kernel I/O | ||
792 | + * scheduler, for example with SG_IO. If larger than max_iov | ||
793 | + * or if zero, blk_get_max_hw_iov will fall back to max_iov. | ||
794 | + */ | ||
795 | + int max_hw_iov; | ||
796 | + | ||
797 | + | ||
798 | + /* memory alignment, in bytes so that no bounce buffer is needed */ | ||
799 | + size_t min_mem_alignment; | ||
800 | + | ||
801 | + /* memory alignment, in bytes, for bounce buffer */ | ||
802 | + size_t opt_mem_alignment; | ||
803 | + | ||
804 | + /* maximum number of iovec elements */ | ||
805 | + int max_iov; | ||
806 | +} BlockLimits; | ||
807 | + | ||
808 | +typedef struct BdrvOpBlocker BdrvOpBlocker; | ||
809 | + | ||
810 | +typedef struct BdrvAioNotifier { | ||
811 | + void (*attached_aio_context)(AioContext *new_context, void *opaque); | ||
812 | + void (*detach_aio_context)(void *opaque); | ||
813 | + | ||
814 | + void *opaque; | ||
815 | + bool deleted; | ||
816 | + | ||
817 | + QLIST_ENTRY(BdrvAioNotifier) list; | ||
818 | +} BdrvAioNotifier; | ||
819 | + | ||
820 | +struct BdrvChildClass { | ||
821 | + /* | ||
822 | + * If true, bdrv_replace_node() doesn't change the node this BdrvChild | ||
823 | + * points to. | ||
824 | + */ | ||
825 | + bool stay_at_node; | ||
826 | + | ||
827 | + /* | ||
828 | + * If true, the parent is a BlockDriverState and bdrv_next_all_states() | ||
829 | + * will return it. This information is used for drain_all, where every node | ||
830 | + * will be drained separately, so the drain only needs to be propagated to | ||
831 | + * non-BDS parents. | ||
832 | + */ | ||
833 | + bool parent_is_bds; | ||
834 | + | ||
835 | + void (*inherit_options)(BdrvChildRole role, bool parent_is_format, | ||
836 | + int *child_flags, QDict *child_options, | ||
837 | + int parent_flags, QDict *parent_options); | ||
838 | + | ||
839 | + void (*change_media)(BdrvChild *child, bool load); | ||
840 | + void (*resize)(BdrvChild *child); | ||
841 | + | ||
842 | + /* | ||
843 | + * Returns a name that is supposedly more useful for human users than the | ||
844 | + * node name for identifying the node in question (in particular, a BB | ||
845 | + * name), or NULL if the parent can't provide a better name. | ||
846 | + */ | ||
847 | + const char *(*get_name)(BdrvChild *child); | ||
848 | + | ||
849 | + /* | ||
850 | + * Returns a malloced string that describes the parent of the child for a | ||
851 | + * human reader. This could be a node-name, BlockBackend name, qdev ID or | ||
852 | + * QOM path of the device owning the BlockBackend, job type and ID etc. The | ||
853 | + * caller is responsible for freeing the memory. | ||
854 | + */ | ||
855 | + char *(*get_parent_desc)(BdrvChild *child); | ||
856 | + | ||
857 | + /* | ||
858 | + * If this pair of functions is implemented, the parent doesn't issue new | ||
859 | + * requests after returning from .drained_begin() until .drained_end() is | ||
860 | + * called. | ||
861 | + * | ||
862 | + * These functions must not change the graph (and therefore also must not | ||
863 | + * call aio_poll(), which could change the graph indirectly). | ||
864 | + * | ||
865 | + * If drained_end() schedules background operations, it must atomically | ||
866 | + * increment *drained_end_counter for each such operation and atomically | ||
867 | + * decrement it once the operation has settled. | ||
868 | + * | ||
869 | + * Note that this can be nested. If drained_begin() was called twice, new | ||
870 | + * I/O is allowed only after drained_end() was called twice, too. | ||
871 | + */ | ||
872 | + void (*drained_begin)(BdrvChild *child); | ||
873 | + void (*drained_end)(BdrvChild *child, int *drained_end_counter); | ||
874 | + | ||
875 | + /* | ||
876 | + * Returns whether the parent has pending requests for the child. This | ||
877 | + * callback is polled after .drained_begin() has been called until all | ||
878 | + * activity on the child has stopped. | ||
879 | + */ | ||
880 | + bool (*drained_poll)(BdrvChild *child); | ||
881 | + | ||
882 | + /* | ||
883 | + * Notifies the parent that the child has been activated/inactivated (e.g. | ||
884 | + * when migration is completing) and it can start/stop requesting | ||
885 | + * permissions and doing I/O on it. | ||
886 | + */ | ||
887 | + void (*activate)(BdrvChild *child, Error **errp); | ||
888 | + int (*inactivate)(BdrvChild *child); | ||
889 | + | ||
890 | + void (*attach)(BdrvChild *child); | ||
891 | + void (*detach)(BdrvChild *child); | ||
892 | + | ||
893 | + /* | ||
894 | + * Notifies the parent that the filename of its child has changed (e.g. | ||
895 | + * because the direct child was removed from the backing chain), so that it | ||
896 | + * can update its reference. | ||
897 | + */ | ||
898 | + int (*update_filename)(BdrvChild *child, BlockDriverState *new_base, | ||
899 | + const char *filename, Error **errp); | ||
900 | + | ||
901 | + bool (*can_set_aio_ctx)(BdrvChild *child, AioContext *ctx, | ||
902 | + GSList **ignore, Error **errp); | ||
903 | + void (*set_aio_ctx)(BdrvChild *child, AioContext *ctx, GSList **ignore); | ||
904 | + | ||
905 | + AioContext *(*get_parent_aio_context)(BdrvChild *child); | ||
906 | +}; | ||
907 | + | ||
908 | +extern const BdrvChildClass child_of_bds; | ||
909 | + | ||
910 | +struct BdrvChild { | ||
911 | + BlockDriverState *bs; | ||
912 | + char *name; | ||
913 | + const BdrvChildClass *klass; | ||
914 | + BdrvChildRole role; | ||
915 | + void *opaque; | ||
916 | + | ||
917 | + /** | ||
918 | + * Granted permissions for operating on this BdrvChild (BLK_PERM_* bitmask) | ||
919 | + */ | ||
920 | + uint64_t perm; | ||
921 | + | ||
922 | + /** | ||
923 | + * Permissions that can still be granted to other users of @bs while this | ||
924 | + * BdrvChild is still attached to it. (BLK_PERM_* bitmask) | ||
925 | + */ | ||
926 | + uint64_t shared_perm; | ||
927 | + | ||
928 | + /* | ||
929 | + * This link is frozen: the child can neither be replaced nor | ||
930 | + * detached from the parent. | ||
931 | + */ | ||
932 | + bool frozen; | ||
933 | + | ||
934 | + /* | ||
935 | + * How many times the parent of this child has been drained | ||
936 | + * (through klass->drained_*). | ||
937 | + * Usually, this is equal to bs->quiesce_counter (potentially | ||
938 | + * reduced by bdrv_drain_all_count). It may differ while the | ||
939 | + * child is entering or leaving a drained section. | ||
940 | + */ | ||
941 | + int parent_quiesce_counter; | ||
942 | + | ||
943 | + QLIST_ENTRY(BdrvChild) next; | ||
944 | + QLIST_ENTRY(BdrvChild) next_parent; | ||
945 | +}; | ||
946 | + | ||
947 | +/* | ||
948 | + * Allows bdrv_co_block_status() to cache one data region for a | ||
949 | + * protocol node. | ||
950 | + * | ||
951 | + * @valid: Whether the cache is valid (should be accessed with atomic | ||
952 | + * functions so this can be reset by RCU readers) | ||
953 | + * @data_start: Offset where we know (or strongly assume) is data | ||
954 | + * @data_end: Offset where the data region ends (which is not necessarily | ||
955 | + * the start of a zeroed region) | ||
956 | + */ | ||
957 | +typedef struct BdrvBlockStatusCache { | ||
958 | + struct rcu_head rcu; | ||
959 | + | ||
960 | + bool valid; | ||
961 | + int64_t data_start; | ||
962 | + int64_t data_end; | ||
963 | +} BdrvBlockStatusCache; | ||
964 | + | ||
965 | +struct BlockDriverState { | ||
966 | + /* | ||
967 | + * Protected by big QEMU lock or read-only after opening. No special | ||
968 | + * locking needed during I/O... | ||
969 | + */ | ||
970 | + int open_flags; /* flags used to open the file, re-used for re-open */ | ||
971 | + bool encrypted; /* if true, the media is encrypted */ | ||
972 | + bool sg; /* if true, the device is a /dev/sg* */ | ||
973 | + bool probed; /* if true, format was probed rather than specified */ | ||
974 | + bool force_share; /* if true, always allow all shared permissions */ | ||
975 | + bool implicit; /* if true, this filter node was automatically inserted */ | ||
976 | + | ||
977 | + BlockDriver *drv; /* NULL means no media */ | ||
978 | + void *opaque; | ||
979 | + | ||
980 | + AioContext *aio_context; /* event loop used for fd handlers, timers, etc */ | ||
981 | + /* | ||
982 | + * long-running tasks intended to always use the same AioContext as this | ||
983 | + * BDS may register themselves in this list to be notified of changes | ||
984 | + * regarding this BDS's context | ||
985 | + */ | ||
986 | + QLIST_HEAD(, BdrvAioNotifier) aio_notifiers; | ||
987 | + bool walking_aio_notifiers; /* to make removal during iteration safe */ | ||
988 | + | ||
989 | + char filename[PATH_MAX]; | ||
990 | + /* | ||
991 | + * If not empty, this image is a diff in relation to backing_file. | ||
992 | + * Note that this is the name given in the image header and | ||
993 | + * therefore may or may not be equal to .backing->bs->filename. | ||
994 | + * If this field contains a relative path, it is to be resolved | ||
995 | + * relatively to the overlay's location. | ||
996 | + */ | ||
997 | + char backing_file[PATH_MAX]; | ||
998 | + /* | ||
999 | + * The backing filename indicated by the image header. Contrary | ||
1000 | + * to backing_file, if we ever open this file, auto_backing_file | ||
1001 | + * is replaced by the resulting BDS's filename (i.e. after a | ||
1002 | + * bdrv_refresh_filename() run). | ||
1003 | + */ | ||
1004 | + char auto_backing_file[PATH_MAX]; | ||
1005 | + char backing_format[16]; /* if non-zero and backing_file exists */ | ||
1006 | + | ||
1007 | + QDict *full_open_options; | ||
1008 | + char exact_filename[PATH_MAX]; | ||
1009 | + | ||
1010 | + BdrvChild *backing; | ||
1011 | + BdrvChild *file; | ||
1012 | + | ||
1013 | + /* I/O Limits */ | ||
1014 | + BlockLimits bl; | ||
1015 | + | ||
1016 | + /* | ||
1017 | + * Flags honored during pread | ||
1018 | + */ | ||
1019 | + unsigned int supported_read_flags; | ||
1020 | + /* | ||
1021 | + * Flags honored during pwrite (so far: BDRV_REQ_FUA, | ||
1022 | + * BDRV_REQ_WRITE_UNCHANGED). | ||
1023 | + * If a driver does not support BDRV_REQ_WRITE_UNCHANGED, those | ||
1024 | + * writes will be issued as normal writes without the flag set. | ||
1025 | + * This is important to note for drivers that do not explicitly | ||
1026 | + * request a WRITE permission for their children and instead take | ||
1027 | + * the same permissions as their parent did (this is commonly what | ||
1028 | + * block filters do). Such drivers have to be aware that the | ||
1029 | + * parent may have taken a WRITE_UNCHANGED permission only and is | ||
1030 | + * issuing such requests. Drivers either must make sure that | ||
1031 | + * these requests do not result in plain WRITE accesses (usually | ||
1032 | + * by supporting BDRV_REQ_WRITE_UNCHANGED, and then forwarding | ||
1033 | + * every incoming write request as-is, including potentially that | ||
1034 | + * flag), or they have to explicitly take the WRITE permission for | ||
1035 | + * their children. | ||
1036 | + */ | ||
1037 | + unsigned int supported_write_flags; | ||
1038 | + /* | ||
1039 | + * Flags honored during pwrite_zeroes (so far: BDRV_REQ_FUA, | ||
1040 | + * BDRV_REQ_MAY_UNMAP, BDRV_REQ_WRITE_UNCHANGED) | ||
1041 | + */ | ||
1042 | + unsigned int supported_zero_flags; | ||
1043 | + /* | ||
1044 | + * Flags honoured during truncate (so far: BDRV_REQ_ZERO_WRITE). | ||
1045 | + * | ||
1046 | + * If BDRV_REQ_ZERO_WRITE is given, the truncate operation must make sure | ||
1047 | + * that any added space reads as all zeros. If this can't be guaranteed, | ||
1048 | + * the operation must fail. | ||
1049 | + */ | ||
1050 | + unsigned int supported_truncate_flags; | ||
1051 | + | ||
1052 | + /* the following member gives a name to every node on the bs graph. */ | ||
1053 | + char node_name[32]; | ||
1054 | + /* element of the list of named nodes building the graph */ | ||
1055 | + QTAILQ_ENTRY(BlockDriverState) node_list; | ||
1056 | + /* element of the list of all BlockDriverStates (all_bdrv_states) */ | ||
1057 | + QTAILQ_ENTRY(BlockDriverState) bs_list; | ||
1058 | + /* element of the list of monitor-owned BDS */ | ||
1059 | + QTAILQ_ENTRY(BlockDriverState) monitor_list; | ||
1060 | + int refcnt; | ||
1061 | + | ||
1062 | + /* operation blockers. Protected by BQL. */ | ||
1063 | + QLIST_HEAD(, BdrvOpBlocker) op_blockers[BLOCK_OP_TYPE_MAX]; | ||
1064 | + | ||
1065 | + /* | ||
1066 | + * The node that this node inherited default options from (and a reopen on | ||
1067 | + * which can affect this node by changing these defaults). This is always a | ||
1068 | + * parent node of this node. | ||
1069 | + */ | ||
1070 | + BlockDriverState *inherits_from; | ||
1071 | + QLIST_HEAD(, BdrvChild) children; | ||
1072 | + QLIST_HEAD(, BdrvChild) parents; | ||
1073 | + | ||
1074 | + QDict *options; | ||
1075 | + QDict *explicit_options; | ||
1076 | + BlockdevDetectZeroesOptions detect_zeroes; | ||
1077 | + | ||
1078 | + /* The error object in use for blocking operations on backing_hd */ | ||
1079 | + Error *backing_blocker; | ||
1080 | + | ||
1081 | + /* Protected by AioContext lock */ | ||
1082 | + | ||
1083 | + /* | ||
1084 | + * If we are reading a disk image, give its size in sectors. | ||
1085 | + * Generally read-only; it is written to by load_snapshot and | ||
1086 | + * save_snaphost, but the block layer is quiescent during those. | ||
1087 | + */ | ||
1088 | + int64_t total_sectors; | ||
1089 | + | ||
1090 | + /* threshold limit for writes, in bytes. "High water mark". */ | ||
1091 | + uint64_t write_threshold_offset; | ||
1092 | + | ||
1093 | + /* | ||
1094 | + * Writing to the list requires the BQL _and_ the dirty_bitmap_mutex. | ||
1095 | + * Reading from the list can be done with either the BQL or the | ||
1096 | + * dirty_bitmap_mutex. Modifying a bitmap only requires | ||
1097 | + * dirty_bitmap_mutex. | ||
1098 | + */ | ||
1099 | + QemuMutex dirty_bitmap_mutex; | ||
1100 | + QLIST_HEAD(, BdrvDirtyBitmap) dirty_bitmaps; | ||
1101 | + | ||
1102 | + /* Offset after the highest byte written to */ | ||
1103 | + Stat64 wr_highest_offset; | ||
1104 | + | ||
1105 | + /* | ||
1106 | + * If true, copy read backing sectors into image. Can be >1 if more | ||
1107 | + * than one client has requested copy-on-read. Accessed with atomic | ||
1108 | + * ops. | ||
1109 | + */ | ||
1110 | + int copy_on_read; | ||
1111 | + | ||
1112 | + /* | ||
1113 | + * number of in-flight requests; overall and serialising. | ||
1114 | + * Accessed with atomic ops. | ||
1115 | + */ | ||
1116 | + unsigned int in_flight; | ||
1117 | + unsigned int serialising_in_flight; | ||
1118 | + | ||
1119 | + /* | ||
1120 | + * counter for nested bdrv_io_plug. | ||
1121 | + * Accessed with atomic ops. | ||
1122 | + */ | ||
1123 | + unsigned io_plugged; | ||
1124 | + | ||
1125 | + /* do we need to tell the quest if we have a volatile write cache? */ | ||
1126 | + int enable_write_cache; | ||
1127 | + | ||
1128 | + /* Accessed with atomic ops. */ | ||
1129 | + int quiesce_counter; | ||
1130 | + int recursive_quiesce_counter; | ||
1131 | + | ||
1132 | + unsigned int write_gen; /* Current data generation */ | ||
1133 | + | ||
1134 | + /* Protected by reqs_lock. */ | ||
1135 | + CoMutex reqs_lock; | ||
1136 | + QLIST_HEAD(, BdrvTrackedRequest) tracked_requests; | ||
1137 | + CoQueue flush_queue; /* Serializing flush queue */ | ||
1138 | + bool active_flush_req; /* Flush request in flight? */ | ||
1139 | + | ||
1140 | + /* Only read/written by whoever has set active_flush_req to true. */ | ||
1141 | + unsigned int flushed_gen; /* Flushed write generation */ | ||
1142 | + | ||
1143 | + /* BdrvChild links to this node may never be frozen */ | ||
1144 | + bool never_freeze; | ||
1145 | + | ||
1146 | + /* Lock for block-status cache RCU writers */ | ||
1147 | + CoMutex bsc_modify_lock; | ||
1148 | + /* Always non-NULL, but must only be dereferenced under an RCU read guard */ | ||
1149 | + BdrvBlockStatusCache *block_status_cache; | ||
1150 | +}; | ||
1151 | + | ||
1152 | +struct BlockBackendRootState { | ||
1153 | + int open_flags; | ||
1154 | + BlockdevDetectZeroesOptions detect_zeroes; | ||
1155 | +}; | ||
1156 | + | ||
1157 | +typedef enum BlockMirrorBackingMode { | ||
1158 | + /* | ||
1159 | + * Reuse the existing backing chain from the source for the target. | ||
1160 | + * - sync=full: Set backing BDS to NULL. | ||
1161 | + * - sync=top: Use source's backing BDS. | ||
1162 | + * - sync=none: Use source as the backing BDS. | ||
1163 | + */ | ||
1164 | + MIRROR_SOURCE_BACKING_CHAIN, | ||
1165 | + | ||
1166 | + /* Open the target's backing chain completely anew */ | ||
1167 | + MIRROR_OPEN_BACKING_CHAIN, | ||
1168 | + | ||
1169 | + /* Do not change the target's backing BDS after job completion */ | ||
1170 | + MIRROR_LEAVE_BACKING_CHAIN, | ||
1171 | +} BlockMirrorBackingMode; | ||
1172 | + | ||
1173 | + | ||
1174 | +/* | ||
1175 | + * Essential block drivers which must always be statically linked into qemu, and | ||
1176 | + * which therefore can be accessed without using bdrv_find_format() | ||
1177 | + */ | ||
1178 | +extern BlockDriver bdrv_file; | ||
1179 | +extern BlockDriver bdrv_raw; | ||
1180 | +extern BlockDriver bdrv_qcow2; | ||
1181 | + | ||
1182 | +extern unsigned int bdrv_drain_all_count; | ||
1183 | +extern QemuOptsList bdrv_create_opts_simple; | ||
1184 | + | ||
1185 | +/* | ||
1186 | + * Common functions that are neither I/O nor Global State. | ||
1187 | + * | ||
1188 | + * See include/block/block-commmon.h for more information about | ||
1189 | + * the Common API. | ||
1190 | + */ | ||
1191 | + | ||
1192 | +static inline BlockDriverState *child_bs(BdrvChild *child) | ||
1193 | +{ | 47 | +{ |
1194 | + return child ? child->bs : NULL; | 48 | + switch (drain_type) { |
49 | + case BDRV_DRAIN_ALL: bdrv_drain_all_end(); break; | ||
50 | + case BDRV_DRAIN: bdrv_drained_end(bs); break; | ||
51 | + default: g_assert_not_reached(); | ||
52 | + } | ||
1195 | +} | 53 | +} |
1196 | + | 54 | + |
1197 | +int bdrv_check_request(int64_t offset, int64_t bytes, Error **errp); | 55 | +static void test_drv_cb_common(enum drain_type drain_type, bool recursive) |
1198 | +int get_tmp_filename(char *filename, int size); | 56 | { |
1199 | +void bdrv_parse_filename_strip_prefix(const char *filename, const char *prefix, | 57 | BlockBackend *blk; |
1200 | + QDict *options); | 58 | - BlockDriverState *bs; |
59 | - BDRVTestState *s; | ||
60 | + BlockDriverState *bs, *backing; | ||
61 | + BDRVTestState *s, *backing_s; | ||
62 | BlockAIOCB *acb; | ||
63 | int aio_ret; | ||
64 | |||
65 | @@ -XXX,XX +XXX,XX @@ static void test_drv_cb_drain_all(void) | ||
66 | s = bs->opaque; | ||
67 | blk_insert_bs(blk, bs, &error_abort); | ||
68 | |||
69 | + backing = bdrv_new_open_driver(&bdrv_test, "backing", 0, &error_abort); | ||
70 | + backing_s = backing->opaque; | ||
71 | + bdrv_set_backing_hd(bs, backing, &error_abort); | ||
1201 | + | 72 | + |
73 | /* Simple bdrv_drain_all_begin/end pair, check that CBs are called */ | ||
74 | g_assert_cmpint(s->drain_count, ==, 0); | ||
75 | - bdrv_drain_all_begin(); | ||
76 | + g_assert_cmpint(backing_s->drain_count, ==, 0); | ||
1202 | + | 77 | + |
1203 | +int bdrv_check_qiov_request(int64_t offset, int64_t bytes, | 78 | + do_drain_begin(drain_type, bs); |
1204 | + QEMUIOVector *qiov, size_t qiov_offset, | ||
1205 | + Error **errp); | ||
1206 | + | 79 | + |
1207 | +#ifdef _WIN32 | 80 | g_assert_cmpint(s->drain_count, ==, 1); |
1208 | +int is_windows_drive(const char *filename); | 81 | - bdrv_drain_all_end(); |
1209 | +#endif | 82 | + g_assert_cmpint(backing_s->drain_count, ==, !!recursive); |
1210 | + | 83 | + |
1211 | +#endif /* BLOCK_INT_COMMON_H */ | 84 | + do_drain_end(drain_type, bs); |
1212 | diff --git a/include/block/block_int-global-state.h b/include/block/block_int-global-state.h | ||
1213 | new file mode 100644 | ||
1214 | index XXXXXXX..XXXXXXX | ||
1215 | --- /dev/null | ||
1216 | +++ b/include/block/block_int-global-state.h | ||
1217 | @@ -XXX,XX +XXX,XX @@ | ||
1218 | +/* | ||
1219 | + * QEMU System Emulator block driver | ||
1220 | + * | ||
1221 | + * Copyright (c) 2003 Fabrice Bellard | ||
1222 | + * | ||
1223 | + * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
1224 | + * of this software and associated documentation files (the "Software"), to deal | ||
1225 | + * in the Software without restriction, including without limitation the rights | ||
1226 | + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
1227 | + * copies of the Software, and to permit persons to whom the Software is | ||
1228 | + * furnished to do so, subject to the following conditions: | ||
1229 | + * | ||
1230 | + * The above copyright notice and this permission notice shall be included in | ||
1231 | + * all copies or substantial portions of the Software. | ||
1232 | + * | ||
1233 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
1234 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
1235 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
1236 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
1237 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
1238 | + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
1239 | + * THE SOFTWARE. | ||
1240 | + */ | ||
1241 | +#ifndef BLOCK_INT_GLOBAL_STATE_H | ||
1242 | +#define BLOCK_INT_GLOBAL_STATE_H | ||
1243 | + | 85 | + |
1244 | +#include "block_int-common.h" | 86 | g_assert_cmpint(s->drain_count, ==, 0); |
87 | + g_assert_cmpint(backing_s->drain_count, ==, 0); | ||
88 | |||
89 | /* Now do the same while a request is pending */ | ||
90 | aio_ret = -EINPROGRESS; | ||
91 | @@ -XXX,XX +XXX,XX @@ static void test_drv_cb_drain_all(void) | ||
92 | g_assert_cmpint(aio_ret, ==, -EINPROGRESS); | ||
93 | |||
94 | g_assert_cmpint(s->drain_count, ==, 0); | ||
95 | - bdrv_drain_all_begin(); | ||
96 | + g_assert_cmpint(backing_s->drain_count, ==, 0); | ||
1245 | + | 97 | + |
1246 | +/* | 98 | + do_drain_begin(drain_type, bs); |
1247 | + * Global state (GS) API. These functions run under the BQL. | ||
1248 | + * | ||
1249 | + * See include/block/block-global-state.h for more information about | ||
1250 | + * the GS API. | ||
1251 | + */ | ||
1252 | + | 99 | + |
1253 | +/** | 100 | g_assert_cmpint(aio_ret, ==, 0); |
1254 | + * stream_start: | 101 | g_assert_cmpint(s->drain_count, ==, 1); |
1255 | + * @job_id: The id of the newly-created job, or %NULL to use the | 102 | - bdrv_drain_all_end(); |
1256 | + * device name of @bs. | 103 | + g_assert_cmpint(backing_s->drain_count, ==, !!recursive); |
1257 | + * @bs: Block device to operate on. | ||
1258 | + * @base: Block device that will become the new base, or %NULL to | ||
1259 | + * flatten the whole backing file chain onto @bs. | ||
1260 | + * @backing_file_str: The file name that will be written to @bs as the | ||
1261 | + * the new backing file if the job completes. Ignored if @base is %NULL. | ||
1262 | + * @creation_flags: Flags that control the behavior of the Job lifetime. | ||
1263 | + * See @BlockJobCreateFlags | ||
1264 | + * @speed: The maximum speed, in bytes per second, or 0 for unlimited. | ||
1265 | + * @on_error: The action to take upon error. | ||
1266 | + * @filter_node_name: The node name that should be assigned to the filter | ||
1267 | + * driver that the stream job inserts into the graph above | ||
1268 | + * @bs. NULL means that a node name should be autogenerated. | ||
1269 | + * @errp: Error object. | ||
1270 | + * | ||
1271 | + * Start a streaming operation on @bs. Clusters that are unallocated | ||
1272 | + * in @bs, but allocated in any image between @base and @bs (both | ||
1273 | + * exclusive) will be written to @bs. At the end of a successful | ||
1274 | + * streaming job, the backing file of @bs will be changed to | ||
1275 | + * @backing_file_str in the written image and to @base in the live | ||
1276 | + * BlockDriverState. | ||
1277 | + */ | ||
1278 | +void stream_start(const char *job_id, BlockDriverState *bs, | ||
1279 | + BlockDriverState *base, const char *backing_file_str, | ||
1280 | + BlockDriverState *bottom, | ||
1281 | + int creation_flags, int64_t speed, | ||
1282 | + BlockdevOnError on_error, | ||
1283 | + const char *filter_node_name, | ||
1284 | + Error **errp); | ||
1285 | + | 104 | + |
1286 | +/** | 105 | + do_drain_end(drain_type, bs); |
1287 | + * commit_start: | ||
1288 | + * @job_id: The id of the newly-created job, or %NULL to use the | ||
1289 | + * device name of @bs. | ||
1290 | + * @bs: Active block device. | ||
1291 | + * @top: Top block device to be committed. | ||
1292 | + * @base: Block device that will be written into, and become the new top. | ||
1293 | + * @creation_flags: Flags that control the behavior of the Job lifetime. | ||
1294 | + * See @BlockJobCreateFlags | ||
1295 | + * @speed: The maximum speed, in bytes per second, or 0 for unlimited. | ||
1296 | + * @on_error: The action to take upon error. | ||
1297 | + * @backing_file_str: String to use as the backing file in @top's overlay | ||
1298 | + * @filter_node_name: The node name that should be assigned to the filter | ||
1299 | + * driver that the commit job inserts into the graph above @top. NULL means | ||
1300 | + * that a node name should be autogenerated. | ||
1301 | + * @errp: Error object. | ||
1302 | + * | ||
1303 | + */ | ||
1304 | +void commit_start(const char *job_id, BlockDriverState *bs, | ||
1305 | + BlockDriverState *base, BlockDriverState *top, | ||
1306 | + int creation_flags, int64_t speed, | ||
1307 | + BlockdevOnError on_error, const char *backing_file_str, | ||
1308 | + const char *filter_node_name, Error **errp); | ||
1309 | +/** | ||
1310 | + * commit_active_start: | ||
1311 | + * @job_id: The id of the newly-created job, or %NULL to use the | ||
1312 | + * device name of @bs. | ||
1313 | + * @bs: Active block device to be committed. | ||
1314 | + * @base: Block device that will be written into, and become the new top. | ||
1315 | + * @creation_flags: Flags that control the behavior of the Job lifetime. | ||
1316 | + * See @BlockJobCreateFlags | ||
1317 | + * @speed: The maximum speed, in bytes per second, or 0 for unlimited. | ||
1318 | + * @on_error: The action to take upon error. | ||
1319 | + * @filter_node_name: The node name that should be assigned to the filter | ||
1320 | + * driver that the commit job inserts into the graph above @bs. NULL means that | ||
1321 | + * a node name should be autogenerated. | ||
1322 | + * @cb: Completion function for the job. | ||
1323 | + * @opaque: Opaque pointer value passed to @cb. | ||
1324 | + * @auto_complete: Auto complete the job. | ||
1325 | + * @errp: Error object. | ||
1326 | + * | ||
1327 | + */ | ||
1328 | +BlockJob *commit_active_start(const char *job_id, BlockDriverState *bs, | ||
1329 | + BlockDriverState *base, int creation_flags, | ||
1330 | + int64_t speed, BlockdevOnError on_error, | ||
1331 | + const char *filter_node_name, | ||
1332 | + BlockCompletionFunc *cb, void *opaque, | ||
1333 | + bool auto_complete, Error **errp); | ||
1334 | +/* | ||
1335 | + * mirror_start: | ||
1336 | + * @job_id: The id of the newly-created job, or %NULL to use the | ||
1337 | + * device name of @bs. | ||
1338 | + * @bs: Block device to operate on. | ||
1339 | + * @target: Block device to write to. | ||
1340 | + * @replaces: Block graph node name to replace once the mirror is done. Can | ||
1341 | + * only be used when full mirroring is selected. | ||
1342 | + * @creation_flags: Flags that control the behavior of the Job lifetime. | ||
1343 | + * See @BlockJobCreateFlags | ||
1344 | + * @speed: The maximum speed, in bytes per second, or 0 for unlimited. | ||
1345 | + * @granularity: The chosen granularity for the dirty bitmap. | ||
1346 | + * @buf_size: The amount of data that can be in flight at one time. | ||
1347 | + * @mode: Whether to collapse all images in the chain to the target. | ||
1348 | + * @backing_mode: How to establish the target's backing chain after completion. | ||
1349 | + * @zero_target: Whether the target should be explicitly zero-initialized | ||
1350 | + * @on_source_error: The action to take upon error reading from the source. | ||
1351 | + * @on_target_error: The action to take upon error writing to the target. | ||
1352 | + * @unmap: Whether to unmap target where source sectors only contain zeroes. | ||
1353 | + * @filter_node_name: The node name that should be assigned to the filter | ||
1354 | + * driver that the mirror job inserts into the graph above @bs. NULL means that | ||
1355 | + * a node name should be autogenerated. | ||
1356 | + * @copy_mode: When to trigger writes to the target. | ||
1357 | + * @errp: Error object. | ||
1358 | + * | ||
1359 | + * Start a mirroring operation on @bs. Clusters that are allocated | ||
1360 | + * in @bs will be written to @target until the job is cancelled or | ||
1361 | + * manually completed. At the end of a successful mirroring job, | ||
1362 | + * @bs will be switched to read from @target. | ||
1363 | + */ | ||
1364 | +void mirror_start(const char *job_id, BlockDriverState *bs, | ||
1365 | + BlockDriverState *target, const char *replaces, | ||
1366 | + int creation_flags, int64_t speed, | ||
1367 | + uint32_t granularity, int64_t buf_size, | ||
1368 | + MirrorSyncMode mode, BlockMirrorBackingMode backing_mode, | ||
1369 | + bool zero_target, | ||
1370 | + BlockdevOnError on_source_error, | ||
1371 | + BlockdevOnError on_target_error, | ||
1372 | + bool unmap, const char *filter_node_name, | ||
1373 | + MirrorCopyMode copy_mode, Error **errp); | ||
1374 | + | 106 | + |
1375 | +/* | 107 | g_assert_cmpint(s->drain_count, ==, 0); |
1376 | + * backup_job_create: | 108 | + g_assert_cmpint(backing_s->drain_count, ==, 0); |
1377 | + * @job_id: The id of the newly-created job, or %NULL to use the | 109 | |
1378 | + * device name of @bs. | 110 | + bdrv_unref(backing); |
1379 | + * @bs: Block device to operate on. | 111 | bdrv_unref(bs); |
1380 | + * @target: Block device to write to. | 112 | blk_unref(blk); |
1381 | + * @speed: The maximum speed, in bytes per second, or 0 for unlimited. | 113 | } |
1382 | + * @sync_mode: What parts of the disk image should be copied to the destination. | 114 | |
1383 | + * @sync_bitmap: The dirty bitmap if sync_mode is 'bitmap' or 'incremental' | 115 | +static void test_drv_cb_drain_all(void) |
1384 | + * @bitmap_mode: The bitmap synchronization policy to use. | ||
1385 | + * @perf: Performance options. All actual fields assumed to be present, | ||
1386 | + * all ".has_*" fields are ignored. | ||
1387 | + * @on_source_error: The action to take upon error reading from the source. | ||
1388 | + * @on_target_error: The action to take upon error writing to the target. | ||
1389 | + * @creation_flags: Flags that control the behavior of the Job lifetime. | ||
1390 | + * See @BlockJobCreateFlags | ||
1391 | + * @cb: Completion function for the job. | ||
1392 | + * @opaque: Opaque pointer value passed to @cb. | ||
1393 | + * @txn: Transaction that this job is part of (may be NULL). | ||
1394 | + * | ||
1395 | + * Create a backup operation on @bs. Clusters in @bs are written to @target | ||
1396 | + * until the job is cancelled or manually completed. | ||
1397 | + */ | ||
1398 | +BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, | ||
1399 | + BlockDriverState *target, int64_t speed, | ||
1400 | + MirrorSyncMode sync_mode, | ||
1401 | + BdrvDirtyBitmap *sync_bitmap, | ||
1402 | + BitmapSyncMode bitmap_mode, | ||
1403 | + bool compress, | ||
1404 | + const char *filter_node_name, | ||
1405 | + BackupPerf *perf, | ||
1406 | + BlockdevOnError on_source_error, | ||
1407 | + BlockdevOnError on_target_error, | ||
1408 | + int creation_flags, | ||
1409 | + BlockCompletionFunc *cb, void *opaque, | ||
1410 | + JobTxn *txn, Error **errp); | ||
1411 | + | ||
1412 | +BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs, | ||
1413 | + const char *child_name, | ||
1414 | + const BdrvChildClass *child_class, | ||
1415 | + BdrvChildRole child_role, | ||
1416 | + uint64_t perm, uint64_t shared_perm, | ||
1417 | + void *opaque, Error **errp); | ||
1418 | +void bdrv_root_unref_child(BdrvChild *child); | ||
1419 | + | ||
1420 | +void bdrv_get_cumulative_perm(BlockDriverState *bs, uint64_t *perm, | ||
1421 | + uint64_t *shared_perm); | ||
1422 | + | ||
1423 | +/** | ||
1424 | + * Sets a BdrvChild's permissions. Avoid if the parent is a BDS; use | ||
1425 | + * bdrv_child_refresh_perms() instead and make the parent's | ||
1426 | + * .bdrv_child_perm() implementation return the correct values. | ||
1427 | + */ | ||
1428 | +int bdrv_child_try_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared, | ||
1429 | + Error **errp); | ||
1430 | + | ||
1431 | +/** | ||
1432 | + * Calls bs->drv->bdrv_child_perm() and updates the child's permission | ||
1433 | + * masks with the result. | ||
1434 | + * Drivers should invoke this function whenever an event occurs that | ||
1435 | + * makes their .bdrv_child_perm() implementation return different | ||
1436 | + * values than before, but which will not result in the block layer | ||
1437 | + * automatically refreshing the permissions. | ||
1438 | + */ | ||
1439 | +int bdrv_child_refresh_perms(BlockDriverState *bs, BdrvChild *c, Error **errp); | ||
1440 | + | ||
1441 | +bool bdrv_recurse_can_replace(BlockDriverState *bs, | ||
1442 | + BlockDriverState *to_replace); | ||
1443 | + | ||
1444 | +/* | ||
1445 | + * Default implementation for BlockDriver.bdrv_child_perm() that can | ||
1446 | + * be used by block filters and image formats, as long as they use the | ||
1447 | + * child_of_bds child class and set an appropriate BdrvChildRole. | ||
1448 | + */ | ||
1449 | +void bdrv_default_perms(BlockDriverState *bs, BdrvChild *c, | ||
1450 | + BdrvChildRole role, BlockReopenQueue *reopen_queue, | ||
1451 | + uint64_t perm, uint64_t shared, | ||
1452 | + uint64_t *nperm, uint64_t *nshared); | ||
1453 | + | ||
1454 | +void blk_dev_change_media_cb(BlockBackend *blk, bool load, Error **errp); | ||
1455 | +bool blk_dev_has_removable_media(BlockBackend *blk); | ||
1456 | +void blk_dev_eject_request(BlockBackend *blk, bool force); | ||
1457 | +bool blk_dev_is_medium_locked(BlockBackend *blk); | ||
1458 | + | ||
1459 | +void bdrv_restore_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap *backup); | ||
1460 | + | ||
1461 | +void bdrv_set_monitor_owned(BlockDriverState *bs); | ||
1462 | + | ||
1463 | +void blockdev_close_all_bdrv_states(void); | ||
1464 | + | ||
1465 | +BlockDriverState *bds_tree_init(QDict *bs_opts, Error **errp); | ||
1466 | + | ||
1467 | +/** | ||
1468 | + * Simple implementation of bdrv_co_create_opts for protocol drivers | ||
1469 | + * which only support creation via opening a file | ||
1470 | + * (usually existing raw storage device) | ||
1471 | + */ | ||
1472 | +int coroutine_fn bdrv_co_create_opts_simple(BlockDriver *drv, | ||
1473 | + const char *filename, | ||
1474 | + QemuOpts *opts, | ||
1475 | + Error **errp); | ||
1476 | + | ||
1477 | +BdrvDirtyBitmap *block_dirty_bitmap_lookup(const char *node, | ||
1478 | + const char *name, | ||
1479 | + BlockDriverState **pbs, | ||
1480 | + Error **errp); | ||
1481 | +BdrvDirtyBitmap *block_dirty_bitmap_merge(const char *node, const char *target, | ||
1482 | + BlockDirtyBitmapMergeSourceList *bms, | ||
1483 | + HBitmap **backup, Error **errp); | ||
1484 | +BdrvDirtyBitmap *block_dirty_bitmap_remove(const char *node, const char *name, | ||
1485 | + bool release, | ||
1486 | + BlockDriverState **bitmap_bs, | ||
1487 | + Error **errp); | ||
1488 | + | ||
1489 | + | ||
1490 | +BlockDriverState *bdrv_skip_implicit_filters(BlockDriverState *bs); | ||
1491 | + | ||
1492 | +/** | ||
1493 | + * bdrv_add_aio_context_notifier: | ||
1494 | + * | ||
1495 | + * If a long-running job intends to be always run in the same AioContext as a | ||
1496 | + * certain BDS, it may use this function to be notified of changes regarding the | ||
1497 | + * association of the BDS to an AioContext. | ||
1498 | + * | ||
1499 | + * attached_aio_context() is called after the target BDS has been attached to a | ||
1500 | + * new AioContext; detach_aio_context() is called before the target BDS is being | ||
1501 | + * detached from its old AioContext. | ||
1502 | + */ | ||
1503 | +void bdrv_add_aio_context_notifier(BlockDriverState *bs, | ||
1504 | + void (*attached_aio_context)(AioContext *new_context, void *opaque), | ||
1505 | + void (*detach_aio_context)(void *opaque), void *opaque); | ||
1506 | + | ||
1507 | +/** | ||
1508 | + * bdrv_remove_aio_context_notifier: | ||
1509 | + * | ||
1510 | + * Unsubscribe of change notifications regarding the BDS's AioContext. The | ||
1511 | + * parameters given here have to be the same as those given to | ||
1512 | + * bdrv_add_aio_context_notifier(). | ||
1513 | + */ | ||
1514 | +void bdrv_remove_aio_context_notifier(BlockDriverState *bs, | ||
1515 | + void (*aio_context_attached)(AioContext *, | ||
1516 | + void *), | ||
1517 | + void (*aio_context_detached)(void *), | ||
1518 | + void *opaque); | ||
1519 | + | ||
1520 | +/** | ||
1521 | + * End all quiescent sections started by bdrv_drain_all_begin(). This is | ||
1522 | + * needed when deleting a BDS before bdrv_drain_all_end() is called. | ||
1523 | + * | ||
1524 | + * NOTE: this is an internal helper for bdrv_close() *only*. No one else | ||
1525 | + * should call it. | ||
1526 | + */ | ||
1527 | +void bdrv_drain_all_end_quiesce(BlockDriverState *bs); | ||
1528 | + | ||
1529 | +#endif /* BLOCK_INT_GLOBAL_STATE */ | ||
1530 | diff --git a/include/block/block_int-io.h b/include/block/block_int-io.h | ||
1531 | new file mode 100644 | ||
1532 | index XXXXXXX..XXXXXXX | ||
1533 | --- /dev/null | ||
1534 | +++ b/include/block/block_int-io.h | ||
1535 | @@ -XXX,XX +XXX,XX @@ | ||
1536 | +/* | ||
1537 | + * QEMU System Emulator block driver | ||
1538 | + * | ||
1539 | + * Copyright (c) 2003 Fabrice Bellard | ||
1540 | + * | ||
1541 | + * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
1542 | + * of this software and associated documentation files (the "Software"), to deal | ||
1543 | + * in the Software without restriction, including without limitation the rights | ||
1544 | + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
1545 | + * copies of the Software, and to permit persons to whom the Software is | ||
1546 | + * furnished to do so, subject to the following conditions: | ||
1547 | + * | ||
1548 | + * The above copyright notice and this permission notice shall be included in | ||
1549 | + * all copies or substantial portions of the Software. | ||
1550 | + * | ||
1551 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
1552 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
1553 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
1554 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
1555 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
1556 | + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
1557 | + * THE SOFTWARE. | ||
1558 | + */ | ||
1559 | +#ifndef BLOCK_INT_IO_H | ||
1560 | +#define BLOCK_INT_IO_H | ||
1561 | + | ||
1562 | +#include "block_int-common.h" | ||
1563 | + | ||
1564 | +/* | ||
1565 | + * I/O API functions. These functions are thread-safe. | ||
1566 | + * | ||
1567 | + * See include/block/block-io.h for more information about | ||
1568 | + * the I/O API. | ||
1569 | + */ | ||
1570 | + | ||
1571 | +int coroutine_fn bdrv_co_preadv(BdrvChild *child, | ||
1572 | + int64_t offset, int64_t bytes, QEMUIOVector *qiov, | ||
1573 | + BdrvRequestFlags flags); | ||
1574 | +int coroutine_fn bdrv_co_preadv_part(BdrvChild *child, | ||
1575 | + int64_t offset, int64_t bytes, | ||
1576 | + QEMUIOVector *qiov, size_t qiov_offset, BdrvRequestFlags flags); | ||
1577 | +int coroutine_fn bdrv_co_pwritev(BdrvChild *child, | ||
1578 | + int64_t offset, int64_t bytes, QEMUIOVector *qiov, | ||
1579 | + BdrvRequestFlags flags); | ||
1580 | +int coroutine_fn bdrv_co_pwritev_part(BdrvChild *child, | ||
1581 | + int64_t offset, int64_t bytes, | ||
1582 | + QEMUIOVector *qiov, size_t qiov_offset, BdrvRequestFlags flags); | ||
1583 | + | ||
1584 | +static inline int coroutine_fn bdrv_co_pread(BdrvChild *child, | ||
1585 | + int64_t offset, unsigned int bytes, void *buf, BdrvRequestFlags flags) | ||
1586 | +{ | 116 | +{ |
1587 | + QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes); | 117 | + test_drv_cb_common(BDRV_DRAIN_ALL, true); |
1588 | + | ||
1589 | + return bdrv_co_preadv(child, offset, bytes, &qiov, flags); | ||
1590 | +} | 118 | +} |
1591 | + | 119 | + |
1592 | +static inline int coroutine_fn bdrv_co_pwrite(BdrvChild *child, | 120 | +static void test_drv_cb_drain(void) |
1593 | + int64_t offset, unsigned int bytes, void *buf, BdrvRequestFlags flags) | ||
1594 | +{ | 121 | +{ |
1595 | + QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes); | 122 | + test_drv_cb_common(BDRV_DRAIN, false); |
1596 | + | ||
1597 | + return bdrv_co_pwritev(child, offset, bytes, &qiov, flags); | ||
1598 | +} | 123 | +} |
1599 | + | 124 | + |
1600 | +bool coroutine_fn bdrv_make_request_serialising(BdrvTrackedRequest *req, | 125 | int main(int argc, char **argv) |
1601 | + uint64_t align); | 126 | { |
1602 | +BdrvTrackedRequest *coroutine_fn bdrv_co_get_self_request(BlockDriverState *bs); | 127 | bdrv_init(); |
1603 | + | 128 | @@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv) |
1604 | +BlockDriver *bdrv_probe_all(const uint8_t *buf, int buf_size, | 129 | g_test_init(&argc, &argv, NULL); |
1605 | + const char *filename); | 130 | |
1606 | + | 131 | g_test_add_func("/bdrv-drain/driver-cb/drain_all", test_drv_cb_drain_all); |
1607 | +/** | 132 | + g_test_add_func("/bdrv-drain/driver-cb/drain", test_drv_cb_drain); |
1608 | + * bdrv_wakeup: | 133 | |
1609 | + * @bs: The BlockDriverState for which an I/O operation has been completed. | 134 | return g_test_run(); |
1610 | + * | 135 | } |
1611 | + * Wake up the main thread if it is waiting on BDRV_POLL_WHILE. During | ||
1612 | + * synchronous I/O on a BlockDriverState that is attached to another | ||
1613 | + * I/O thread, the main thread lets the I/O thread's event loop run, | ||
1614 | + * waiting for the I/O operation to complete. A bdrv_wakeup will wake | ||
1615 | + * up the main thread if necessary. | ||
1616 | + * | ||
1617 | + * Manual calls to bdrv_wakeup are rarely necessary, because | ||
1618 | + * bdrv_dec_in_flight already calls it. | ||
1619 | + */ | ||
1620 | +void bdrv_wakeup(BlockDriverState *bs); | ||
1621 | + | ||
1622 | +const char *bdrv_get_parent_name(const BlockDriverState *bs); | ||
1623 | +bool blk_dev_has_tray(BlockBackend *blk); | ||
1624 | +bool blk_dev_is_tray_open(BlockBackend *blk); | ||
1625 | + | ||
1626 | +void bdrv_set_dirty(BlockDriverState *bs, int64_t offset, int64_t bytes); | ||
1627 | + | ||
1628 | +void bdrv_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap **out); | ||
1629 | +bool bdrv_dirty_bitmap_merge_internal(BdrvDirtyBitmap *dest, | ||
1630 | + const BdrvDirtyBitmap *src, | ||
1631 | + HBitmap **backup, bool lock); | ||
1632 | + | ||
1633 | +void bdrv_inc_in_flight(BlockDriverState *bs); | ||
1634 | +void bdrv_dec_in_flight(BlockDriverState *bs); | ||
1635 | + | ||
1636 | +int coroutine_fn bdrv_co_copy_range_from(BdrvChild *src, int64_t src_offset, | ||
1637 | + BdrvChild *dst, int64_t dst_offset, | ||
1638 | + int64_t bytes, | ||
1639 | + BdrvRequestFlags read_flags, | ||
1640 | + BdrvRequestFlags write_flags); | ||
1641 | +int coroutine_fn bdrv_co_copy_range_to(BdrvChild *src, int64_t src_offset, | ||
1642 | + BdrvChild *dst, int64_t dst_offset, | ||
1643 | + int64_t bytes, | ||
1644 | + BdrvRequestFlags read_flags, | ||
1645 | + BdrvRequestFlags write_flags); | ||
1646 | + | ||
1647 | +int refresh_total_sectors(BlockDriverState *bs, int64_t hint); | ||
1648 | + | ||
1649 | +BdrvChild *bdrv_cow_child(BlockDriverState *bs); | ||
1650 | +BdrvChild *bdrv_filter_child(BlockDriverState *bs); | ||
1651 | +BdrvChild *bdrv_filter_or_cow_child(BlockDriverState *bs); | ||
1652 | +BdrvChild *bdrv_primary_child(BlockDriverState *bs); | ||
1653 | +BlockDriverState *bdrv_skip_filters(BlockDriverState *bs); | ||
1654 | +BlockDriverState *bdrv_backing_chain_next(BlockDriverState *bs); | ||
1655 | + | ||
1656 | +static inline BlockDriverState *bdrv_cow_bs(BlockDriverState *bs) | ||
1657 | +{ | ||
1658 | + return child_bs(bdrv_cow_child(bs)); | ||
1659 | +} | ||
1660 | + | ||
1661 | +static inline BlockDriverState *bdrv_filter_bs(BlockDriverState *bs) | ||
1662 | +{ | ||
1663 | + return child_bs(bdrv_filter_child(bs)); | ||
1664 | +} | ||
1665 | + | ||
1666 | +static inline BlockDriverState *bdrv_filter_or_cow_bs(BlockDriverState *bs) | ||
1667 | +{ | ||
1668 | + return child_bs(bdrv_filter_or_cow_child(bs)); | ||
1669 | +} | ||
1670 | + | ||
1671 | +static inline BlockDriverState *bdrv_primary_bs(BlockDriverState *bs) | ||
1672 | +{ | ||
1673 | + return child_bs(bdrv_primary_child(bs)); | ||
1674 | +} | ||
1675 | + | ||
1676 | +/** | ||
1677 | + * Check whether the given offset is in the cached block-status data | ||
1678 | + * region. | ||
1679 | + * | ||
1680 | + * If it is, and @pnum is not NULL, *pnum is set to | ||
1681 | + * `bsc.data_end - offset`, i.e. how many bytes, starting from | ||
1682 | + * @offset, are data (according to the cache). | ||
1683 | + * Otherwise, *pnum is not touched. | ||
1684 | + */ | ||
1685 | +bool bdrv_bsc_is_data(BlockDriverState *bs, int64_t offset, int64_t *pnum); | ||
1686 | + | ||
1687 | +/** | ||
1688 | + * If [offset, offset + bytes) overlaps with the currently cached | ||
1689 | + * block-status region, invalidate the cache. | ||
1690 | + * | ||
1691 | + * (To be used by I/O paths that cause data regions to be zero or | ||
1692 | + * holes.) | ||
1693 | + */ | ||
1694 | +void bdrv_bsc_invalidate_range(BlockDriverState *bs, | ||
1695 | + int64_t offset, int64_t bytes); | ||
1696 | + | ||
1697 | +/** | ||
1698 | + * Mark the range [offset, offset + bytes) as a data region. | ||
1699 | + */ | ||
1700 | +void bdrv_bsc_fill(BlockDriverState *bs, int64_t offset, int64_t bytes); | ||
1701 | + | ||
1702 | + | ||
1703 | +/* | ||
1704 | + * "I/O or GS" API functions. These functions can run without | ||
1705 | + * the BQL, but only in one specific iothread/main loop. | ||
1706 | + * | ||
1707 | + * See include/block/block-io.h for more information about | ||
1708 | + * the "I/O or GS" API. | ||
1709 | + */ | ||
1710 | + | ||
1711 | +void bdrv_apply_subtree_drain(BdrvChild *child, BlockDriverState *new_parent); | ||
1712 | +void bdrv_unapply_subtree_drain(BdrvChild *child, BlockDriverState *old_parent); | ||
1713 | + | ||
1714 | +#endif /* BLOCK_INT_IO_H */ | ||
1715 | diff --git a/include/block/block_int.h b/include/block/block_int.h | ||
1716 | index XXXXXXX..XXXXXXX 100644 | ||
1717 | --- a/include/block/block_int.h | ||
1718 | +++ b/include/block/block_int.h | ||
1719 | @@ -XXX,XX +XXX,XX @@ | ||
1720 | #ifndef BLOCK_INT_H | ||
1721 | #define BLOCK_INT_H | ||
1722 | |||
1723 | -#include "block/accounting.h" | ||
1724 | -#include "block/block.h" | ||
1725 | -#include "block/aio-wait.h" | ||
1726 | -#include "qemu/queue.h" | ||
1727 | -#include "qemu/coroutine.h" | ||
1728 | -#include "qemu/stats64.h" | ||
1729 | -#include "qemu/timer.h" | ||
1730 | -#include "qemu/hbitmap.h" | ||
1731 | -#include "block/snapshot.h" | ||
1732 | -#include "qemu/throttle.h" | ||
1733 | -#include "qemu/rcu.h" | ||
1734 | +#include "block_int-global-state.h" | ||
1735 | +#include "block_int-io.h" | ||
1736 | |||
1737 | -#define BLOCK_FLAG_LAZY_REFCOUNTS 8 | ||
1738 | - | ||
1739 | -#define BLOCK_OPT_SIZE "size" | ||
1740 | -#define BLOCK_OPT_ENCRYPT "encryption" | ||
1741 | -#define BLOCK_OPT_ENCRYPT_FORMAT "encrypt.format" | ||
1742 | -#define BLOCK_OPT_COMPAT6 "compat6" | ||
1743 | -#define BLOCK_OPT_HWVERSION "hwversion" | ||
1744 | -#define BLOCK_OPT_BACKING_FILE "backing_file" | ||
1745 | -#define BLOCK_OPT_BACKING_FMT "backing_fmt" | ||
1746 | -#define BLOCK_OPT_CLUSTER_SIZE "cluster_size" | ||
1747 | -#define BLOCK_OPT_TABLE_SIZE "table_size" | ||
1748 | -#define BLOCK_OPT_PREALLOC "preallocation" | ||
1749 | -#define BLOCK_OPT_SUBFMT "subformat" | ||
1750 | -#define BLOCK_OPT_COMPAT_LEVEL "compat" | ||
1751 | -#define BLOCK_OPT_LAZY_REFCOUNTS "lazy_refcounts" | ||
1752 | -#define BLOCK_OPT_ADAPTER_TYPE "adapter_type" | ||
1753 | -#define BLOCK_OPT_REDUNDANCY "redundancy" | ||
1754 | -#define BLOCK_OPT_NOCOW "nocow" | ||
1755 | -#define BLOCK_OPT_EXTENT_SIZE_HINT "extent_size_hint" | ||
1756 | -#define BLOCK_OPT_OBJECT_SIZE "object_size" | ||
1757 | -#define BLOCK_OPT_REFCOUNT_BITS "refcount_bits" | ||
1758 | -#define BLOCK_OPT_DATA_FILE "data_file" | ||
1759 | -#define BLOCK_OPT_DATA_FILE_RAW "data_file_raw" | ||
1760 | -#define BLOCK_OPT_COMPRESSION_TYPE "compression_type" | ||
1761 | -#define BLOCK_OPT_EXTL2 "extended_l2" | ||
1762 | - | ||
1763 | -#define BLOCK_PROBE_BUF_SIZE 512 | ||
1764 | - | ||
1765 | -enum BdrvTrackedRequestType { | ||
1766 | - BDRV_TRACKED_READ, | ||
1767 | - BDRV_TRACKED_WRITE, | ||
1768 | - BDRV_TRACKED_DISCARD, | ||
1769 | - BDRV_TRACKED_TRUNCATE, | ||
1770 | -}; | ||
1771 | - | ||
1772 | -/* | ||
1773 | - * That is not quite good that BdrvTrackedRequest structure is public, | ||
1774 | - * as block/io.c is very careful about incoming offset/bytes being | ||
1775 | - * correct. Be sure to assert bdrv_check_request() succeeded after any | ||
1776 | - * modification of BdrvTrackedRequest object out of block/io.c | ||
1777 | - */ | ||
1778 | -typedef struct BdrvTrackedRequest { | ||
1779 | - BlockDriverState *bs; | ||
1780 | - int64_t offset; | ||
1781 | - int64_t bytes; | ||
1782 | - enum BdrvTrackedRequestType type; | ||
1783 | - | ||
1784 | - bool serialising; | ||
1785 | - int64_t overlap_offset; | ||
1786 | - int64_t overlap_bytes; | ||
1787 | - | ||
1788 | - QLIST_ENTRY(BdrvTrackedRequest) list; | ||
1789 | - Coroutine *co; /* owner, used for deadlock detection */ | ||
1790 | - CoQueue wait_queue; /* coroutines blocked on this request */ | ||
1791 | - | ||
1792 | - struct BdrvTrackedRequest *waiting_for; | ||
1793 | -} BdrvTrackedRequest; | ||
1794 | - | ||
1795 | -int bdrv_check_qiov_request(int64_t offset, int64_t bytes, | ||
1796 | - QEMUIOVector *qiov, size_t qiov_offset, | ||
1797 | - Error **errp); | ||
1798 | -int bdrv_check_request(int64_t offset, int64_t bytes, Error **errp); | ||
1799 | - | ||
1800 | -struct BlockDriver { | ||
1801 | - const char *format_name; | ||
1802 | - int instance_size; | ||
1803 | - | ||
1804 | - /* set to true if the BlockDriver is a block filter. Block filters pass | ||
1805 | - * certain callbacks that refer to data (see block.c) to their bs->file | ||
1806 | - * or bs->backing (whichever one exists) if the driver doesn't implement | ||
1807 | - * them. Drivers that do not wish to forward must implement them and return | ||
1808 | - * -ENOTSUP. | ||
1809 | - * Note that filters are not allowed to modify data. | ||
1810 | - * | ||
1811 | - * Filters generally cannot have more than a single filtered child, | ||
1812 | - * because the data they present must at all times be the same as | ||
1813 | - * that on their filtered child. That would be impossible to | ||
1814 | - * achieve for multiple filtered children. | ||
1815 | - * (And this filtered child must then be bs->file or bs->backing.) | ||
1816 | - */ | ||
1817 | - bool is_filter; | ||
1818 | - /* | ||
1819 | - * Set to true if the BlockDriver is a format driver. Format nodes | ||
1820 | - * generally do not expect their children to be other format nodes | ||
1821 | - * (except for backing files), and so format probing is disabled | ||
1822 | - * on those children. | ||
1823 | - */ | ||
1824 | - bool is_format; | ||
1825 | - | ||
1826 | - /* | ||
1827 | - * This function is invoked under BQL before .bdrv_co_amend() | ||
1828 | - * (which in contrast does not necessarily run under the BQL) | ||
1829 | - * to allow driver-specific initialization code that requires | ||
1830 | - * the BQL, like setting up specific permission flags. | ||
1831 | - */ | ||
1832 | - int (*bdrv_amend_pre_run)(BlockDriverState *bs, Error **errp); | ||
1833 | - /* | ||
1834 | - * This function is invoked under BQL after .bdrv_co_amend() | ||
1835 | - * to allow cleaning up what was done in .bdrv_amend_pre_run(). | ||
1836 | - */ | ||
1837 | - void (*bdrv_amend_clean)(BlockDriverState *bs); | ||
1838 | - | ||
1839 | - /* | ||
1840 | - * Return true if @to_replace can be replaced by a BDS with the | ||
1841 | - * same data as @bs without it affecting @bs's behavior (that is, | ||
1842 | - * without it being visible to @bs's parents). | ||
1843 | - */ | ||
1844 | - bool (*bdrv_recurse_can_replace)(BlockDriverState *bs, | ||
1845 | - BlockDriverState *to_replace); | ||
1846 | - | ||
1847 | - int (*bdrv_probe)(const uint8_t *buf, int buf_size, const char *filename); | ||
1848 | - int (*bdrv_probe_device)(const char *filename); | ||
1849 | - | ||
1850 | - /* Any driver implementing this callback is expected to be able to handle | ||
1851 | - * NULL file names in its .bdrv_open() implementation */ | ||
1852 | - void (*bdrv_parse_filename)(const char *filename, QDict *options, Error **errp); | ||
1853 | - /* Drivers not implementing bdrv_parse_filename nor bdrv_open should have | ||
1854 | - * this field set to true, except ones that are defined only by their | ||
1855 | - * child's bs. | ||
1856 | - * An example of the last type will be the quorum block driver. | ||
1857 | - */ | ||
1858 | - bool bdrv_needs_filename; | ||
1859 | - | ||
1860 | - /* | ||
1861 | - * Set if a driver can support backing files. This also implies the | ||
1862 | - * following semantics: | ||
1863 | - * | ||
1864 | - * - Return status 0 of .bdrv_co_block_status means that corresponding | ||
1865 | - * blocks are not allocated in this layer of backing-chain | ||
1866 | - * - For such (unallocated) blocks, read will: | ||
1867 | - * - fill buffer with zeros if there is no backing file | ||
1868 | - * - read from the backing file otherwise, where the block layer | ||
1869 | - * takes care of reading zeros beyond EOF if backing file is short | ||
1870 | - */ | ||
1871 | - bool supports_backing; | ||
1872 | - | ||
1873 | - /* For handling image reopen for split or non-split files */ | ||
1874 | - int (*bdrv_reopen_prepare)(BDRVReopenState *reopen_state, | ||
1875 | - BlockReopenQueue *queue, Error **errp); | ||
1876 | - void (*bdrv_reopen_commit)(BDRVReopenState *reopen_state); | ||
1877 | - void (*bdrv_reopen_commit_post)(BDRVReopenState *reopen_state); | ||
1878 | - void (*bdrv_reopen_abort)(BDRVReopenState *reopen_state); | ||
1879 | - void (*bdrv_join_options)(QDict *options, QDict *old_options); | ||
1880 | - | ||
1881 | - int (*bdrv_open)(BlockDriverState *bs, QDict *options, int flags, | ||
1882 | - Error **errp); | ||
1883 | - | ||
1884 | - /* Protocol drivers should implement this instead of bdrv_open */ | ||
1885 | - int (*bdrv_file_open)(BlockDriverState *bs, QDict *options, int flags, | ||
1886 | - Error **errp); | ||
1887 | - void (*bdrv_close)(BlockDriverState *bs); | ||
1888 | - | ||
1889 | - | ||
1890 | - int coroutine_fn (*bdrv_co_create)(BlockdevCreateOptions *opts, | ||
1891 | - Error **errp); | ||
1892 | - int coroutine_fn (*bdrv_co_create_opts)(BlockDriver *drv, | ||
1893 | - const char *filename, | ||
1894 | - QemuOpts *opts, | ||
1895 | - Error **errp); | ||
1896 | - | ||
1897 | - int coroutine_fn (*bdrv_co_amend)(BlockDriverState *bs, | ||
1898 | - BlockdevAmendOptions *opts, | ||
1899 | - bool force, | ||
1900 | - Error **errp); | ||
1901 | - | ||
1902 | - int (*bdrv_amend_options)(BlockDriverState *bs, | ||
1903 | - QemuOpts *opts, | ||
1904 | - BlockDriverAmendStatusCB *status_cb, | ||
1905 | - void *cb_opaque, | ||
1906 | - bool force, | ||
1907 | - Error **errp); | ||
1908 | - | ||
1909 | - int (*bdrv_make_empty)(BlockDriverState *bs); | ||
1910 | - | ||
1911 | - /* | ||
1912 | - * Refreshes the bs->exact_filename field. If that is impossible, | ||
1913 | - * bs->exact_filename has to be left empty. | ||
1914 | - */ | ||
1915 | - void (*bdrv_refresh_filename)(BlockDriverState *bs); | ||
1916 | - | ||
1917 | - /* | ||
1918 | - * Gathers the open options for all children into @target. | ||
1919 | - * A simple format driver (without backing file support) might | ||
1920 | - * implement this function like this: | ||
1921 | - * | ||
1922 | - * QINCREF(bs->file->bs->full_open_options); | ||
1923 | - * qdict_put(target, "file", bs->file->bs->full_open_options); | ||
1924 | - * | ||
1925 | - * If not specified, the generic implementation will simply put | ||
1926 | - * all children's options under their respective name. | ||
1927 | - * | ||
1928 | - * @backing_overridden is true when bs->backing seems not to be | ||
1929 | - * the child that would result from opening bs->backing_file. | ||
1930 | - * Therefore, if it is true, the backing child's options should be | ||
1931 | - * gathered; otherwise, there is no need since the backing child | ||
1932 | - * is the one implied by the image header. | ||
1933 | - * | ||
1934 | - * Note that ideally this function would not be needed. Every | ||
1935 | - * block driver which implements it is probably doing something | ||
1936 | - * shady regarding its runtime option structure. | ||
1937 | - */ | ||
1938 | - void (*bdrv_gather_child_options)(BlockDriverState *bs, QDict *target, | ||
1939 | - bool backing_overridden); | ||
1940 | - | ||
1941 | - /* | ||
1942 | - * Returns an allocated string which is the directory name of this BDS: It | ||
1943 | - * will be used to make relative filenames absolute by prepending this | ||
1944 | - * function's return value to them. | ||
1945 | - */ | ||
1946 | - char *(*bdrv_dirname)(BlockDriverState *bs, Error **errp); | ||
1947 | - | ||
1948 | - /* aio */ | ||
1949 | - BlockAIOCB *(*bdrv_aio_preadv)(BlockDriverState *bs, | ||
1950 | - int64_t offset, int64_t bytes, QEMUIOVector *qiov, | ||
1951 | - BdrvRequestFlags flags, BlockCompletionFunc *cb, void *opaque); | ||
1952 | - BlockAIOCB *(*bdrv_aio_pwritev)(BlockDriverState *bs, | ||
1953 | - int64_t offset, int64_t bytes, QEMUIOVector *qiov, | ||
1954 | - BdrvRequestFlags flags, BlockCompletionFunc *cb, void *opaque); | ||
1955 | - BlockAIOCB *(*bdrv_aio_flush)(BlockDriverState *bs, | ||
1956 | - BlockCompletionFunc *cb, void *opaque); | ||
1957 | - BlockAIOCB *(*bdrv_aio_pdiscard)(BlockDriverState *bs, | ||
1958 | - int64_t offset, int bytes, | ||
1959 | - BlockCompletionFunc *cb, void *opaque); | ||
1960 | - | ||
1961 | - int coroutine_fn (*bdrv_co_readv)(BlockDriverState *bs, | ||
1962 | - int64_t sector_num, int nb_sectors, QEMUIOVector *qiov); | ||
1963 | - | ||
1964 | - /** | ||
1965 | - * @offset: position in bytes to read at | ||
1966 | - * @bytes: number of bytes to read | ||
1967 | - * @qiov: the buffers to fill with read data | ||
1968 | - * @flags: currently unused, always 0 | ||
1969 | - * | ||
1970 | - * @offset and @bytes will be a multiple of 'request_alignment', | ||
1971 | - * but the length of individual @qiov elements does not have to | ||
1972 | - * be a multiple. | ||
1973 | - * | ||
1974 | - * @bytes will always equal the total size of @qiov, and will be | ||
1975 | - * no larger than 'max_transfer'. | ||
1976 | - * | ||
1977 | - * The buffer in @qiov may point directly to guest memory. | ||
1978 | - */ | ||
1979 | - int coroutine_fn (*bdrv_co_preadv)(BlockDriverState *bs, | ||
1980 | - int64_t offset, int64_t bytes, QEMUIOVector *qiov, | ||
1981 | - BdrvRequestFlags flags); | ||
1982 | - int coroutine_fn (*bdrv_co_preadv_part)(BlockDriverState *bs, | ||
1983 | - int64_t offset, int64_t bytes, | ||
1984 | - QEMUIOVector *qiov, size_t qiov_offset, BdrvRequestFlags flags); | ||
1985 | - int coroutine_fn (*bdrv_co_writev)(BlockDriverState *bs, | ||
1986 | - int64_t sector_num, int nb_sectors, QEMUIOVector *qiov, int flags); | ||
1987 | - /** | ||
1988 | - * @offset: position in bytes to write at | ||
1989 | - * @bytes: number of bytes to write | ||
1990 | - * @qiov: the buffers containing data to write | ||
1991 | - * @flags: zero or more bits allowed by 'supported_write_flags' | ||
1992 | - * | ||
1993 | - * @offset and @bytes will be a multiple of 'request_alignment', | ||
1994 | - * but the length of individual @qiov elements does not have to | ||
1995 | - * be a multiple. | ||
1996 | - * | ||
1997 | - * @bytes will always equal the total size of @qiov, and will be | ||
1998 | - * no larger than 'max_transfer'. | ||
1999 | - * | ||
2000 | - * The buffer in @qiov may point directly to guest memory. | ||
2001 | - */ | ||
2002 | - int coroutine_fn (*bdrv_co_pwritev)(BlockDriverState *bs, | ||
2003 | - int64_t offset, int64_t bytes, QEMUIOVector *qiov, | ||
2004 | - BdrvRequestFlags flags); | ||
2005 | - int coroutine_fn (*bdrv_co_pwritev_part)(BlockDriverState *bs, | ||
2006 | - int64_t offset, int64_t bytes, QEMUIOVector *qiov, size_t qiov_offset, | ||
2007 | - BdrvRequestFlags flags); | ||
2008 | - | ||
2009 | - /* | ||
2010 | - * Efficiently zero a region of the disk image. Typically an image format | ||
2011 | - * would use a compact metadata representation to implement this. This | ||
2012 | - * function pointer may be NULL or return -ENOSUP and .bdrv_co_writev() | ||
2013 | - * will be called instead. | ||
2014 | - */ | ||
2015 | - int coroutine_fn (*bdrv_co_pwrite_zeroes)(BlockDriverState *bs, | ||
2016 | - int64_t offset, int64_t bytes, BdrvRequestFlags flags); | ||
2017 | - int coroutine_fn (*bdrv_co_pdiscard)(BlockDriverState *bs, | ||
2018 | - int64_t offset, int64_t bytes); | ||
2019 | - | ||
2020 | - /* Map [offset, offset + nbytes) range onto a child of @bs to copy from, | ||
2021 | - * and invoke bdrv_co_copy_range_from(child, ...), or invoke | ||
2022 | - * bdrv_co_copy_range_to() if @bs is the leaf child to copy data from. | ||
2023 | - * | ||
2024 | - * See the comment of bdrv_co_copy_range for the parameter and return value | ||
2025 | - * semantics. | ||
2026 | - */ | ||
2027 | - int coroutine_fn (*bdrv_co_copy_range_from)(BlockDriverState *bs, | ||
2028 | - BdrvChild *src, | ||
2029 | - int64_t offset, | ||
2030 | - BdrvChild *dst, | ||
2031 | - int64_t dst_offset, | ||
2032 | - int64_t bytes, | ||
2033 | - BdrvRequestFlags read_flags, | ||
2034 | - BdrvRequestFlags write_flags); | ||
2035 | - | ||
2036 | - /* Map [offset, offset + nbytes) range onto a child of bs to copy data to, | ||
2037 | - * and invoke bdrv_co_copy_range_to(child, src, ...), or perform the copy | ||
2038 | - * operation if @bs is the leaf and @src has the same BlockDriver. Return | ||
2039 | - * -ENOTSUP if @bs is the leaf but @src has a different BlockDriver. | ||
2040 | - * | ||
2041 | - * See the comment of bdrv_co_copy_range for the parameter and return value | ||
2042 | - * semantics. | ||
2043 | - */ | ||
2044 | - int coroutine_fn (*bdrv_co_copy_range_to)(BlockDriverState *bs, | ||
2045 | - BdrvChild *src, | ||
2046 | - int64_t src_offset, | ||
2047 | - BdrvChild *dst, | ||
2048 | - int64_t dst_offset, | ||
2049 | - int64_t bytes, | ||
2050 | - BdrvRequestFlags read_flags, | ||
2051 | - BdrvRequestFlags write_flags); | ||
2052 | - | ||
2053 | - /* | ||
2054 | - * Building block for bdrv_block_status[_above] and | ||
2055 | - * bdrv_is_allocated[_above]. The driver should answer only | ||
2056 | - * according to the current layer, and should only need to set | ||
2057 | - * BDRV_BLOCK_DATA, BDRV_BLOCK_ZERO, BDRV_BLOCK_OFFSET_VALID, | ||
2058 | - * and/or BDRV_BLOCK_RAW; if the current layer defers to a backing | ||
2059 | - * layer, the result should be 0 (and not BDRV_BLOCK_ZERO). See | ||
2060 | - * block.h for the overall meaning of the bits. As a hint, the | ||
2061 | - * flag want_zero is true if the caller cares more about precise | ||
2062 | - * mappings (favor accurate _OFFSET_VALID/_ZERO) or false for | ||
2063 | - * overall allocation (favor larger *pnum, perhaps by reporting | ||
2064 | - * _DATA instead of _ZERO). The block layer guarantees input | ||
2065 | - * clamped to bdrv_getlength() and aligned to request_alignment, | ||
2066 | - * as well as non-NULL pnum, map, and file; in turn, the driver | ||
2067 | - * must return an error or set pnum to an aligned non-zero value. | ||
2068 | - * | ||
2069 | - * Note that @bytes is just a hint on how big of a region the | ||
2070 | - * caller wants to inspect. It is not a limit on *pnum. | ||
2071 | - * Implementations are free to return larger values of *pnum if | ||
2072 | - * doing so does not incur a performance penalty. | ||
2073 | - * | ||
2074 | - * block/io.c's bdrv_co_block_status() will utilize an unclamped | ||
2075 | - * *pnum value for the block-status cache on protocol nodes, prior | ||
2076 | - * to clamping *pnum for return to its caller. | ||
2077 | - */ | ||
2078 | - int coroutine_fn (*bdrv_co_block_status)(BlockDriverState *bs, | ||
2079 | - bool want_zero, int64_t offset, int64_t bytes, int64_t *pnum, | ||
2080 | - int64_t *map, BlockDriverState **file); | ||
2081 | - | ||
2082 | - /* | ||
2083 | - * This informs the driver that we are no longer interested in the result | ||
2084 | - * of in-flight requests, so don't waste the time if possible. | ||
2085 | - * | ||
2086 | - * One example usage is to avoid waiting for an nbd target node reconnect | ||
2087 | - * timeout during job-cancel with force=true. | ||
2088 | - */ | ||
2089 | - void (*bdrv_cancel_in_flight)(BlockDriverState *bs); | ||
2090 | - | ||
2091 | - /* | ||
2092 | - * Invalidate any cached meta-data. | ||
2093 | - */ | ||
2094 | - void coroutine_fn (*bdrv_co_invalidate_cache)(BlockDriverState *bs, | ||
2095 | - Error **errp); | ||
2096 | - int (*bdrv_inactivate)(BlockDriverState *bs); | ||
2097 | - | ||
2098 | - /* | ||
2099 | - * Flushes all data for all layers by calling bdrv_co_flush for underlying | ||
2100 | - * layers, if needed. This function is needed for deterministic | ||
2101 | - * synchronization of the flush finishing callback. | ||
2102 | - */ | ||
2103 | - int coroutine_fn (*bdrv_co_flush)(BlockDriverState *bs); | ||
2104 | - | ||
2105 | - /* Delete a created file. */ | ||
2106 | - int coroutine_fn (*bdrv_co_delete_file)(BlockDriverState *bs, | ||
2107 | - Error **errp); | ||
2108 | - | ||
2109 | - /* | ||
2110 | - * Flushes all data that was already written to the OS all the way down to | ||
2111 | - * the disk (for example file-posix.c calls fsync()). | ||
2112 | - */ | ||
2113 | - int coroutine_fn (*bdrv_co_flush_to_disk)(BlockDriverState *bs); | ||
2114 | - | ||
2115 | - /* | ||
2116 | - * Flushes all internal caches to the OS. The data may still sit in a | ||
2117 | - * writeback cache of the host OS, but it will survive a crash of the qemu | ||
2118 | - * process. | ||
2119 | - */ | ||
2120 | - int coroutine_fn (*bdrv_co_flush_to_os)(BlockDriverState *bs); | ||
2121 | - | ||
2122 | - /* | ||
2123 | - * Drivers setting this field must be able to work with just a plain | ||
2124 | - * filename with '<protocol_name>:' as a prefix, and no other options. | ||
2125 | - * Options may be extracted from the filename by implementing | ||
2126 | - * bdrv_parse_filename. | ||
2127 | - */ | ||
2128 | - const char *protocol_name; | ||
2129 | - | ||
2130 | - /* | ||
2131 | - * Truncate @bs to @offset bytes using the given @prealloc mode | ||
2132 | - * when growing. Modes other than PREALLOC_MODE_OFF should be | ||
2133 | - * rejected when shrinking @bs. | ||
2134 | - * | ||
2135 | - * If @exact is true, @bs must be resized to exactly @offset. | ||
2136 | - * Otherwise, it is sufficient for @bs (if it is a host block | ||
2137 | - * device and thus there is no way to resize it) to be at least | ||
2138 | - * @offset bytes in length. | ||
2139 | - * | ||
2140 | - * If @exact is true and this function fails but would succeed | ||
2141 | - * with @exact = false, it should return -ENOTSUP. | ||
2142 | - */ | ||
2143 | - int coroutine_fn (*bdrv_co_truncate)(BlockDriverState *bs, int64_t offset, | ||
2144 | - bool exact, PreallocMode prealloc, | ||
2145 | - BdrvRequestFlags flags, Error **errp); | ||
2146 | - | ||
2147 | - int64_t (*bdrv_getlength)(BlockDriverState *bs); | ||
2148 | - bool has_variable_length; | ||
2149 | - int64_t (*bdrv_get_allocated_file_size)(BlockDriverState *bs); | ||
2150 | - BlockMeasureInfo *(*bdrv_measure)(QemuOpts *opts, BlockDriverState *in_bs, | ||
2151 | - Error **errp); | ||
2152 | - | ||
2153 | - int coroutine_fn (*bdrv_co_pwritev_compressed)(BlockDriverState *bs, | ||
2154 | - int64_t offset, int64_t bytes, QEMUIOVector *qiov); | ||
2155 | - int coroutine_fn (*bdrv_co_pwritev_compressed_part)(BlockDriverState *bs, | ||
2156 | - int64_t offset, int64_t bytes, QEMUIOVector *qiov, size_t qiov_offset); | ||
2157 | - | ||
2158 | - int (*bdrv_snapshot_create)(BlockDriverState *bs, | ||
2159 | - QEMUSnapshotInfo *sn_info); | ||
2160 | - int (*bdrv_snapshot_goto)(BlockDriverState *bs, | ||
2161 | - const char *snapshot_id); | ||
2162 | - int (*bdrv_snapshot_delete)(BlockDriverState *bs, | ||
2163 | - const char *snapshot_id, | ||
2164 | - const char *name, | ||
2165 | - Error **errp); | ||
2166 | - int (*bdrv_snapshot_list)(BlockDriverState *bs, | ||
2167 | - QEMUSnapshotInfo **psn_info); | ||
2168 | - int (*bdrv_snapshot_load_tmp)(BlockDriverState *bs, | ||
2169 | - const char *snapshot_id, | ||
2170 | - const char *name, | ||
2171 | - Error **errp); | ||
2172 | - int (*bdrv_get_info)(BlockDriverState *bs, BlockDriverInfo *bdi); | ||
2173 | - ImageInfoSpecific *(*bdrv_get_specific_info)(BlockDriverState *bs, | ||
2174 | - Error **errp); | ||
2175 | - BlockStatsSpecific *(*bdrv_get_specific_stats)(BlockDriverState *bs); | ||
2176 | - | ||
2177 | - int coroutine_fn (*bdrv_save_vmstate)(BlockDriverState *bs, | ||
2178 | - QEMUIOVector *qiov, | ||
2179 | - int64_t pos); | ||
2180 | - int coroutine_fn (*bdrv_load_vmstate)(BlockDriverState *bs, | ||
2181 | - QEMUIOVector *qiov, | ||
2182 | - int64_t pos); | ||
2183 | - | ||
2184 | - int (*bdrv_change_backing_file)(BlockDriverState *bs, | ||
2185 | - const char *backing_file, const char *backing_fmt); | ||
2186 | - | ||
2187 | - /* removable device specific */ | ||
2188 | - bool (*bdrv_is_inserted)(BlockDriverState *bs); | ||
2189 | - void (*bdrv_eject)(BlockDriverState *bs, bool eject_flag); | ||
2190 | - void (*bdrv_lock_medium)(BlockDriverState *bs, bool locked); | ||
2191 | - | ||
2192 | - /* to control generic scsi devices */ | ||
2193 | - BlockAIOCB *(*bdrv_aio_ioctl)(BlockDriverState *bs, | ||
2194 | - unsigned long int req, void *buf, | ||
2195 | - BlockCompletionFunc *cb, void *opaque); | ||
2196 | - int coroutine_fn (*bdrv_co_ioctl)(BlockDriverState *bs, | ||
2197 | - unsigned long int req, void *buf); | ||
2198 | - | ||
2199 | - /* List of options for creating images, terminated by name == NULL */ | ||
2200 | - QemuOptsList *create_opts; | ||
2201 | - | ||
2202 | - /* List of options for image amend */ | ||
2203 | - QemuOptsList *amend_opts; | ||
2204 | - | ||
2205 | - /* | ||
2206 | - * If this driver supports reopening images this contains a | ||
2207 | - * NULL-terminated list of the runtime options that can be | ||
2208 | - * modified. If an option in this list is unspecified during | ||
2209 | - * reopen then it _must_ be reset to its default value or return | ||
2210 | - * an error. | ||
2211 | - */ | ||
2212 | - const char *const *mutable_opts; | ||
2213 | - | ||
2214 | - /* | ||
2215 | - * Returns 0 for completed check, -errno for internal errors. | ||
2216 | - * The check results are stored in result. | ||
2217 | - */ | ||
2218 | - int coroutine_fn (*bdrv_co_check)(BlockDriverState *bs, | ||
2219 | - BdrvCheckResult *result, | ||
2220 | - BdrvCheckMode fix); | ||
2221 | - | ||
2222 | - void (*bdrv_debug_event)(BlockDriverState *bs, BlkdebugEvent event); | ||
2223 | - | ||
2224 | - /* TODO Better pass a option string/QDict/QemuOpts to add any rule? */ | ||
2225 | - int (*bdrv_debug_breakpoint)(BlockDriverState *bs, const char *event, | ||
2226 | - const char *tag); | ||
2227 | - int (*bdrv_debug_remove_breakpoint)(BlockDriverState *bs, | ||
2228 | - const char *tag); | ||
2229 | - int (*bdrv_debug_resume)(BlockDriverState *bs, const char *tag); | ||
2230 | - bool (*bdrv_debug_is_suspended)(BlockDriverState *bs, const char *tag); | ||
2231 | - | ||
2232 | - void (*bdrv_refresh_limits)(BlockDriverState *bs, Error **errp); | ||
2233 | - | ||
2234 | - /* | ||
2235 | - * Returns 1 if newly created images are guaranteed to contain only | ||
2236 | - * zeros, 0 otherwise. | ||
2237 | - */ | ||
2238 | - int (*bdrv_has_zero_init)(BlockDriverState *bs); | ||
2239 | - | ||
2240 | - /* Remove fd handlers, timers, and other event loop callbacks so the event | ||
2241 | - * loop is no longer in use. Called with no in-flight requests and in | ||
2242 | - * depth-first traversal order with parents before child nodes. | ||
2243 | - */ | ||
2244 | - void (*bdrv_detach_aio_context)(BlockDriverState *bs); | ||
2245 | - | ||
2246 | - /* Add fd handlers, timers, and other event loop callbacks so I/O requests | ||
2247 | - * can be processed again. Called with no in-flight requests and in | ||
2248 | - * depth-first traversal order with child nodes before parent nodes. | ||
2249 | - */ | ||
2250 | - void (*bdrv_attach_aio_context)(BlockDriverState *bs, | ||
2251 | - AioContext *new_context); | ||
2252 | - | ||
2253 | - /* io queue for linux-aio */ | ||
2254 | - void (*bdrv_io_plug)(BlockDriverState *bs); | ||
2255 | - void (*bdrv_io_unplug)(BlockDriverState *bs); | ||
2256 | - | ||
2257 | - /** | ||
2258 | - * Try to get @bs's logical and physical block size. | ||
2259 | - * On success, store them in @bsz and return zero. | ||
2260 | - * On failure, return negative errno. | ||
2261 | - */ | ||
2262 | - int (*bdrv_probe_blocksizes)(BlockDriverState *bs, BlockSizes *bsz); | ||
2263 | - /** | ||
2264 | - * Try to get @bs's geometry (cyls, heads, sectors) | ||
2265 | - * On success, store them in @geo and return 0. | ||
2266 | - * On failure return -errno. | ||
2267 | - * Only drivers that want to override guest geometry implement this | ||
2268 | - * callback; see hd_geometry_guess(). | ||
2269 | - */ | ||
2270 | - int (*bdrv_probe_geometry)(BlockDriverState *bs, HDGeometry *geo); | ||
2271 | - | ||
2272 | - /** | ||
2273 | - * bdrv_co_drain_begin is called if implemented in the beginning of a | ||
2274 | - * drain operation to drain and stop any internal sources of requests in | ||
2275 | - * the driver. | ||
2276 | - * bdrv_co_drain_end is called if implemented at the end of the drain. | ||
2277 | - * | ||
2278 | - * They should be used by the driver to e.g. manage scheduled I/O | ||
2279 | - * requests, or toggle an internal state. After the end of the drain new | ||
2280 | - * requests will continue normally. | ||
2281 | - */ | ||
2282 | - void coroutine_fn (*bdrv_co_drain_begin)(BlockDriverState *bs); | ||
2283 | - void coroutine_fn (*bdrv_co_drain_end)(BlockDriverState *bs); | ||
2284 | - | ||
2285 | - void (*bdrv_add_child)(BlockDriverState *parent, BlockDriverState *child, | ||
2286 | - Error **errp); | ||
2287 | - void (*bdrv_del_child)(BlockDriverState *parent, BdrvChild *child, | ||
2288 | - Error **errp); | ||
2289 | - | ||
2290 | - /** | ||
2291 | - * Informs the block driver that a permission change is intended. The | ||
2292 | - * driver checks whether the change is permissible and may take other | ||
2293 | - * preparations for the change (e.g. get file system locks). This operation | ||
2294 | - * is always followed either by a call to either .bdrv_set_perm or | ||
2295 | - * .bdrv_abort_perm_update. | ||
2296 | - * | ||
2297 | - * Checks whether the requested set of cumulative permissions in @perm | ||
2298 | - * can be granted for accessing @bs and whether no other users are using | ||
2299 | - * permissions other than those given in @shared (both arguments take | ||
2300 | - * BLK_PERM_* bitmasks). | ||
2301 | - * | ||
2302 | - * If both conditions are met, 0 is returned. Otherwise, -errno is returned | ||
2303 | - * and errp is set to an error describing the conflict. | ||
2304 | - */ | ||
2305 | - int (*bdrv_check_perm)(BlockDriverState *bs, uint64_t perm, | ||
2306 | - uint64_t shared, Error **errp); | ||
2307 | - | ||
2308 | - /** | ||
2309 | - * Called to inform the driver that the set of cumulative set of used | ||
2310 | - * permissions for @bs has changed to @perm, and the set of sharable | ||
2311 | - * permission to @shared. The driver can use this to propagate changes to | ||
2312 | - * its children (i.e. request permissions only if a parent actually needs | ||
2313 | - * them). | ||
2314 | - * | ||
2315 | - * This function is only invoked after bdrv_check_perm(), so block drivers | ||
2316 | - * may rely on preparations made in their .bdrv_check_perm implementation. | ||
2317 | - */ | ||
2318 | - void (*bdrv_set_perm)(BlockDriverState *bs, uint64_t perm, uint64_t shared); | ||
2319 | - | ||
2320 | - /* | ||
2321 | - * Called to inform the driver that after a previous bdrv_check_perm() | ||
2322 | - * call, the permission update is not performed and any preparations made | ||
2323 | - * for it (e.g. taken file locks) need to be undone. | ||
2324 | - * | ||
2325 | - * This function can be called even for nodes that never saw a | ||
2326 | - * bdrv_check_perm() call. It is a no-op then. | ||
2327 | - */ | ||
2328 | - void (*bdrv_abort_perm_update)(BlockDriverState *bs); | ||
2329 | - | ||
2330 | - /** | ||
2331 | - * Returns in @nperm and @nshared the permissions that the driver for @bs | ||
2332 | - * needs on its child @c, based on the cumulative permissions requested by | ||
2333 | - * the parents in @parent_perm and @parent_shared. | ||
2334 | - * | ||
2335 | - * If @c is NULL, return the permissions for attaching a new child for the | ||
2336 | - * given @child_class and @role. | ||
2337 | - * | ||
2338 | - * If @reopen_queue is non-NULL, don't return the currently needed | ||
2339 | - * permissions, but those that will be needed after applying the | ||
2340 | - * @reopen_queue. | ||
2341 | - */ | ||
2342 | - void (*bdrv_child_perm)(BlockDriverState *bs, BdrvChild *c, | ||
2343 | - BdrvChildRole role, | ||
2344 | - BlockReopenQueue *reopen_queue, | ||
2345 | - uint64_t parent_perm, uint64_t parent_shared, | ||
2346 | - uint64_t *nperm, uint64_t *nshared); | ||
2347 | - | ||
2348 | - bool (*bdrv_supports_persistent_dirty_bitmap)(BlockDriverState *bs); | ||
2349 | - bool (*bdrv_co_can_store_new_dirty_bitmap)(BlockDriverState *bs, | ||
2350 | - const char *name, | ||
2351 | - uint32_t granularity, | ||
2352 | - Error **errp); | ||
2353 | - int (*bdrv_co_remove_persistent_dirty_bitmap)(BlockDriverState *bs, | ||
2354 | - const char *name, | ||
2355 | - Error **errp); | ||
2356 | - | ||
2357 | - /** | ||
2358 | - * Register/unregister a buffer for I/O. For example, when the driver is | ||
2359 | - * interested to know the memory areas that will later be used in iovs, so | ||
2360 | - * that it can do IOMMU mapping with VFIO etc., in order to get better | ||
2361 | - * performance. In the case of VFIO drivers, this callback is used to do | ||
2362 | - * DMA mapping for hot buffers. | ||
2363 | - */ | ||
2364 | - void (*bdrv_register_buf)(BlockDriverState *bs, void *host, size_t size); | ||
2365 | - void (*bdrv_unregister_buf)(BlockDriverState *bs, void *host); | ||
2366 | - QLIST_ENTRY(BlockDriver) list; | ||
2367 | - | ||
2368 | - /* Pointer to a NULL-terminated array of names of strong options | ||
2369 | - * that can be specified for bdrv_open(). A strong option is one | ||
2370 | - * that changes the data of a BDS. | ||
2371 | - * If this pointer is NULL, the array is considered empty. | ||
2372 | - * "filename" and "driver" are always considered strong. */ | ||
2373 | - const char *const *strong_runtime_opts; | ||
2374 | -}; | ||
2375 | - | ||
2376 | -static inline bool block_driver_can_compress(BlockDriver *drv) | ||
2377 | -{ | ||
2378 | - return drv->bdrv_co_pwritev_compressed || | ||
2379 | - drv->bdrv_co_pwritev_compressed_part; | ||
2380 | -} | ||
2381 | - | ||
2382 | -typedef struct BlockLimits { | ||
2383 | - /* Alignment requirement, in bytes, for offset/length of I/O | ||
2384 | - * requests. Must be a power of 2 less than INT_MAX; defaults to | ||
2385 | - * 1 for drivers with modern byte interfaces, and to 512 | ||
2386 | - * otherwise. */ | ||
2387 | - uint32_t request_alignment; | ||
2388 | - | ||
2389 | - /* | ||
2390 | - * Maximum number of bytes that can be discarded at once. Must be multiple | ||
2391 | - * of pdiscard_alignment, but need not be power of 2. May be 0 if no | ||
2392 | - * inherent 64-bit limit. | ||
2393 | - */ | ||
2394 | - int64_t max_pdiscard; | ||
2395 | - | ||
2396 | - /* Optimal alignment for discard requests in bytes. A power of 2 | ||
2397 | - * is best but not mandatory. Must be a multiple of | ||
2398 | - * bl.request_alignment, and must be less than max_pdiscard if | ||
2399 | - * that is set. May be 0 if bl.request_alignment is good enough */ | ||
2400 | - uint32_t pdiscard_alignment; | ||
2401 | - | ||
2402 | - /* | ||
2403 | - * Maximum number of bytes that can zeroized at once. Must be multiple of | ||
2404 | - * pwrite_zeroes_alignment. 0 means no limit. | ||
2405 | - */ | ||
2406 | - int64_t max_pwrite_zeroes; | ||
2407 | - | ||
2408 | - /* Optimal alignment for write zeroes requests in bytes. A power | ||
2409 | - * of 2 is best but not mandatory. Must be a multiple of | ||
2410 | - * bl.request_alignment, and must be less than max_pwrite_zeroes | ||
2411 | - * if that is set. May be 0 if bl.request_alignment is good | ||
2412 | - * enough */ | ||
2413 | - uint32_t pwrite_zeroes_alignment; | ||
2414 | - | ||
2415 | - /* Optimal transfer length in bytes. A power of 2 is best but not | ||
2416 | - * mandatory. Must be a multiple of bl.request_alignment, or 0 if | ||
2417 | - * no preferred size */ | ||
2418 | - uint32_t opt_transfer; | ||
2419 | - | ||
2420 | - /* Maximal transfer length in bytes. Need not be power of 2, but | ||
2421 | - * must be multiple of opt_transfer and bl.request_alignment, or 0 | ||
2422 | - * for no 32-bit limit. For now, anything larger than INT_MAX is | ||
2423 | - * clamped down. */ | ||
2424 | - uint32_t max_transfer; | ||
2425 | - | ||
2426 | - /* Maximal hardware transfer length in bytes. Applies whenever | ||
2427 | - * transfers to the device bypass the kernel I/O scheduler, for | ||
2428 | - * example with SG_IO. If larger than max_transfer or if zero, | ||
2429 | - * blk_get_max_hw_transfer will fall back to max_transfer. | ||
2430 | - */ | ||
2431 | - uint64_t max_hw_transfer; | ||
2432 | - | ||
2433 | - /* Maximal number of scatter/gather elements allowed by the hardware. | ||
2434 | - * Applies whenever transfers to the device bypass the kernel I/O | ||
2435 | - * scheduler, for example with SG_IO. If larger than max_iov | ||
2436 | - * or if zero, blk_get_max_hw_iov will fall back to max_iov. | ||
2437 | - */ | ||
2438 | - int max_hw_iov; | ||
2439 | - | ||
2440 | - /* memory alignment, in bytes so that no bounce buffer is needed */ | ||
2441 | - size_t min_mem_alignment; | ||
2442 | - | ||
2443 | - /* memory alignment, in bytes, for bounce buffer */ | ||
2444 | - size_t opt_mem_alignment; | ||
2445 | - | ||
2446 | - /* maximum number of iovec elements */ | ||
2447 | - int max_iov; | ||
2448 | -} BlockLimits; | ||
2449 | - | ||
2450 | -typedef struct BdrvOpBlocker BdrvOpBlocker; | ||
2451 | - | ||
2452 | -typedef struct BdrvAioNotifier { | ||
2453 | - void (*attached_aio_context)(AioContext *new_context, void *opaque); | ||
2454 | - void (*detach_aio_context)(void *opaque); | ||
2455 | - | ||
2456 | - void *opaque; | ||
2457 | - bool deleted; | ||
2458 | - | ||
2459 | - QLIST_ENTRY(BdrvAioNotifier) list; | ||
2460 | -} BdrvAioNotifier; | ||
2461 | - | ||
2462 | -struct BdrvChildClass { | ||
2463 | - /* If true, bdrv_replace_node() doesn't change the node this BdrvChild | ||
2464 | - * points to. */ | ||
2465 | - bool stay_at_node; | ||
2466 | - | ||
2467 | - /* If true, the parent is a BlockDriverState and bdrv_next_all_states() | ||
2468 | - * will return it. This information is used for drain_all, where every node | ||
2469 | - * will be drained separately, so the drain only needs to be propagated to | ||
2470 | - * non-BDS parents. */ | ||
2471 | - bool parent_is_bds; | ||
2472 | - | ||
2473 | - void (*inherit_options)(BdrvChildRole role, bool parent_is_format, | ||
2474 | - int *child_flags, QDict *child_options, | ||
2475 | - int parent_flags, QDict *parent_options); | ||
2476 | - | ||
2477 | - void (*change_media)(BdrvChild *child, bool load); | ||
2478 | - void (*resize)(BdrvChild *child); | ||
2479 | - | ||
2480 | - /* Returns a name that is supposedly more useful for human users than the | ||
2481 | - * node name for identifying the node in question (in particular, a BB | ||
2482 | - * name), or NULL if the parent can't provide a better name. */ | ||
2483 | - const char *(*get_name)(BdrvChild *child); | ||
2484 | - | ||
2485 | - /* Returns a malloced string that describes the parent of the child for a | ||
2486 | - * human reader. This could be a node-name, BlockBackend name, qdev ID or | ||
2487 | - * QOM path of the device owning the BlockBackend, job type and ID etc. The | ||
2488 | - * caller is responsible for freeing the memory. */ | ||
2489 | - char *(*get_parent_desc)(BdrvChild *child); | ||
2490 | - | ||
2491 | - /* | ||
2492 | - * If this pair of functions is implemented, the parent doesn't issue new | ||
2493 | - * requests after returning from .drained_begin() until .drained_end() is | ||
2494 | - * called. | ||
2495 | - * | ||
2496 | - * These functions must not change the graph (and therefore also must not | ||
2497 | - * call aio_poll(), which could change the graph indirectly). | ||
2498 | - * | ||
2499 | - * If drained_end() schedules background operations, it must atomically | ||
2500 | - * increment *drained_end_counter for each such operation and atomically | ||
2501 | - * decrement it once the operation has settled. | ||
2502 | - * | ||
2503 | - * Note that this can be nested. If drained_begin() was called twice, new | ||
2504 | - * I/O is allowed only after drained_end() was called twice, too. | ||
2505 | - */ | ||
2506 | - void (*drained_begin)(BdrvChild *child); | ||
2507 | - void (*drained_end)(BdrvChild *child, int *drained_end_counter); | ||
2508 | - | ||
2509 | - /* | ||
2510 | - * Returns whether the parent has pending requests for the child. This | ||
2511 | - * callback is polled after .drained_begin() has been called until all | ||
2512 | - * activity on the child has stopped. | ||
2513 | - */ | ||
2514 | - bool (*drained_poll)(BdrvChild *child); | ||
2515 | - | ||
2516 | - /* Notifies the parent that the child has been activated/inactivated (e.g. | ||
2517 | - * when migration is completing) and it can start/stop requesting | ||
2518 | - * permissions and doing I/O on it. */ | ||
2519 | - void (*activate)(BdrvChild *child, Error **errp); | ||
2520 | - int (*inactivate)(BdrvChild *child); | ||
2521 | - | ||
2522 | - void (*attach)(BdrvChild *child); | ||
2523 | - void (*detach)(BdrvChild *child); | ||
2524 | - | ||
2525 | - /* Notifies the parent that the filename of its child has changed (e.g. | ||
2526 | - * because the direct child was removed from the backing chain), so that it | ||
2527 | - * can update its reference. */ | ||
2528 | - int (*update_filename)(BdrvChild *child, BlockDriverState *new_base, | ||
2529 | - const char *filename, Error **errp); | ||
2530 | - | ||
2531 | - bool (*can_set_aio_ctx)(BdrvChild *child, AioContext *ctx, | ||
2532 | - GSList **ignore, Error **errp); | ||
2533 | - void (*set_aio_ctx)(BdrvChild *child, AioContext *ctx, GSList **ignore); | ||
2534 | - | ||
2535 | - AioContext *(*get_parent_aio_context)(BdrvChild *child); | ||
2536 | -}; | ||
2537 | - | ||
2538 | -extern const BdrvChildClass child_of_bds; | ||
2539 | - | ||
2540 | -struct BdrvChild { | ||
2541 | - BlockDriverState *bs; | ||
2542 | - char *name; | ||
2543 | - const BdrvChildClass *klass; | ||
2544 | - BdrvChildRole role; | ||
2545 | - void *opaque; | ||
2546 | - | ||
2547 | - /** | ||
2548 | - * Granted permissions for operating on this BdrvChild (BLK_PERM_* bitmask) | ||
2549 | - */ | ||
2550 | - uint64_t perm; | ||
2551 | - | ||
2552 | - /** | ||
2553 | - * Permissions that can still be granted to other users of @bs while this | ||
2554 | - * BdrvChild is still attached to it. (BLK_PERM_* bitmask) | ||
2555 | - */ | ||
2556 | - uint64_t shared_perm; | ||
2557 | - | ||
2558 | - /* | ||
2559 | - * This link is frozen: the child can neither be replaced nor | ||
2560 | - * detached from the parent. | ||
2561 | - */ | ||
2562 | - bool frozen; | ||
2563 | - | ||
2564 | - /* | ||
2565 | - * How many times the parent of this child has been drained | ||
2566 | - * (through klass->drained_*). | ||
2567 | - * Usually, this is equal to bs->quiesce_counter (potentially | ||
2568 | - * reduced by bdrv_drain_all_count). It may differ while the | ||
2569 | - * child is entering or leaving a drained section. | ||
2570 | - */ | ||
2571 | - int parent_quiesce_counter; | ||
2572 | - | ||
2573 | - QLIST_ENTRY(BdrvChild) next; | ||
2574 | - QLIST_ENTRY(BdrvChild) next_parent; | ||
2575 | -}; | ||
2576 | - | ||
2577 | -/* | ||
2578 | - * Allows bdrv_co_block_status() to cache one data region for a | ||
2579 | - * protocol node. | ||
2580 | - * | ||
2581 | - * @valid: Whether the cache is valid (should be accessed with atomic | ||
2582 | - * functions so this can be reset by RCU readers) | ||
2583 | - * @data_start: Offset where we know (or strongly assume) is data | ||
2584 | - * @data_end: Offset where the data region ends (which is not necessarily | ||
2585 | - * the start of a zeroed region) | ||
2586 | - */ | ||
2587 | -typedef struct BdrvBlockStatusCache { | ||
2588 | - struct rcu_head rcu; | ||
2589 | - | ||
2590 | - bool valid; | ||
2591 | - int64_t data_start; | ||
2592 | - int64_t data_end; | ||
2593 | -} BdrvBlockStatusCache; | ||
2594 | - | ||
2595 | -struct BlockDriverState { | ||
2596 | - /* Protected by big QEMU lock or read-only after opening. No special | ||
2597 | - * locking needed during I/O... | ||
2598 | - */ | ||
2599 | - int open_flags; /* flags used to open the file, re-used for re-open */ | ||
2600 | - bool encrypted; /* if true, the media is encrypted */ | ||
2601 | - bool sg; /* if true, the device is a /dev/sg* */ | ||
2602 | - bool probed; /* if true, format was probed rather than specified */ | ||
2603 | - bool force_share; /* if true, always allow all shared permissions */ | ||
2604 | - bool implicit; /* if true, this filter node was automatically inserted */ | ||
2605 | - | ||
2606 | - BlockDriver *drv; /* NULL means no media */ | ||
2607 | - void *opaque; | ||
2608 | - | ||
2609 | - AioContext *aio_context; /* event loop used for fd handlers, timers, etc */ | ||
2610 | - /* long-running tasks intended to always use the same AioContext as this | ||
2611 | - * BDS may register themselves in this list to be notified of changes | ||
2612 | - * regarding this BDS's context */ | ||
2613 | - QLIST_HEAD(, BdrvAioNotifier) aio_notifiers; | ||
2614 | - bool walking_aio_notifiers; /* to make removal during iteration safe */ | ||
2615 | - | ||
2616 | - char filename[PATH_MAX]; | ||
2617 | - /* | ||
2618 | - * If not empty, this image is a diff in relation to backing_file. | ||
2619 | - * Note that this is the name given in the image header and | ||
2620 | - * therefore may or may not be equal to .backing->bs->filename. | ||
2621 | - * If this field contains a relative path, it is to be resolved | ||
2622 | - * relatively to the overlay's location. | ||
2623 | - */ | ||
2624 | - char backing_file[PATH_MAX]; | ||
2625 | - /* | ||
2626 | - * The backing filename indicated by the image header. Contrary | ||
2627 | - * to backing_file, if we ever open this file, auto_backing_file | ||
2628 | - * is replaced by the resulting BDS's filename (i.e. after a | ||
2629 | - * bdrv_refresh_filename() run). | ||
2630 | - */ | ||
2631 | - char auto_backing_file[PATH_MAX]; | ||
2632 | - char backing_format[16]; /* if non-zero and backing_file exists */ | ||
2633 | - | ||
2634 | - QDict *full_open_options; | ||
2635 | - char exact_filename[PATH_MAX]; | ||
2636 | - | ||
2637 | - BdrvChild *backing; | ||
2638 | - BdrvChild *file; | ||
2639 | - | ||
2640 | - /* I/O Limits */ | ||
2641 | - BlockLimits bl; | ||
2642 | - | ||
2643 | - /* | ||
2644 | - * Flags honored during pread | ||
2645 | - */ | ||
2646 | - unsigned int supported_read_flags; | ||
2647 | - /* Flags honored during pwrite (so far: BDRV_REQ_FUA, | ||
2648 | - * BDRV_REQ_WRITE_UNCHANGED). | ||
2649 | - * If a driver does not support BDRV_REQ_WRITE_UNCHANGED, those | ||
2650 | - * writes will be issued as normal writes without the flag set. | ||
2651 | - * This is important to note for drivers that do not explicitly | ||
2652 | - * request a WRITE permission for their children and instead take | ||
2653 | - * the same permissions as their parent did (this is commonly what | ||
2654 | - * block filters do). Such drivers have to be aware that the | ||
2655 | - * parent may have taken a WRITE_UNCHANGED permission only and is | ||
2656 | - * issuing such requests. Drivers either must make sure that | ||
2657 | - * these requests do not result in plain WRITE accesses (usually | ||
2658 | - * by supporting BDRV_REQ_WRITE_UNCHANGED, and then forwarding | ||
2659 | - * every incoming write request as-is, including potentially that | ||
2660 | - * flag), or they have to explicitly take the WRITE permission for | ||
2661 | - * their children. */ | ||
2662 | - unsigned int supported_write_flags; | ||
2663 | - /* Flags honored during pwrite_zeroes (so far: BDRV_REQ_FUA, | ||
2664 | - * BDRV_REQ_MAY_UNMAP, BDRV_REQ_WRITE_UNCHANGED) */ | ||
2665 | - unsigned int supported_zero_flags; | ||
2666 | - /* | ||
2667 | - * Flags honoured during truncate (so far: BDRV_REQ_ZERO_WRITE). | ||
2668 | - * | ||
2669 | - * If BDRV_REQ_ZERO_WRITE is given, the truncate operation must make sure | ||
2670 | - * that any added space reads as all zeros. If this can't be guaranteed, | ||
2671 | - * the operation must fail. | ||
2672 | - */ | ||
2673 | - unsigned int supported_truncate_flags; | ||
2674 | - | ||
2675 | - /* the following member gives a name to every node on the bs graph. */ | ||
2676 | - char node_name[32]; | ||
2677 | - /* element of the list of named nodes building the graph */ | ||
2678 | - QTAILQ_ENTRY(BlockDriverState) node_list; | ||
2679 | - /* element of the list of all BlockDriverStates (all_bdrv_states) */ | ||
2680 | - QTAILQ_ENTRY(BlockDriverState) bs_list; | ||
2681 | - /* element of the list of monitor-owned BDS */ | ||
2682 | - QTAILQ_ENTRY(BlockDriverState) monitor_list; | ||
2683 | - int refcnt; | ||
2684 | - | ||
2685 | - /* operation blockers */ | ||
2686 | - QLIST_HEAD(, BdrvOpBlocker) op_blockers[BLOCK_OP_TYPE_MAX]; | ||
2687 | - | ||
2688 | - /* The node that this node inherited default options from (and a reopen on | ||
2689 | - * which can affect this node by changing these defaults). This is always a | ||
2690 | - * parent node of this node. */ | ||
2691 | - BlockDriverState *inherits_from; | ||
2692 | - QLIST_HEAD(, BdrvChild) children; | ||
2693 | - QLIST_HEAD(, BdrvChild) parents; | ||
2694 | - | ||
2695 | - QDict *options; | ||
2696 | - QDict *explicit_options; | ||
2697 | - BlockdevDetectZeroesOptions detect_zeroes; | ||
2698 | - | ||
2699 | - /* The error object in use for blocking operations on backing_hd */ | ||
2700 | - Error *backing_blocker; | ||
2701 | - | ||
2702 | - /* Protected by AioContext lock */ | ||
2703 | - | ||
2704 | - /* If we are reading a disk image, give its size in sectors. | ||
2705 | - * Generally read-only; it is written to by load_snapshot and | ||
2706 | - * save_snaphost, but the block layer is quiescent during those. | ||
2707 | - */ | ||
2708 | - int64_t total_sectors; | ||
2709 | - | ||
2710 | - /* threshold limit for writes, in bytes. "High water mark". */ | ||
2711 | - uint64_t write_threshold_offset; | ||
2712 | - | ||
2713 | - /* Writing to the list requires the BQL _and_ the dirty_bitmap_mutex. | ||
2714 | - * Reading from the list can be done with either the BQL or the | ||
2715 | - * dirty_bitmap_mutex. Modifying a bitmap only requires | ||
2716 | - * dirty_bitmap_mutex. */ | ||
2717 | - QemuMutex dirty_bitmap_mutex; | ||
2718 | - QLIST_HEAD(, BdrvDirtyBitmap) dirty_bitmaps; | ||
2719 | - | ||
2720 | - /* Offset after the highest byte written to */ | ||
2721 | - Stat64 wr_highest_offset; | ||
2722 | - | ||
2723 | - /* If true, copy read backing sectors into image. Can be >1 if more | ||
2724 | - * than one client has requested copy-on-read. Accessed with atomic | ||
2725 | - * ops. | ||
2726 | - */ | ||
2727 | - int copy_on_read; | ||
2728 | - | ||
2729 | - /* number of in-flight requests; overall and serialising. | ||
2730 | - * Accessed with atomic ops. | ||
2731 | - */ | ||
2732 | - unsigned int in_flight; | ||
2733 | - unsigned int serialising_in_flight; | ||
2734 | - | ||
2735 | - /* counter for nested bdrv_io_plug. | ||
2736 | - * Accessed with atomic ops. | ||
2737 | - */ | ||
2738 | - unsigned io_plugged; | ||
2739 | - | ||
2740 | - /* do we need to tell the quest if we have a volatile write cache? */ | ||
2741 | - int enable_write_cache; | ||
2742 | - | ||
2743 | - /* Accessed with atomic ops. */ | ||
2744 | - int quiesce_counter; | ||
2745 | - int recursive_quiesce_counter; | ||
2746 | - | ||
2747 | - unsigned int write_gen; /* Current data generation */ | ||
2748 | - | ||
2749 | - /* Protected by reqs_lock. */ | ||
2750 | - CoMutex reqs_lock; | ||
2751 | - QLIST_HEAD(, BdrvTrackedRequest) tracked_requests; | ||
2752 | - CoQueue flush_queue; /* Serializing flush queue */ | ||
2753 | - bool active_flush_req; /* Flush request in flight? */ | ||
2754 | - | ||
2755 | - /* Only read/written by whoever has set active_flush_req to true. */ | ||
2756 | - unsigned int flushed_gen; /* Flushed write generation */ | ||
2757 | - | ||
2758 | - /* BdrvChild links to this node may never be frozen */ | ||
2759 | - bool never_freeze; | ||
2760 | - | ||
2761 | - /* Lock for block-status cache RCU writers */ | ||
2762 | - CoMutex bsc_modify_lock; | ||
2763 | - /* Always non-NULL, but must only be dereferenced under an RCU read guard */ | ||
2764 | - BdrvBlockStatusCache *block_status_cache; | ||
2765 | -}; | ||
2766 | - | ||
2767 | -struct BlockBackendRootState { | ||
2768 | - int open_flags; | ||
2769 | - BlockdevDetectZeroesOptions detect_zeroes; | ||
2770 | -}; | ||
2771 | - | ||
2772 | -typedef enum BlockMirrorBackingMode { | ||
2773 | - /* Reuse the existing backing chain from the source for the target. | ||
2774 | - * - sync=full: Set backing BDS to NULL. | ||
2775 | - * - sync=top: Use source's backing BDS. | ||
2776 | - * - sync=none: Use source as the backing BDS. */ | ||
2777 | - MIRROR_SOURCE_BACKING_CHAIN, | ||
2778 | - | ||
2779 | - /* Open the target's backing chain completely anew */ | ||
2780 | - MIRROR_OPEN_BACKING_CHAIN, | ||
2781 | - | ||
2782 | - /* Do not change the target's backing BDS after job completion */ | ||
2783 | - MIRROR_LEAVE_BACKING_CHAIN, | ||
2784 | -} BlockMirrorBackingMode; | ||
2785 | - | ||
2786 | - | ||
2787 | -/* Essential block drivers which must always be statically linked into qemu, and | ||
2788 | - * which therefore can be accessed without using bdrv_find_format() */ | ||
2789 | -extern BlockDriver bdrv_file; | ||
2790 | -extern BlockDriver bdrv_raw; | ||
2791 | -extern BlockDriver bdrv_qcow2; | ||
2792 | - | ||
2793 | -int coroutine_fn bdrv_co_preadv(BdrvChild *child, | ||
2794 | - int64_t offset, int64_t bytes, QEMUIOVector *qiov, | ||
2795 | - BdrvRequestFlags flags); | ||
2796 | -int coroutine_fn bdrv_co_preadv_part(BdrvChild *child, | ||
2797 | - int64_t offset, int64_t bytes, | ||
2798 | - QEMUIOVector *qiov, size_t qiov_offset, BdrvRequestFlags flags); | ||
2799 | -int coroutine_fn bdrv_co_pwritev(BdrvChild *child, | ||
2800 | - int64_t offset, int64_t bytes, QEMUIOVector *qiov, | ||
2801 | - BdrvRequestFlags flags); | ||
2802 | -int coroutine_fn bdrv_co_pwritev_part(BdrvChild *child, | ||
2803 | - int64_t offset, int64_t bytes, | ||
2804 | - QEMUIOVector *qiov, size_t qiov_offset, BdrvRequestFlags flags); | ||
2805 | - | ||
2806 | -static inline int coroutine_fn bdrv_co_pread(BdrvChild *child, | ||
2807 | - int64_t offset, unsigned int bytes, void *buf, BdrvRequestFlags flags) | ||
2808 | -{ | ||
2809 | - QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes); | ||
2810 | - | ||
2811 | - return bdrv_co_preadv(child, offset, bytes, &qiov, flags); | ||
2812 | -} | ||
2813 | - | ||
2814 | -static inline int coroutine_fn bdrv_co_pwrite(BdrvChild *child, | ||
2815 | - int64_t offset, unsigned int bytes, void *buf, BdrvRequestFlags flags) | ||
2816 | -{ | ||
2817 | - QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes); | ||
2818 | - | ||
2819 | - return bdrv_co_pwritev(child, offset, bytes, &qiov, flags); | ||
2820 | -} | ||
2821 | - | ||
2822 | -extern unsigned int bdrv_drain_all_count; | ||
2823 | -void bdrv_apply_subtree_drain(BdrvChild *child, BlockDriverState *new_parent); | ||
2824 | -void bdrv_unapply_subtree_drain(BdrvChild *child, BlockDriverState *old_parent); | ||
2825 | - | ||
2826 | -bool coroutine_fn bdrv_make_request_serialising(BdrvTrackedRequest *req, | ||
2827 | - uint64_t align); | ||
2828 | -BdrvTrackedRequest *coroutine_fn bdrv_co_get_self_request(BlockDriverState *bs); | ||
2829 | - | ||
2830 | -int get_tmp_filename(char *filename, int size); | ||
2831 | -BlockDriver *bdrv_probe_all(const uint8_t *buf, int buf_size, | ||
2832 | - const char *filename); | ||
2833 | - | ||
2834 | -void bdrv_parse_filename_strip_prefix(const char *filename, const char *prefix, | ||
2835 | - QDict *options); | ||
2836 | - | ||
2837 | -/** | ||
2838 | - * bdrv_add_aio_context_notifier: | ||
2839 | - * | ||
2840 | - * If a long-running job intends to be always run in the same AioContext as a | ||
2841 | - * certain BDS, it may use this function to be notified of changes regarding the | ||
2842 | - * association of the BDS to an AioContext. | ||
2843 | - * | ||
2844 | - * attached_aio_context() is called after the target BDS has been attached to a | ||
2845 | - * new AioContext; detach_aio_context() is called before the target BDS is being | ||
2846 | - * detached from its old AioContext. | ||
2847 | - */ | ||
2848 | -void bdrv_add_aio_context_notifier(BlockDriverState *bs, | ||
2849 | - void (*attached_aio_context)(AioContext *new_context, void *opaque), | ||
2850 | - void (*detach_aio_context)(void *opaque), void *opaque); | ||
2851 | - | ||
2852 | -/** | ||
2853 | - * bdrv_remove_aio_context_notifier: | ||
2854 | - * | ||
2855 | - * Unsubscribe of change notifications regarding the BDS's AioContext. The | ||
2856 | - * parameters given here have to be the same as those given to | ||
2857 | - * bdrv_add_aio_context_notifier(). | ||
2858 | - */ | ||
2859 | -void bdrv_remove_aio_context_notifier(BlockDriverState *bs, | ||
2860 | - void (*aio_context_attached)(AioContext *, | ||
2861 | - void *), | ||
2862 | - void (*aio_context_detached)(void *), | ||
2863 | - void *opaque); | ||
2864 | - | ||
2865 | -/** | ||
2866 | - * bdrv_wakeup: | ||
2867 | - * @bs: The BlockDriverState for which an I/O operation has been completed. | ||
2868 | - * | ||
2869 | - * Wake up the main thread if it is waiting on BDRV_POLL_WHILE. During | ||
2870 | - * synchronous I/O on a BlockDriverState that is attached to another | ||
2871 | - * I/O thread, the main thread lets the I/O thread's event loop run, | ||
2872 | - * waiting for the I/O operation to complete. A bdrv_wakeup will wake | ||
2873 | - * up the main thread if necessary. | ||
2874 | - * | ||
2875 | - * Manual calls to bdrv_wakeup are rarely necessary, because | ||
2876 | - * bdrv_dec_in_flight already calls it. | ||
2877 | - */ | ||
2878 | -void bdrv_wakeup(BlockDriverState *bs); | ||
2879 | - | ||
2880 | -#ifdef _WIN32 | ||
2881 | -int is_windows_drive(const char *filename); | ||
2882 | -#endif | ||
2883 | - | ||
2884 | -/** | ||
2885 | - * stream_start: | ||
2886 | - * @job_id: The id of the newly-created job, or %NULL to use the | ||
2887 | - * device name of @bs. | ||
2888 | - * @bs: Block device to operate on. | ||
2889 | - * @base: Block device that will become the new base, or %NULL to | ||
2890 | - * flatten the whole backing file chain onto @bs. | ||
2891 | - * @backing_file_str: The file name that will be written to @bs as the | ||
2892 | - * the new backing file if the job completes. Ignored if @base is %NULL. | ||
2893 | - * @creation_flags: Flags that control the behavior of the Job lifetime. | ||
2894 | - * See @BlockJobCreateFlags | ||
2895 | - * @speed: The maximum speed, in bytes per second, or 0 for unlimited. | ||
2896 | - * @on_error: The action to take upon error. | ||
2897 | - * @filter_node_name: The node name that should be assigned to the filter | ||
2898 | - * driver that the stream job inserts into the graph above | ||
2899 | - * @bs. NULL means that a node name should be autogenerated. | ||
2900 | - * @errp: Error object. | ||
2901 | - * | ||
2902 | - * Start a streaming operation on @bs. Clusters that are unallocated | ||
2903 | - * in @bs, but allocated in any image between @base and @bs (both | ||
2904 | - * exclusive) will be written to @bs. At the end of a successful | ||
2905 | - * streaming job, the backing file of @bs will be changed to | ||
2906 | - * @backing_file_str in the written image and to @base in the live | ||
2907 | - * BlockDriverState. | ||
2908 | - */ | ||
2909 | -void stream_start(const char *job_id, BlockDriverState *bs, | ||
2910 | - BlockDriverState *base, const char *backing_file_str, | ||
2911 | - BlockDriverState *bottom, | ||
2912 | - int creation_flags, int64_t speed, | ||
2913 | - BlockdevOnError on_error, | ||
2914 | - const char *filter_node_name, | ||
2915 | - Error **errp); | ||
2916 | - | ||
2917 | -/** | ||
2918 | - * commit_start: | ||
2919 | - * @job_id: The id of the newly-created job, or %NULL to use the | ||
2920 | - * device name of @bs. | ||
2921 | - * @bs: Active block device. | ||
2922 | - * @top: Top block device to be committed. | ||
2923 | - * @base: Block device that will be written into, and become the new top. | ||
2924 | - * @creation_flags: Flags that control the behavior of the Job lifetime. | ||
2925 | - * See @BlockJobCreateFlags | ||
2926 | - * @speed: The maximum speed, in bytes per second, or 0 for unlimited. | ||
2927 | - * @on_error: The action to take upon error. | ||
2928 | - * @backing_file_str: String to use as the backing file in @top's overlay | ||
2929 | - * @filter_node_name: The node name that should be assigned to the filter | ||
2930 | - * driver that the commit job inserts into the graph above @top. NULL means | ||
2931 | - * that a node name should be autogenerated. | ||
2932 | - * @errp: Error object. | ||
2933 | - * | ||
2934 | - */ | ||
2935 | -void commit_start(const char *job_id, BlockDriverState *bs, | ||
2936 | - BlockDriverState *base, BlockDriverState *top, | ||
2937 | - int creation_flags, int64_t speed, | ||
2938 | - BlockdevOnError on_error, const char *backing_file_str, | ||
2939 | - const char *filter_node_name, Error **errp); | ||
2940 | -/** | ||
2941 | - * commit_active_start: | ||
2942 | - * @job_id: The id of the newly-created job, or %NULL to use the | ||
2943 | - * device name of @bs. | ||
2944 | - * @bs: Active block device to be committed. | ||
2945 | - * @base: Block device that will be written into, and become the new top. | ||
2946 | - * @creation_flags: Flags that control the behavior of the Job lifetime. | ||
2947 | - * See @BlockJobCreateFlags | ||
2948 | - * @speed: The maximum speed, in bytes per second, or 0 for unlimited. | ||
2949 | - * @on_error: The action to take upon error. | ||
2950 | - * @filter_node_name: The node name that should be assigned to the filter | ||
2951 | - * driver that the commit job inserts into the graph above @bs. NULL means that | ||
2952 | - * a node name should be autogenerated. | ||
2953 | - * @cb: Completion function for the job. | ||
2954 | - * @opaque: Opaque pointer value passed to @cb. | ||
2955 | - * @auto_complete: Auto complete the job. | ||
2956 | - * @errp: Error object. | ||
2957 | - * | ||
2958 | - */ | ||
2959 | -BlockJob *commit_active_start(const char *job_id, BlockDriverState *bs, | ||
2960 | - BlockDriverState *base, int creation_flags, | ||
2961 | - int64_t speed, BlockdevOnError on_error, | ||
2962 | - const char *filter_node_name, | ||
2963 | - BlockCompletionFunc *cb, void *opaque, | ||
2964 | - bool auto_complete, Error **errp); | ||
2965 | -/* | ||
2966 | - * mirror_start: | ||
2967 | - * @job_id: The id of the newly-created job, or %NULL to use the | ||
2968 | - * device name of @bs. | ||
2969 | - * @bs: Block device to operate on. | ||
2970 | - * @target: Block device to write to. | ||
2971 | - * @replaces: Block graph node name to replace once the mirror is done. Can | ||
2972 | - * only be used when full mirroring is selected. | ||
2973 | - * @creation_flags: Flags that control the behavior of the Job lifetime. | ||
2974 | - * See @BlockJobCreateFlags | ||
2975 | - * @speed: The maximum speed, in bytes per second, or 0 for unlimited. | ||
2976 | - * @granularity: The chosen granularity for the dirty bitmap. | ||
2977 | - * @buf_size: The amount of data that can be in flight at one time. | ||
2978 | - * @mode: Whether to collapse all images in the chain to the target. | ||
2979 | - * @backing_mode: How to establish the target's backing chain after completion. | ||
2980 | - * @zero_target: Whether the target should be explicitly zero-initialized | ||
2981 | - * @on_source_error: The action to take upon error reading from the source. | ||
2982 | - * @on_target_error: The action to take upon error writing to the target. | ||
2983 | - * @unmap: Whether to unmap target where source sectors only contain zeroes. | ||
2984 | - * @filter_node_name: The node name that should be assigned to the filter | ||
2985 | - * driver that the mirror job inserts into the graph above @bs. NULL means that | ||
2986 | - * a node name should be autogenerated. | ||
2987 | - * @copy_mode: When to trigger writes to the target. | ||
2988 | - * @errp: Error object. | ||
2989 | - * | ||
2990 | - * Start a mirroring operation on @bs. Clusters that are allocated | ||
2991 | - * in @bs will be written to @target until the job is cancelled or | ||
2992 | - * manually completed. At the end of a successful mirroring job, | ||
2993 | - * @bs will be switched to read from @target. | ||
2994 | - */ | ||
2995 | -void mirror_start(const char *job_id, BlockDriverState *bs, | ||
2996 | - BlockDriverState *target, const char *replaces, | ||
2997 | - int creation_flags, int64_t speed, | ||
2998 | - uint32_t granularity, int64_t buf_size, | ||
2999 | - MirrorSyncMode mode, BlockMirrorBackingMode backing_mode, | ||
3000 | - bool zero_target, | ||
3001 | - BlockdevOnError on_source_error, | ||
3002 | - BlockdevOnError on_target_error, | ||
3003 | - bool unmap, const char *filter_node_name, | ||
3004 | - MirrorCopyMode copy_mode, Error **errp); | ||
3005 | - | ||
3006 | -/* | ||
3007 | - * backup_job_create: | ||
3008 | - * @job_id: The id of the newly-created job, or %NULL to use the | ||
3009 | - * device name of @bs. | ||
3010 | - * @bs: Block device to operate on. | ||
3011 | - * @target: Block device to write to. | ||
3012 | - * @speed: The maximum speed, in bytes per second, or 0 for unlimited. | ||
3013 | - * @sync_mode: What parts of the disk image should be copied to the destination. | ||
3014 | - * @sync_bitmap: The dirty bitmap if sync_mode is 'bitmap' or 'incremental' | ||
3015 | - * @bitmap_mode: The bitmap synchronization policy to use. | ||
3016 | - * @perf: Performance options. All actual fields assumed to be present, | ||
3017 | - * all ".has_*" fields are ignored. | ||
3018 | - * @on_source_error: The action to take upon error reading from the source. | ||
3019 | - * @on_target_error: The action to take upon error writing to the target. | ||
3020 | - * @creation_flags: Flags that control the behavior of the Job lifetime. | ||
3021 | - * See @BlockJobCreateFlags | ||
3022 | - * @cb: Completion function for the job. | ||
3023 | - * @opaque: Opaque pointer value passed to @cb. | ||
3024 | - * @txn: Transaction that this job is part of (may be NULL). | ||
3025 | - * | ||
3026 | - * Create a backup operation on @bs. Clusters in @bs are written to @target | ||
3027 | - * until the job is cancelled or manually completed. | ||
3028 | - */ | ||
3029 | -BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, | ||
3030 | - BlockDriverState *target, int64_t speed, | ||
3031 | - MirrorSyncMode sync_mode, | ||
3032 | - BdrvDirtyBitmap *sync_bitmap, | ||
3033 | - BitmapSyncMode bitmap_mode, | ||
3034 | - bool compress, | ||
3035 | - const char *filter_node_name, | ||
3036 | - BackupPerf *perf, | ||
3037 | - BlockdevOnError on_source_error, | ||
3038 | - BlockdevOnError on_target_error, | ||
3039 | - int creation_flags, | ||
3040 | - BlockCompletionFunc *cb, void *opaque, | ||
3041 | - JobTxn *txn, Error **errp); | ||
3042 | - | ||
3043 | -BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs, | ||
3044 | - const char *child_name, | ||
3045 | - const BdrvChildClass *child_class, | ||
3046 | - BdrvChildRole child_role, | ||
3047 | - uint64_t perm, uint64_t shared_perm, | ||
3048 | - void *opaque, Error **errp); | ||
3049 | -void bdrv_root_unref_child(BdrvChild *child); | ||
3050 | - | ||
3051 | -void bdrv_get_cumulative_perm(BlockDriverState *bs, uint64_t *perm, | ||
3052 | - uint64_t *shared_perm); | ||
3053 | - | ||
3054 | -/** | ||
3055 | - * Sets a BdrvChild's permissions. Avoid if the parent is a BDS; use | ||
3056 | - * bdrv_child_refresh_perms() instead and make the parent's | ||
3057 | - * .bdrv_child_perm() implementation return the correct values. | ||
3058 | - */ | ||
3059 | -int bdrv_child_try_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared, | ||
3060 | - Error **errp); | ||
3061 | - | ||
3062 | -/** | ||
3063 | - * Calls bs->drv->bdrv_child_perm() and updates the child's permission | ||
3064 | - * masks with the result. | ||
3065 | - * Drivers should invoke this function whenever an event occurs that | ||
3066 | - * makes their .bdrv_child_perm() implementation return different | ||
3067 | - * values than before, but which will not result in the block layer | ||
3068 | - * automatically refreshing the permissions. | ||
3069 | - */ | ||
3070 | -int bdrv_child_refresh_perms(BlockDriverState *bs, BdrvChild *c, Error **errp); | ||
3071 | - | ||
3072 | -bool bdrv_recurse_can_replace(BlockDriverState *bs, | ||
3073 | - BlockDriverState *to_replace); | ||
3074 | - | ||
3075 | -/* | ||
3076 | - * Default implementation for BlockDriver.bdrv_child_perm() that can | ||
3077 | - * be used by block filters and image formats, as long as they use the | ||
3078 | - * child_of_bds child class and set an appropriate BdrvChildRole. | ||
3079 | - */ | ||
3080 | -void bdrv_default_perms(BlockDriverState *bs, BdrvChild *c, | ||
3081 | - BdrvChildRole role, BlockReopenQueue *reopen_queue, | ||
3082 | - uint64_t perm, uint64_t shared, | ||
3083 | - uint64_t *nperm, uint64_t *nshared); | ||
3084 | - | ||
3085 | -const char *bdrv_get_parent_name(const BlockDriverState *bs); | ||
3086 | -void blk_dev_change_media_cb(BlockBackend *blk, bool load, Error **errp); | ||
3087 | -bool blk_dev_has_removable_media(BlockBackend *blk); | ||
3088 | -bool blk_dev_has_tray(BlockBackend *blk); | ||
3089 | -void blk_dev_eject_request(BlockBackend *blk, bool force); | ||
3090 | -bool blk_dev_is_tray_open(BlockBackend *blk); | ||
3091 | -bool blk_dev_is_medium_locked(BlockBackend *blk); | ||
3092 | - | ||
3093 | -void bdrv_set_dirty(BlockDriverState *bs, int64_t offset, int64_t bytes); | ||
3094 | - | ||
3095 | -void bdrv_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap **out); | ||
3096 | -void bdrv_restore_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap *backup); | ||
3097 | -bool bdrv_dirty_bitmap_merge_internal(BdrvDirtyBitmap *dest, | ||
3098 | - const BdrvDirtyBitmap *src, | ||
3099 | - HBitmap **backup, bool lock); | ||
3100 | - | ||
3101 | -void bdrv_inc_in_flight(BlockDriverState *bs); | ||
3102 | -void bdrv_dec_in_flight(BlockDriverState *bs); | ||
3103 | - | ||
3104 | -void blockdev_close_all_bdrv_states(void); | ||
3105 | - | ||
3106 | -int coroutine_fn bdrv_co_copy_range_from(BdrvChild *src, int64_t src_offset, | ||
3107 | - BdrvChild *dst, int64_t dst_offset, | ||
3108 | - int64_t bytes, | ||
3109 | - BdrvRequestFlags read_flags, | ||
3110 | - BdrvRequestFlags write_flags); | ||
3111 | -int coroutine_fn bdrv_co_copy_range_to(BdrvChild *src, int64_t src_offset, | ||
3112 | - BdrvChild *dst, int64_t dst_offset, | ||
3113 | - int64_t bytes, | ||
3114 | - BdrvRequestFlags read_flags, | ||
3115 | - BdrvRequestFlags write_flags); | ||
3116 | - | ||
3117 | -int refresh_total_sectors(BlockDriverState *bs, int64_t hint); | ||
3118 | - | ||
3119 | -void bdrv_set_monitor_owned(BlockDriverState *bs); | ||
3120 | -BlockDriverState *bds_tree_init(QDict *bs_opts, Error **errp); | ||
3121 | - | ||
3122 | -/** | ||
3123 | - * Simple implementation of bdrv_co_create_opts for protocol drivers | ||
3124 | - * which only support creation via opening a file | ||
3125 | - * (usually existing raw storage device) | ||
3126 | - */ | ||
3127 | -int coroutine_fn bdrv_co_create_opts_simple(BlockDriver *drv, | ||
3128 | - const char *filename, | ||
3129 | - QemuOpts *opts, | ||
3130 | - Error **errp); | ||
3131 | -extern QemuOptsList bdrv_create_opts_simple; | ||
3132 | - | ||
3133 | -BdrvDirtyBitmap *block_dirty_bitmap_lookup(const char *node, | ||
3134 | - const char *name, | ||
3135 | - BlockDriverState **pbs, | ||
3136 | - Error **errp); | ||
3137 | -BdrvDirtyBitmap *block_dirty_bitmap_merge(const char *node, const char *target, | ||
3138 | - BlockDirtyBitmapMergeSourceList *bms, | ||
3139 | - HBitmap **backup, Error **errp); | ||
3140 | -BdrvDirtyBitmap *block_dirty_bitmap_remove(const char *node, const char *name, | ||
3141 | - bool release, | ||
3142 | - BlockDriverState **bitmap_bs, | ||
3143 | - Error **errp); | ||
3144 | - | ||
3145 | -BdrvChild *bdrv_cow_child(BlockDriverState *bs); | ||
3146 | -BdrvChild *bdrv_filter_child(BlockDriverState *bs); | ||
3147 | -BdrvChild *bdrv_filter_or_cow_child(BlockDriverState *bs); | ||
3148 | -BdrvChild *bdrv_primary_child(BlockDriverState *bs); | ||
3149 | -BlockDriverState *bdrv_skip_implicit_filters(BlockDriverState *bs); | ||
3150 | -BlockDriverState *bdrv_skip_filters(BlockDriverState *bs); | ||
3151 | -BlockDriverState *bdrv_backing_chain_next(BlockDriverState *bs); | ||
3152 | - | ||
3153 | -static inline BlockDriverState *child_bs(BdrvChild *child) | ||
3154 | -{ | ||
3155 | - return child ? child->bs : NULL; | ||
3156 | -} | ||
3157 | - | ||
3158 | -static inline BlockDriverState *bdrv_cow_bs(BlockDriverState *bs) | ||
3159 | -{ | ||
3160 | - return child_bs(bdrv_cow_child(bs)); | ||
3161 | -} | ||
3162 | - | ||
3163 | -static inline BlockDriverState *bdrv_filter_bs(BlockDriverState *bs) | ||
3164 | -{ | ||
3165 | - return child_bs(bdrv_filter_child(bs)); | ||
3166 | -} | ||
3167 | - | ||
3168 | -static inline BlockDriverState *bdrv_filter_or_cow_bs(BlockDriverState *bs) | ||
3169 | -{ | ||
3170 | - return child_bs(bdrv_filter_or_cow_child(bs)); | ||
3171 | -} | ||
3172 | - | ||
3173 | -static inline BlockDriverState *bdrv_primary_bs(BlockDriverState *bs) | ||
3174 | -{ | ||
3175 | - return child_bs(bdrv_primary_child(bs)); | ||
3176 | -} | ||
3177 | - | ||
3178 | -/** | ||
3179 | - * End all quiescent sections started by bdrv_drain_all_begin(). This is | ||
3180 | - * needed when deleting a BDS before bdrv_drain_all_end() is called. | ||
3181 | - * | ||
3182 | - * NOTE: this is an internal helper for bdrv_close() *only*. No one else | ||
3183 | - * should call it. | ||
3184 | - */ | ||
3185 | -void bdrv_drain_all_end_quiesce(BlockDriverState *bs); | ||
3186 | - | ||
3187 | -/** | ||
3188 | - * Check whether the given offset is in the cached block-status data | ||
3189 | - * region. | ||
3190 | - * | ||
3191 | - * If it is, and @pnum is not NULL, *pnum is set to | ||
3192 | - * `bsc.data_end - offset`, i.e. how many bytes, starting from | ||
3193 | - * @offset, are data (according to the cache). | ||
3194 | - * Otherwise, *pnum is not touched. | ||
3195 | - */ | ||
3196 | -bool bdrv_bsc_is_data(BlockDriverState *bs, int64_t offset, int64_t *pnum); | ||
3197 | - | ||
3198 | -/** | ||
3199 | - * If [offset, offset + bytes) overlaps with the currently cached | ||
3200 | - * block-status region, invalidate the cache. | ||
3201 | - * | ||
3202 | - * (To be used by I/O paths that cause data regions to be zero or | ||
3203 | - * holes.) | ||
3204 | - */ | ||
3205 | -void bdrv_bsc_invalidate_range(BlockDriverState *bs, | ||
3206 | - int64_t offset, int64_t bytes); | ||
3207 | - | ||
3208 | -/** | ||
3209 | - * Mark the range [offset, offset + bytes) as a data region. | ||
3210 | - */ | ||
3211 | -void bdrv_bsc_fill(BlockDriverState *bs, int64_t offset, int64_t bytes); | ||
3212 | +/* DO NOT ADD ANYTHING IN HERE. USE ONE OF THE HEADERS INCLUDED ABOVE */ | ||
3213 | |||
3214 | #endif /* BLOCK_INT_H */ | ||
3215 | diff --git a/blockdev.c b/blockdev.c | ||
3216 | index XXXXXXX..XXXXXXX 100644 | ||
3217 | --- a/blockdev.c | ||
3218 | +++ b/blockdev.c | ||
3219 | @@ -XXX,XX +XXX,XX @@ | ||
3220 | #include "qemu/main-loop.h" | ||
3221 | #include "qemu/throttle-options.h" | ||
3222 | |||
3223 | +/* Protected by BQL */ | ||
3224 | QTAILQ_HEAD(, BlockDriverState) monitor_bdrv_states = | ||
3225 | QTAILQ_HEAD_INITIALIZER(monitor_bdrv_states); | ||
3226 | |||
3227 | @@ -XXX,XX +XXX,XX @@ typedef struct BlkActionState BlkActionState; | ||
3228 | * | ||
3229 | * Only prepare() may fail. In a single transaction, only one of commit() or | ||
3230 | * abort() will be called. clean() will always be called if it is present. | ||
3231 | + * | ||
3232 | + * Always run under BQL. | ||
3233 | */ | ||
3234 | typedef struct BlkActionOps { | ||
3235 | size_t instance_size; | ||
3236 | @@ -XXX,XX +XXX,XX @@ static TransactionProperties *get_transaction_properties( | ||
3237 | /* | ||
3238 | * 'Atomic' group operations. The operations are performed as a set, and if | ||
3239 | * any fail then we roll back all operations in the group. | ||
3240 | + * | ||
3241 | + * Always run under BQL. | ||
3242 | */ | ||
3243 | void qmp_transaction(TransactionActionList *dev_list, | ||
3244 | bool has_props, | ||
3245 | -- | 136 | -- |
3246 | 2.35.1 | 137 | 2.13.6 |
138 | |||
139 | diff view generated by jsdifflib |
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | 1 | This is currently only working correctly for bdrv_drain(), not for |
---|---|---|---|
2 | bdrv_drain_all(). Leave a comment for the drain_all case, we'll address | ||
3 | it later. | ||
2 | 4 | ||
3 | Similarly to the previous patches, split block-backend.h | ||
4 | in block-backend-io.h and block-backend-global-state.h | ||
5 | |||
6 | In addition, remove "block/block.h" include as it seems | ||
7 | it is not necessary anymore, together with "qemu/iov.h" | ||
8 | |||
9 | block-backend-common.h contains the structures shared between | ||
10 | the two headers, and the functions that can't be categorized as | ||
11 | I/O or global state. | ||
12 | |||
13 | Assertions are added in the next patch. | ||
14 | |||
15 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
16 | Message-Id: <20220303151616.325444-8-eesposit@redhat.com> | ||
17 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 5 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
18 | --- | 6 | --- |
19 | include/sysemu/block-backend-common.h | 84 ++++++ | 7 | tests/test-bdrv-drain.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ |
20 | include/sysemu/block-backend-global-state.h | 116 +++++++++ | 8 | 1 file changed, 45 insertions(+) |
21 | include/sysemu/block-backend-io.h | 159 ++++++++++++ | ||
22 | include/sysemu/block-backend.h | 269 +------------------- | ||
23 | block/block-backend.c | 9 +- | ||
24 | 5 files changed, 368 insertions(+), 269 deletions(-) | ||
25 | create mode 100644 include/sysemu/block-backend-common.h | ||
26 | create mode 100644 include/sysemu/block-backend-global-state.h | ||
27 | create mode 100644 include/sysemu/block-backend-io.h | ||
28 | 9 | ||
29 | diff --git a/include/sysemu/block-backend-common.h b/include/sysemu/block-backend-common.h | 10 | diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c |
30 | new file mode 100644 | 11 | index XXXXXXX..XXXXXXX 100644 |
31 | index XXXXXXX..XXXXXXX | 12 | --- a/tests/test-bdrv-drain.c |
32 | --- /dev/null | 13 | +++ b/tests/test-bdrv-drain.c |
33 | +++ b/include/sysemu/block-backend-common.h | 14 | @@ -XXX,XX +XXX,XX @@ static void test_drv_cb_drain(void) |
34 | @@ -XXX,XX +XXX,XX @@ | 15 | test_drv_cb_common(BDRV_DRAIN, false); |
35 | +/* | 16 | } |
36 | + * QEMU Block backends | 17 | |
37 | + * | 18 | +static void test_quiesce_common(enum drain_type drain_type, bool recursive) |
38 | + * Copyright (C) 2014-2016 Red Hat, Inc. | 19 | +{ |
39 | + * | 20 | + BlockBackend *blk; |
40 | + * Authors: | 21 | + BlockDriverState *bs, *backing; |
41 | + * Markus Armbruster <armbru@redhat.com>, | ||
42 | + * | ||
43 | + * This work is licensed under the terms of the GNU LGPL, version 2.1 | ||
44 | + * or later. See the COPYING.LIB file in the top-level directory. | ||
45 | + */ | ||
46 | + | 22 | + |
47 | +#ifndef BLOCK_BACKEND_COMMON_H | 23 | + blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL); |
48 | +#define BLOCK_BACKEND_COMMON_H | 24 | + bs = bdrv_new_open_driver(&bdrv_test, "test-node", BDRV_O_RDWR, |
25 | + &error_abort); | ||
26 | + blk_insert_bs(blk, bs, &error_abort); | ||
49 | + | 27 | + |
50 | +#include "qemu/iov.h" | 28 | + backing = bdrv_new_open_driver(&bdrv_test, "backing", 0, &error_abort); |
51 | +#include "block/throttle-groups.h" | 29 | + bdrv_set_backing_hd(bs, backing, &error_abort); |
52 | + | 30 | + |
53 | +/* | 31 | + g_assert_cmpint(bs->quiesce_counter, ==, 0); |
54 | + * TODO Have to include block/block.h for a bunch of block layer | 32 | + g_assert_cmpint(backing->quiesce_counter, ==, 0); |
55 | + * types. Unfortunately, this pulls in the whole BlockDriverState | ||
56 | + * API, which we don't want used by many BlockBackend users. Some of | ||
57 | + * the types belong here, and the rest should be split into a common | ||
58 | + * header and one for the BlockDriverState API. | ||
59 | + */ | ||
60 | +#include "block/block.h" | ||
61 | + | 33 | + |
62 | +/* Callbacks for block device models */ | 34 | + do_drain_begin(drain_type, bs); |
63 | +typedef struct BlockDevOps { | ||
64 | + /* | ||
65 | + * Runs when virtual media changed (monitor commands eject, change) | ||
66 | + * Argument load is true on load and false on eject. | ||
67 | + * Beware: doesn't run when a host device's physical media | ||
68 | + * changes. Sure would be useful if it did. | ||
69 | + * Device models with removable media must implement this callback. | ||
70 | + */ | ||
71 | + void (*change_media_cb)(void *opaque, bool load, Error **errp); | ||
72 | + /* | ||
73 | + * Runs when an eject request is issued from the monitor, the tray | ||
74 | + * is closed, and the medium is locked. | ||
75 | + * Device models that do not implement is_medium_locked will not need | ||
76 | + * this callback. Device models that can lock the medium or tray might | ||
77 | + * want to implement the callback and unlock the tray when "force" is | ||
78 | + * true, even if they do not support eject requests. | ||
79 | + */ | ||
80 | + void (*eject_request_cb)(void *opaque, bool force); | ||
81 | + /* | ||
82 | + * Is the virtual tray open? | ||
83 | + * Device models implement this only when the device has a tray. | ||
84 | + */ | ||
85 | + bool (*is_tray_open)(void *opaque); | ||
86 | + /* | ||
87 | + * Is the virtual medium locked into the device? | ||
88 | + * Device models implement this only when device has such a lock. | ||
89 | + */ | ||
90 | + bool (*is_medium_locked)(void *opaque); | ||
91 | + /* | ||
92 | + * Runs when the size changed (e.g. monitor command block_resize) | ||
93 | + */ | ||
94 | + void (*resize_cb)(void *opaque); | ||
95 | + /* | ||
96 | + * Runs when the backend receives a drain request. | ||
97 | + */ | ||
98 | + void (*drained_begin)(void *opaque); | ||
99 | + /* | ||
100 | + * Runs when the backend's last drain request ends. | ||
101 | + */ | ||
102 | + void (*drained_end)(void *opaque); | ||
103 | + /* | ||
104 | + * Is the device still busy? | ||
105 | + */ | ||
106 | + bool (*drained_poll)(void *opaque); | ||
107 | +} BlockDevOps; | ||
108 | + | 35 | + |
109 | +/* | 36 | + g_assert_cmpint(bs->quiesce_counter, ==, 1); |
110 | + * This struct is embedded in (the private) BlockBackend struct and contains | 37 | + g_assert_cmpint(backing->quiesce_counter, ==, !!recursive); |
111 | + * fields that must be public. This is in particular for QLIST_ENTRY() and | ||
112 | + * friends so that BlockBackends can be kept in lists outside block-backend.c | ||
113 | + */ | ||
114 | +typedef struct BlockBackendPublic { | ||
115 | + ThrottleGroupMember throttle_group_member; | ||
116 | +} BlockBackendPublic; | ||
117 | + | 38 | + |
118 | +#endif /* BLOCK_BACKEND_COMMON_H */ | 39 | + do_drain_end(drain_type, bs); |
119 | diff --git a/include/sysemu/block-backend-global-state.h b/include/sysemu/block-backend-global-state.h | ||
120 | new file mode 100644 | ||
121 | index XXXXXXX..XXXXXXX | ||
122 | --- /dev/null | ||
123 | +++ b/include/sysemu/block-backend-global-state.h | ||
124 | @@ -XXX,XX +XXX,XX @@ | ||
125 | +/* | ||
126 | + * QEMU Block backends | ||
127 | + * | ||
128 | + * Copyright (C) 2014-2016 Red Hat, Inc. | ||
129 | + * | ||
130 | + * Authors: | ||
131 | + * Markus Armbruster <armbru@redhat.com>, | ||
132 | + * | ||
133 | + * This work is licensed under the terms of the GNU LGPL, version 2.1 | ||
134 | + * or later. See the COPYING.LIB file in the top-level directory. | ||
135 | + */ | ||
136 | + | 40 | + |
137 | +#ifndef BLOCK_BACKEND_GS_H | 41 | + g_assert_cmpint(bs->quiesce_counter, ==, 0); |
138 | +#define BLOCK_BACKEND_GS_H | 42 | + g_assert_cmpint(backing->quiesce_counter, ==, 0); |
139 | + | 43 | + |
140 | +#include "block-backend-common.h" | 44 | + bdrv_unref(backing); |
141 | + | 45 | + bdrv_unref(bs); |
142 | +/* | 46 | + blk_unref(blk); |
143 | + * Global state (GS) API. These functions run under the BQL. | ||
144 | + * | ||
145 | + * See include/block/block-global-state.h for more information about | ||
146 | + * the GS API. | ||
147 | + */ | ||
148 | + | ||
149 | +BlockBackend *blk_new(AioContext *ctx, uint64_t perm, uint64_t shared_perm); | ||
150 | +BlockBackend *blk_new_with_bs(BlockDriverState *bs, uint64_t perm, | ||
151 | + uint64_t shared_perm, Error **errp); | ||
152 | +BlockBackend *blk_new_open(const char *filename, const char *reference, | ||
153 | + QDict *options, int flags, Error **errp); | ||
154 | +int blk_get_refcnt(BlockBackend *blk); | ||
155 | +void blk_ref(BlockBackend *blk); | ||
156 | +void blk_unref(BlockBackend *blk); | ||
157 | +void blk_remove_all_bs(void); | ||
158 | +BlockBackend *blk_by_name(const char *name); | ||
159 | +BlockBackend *blk_next(BlockBackend *blk); | ||
160 | +BlockBackend *blk_all_next(BlockBackend *blk); | ||
161 | +bool monitor_add_blk(BlockBackend *blk, const char *name, Error **errp); | ||
162 | +void monitor_remove_blk(BlockBackend *blk); | ||
163 | + | ||
164 | +BlockBackendPublic *blk_get_public(BlockBackend *blk); | ||
165 | +BlockBackend *blk_by_public(BlockBackendPublic *public); | ||
166 | + | ||
167 | +void blk_remove_bs(BlockBackend *blk); | ||
168 | +int blk_insert_bs(BlockBackend *blk, BlockDriverState *bs, Error **errp); | ||
169 | +int blk_replace_bs(BlockBackend *blk, BlockDriverState *new_bs, Error **errp); | ||
170 | +bool bdrv_has_blk(BlockDriverState *bs); | ||
171 | +bool bdrv_is_root_node(BlockDriverState *bs); | ||
172 | +int blk_set_perm(BlockBackend *blk, uint64_t perm, uint64_t shared_perm, | ||
173 | + Error **errp); | ||
174 | +void blk_get_perm(BlockBackend *blk, uint64_t *perm, uint64_t *shared_perm); | ||
175 | + | ||
176 | +void blk_iostatus_enable(BlockBackend *blk); | ||
177 | +BlockDeviceIoStatus blk_iostatus(const BlockBackend *blk); | ||
178 | +void blk_iostatus_disable(BlockBackend *blk); | ||
179 | +void blk_iostatus_reset(BlockBackend *blk); | ||
180 | +int blk_attach_dev(BlockBackend *blk, DeviceState *dev); | ||
181 | +void blk_detach_dev(BlockBackend *blk, DeviceState *dev); | ||
182 | +DeviceState *blk_get_attached_dev(BlockBackend *blk); | ||
183 | +BlockBackend *blk_by_dev(void *dev); | ||
184 | +BlockBackend *blk_by_qdev_id(const char *id, Error **errp); | ||
185 | +void blk_set_dev_ops(BlockBackend *blk, const BlockDevOps *ops, void *opaque); | ||
186 | + | ||
187 | +void blk_activate(BlockBackend *blk, Error **errp); | ||
188 | + | ||
189 | +int blk_make_zero(BlockBackend *blk, BdrvRequestFlags flags); | ||
190 | +void blk_aio_cancel(BlockAIOCB *acb); | ||
191 | +int blk_commit_all(void); | ||
192 | +void blk_drain(BlockBackend *blk); | ||
193 | +void blk_drain_all(void); | ||
194 | +void blk_set_on_error(BlockBackend *blk, BlockdevOnError on_read_error, | ||
195 | + BlockdevOnError on_write_error); | ||
196 | +bool blk_supports_write_perm(BlockBackend *blk); | ||
197 | +bool blk_is_sg(BlockBackend *blk); | ||
198 | +void blk_set_enable_write_cache(BlockBackend *blk, bool wce); | ||
199 | +int blk_get_flags(BlockBackend *blk); | ||
200 | +bool blk_op_is_blocked(BlockBackend *blk, BlockOpType op, Error **errp); | ||
201 | +void blk_op_unblock(BlockBackend *blk, BlockOpType op, Error *reason); | ||
202 | +void blk_op_block_all(BlockBackend *blk, Error *reason); | ||
203 | +void blk_op_unblock_all(BlockBackend *blk, Error *reason); | ||
204 | +int blk_set_aio_context(BlockBackend *blk, AioContext *new_context, | ||
205 | + Error **errp); | ||
206 | +void blk_add_aio_context_notifier(BlockBackend *blk, | ||
207 | + void (*attached_aio_context)(AioContext *new_context, void *opaque), | ||
208 | + void (*detach_aio_context)(void *opaque), void *opaque); | ||
209 | +void blk_remove_aio_context_notifier(BlockBackend *blk, | ||
210 | + void (*attached_aio_context)(AioContext *, | ||
211 | + void *), | ||
212 | + void (*detach_aio_context)(void *), | ||
213 | + void *opaque); | ||
214 | +void blk_add_remove_bs_notifier(BlockBackend *blk, Notifier *notify); | ||
215 | +void blk_add_insert_bs_notifier(BlockBackend *blk, Notifier *notify); | ||
216 | +BlockBackendRootState *blk_get_root_state(BlockBackend *blk); | ||
217 | +void blk_update_root_state(BlockBackend *blk); | ||
218 | +bool blk_get_detect_zeroes_from_root_state(BlockBackend *blk); | ||
219 | +int blk_get_open_flags_from_root_state(BlockBackend *blk); | ||
220 | + | ||
221 | +int blk_save_vmstate(BlockBackend *blk, const uint8_t *buf, | ||
222 | + int64_t pos, int size); | ||
223 | +int blk_load_vmstate(BlockBackend *blk, uint8_t *buf, int64_t pos, int size); | ||
224 | +int blk_probe_blocksizes(BlockBackend *blk, BlockSizes *bsz); | ||
225 | +int blk_probe_geometry(BlockBackend *blk, HDGeometry *geo); | ||
226 | + | ||
227 | +void blk_set_io_limits(BlockBackend *blk, ThrottleConfig *cfg); | ||
228 | +void blk_io_limits_disable(BlockBackend *blk); | ||
229 | +void blk_io_limits_enable(BlockBackend *blk, const char *group); | ||
230 | +void blk_io_limits_update_group(BlockBackend *blk, const char *group); | ||
231 | +void blk_set_force_allow_inactivate(BlockBackend *blk); | ||
232 | + | ||
233 | +void blk_register_buf(BlockBackend *blk, void *host, size_t size); | ||
234 | +void blk_unregister_buf(BlockBackend *blk, void *host); | ||
235 | + | ||
236 | +const BdrvChild *blk_root(BlockBackend *blk); | ||
237 | + | ||
238 | +int blk_make_empty(BlockBackend *blk, Error **errp); | ||
239 | + | ||
240 | +#endif /* BLOCK_BACKEND_GS_H */ | ||
241 | diff --git a/include/sysemu/block-backend-io.h b/include/sysemu/block-backend-io.h | ||
242 | new file mode 100644 | ||
243 | index XXXXXXX..XXXXXXX | ||
244 | --- /dev/null | ||
245 | +++ b/include/sysemu/block-backend-io.h | ||
246 | @@ -XXX,XX +XXX,XX @@ | ||
247 | +/* | ||
248 | + * QEMU Block backends | ||
249 | + * | ||
250 | + * Copyright (C) 2014-2016 Red Hat, Inc. | ||
251 | + * | ||
252 | + * Authors: | ||
253 | + * Markus Armbruster <armbru@redhat.com>, | ||
254 | + * | ||
255 | + * This work is licensed under the terms of the GNU LGPL, version 2.1 | ||
256 | + * or later. See the COPYING.LIB file in the top-level directory. | ||
257 | + */ | ||
258 | + | ||
259 | +#ifndef BLOCK_BACKEND_IO_H | ||
260 | +#define BLOCK_BACKEND_IO_H | ||
261 | + | ||
262 | +#include "block-backend-common.h" | ||
263 | + | ||
264 | +/* | ||
265 | + * I/O API functions. These functions are thread-safe. | ||
266 | + * | ||
267 | + * See include/block/block-io.h for more information about | ||
268 | + * the I/O API. | ||
269 | + */ | ||
270 | + | ||
271 | +const char *blk_name(const BlockBackend *blk); | ||
272 | + | ||
273 | +BlockDriverState *blk_bs(BlockBackend *blk); | ||
274 | + | ||
275 | +void blk_set_allow_write_beyond_eof(BlockBackend *blk, bool allow); | ||
276 | +void blk_set_allow_aio_context_change(BlockBackend *blk, bool allow); | ||
277 | +void blk_set_disable_request_queuing(BlockBackend *blk, bool disable); | ||
278 | +bool blk_iostatus_is_enabled(const BlockBackend *blk); | ||
279 | + | ||
280 | +char *blk_get_attached_dev_id(BlockBackend *blk); | ||
281 | + | ||
282 | +BlockAIOCB *blk_aio_pwrite_zeroes(BlockBackend *blk, int64_t offset, | ||
283 | + int64_t bytes, BdrvRequestFlags flags, | ||
284 | + BlockCompletionFunc *cb, void *opaque); | ||
285 | + | ||
286 | +BlockAIOCB *blk_aio_preadv(BlockBackend *blk, int64_t offset, | ||
287 | + QEMUIOVector *qiov, BdrvRequestFlags flags, | ||
288 | + BlockCompletionFunc *cb, void *opaque); | ||
289 | +BlockAIOCB *blk_aio_pwritev(BlockBackend *blk, int64_t offset, | ||
290 | + QEMUIOVector *qiov, BdrvRequestFlags flags, | ||
291 | + BlockCompletionFunc *cb, void *opaque); | ||
292 | +BlockAIOCB *blk_aio_flush(BlockBackend *blk, | ||
293 | + BlockCompletionFunc *cb, void *opaque); | ||
294 | +BlockAIOCB *blk_aio_pdiscard(BlockBackend *blk, int64_t offset, int64_t bytes, | ||
295 | + BlockCompletionFunc *cb, void *opaque); | ||
296 | +void blk_aio_cancel_async(BlockAIOCB *acb); | ||
297 | +BlockAIOCB *blk_aio_ioctl(BlockBackend *blk, unsigned long int req, void *buf, | ||
298 | + BlockCompletionFunc *cb, void *opaque); | ||
299 | + | ||
300 | +void blk_inc_in_flight(BlockBackend *blk); | ||
301 | +void blk_dec_in_flight(BlockBackend *blk); | ||
302 | +bool blk_is_inserted(BlockBackend *blk); | ||
303 | +bool blk_is_available(BlockBackend *blk); | ||
304 | +void blk_lock_medium(BlockBackend *blk, bool locked); | ||
305 | +void blk_eject(BlockBackend *blk, bool eject_flag); | ||
306 | +int64_t blk_getlength(BlockBackend *blk); | ||
307 | +void blk_get_geometry(BlockBackend *blk, uint64_t *nb_sectors_ptr); | ||
308 | +int64_t blk_nb_sectors(BlockBackend *blk); | ||
309 | +void *blk_try_blockalign(BlockBackend *blk, size_t size); | ||
310 | +void *blk_blockalign(BlockBackend *blk, size_t size); | ||
311 | +bool blk_is_writable(BlockBackend *blk); | ||
312 | +bool blk_enable_write_cache(BlockBackend *blk); | ||
313 | +BlockdevOnError blk_get_on_error(BlockBackend *blk, bool is_read); | ||
314 | +BlockErrorAction blk_get_error_action(BlockBackend *blk, bool is_read, | ||
315 | + int error); | ||
316 | +void blk_error_action(BlockBackend *blk, BlockErrorAction action, | ||
317 | + bool is_read, int error); | ||
318 | +void blk_iostatus_set_err(BlockBackend *blk, int error); | ||
319 | +int blk_get_max_iov(BlockBackend *blk); | ||
320 | +int blk_get_max_hw_iov(BlockBackend *blk); | ||
321 | +void blk_set_guest_block_size(BlockBackend *blk, int align); | ||
322 | + | ||
323 | +void blk_io_plug(BlockBackend *blk); | ||
324 | +void blk_io_unplug(BlockBackend *blk); | ||
325 | +AioContext *blk_get_aio_context(BlockBackend *blk); | ||
326 | +BlockAcctStats *blk_get_stats(BlockBackend *blk); | ||
327 | +void *blk_aio_get(const AIOCBInfo *aiocb_info, BlockBackend *blk, | ||
328 | + BlockCompletionFunc *cb, void *opaque); | ||
329 | +BlockAIOCB *blk_abort_aio_request(BlockBackend *blk, | ||
330 | + BlockCompletionFunc *cb, | ||
331 | + void *opaque, int ret); | ||
332 | + | ||
333 | +uint32_t blk_get_request_alignment(BlockBackend *blk); | ||
334 | +uint32_t blk_get_max_transfer(BlockBackend *blk); | ||
335 | +uint64_t blk_get_max_hw_transfer(BlockBackend *blk); | ||
336 | + | ||
337 | +int coroutine_fn blk_co_copy_range(BlockBackend *blk_in, int64_t off_in, | ||
338 | + BlockBackend *blk_out, int64_t off_out, | ||
339 | + int64_t bytes, BdrvRequestFlags read_flags, | ||
340 | + BdrvRequestFlags write_flags); | ||
341 | + | ||
342 | + | ||
343 | +/* | ||
344 | + * "I/O or GS" API functions. These functions can run without | ||
345 | + * the BQL, but only in one specific iothread/main loop. | ||
346 | + * | ||
347 | + * See include/block/block-io.h for more information about | ||
348 | + * the "I/O or GS" API. | ||
349 | + */ | ||
350 | + | ||
351 | +int blk_pread(BlockBackend *blk, int64_t offset, void *buf, int bytes); | ||
352 | +int blk_pwrite(BlockBackend *blk, int64_t offset, const void *buf, int bytes, | ||
353 | + BdrvRequestFlags flags); | ||
354 | +int coroutine_fn blk_co_preadv(BlockBackend *blk, int64_t offset, | ||
355 | + int64_t bytes, QEMUIOVector *qiov, | ||
356 | + BdrvRequestFlags flags); | ||
357 | +int coroutine_fn blk_co_pwritev_part(BlockBackend *blk, int64_t offset, | ||
358 | + int64_t bytes, | ||
359 | + QEMUIOVector *qiov, size_t qiov_offset, | ||
360 | + BdrvRequestFlags flags); | ||
361 | +int coroutine_fn blk_co_pwritev(BlockBackend *blk, int64_t offset, | ||
362 | + int64_t bytes, QEMUIOVector *qiov, | ||
363 | + BdrvRequestFlags flags); | ||
364 | + | ||
365 | +static inline int coroutine_fn blk_co_pread(BlockBackend *blk, int64_t offset, | ||
366 | + int64_t bytes, void *buf, | ||
367 | + BdrvRequestFlags flags) | ||
368 | +{ | ||
369 | + QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes); | ||
370 | + | ||
371 | + assert(bytes <= SIZE_MAX); | ||
372 | + | ||
373 | + return blk_co_preadv(blk, offset, bytes, &qiov, flags); | ||
374 | +} | 47 | +} |
375 | + | 48 | + |
376 | +static inline int coroutine_fn blk_co_pwrite(BlockBackend *blk, int64_t offset, | 49 | +static void test_quiesce_drain_all(void) |
377 | + int64_t bytes, void *buf, | ||
378 | + BdrvRequestFlags flags) | ||
379 | +{ | 50 | +{ |
380 | + QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes); | 51 | + // XXX drain_all doesn't quiesce |
381 | + | 52 | + //test_quiesce_common(BDRV_DRAIN_ALL, true); |
382 | + assert(bytes <= SIZE_MAX); | ||
383 | + | ||
384 | + return blk_co_pwritev(blk, offset, bytes, &qiov, flags); | ||
385 | +} | 53 | +} |
386 | + | 54 | + |
387 | +int coroutine_fn blk_co_pdiscard(BlockBackend *blk, int64_t offset, | 55 | +static void test_quiesce_drain(void) |
388 | + int64_t bytes); | 56 | +{ |
57 | + test_quiesce_common(BDRV_DRAIN, false); | ||
58 | +} | ||
389 | + | 59 | + |
390 | +int coroutine_fn blk_co_flush(BlockBackend *blk); | 60 | int main(int argc, char **argv) |
391 | +int blk_flush(BlockBackend *blk); | 61 | { |
62 | bdrv_init(); | ||
63 | @@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv) | ||
64 | g_test_add_func("/bdrv-drain/driver-cb/drain_all", test_drv_cb_drain_all); | ||
65 | g_test_add_func("/bdrv-drain/driver-cb/drain", test_drv_cb_drain); | ||
66 | |||
67 | + g_test_add_func("/bdrv-drain/quiesce/drain_all", test_quiesce_drain_all); | ||
68 | + g_test_add_func("/bdrv-drain/quiesce/drain", test_quiesce_drain); | ||
392 | + | 69 | + |
393 | +int blk_ioctl(BlockBackend *blk, unsigned long int req, void *buf); | 70 | return g_test_run(); |
394 | + | 71 | } |
395 | +int blk_pwrite_compressed(BlockBackend *blk, int64_t offset, const void *buf, | ||
396 | + int64_t bytes); | ||
397 | +int blk_pdiscard(BlockBackend *blk, int64_t offset, int64_t bytes); | ||
398 | +int blk_pwrite_zeroes(BlockBackend *blk, int64_t offset, | ||
399 | + int64_t bytes, BdrvRequestFlags flags); | ||
400 | +int coroutine_fn blk_co_pwrite_zeroes(BlockBackend *blk, int64_t offset, | ||
401 | + int64_t bytes, BdrvRequestFlags flags); | ||
402 | +int blk_truncate(BlockBackend *blk, int64_t offset, bool exact, | ||
403 | + PreallocMode prealloc, BdrvRequestFlags flags, Error **errp); | ||
404 | + | ||
405 | +#endif /* BLOCK_BACKEND_IO_H */ | ||
406 | diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h | ||
407 | index XXXXXXX..XXXXXXX 100644 | ||
408 | --- a/include/sysemu/block-backend.h | ||
409 | +++ b/include/sysemu/block-backend.h | ||
410 | @@ -XXX,XX +XXX,XX @@ | ||
411 | #ifndef BLOCK_BACKEND_H | ||
412 | #define BLOCK_BACKEND_H | ||
413 | |||
414 | -#include "qemu/iov.h" | ||
415 | -#include "block/throttle-groups.h" | ||
416 | +#include "block-backend-global-state.h" | ||
417 | +#include "block-backend-io.h" | ||
418 | |||
419 | -/* | ||
420 | - * TODO Have to include block/block.h for a bunch of block layer | ||
421 | - * types. Unfortunately, this pulls in the whole BlockDriverState | ||
422 | - * API, which we don't want used by many BlockBackend users. Some of | ||
423 | - * the types belong here, and the rest should be split into a common | ||
424 | - * header and one for the BlockDriverState API. | ||
425 | - */ | ||
426 | -#include "block/block.h" | ||
427 | - | ||
428 | -/* Callbacks for block device models */ | ||
429 | -typedef struct BlockDevOps { | ||
430 | - /* | ||
431 | - * Runs when virtual media changed (monitor commands eject, change) | ||
432 | - * Argument load is true on load and false on eject. | ||
433 | - * Beware: doesn't run when a host device's physical media | ||
434 | - * changes. Sure would be useful if it did. | ||
435 | - * Device models with removable media must implement this callback. | ||
436 | - */ | ||
437 | - void (*change_media_cb)(void *opaque, bool load, Error **errp); | ||
438 | - /* | ||
439 | - * Runs when an eject request is issued from the monitor, the tray | ||
440 | - * is closed, and the medium is locked. | ||
441 | - * Device models that do not implement is_medium_locked will not need | ||
442 | - * this callback. Device models that can lock the medium or tray might | ||
443 | - * want to implement the callback and unlock the tray when "force" is | ||
444 | - * true, even if they do not support eject requests. | ||
445 | - */ | ||
446 | - void (*eject_request_cb)(void *opaque, bool force); | ||
447 | - /* | ||
448 | - * Is the virtual tray open? | ||
449 | - * Device models implement this only when the device has a tray. | ||
450 | - */ | ||
451 | - bool (*is_tray_open)(void *opaque); | ||
452 | - /* | ||
453 | - * Is the virtual medium locked into the device? | ||
454 | - * Device models implement this only when device has such a lock. | ||
455 | - */ | ||
456 | - bool (*is_medium_locked)(void *opaque); | ||
457 | - /* | ||
458 | - * Runs when the size changed (e.g. monitor command block_resize) | ||
459 | - */ | ||
460 | - void (*resize_cb)(void *opaque); | ||
461 | - /* | ||
462 | - * Runs when the backend receives a drain request. | ||
463 | - */ | ||
464 | - void (*drained_begin)(void *opaque); | ||
465 | - /* | ||
466 | - * Runs when the backend's last drain request ends. | ||
467 | - */ | ||
468 | - void (*drained_end)(void *opaque); | ||
469 | - /* | ||
470 | - * Is the device still busy? | ||
471 | - */ | ||
472 | - bool (*drained_poll)(void *opaque); | ||
473 | -} BlockDevOps; | ||
474 | - | ||
475 | -/* This struct is embedded in (the private) BlockBackend struct and contains | ||
476 | - * fields that must be public. This is in particular for QLIST_ENTRY() and | ||
477 | - * friends so that BlockBackends can be kept in lists outside block-backend.c | ||
478 | - * */ | ||
479 | -typedef struct BlockBackendPublic { | ||
480 | - ThrottleGroupMember throttle_group_member; | ||
481 | -} BlockBackendPublic; | ||
482 | - | ||
483 | -BlockBackend *blk_new(AioContext *ctx, uint64_t perm, uint64_t shared_perm); | ||
484 | -BlockBackend *blk_new_with_bs(BlockDriverState *bs, uint64_t perm, | ||
485 | - uint64_t shared_perm, Error **errp); | ||
486 | -BlockBackend *blk_new_open(const char *filename, const char *reference, | ||
487 | - QDict *options, int flags, Error **errp); | ||
488 | -int blk_get_refcnt(BlockBackend *blk); | ||
489 | -void blk_ref(BlockBackend *blk); | ||
490 | -void blk_unref(BlockBackend *blk); | ||
491 | -void blk_remove_all_bs(void); | ||
492 | -const char *blk_name(const BlockBackend *blk); | ||
493 | -BlockBackend *blk_by_name(const char *name); | ||
494 | -BlockBackend *blk_next(BlockBackend *blk); | ||
495 | -BlockBackend *blk_all_next(BlockBackend *blk); | ||
496 | -bool monitor_add_blk(BlockBackend *blk, const char *name, Error **errp); | ||
497 | -void monitor_remove_blk(BlockBackend *blk); | ||
498 | - | ||
499 | -BlockBackendPublic *blk_get_public(BlockBackend *blk); | ||
500 | -BlockBackend *blk_by_public(BlockBackendPublic *public); | ||
501 | - | ||
502 | -BlockDriverState *blk_bs(BlockBackend *blk); | ||
503 | -void blk_remove_bs(BlockBackend *blk); | ||
504 | -int blk_insert_bs(BlockBackend *blk, BlockDriverState *bs, Error **errp); | ||
505 | -int blk_replace_bs(BlockBackend *blk, BlockDriverState *new_bs, Error **errp); | ||
506 | -bool bdrv_has_blk(BlockDriverState *bs); | ||
507 | -bool bdrv_is_root_node(BlockDriverState *bs); | ||
508 | -int blk_set_perm(BlockBackend *blk, uint64_t perm, uint64_t shared_perm, | ||
509 | - Error **errp); | ||
510 | -void blk_get_perm(BlockBackend *blk, uint64_t *perm, uint64_t *shared_perm); | ||
511 | - | ||
512 | -void blk_set_allow_write_beyond_eof(BlockBackend *blk, bool allow); | ||
513 | -void blk_set_allow_aio_context_change(BlockBackend *blk, bool allow); | ||
514 | -void blk_set_disable_request_queuing(BlockBackend *blk, bool disable); | ||
515 | -void blk_iostatus_enable(BlockBackend *blk); | ||
516 | -bool blk_iostatus_is_enabled(const BlockBackend *blk); | ||
517 | -BlockDeviceIoStatus blk_iostatus(const BlockBackend *blk); | ||
518 | -void blk_iostatus_disable(BlockBackend *blk); | ||
519 | -void blk_iostatus_reset(BlockBackend *blk); | ||
520 | -void blk_iostatus_set_err(BlockBackend *blk, int error); | ||
521 | -int blk_attach_dev(BlockBackend *blk, DeviceState *dev); | ||
522 | -void blk_detach_dev(BlockBackend *blk, DeviceState *dev); | ||
523 | -DeviceState *blk_get_attached_dev(BlockBackend *blk); | ||
524 | -char *blk_get_attached_dev_id(BlockBackend *blk); | ||
525 | -BlockBackend *blk_by_dev(void *dev); | ||
526 | -BlockBackend *blk_by_qdev_id(const char *id, Error **errp); | ||
527 | -void blk_set_dev_ops(BlockBackend *blk, const BlockDevOps *ops, void *opaque); | ||
528 | -int coroutine_fn blk_co_preadv(BlockBackend *blk, int64_t offset, | ||
529 | - int64_t bytes, QEMUIOVector *qiov, | ||
530 | - BdrvRequestFlags flags); | ||
531 | -int coroutine_fn blk_co_pwritev_part(BlockBackend *blk, int64_t offset, | ||
532 | - int64_t bytes, | ||
533 | - QEMUIOVector *qiov, size_t qiov_offset, | ||
534 | - BdrvRequestFlags flags); | ||
535 | -int coroutine_fn blk_co_pwritev(BlockBackend *blk, int64_t offset, | ||
536 | - int64_t bytes, QEMUIOVector *qiov, | ||
537 | - BdrvRequestFlags flags); | ||
538 | - | ||
539 | -static inline int coroutine_fn blk_co_pread(BlockBackend *blk, int64_t offset, | ||
540 | - int64_t bytes, void *buf, | ||
541 | - BdrvRequestFlags flags) | ||
542 | -{ | ||
543 | - QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes); | ||
544 | - | ||
545 | - assert(bytes <= SIZE_MAX); | ||
546 | - | ||
547 | - return blk_co_preadv(blk, offset, bytes, &qiov, flags); | ||
548 | -} | ||
549 | - | ||
550 | -static inline int coroutine_fn blk_co_pwrite(BlockBackend *blk, int64_t offset, | ||
551 | - int64_t bytes, void *buf, | ||
552 | - BdrvRequestFlags flags) | ||
553 | -{ | ||
554 | - QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes); | ||
555 | - | ||
556 | - assert(bytes <= SIZE_MAX); | ||
557 | - | ||
558 | - return blk_co_pwritev(blk, offset, bytes, &qiov, flags); | ||
559 | -} | ||
560 | - | ||
561 | -int blk_pwrite_zeroes(BlockBackend *blk, int64_t offset, | ||
562 | - int64_t bytes, BdrvRequestFlags flags); | ||
563 | -BlockAIOCB *blk_aio_pwrite_zeroes(BlockBackend *blk, int64_t offset, | ||
564 | - int64_t bytes, BdrvRequestFlags flags, | ||
565 | - BlockCompletionFunc *cb, void *opaque); | ||
566 | -int blk_make_zero(BlockBackend *blk, BdrvRequestFlags flags); | ||
567 | -int blk_pread(BlockBackend *blk, int64_t offset, void *buf, int bytes); | ||
568 | -int blk_pwrite(BlockBackend *blk, int64_t offset, const void *buf, int bytes, | ||
569 | - BdrvRequestFlags flags); | ||
570 | -int64_t blk_getlength(BlockBackend *blk); | ||
571 | -void blk_get_geometry(BlockBackend *blk, uint64_t *nb_sectors_ptr); | ||
572 | -int64_t blk_nb_sectors(BlockBackend *blk); | ||
573 | -BlockAIOCB *blk_aio_preadv(BlockBackend *blk, int64_t offset, | ||
574 | - QEMUIOVector *qiov, BdrvRequestFlags flags, | ||
575 | - BlockCompletionFunc *cb, void *opaque); | ||
576 | -BlockAIOCB *blk_aio_pwritev(BlockBackend *blk, int64_t offset, | ||
577 | - QEMUIOVector *qiov, BdrvRequestFlags flags, | ||
578 | - BlockCompletionFunc *cb, void *opaque); | ||
579 | -BlockAIOCB *blk_aio_flush(BlockBackend *blk, | ||
580 | - BlockCompletionFunc *cb, void *opaque); | ||
581 | -BlockAIOCB *blk_aio_pdiscard(BlockBackend *blk, int64_t offset, int64_t bytes, | ||
582 | - BlockCompletionFunc *cb, void *opaque); | ||
583 | -void blk_aio_cancel(BlockAIOCB *acb); | ||
584 | -void blk_aio_cancel_async(BlockAIOCB *acb); | ||
585 | -int blk_ioctl(BlockBackend *blk, unsigned long int req, void *buf); | ||
586 | -BlockAIOCB *blk_aio_ioctl(BlockBackend *blk, unsigned long int req, void *buf, | ||
587 | - BlockCompletionFunc *cb, void *opaque); | ||
588 | -int coroutine_fn blk_co_pdiscard(BlockBackend *blk, int64_t offset, | ||
589 | - int64_t bytes); | ||
590 | -int coroutine_fn blk_co_flush(BlockBackend *blk); | ||
591 | -int blk_flush(BlockBackend *blk); | ||
592 | -int blk_commit_all(void); | ||
593 | -void blk_inc_in_flight(BlockBackend *blk); | ||
594 | -void blk_dec_in_flight(BlockBackend *blk); | ||
595 | -void blk_drain(BlockBackend *blk); | ||
596 | -void blk_drain_all(void); | ||
597 | -void blk_set_on_error(BlockBackend *blk, BlockdevOnError on_read_error, | ||
598 | - BlockdevOnError on_write_error); | ||
599 | -BlockdevOnError blk_get_on_error(BlockBackend *blk, bool is_read); | ||
600 | -BlockErrorAction blk_get_error_action(BlockBackend *blk, bool is_read, | ||
601 | - int error); | ||
602 | -void blk_error_action(BlockBackend *blk, BlockErrorAction action, | ||
603 | - bool is_read, int error); | ||
604 | -bool blk_supports_write_perm(BlockBackend *blk); | ||
605 | -bool blk_is_writable(BlockBackend *blk); | ||
606 | -bool blk_is_sg(BlockBackend *blk); | ||
607 | -bool blk_enable_write_cache(BlockBackend *blk); | ||
608 | -void blk_set_enable_write_cache(BlockBackend *blk, bool wce); | ||
609 | -void blk_activate(BlockBackend *blk, Error **errp); | ||
610 | -bool blk_is_inserted(BlockBackend *blk); | ||
611 | -bool blk_is_available(BlockBackend *blk); | ||
612 | -void blk_lock_medium(BlockBackend *blk, bool locked); | ||
613 | -void blk_eject(BlockBackend *blk, bool eject_flag); | ||
614 | -int blk_get_flags(BlockBackend *blk); | ||
615 | -uint32_t blk_get_request_alignment(BlockBackend *blk); | ||
616 | -uint32_t blk_get_max_transfer(BlockBackend *blk); | ||
617 | -uint64_t blk_get_max_hw_transfer(BlockBackend *blk); | ||
618 | -int blk_get_max_iov(BlockBackend *blk); | ||
619 | -int blk_get_max_hw_iov(BlockBackend *blk); | ||
620 | -void blk_set_guest_block_size(BlockBackend *blk, int align); | ||
621 | -void *blk_try_blockalign(BlockBackend *blk, size_t size); | ||
622 | -void *blk_blockalign(BlockBackend *blk, size_t size); | ||
623 | -bool blk_op_is_blocked(BlockBackend *blk, BlockOpType op, Error **errp); | ||
624 | -void blk_op_unblock(BlockBackend *blk, BlockOpType op, Error *reason); | ||
625 | -void blk_op_block_all(BlockBackend *blk, Error *reason); | ||
626 | -void blk_op_unblock_all(BlockBackend *blk, Error *reason); | ||
627 | -AioContext *blk_get_aio_context(BlockBackend *blk); | ||
628 | -int blk_set_aio_context(BlockBackend *blk, AioContext *new_context, | ||
629 | - Error **errp); | ||
630 | -void blk_add_aio_context_notifier(BlockBackend *blk, | ||
631 | - void (*attached_aio_context)(AioContext *new_context, void *opaque), | ||
632 | - void (*detach_aio_context)(void *opaque), void *opaque); | ||
633 | -void blk_remove_aio_context_notifier(BlockBackend *blk, | ||
634 | - void (*attached_aio_context)(AioContext *, | ||
635 | - void *), | ||
636 | - void (*detach_aio_context)(void *), | ||
637 | - void *opaque); | ||
638 | -void blk_add_remove_bs_notifier(BlockBackend *blk, Notifier *notify); | ||
639 | -void blk_add_insert_bs_notifier(BlockBackend *blk, Notifier *notify); | ||
640 | -void blk_io_plug(BlockBackend *blk); | ||
641 | -void blk_io_unplug(BlockBackend *blk); | ||
642 | -BlockAcctStats *blk_get_stats(BlockBackend *blk); | ||
643 | -BlockBackendRootState *blk_get_root_state(BlockBackend *blk); | ||
644 | -void blk_update_root_state(BlockBackend *blk); | ||
645 | -bool blk_get_detect_zeroes_from_root_state(BlockBackend *blk); | ||
646 | -int blk_get_open_flags_from_root_state(BlockBackend *blk); | ||
647 | - | ||
648 | -void *blk_aio_get(const AIOCBInfo *aiocb_info, BlockBackend *blk, | ||
649 | - BlockCompletionFunc *cb, void *opaque); | ||
650 | -int coroutine_fn blk_co_pwrite_zeroes(BlockBackend *blk, int64_t offset, | ||
651 | - int64_t bytes, BdrvRequestFlags flags); | ||
652 | -int blk_pwrite_compressed(BlockBackend *blk, int64_t offset, const void *buf, | ||
653 | - int64_t bytes); | ||
654 | -int blk_truncate(BlockBackend *blk, int64_t offset, bool exact, | ||
655 | - PreallocMode prealloc, BdrvRequestFlags flags, Error **errp); | ||
656 | -int blk_pdiscard(BlockBackend *blk, int64_t offset, int64_t bytes); | ||
657 | -int blk_save_vmstate(BlockBackend *blk, const uint8_t *buf, | ||
658 | - int64_t pos, int size); | ||
659 | -int blk_load_vmstate(BlockBackend *blk, uint8_t *buf, int64_t pos, int size); | ||
660 | -int blk_probe_blocksizes(BlockBackend *blk, BlockSizes *bsz); | ||
661 | -int blk_probe_geometry(BlockBackend *blk, HDGeometry *geo); | ||
662 | -BlockAIOCB *blk_abort_aio_request(BlockBackend *blk, | ||
663 | - BlockCompletionFunc *cb, | ||
664 | - void *opaque, int ret); | ||
665 | - | ||
666 | -void blk_set_io_limits(BlockBackend *blk, ThrottleConfig *cfg); | ||
667 | -void blk_io_limits_disable(BlockBackend *blk); | ||
668 | -void blk_io_limits_enable(BlockBackend *blk, const char *group); | ||
669 | -void blk_io_limits_update_group(BlockBackend *blk, const char *group); | ||
670 | -void blk_set_force_allow_inactivate(BlockBackend *blk); | ||
671 | - | ||
672 | -void blk_register_buf(BlockBackend *blk, void *host, size_t size); | ||
673 | -void blk_unregister_buf(BlockBackend *blk, void *host); | ||
674 | - | ||
675 | -int coroutine_fn blk_co_copy_range(BlockBackend *blk_in, int64_t off_in, | ||
676 | - BlockBackend *blk_out, int64_t off_out, | ||
677 | - int64_t bytes, BdrvRequestFlags read_flags, | ||
678 | - BdrvRequestFlags write_flags); | ||
679 | - | ||
680 | -const BdrvChild *blk_root(BlockBackend *blk); | ||
681 | - | ||
682 | -int blk_make_empty(BlockBackend *blk, Error **errp); | ||
683 | +/* DO NOT ADD ANYTHING IN HERE. USE ONE OF THE HEADERS INCLUDED ABOVE */ | ||
684 | |||
685 | #endif | ||
686 | diff --git a/block/block-backend.c b/block/block-backend.c | ||
687 | index XXXXXXX..XXXXXXX 100644 | ||
688 | --- a/block/block-backend.c | ||
689 | +++ b/block/block-backend.c | ||
690 | @@ -XXX,XX +XXX,XX @@ struct BlockBackend { | ||
691 | bool allow_aio_context_change; | ||
692 | bool allow_write_beyond_eof; | ||
693 | |||
694 | + /* Protected by BQL */ | ||
695 | NotifierList remove_bs_notifiers, insert_bs_notifiers; | ||
696 | QLIST_HEAD(, BlockBackendAioNotifier) aio_notifiers; | ||
697 | |||
698 | @@ -XXX,XX +XXX,XX @@ static const AIOCBInfo block_backend_aiocb_info = { | ||
699 | static void drive_info_del(DriveInfo *dinfo); | ||
700 | static BlockBackend *bdrv_first_blk(BlockDriverState *bs); | ||
701 | |||
702 | -/* All BlockBackends */ | ||
703 | +/* All BlockBackends. Protected by BQL. */ | ||
704 | static QTAILQ_HEAD(, BlockBackend) block_backends = | ||
705 | QTAILQ_HEAD_INITIALIZER(block_backends); | ||
706 | |||
707 | -/* All BlockBackends referenced by the monitor and which are iterated through by | ||
708 | - * blk_next() */ | ||
709 | +/* | ||
710 | + * All BlockBackends referenced by the monitor and which are iterated through by | ||
711 | + * blk_next(). Protected by BQL. | ||
712 | + */ | ||
713 | static QTAILQ_HEAD(, BlockBackend) monitor_block_backends = | ||
714 | QTAILQ_HEAD_INITIALIZER(monitor_block_backends); | ||
715 | |||
716 | -- | 72 | -- |
717 | 2.35.1 | 73 | 2.13.6 |
74 | |||
75 | diff view generated by jsdifflib |
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | 1 | Block jobs already paused themselves when their main BlockBackend |
---|---|---|---|
2 | entered a drained section. This is not good enough: We also want to | ||
3 | pause a block job and may not submit new requests if, for example, the | ||
4 | mirror target node should be drained. | ||
2 | 5 | ||
3 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | 6 | This implements .drained_begin/end callbacks in child_job in order to |
4 | Message-Id: <20220303151616.325444-20-eesposit@redhat.com> | 7 | consider all block nodes related to the job, and removes the |
8 | BlockBackend callbacks which are unnecessary now because the root of the | ||
9 | job main BlockBackend is always referenced with a child_job, too. | ||
10 | |||
5 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
6 | --- | 12 | --- |
7 | blockjob.c | 11 +++++++++++ | 13 | blockjob.c | 22 +++++++++------------- |
8 | 1 file changed, 11 insertions(+) | 14 | 1 file changed, 9 insertions(+), 13 deletions(-) |
9 | 15 | ||
10 | diff --git a/blockjob.c b/blockjob.c | 16 | diff --git a/blockjob.c b/blockjob.c |
11 | index XXXXXXX..XXXXXXX 100644 | 17 | index XXXXXXX..XXXXXXX 100644 |
12 | --- a/blockjob.c | 18 | --- a/blockjob.c |
13 | +++ b/blockjob.c | 19 | +++ b/blockjob.c |
14 | @@ -XXX,XX +XXX,XX @@ static bool is_block_job(Job *job) | 20 | @@ -XXX,XX +XXX,XX @@ static char *child_job_get_parent_desc(BdrvChild *c) |
15 | BlockJob *block_job_next(BlockJob *bjob) | 21 | job->id); |
22 | } | ||
23 | |||
24 | -static const BdrvChildRole child_job = { | ||
25 | - .get_parent_desc = child_job_get_parent_desc, | ||
26 | - .stay_at_node = true, | ||
27 | -}; | ||
28 | - | ||
29 | -static void block_job_drained_begin(void *opaque) | ||
30 | +static void child_job_drained_begin(BdrvChild *c) | ||
16 | { | 31 | { |
17 | Job *job = bjob ? &bjob->job : NULL; | 32 | - BlockJob *job = opaque; |
18 | + GLOBAL_STATE_CODE(); | 33 | + BlockJob *job = c->opaque; |
19 | 34 | block_job_pause(job); | |
20 | do { | 35 | } |
21 | job = job_next(job); | 36 | |
22 | @@ -XXX,XX +XXX,XX @@ BlockJob *block_job_next(BlockJob *bjob) | 37 | -static void block_job_drained_end(void *opaque) |
23 | BlockJob *block_job_get(const char *id) | 38 | +static void child_job_drained_end(BdrvChild *c) |
24 | { | 39 | { |
25 | Job *job = job_get(id); | 40 | - BlockJob *job = opaque; |
26 | + GLOBAL_STATE_CODE(); | 41 | + BlockJob *job = c->opaque; |
27 | 42 | block_job_resume(job); | |
28 | if (job && is_block_job(job)) { | 43 | } |
29 | return container_of(job, BlockJob, job); | 44 | |
30 | @@ -XXX,XX +XXX,XX @@ static const BdrvChildClass child_job = { | 45 | -static const BlockDevOps block_job_dev_ops = { |
46 | - .drained_begin = block_job_drained_begin, | ||
47 | - .drained_end = block_job_drained_end, | ||
48 | +static const BdrvChildRole child_job = { | ||
49 | + .get_parent_desc = child_job_get_parent_desc, | ||
50 | + .drained_begin = child_job_drained_begin, | ||
51 | + .drained_end = child_job_drained_end, | ||
52 | + .stay_at_node = true, | ||
53 | }; | ||
31 | 54 | ||
32 | void block_job_remove_all_bdrv(BlockJob *job) | 55 | void block_job_remove_all_bdrv(BlockJob *job) |
33 | { | 56 | @@ -XXX,XX +XXX,XX @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver, |
34 | + GLOBAL_STATE_CODE(); | 57 | block_job_add_bdrv(job, "main node", bs, 0, BLK_PERM_ALL, &error_abort); |
35 | /* | 58 | bs->job = job; |
36 | * bdrv_root_unref_child() may reach child_job_[can_]set_aio_ctx(), | 59 | |
37 | * which will also traverse job->nodes, so consume the list one by | 60 | - blk_set_dev_ops(blk, &block_job_dev_ops, job); |
38 | @@ -XXX,XX +XXX,XX @@ void block_job_remove_all_bdrv(BlockJob *job) | 61 | bdrv_op_unblock(bs, BLOCK_OP_TYPE_DATAPLANE, job->blocker); |
39 | bool block_job_has_bdrv(BlockJob *job, BlockDriverState *bs) | 62 | |
40 | { | 63 | QLIST_INSERT_HEAD(&block_jobs, job, job_list); |
41 | GSList *el; | ||
42 | + GLOBAL_STATE_CODE(); | ||
43 | |||
44 | for (el = job->nodes; el; el = el->next) { | ||
45 | BdrvChild *c = el->data; | ||
46 | @@ -XXX,XX +XXX,XX @@ int block_job_add_bdrv(BlockJob *job, const char *name, BlockDriverState *bs, | ||
47 | { | ||
48 | BdrvChild *c; | ||
49 | bool need_context_ops; | ||
50 | + GLOBAL_STATE_CODE(); | ||
51 | |||
52 | bdrv_ref(bs); | ||
53 | |||
54 | @@ -XXX,XX +XXX,XX @@ bool block_job_set_speed(BlockJob *job, int64_t speed, Error **errp) | ||
55 | const BlockJobDriver *drv = block_job_driver(job); | ||
56 | int64_t old_speed = job->speed; | ||
57 | |||
58 | + GLOBAL_STATE_CODE(); | ||
59 | + | ||
60 | if (job_apply_verb(&job->job, JOB_VERB_SET_SPEED, errp) < 0) { | ||
61 | return false; | ||
62 | } | ||
63 | @@ -XXX,XX +XXX,XX @@ BlockJobInfo *block_job_query(BlockJob *job, Error **errp) | ||
64 | BlockJobInfo *info; | ||
65 | uint64_t progress_current, progress_total; | ||
66 | |||
67 | + GLOBAL_STATE_CODE(); | ||
68 | + | ||
69 | if (block_job_is_internal(job)) { | ||
70 | error_setg(errp, "Cannot query QEMU internal jobs"); | ||
71 | return NULL; | ||
72 | @@ -XXX,XX +XXX,XX @@ fail: | ||
73 | |||
74 | void block_job_iostatus_reset(BlockJob *job) | ||
75 | { | ||
76 | + GLOBAL_STATE_CODE(); | ||
77 | if (job->iostatus == BLOCK_DEVICE_IO_STATUS_OK) { | ||
78 | return; | ||
79 | } | ||
80 | @@ -XXX,XX +XXX,XX @@ BlockErrorAction block_job_error_action(BlockJob *job, BlockdevOnError on_err, | ||
81 | |||
82 | AioContext *block_job_get_aio_context(BlockJob *job) | ||
83 | { | ||
84 | + GLOBAL_STATE_CODE(); | ||
85 | return job->job.aio_context; | ||
86 | } | ||
87 | -- | 64 | -- |
88 | 2.35.1 | 65 | 2.13.6 |
66 | |||
67 | diff view generated by jsdifflib |
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | 1 | Block jobs must be paused if any of the involved nodes are drained. |
---|---|---|---|
2 | 2 | ||
3 | Move the permission API calls into driver-specific callbacks | ||
4 | that always run under BQL. In this case, bdrv_crypto_luks | ||
5 | needs to perform permission checks before and after | ||
6 | qcrypto_block_amend_options(). The problem is that the caller, | ||
7 | block_crypto_amend_options_generic_luks(), can also run in I/O | ||
8 | from .bdrv_co_amend(). This does not comply with Global State-I/O API split, | ||
9 | as permissions API must always run under BQL. | ||
10 | |||
11 | Firstly, introduce .bdrv_amend_pre_run() and .bdrv_amend_clean() | ||
12 | callbacks. These two callbacks are guaranteed to be invoked under | ||
13 | BQL, respectively before and after .bdrv_co_amend(). | ||
14 | They take care of performing the permission checks | ||
15 | in the same way as they are currently done before and after | ||
16 | qcrypto_block_amend_options(). | ||
17 | These callbacks are in preparation for next patch, where we | ||
18 | delete the original permission check. Right now they just add redundant | ||
19 | control. | ||
20 | |||
21 | Then, call .bdrv_amend_pre_run() before job_start in | ||
22 | qmp_x_blockdev_amend(), so that it will be run before the job coroutine | ||
23 | is created and stay in the main loop. | ||
24 | As a cleanup, use JobDriver's .clean() callback to call | ||
25 | .bdrv_amend_clean(), and run amend-specific cleanup callbacks under BQL. | ||
26 | |||
27 | After this patch, permission failures occur early in the blockdev-amend | ||
28 | job to update a LUKS volume's keys. iotest 296 must now expect them in | ||
29 | x-blockdev-amend's QMP reply instead of waiting for the actual job to | ||
30 | fail later. | ||
31 | |||
32 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
33 | Message-Id: <20220209105452.1694545-2-eesposit@redhat.com> | ||
34 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
35 | Message-Id: <20220304153729.711387-6-hreitz@redhat.com> | ||
36 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 3 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
37 | --- | 4 | --- |
38 | include/block/block_int.h | 14 ++++++++++++++ | 5 | tests/test-bdrv-drain.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++++ |
39 | block/amend.c | 25 +++++++++++++++++++++++++ | 6 | 1 file changed, 121 insertions(+) |
40 | block/crypto.c | 33 +++++++++++++++++++++++++++++++++ | ||
41 | tests/qemu-iotests/296 | 8 ++++++-- | ||
42 | tests/qemu-iotests/296.out | 17 +++++------------ | ||
43 | 5 files changed, 83 insertions(+), 14 deletions(-) | ||
44 | 7 | ||
45 | diff --git a/include/block/block_int.h b/include/block/block_int.h | 8 | diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c |
46 | index XXXXXXX..XXXXXXX 100644 | 9 | index XXXXXXX..XXXXXXX 100644 |
47 | --- a/include/block/block_int.h | 10 | --- a/tests/test-bdrv-drain.c |
48 | +++ b/include/block/block_int.h | 11 | +++ b/tests/test-bdrv-drain.c |
49 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { | 12 | @@ -XXX,XX +XXX,XX @@ |
50 | * on those children. | 13 | |
51 | */ | 14 | #include "qemu/osdep.h" |
52 | bool is_format; | 15 | #include "block/block.h" |
16 | +#include "block/blockjob_int.h" | ||
17 | #include "sysemu/block-backend.h" | ||
18 | #include "qapi/error.h" | ||
19 | |||
20 | @@ -XXX,XX +XXX,XX @@ static void test_quiesce_drain(void) | ||
21 | test_quiesce_common(BDRV_DRAIN, false); | ||
22 | } | ||
23 | |||
53 | + | 24 | + |
54 | + /* | 25 | +typedef struct TestBlockJob { |
55 | + * This function is invoked under BQL before .bdrv_co_amend() | 26 | + BlockJob common; |
56 | + * (which in contrast does not necessarily run under the BQL) | 27 | + bool should_complete; |
57 | + * to allow driver-specific initialization code that requires | 28 | +} TestBlockJob; |
58 | + * the BQL, like setting up specific permission flags. | ||
59 | + */ | ||
60 | + int (*bdrv_amend_pre_run)(BlockDriverState *bs, Error **errp); | ||
61 | + /* | ||
62 | + * This function is invoked under BQL after .bdrv_co_amend() | ||
63 | + * to allow cleaning up what was done in .bdrv_amend_pre_run(). | ||
64 | + */ | ||
65 | + void (*bdrv_amend_clean)(BlockDriverState *bs); | ||
66 | + | 29 | + |
67 | /* | 30 | +static void test_job_completed(BlockJob *job, void *opaque) |
68 | * Return true if @to_replace can be replaced by a BDS with the | ||
69 | * same data as @bs without it affecting @bs's behavior (that is, | ||
70 | diff --git a/block/amend.c b/block/amend.c | ||
71 | index XXXXXXX..XXXXXXX 100644 | ||
72 | --- a/block/amend.c | ||
73 | +++ b/block/amend.c | ||
74 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn blockdev_amend_run(Job *job, Error **errp) | ||
75 | return ret; | ||
76 | } | ||
77 | |||
78 | +static int blockdev_amend_pre_run(BlockdevAmendJob *s, Error **errp) | ||
79 | +{ | 31 | +{ |
80 | + if (s->bs->drv->bdrv_amend_pre_run) { | 32 | + block_job_completed(job, 0); |
81 | + return s->bs->drv->bdrv_amend_pre_run(s->bs, errp); | 33 | +} |
34 | + | ||
35 | +static void coroutine_fn test_job_start(void *opaque) | ||
36 | +{ | ||
37 | + TestBlockJob *s = opaque; | ||
38 | + | ||
39 | + while (!s->should_complete) { | ||
40 | + block_job_sleep_ns(&s->common, 100000); | ||
82 | + } | 41 | + } |
83 | + | 42 | + |
84 | + return 0; | 43 | + block_job_defer_to_main_loop(&s->common, test_job_completed, NULL); |
85 | +} | 44 | +} |
86 | + | 45 | + |
87 | +static void blockdev_amend_clean(Job *job) | 46 | +static void test_job_complete(BlockJob *job, Error **errp) |
88 | +{ | 47 | +{ |
89 | + BlockdevAmendJob *s = container_of(job, BlockdevAmendJob, common); | 48 | + TestBlockJob *s = container_of(job, TestBlockJob, common); |
90 | + | 49 | + s->should_complete = true; |
91 | + if (s->bs->drv->bdrv_amend_clean) { | ||
92 | + s->bs->drv->bdrv_amend_clean(s->bs); | ||
93 | + } | ||
94 | +} | 50 | +} |
95 | + | 51 | + |
96 | static const JobDriver blockdev_amend_job_driver = { | 52 | +BlockJobDriver test_job_driver = { |
97 | .instance_size = sizeof(BlockdevAmendJob), | 53 | + .instance_size = sizeof(TestBlockJob), |
98 | .job_type = JOB_TYPE_AMEND, | 54 | + .start = test_job_start, |
99 | .run = blockdev_amend_run, | 55 | + .complete = test_job_complete, |
100 | + .clean = blockdev_amend_clean, | 56 | +}; |
101 | }; | ||
102 | |||
103 | void qmp_x_blockdev_amend(const char *job_id, | ||
104 | @@ -XXX,XX +XXX,XX @@ void qmp_x_blockdev_amend(const char *job_id, | ||
105 | s->bs = bs, | ||
106 | s->opts = QAPI_CLONE(BlockdevAmendOptions, options), | ||
107 | s->force = has_force ? force : false; | ||
108 | + | 57 | + |
109 | + if (blockdev_amend_pre_run(s, errp)) { | 58 | +static void test_blockjob_common(enum drain_type drain_type) |
110 | + job_early_fail(&s->common); | ||
111 | + return; | ||
112 | + } | ||
113 | + | ||
114 | job_start(&s->common); | ||
115 | } | ||
116 | diff --git a/block/crypto.c b/block/crypto.c | ||
117 | index XXXXXXX..XXXXXXX 100644 | ||
118 | --- a/block/crypto.c | ||
119 | +++ b/block/crypto.c | ||
120 | @@ -XXX,XX +XXX,XX @@ block_crypto_get_specific_info_luks(BlockDriverState *bs, Error **errp) | ||
121 | return spec_info; | ||
122 | } | ||
123 | |||
124 | +static int | ||
125 | +block_crypto_amend_prepare(BlockDriverState *bs, Error **errp) | ||
126 | +{ | 59 | +{ |
127 | + BlockCrypto *crypto = bs->opaque; | 60 | + BlockBackend *blk_src, *blk_target; |
61 | + BlockDriverState *src, *target; | ||
62 | + BlockJob *job; | ||
128 | + int ret; | 63 | + int ret; |
129 | + | 64 | + |
130 | + /* apply for exclusive read/write permissions to the underlying file */ | 65 | + src = bdrv_new_open_driver(&bdrv_test, "source", BDRV_O_RDWR, |
131 | + crypto->updating_keys = true; | 66 | + &error_abort); |
132 | + ret = bdrv_child_refresh_perms(bs, bs->file, errp); | 67 | + blk_src = blk_new(BLK_PERM_ALL, BLK_PERM_ALL); |
133 | + if (ret < 0) { | 68 | + blk_insert_bs(blk_src, src, &error_abort); |
134 | + /* Well, in this case we will not be updating any keys */ | 69 | + |
135 | + crypto->updating_keys = false; | 70 | + target = bdrv_new_open_driver(&bdrv_test, "target", BDRV_O_RDWR, |
71 | + &error_abort); | ||
72 | + blk_target = blk_new(BLK_PERM_ALL, BLK_PERM_ALL); | ||
73 | + blk_insert_bs(blk_target, target, &error_abort); | ||
74 | + | ||
75 | + job = block_job_create("job0", &test_job_driver, src, 0, BLK_PERM_ALL, 0, | ||
76 | + 0, NULL, NULL, &error_abort); | ||
77 | + block_job_add_bdrv(job, "target", target, 0, BLK_PERM_ALL, &error_abort); | ||
78 | + block_job_start(job); | ||
79 | + | ||
80 | + g_assert_cmpint(job->pause_count, ==, 0); | ||
81 | + g_assert_false(job->paused); | ||
82 | + g_assert_false(job->busy); /* We're in block_job_sleep_ns() */ | ||
83 | + | ||
84 | + do_drain_begin(drain_type, src); | ||
85 | + | ||
86 | + if (drain_type == BDRV_DRAIN_ALL) { | ||
87 | + /* bdrv_drain_all() drains both src and target, and involves an | ||
88 | + * additional block_job_pause_all() */ | ||
89 | + g_assert_cmpint(job->pause_count, ==, 3); | ||
90 | + } else { | ||
91 | + g_assert_cmpint(job->pause_count, ==, 1); | ||
136 | + } | 92 | + } |
137 | + return ret; | 93 | + /* XXX We don't wait until the job is actually paused. Is this okay? */ |
94 | + /* g_assert_true(job->paused); */ | ||
95 | + g_assert_false(job->busy); /* The job is paused */ | ||
96 | + | ||
97 | + do_drain_end(drain_type, src); | ||
98 | + | ||
99 | + g_assert_cmpint(job->pause_count, ==, 0); | ||
100 | + g_assert_false(job->paused); | ||
101 | + g_assert_false(job->busy); /* We're in block_job_sleep_ns() */ | ||
102 | + | ||
103 | + do_drain_begin(drain_type, target); | ||
104 | + | ||
105 | + if (drain_type == BDRV_DRAIN_ALL) { | ||
106 | + /* bdrv_drain_all() drains both src and target, and involves an | ||
107 | + * additional block_job_pause_all() */ | ||
108 | + g_assert_cmpint(job->pause_count, ==, 3); | ||
109 | + } else { | ||
110 | + g_assert_cmpint(job->pause_count, ==, 1); | ||
111 | + } | ||
112 | + /* XXX We don't wait until the job is actually paused. Is this okay? */ | ||
113 | + /* g_assert_true(job->paused); */ | ||
114 | + g_assert_false(job->busy); /* The job is paused */ | ||
115 | + | ||
116 | + do_drain_end(drain_type, target); | ||
117 | + | ||
118 | + g_assert_cmpint(job->pause_count, ==, 0); | ||
119 | + g_assert_false(job->paused); | ||
120 | + g_assert_false(job->busy); /* We're in block_job_sleep_ns() */ | ||
121 | + | ||
122 | + ret = block_job_complete_sync(job, &error_abort); | ||
123 | + g_assert_cmpint(ret, ==, 0); | ||
124 | + | ||
125 | + blk_unref(blk_src); | ||
126 | + blk_unref(blk_target); | ||
127 | + bdrv_unref(src); | ||
128 | + bdrv_unref(target); | ||
138 | +} | 129 | +} |
139 | + | 130 | + |
140 | +static void | 131 | +static void test_blockjob_drain_all(void) |
141 | +block_crypto_amend_cleanup(BlockDriverState *bs) | ||
142 | +{ | 132 | +{ |
143 | + BlockCrypto *crypto = bs->opaque; | 133 | + test_blockjob_common(BDRV_DRAIN_ALL); |
144 | + Error *errp = NULL; | ||
145 | + | ||
146 | + /* release exclusive read/write permissions to the underlying file */ | ||
147 | + crypto->updating_keys = false; | ||
148 | + bdrv_child_refresh_perms(bs, bs->file, &errp); | ||
149 | + | ||
150 | + if (errp) { | ||
151 | + error_report_err(errp); | ||
152 | + } | ||
153 | +} | 134 | +} |
154 | + | 135 | + |
155 | static int | 136 | +static void test_blockjob_drain(void) |
156 | block_crypto_amend_options_generic_luks(BlockDriverState *bs, | 137 | +{ |
157 | QCryptoBlockAmendOptions *amend_options, | 138 | + test_blockjob_common(BDRV_DRAIN); |
158 | @@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_crypto_luks = { | 139 | +} |
159 | .bdrv_get_specific_info = block_crypto_get_specific_info_luks, | 140 | + |
160 | .bdrv_amend_options = block_crypto_amend_options_luks, | 141 | int main(int argc, char **argv) |
161 | .bdrv_co_amend = block_crypto_co_amend_luks, | 142 | { |
162 | + .bdrv_amend_pre_run = block_crypto_amend_prepare, | 143 | bdrv_init(); |
163 | + .bdrv_amend_clean = block_crypto_amend_cleanup, | 144 | @@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv) |
164 | 145 | g_test_add_func("/bdrv-drain/quiesce/drain_all", test_quiesce_drain_all); | |
165 | .is_format = true, | 146 | g_test_add_func("/bdrv-drain/quiesce/drain", test_quiesce_drain); |
166 | 147 | ||
167 | diff --git a/tests/qemu-iotests/296 b/tests/qemu-iotests/296 | 148 | + g_test_add_func("/bdrv-drain/blockjob/drain_all", test_blockjob_drain_all); |
168 | index XXXXXXX..XXXXXXX 100755 | 149 | + g_test_add_func("/bdrv-drain/blockjob/drain", test_blockjob_drain); |
169 | --- a/tests/qemu-iotests/296 | 150 | + |
170 | +++ b/tests/qemu-iotests/296 | 151 | return g_test_run(); |
171 | @@ -XXX,XX +XXX,XX @@ class EncryptionSetupTestCase(iotests.QMPTestCase): | 152 | } |
172 | } | ||
173 | |||
174 | result = vm.qmp('x-blockdev-amend', **args) | ||
175 | - assert result['return'] == {} | ||
176 | - vm.run_job('job0') | ||
177 | + iotests.log(result) | ||
178 | + # Run the job only if it was created | ||
179 | + event = ('JOB_STATUS_CHANGE', | ||
180 | + {'data': {'id': 'job0', 'status': 'created'}}) | ||
181 | + if vm.events_wait([event], timeout=0.0) is not None: | ||
182 | + vm.run_job('job0') | ||
183 | |||
184 | # test that when the image opened by two qemu processes, | ||
185 | # neither of them can update the encryption keys | ||
186 | diff --git a/tests/qemu-iotests/296.out b/tests/qemu-iotests/296.out | ||
187 | index XXXXXXX..XXXXXXX 100644 | ||
188 | --- a/tests/qemu-iotests/296.out | ||
189 | +++ b/tests/qemu-iotests/296.out | ||
190 | @@ -XXX,XX +XXX,XX @@ | ||
191 | |||
192 | -{"execute": "job-dismiss", "arguments": {"id": "job0"}} | ||
193 | {"return": {}} | ||
194 | -Job failed: Failed to get shared "consistent read" lock | ||
195 | {"execute": "job-dismiss", "arguments": {"id": "job0"}} | ||
196 | {"return": {}} | ||
197 | -Job failed: Failed to get shared "consistent read" lock | ||
198 | -{"execute": "job-dismiss", "arguments": {"id": "job0"}} | ||
199 | +{"error": {"class": "GenericError", "desc": "Failed to get shared \"consistent read\" lock"}} | ||
200 | +{"error": {"class": "GenericError", "desc": "Failed to get shared \"consistent read\" lock"}} | ||
201 | {"return": {}} | ||
202 | {"execute": "job-dismiss", "arguments": {"id": "job0"}} | ||
203 | {"return": {}} | ||
204 | @@ -XXX,XX +XXX,XX @@ qemu-img: Failed to get shared "consistent read" lock | ||
205 | Is another process using the image [TEST_DIR/test.img]? | ||
206 | |||
207 | . | ||
208 | -Job failed: Block node is read-only | ||
209 | -{"execute": "job-dismiss", "arguments": {"id": "job0"}} | ||
210 | -{"return": {}} | ||
211 | -Job failed: Failed to get shared "consistent read" lock | ||
212 | -{"execute": "job-dismiss", "arguments": {"id": "job0"}} | ||
213 | -{"return": {}} | ||
214 | -Job failed: Failed to get shared "consistent read" lock | ||
215 | -{"execute": "job-dismiss", "arguments": {"id": "job0"}} | ||
216 | +{"error": {"class": "GenericError", "desc": "Block node is read-only"}} | ||
217 | +{"error": {"class": "GenericError", "desc": "Failed to get shared \"consistent read\" lock"}} | ||
218 | +{"error": {"class": "GenericError", "desc": "Failed to get shared \"consistent read\" lock"}} | ||
219 | {"return": {}} | ||
220 | {"execute": "job-dismiss", "arguments": {"id": "job0"}} | ||
221 | {"return": {}} | ||
222 | -- | 153 | -- |
223 | 2.35.1 | 154 | 2.13.6 |
155 | |||
156 | diff view generated by jsdifflib |
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | 1 | Block jobs are already paused using the BdrvChildRole drain callbacks, |
---|---|---|---|
2 | so we don't need an additional block_job_pause_all() call. | ||
2 | 3 | ||
3 | All the global state (GS) API functions will check that | ||
4 | qemu_in_main_thread() returns true. If not, it means | ||
5 | that the safety of BQL cannot be guaranteed, and | ||
6 | they need to be moved to I/O. | ||
7 | |||
8 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
9 | Message-Id: <20220303151616.325444-5-eesposit@redhat.com> | ||
10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 4 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
11 | --- | 5 | --- |
12 | block.c | 125 ++++++++++++++++++++++++++++++++++++++++++++++++- | 6 | block/io.c | 4 ---- |
13 | block/commit.c | 2 + | 7 | tests/test-bdrv-drain.c | 10 ++++------ |
14 | block/io.c | 11 +++++ | 8 | 2 files changed, 4 insertions(+), 10 deletions(-) |
15 | blockdev.c | 1 + | ||
16 | 4 files changed, 137 insertions(+), 2 deletions(-) | ||
17 | 9 | ||
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 @@ static char *bdrv_make_absolute_filename(BlockDriverState *relative_to, | ||
23 | |||
24 | char *bdrv_get_full_backing_filename(BlockDriverState *bs, Error **errp) | ||
25 | { | ||
26 | + GLOBAL_STATE_CODE(); | ||
27 | return bdrv_make_absolute_filename(bs, bs->backing_file, errp); | ||
28 | } | ||
29 | |||
30 | void bdrv_register(BlockDriver *bdrv) | ||
31 | { | ||
32 | assert(bdrv->format_name); | ||
33 | + GLOBAL_STATE_CODE(); | ||
34 | QLIST_INSERT_HEAD(&bdrv_drivers, bdrv, list); | ||
35 | } | ||
36 | |||
37 | @@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_new(void) | ||
38 | BlockDriverState *bs; | ||
39 | int i; | ||
40 | |||
41 | + GLOBAL_STATE_CODE(); | ||
42 | + | ||
43 | bs = g_new0(BlockDriverState, 1); | ||
44 | QLIST_INIT(&bs->dirty_bitmaps); | ||
45 | for (i = 0; i < BLOCK_OP_TYPE_MAX; i++) { | ||
46 | @@ -XXX,XX +XXX,XX @@ BlockDriver *bdrv_find_format(const char *format_name) | ||
47 | BlockDriver *drv1; | ||
48 | int i; | ||
49 | |||
50 | + GLOBAL_STATE_CODE(); | ||
51 | + | ||
52 | drv1 = bdrv_do_find_format(format_name); | ||
53 | if (drv1) { | ||
54 | return drv1; | ||
55 | @@ -XXX,XX +XXX,XX @@ static int bdrv_format_is_whitelisted(const char *format_name, bool read_only) | ||
56 | |||
57 | int bdrv_is_whitelisted(BlockDriver *drv, bool read_only) | ||
58 | { | ||
59 | + GLOBAL_STATE_CODE(); | ||
60 | return bdrv_format_is_whitelisted(drv->format_name, read_only); | ||
61 | } | ||
62 | |||
63 | @@ -XXX,XX +XXX,XX @@ int bdrv_create(BlockDriver *drv, const char* filename, | ||
64 | { | ||
65 | int ret; | ||
66 | |||
67 | + GLOBAL_STATE_CODE(); | ||
68 | + | ||
69 | Coroutine *co; | ||
70 | CreateCo cco = { | ||
71 | .drv = drv, | ||
72 | @@ -XXX,XX +XXX,XX @@ int bdrv_create_file(const char *filename, QemuOpts *opts, Error **errp) | ||
73 | QDict *qdict; | ||
74 | int ret; | ||
75 | |||
76 | + GLOBAL_STATE_CODE(); | ||
77 | + | ||
78 | drv = bdrv_find_protocol(filename, true, errp); | ||
79 | if (drv == NULL) { | ||
80 | return -ENOENT; | ||
81 | @@ -XXX,XX +XXX,XX @@ int bdrv_probe_blocksizes(BlockDriverState *bs, BlockSizes *bsz) | ||
82 | { | ||
83 | BlockDriver *drv = bs->drv; | ||
84 | BlockDriverState *filtered = bdrv_filter_bs(bs); | ||
85 | + GLOBAL_STATE_CODE(); | ||
86 | |||
87 | if (drv && drv->bdrv_probe_blocksizes) { | ||
88 | return drv->bdrv_probe_blocksizes(bs, bsz); | ||
89 | @@ -XXX,XX +XXX,XX @@ int bdrv_probe_geometry(BlockDriverState *bs, HDGeometry *geo) | ||
90 | { | ||
91 | BlockDriver *drv = bs->drv; | ||
92 | BlockDriverState *filtered = bdrv_filter_bs(bs); | ||
93 | + GLOBAL_STATE_CODE(); | ||
94 | |||
95 | if (drv && drv->bdrv_probe_geometry) { | ||
96 | return drv->bdrv_probe_geometry(bs, geo); | ||
97 | @@ -XXX,XX +XXX,XX @@ BlockDriver *bdrv_find_protocol(const char *filename, | ||
98 | const char *p; | ||
99 | int i; | ||
100 | |||
101 | + GLOBAL_STATE_CODE(); | ||
102 | /* TODO Drivers without bdrv_file_open must be specified explicitly */ | ||
103 | |||
104 | /* | ||
105 | @@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_new_open_driver_opts(BlockDriver *drv, | ||
106 | BlockDriverState *bs; | ||
107 | int ret; | ||
108 | |||
109 | + GLOBAL_STATE_CODE(); | ||
110 | + | ||
111 | bs = bdrv_new(); | ||
112 | bs->open_flags = flags; | ||
113 | bs->options = options ?: qdict_new(); | ||
114 | @@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_new_open_driver_opts(BlockDriver *drv, | ||
115 | BlockDriverState *bdrv_new_open_driver(BlockDriver *drv, const char *node_name, | ||
116 | int flags, Error **errp) | ||
117 | { | ||
118 | + GLOBAL_STATE_CODE(); | ||
119 | return bdrv_new_open_driver_opts(drv, node_name, NULL, flags, errp); | ||
120 | } | ||
121 | |||
122 | @@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs, | ||
123 | BdrvChild *child = NULL; | ||
124 | Transaction *tran = tran_new(); | ||
125 | |||
126 | + GLOBAL_STATE_CODE(); | ||
127 | + | ||
128 | ret = bdrv_attach_child_noperm(parent_bs, child_bs, child_name, child_class, | ||
129 | child_role, &child, tran, errp); | ||
130 | if (ret < 0) { | ||
131 | @@ -XXX,XX +XXX,XX @@ void bdrv_root_unref_child(BdrvChild *child) | ||
132 | { | ||
133 | BlockDriverState *child_bs; | ||
134 | |||
135 | + GLOBAL_STATE_CODE(); | ||
136 | + | ||
137 | child_bs = child->bs; | ||
138 | bdrv_detach_child(&child); | ||
139 | bdrv_unref(child_bs); | ||
140 | @@ -XXX,XX +XXX,XX @@ static void bdrv_unset_inherits_from(BlockDriverState *root, BdrvChild *child, | ||
141 | /* Callers must ensure that child->frozen is false. */ | ||
142 | void bdrv_unref_child(BlockDriverState *parent, BdrvChild *child) | ||
143 | { | ||
144 | + GLOBAL_STATE_CODE(); | ||
145 | if (child == NULL) { | ||
146 | return; | ||
147 | } | ||
148 | @@ -XXX,XX +XXX,XX @@ int bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd, | ||
149 | int ret; | ||
150 | Transaction *tran = tran_new(); | ||
151 | |||
152 | + GLOBAL_STATE_CODE(); | ||
153 | bdrv_drained_begin(bs); | ||
154 | |||
155 | ret = bdrv_set_backing_noperm(bs, backing_hd, tran, errp); | ||
156 | @@ -XXX,XX +XXX,XX @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options, | ||
157 | QDict *tmp_parent_options = NULL; | ||
158 | Error *local_err = NULL; | ||
159 | |||
160 | + GLOBAL_STATE_CODE(); | ||
161 | + | ||
162 | if (bs->backing != NULL) { | ||
163 | goto free_exit; | ||
164 | } | ||
165 | @@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_open_child(const char *filename, | ||
166 | { | ||
167 | BlockDriverState *bs; | ||
168 | |||
169 | + GLOBAL_STATE_CODE(); | ||
170 | + | ||
171 | bs = bdrv_open_child_bs(filename, options, bdref_key, parent, child_class, | ||
172 | child_role, allow_none, errp); | ||
173 | if (bs == NULL) { | ||
174 | @@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_open_blockdev_ref(BlockdevRef *ref, Error **errp) | ||
175 | const char *reference = NULL; | ||
176 | Visitor *v = NULL; | ||
177 | |||
178 | + GLOBAL_STATE_CODE(); | ||
179 | + | ||
180 | if (ref->type == QTYPE_QSTRING) { | ||
181 | reference = ref->u.reference; | ||
182 | } else { | ||
183 | @@ -XXX,XX +XXX,XX @@ close_and_fail: | ||
184 | BlockDriverState *bdrv_open(const char *filename, const char *reference, | ||
185 | QDict *options, int flags, Error **errp) | ||
186 | { | ||
187 | + GLOBAL_STATE_CODE(); | ||
188 | + | ||
189 | return bdrv_open_inherit(filename, reference, options, flags, NULL, | ||
190 | NULL, 0, errp); | ||
191 | } | ||
192 | @@ -XXX,XX +XXX,XX @@ BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue, | ||
193 | BlockDriverState *bs, | ||
194 | QDict *options, bool keep_old_opts) | ||
195 | { | ||
196 | + GLOBAL_STATE_CODE(); | ||
197 | + | ||
198 | return bdrv_reopen_queue_child(bs_queue, bs, options, NULL, 0, false, | ||
199 | NULL, 0, keep_old_opts); | ||
200 | } | ||
201 | |||
202 | void bdrv_reopen_queue_free(BlockReopenQueue *bs_queue) | ||
203 | { | ||
204 | + GLOBAL_STATE_CODE(); | ||
205 | if (bs_queue) { | ||
206 | BlockReopenQueueEntry *bs_entry, *next; | ||
207 | QTAILQ_FOREACH_SAFE(bs_entry, bs_queue, entry, next) { | ||
208 | @@ -XXX,XX +XXX,XX @@ int bdrv_reopen(BlockDriverState *bs, QDict *opts, bool keep_old_opts, | ||
209 | BlockReopenQueue *queue; | ||
210 | int ret; | ||
211 | |||
212 | + GLOBAL_STATE_CODE(); | ||
213 | + | ||
214 | bdrv_subtree_drained_begin(bs); | ||
215 | if (ctx != qemu_get_aio_context()) { | ||
216 | aio_context_release(ctx); | ||
217 | @@ -XXX,XX +XXX,XX @@ int bdrv_reopen_set_read_only(BlockDriverState *bs, bool read_only, | ||
218 | { | ||
219 | QDict *opts = qdict_new(); | ||
220 | |||
221 | + GLOBAL_STATE_CODE(); | ||
222 | + | ||
223 | qdict_put_bool(opts, BDRV_OPT_READ_ONLY, read_only); | ||
224 | |||
225 | return bdrv_reopen(bs, opts, true, errp); | ||
226 | @@ -XXX,XX +XXX,XX @@ static void bdrv_close(BlockDriverState *bs) | ||
227 | BdrvAioNotifier *ban, *ban_next; | ||
228 | BdrvChild *child, *next; | ||
229 | |||
230 | + GLOBAL_STATE_CODE(); | ||
231 | assert(!bs->refcnt); | ||
232 | |||
233 | bdrv_drained_begin(bs); /* complete I/O */ | ||
234 | @@ -XXX,XX +XXX,XX @@ static void bdrv_close(BlockDriverState *bs) | ||
235 | void bdrv_close_all(void) | ||
236 | { | ||
237 | assert(job_next(NULL) == NULL); | ||
238 | + GLOBAL_STATE_CODE(); | ||
239 | |||
240 | /* Drop references from requests still in flight, such as canceled block | ||
241 | * jobs whose AIO context has not been polled yet */ | ||
242 | @@ -XXX,XX +XXX,XX @@ out: | ||
243 | int bdrv_replace_node(BlockDriverState *from, BlockDriverState *to, | ||
244 | Error **errp) | ||
245 | { | ||
246 | + GLOBAL_STATE_CODE(); | ||
247 | + | ||
248 | return bdrv_replace_node_common(from, to, true, false, errp); | ||
249 | } | ||
250 | |||
251 | int bdrv_drop_filter(BlockDriverState *bs, Error **errp) | ||
252 | { | ||
253 | + GLOBAL_STATE_CODE(); | ||
254 | + | ||
255 | return bdrv_replace_node_common(bs, bdrv_filter_or_cow_bs(bs), true, true, | ||
256 | errp); | ||
257 | } | ||
258 | @@ -XXX,XX +XXX,XX @@ int bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top, | ||
259 | int ret; | ||
260 | Transaction *tran = tran_new(); | ||
261 | |||
262 | + GLOBAL_STATE_CODE(); | ||
263 | + | ||
264 | assert(!bs_new->backing); | ||
265 | |||
266 | ret = bdrv_attach_child_noperm(bs_new, bs_top, "backing", | ||
267 | @@ -XXX,XX +XXX,XX @@ int bdrv_replace_child_bs(BdrvChild *child, BlockDriverState *new_bs, | ||
268 | g_autoptr(GSList) refresh_list = NULL; | ||
269 | BlockDriverState *old_bs = child->bs; | ||
270 | |||
271 | + GLOBAL_STATE_CODE(); | ||
272 | + | ||
273 | bdrv_ref(old_bs); | ||
274 | bdrv_drained_begin(old_bs); | ||
275 | bdrv_drained_begin(new_bs); | ||
276 | @@ -XXX,XX +XXX,XX @@ static void bdrv_delete(BlockDriverState *bs) | ||
277 | { | ||
278 | assert(bdrv_op_blocker_is_empty(bs)); | ||
279 | assert(!bs->refcnt); | ||
280 | + GLOBAL_STATE_CODE(); | ||
281 | |||
282 | /* remove from list, if necessary */ | ||
283 | if (bs->node_name[0] != '\0') { | ||
284 | @@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_insert_node(BlockDriverState *bs, QDict *options, | ||
285 | |||
286 | node_name = qdict_get_try_str(options, "node-name"); | ||
287 | |||
288 | + GLOBAL_STATE_CODE(); | ||
289 | + | ||
290 | new_node_bs = bdrv_new_open_driver_opts(drv, node_name, options, flags, | ||
291 | errp); | ||
292 | options = NULL; /* bdrv_new_open_driver() eats options */ | ||
293 | @@ -XXX,XX +XXX,XX @@ int bdrv_change_backing_file(BlockDriverState *bs, const char *backing_file, | ||
294 | BlockDriver *drv = bs->drv; | ||
295 | int ret; | ||
296 | |||
297 | + GLOBAL_STATE_CODE(); | ||
298 | + | ||
299 | if (!drv) { | ||
300 | return -ENOMEDIUM; | ||
301 | } | ||
302 | @@ -XXX,XX +XXX,XX @@ int bdrv_change_backing_file(BlockDriverState *bs, const char *backing_file, | ||
303 | BlockDriverState *bdrv_find_overlay(BlockDriverState *active, | ||
304 | BlockDriverState *bs) | ||
305 | { | ||
306 | + | ||
307 | + GLOBAL_STATE_CODE(); | ||
308 | + | ||
309 | bs = bdrv_skip_filters(bs); | ||
310 | active = bdrv_skip_filters(active); | ||
311 | |||
312 | @@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_find_overlay(BlockDriverState *active, | ||
313 | /* Given a BDS, searches for the base layer. */ | ||
314 | BlockDriverState *bdrv_find_base(BlockDriverState *bs) | ||
315 | { | ||
316 | + GLOBAL_STATE_CODE(); | ||
317 | + | ||
318 | return bdrv_find_overlay(bs, NULL); | ||
319 | } | ||
320 | |||
321 | @@ -XXX,XX +XXX,XX @@ bool bdrv_is_backing_chain_frozen(BlockDriverState *bs, BlockDriverState *base, | ||
322 | BlockDriverState *i; | ||
323 | BdrvChild *child; | ||
324 | |||
325 | + GLOBAL_STATE_CODE(); | ||
326 | + | ||
327 | for (i = bs; i != base; i = child_bs(child)) { | ||
328 | child = bdrv_filter_or_cow_child(i); | ||
329 | |||
330 | @@ -XXX,XX +XXX,XX @@ int bdrv_freeze_backing_chain(BlockDriverState *bs, BlockDriverState *base, | ||
331 | BlockDriverState *i; | ||
332 | BdrvChild *child; | ||
333 | |||
334 | + GLOBAL_STATE_CODE(); | ||
335 | + | ||
336 | if (bdrv_is_backing_chain_frozen(bs, base, errp)) { | ||
337 | return -EPERM; | ||
338 | } | ||
339 | @@ -XXX,XX +XXX,XX @@ void bdrv_unfreeze_backing_chain(BlockDriverState *bs, BlockDriverState *base) | ||
340 | BlockDriverState *i; | ||
341 | BdrvChild *child; | ||
342 | |||
343 | + GLOBAL_STATE_CODE(); | ||
344 | + | ||
345 | for (i = bs; i != base; i = child_bs(child)) { | ||
346 | child = bdrv_filter_or_cow_child(i); | ||
347 | if (child) { | ||
348 | @@ -XXX,XX +XXX,XX @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base, | ||
349 | g_autoptr(GSList) updated_children = NULL; | ||
350 | GSList *p; | ||
351 | |||
352 | + GLOBAL_STATE_CODE(); | ||
353 | + | ||
354 | bdrv_ref(top); | ||
355 | bdrv_subtree_drained_begin(top); | ||
356 | |||
357 | @@ -XXX,XX +XXX,XX @@ void bdrv_iterate_format(void (*it)(void *opaque, const char *name), | ||
358 | int i; | ||
359 | const char **formats = NULL; | ||
360 | |||
361 | + GLOBAL_STATE_CODE(); | ||
362 | + | ||
363 | QLIST_FOREACH(drv, &bdrv_drivers, list) { | ||
364 | if (drv->format_name) { | ||
365 | bool found = false; | ||
366 | @@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_find_node(const char *node_name) | ||
367 | BlockDriverState *bs; | ||
368 | |||
369 | assert(node_name); | ||
370 | + GLOBAL_STATE_CODE(); | ||
371 | |||
372 | QTAILQ_FOREACH(bs, &graph_bdrv_states, node_list) { | ||
373 | if (!strcmp(node_name, bs->node_name)) { | ||
374 | @@ -XXX,XX +XXX,XX @@ BlockDeviceInfoList *bdrv_named_nodes_list(bool flat, | ||
375 | BlockDeviceInfoList *list; | ||
376 | BlockDriverState *bs; | ||
377 | |||
378 | + GLOBAL_STATE_CODE(); | ||
379 | + | ||
380 | list = NULL; | ||
381 | QTAILQ_FOREACH(bs, &graph_bdrv_states, node_list) { | ||
382 | BlockDeviceInfo *info = bdrv_block_device_info(NULL, bs, flat, errp); | ||
383 | @@ -XXX,XX +XXX,XX @@ XDbgBlockGraph *bdrv_get_xdbg_block_graph(Error **errp) | ||
384 | BdrvChild *child; | ||
385 | XDbgBlockGraphConstructor *gr = xdbg_graph_new(); | ||
386 | |||
387 | + GLOBAL_STATE_CODE(); | ||
388 | + | ||
389 | for (blk = blk_all_next(NULL); blk; blk = blk_all_next(blk)) { | ||
390 | char *allocated_name = NULL; | ||
391 | const char *name = blk_name(blk); | ||
392 | @@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_lookup_bs(const char *device, | ||
393 | BlockBackend *blk; | ||
394 | BlockDriverState *bs; | ||
395 | |||
396 | + GLOBAL_STATE_CODE(); | ||
397 | + | ||
398 | if (device) { | ||
399 | blk = blk_by_name(device); | ||
400 | |||
401 | @@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_lookup_bs(const char *device, | ||
402 | * return false. If either argument is NULL, return false. */ | ||
403 | bool bdrv_chain_contains(BlockDriverState *top, BlockDriverState *base) | ||
404 | { | ||
405 | + | ||
406 | + GLOBAL_STATE_CODE(); | ||
407 | + | ||
408 | while (top && top != base) { | ||
409 | top = bdrv_filter_or_cow_bs(top); | ||
410 | } | ||
411 | @@ -XXX,XX +XXX,XX @@ bool bdrv_chain_contains(BlockDriverState *top, BlockDriverState *base) | ||
412 | |||
413 | BlockDriverState *bdrv_next_node(BlockDriverState *bs) | ||
414 | { | ||
415 | + GLOBAL_STATE_CODE(); | ||
416 | if (!bs) { | ||
417 | return QTAILQ_FIRST(&graph_bdrv_states); | ||
418 | } | ||
419 | @@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_next_node(BlockDriverState *bs) | ||
420 | |||
421 | BlockDriverState *bdrv_next_all_states(BlockDriverState *bs) | ||
422 | { | ||
423 | + GLOBAL_STATE_CODE(); | ||
424 | if (!bs) { | ||
425 | return QTAILQ_FIRST(&all_bdrv_states); | ||
426 | } | ||
427 | @@ -XXX,XX +XXX,XX @@ const char *bdrv_get_device_or_node_name(const BlockDriverState *bs) | ||
428 | |||
429 | int bdrv_get_flags(BlockDriverState *bs) | ||
430 | { | ||
431 | + GLOBAL_STATE_CODE(); | ||
432 | return bs->open_flags; | ||
433 | } | ||
434 | |||
435 | int bdrv_has_zero_init_1(BlockDriverState *bs) | ||
436 | { | ||
437 | + GLOBAL_STATE_CODE(); | ||
438 | return 1; | ||
439 | } | ||
440 | |||
441 | int bdrv_has_zero_init(BlockDriverState *bs) | ||
442 | { | ||
443 | BlockDriverState *filtered; | ||
444 | + GLOBAL_STATE_CODE(); | ||
445 | |||
446 | if (!bs->drv) { | ||
447 | return 0; | ||
448 | @@ -XXX,XX +XXX,XX @@ static BlockDriverState *bdrv_find_debug_node(BlockDriverState *bs) | ||
449 | int bdrv_debug_breakpoint(BlockDriverState *bs, const char *event, | ||
450 | const char *tag) | ||
451 | { | ||
452 | + GLOBAL_STATE_CODE(); | ||
453 | bs = bdrv_find_debug_node(bs); | ||
454 | if (bs) { | ||
455 | return bs->drv->bdrv_debug_breakpoint(bs, event, tag); | ||
456 | @@ -XXX,XX +XXX,XX @@ int bdrv_debug_breakpoint(BlockDriverState *bs, const char *event, | ||
457 | |||
458 | int bdrv_debug_remove_breakpoint(BlockDriverState *bs, const char *tag) | ||
459 | { | ||
460 | + GLOBAL_STATE_CODE(); | ||
461 | bs = bdrv_find_debug_node(bs); | ||
462 | if (bs) { | ||
463 | return bs->drv->bdrv_debug_remove_breakpoint(bs, tag); | ||
464 | @@ -XXX,XX +XXX,XX @@ int bdrv_debug_remove_breakpoint(BlockDriverState *bs, const char *tag) | ||
465 | |||
466 | int bdrv_debug_resume(BlockDriverState *bs, const char *tag) | ||
467 | { | ||
468 | + GLOBAL_STATE_CODE(); | ||
469 | while (bs && (!bs->drv || !bs->drv->bdrv_debug_resume)) { | ||
470 | bs = bdrv_primary_bs(bs); | ||
471 | } | ||
472 | @@ -XXX,XX +XXX,XX @@ int bdrv_debug_resume(BlockDriverState *bs, const char *tag) | ||
473 | |||
474 | bool bdrv_debug_is_suspended(BlockDriverState *bs, const char *tag) | ||
475 | { | ||
476 | + GLOBAL_STATE_CODE(); | ||
477 | while (bs && bs->drv && !bs->drv->bdrv_debug_is_suspended) { | ||
478 | bs = bdrv_primary_bs(bs); | ||
479 | } | ||
480 | @@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs, | ||
481 | BlockDriverState *retval = NULL; | ||
482 | BlockDriverState *bs_below; | ||
483 | |||
484 | + GLOBAL_STATE_CODE(); | ||
485 | + | ||
486 | if (!bs || !bs->drv || !backing_file) { | ||
487 | return NULL; | ||
488 | } | ||
489 | @@ -XXX,XX +XXX,XX @@ int bdrv_activate(BlockDriverState *bs, Error **errp) | ||
490 | int ret; | ||
491 | BdrvDirtyBitmap *bm; | ||
492 | |||
493 | + GLOBAL_STATE_CODE(); | ||
494 | + | ||
495 | if (!bs->drv) { | ||
496 | return -ENOMEDIUM; | ||
497 | } | ||
498 | @@ -XXX,XX +XXX,XX @@ void bdrv_activate_all(Error **errp) | ||
499 | BlockDriverState *bs; | ||
500 | BdrvNextIterator it; | ||
501 | |||
502 | + GLOBAL_STATE_CODE(); | ||
503 | + | ||
504 | for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { | ||
505 | AioContext *aio_context = bdrv_get_aio_context(bs); | ||
506 | int ret; | ||
507 | @@ -XXX,XX +XXX,XX @@ int bdrv_inactivate_all(void) | ||
508 | int ret = 0; | ||
509 | GSList *aio_ctxs = NULL, *ctx; | ||
510 | |||
511 | + GLOBAL_STATE_CODE(); | ||
512 | + | ||
513 | for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { | ||
514 | AioContext *aio_context = bdrv_get_aio_context(bs); | ||
515 | |||
516 | @@ -XXX,XX +XXX,XX @@ void bdrv_lock_medium(BlockDriverState *bs, bool locked) | ||
517 | /* Get a reference to bs */ | ||
518 | void bdrv_ref(BlockDriverState *bs) | ||
519 | { | ||
520 | + GLOBAL_STATE_CODE(); | ||
521 | bs->refcnt++; | ||
522 | } | ||
523 | |||
524 | @@ -XXX,XX +XXX,XX @@ void bdrv_ref(BlockDriverState *bs) | ||
525 | * deleted. */ | ||
526 | void bdrv_unref(BlockDriverState *bs) | ||
527 | { | ||
528 | + GLOBAL_STATE_CODE(); | ||
529 | if (!bs) { | ||
530 | return; | ||
531 | } | ||
532 | @@ -XXX,XX +XXX,XX @@ struct BdrvOpBlocker { | ||
533 | bool bdrv_op_is_blocked(BlockDriverState *bs, BlockOpType op, Error **errp) | ||
534 | { | ||
535 | BdrvOpBlocker *blocker; | ||
536 | + GLOBAL_STATE_CODE(); | ||
537 | assert((int) op >= 0 && op < BLOCK_OP_TYPE_MAX); | ||
538 | if (!QLIST_EMPTY(&bs->op_blockers[op])) { | ||
539 | blocker = QLIST_FIRST(&bs->op_blockers[op]); | ||
540 | @@ -XXX,XX +XXX,XX @@ bool bdrv_op_is_blocked(BlockDriverState *bs, BlockOpType op, Error **errp) | ||
541 | void bdrv_op_block(BlockDriverState *bs, BlockOpType op, Error *reason) | ||
542 | { | ||
543 | BdrvOpBlocker *blocker; | ||
544 | + GLOBAL_STATE_CODE(); | ||
545 | assert((int) op >= 0 && op < BLOCK_OP_TYPE_MAX); | ||
546 | |||
547 | blocker = g_new0(BdrvOpBlocker, 1); | ||
548 | @@ -XXX,XX +XXX,XX @@ void bdrv_op_block(BlockDriverState *bs, BlockOpType op, Error *reason) | ||
549 | void bdrv_op_unblock(BlockDriverState *bs, BlockOpType op, Error *reason) | ||
550 | { | ||
551 | BdrvOpBlocker *blocker, *next; | ||
552 | + GLOBAL_STATE_CODE(); | ||
553 | assert((int) op >= 0 && op < BLOCK_OP_TYPE_MAX); | ||
554 | QLIST_FOREACH_SAFE(blocker, &bs->op_blockers[op], list, next) { | ||
555 | if (blocker->reason == reason) { | ||
556 | @@ -XXX,XX +XXX,XX @@ void bdrv_op_unblock(BlockDriverState *bs, BlockOpType op, Error *reason) | ||
557 | void bdrv_op_block_all(BlockDriverState *bs, Error *reason) | ||
558 | { | ||
559 | int i; | ||
560 | + GLOBAL_STATE_CODE(); | ||
561 | for (i = 0; i < BLOCK_OP_TYPE_MAX; i++) { | ||
562 | bdrv_op_block(bs, i, reason); | ||
563 | } | ||
564 | @@ -XXX,XX +XXX,XX @@ void bdrv_op_block_all(BlockDriverState *bs, Error *reason) | ||
565 | void bdrv_op_unblock_all(BlockDriverState *bs, Error *reason) | ||
566 | { | ||
567 | int i; | ||
568 | + GLOBAL_STATE_CODE(); | ||
569 | for (i = 0; i < BLOCK_OP_TYPE_MAX; i++) { | ||
570 | bdrv_op_unblock(bs, i, reason); | ||
571 | } | ||
572 | @@ -XXX,XX +XXX,XX @@ void bdrv_op_unblock_all(BlockDriverState *bs, Error *reason) | ||
573 | bool bdrv_op_blocker_is_empty(BlockDriverState *bs) | ||
574 | { | ||
575 | int i; | ||
576 | - | ||
577 | + GLOBAL_STATE_CODE(); | ||
578 | for (i = 0; i < BLOCK_OP_TYPE_MAX; i++) { | ||
579 | if (!QLIST_EMPTY(&bs->op_blockers[i])) { | ||
580 | return false; | ||
581 | @@ -XXX,XX +XXX,XX @@ void bdrv_img_create(const char *filename, const char *fmt, | ||
582 | Error *local_err = NULL; | ||
583 | int ret = 0; | ||
584 | |||
585 | + GLOBAL_STATE_CODE(); | ||
586 | + | ||
587 | /* Find driver and parse its options */ | ||
588 | drv = bdrv_find_format(fmt); | ||
589 | if (!drv) { | ||
590 | @@ -XXX,XX +XXX,XX @@ static bool bdrv_parent_can_set_aio_context(BdrvChild *c, AioContext *ctx, | ||
591 | bool bdrv_child_can_set_aio_context(BdrvChild *c, AioContext *ctx, | ||
592 | GSList **ignore, Error **errp) | ||
593 | { | ||
594 | + GLOBAL_STATE_CODE(); | ||
595 | if (g_slist_find(*ignore, c)) { | ||
596 | return true; | ||
597 | } | ||
598 | @@ -XXX,XX +XXX,XX @@ bool bdrv_can_set_aio_context(BlockDriverState *bs, AioContext *ctx, | ||
599 | return true; | ||
600 | } | ||
601 | |||
602 | + GLOBAL_STATE_CODE(); | ||
603 | + | ||
604 | QLIST_FOREACH(c, &bs->parents, next_parent) { | ||
605 | if (!bdrv_parent_can_set_aio_context(c, ctx, ignore, errp)) { | ||
606 | return false; | ||
607 | @@ -XXX,XX +XXX,XX @@ int bdrv_child_try_set_aio_context(BlockDriverState *bs, AioContext *ctx, | ||
608 | GSList *ignore; | ||
609 | bool ret; | ||
610 | |||
611 | + GLOBAL_STATE_CODE(); | ||
612 | + | ||
613 | ignore = ignore_child ? g_slist_prepend(NULL, ignore_child) : NULL; | ||
614 | ret = bdrv_can_set_aio_context(bs, ctx, &ignore, errp); | ||
615 | g_slist_free(ignore); | ||
616 | @@ -XXX,XX +XXX,XX @@ int bdrv_child_try_set_aio_context(BlockDriverState *bs, AioContext *ctx, | ||
617 | int bdrv_try_set_aio_context(BlockDriverState *bs, AioContext *ctx, | ||
618 | Error **errp) | ||
619 | { | ||
620 | + GLOBAL_STATE_CODE(); | ||
621 | return bdrv_child_try_set_aio_context(bs, ctx, NULL, errp); | ||
622 | } | ||
623 | |||
624 | @@ -XXX,XX +XXX,XX @@ void bdrv_add_aio_context_notifier(BlockDriverState *bs, | ||
625 | .detach_aio_context = detach_aio_context, | ||
626 | .opaque = opaque | ||
627 | }; | ||
628 | + GLOBAL_STATE_CODE(); | ||
629 | |||
630 | QLIST_INSERT_HEAD(&bs->aio_notifiers, ban, list); | ||
631 | } | ||
632 | @@ -XXX,XX +XXX,XX @@ void bdrv_remove_aio_context_notifier(BlockDriverState *bs, | ||
633 | void *opaque) | ||
634 | { | ||
635 | BdrvAioNotifier *ban, *ban_next; | ||
636 | + GLOBAL_STATE_CODE(); | ||
637 | |||
638 | QLIST_FOREACH_SAFE(ban, &bs->aio_notifiers, list, ban_next) { | ||
639 | if (ban->attached_aio_context == attached_aio_context && | ||
640 | @@ -XXX,XX +XXX,XX @@ int bdrv_amend_options(BlockDriverState *bs, QemuOpts *opts, | ||
641 | bool force, | ||
642 | Error **errp) | ||
643 | { | ||
644 | + GLOBAL_STATE_CODE(); | ||
645 | if (!bs->drv) { | ||
646 | error_setg(errp, "Node is ejected"); | ||
647 | return -ENOMEDIUM; | ||
648 | @@ -XXX,XX +XXX,XX @@ BlockDriverState *check_to_replace_node(BlockDriverState *parent_bs, | ||
649 | BlockDriverState *to_replace_bs = bdrv_find_node(node_name); | ||
650 | AioContext *aio_context; | ||
651 | |||
652 | + GLOBAL_STATE_CODE(); | ||
653 | + | ||
654 | if (!to_replace_bs) { | ||
655 | error_setg(errp, "Failed to find node with node-name='%s'", node_name); | ||
656 | return NULL; | ||
657 | @@ -XXX,XX +XXX,XX @@ void bdrv_refresh_filename(BlockDriverState *bs) | ||
658 | bool generate_json_filename; /* Whether our default implementation should | ||
659 | fill exact_filename (false) or not (true) */ | ||
660 | |||
661 | + GLOBAL_STATE_CODE(); | ||
662 | + | ||
663 | if (!drv) { | ||
664 | return; | ||
665 | } | ||
666 | @@ -XXX,XX +XXX,XX @@ char *bdrv_dirname(BlockDriverState *bs, Error **errp) | ||
667 | BlockDriver *drv = bs->drv; | ||
668 | BlockDriverState *child_bs; | ||
669 | |||
670 | + GLOBAL_STATE_CODE(); | ||
671 | + | ||
672 | if (!drv) { | ||
673 | error_setg(errp, "Node '%s' is ejected", bs->node_name); | ||
674 | return NULL; | ||
675 | @@ -XXX,XX +XXX,XX @@ char *bdrv_dirname(BlockDriverState *bs, Error **errp) | ||
676 | void bdrv_add_child(BlockDriverState *parent_bs, BlockDriverState *child_bs, | ||
677 | Error **errp) | ||
678 | { | ||
679 | - | ||
680 | + GLOBAL_STATE_CODE(); | ||
681 | if (!parent_bs->drv || !parent_bs->drv->bdrv_add_child) { | ||
682 | error_setg(errp, "The node %s does not support adding a child", | ||
683 | bdrv_get_device_or_node_name(parent_bs)); | ||
684 | @@ -XXX,XX +XXX,XX @@ void bdrv_del_child(BlockDriverState *parent_bs, BdrvChild *child, Error **errp) | ||
685 | { | ||
686 | BdrvChild *tmp; | ||
687 | |||
688 | + GLOBAL_STATE_CODE(); | ||
689 | if (!parent_bs->drv || !parent_bs->drv->bdrv_del_child) { | ||
690 | error_setg(errp, "The node %s does not support removing a child", | ||
691 | bdrv_get_device_or_node_name(parent_bs)); | ||
692 | @@ -XXX,XX +XXX,XX @@ int bdrv_make_empty(BdrvChild *c, Error **errp) | ||
693 | BlockDriver *drv = c->bs->drv; | ||
694 | int ret; | ||
695 | |||
696 | + GLOBAL_STATE_CODE(); | ||
697 | assert(c->perm & (BLK_PERM_WRITE | BLK_PERM_WRITE_UNCHANGED)); | ||
698 | |||
699 | if (!drv->bdrv_make_empty) { | ||
700 | diff --git a/block/commit.c b/block/commit.c | ||
701 | index XXXXXXX..XXXXXXX 100644 | ||
702 | --- a/block/commit.c | ||
703 | +++ b/block/commit.c | ||
704 | @@ -XXX,XX +XXX,XX @@ int bdrv_commit(BlockDriverState *bs) | ||
705 | QEMU_AUTO_VFREE uint8_t *buf = NULL; | ||
706 | Error *local_err = NULL; | ||
707 | |||
708 | + GLOBAL_STATE_CODE(); | ||
709 | + | ||
710 | if (!drv) | ||
711 | return -ENOMEDIUM; | ||
712 | |||
713 | diff --git a/block/io.c b/block/io.c | 10 | diff --git a/block/io.c b/block/io.c |
714 | index XXXXXXX..XXXXXXX 100644 | 11 | index XXXXXXX..XXXXXXX 100644 |
715 | --- a/block/io.c | 12 | --- a/block/io.c |
716 | +++ b/block/io.c | 13 | +++ b/block/io.c |
717 | @@ -XXX,XX +XXX,XX @@ void bdrv_refresh_limits(BlockDriverState *bs, Transaction *tran, Error **errp) | 14 | @@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void) |
718 | BdrvChild *c; | 15 | * context. */ |
719 | bool have_limits; | 16 | assert(qemu_get_current_aio_context() == qemu_get_aio_context()); |
720 | 17 | ||
721 | + GLOBAL_STATE_CODE(); | 18 | - block_job_pause_all(); |
722 | + | 19 | - |
723 | if (tran) { | 20 | for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { |
724 | BdrvRefreshLimitsState *s = g_new(BdrvRefreshLimitsState, 1); | 21 | AioContext *aio_context = bdrv_get_aio_context(bs); |
725 | *s = (BdrvRefreshLimitsState) { | 22 | |
726 | @@ -XXX,XX +XXX,XX @@ static bool bdrv_drain_all_poll(void) | ||
727 | { | ||
728 | BlockDriverState *bs = NULL; | ||
729 | bool result = false; | ||
730 | + GLOBAL_STATE_CODE(); | ||
731 | |||
732 | /* bdrv_drain_poll() can't make changes to the graph and we are holding the | ||
733 | * main AioContext lock, so iterating bdrv_next_all_states() is safe. */ | ||
734 | @@ -XXX,XX +XXX,XX @@ static bool bdrv_drain_all_poll(void) | ||
735 | void bdrv_drain_all_begin(void) | ||
736 | { | ||
737 | BlockDriverState *bs = NULL; | ||
738 | + GLOBAL_STATE_CODE(); | ||
739 | |||
740 | if (qemu_in_coroutine()) { | ||
741 | bdrv_co_yield_to_drain(NULL, true, false, NULL, true, true, NULL); | ||
742 | @@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_end(void) | 23 | @@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_end(void) |
743 | { | 24 | aio_enable_external(aio_context); |
744 | BlockDriverState *bs = NULL; | 25 | aio_context_release(aio_context); |
745 | int drained_end_counter = 0; | 26 | } |
746 | + GLOBAL_STATE_CODE(); | 27 | - |
747 | 28 | - block_job_resume_all(); | |
748 | /* | 29 | } |
749 | * bdrv queue is managed by record/replay, | ||
750 | @@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_end(void) | ||
751 | 30 | ||
752 | void bdrv_drain_all(void) | 31 | void bdrv_drain_all(void) |
753 | { | 32 | diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c |
754 | + GLOBAL_STATE_CODE(); | 33 | index XXXXXXX..XXXXXXX 100644 |
755 | bdrv_drain_all_begin(); | 34 | --- a/tests/test-bdrv-drain.c |
756 | bdrv_drain_all_end(); | 35 | +++ b/tests/test-bdrv-drain.c |
757 | } | 36 | @@ -XXX,XX +XXX,XX @@ static void test_blockjob_common(enum drain_type drain_type) |
758 | @@ -XXX,XX +XXX,XX @@ int bdrv_flush_all(void) | 37 | do_drain_begin(drain_type, src); |
759 | BlockDriverState *bs = NULL; | 38 | |
760 | int result = 0; | 39 | if (drain_type == BDRV_DRAIN_ALL) { |
761 | 40 | - /* bdrv_drain_all() drains both src and target, and involves an | |
762 | + GLOBAL_STATE_CODE(); | 41 | - * additional block_job_pause_all() */ |
763 | + | 42 | - g_assert_cmpint(job->pause_count, ==, 3); |
764 | /* | 43 | + /* bdrv_drain_all() drains both src and target */ |
765 | * bdrv queue is managed by record/replay, | 44 | + g_assert_cmpint(job->pause_count, ==, 2); |
766 | * creating new flush request for stopping | 45 | } else { |
767 | @@ -XXX,XX +XXX,XX @@ void bdrv_register_buf(BlockDriverState *bs, void *host, size_t size) | 46 | g_assert_cmpint(job->pause_count, ==, 1); |
768 | { | ||
769 | BdrvChild *child; | ||
770 | |||
771 | + GLOBAL_STATE_CODE(); | ||
772 | if (bs->drv && bs->drv->bdrv_register_buf) { | ||
773 | bs->drv->bdrv_register_buf(bs, host, size); | ||
774 | } | 47 | } |
775 | @@ -XXX,XX +XXX,XX @@ void bdrv_unregister_buf(BlockDriverState *bs, void *host) | 48 | @@ -XXX,XX +XXX,XX @@ static void test_blockjob_common(enum drain_type drain_type) |
776 | { | 49 | do_drain_begin(drain_type, target); |
777 | BdrvChild *child; | 50 | |
778 | 51 | if (drain_type == BDRV_DRAIN_ALL) { | |
779 | + GLOBAL_STATE_CODE(); | 52 | - /* bdrv_drain_all() drains both src and target, and involves an |
780 | if (bs->drv && bs->drv->bdrv_unregister_buf) { | 53 | - * additional block_job_pause_all() */ |
781 | bs->drv->bdrv_unregister_buf(bs, host); | 54 | - g_assert_cmpint(job->pause_count, ==, 3); |
55 | + /* bdrv_drain_all() drains both src and target */ | ||
56 | + g_assert_cmpint(job->pause_count, ==, 2); | ||
57 | } else { | ||
58 | g_assert_cmpint(job->pause_count, ==, 1); | ||
782 | } | 59 | } |
783 | @@ -XXX,XX +XXX,XX @@ out: | ||
784 | |||
785 | void bdrv_cancel_in_flight(BlockDriverState *bs) | ||
786 | { | ||
787 | + GLOBAL_STATE_CODE(); | ||
788 | if (!bs || !bs->drv) { | ||
789 | return; | ||
790 | } | ||
791 | diff --git a/blockdev.c b/blockdev.c | ||
792 | index XXXXXXX..XXXXXXX 100644 | ||
793 | --- a/blockdev.c | ||
794 | +++ b/blockdev.c | ||
795 | @@ -XXX,XX +XXX,XX @@ void blockdev_close_all_bdrv_states(void) | ||
796 | /* Iterates over the list of monitor-owned BlockDriverStates */ | ||
797 | BlockDriverState *bdrv_next_monitor_owned(BlockDriverState *bs) | ||
798 | { | ||
799 | + GLOBAL_STATE_CODE(); | ||
800 | return bs ? QTAILQ_NEXT(bs, monitor_list) | ||
801 | : QTAILQ_FIRST(&monitor_bdrv_states); | ||
802 | } | ||
803 | -- | 60 | -- |
804 | 2.35.1 | 61 | 2.13.6 |
62 | |||
63 | diff view generated by jsdifflib |
1 | From: Stefan Hajnoczi <stefanha@redhat.com> | 1 | bdrv_do_drained_begin() restricts the call of parent callbacks and |
---|---|---|---|
2 | aio_disable_external() to the outermost drain section, but the block | ||
3 | driver callbacks are always called. bdrv_do_drained_end() must match | ||
4 | this behaviour, otherwise nodes stay drained even if begin/end calls | ||
5 | were balanced. | ||
2 | 6 | ||
3 | QEMU TLS macros must be used to make TLS variables safe with coroutines. | ||
4 | |||
5 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
6 | Message-Id: <20220222140150.27240-3-stefanha@redhat.com> | ||
7 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 7 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
8 | --- | 8 | --- |
9 | util/async.c | 12 +++++++----- | 9 | block/io.c | 12 +++++++----- |
10 | 1 file changed, 7 insertions(+), 5 deletions(-) | 10 | 1 file changed, 7 insertions(+), 5 deletions(-) |
11 | 11 | ||
12 | diff --git a/util/async.c b/util/async.c | 12 | diff --git a/block/io.c b/block/io.c |
13 | index XXXXXXX..XXXXXXX 100644 | 13 | index XXXXXXX..XXXXXXX 100644 |
14 | --- a/util/async.c | 14 | --- a/block/io.c |
15 | +++ b/util/async.c | 15 | +++ b/block/io.c |
16 | @@ -XXX,XX +XXX,XX @@ | 16 | @@ -XXX,XX +XXX,XX @@ void bdrv_drained_begin(BlockDriverState *bs) |
17 | #include "qemu/rcu_queue.h" | 17 | |
18 | #include "block/raw-aio.h" | 18 | void bdrv_drained_end(BlockDriverState *bs) |
19 | #include "qemu/coroutine_int.h" | 19 | { |
20 | +#include "qemu/coroutine-tls.h" | 20 | + int old_quiesce_counter; |
21 | #include "trace.h" | 21 | + |
22 | 22 | if (qemu_in_coroutine()) { | |
23 | /***********************************************************/ | 23 | bdrv_co_yield_to_drain(bs, false); |
24 | @@ -XXX,XX +XXX,XX @@ void aio_context_release(AioContext *ctx) | 24 | return; |
25 | qemu_rec_mutex_unlock(&ctx->lock); | 25 | } |
26 | assert(bs->quiesce_counter > 0); | ||
27 | - if (atomic_fetch_dec(&bs->quiesce_counter) > 1) { | ||
28 | - return; | ||
29 | - } | ||
30 | + old_quiesce_counter = atomic_fetch_dec(&bs->quiesce_counter); | ||
31 | |||
32 | /* Re-enable things in child-to-parent order */ | ||
33 | bdrv_drain_invoke(bs, false, false); | ||
34 | - bdrv_parent_drained_end(bs); | ||
35 | - aio_enable_external(bdrv_get_aio_context(bs)); | ||
36 | + if (old_quiesce_counter == 1) { | ||
37 | + bdrv_parent_drained_end(bs); | ||
38 | + aio_enable_external(bdrv_get_aio_context(bs)); | ||
39 | + } | ||
26 | } | 40 | } |
27 | 41 | ||
28 | -static __thread AioContext *my_aiocontext; | 42 | /* |
29 | +QEMU_DEFINE_STATIC_CO_TLS(AioContext *, my_aiocontext) | ||
30 | |||
31 | AioContext *qemu_get_current_aio_context(void) | ||
32 | { | ||
33 | - if (my_aiocontext) { | ||
34 | - return my_aiocontext; | ||
35 | + AioContext *ctx = get_my_aiocontext(); | ||
36 | + if (ctx) { | ||
37 | + return ctx; | ||
38 | } | ||
39 | if (qemu_mutex_iothread_locked()) { | ||
40 | /* Possibly in a vCPU thread. */ | ||
41 | @@ -XXX,XX +XXX,XX @@ AioContext *qemu_get_current_aio_context(void) | ||
42 | |||
43 | void qemu_set_current_aio_context(AioContext *ctx) | ||
44 | { | ||
45 | - assert(!my_aiocontext); | ||
46 | - my_aiocontext = ctx; | ||
47 | + assert(!get_my_aiocontext()); | ||
48 | + set_my_aiocontext(ctx); | ||
49 | } | ||
50 | -- | 43 | -- |
51 | 2.35.1 | 44 | 2.13.6 |
45 | |||
46 | diff view generated by jsdifflib |
1 | From: Stefan Hajnoczi <stefanha@redhat.com> | ||
---|---|---|---|
2 | |||
3 | RCU may be used from coroutines. Standard __thread variables cannot be | ||
4 | used by coroutines. Use the coroutine TLS macros instead. | ||
5 | |||
6 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
7 | Message-Id: <20220222140150.27240-4-stefanha@redhat.com> | ||
8 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 1 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
9 | --- | 2 | --- |
10 | include/qemu/rcu.h | 7 ++++--- | 3 | tests/test-bdrv-drain.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++ |
11 | tests/unit/rcutorture.c | 10 +++++----- | 4 | 1 file changed, 57 insertions(+) |
12 | tests/unit/test-rcu-list.c | 4 ++-- | ||
13 | util/rcu.c | 10 +++++----- | ||
14 | 4 files changed, 16 insertions(+), 15 deletions(-) | ||
15 | 5 | ||
16 | diff --git a/include/qemu/rcu.h b/include/qemu/rcu.h | 6 | diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c |
17 | index XXXXXXX..XXXXXXX 100644 | 7 | index XXXXXXX..XXXXXXX 100644 |
18 | --- a/include/qemu/rcu.h | 8 | --- a/tests/test-bdrv-drain.c |
19 | +++ b/include/qemu/rcu.h | 9 | +++ b/tests/test-bdrv-drain.c |
20 | @@ -XXX,XX +XXX,XX @@ | 10 | @@ -XXX,XX +XXX,XX @@ static void aio_ret_cb(void *opaque, int ret) |
21 | #include "qemu/atomic.h" | 11 | enum drain_type { |
22 | #include "qemu/notify.h" | 12 | BDRV_DRAIN_ALL, |
23 | #include "qemu/sys_membarrier.h" | 13 | BDRV_DRAIN, |
24 | +#include "qemu/coroutine-tls.h" | 14 | + DRAIN_TYPE_MAX, |
25 | |||
26 | #ifdef __cplusplus | ||
27 | extern "C" { | ||
28 | @@ -XXX,XX +XXX,XX @@ struct rcu_reader_data { | ||
29 | NotifierList force_rcu; | ||
30 | }; | 15 | }; |
31 | 16 | ||
32 | -extern __thread struct rcu_reader_data rcu_reader; | 17 | static void do_drain_begin(enum drain_type drain_type, BlockDriverState *bs) |
33 | +QEMU_DECLARE_CO_TLS(struct rcu_reader_data, rcu_reader) | 18 | @@ -XXX,XX +XXX,XX @@ static void test_quiesce_drain(void) |
34 | 19 | test_quiesce_common(BDRV_DRAIN, false); | |
35 | static inline void rcu_read_lock(void) | ||
36 | { | ||
37 | - struct rcu_reader_data *p_rcu_reader = &rcu_reader; | ||
38 | + struct rcu_reader_data *p_rcu_reader = get_ptr_rcu_reader(); | ||
39 | unsigned ctr; | ||
40 | |||
41 | if (p_rcu_reader->depth++ > 0) { | ||
42 | @@ -XXX,XX +XXX,XX @@ static inline void rcu_read_lock(void) | ||
43 | |||
44 | static inline void rcu_read_unlock(void) | ||
45 | { | ||
46 | - struct rcu_reader_data *p_rcu_reader = &rcu_reader; | ||
47 | + struct rcu_reader_data *p_rcu_reader = get_ptr_rcu_reader(); | ||
48 | |||
49 | assert(p_rcu_reader->depth != 0); | ||
50 | if (--p_rcu_reader->depth > 0) { | ||
51 | diff --git a/tests/unit/rcutorture.c b/tests/unit/rcutorture.c | ||
52 | index XXXXXXX..XXXXXXX 100644 | ||
53 | --- a/tests/unit/rcutorture.c | ||
54 | +++ b/tests/unit/rcutorture.c | ||
55 | @@ -XXX,XX +XXX,XX @@ static void *rcu_read_perf_test(void *arg) | ||
56 | |||
57 | rcu_register_thread(); | ||
58 | |||
59 | - *(struct rcu_reader_data **)arg = &rcu_reader; | ||
60 | + *(struct rcu_reader_data **)arg = get_ptr_rcu_reader(); | ||
61 | qatomic_inc(&nthreadsrunning); | ||
62 | while (goflag == GOFLAG_INIT) { | ||
63 | g_usleep(1000); | ||
64 | @@ -XXX,XX +XXX,XX @@ static void *rcu_update_perf_test(void *arg) | ||
65 | |||
66 | rcu_register_thread(); | ||
67 | |||
68 | - *(struct rcu_reader_data **)arg = &rcu_reader; | ||
69 | + *(struct rcu_reader_data **)arg = get_ptr_rcu_reader(); | ||
70 | qatomic_inc(&nthreadsrunning); | ||
71 | while (goflag == GOFLAG_INIT) { | ||
72 | g_usleep(1000); | ||
73 | @@ -XXX,XX +XXX,XX @@ static void *rcu_read_stress_test(void *arg) | ||
74 | |||
75 | rcu_register_thread(); | ||
76 | |||
77 | - *(struct rcu_reader_data **)arg = &rcu_reader; | ||
78 | + *(struct rcu_reader_data **)arg = get_ptr_rcu_reader(); | ||
79 | while (goflag == GOFLAG_INIT) { | ||
80 | g_usleep(1000); | ||
81 | } | ||
82 | @@ -XXX,XX +XXX,XX @@ static void *rcu_update_stress_test(void *arg) | ||
83 | struct rcu_stress *cp = qatomic_read(&rcu_stress_current); | ||
84 | |||
85 | rcu_register_thread(); | ||
86 | - *(struct rcu_reader_data **)arg = &rcu_reader; | ||
87 | + *(struct rcu_reader_data **)arg = get_ptr_rcu_reader(); | ||
88 | |||
89 | while (goflag == GOFLAG_INIT) { | ||
90 | g_usleep(1000); | ||
91 | @@ -XXX,XX +XXX,XX @@ static void *rcu_fake_update_stress_test(void *arg) | ||
92 | { | ||
93 | rcu_register_thread(); | ||
94 | |||
95 | - *(struct rcu_reader_data **)arg = &rcu_reader; | ||
96 | + *(struct rcu_reader_data **)arg = get_ptr_rcu_reader(); | ||
97 | while (goflag == GOFLAG_INIT) { | ||
98 | g_usleep(1000); | ||
99 | } | ||
100 | diff --git a/tests/unit/test-rcu-list.c b/tests/unit/test-rcu-list.c | ||
101 | index XXXXXXX..XXXXXXX 100644 | ||
102 | --- a/tests/unit/test-rcu-list.c | ||
103 | +++ b/tests/unit/test-rcu-list.c | ||
104 | @@ -XXX,XX +XXX,XX @@ static void *rcu_q_reader(void *arg) | ||
105 | |||
106 | rcu_register_thread(); | ||
107 | |||
108 | - *(struct rcu_reader_data **)arg = &rcu_reader; | ||
109 | + *(struct rcu_reader_data **)arg = get_ptr_rcu_reader(); | ||
110 | qatomic_inc(&nthreadsrunning); | ||
111 | while (qatomic_read(&goflag) == GOFLAG_INIT) { | ||
112 | g_usleep(1000); | ||
113 | @@ -XXX,XX +XXX,XX @@ static void *rcu_q_updater(void *arg) | ||
114 | long long n_removed_local = 0; | ||
115 | struct list_element *el, *prev_el; | ||
116 | |||
117 | - *(struct rcu_reader_data **)arg = &rcu_reader; | ||
118 | + *(struct rcu_reader_data **)arg = get_ptr_rcu_reader(); | ||
119 | qatomic_inc(&nthreadsrunning); | ||
120 | while (qatomic_read(&goflag) == GOFLAG_INIT) { | ||
121 | g_usleep(1000); | ||
122 | diff --git a/util/rcu.c b/util/rcu.c | ||
123 | index XXXXXXX..XXXXXXX 100644 | ||
124 | --- a/util/rcu.c | ||
125 | +++ b/util/rcu.c | ||
126 | @@ -XXX,XX +XXX,XX @@ static inline int rcu_gp_ongoing(unsigned long *ctr) | ||
127 | /* Written to only by each individual reader. Read by both the reader and the | ||
128 | * writers. | ||
129 | */ | ||
130 | -__thread struct rcu_reader_data rcu_reader; | ||
131 | +QEMU_DEFINE_CO_TLS(struct rcu_reader_data, rcu_reader) | ||
132 | |||
133 | /* Protected by rcu_registry_lock. */ | ||
134 | typedef QLIST_HEAD(, rcu_reader_data) ThreadList; | ||
135 | @@ -XXX,XX +XXX,XX @@ void drain_call_rcu(void) | ||
136 | |||
137 | void rcu_register_thread(void) | ||
138 | { | ||
139 | - assert(rcu_reader.ctr == 0); | ||
140 | + assert(get_ptr_rcu_reader()->ctr == 0); | ||
141 | qemu_mutex_lock(&rcu_registry_lock); | ||
142 | - QLIST_INSERT_HEAD(®istry, &rcu_reader, node); | ||
143 | + QLIST_INSERT_HEAD(®istry, get_ptr_rcu_reader(), node); | ||
144 | qemu_mutex_unlock(&rcu_registry_lock); | ||
145 | } | 20 | } |
146 | 21 | ||
147 | void rcu_unregister_thread(void) | 22 | +static void test_nested(void) |
148 | { | 23 | +{ |
149 | qemu_mutex_lock(&rcu_registry_lock); | 24 | + BlockBackend *blk; |
150 | - QLIST_REMOVE(&rcu_reader, node); | 25 | + BlockDriverState *bs, *backing; |
151 | + QLIST_REMOVE(get_ptr_rcu_reader(), node); | 26 | + BDRVTestState *s, *backing_s; |
152 | qemu_mutex_unlock(&rcu_registry_lock); | 27 | + enum drain_type outer, inner; |
153 | } | 28 | + |
154 | 29 | + blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL); | |
155 | void rcu_add_force_rcu_notifier(Notifier *n) | 30 | + bs = bdrv_new_open_driver(&bdrv_test, "test-node", BDRV_O_RDWR, |
156 | { | 31 | + &error_abort); |
157 | qemu_mutex_lock(&rcu_registry_lock); | 32 | + s = bs->opaque; |
158 | - notifier_list_add(&rcu_reader.force_rcu, n); | 33 | + blk_insert_bs(blk, bs, &error_abort); |
159 | + notifier_list_add(&get_ptr_rcu_reader()->force_rcu, n); | 34 | + |
160 | qemu_mutex_unlock(&rcu_registry_lock); | 35 | + backing = bdrv_new_open_driver(&bdrv_test, "backing", 0, &error_abort); |
161 | } | 36 | + backing_s = backing->opaque; |
37 | + bdrv_set_backing_hd(bs, backing, &error_abort); | ||
38 | + | ||
39 | + for (outer = 0; outer < DRAIN_TYPE_MAX; outer++) { | ||
40 | + for (inner = 0; inner < DRAIN_TYPE_MAX; inner++) { | ||
41 | + /* XXX bdrv_drain_all() doesn't increase the quiesce_counter */ | ||
42 | + int bs_quiesce = (outer != BDRV_DRAIN_ALL) + | ||
43 | + (inner != BDRV_DRAIN_ALL); | ||
44 | + int backing_quiesce = 0; | ||
45 | + int backing_cb_cnt = (outer != BDRV_DRAIN) + | ||
46 | + (inner != BDRV_DRAIN); | ||
47 | + | ||
48 | + g_assert_cmpint(bs->quiesce_counter, ==, 0); | ||
49 | + g_assert_cmpint(backing->quiesce_counter, ==, 0); | ||
50 | + g_assert_cmpint(s->drain_count, ==, 0); | ||
51 | + g_assert_cmpint(backing_s->drain_count, ==, 0); | ||
52 | + | ||
53 | + do_drain_begin(outer, bs); | ||
54 | + do_drain_begin(inner, bs); | ||
55 | + | ||
56 | + g_assert_cmpint(bs->quiesce_counter, ==, bs_quiesce); | ||
57 | + g_assert_cmpint(backing->quiesce_counter, ==, backing_quiesce); | ||
58 | + g_assert_cmpint(s->drain_count, ==, 2); | ||
59 | + g_assert_cmpint(backing_s->drain_count, ==, backing_cb_cnt); | ||
60 | + | ||
61 | + do_drain_end(inner, bs); | ||
62 | + do_drain_end(outer, bs); | ||
63 | + | ||
64 | + g_assert_cmpint(bs->quiesce_counter, ==, 0); | ||
65 | + g_assert_cmpint(backing->quiesce_counter, ==, 0); | ||
66 | + g_assert_cmpint(s->drain_count, ==, 0); | ||
67 | + g_assert_cmpint(backing_s->drain_count, ==, 0); | ||
68 | + } | ||
69 | + } | ||
70 | + | ||
71 | + bdrv_unref(backing); | ||
72 | + bdrv_unref(bs); | ||
73 | + blk_unref(blk); | ||
74 | +} | ||
75 | + | ||
76 | |||
77 | typedef struct TestBlockJob { | ||
78 | BlockJob common; | ||
79 | @@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv) | ||
80 | g_test_add_func("/bdrv-drain/quiesce/drain_all", test_quiesce_drain_all); | ||
81 | g_test_add_func("/bdrv-drain/quiesce/drain", test_quiesce_drain); | ||
82 | |||
83 | + g_test_add_func("/bdrv-drain/nested", test_nested); | ||
84 | + | ||
85 | g_test_add_func("/bdrv-drain/blockjob/drain_all", test_blockjob_drain_all); | ||
86 | g_test_add_func("/bdrv-drain/blockjob/drain", test_blockjob_drain); | ||
162 | 87 | ||
163 | -- | 88 | -- |
164 | 2.35.1 | 89 | 2.13.6 |
90 | |||
91 | diff view generated by jsdifflib |
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | 1 | This is in preparation for subtree drains, i.e. drained sections that |
---|---|---|---|
2 | 2 | affect not only a single node, but recursively all child nodes, too. | |
3 | Following the bdrv_activate renaming, change also the name | 3 | |
4 | of the respective callers. | 4 | Calling the parent callbacks for drain is pointless when we just came |
5 | 5 | from that parent node recursively and leads to multiple increases of | |
6 | bdrv_invalidate_cache_all -> bdrv_activate_all | 6 | bs->quiesce_counter in a single drain call. Don't do it. |
7 | blk_invalidate_cache -> blk_activate | 7 | |
8 | test_sync_op_invalidate_cache -> test_sync_op_activate | 8 | In order for this to work correctly, the parent callback must be called |
9 | 9 | for every bdrv_drain_begin/end() call, not only for the outermost one: | |
10 | No functional change intended. | 10 | |
11 | 11 | If we have a node N with two parents A and B, recursive draining of A | |
12 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | 12 | should cause the quiesce_counter of B to increase because its child N is |
13 | Reviewed-by: Juan Quintela <quintela@redhat.com> | 13 | drained independently of B. If now B is recursively drained, too, A must |
14 | Reviewed-by: Hanna Reitz <hreitz@redhat.com> | 14 | increase its quiesce_counter because N is drained independently of A |
15 | Message-Id: <20220209105452.1694545-5-eesposit@redhat.com> | 15 | only now, even if N is going from quiesce_counter 1 to 2. |
16 | |||
16 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 17 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
17 | --- | 18 | --- |
18 | include/block/block.h | 2 +- | 19 | include/block/block.h | 4 ++-- |
19 | include/sysemu/block-backend.h | 2 +- | 20 | block.c | 13 +++++++++---- |
20 | block.c | 2 +- | 21 | block/io.c | 47 ++++++++++++++++++++++++++++++++++------------- |
21 | block/block-backend.c | 2 +- | 22 | 3 files changed, 45 insertions(+), 19 deletions(-) |
22 | hw/block/pflash_cfi01.c | 2 +- | ||
23 | hw/nvram/spapr_nvram.c | 2 +- | ||
24 | migration/block.c | 2 +- | ||
25 | migration/migration.c | 14 +++++++------- | ||
26 | migration/savevm.c | 6 +++--- | ||
27 | monitor/qmp-cmds.c | 2 +- | ||
28 | tests/unit/test-block-iothread.c | 6 +++--- | ||
29 | 11 files changed, 21 insertions(+), 21 deletions(-) | ||
30 | 23 | ||
31 | diff --git a/include/block/block.h b/include/block/block.h | 24 | diff --git a/include/block/block.h b/include/block/block.h |
32 | index XXXXXXX..XXXXXXX 100644 | 25 | index XXXXXXX..XXXXXXX 100644 |
33 | --- a/include/block/block.h | 26 | --- a/include/block/block.h |
34 | +++ b/include/block/block.h | 27 | +++ b/include/block/block.h |
35 | @@ -XXX,XX +XXX,XX @@ int bdrv_co_ioctl(BlockDriverState *bs, int req, void *buf); | 28 | @@ -XXX,XX +XXX,XX @@ void bdrv_io_unplug(BlockDriverState *bs); |
36 | /* Invalidate any cached metadata used by image formats */ | 29 | * Begin a quiesced section of all users of @bs. This is part of |
37 | int generated_co_wrapper bdrv_invalidate_cache(BlockDriverState *bs, | 30 | * bdrv_drained_begin. |
38 | Error **errp); | 31 | */ |
39 | -void bdrv_invalidate_cache_all(Error **errp); | 32 | -void bdrv_parent_drained_begin(BlockDriverState *bs); |
40 | int bdrv_activate(BlockDriverState *bs, Error **errp); | 33 | +void bdrv_parent_drained_begin(BlockDriverState *bs, BdrvChild *ignore); |
41 | +void bdrv_activate_all(Error **errp); | 34 | |
42 | int bdrv_inactivate_all(void); | 35 | /** |
43 | 36 | * bdrv_parent_drained_end: | |
44 | /* Ensure contents are flushed to disk. */ | 37 | @@ -XXX,XX +XXX,XX @@ void bdrv_parent_drained_begin(BlockDriverState *bs); |
45 | diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h | 38 | * End a quiesced section of all users of @bs. This is part of |
46 | index XXXXXXX..XXXXXXX 100644 | 39 | * bdrv_drained_end. |
47 | --- a/include/sysemu/block-backend.h | 40 | */ |
48 | +++ b/include/sysemu/block-backend.h | 41 | -void bdrv_parent_drained_end(BlockDriverState *bs); |
49 | @@ -XXX,XX +XXX,XX @@ bool blk_is_writable(BlockBackend *blk); | 42 | +void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore); |
50 | bool blk_is_sg(BlockBackend *blk); | 43 | |
51 | bool blk_enable_write_cache(BlockBackend *blk); | 44 | /** |
52 | void blk_set_enable_write_cache(BlockBackend *blk, bool wce); | 45 | * bdrv_drained_begin: |
53 | -void blk_invalidate_cache(BlockBackend *blk, Error **errp); | ||
54 | +void blk_activate(BlockBackend *blk, Error **errp); | ||
55 | bool blk_is_inserted(BlockBackend *blk); | ||
56 | bool blk_is_available(BlockBackend *blk); | ||
57 | void blk_lock_medium(BlockBackend *blk, bool locked); | ||
58 | diff --git a/block.c b/block.c | 46 | diff --git a/block.c b/block.c |
59 | index XXXXXXX..XXXXXXX 100644 | 47 | index XXXXXXX..XXXXXXX 100644 |
60 | --- a/block.c | 48 | --- a/block.c |
61 | +++ b/block.c | 49 | +++ b/block.c |
62 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs, Error **errp) | 50 | @@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_noperm(BdrvChild *child, |
63 | return 0; | 51 | BlockDriverState *new_bs) |
64 | } | 52 | { |
65 | 53 | BlockDriverState *old_bs = child->bs; | |
66 | -void bdrv_invalidate_cache_all(Error **errp) | 54 | + int i; |
67 | +void bdrv_activate_all(Error **errp) | 55 | |
68 | { | 56 | if (old_bs && new_bs) { |
57 | assert(bdrv_get_aio_context(old_bs) == bdrv_get_aio_context(new_bs)); | ||
58 | } | ||
59 | if (old_bs) { | ||
60 | if (old_bs->quiesce_counter && child->role->drained_end) { | ||
61 | - child->role->drained_end(child); | ||
62 | + for (i = 0; i < old_bs->quiesce_counter; i++) { | ||
63 | + child->role->drained_end(child); | ||
64 | + } | ||
65 | } | ||
66 | if (child->role->detach) { | ||
67 | child->role->detach(child); | ||
68 | @@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_noperm(BdrvChild *child, | ||
69 | if (new_bs) { | ||
70 | QLIST_INSERT_HEAD(&new_bs->parents, child, next_parent); | ||
71 | if (new_bs->quiesce_counter && child->role->drained_begin) { | ||
72 | - child->role->drained_begin(child); | ||
73 | + for (i = 0; i < new_bs->quiesce_counter; i++) { | ||
74 | + child->role->drained_begin(child); | ||
75 | + } | ||
76 | } | ||
77 | |||
78 | if (child->role->attach) { | ||
79 | @@ -XXX,XX +XXX,XX @@ void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context) | ||
80 | AioContext *ctx = bdrv_get_aio_context(bs); | ||
81 | |||
82 | aio_disable_external(ctx); | ||
83 | - bdrv_parent_drained_begin(bs); | ||
84 | + bdrv_parent_drained_begin(bs, NULL); | ||
85 | bdrv_drain(bs); /* ensure there are no in-flight requests */ | ||
86 | |||
87 | while (aio_poll(ctx, false)) { | ||
88 | @@ -XXX,XX +XXX,XX @@ void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context) | ||
89 | */ | ||
90 | aio_context_acquire(new_context); | ||
91 | bdrv_attach_aio_context(bs, new_context); | ||
92 | - bdrv_parent_drained_end(bs); | ||
93 | + bdrv_parent_drained_end(bs, NULL); | ||
94 | aio_enable_external(ctx); | ||
95 | aio_context_release(new_context); | ||
96 | } | ||
97 | diff --git a/block/io.c b/block/io.c | ||
98 | index XXXXXXX..XXXXXXX 100644 | ||
99 | --- a/block/io.c | ||
100 | +++ b/block/io.c | ||
101 | @@ -XXX,XX +XXX,XX @@ | ||
102 | static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs, | ||
103 | int64_t offset, int bytes, BdrvRequestFlags flags); | ||
104 | |||
105 | -void bdrv_parent_drained_begin(BlockDriverState *bs) | ||
106 | +void bdrv_parent_drained_begin(BlockDriverState *bs, BdrvChild *ignore) | ||
107 | { | ||
108 | BdrvChild *c, *next; | ||
109 | |||
110 | QLIST_FOREACH_SAFE(c, &bs->parents, next_parent, next) { | ||
111 | + if (c == ignore) { | ||
112 | + continue; | ||
113 | + } | ||
114 | if (c->role->drained_begin) { | ||
115 | c->role->drained_begin(c); | ||
116 | } | ||
117 | } | ||
118 | } | ||
119 | |||
120 | -void bdrv_parent_drained_end(BlockDriverState *bs) | ||
121 | +void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore) | ||
122 | { | ||
123 | BdrvChild *c, *next; | ||
124 | |||
125 | QLIST_FOREACH_SAFE(c, &bs->parents, next_parent, next) { | ||
126 | + if (c == ignore) { | ||
127 | + continue; | ||
128 | + } | ||
129 | if (c->role->drained_end) { | ||
130 | c->role->drained_end(c); | ||
131 | } | ||
132 | @@ -XXX,XX +XXX,XX @@ typedef struct { | ||
69 | BlockDriverState *bs; | 133 | BlockDriverState *bs; |
70 | BdrvNextIterator it; | 134 | bool done; |
71 | diff --git a/block/block-backend.c b/block/block-backend.c | 135 | bool begin; |
72 | index XXXXXXX..XXXXXXX 100644 | 136 | + BdrvChild *parent; |
73 | --- a/block/block-backend.c | 137 | } BdrvCoDrainData; |
74 | +++ b/block/block-backend.c | 138 | |
75 | @@ -XXX,XX +XXX,XX @@ void blk_set_enable_write_cache(BlockBackend *blk, bool wce) | 139 | static void coroutine_fn bdrv_drain_invoke_entry(void *opaque) |
76 | blk->enable_write_cache = wce; | 140 | @@ -XXX,XX +XXX,XX @@ static bool bdrv_drain_recurse(BlockDriverState *bs) |
77 | } | 141 | return waited; |
78 | 142 | } | |
79 | -void blk_invalidate_cache(BlockBackend *blk, Error **errp) | 143 | |
80 | +void blk_activate(BlockBackend *blk, Error **errp) | 144 | +static void bdrv_do_drained_begin(BlockDriverState *bs, BdrvChild *parent); |
81 | { | 145 | +static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent); |
82 | BlockDriverState *bs = blk_bs(blk); | 146 | + |
83 | 147 | static void bdrv_co_drain_bh_cb(void *opaque) | |
84 | diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c | 148 | { |
85 | index XXXXXXX..XXXXXXX 100644 | 149 | BdrvCoDrainData *data = opaque; |
86 | --- a/hw/block/pflash_cfi01.c | 150 | @@ -XXX,XX +XXX,XX @@ static void bdrv_co_drain_bh_cb(void *opaque) |
87 | +++ b/hw/block/pflash_cfi01.c | 151 | |
88 | @@ -XXX,XX +XXX,XX @@ static void postload_update_cb(void *opaque, bool running, RunState state) | 152 | bdrv_dec_in_flight(bs); |
89 | { | 153 | if (data->begin) { |
90 | PFlashCFI01 *pfl = opaque; | 154 | - bdrv_drained_begin(bs); |
91 | 155 | + bdrv_do_drained_begin(bs, data->parent); | |
92 | - /* This is called after bdrv_invalidate_cache_all. */ | 156 | } else { |
93 | + /* This is called after bdrv_activate_all. */ | 157 | - bdrv_drained_end(bs); |
94 | qemu_del_vm_change_state_handler(pfl->vmstate); | 158 | + bdrv_do_drained_end(bs, data->parent); |
95 | pfl->vmstate = NULL; | 159 | } |
96 | 160 | ||
97 | diff --git a/hw/nvram/spapr_nvram.c b/hw/nvram/spapr_nvram.c | 161 | data->done = true; |
98 | index XXXXXXX..XXXXXXX 100644 | 162 | @@ -XXX,XX +XXX,XX @@ static void bdrv_co_drain_bh_cb(void *opaque) |
99 | --- a/hw/nvram/spapr_nvram.c | 163 | } |
100 | +++ b/hw/nvram/spapr_nvram.c | 164 | |
101 | @@ -XXX,XX +XXX,XX @@ static void postload_update_cb(void *opaque, bool running, RunState state) | 165 | static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs, |
102 | { | 166 | - bool begin) |
103 | SpaprNvram *nvram = opaque; | 167 | + bool begin, BdrvChild *parent) |
104 | 168 | { | |
105 | - /* This is called after bdrv_invalidate_cache_all. */ | 169 | BdrvCoDrainData data; |
106 | + /* This is called after bdrv_activate_all. */ | 170 | |
107 | 171 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs, | |
108 | qemu_del_vm_change_state_handler(nvram->vmstate); | 172 | .bs = bs, |
109 | nvram->vmstate = NULL; | 173 | .done = false, |
110 | diff --git a/migration/block.c b/migration/block.c | 174 | .begin = begin, |
111 | index XXXXXXX..XXXXXXX 100644 | 175 | + .parent = parent, |
112 | --- a/migration/block.c | 176 | }; |
113 | +++ b/migration/block.c | 177 | bdrv_inc_in_flight(bs); |
114 | @@ -XXX,XX +XXX,XX @@ static int block_load(QEMUFile *f, void *opaque, int version_id) | 178 | aio_bh_schedule_oneshot(bdrv_get_aio_context(bs), |
115 | return -EINVAL; | 179 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs, |
116 | } | 180 | assert(data.done); |
117 | 181 | } | |
118 | - blk_invalidate_cache(blk, &local_err); | 182 | |
119 | + blk_activate(blk, &local_err); | 183 | -void bdrv_drained_begin(BlockDriverState *bs) |
120 | if (local_err) { | 184 | +static void bdrv_do_drained_begin(BlockDriverState *bs, BdrvChild *parent) |
121 | error_report_err(local_err); | 185 | { |
122 | return -EINVAL; | 186 | if (qemu_in_coroutine()) { |
123 | diff --git a/migration/migration.c b/migration/migration.c | 187 | - bdrv_co_yield_to_drain(bs, true); |
124 | index XXXXXXX..XXXXXXX 100644 | 188 | + bdrv_co_yield_to_drain(bs, true, parent); |
125 | --- a/migration/migration.c | ||
126 | +++ b/migration/migration.c | ||
127 | @@ -XXX,XX +XXX,XX @@ static void process_incoming_migration_bh(void *opaque) | ||
128 | if (!migrate_late_block_activate() || | ||
129 | (autostart && (!global_state_received() || | ||
130 | global_state_get_runstate() == RUN_STATE_RUNNING))) { | ||
131 | - /* Make sure all file formats flush their mutable metadata. | ||
132 | + /* Make sure all file formats throw away their mutable metadata. | ||
133 | * If we get an error here, just don't restart the VM yet. */ | ||
134 | - bdrv_invalidate_cache_all(&local_err); | ||
135 | + bdrv_activate_all(&local_err); | ||
136 | if (local_err) { | ||
137 | error_report_err(local_err); | ||
138 | local_err = NULL; | ||
139 | @@ -XXX,XX +XXX,XX @@ static void process_incoming_migration_co(void *opaque) | ||
140 | |||
141 | /* we get COLO info, and know if we are in COLO mode */ | ||
142 | if (!ret && migration_incoming_colo_enabled()) { | ||
143 | - /* Make sure all file formats flush their mutable metadata */ | ||
144 | - bdrv_invalidate_cache_all(&local_err); | ||
145 | + /* Make sure all file formats throw away their mutable metadata */ | ||
146 | + bdrv_activate_all(&local_err); | ||
147 | if (local_err) { | ||
148 | error_report_err(local_err); | ||
149 | goto fail; | ||
150 | @@ -XXX,XX +XXX,XX @@ static void migrate_fd_cancel(MigrationState *s) | ||
151 | if (s->state == MIGRATION_STATUS_CANCELLING && s->block_inactive) { | ||
152 | Error *local_err = NULL; | ||
153 | |||
154 | - bdrv_invalidate_cache_all(&local_err); | ||
155 | + bdrv_activate_all(&local_err); | ||
156 | if (local_err) { | ||
157 | error_report_err(local_err); | ||
158 | } else { | ||
159 | @@ -XXX,XX +XXX,XX @@ fail: | ||
160 | */ | ||
161 | Error *local_err = NULL; | ||
162 | |||
163 | - bdrv_invalidate_cache_all(&local_err); | ||
164 | + bdrv_activate_all(&local_err); | ||
165 | if (local_err) { | ||
166 | error_report_err(local_err); | ||
167 | } | ||
168 | @@ -XXX,XX +XXX,XX @@ fail_invalidate: | ||
169 | Error *local_err = NULL; | ||
170 | |||
171 | qemu_mutex_lock_iothread(); | ||
172 | - bdrv_invalidate_cache_all(&local_err); | ||
173 | + bdrv_activate_all(&local_err); | ||
174 | if (local_err) { | ||
175 | error_report_err(local_err); | ||
176 | } else { | ||
177 | diff --git a/migration/savevm.c b/migration/savevm.c | ||
178 | index XXXXXXX..XXXXXXX 100644 | ||
179 | --- a/migration/savevm.c | ||
180 | +++ b/migration/savevm.c | ||
181 | @@ -XXX,XX +XXX,XX @@ int qemu_savevm_state_complete_precopy_non_iterable(QEMUFile *f, | ||
182 | |||
183 | if (inactivate_disks) { | ||
184 | /* Inactivate before sending QEMU_VM_EOF so that the | ||
185 | - * bdrv_invalidate_cache_all() on the other end won't fail. */ | ||
186 | + * bdrv_activate_all() on the other end won't fail. */ | ||
187 | ret = bdrv_inactivate_all(); | ||
188 | if (ret) { | ||
189 | error_report("%s: bdrv_inactivate_all() failed (%d)", | ||
190 | @@ -XXX,XX +XXX,XX @@ static void loadvm_postcopy_handle_run_bh(void *opaque) | ||
191 | |||
192 | trace_loadvm_postcopy_handle_run_bh("after announce"); | ||
193 | |||
194 | - /* Make sure all file formats flush their mutable metadata. | ||
195 | + /* Make sure all file formats throw away their mutable metadata. | ||
196 | * If we get an error here, just don't restart the VM yet. */ | ||
197 | - bdrv_invalidate_cache_all(&local_err); | ||
198 | + bdrv_activate_all(&local_err); | ||
199 | if (local_err) { | ||
200 | error_report_err(local_err); | ||
201 | local_err = NULL; | ||
202 | diff --git a/monitor/qmp-cmds.c b/monitor/qmp-cmds.c | ||
203 | index XXXXXXX..XXXXXXX 100644 | ||
204 | --- a/monitor/qmp-cmds.c | ||
205 | +++ b/monitor/qmp-cmds.c | ||
206 | @@ -XXX,XX +XXX,XX @@ void qmp_cont(Error **errp) | ||
207 | * If there are no inactive block nodes (e.g. because the VM was just | ||
208 | * paused rather than completing a migration), bdrv_inactivate_all() simply | ||
209 | * doesn't do anything. */ | ||
210 | - bdrv_invalidate_cache_all(&local_err); | ||
211 | + bdrv_activate_all(&local_err); | ||
212 | if (local_err) { | ||
213 | error_propagate(errp, local_err); | ||
214 | return; | 189 | return; |
215 | diff --git a/tests/unit/test-block-iothread.c b/tests/unit/test-block-iothread.c | 190 | } |
216 | index XXXXXXX..XXXXXXX 100644 | 191 | |
217 | --- a/tests/unit/test-block-iothread.c | 192 | /* Stop things in parent-to-child order */ |
218 | +++ b/tests/unit/test-block-iothread.c | 193 | if (atomic_fetch_inc(&bs->quiesce_counter) == 0) { |
219 | @@ -XXX,XX +XXX,XX @@ static void test_sync_op_check(BdrvChild *c) | 194 | aio_disable_external(bdrv_get_aio_context(bs)); |
220 | g_assert_cmpint(ret, ==, -ENOTSUP); | 195 | - bdrv_parent_drained_begin(bs); |
221 | } | 196 | } |
222 | 197 | ||
223 | -static void test_sync_op_invalidate_cache(BdrvChild *c) | 198 | + bdrv_parent_drained_begin(bs, parent); |
224 | +static void test_sync_op_activate(BdrvChild *c) | 199 | bdrv_drain_invoke(bs, true, false); |
225 | { | 200 | bdrv_drain_recurse(bs); |
226 | /* Early success: Image is not inactive */ | 201 | } |
227 | bdrv_activate(c->bs, NULL); | 202 | |
228 | @@ -XXX,XX +XXX,XX @@ const SyncOpTest sync_op_tests[] = { | 203 | -void bdrv_drained_end(BlockDriverState *bs) |
229 | .name = "/sync-op/check", | 204 | +void bdrv_drained_begin(BlockDriverState *bs) |
230 | .fn = test_sync_op_check, | 205 | +{ |
231 | }, { | 206 | + bdrv_do_drained_begin(bs, NULL); |
232 | - .name = "/sync-op/invalidate_cache", | 207 | +} |
233 | - .fn = test_sync_op_invalidate_cache, | 208 | + |
234 | + .name = "/sync-op/activate", | 209 | +static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent) |
235 | + .fn = test_sync_op_activate, | 210 | { |
236 | }, | 211 | int old_quiesce_counter; |
237 | }; | 212 | |
238 | 213 | if (qemu_in_coroutine()) { | |
214 | - bdrv_co_yield_to_drain(bs, false); | ||
215 | + bdrv_co_yield_to_drain(bs, false, parent); | ||
216 | return; | ||
217 | } | ||
218 | assert(bs->quiesce_counter > 0); | ||
219 | @@ -XXX,XX +XXX,XX @@ void bdrv_drained_end(BlockDriverState *bs) | ||
220 | |||
221 | /* Re-enable things in child-to-parent order */ | ||
222 | bdrv_drain_invoke(bs, false, false); | ||
223 | + bdrv_parent_drained_end(bs, parent); | ||
224 | if (old_quiesce_counter == 1) { | ||
225 | - bdrv_parent_drained_end(bs); | ||
226 | aio_enable_external(bdrv_get_aio_context(bs)); | ||
227 | } | ||
228 | } | ||
229 | |||
230 | +void bdrv_drained_end(BlockDriverState *bs) | ||
231 | +{ | ||
232 | + bdrv_do_drained_end(bs, NULL); | ||
233 | +} | ||
234 | + | ||
235 | /* | ||
236 | * Wait for pending requests to complete on a single BlockDriverState subtree, | ||
237 | * and suspend block driver's internal I/O until next request arrives. | ||
238 | @@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void) | ||
239 | /* Stop things in parent-to-child order */ | ||
240 | aio_context_acquire(aio_context); | ||
241 | aio_disable_external(aio_context); | ||
242 | - bdrv_parent_drained_begin(bs); | ||
243 | + bdrv_parent_drained_begin(bs, NULL); | ||
244 | bdrv_drain_invoke(bs, true, true); | ||
245 | aio_context_release(aio_context); | ||
246 | |||
247 | @@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_end(void) | ||
248 | /* Re-enable things in child-to-parent order */ | ||
249 | aio_context_acquire(aio_context); | ||
250 | bdrv_drain_invoke(bs, false, true); | ||
251 | - bdrv_parent_drained_end(bs); | ||
252 | + bdrv_parent_drained_end(bs, NULL); | ||
253 | aio_enable_external(aio_context); | ||
254 | aio_context_release(aio_context); | ||
255 | } | ||
239 | -- | 256 | -- |
240 | 2.35.1 | 257 | 2.13.6 |
258 | |||
259 | diff view generated by jsdifflib |
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | 1 | bdrv_drained_begin() waits for the completion of requests in the whole |
---|---|---|---|
2 | subtree, but it only actually keeps its immediate bs parameter quiesced | ||
3 | until bdrv_drained_end(). | ||
2 | 4 | ||
3 | This function is currently just a wrapper for bdrv_invalidate_cache(), | 5 | Add a version that keeps the whole subtree drained. As of this commit, |
4 | but in future will contain the code of bdrv_co_invalidate_cache() that | 6 | graph changes cannot be allowed during a subtree drained section, but |
5 | has to always be protected by BQL, and leave the rest in the I/O | 7 | this will be fixed soon. |
6 | coroutine. | ||
7 | 8 | ||
8 | Replace all bdrv_invalidate_cache() invokations with bdrv_activate(). | ||
9 | |||
10 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
11 | Reviewed-by: Hanna Reitz <hreitz@redhat.com> | ||
12 | Message-Id: <20220209105452.1694545-4-eesposit@redhat.com> | ||
13 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 9 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
14 | --- | 10 | --- |
15 | include/block/block.h | 1 + | 11 | include/block/block.h | 13 +++++++++++++ |
16 | block.c | 7 ++++++- | 12 | block/io.c | 54 ++++++++++++++++++++++++++++++++++++++++----------- |
17 | block/block-backend.c | 2 +- | 13 | 2 files changed, 56 insertions(+), 11 deletions(-) |
18 | block/export/export.c | 2 +- | ||
19 | block/parallels.c | 2 +- | ||
20 | tests/unit/test-block-iothread.c | 2 +- | ||
21 | 6 files changed, 11 insertions(+), 5 deletions(-) | ||
22 | 14 | ||
23 | diff --git a/include/block/block.h b/include/block/block.h | 15 | diff --git a/include/block/block.h b/include/block/block.h |
24 | index XXXXXXX..XXXXXXX 100644 | 16 | index XXXXXXX..XXXXXXX 100644 |
25 | --- a/include/block/block.h | 17 | --- a/include/block/block.h |
26 | +++ b/include/block/block.h | 18 | +++ b/include/block/block.h |
27 | @@ -XXX,XX +XXX,XX @@ int bdrv_co_ioctl(BlockDriverState *bs, int req, void *buf); | 19 | @@ -XXX,XX +XXX,XX @@ void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore); |
28 | int generated_co_wrapper bdrv_invalidate_cache(BlockDriverState *bs, | 20 | void bdrv_drained_begin(BlockDriverState *bs); |
29 | Error **errp); | 21 | |
30 | void bdrv_invalidate_cache_all(Error **errp); | 22 | /** |
31 | +int bdrv_activate(BlockDriverState *bs, Error **errp); | 23 | + * Like bdrv_drained_begin, but recursively begins a quiesced section for |
32 | int bdrv_inactivate_all(void); | 24 | + * exclusive access to all child nodes as well. |
33 | 25 | + * | |
34 | /* Ensure contents are flushed to disk. */ | 26 | + * Graph changes are not allowed during a subtree drain section. |
35 | diff --git a/block.c b/block.c | 27 | + */ |
28 | +void bdrv_subtree_drained_begin(BlockDriverState *bs); | ||
29 | + | ||
30 | +/** | ||
31 | * bdrv_drained_end: | ||
32 | * | ||
33 | * End a quiescent section started by bdrv_drained_begin(). | ||
34 | */ | ||
35 | void bdrv_drained_end(BlockDriverState *bs); | ||
36 | |||
37 | +/** | ||
38 | + * End a quiescent section started by bdrv_subtree_drained_begin(). | ||
39 | + */ | ||
40 | +void bdrv_subtree_drained_end(BlockDriverState *bs); | ||
41 | + | ||
42 | void bdrv_add_child(BlockDriverState *parent, BlockDriverState *child, | ||
43 | Error **errp); | ||
44 | void bdrv_del_child(BlockDriverState *parent, BdrvChild *child, Error **errp); | ||
45 | diff --git a/block/io.c b/block/io.c | ||
36 | index XXXXXXX..XXXXXXX 100644 | 46 | index XXXXXXX..XXXXXXX 100644 |
37 | --- a/block.c | 47 | --- a/block/io.c |
38 | +++ b/block.c | 48 | +++ b/block/io.c |
39 | @@ -XXX,XX +XXX,XX @@ void bdrv_init_with_whitelist(void) | 49 | @@ -XXX,XX +XXX,XX @@ typedef struct { |
40 | bdrv_init(); | 50 | BlockDriverState *bs; |
51 | bool done; | ||
52 | bool begin; | ||
53 | + bool recursive; | ||
54 | BdrvChild *parent; | ||
55 | } BdrvCoDrainData; | ||
56 | |||
57 | @@ -XXX,XX +XXX,XX @@ static bool bdrv_drain_recurse(BlockDriverState *bs) | ||
58 | return waited; | ||
41 | } | 59 | } |
42 | 60 | ||
43 | +int bdrv_activate(BlockDriverState *bs, Error **errp) | 61 | -static void bdrv_do_drained_begin(BlockDriverState *bs, BdrvChild *parent); |
44 | +{ | 62 | -static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent); |
45 | + return bdrv_invalidate_cache(bs, errp); | 63 | +static void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive, |
64 | + BdrvChild *parent); | ||
65 | +static void bdrv_do_drained_end(BlockDriverState *bs, bool recursive, | ||
66 | + BdrvChild *parent); | ||
67 | |||
68 | static void bdrv_co_drain_bh_cb(void *opaque) | ||
69 | { | ||
70 | @@ -XXX,XX +XXX,XX @@ static void bdrv_co_drain_bh_cb(void *opaque) | ||
71 | |||
72 | bdrv_dec_in_flight(bs); | ||
73 | if (data->begin) { | ||
74 | - bdrv_do_drained_begin(bs, data->parent); | ||
75 | + bdrv_do_drained_begin(bs, data->recursive, data->parent); | ||
76 | } else { | ||
77 | - bdrv_do_drained_end(bs, data->parent); | ||
78 | + bdrv_do_drained_end(bs, data->recursive, data->parent); | ||
79 | } | ||
80 | |||
81 | data->done = true; | ||
82 | @@ -XXX,XX +XXX,XX @@ static void bdrv_co_drain_bh_cb(void *opaque) | ||
83 | } | ||
84 | |||
85 | static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs, | ||
86 | - bool begin, BdrvChild *parent) | ||
87 | + bool begin, bool recursive, | ||
88 | + BdrvChild *parent) | ||
89 | { | ||
90 | BdrvCoDrainData data; | ||
91 | |||
92 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs, | ||
93 | .bs = bs, | ||
94 | .done = false, | ||
95 | .begin = begin, | ||
96 | + .recursive = recursive, | ||
97 | .parent = parent, | ||
98 | }; | ||
99 | bdrv_inc_in_flight(bs); | ||
100 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs, | ||
101 | assert(data.done); | ||
102 | } | ||
103 | |||
104 | -static void bdrv_do_drained_begin(BlockDriverState *bs, BdrvChild *parent) | ||
105 | +static void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive, | ||
106 | + BdrvChild *parent) | ||
107 | { | ||
108 | + BdrvChild *child, *next; | ||
109 | + | ||
110 | if (qemu_in_coroutine()) { | ||
111 | - bdrv_co_yield_to_drain(bs, true, parent); | ||
112 | + bdrv_co_yield_to_drain(bs, true, recursive, parent); | ||
113 | return; | ||
114 | } | ||
115 | |||
116 | @@ -XXX,XX +XXX,XX @@ static void bdrv_do_drained_begin(BlockDriverState *bs, BdrvChild *parent) | ||
117 | bdrv_parent_drained_begin(bs, parent); | ||
118 | bdrv_drain_invoke(bs, true, false); | ||
119 | bdrv_drain_recurse(bs); | ||
120 | + | ||
121 | + if (recursive) { | ||
122 | + QLIST_FOREACH_SAFE(child, &bs->children, next, next) { | ||
123 | + bdrv_do_drained_begin(child->bs, true, child); | ||
124 | + } | ||
125 | + } | ||
126 | } | ||
127 | |||
128 | void bdrv_drained_begin(BlockDriverState *bs) | ||
129 | { | ||
130 | - bdrv_do_drained_begin(bs, NULL); | ||
131 | + bdrv_do_drained_begin(bs, false, NULL); | ||
46 | +} | 132 | +} |
47 | + | 133 | + |
48 | int coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs, Error **errp) | 134 | +void bdrv_subtree_drained_begin(BlockDriverState *bs) |
135 | +{ | ||
136 | + bdrv_do_drained_begin(bs, true, NULL); | ||
137 | } | ||
138 | |||
139 | -static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent) | ||
140 | +static void bdrv_do_drained_end(BlockDriverState *bs, bool recursive, | ||
141 | + BdrvChild *parent) | ||
49 | { | 142 | { |
50 | BdrvChild *child, *parent; | 143 | + BdrvChild *child, *next; |
51 | @@ -XXX,XX +XXX,XX @@ void bdrv_invalidate_cache_all(Error **errp) | 144 | int old_quiesce_counter; |
52 | int ret; | 145 | |
53 | 146 | if (qemu_in_coroutine()) { | |
54 | aio_context_acquire(aio_context); | 147 | - bdrv_co_yield_to_drain(bs, false, parent); |
55 | - ret = bdrv_invalidate_cache(bs, errp); | 148 | + bdrv_co_yield_to_drain(bs, false, recursive, parent); |
56 | + ret = bdrv_activate(bs, errp); | ||
57 | aio_context_release(aio_context); | ||
58 | if (ret < 0) { | ||
59 | bdrv_next_cleanup(&it); | ||
60 | diff --git a/block/block-backend.c b/block/block-backend.c | ||
61 | index XXXXXXX..XXXXXXX 100644 | ||
62 | --- a/block/block-backend.c | ||
63 | +++ b/block/block-backend.c | ||
64 | @@ -XXX,XX +XXX,XX @@ void blk_invalidate_cache(BlockBackend *blk, Error **errp) | ||
65 | return; | 149 | return; |
66 | } | 150 | } |
67 | 151 | assert(bs->quiesce_counter > 0); | |
68 | - bdrv_invalidate_cache(bs, errp); | 152 | @@ -XXX,XX +XXX,XX @@ static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent) |
69 | + bdrv_activate(bs, errp); | 153 | if (old_quiesce_counter == 1) { |
154 | aio_enable_external(bdrv_get_aio_context(bs)); | ||
155 | } | ||
156 | + | ||
157 | + if (recursive) { | ||
158 | + QLIST_FOREACH_SAFE(child, &bs->children, next, next) { | ||
159 | + bdrv_do_drained_end(child->bs, true, child); | ||
160 | + } | ||
161 | + } | ||
70 | } | 162 | } |
71 | 163 | ||
72 | bool blk_is_inserted(BlockBackend *blk) | 164 | void bdrv_drained_end(BlockDriverState *bs) |
73 | diff --git a/block/export/export.c b/block/export/export.c | ||
74 | index XXXXXXX..XXXXXXX 100644 | ||
75 | --- a/block/export/export.c | ||
76 | +++ b/block/export/export.c | ||
77 | @@ -XXX,XX +XXX,XX @@ BlockExport *blk_exp_add(BlockExportOptions *export, Error **errp) | ||
78 | * access since the export could be available before migration handover. | ||
79 | * ctx was acquired in the caller. | ||
80 | */ | ||
81 | - bdrv_invalidate_cache(bs, NULL); | ||
82 | + bdrv_activate(bs, NULL); | ||
83 | |||
84 | perm = BLK_PERM_CONSISTENT_READ; | ||
85 | if (export->writable) { | ||
86 | diff --git a/block/parallels.c b/block/parallels.c | ||
87 | index XXXXXXX..XXXXXXX 100644 | ||
88 | --- a/block/parallels.c | ||
89 | +++ b/block/parallels.c | ||
90 | @@ -XXX,XX +XXX,XX @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags, | ||
91 | s->bat_dirty_bmap = | ||
92 | bitmap_new(DIV_ROUND_UP(s->header_size, s->bat_dirty_block)); | ||
93 | |||
94 | - /* Disable migration until bdrv_invalidate_cache method is added */ | ||
95 | + /* Disable migration until bdrv_activate method is added */ | ||
96 | error_setg(&s->migration_blocker, "The Parallels format used by node '%s' " | ||
97 | "does not support live migration", | ||
98 | bdrv_get_device_or_node_name(bs)); | ||
99 | diff --git a/tests/unit/test-block-iothread.c b/tests/unit/test-block-iothread.c | ||
100 | index XXXXXXX..XXXXXXX 100644 | ||
101 | --- a/tests/unit/test-block-iothread.c | ||
102 | +++ b/tests/unit/test-block-iothread.c | ||
103 | @@ -XXX,XX +XXX,XX @@ static void test_sync_op_check(BdrvChild *c) | ||
104 | static void test_sync_op_invalidate_cache(BdrvChild *c) | ||
105 | { | 165 | { |
106 | /* Early success: Image is not inactive */ | 166 | - bdrv_do_drained_end(bs, NULL); |
107 | - bdrv_invalidate_cache(c->bs, NULL); | 167 | + bdrv_do_drained_end(bs, false, NULL); |
108 | + bdrv_activate(c->bs, NULL); | 168 | +} |
169 | + | ||
170 | +void bdrv_subtree_drained_end(BlockDriverState *bs) | ||
171 | +{ | ||
172 | + bdrv_do_drained_end(bs, true, NULL); | ||
109 | } | 173 | } |
110 | 174 | ||
111 | 175 | /* | |
112 | -- | 176 | -- |
113 | 2.35.1 | 177 | 2.13.6 |
178 | |||
179 | diff view generated by jsdifflib |
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | 1 | Add a subtree drain version to the existing test cases. |
---|---|---|---|
2 | 2 | ||
3 | When invoked from the main loop, this function is the same | ||
4 | as qemu_mutex_iothread_locked, and returns true if the BQL is held. | ||
5 | When invoked from iothreads or tests, it returns true only | ||
6 | if the current AioContext is the Main Loop. | ||
7 | |||
8 | This essentially just extends qemu_mutex_iothread_locked to work | ||
9 | also in unit tests or other users like storage-daemon, that run | ||
10 | in the Main Loop but end up using the implementation in | ||
11 | stubs/iothread-lock.c. | ||
12 | |||
13 | Using qemu_mutex_iothread_locked in unit tests defaults to false | ||
14 | because they use the implementation in stubs/iothread-lock, | ||
15 | making all assertions added in next patches fail despite the | ||
16 | AioContext is still the main loop. | ||
17 | |||
18 | See the comment in the function header for more information. | ||
19 | |||
20 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
21 | Message-Id: <20220303151616.325444-2-eesposit@redhat.com> | ||
22 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 3 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
23 | --- | 4 | --- |
24 | include/qemu/main-loop.h | 24 ++++++++++++++++++++++++ | 5 | tests/test-bdrv-drain.c | 27 ++++++++++++++++++++++++++- |
25 | softmmu/cpus.c | 5 +++++ | 6 | 1 file changed, 26 insertions(+), 1 deletion(-) |
26 | stubs/iothread-lock.c | 5 +++++ | ||
27 | 3 files changed, 34 insertions(+) | ||
28 | 7 | ||
29 | diff --git a/include/qemu/main-loop.h b/include/qemu/main-loop.h | 8 | diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c |
30 | index XXXXXXX..XXXXXXX 100644 | 9 | index XXXXXXX..XXXXXXX 100644 |
31 | --- a/include/qemu/main-loop.h | 10 | --- a/tests/test-bdrv-drain.c |
32 | +++ b/include/qemu/main-loop.h | 11 | +++ b/tests/test-bdrv-drain.c |
33 | @@ -XXX,XX +XXX,XX @@ AioContext *iohandler_get_aio_context(void); | 12 | @@ -XXX,XX +XXX,XX @@ static void aio_ret_cb(void *opaque, int ret) |
34 | * must always be taken outside other locks. This function helps | 13 | enum drain_type { |
35 | * functions take different paths depending on whether the current | 14 | BDRV_DRAIN_ALL, |
36 | * thread is running within the main loop mutex. | 15 | BDRV_DRAIN, |
37 | + * | 16 | + BDRV_SUBTREE_DRAIN, |
38 | + * This function should never be used in the block layer, because | 17 | DRAIN_TYPE_MAX, |
39 | + * unit tests, block layer tools and qemu-storage-daemon do not | 18 | }; |
40 | + * have a BQL. | 19 | |
41 | + * Please instead refer to qemu_in_main_thread(). | 20 | @@ -XXX,XX +XXX,XX @@ static void do_drain_begin(enum drain_type drain_type, BlockDriverState *bs) |
42 | */ | 21 | switch (drain_type) { |
43 | bool qemu_mutex_iothread_locked(void); | 22 | case BDRV_DRAIN_ALL: bdrv_drain_all_begin(); break; |
44 | 23 | case BDRV_DRAIN: bdrv_drained_begin(bs); break; | |
45 | +/** | 24 | + case BDRV_SUBTREE_DRAIN: bdrv_subtree_drained_begin(bs); break; |
46 | + * qemu_in_main_thread: return whether it's possible to safely access | 25 | default: g_assert_not_reached(); |
47 | + * the global state of the block layer. | 26 | } |
48 | + * | ||
49 | + * Global state of the block layer is not accessible from I/O threads | ||
50 | + * or worker threads; only from threads that "own" the default | ||
51 | + * AioContext that qemu_get_aio_context() returns. For tests, block | ||
52 | + * layer tools and qemu-storage-daemon there is a designated thread that | ||
53 | + * runs the event loop for qemu_get_aio_context(), and that is the | ||
54 | + * main thread. | ||
55 | + * | ||
56 | + * For emulators, however, any thread that holds the BQL can act | ||
57 | + * as the block layer main thread; this will be any of the actual | ||
58 | + * main thread, the vCPU threads or the RCU thread. | ||
59 | + * | ||
60 | + * For clarity, do not use this function outside the block layer. | ||
61 | + */ | ||
62 | +bool qemu_in_main_thread(void); | ||
63 | + | ||
64 | /** | ||
65 | * qemu_mutex_lock_iothread: Lock the main loop mutex. | ||
66 | * | ||
67 | diff --git a/softmmu/cpus.c b/softmmu/cpus.c | ||
68 | index XXXXXXX..XXXXXXX 100644 | ||
69 | --- a/softmmu/cpus.c | ||
70 | +++ b/softmmu/cpus.c | ||
71 | @@ -XXX,XX +XXX,XX @@ bool qemu_mutex_iothread_locked(void) | ||
72 | return get_iothread_locked(); | ||
73 | } | 27 | } |
74 | 28 | @@ -XXX,XX +XXX,XX @@ static void do_drain_end(enum drain_type drain_type, BlockDriverState *bs) | |
75 | +bool qemu_in_main_thread(void) | 29 | switch (drain_type) { |
30 | case BDRV_DRAIN_ALL: bdrv_drain_all_end(); break; | ||
31 | case BDRV_DRAIN: bdrv_drained_end(bs); break; | ||
32 | + case BDRV_SUBTREE_DRAIN: bdrv_subtree_drained_end(bs); break; | ||
33 | default: g_assert_not_reached(); | ||
34 | } | ||
35 | } | ||
36 | @@ -XXX,XX +XXX,XX @@ static void test_drv_cb_drain(void) | ||
37 | test_drv_cb_common(BDRV_DRAIN, false); | ||
38 | } | ||
39 | |||
40 | +static void test_drv_cb_drain_subtree(void) | ||
76 | +{ | 41 | +{ |
77 | + return qemu_mutex_iothread_locked(); | 42 | + test_drv_cb_common(BDRV_SUBTREE_DRAIN, true); |
78 | +} | 43 | +} |
79 | + | 44 | + |
80 | /* | 45 | static void test_quiesce_common(enum drain_type drain_type, bool recursive) |
81 | * The BQL is taken from so many places that it is worth profiling the | 46 | { |
82 | * callers directly, instead of funneling them all through a single function. | 47 | BlockBackend *blk; |
83 | diff --git a/stubs/iothread-lock.c b/stubs/iothread-lock.c | 48 | @@ -XXX,XX +XXX,XX @@ static void test_quiesce_drain(void) |
84 | index XXXXXXX..XXXXXXX 100644 | 49 | test_quiesce_common(BDRV_DRAIN, false); |
85 | --- a/stubs/iothread-lock.c | ||
86 | +++ b/stubs/iothread-lock.c | ||
87 | @@ -XXX,XX +XXX,XX @@ bool qemu_mutex_iothread_locked(void) | ||
88 | return false; | ||
89 | } | 50 | } |
90 | 51 | ||
91 | +bool qemu_in_main_thread(void) | 52 | +static void test_quiesce_drain_subtree(void) |
92 | +{ | 53 | +{ |
93 | + return qemu_get_current_aio_context() == qemu_get_aio_context(); | 54 | + test_quiesce_common(BDRV_SUBTREE_DRAIN, true); |
94 | +} | 55 | +} |
95 | + | 56 | + |
96 | void qemu_mutex_lock_iothread_impl(const char *file, int line) | 57 | static void test_nested(void) |
97 | { | 58 | { |
59 | BlockBackend *blk; | ||
60 | @@ -XXX,XX +XXX,XX @@ static void test_nested(void) | ||
61 | /* XXX bdrv_drain_all() doesn't increase the quiesce_counter */ | ||
62 | int bs_quiesce = (outer != BDRV_DRAIN_ALL) + | ||
63 | (inner != BDRV_DRAIN_ALL); | ||
64 | - int backing_quiesce = 0; | ||
65 | + int backing_quiesce = (outer == BDRV_SUBTREE_DRAIN) + | ||
66 | + (inner == BDRV_SUBTREE_DRAIN); | ||
67 | int backing_cb_cnt = (outer != BDRV_DRAIN) + | ||
68 | (inner != BDRV_DRAIN); | ||
69 | |||
70 | @@ -XXX,XX +XXX,XX @@ static void test_blockjob_drain(void) | ||
71 | test_blockjob_common(BDRV_DRAIN); | ||
72 | } | ||
73 | |||
74 | +static void test_blockjob_drain_subtree(void) | ||
75 | +{ | ||
76 | + test_blockjob_common(BDRV_SUBTREE_DRAIN); | ||
77 | +} | ||
78 | + | ||
79 | int main(int argc, char **argv) | ||
80 | { | ||
81 | bdrv_init(); | ||
82 | @@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv) | ||
83 | |||
84 | g_test_add_func("/bdrv-drain/driver-cb/drain_all", test_drv_cb_drain_all); | ||
85 | g_test_add_func("/bdrv-drain/driver-cb/drain", test_drv_cb_drain); | ||
86 | + g_test_add_func("/bdrv-drain/driver-cb/drain_subtree", | ||
87 | + test_drv_cb_drain_subtree); | ||
88 | |||
89 | g_test_add_func("/bdrv-drain/quiesce/drain_all", test_quiesce_drain_all); | ||
90 | g_test_add_func("/bdrv-drain/quiesce/drain", test_quiesce_drain); | ||
91 | + g_test_add_func("/bdrv-drain/quiesce/drain_subtree", | ||
92 | + test_quiesce_drain_subtree); | ||
93 | |||
94 | g_test_add_func("/bdrv-drain/nested", test_nested); | ||
95 | |||
96 | g_test_add_func("/bdrv-drain/blockjob/drain_all", test_blockjob_drain_all); | ||
97 | g_test_add_func("/bdrv-drain/blockjob/drain", test_blockjob_drain); | ||
98 | + g_test_add_func("/bdrv-drain/blockjob/drain_subtree", | ||
99 | + test_blockjob_drain_subtree); | ||
100 | |||
101 | return g_test_run(); | ||
98 | } | 102 | } |
99 | -- | 103 | -- |
100 | 2.35.1 | 104 | 2.13.6 |
105 | |||
106 | diff view generated by jsdifflib |
1 | From: Hanna Reitz <hreitz@redhat.com> | 1 | If bdrv_do_drained_begin/end() are called in coroutine context, they |
---|---|---|---|
2 | first use a BH to get out of the coroutine context. Call some existing | ||
3 | tests again from a coroutine to cover this code path. | ||
2 | 4 | ||
3 | The daemonizing functions in os-posix (os_daemonize() and | ||
4 | os_setup_post()) only daemonize the process if the static `daemonize` | ||
5 | variable is set. Right now, it can only be set by os_parse_cmd_args(). | ||
6 | |||
7 | In order to use os_daemonize() and os_setup_post() from the storage | ||
8 | daemon to have it be daemonized, we need some other way to set this | ||
9 | `daemonize` variable, because I would rather not tap into the system | ||
10 | emulator's arg-parsing code. Therefore, this patch adds an | ||
11 | os_set_daemonize() function, which will return an error on os-win32 | ||
12 | (because daemonizing is not supported there). | ||
13 | |||
14 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
15 | Message-Id: <20220303164814.284974-2-hreitz@redhat.com> | ||
16 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 5 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
17 | --- | 6 | --- |
18 | include/sysemu/os-posix.h | 1 + | 7 | tests/test-bdrv-drain.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++ |
19 | include/sysemu/os-win32.h | 8 ++++++++ | 8 | 1 file changed, 59 insertions(+) |
20 | os-posix.c | 6 ++++++ | ||
21 | 3 files changed, 15 insertions(+) | ||
22 | 9 | ||
23 | diff --git a/include/sysemu/os-posix.h b/include/sysemu/os-posix.h | 10 | diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c |
24 | index XXXXXXX..XXXXXXX 100644 | 11 | index XXXXXXX..XXXXXXX 100644 |
25 | --- a/include/sysemu/os-posix.h | 12 | --- a/tests/test-bdrv-drain.c |
26 | +++ b/include/sysemu/os-posix.h | 13 | +++ b/tests/test-bdrv-drain.c |
27 | @@ -XXX,XX +XXX,XX @@ int os_mlock(void); | 14 | @@ -XXX,XX +XXX,XX @@ static void aio_ret_cb(void *opaque, int ret) |
28 | typedef struct timeval qemu_timeval; | 15 | *aio_ret = ret; |
29 | #define qemu_gettimeofday(tp) gettimeofday(tp, NULL) | 16 | } |
30 | 17 | ||
31 | +int os_set_daemonize(bool d); | 18 | +typedef struct CallInCoroutineData { |
32 | bool is_daemonized(void); | 19 | + void (*entry)(void); |
33 | 20 | + bool done; | |
34 | /** | 21 | +} CallInCoroutineData; |
35 | diff --git a/include/sysemu/os-win32.h b/include/sysemu/os-win32.h | 22 | + |
36 | index XXXXXXX..XXXXXXX 100644 | 23 | +static coroutine_fn void call_in_coroutine_entry(void *opaque) |
37 | --- a/include/sysemu/os-win32.h | ||
38 | +++ b/include/sysemu/os-win32.h | ||
39 | @@ -XXX,XX +XXX,XX @@ typedef struct { | ||
40 | } qemu_timeval; | ||
41 | int qemu_gettimeofday(qemu_timeval *tp); | ||
42 | |||
43 | +static inline int os_set_daemonize(bool d) | ||
44 | +{ | 24 | +{ |
45 | + if (d) { | 25 | + CallInCoroutineData *data = opaque; |
46 | + return -ENOTSUP; | 26 | + |
47 | + } | 27 | + data->entry(); |
48 | + return 0; | 28 | + data->done = true; |
49 | +} | 29 | +} |
50 | + | 30 | + |
51 | static inline bool is_daemonized(void) | 31 | +static void call_in_coroutine(void (*entry)(void)) |
52 | { | ||
53 | return false; | ||
54 | diff --git a/os-posix.c b/os-posix.c | ||
55 | index XXXXXXX..XXXXXXX 100644 | ||
56 | --- a/os-posix.c | ||
57 | +++ b/os-posix.c | ||
58 | @@ -XXX,XX +XXX,XX @@ bool is_daemonized(void) | ||
59 | return daemonize; | ||
60 | } | ||
61 | |||
62 | +int os_set_daemonize(bool d) | ||
63 | +{ | 32 | +{ |
64 | + daemonize = d; | 33 | + Coroutine *co; |
65 | + return 0; | 34 | + CallInCoroutineData data = { |
35 | + .entry = entry, | ||
36 | + .done = false, | ||
37 | + }; | ||
38 | + | ||
39 | + co = qemu_coroutine_create(call_in_coroutine_entry, &data); | ||
40 | + qemu_coroutine_enter(co); | ||
41 | + while (!data.done) { | ||
42 | + aio_poll(qemu_get_aio_context(), true); | ||
43 | + } | ||
66 | +} | 44 | +} |
67 | + | 45 | + |
68 | int os_mlock(void) | 46 | enum drain_type { |
47 | BDRV_DRAIN_ALL, | ||
48 | BDRV_DRAIN, | ||
49 | @@ -XXX,XX +XXX,XX @@ static void test_drv_cb_drain_subtree(void) | ||
50 | test_drv_cb_common(BDRV_SUBTREE_DRAIN, true); | ||
51 | } | ||
52 | |||
53 | +static void test_drv_cb_co_drain(void) | ||
54 | +{ | ||
55 | + call_in_coroutine(test_drv_cb_drain); | ||
56 | +} | ||
57 | + | ||
58 | +static void test_drv_cb_co_drain_subtree(void) | ||
59 | +{ | ||
60 | + call_in_coroutine(test_drv_cb_drain_subtree); | ||
61 | +} | ||
62 | + | ||
63 | static void test_quiesce_common(enum drain_type drain_type, bool recursive) | ||
69 | { | 64 | { |
70 | #ifdef HAVE_MLOCKALL | 65 | BlockBackend *blk; |
66 | @@ -XXX,XX +XXX,XX @@ static void test_quiesce_drain_subtree(void) | ||
67 | test_quiesce_common(BDRV_SUBTREE_DRAIN, true); | ||
68 | } | ||
69 | |||
70 | +static void test_quiesce_co_drain(void) | ||
71 | +{ | ||
72 | + call_in_coroutine(test_quiesce_drain); | ||
73 | +} | ||
74 | + | ||
75 | +static void test_quiesce_co_drain_subtree(void) | ||
76 | +{ | ||
77 | + call_in_coroutine(test_quiesce_drain_subtree); | ||
78 | +} | ||
79 | + | ||
80 | static void test_nested(void) | ||
81 | { | ||
82 | BlockBackend *blk; | ||
83 | @@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv) | ||
84 | g_test_add_func("/bdrv-drain/driver-cb/drain_subtree", | ||
85 | test_drv_cb_drain_subtree); | ||
86 | |||
87 | + // XXX bdrv_drain_all() doesn't work in coroutine context | ||
88 | + g_test_add_func("/bdrv-drain/driver-cb/co/drain", test_drv_cb_co_drain); | ||
89 | + g_test_add_func("/bdrv-drain/driver-cb/co/drain_subtree", | ||
90 | + test_drv_cb_co_drain_subtree); | ||
91 | + | ||
92 | + | ||
93 | g_test_add_func("/bdrv-drain/quiesce/drain_all", test_quiesce_drain_all); | ||
94 | g_test_add_func("/bdrv-drain/quiesce/drain", test_quiesce_drain); | ||
95 | g_test_add_func("/bdrv-drain/quiesce/drain_subtree", | ||
96 | test_quiesce_drain_subtree); | ||
97 | |||
98 | + // XXX bdrv_drain_all() doesn't work in coroutine context | ||
99 | + g_test_add_func("/bdrv-drain/quiesce/co/drain", test_quiesce_co_drain); | ||
100 | + g_test_add_func("/bdrv-drain/quiesce/co/drain_subtree", | ||
101 | + test_quiesce_co_drain_subtree); | ||
102 | + | ||
103 | g_test_add_func("/bdrv-drain/nested", test_nested); | ||
104 | |||
105 | g_test_add_func("/bdrv-drain/blockjob/drain_all", test_blockjob_drain_all); | ||
71 | -- | 106 | -- |
72 | 2.35.1 | 107 | 2.13.6 |
108 | |||
109 | diff view generated by jsdifflib |
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | 1 | Test that drain sections are correctly propagated through the graph. |
---|---|---|---|
2 | 2 | ||
3 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
4 | Message-Id: <20220303151616.325444-17-eesposit@redhat.com> | ||
5 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 3 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
6 | --- | 4 | --- |
7 | blockjob.c | 5 +++++ | 5 | tests/test-bdrv-drain.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++ |
8 | 1 file changed, 5 insertions(+) | 6 | 1 file changed, 74 insertions(+) |
9 | 7 | ||
10 | diff --git a/blockjob.c b/blockjob.c | 8 | diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c |
11 | index XXXXXXX..XXXXXXX 100644 | 9 | index XXXXXXX..XXXXXXX 100644 |
12 | --- a/blockjob.c | 10 | --- a/tests/test-bdrv-drain.c |
13 | +++ b/blockjob.c | 11 | +++ b/tests/test-bdrv-drain.c |
14 | @@ -XXX,XX +XXX,XX @@ BlockJob *block_job_get(const char *id) | 12 | @@ -XXX,XX +XXX,XX @@ static void test_nested(void) |
15 | void block_job_free(Job *job) | 13 | blk_unref(blk); |
16 | { | ||
17 | BlockJob *bjob = container_of(job, BlockJob, job); | ||
18 | + GLOBAL_STATE_CODE(); | ||
19 | |||
20 | block_job_remove_all_bdrv(bjob); | ||
21 | ratelimit_destroy(&bjob->limit); | ||
22 | @@ -XXX,XX +XXX,XX @@ bool block_job_set_speed(BlockJob *job, int64_t speed, Error **errp) | ||
23 | |||
24 | int64_t block_job_ratelimit_get_delay(BlockJob *job, uint64_t n) | ||
25 | { | ||
26 | + IO_CODE(); | ||
27 | return ratelimit_calculate_delay(&job->limit, n); | ||
28 | } | 14 | } |
29 | 15 | ||
30 | @@ -XXX,XX +XXX,XX @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver, | 16 | +static void test_multiparent(void) |
31 | { | 17 | +{ |
32 | BlockJob *job; | 18 | + BlockBackend *blk_a, *blk_b; |
33 | int ret; | 19 | + BlockDriverState *bs_a, *bs_b, *backing; |
34 | + GLOBAL_STATE_CODE(); | 20 | + BDRVTestState *a_s, *b_s, *backing_s; |
35 | 21 | + | |
36 | if (job_id == NULL && !(flags & JOB_INTERNAL)) { | 22 | + blk_a = blk_new(BLK_PERM_ALL, BLK_PERM_ALL); |
37 | job_id = bdrv_get_device_name(bs); | 23 | + bs_a = bdrv_new_open_driver(&bdrv_test, "test-node-a", BDRV_O_RDWR, |
38 | @@ -XXX,XX +XXX,XX @@ void block_job_iostatus_reset(BlockJob *job) | 24 | + &error_abort); |
39 | void block_job_user_resume(Job *job) | 25 | + a_s = bs_a->opaque; |
40 | { | 26 | + blk_insert_bs(blk_a, bs_a, &error_abort); |
41 | BlockJob *bjob = container_of(job, BlockJob, job); | 27 | + |
42 | + GLOBAL_STATE_CODE(); | 28 | + blk_b = blk_new(BLK_PERM_ALL, BLK_PERM_ALL); |
43 | block_job_iostatus_reset(bjob); | 29 | + bs_b = bdrv_new_open_driver(&bdrv_test, "test-node-b", BDRV_O_RDWR, |
44 | } | 30 | + &error_abort); |
45 | 31 | + b_s = bs_b->opaque; | |
46 | @@ -XXX,XX +XXX,XX @@ BlockErrorAction block_job_error_action(BlockJob *job, BlockdevOnError on_err, | 32 | + blk_insert_bs(blk_b, bs_b, &error_abort); |
47 | int is_read, int error) | 33 | + |
48 | { | 34 | + backing = bdrv_new_open_driver(&bdrv_test, "backing", 0, &error_abort); |
49 | BlockErrorAction action; | 35 | + backing_s = backing->opaque; |
50 | + IO_CODE(); | 36 | + bdrv_set_backing_hd(bs_a, backing, &error_abort); |
51 | 37 | + bdrv_set_backing_hd(bs_b, backing, &error_abort); | |
52 | switch (on_err) { | 38 | + |
53 | case BLOCKDEV_ON_ERROR_ENOSPC: | 39 | + g_assert_cmpint(bs_a->quiesce_counter, ==, 0); |
40 | + g_assert_cmpint(bs_b->quiesce_counter, ==, 0); | ||
41 | + g_assert_cmpint(backing->quiesce_counter, ==, 0); | ||
42 | + g_assert_cmpint(a_s->drain_count, ==, 0); | ||
43 | + g_assert_cmpint(b_s->drain_count, ==, 0); | ||
44 | + g_assert_cmpint(backing_s->drain_count, ==, 0); | ||
45 | + | ||
46 | + do_drain_begin(BDRV_SUBTREE_DRAIN, bs_a); | ||
47 | + | ||
48 | + g_assert_cmpint(bs_a->quiesce_counter, ==, 1); | ||
49 | + g_assert_cmpint(bs_b->quiesce_counter, ==, 1); | ||
50 | + g_assert_cmpint(backing->quiesce_counter, ==, 1); | ||
51 | + g_assert_cmpint(a_s->drain_count, ==, 1); | ||
52 | + g_assert_cmpint(b_s->drain_count, ==, 1); | ||
53 | + g_assert_cmpint(backing_s->drain_count, ==, 1); | ||
54 | + | ||
55 | + do_drain_begin(BDRV_SUBTREE_DRAIN, bs_b); | ||
56 | + | ||
57 | + g_assert_cmpint(bs_a->quiesce_counter, ==, 2); | ||
58 | + g_assert_cmpint(bs_b->quiesce_counter, ==, 2); | ||
59 | + g_assert_cmpint(backing->quiesce_counter, ==, 2); | ||
60 | + g_assert_cmpint(a_s->drain_count, ==, 2); | ||
61 | + g_assert_cmpint(b_s->drain_count, ==, 2); | ||
62 | + g_assert_cmpint(backing_s->drain_count, ==, 2); | ||
63 | + | ||
64 | + do_drain_end(BDRV_SUBTREE_DRAIN, bs_b); | ||
65 | + | ||
66 | + g_assert_cmpint(bs_a->quiesce_counter, ==, 1); | ||
67 | + g_assert_cmpint(bs_b->quiesce_counter, ==, 1); | ||
68 | + g_assert_cmpint(backing->quiesce_counter, ==, 1); | ||
69 | + g_assert_cmpint(a_s->drain_count, ==, 1); | ||
70 | + g_assert_cmpint(b_s->drain_count, ==, 1); | ||
71 | + g_assert_cmpint(backing_s->drain_count, ==, 1); | ||
72 | + | ||
73 | + do_drain_end(BDRV_SUBTREE_DRAIN, bs_a); | ||
74 | + | ||
75 | + g_assert_cmpint(bs_a->quiesce_counter, ==, 0); | ||
76 | + g_assert_cmpint(bs_b->quiesce_counter, ==, 0); | ||
77 | + g_assert_cmpint(backing->quiesce_counter, ==, 0); | ||
78 | + g_assert_cmpint(a_s->drain_count, ==, 0); | ||
79 | + g_assert_cmpint(b_s->drain_count, ==, 0); | ||
80 | + g_assert_cmpint(backing_s->drain_count, ==, 0); | ||
81 | + | ||
82 | + bdrv_unref(backing); | ||
83 | + bdrv_unref(bs_a); | ||
84 | + bdrv_unref(bs_b); | ||
85 | + blk_unref(blk_a); | ||
86 | + blk_unref(blk_b); | ||
87 | +} | ||
88 | + | ||
89 | |||
90 | typedef struct TestBlockJob { | ||
91 | BlockJob common; | ||
92 | @@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv) | ||
93 | test_quiesce_co_drain_subtree); | ||
94 | |||
95 | g_test_add_func("/bdrv-drain/nested", test_nested); | ||
96 | + g_test_add_func("/bdrv-drain/multiparent", test_multiparent); | ||
97 | |||
98 | g_test_add_func("/bdrv-drain/blockjob/drain_all", test_blockjob_drain_all); | ||
99 | g_test_add_func("/bdrv-drain/blockjob/drain", test_blockjob_drain); | ||
54 | -- | 100 | -- |
55 | 2.35.1 | 101 | 2.13.6 |
102 | |||
103 | diff view generated by jsdifflib |
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | 1 | We need to remember how many of the drain sections in which a node is |
---|---|---|---|
2 | 2 | were recursive (i.e. subtree drain rather than node drain), so that they | |
3 | We want to be sure that the functions that write the child and | 3 | can be correctly applied when children are added or removed during the |
4 | parent list of a bs are under BQL and drain. | 4 | drained section. |
5 | 5 | ||
6 | BQL prevents from concurrent writings from the GS API, while | 6 | With this change, it is safe to modify the graph even inside a |
7 | drains protect from I/O. | 7 | bdrv_subtree_drained_begin/end() section. |
8 | 8 | ||
9 | TODO: drains are missing in some functions using this assert. | ||
10 | Therefore a proper assertion will fail. Because adding drains | ||
11 | requires additional discussions, they will be added in future | ||
12 | series. | ||
13 | |||
14 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
15 | Message-Id: <20220303151616.325444-15-eesposit@redhat.com> | ||
16 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 9 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
17 | --- | 10 | --- |
18 | include/block/block_int-global-state.h | 17 +++++++++++++++++ | 11 | include/block/block.h | 2 -- |
19 | block.c | 4 ++++ | 12 | include/block/block_int.h | 5 +++++ |
20 | 2 files changed, 21 insertions(+) | 13 | block.c | 32 +++++++++++++++++++++++++++++--- |
21 | 14 | block/io.c | 28 ++++++++++++++++++++++++---- | |
22 | diff --git a/include/block/block_int-global-state.h b/include/block/block_int-global-state.h | 15 | 4 files changed, 58 insertions(+), 9 deletions(-) |
23 | index XXXXXXX..XXXXXXX 100644 | 16 | |
24 | --- a/include/block/block_int-global-state.h | 17 | diff --git a/include/block/block.h b/include/block/block.h |
25 | +++ b/include/block/block_int-global-state.h | 18 | index XXXXXXX..XXXXXXX 100644 |
26 | @@ -XXX,XX +XXX,XX @@ void bdrv_remove_aio_context_notifier(BlockDriverState *bs, | 19 | --- a/include/block/block.h |
20 | +++ b/include/block/block.h | ||
21 | @@ -XXX,XX +XXX,XX @@ void bdrv_drained_begin(BlockDriverState *bs); | ||
22 | /** | ||
23 | * Like bdrv_drained_begin, but recursively begins a quiesced section for | ||
24 | * exclusive access to all child nodes as well. | ||
25 | - * | ||
26 | - * Graph changes are not allowed during a subtree drain section. | ||
27 | */ | 27 | */ |
28 | void bdrv_drain_all_end_quiesce(BlockDriverState *bs); | 28 | void bdrv_subtree_drained_begin(BlockDriverState *bs); |
29 | 29 | ||
30 | +/** | 30 | diff --git a/include/block/block_int.h b/include/block/block_int.h |
31 | + * Make sure that the function is running under both drain and BQL. | 31 | index XXXXXXX..XXXXXXX 100644 |
32 | + * The latter protects from concurrent writings | 32 | --- a/include/block/block_int.h |
33 | + * from the GS API, while the former prevents concurrent reads | 33 | +++ b/include/block/block_int.h |
34 | + * from I/O. | 34 | @@ -XXX,XX +XXX,XX @@ struct BlockDriverState { |
35 | + */ | 35 | |
36 | +static inline void assert_bdrv_graph_writable(BlockDriverState *bs) | 36 | /* Accessed with atomic ops. */ |
37 | +{ | 37 | int quiesce_counter; |
38 | + /* | 38 | + int recursive_quiesce_counter; |
39 | + * TODO: this function is incomplete. Because the users of this | 39 | + |
40 | + * assert lack the necessary drains, check only for BQL. | 40 | unsigned int write_gen; /* Current data generation */ |
41 | + * Once the necessary drains are added, | 41 | |
42 | + * assert also for qatomic_read(&bs->quiesce_counter) > 0 | 42 | /* Protected by reqs_lock. */ |
43 | + */ | 43 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_pwritev(BdrvChild *child, |
44 | + assert(qemu_in_main_thread()); | 44 | int64_t offset, unsigned int bytes, QEMUIOVector *qiov, |
45 | +} | 45 | BdrvRequestFlags flags); |
46 | + | 46 | |
47 | #endif /* BLOCK_INT_GLOBAL_STATE */ | 47 | +void bdrv_apply_subtree_drain(BdrvChild *child, BlockDriverState *new_parent); |
48 | +void bdrv_unapply_subtree_drain(BdrvChild *child, BlockDriverState *old_parent); | ||
49 | + | ||
50 | int get_tmp_filename(char *filename, int size); | ||
51 | BlockDriver *bdrv_probe_all(const uint8_t *buf, int buf_size, | ||
52 | const char *filename); | ||
48 | diff --git a/block.c b/block.c | 53 | diff --git a/block.c b/block.c |
49 | index XXXXXXX..XXXXXXX 100644 | 54 | index XXXXXXX..XXXXXXX 100644 |
50 | --- a/block.c | 55 | --- a/block.c |
51 | +++ b/block.c | 56 | +++ b/block.c |
52 | @@ -XXX,XX +XXX,XX @@ static void bdrv_child_cb_attach(BdrvChild *child) | 57 | @@ -XXX,XX +XXX,XX @@ static void bdrv_child_cb_drained_end(BdrvChild *child) |
58 | bdrv_drained_end(bs); | ||
59 | } | ||
60 | |||
61 | +static void bdrv_child_cb_attach(BdrvChild *child) | ||
62 | +{ | ||
63 | + BlockDriverState *bs = child->opaque; | ||
64 | + bdrv_apply_subtree_drain(child, bs); | ||
65 | +} | ||
66 | + | ||
67 | +static void bdrv_child_cb_detach(BdrvChild *child) | ||
68 | +{ | ||
69 | + BlockDriverState *bs = child->opaque; | ||
70 | + bdrv_unapply_subtree_drain(child, bs); | ||
71 | +} | ||
72 | + | ||
73 | static int bdrv_child_cb_inactivate(BdrvChild *child) | ||
53 | { | 74 | { |
54 | BlockDriverState *bs = child->opaque; | 75 | BlockDriverState *bs = child->opaque; |
55 | 76 | @@ -XXX,XX +XXX,XX @@ const BdrvChildRole child_file = { | |
56 | + assert_bdrv_graph_writable(bs); | 77 | .inherit_options = bdrv_inherited_options, |
57 | QLIST_INSERT_HEAD(&bs->children, child, next); | 78 | .drained_begin = bdrv_child_cb_drained_begin, |
58 | 79 | .drained_end = bdrv_child_cb_drained_end, | |
59 | if (child->role & BDRV_CHILD_COW) { | 80 | + .attach = bdrv_child_cb_attach, |
60 | @@ -XXX,XX +XXX,XX @@ static void bdrv_child_cb_detach(BdrvChild *child) | 81 | + .detach = bdrv_child_cb_detach, |
61 | 82 | .inactivate = bdrv_child_cb_inactivate, | |
62 | bdrv_unapply_subtree_drain(child, bs); | 83 | }; |
63 | 84 | ||
64 | + assert_bdrv_graph_writable(bs); | 85 | @@ -XXX,XX +XXX,XX @@ const BdrvChildRole child_format = { |
65 | QLIST_REMOVE(child, next); | 86 | .inherit_options = bdrv_inherited_fmt_options, |
66 | } | 87 | .drained_begin = bdrv_child_cb_drained_begin, |
67 | 88 | .drained_end = bdrv_child_cb_drained_end, | |
68 | @@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_noperm(BdrvChild **childp, | 89 | + .attach = bdrv_child_cb_attach, |
69 | if (child->klass->detach) { | 90 | + .detach = bdrv_child_cb_detach, |
70 | child->klass->detach(child); | 91 | .inactivate = bdrv_child_cb_inactivate, |
71 | } | 92 | }; |
72 | + assert_bdrv_graph_writable(old_bs); | 93 | |
94 | @@ -XXX,XX +XXX,XX @@ static void bdrv_backing_attach(BdrvChild *c) | ||
95 | parent->backing_blocker); | ||
96 | bdrv_op_unblock(backing_hd, BLOCK_OP_TYPE_BACKUP_TARGET, | ||
97 | parent->backing_blocker); | ||
98 | + | ||
99 | + bdrv_child_cb_attach(c); | ||
100 | } | ||
101 | |||
102 | static void bdrv_backing_detach(BdrvChild *c) | ||
103 | @@ -XXX,XX +XXX,XX @@ static void bdrv_backing_detach(BdrvChild *c) | ||
104 | bdrv_op_unblock_all(c->bs, parent->backing_blocker); | ||
105 | error_free(parent->backing_blocker); | ||
106 | parent->backing_blocker = NULL; | ||
107 | + | ||
108 | + bdrv_child_cb_detach(c); | ||
109 | } | ||
110 | |||
111 | /* | ||
112 | @@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_noperm(BdrvChild *child, | ||
113 | assert(bdrv_get_aio_context(old_bs) == bdrv_get_aio_context(new_bs)); | ||
114 | } | ||
115 | if (old_bs) { | ||
116 | + /* Detach first so that the recursive drain sections coming from @child | ||
117 | + * are already gone and we only end the drain sections that came from | ||
118 | + * elsewhere. */ | ||
119 | + if (child->role->detach) { | ||
120 | + child->role->detach(child); | ||
121 | + } | ||
122 | if (old_bs->quiesce_counter && child->role->drained_end) { | ||
123 | for (i = 0; i < old_bs->quiesce_counter; i++) { | ||
124 | child->role->drained_end(child); | ||
125 | } | ||
126 | } | ||
127 | - if (child->role->detach) { | ||
128 | - child->role->detach(child); | ||
129 | - } | ||
73 | QLIST_REMOVE(child, next_parent); | 130 | QLIST_REMOVE(child, next_parent); |
74 | } | 131 | } |
75 | 132 | ||
76 | @@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_noperm(BdrvChild **childp, | 133 | @@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_noperm(BdrvChild *child, |
134 | } | ||
135 | } | ||
136 | |||
137 | + /* Attach only after starting new drained sections, so that recursive | ||
138 | + * drain sections coming from @child don't get an extra .drained_begin | ||
139 | + * callback. */ | ||
140 | if (child->role->attach) { | ||
141 | child->role->attach(child); | ||
142 | } | ||
143 | diff --git a/block/io.c b/block/io.c | ||
144 | index XXXXXXX..XXXXXXX 100644 | ||
145 | --- a/block/io.c | ||
146 | +++ b/block/io.c | ||
147 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs, | ||
148 | assert(data.done); | ||
149 | } | ||
150 | |||
151 | -static void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive, | ||
152 | - BdrvChild *parent) | ||
153 | +void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive, | ||
154 | + BdrvChild *parent) | ||
155 | { | ||
156 | BdrvChild *child, *next; | ||
157 | |||
158 | @@ -XXX,XX +XXX,XX @@ static void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive, | ||
159 | bdrv_drain_recurse(bs); | ||
160 | |||
161 | if (recursive) { | ||
162 | + bs->recursive_quiesce_counter++; | ||
163 | QLIST_FOREACH_SAFE(child, &bs->children, next, next) { | ||
164 | bdrv_do_drained_begin(child->bs, true, child); | ||
165 | } | ||
166 | @@ -XXX,XX +XXX,XX @@ void bdrv_subtree_drained_begin(BlockDriverState *bs) | ||
167 | bdrv_do_drained_begin(bs, true, NULL); | ||
168 | } | ||
169 | |||
170 | -static void bdrv_do_drained_end(BlockDriverState *bs, bool recursive, | ||
171 | - BdrvChild *parent) | ||
172 | +void bdrv_do_drained_end(BlockDriverState *bs, bool recursive, | ||
173 | + BdrvChild *parent) | ||
174 | { | ||
175 | BdrvChild *child, *next; | ||
176 | int old_quiesce_counter; | ||
177 | @@ -XXX,XX +XXX,XX @@ static void bdrv_do_drained_end(BlockDriverState *bs, bool recursive, | ||
77 | } | 178 | } |
78 | 179 | ||
79 | if (new_bs) { | 180 | if (recursive) { |
80 | + assert_bdrv_graph_writable(new_bs); | 181 | + bs->recursive_quiesce_counter--; |
81 | QLIST_INSERT_HEAD(&new_bs->parents, child, next_parent); | 182 | QLIST_FOREACH_SAFE(child, &bs->children, next, next) { |
82 | 183 | bdrv_do_drained_end(child->bs, true, child); | |
83 | /* | 184 | } |
185 | @@ -XXX,XX +XXX,XX @@ void bdrv_subtree_drained_end(BlockDriverState *bs) | ||
186 | bdrv_do_drained_end(bs, true, NULL); | ||
187 | } | ||
188 | |||
189 | +void bdrv_apply_subtree_drain(BdrvChild *child, BlockDriverState *new_parent) | ||
190 | +{ | ||
191 | + int i; | ||
192 | + | ||
193 | + for (i = 0; i < new_parent->recursive_quiesce_counter; i++) { | ||
194 | + bdrv_do_drained_begin(child->bs, true, child); | ||
195 | + } | ||
196 | +} | ||
197 | + | ||
198 | +void bdrv_unapply_subtree_drain(BdrvChild *child, BlockDriverState *old_parent) | ||
199 | +{ | ||
200 | + int i; | ||
201 | + | ||
202 | + for (i = 0; i < old_parent->recursive_quiesce_counter; i++) { | ||
203 | + bdrv_do_drained_end(child->bs, true, child); | ||
204 | + } | ||
205 | +} | ||
206 | + | ||
207 | /* | ||
208 | * Wait for pending requests to complete on a single BlockDriverState subtree, | ||
209 | * and suspend block driver's internal I/O until next request arrives. | ||
84 | -- | 210 | -- |
85 | 2.35.1 | 211 | 2.13.6 |
212 | |||
213 | diff view generated by jsdifflib |
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
---|---|---|---|
2 | |||
3 | Mark all I/O functions with IO_CODE, and all "I/O OR GS" with | ||
4 | IO_OR_GS_CODE. | ||
5 | |||
6 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
7 | Message-Id: <20220303151616.325444-10-eesposit@redhat.com> | ||
8 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 1 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
9 | --- | 2 | --- |
10 | include/sysemu/block-backend-io.h | 2 ++ | 3 | tests/test-bdrv-drain.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++ |
11 | block/block-backend.c | 58 +++++++++++++++++++++++++++++++ | 4 | 1 file changed, 80 insertions(+) |
12 | 2 files changed, 60 insertions(+) | ||
13 | 5 | ||
14 | diff --git a/include/sysemu/block-backend-io.h b/include/sysemu/block-backend-io.h | 6 | diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c |
15 | index XXXXXXX..XXXXXXX 100644 | 7 | index XXXXXXX..XXXXXXX 100644 |
16 | --- a/include/sysemu/block-backend-io.h | 8 | --- a/tests/test-bdrv-drain.c |
17 | +++ b/include/sysemu/block-backend-io.h | 9 | +++ b/tests/test-bdrv-drain.c |
18 | @@ -XXX,XX +XXX,XX @@ static inline int coroutine_fn blk_co_pread(BlockBackend *blk, int64_t offset, | 10 | @@ -XXX,XX +XXX,XX @@ static void test_multiparent(void) |
19 | BdrvRequestFlags flags) | 11 | blk_unref(blk_b); |
20 | { | ||
21 | QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes); | ||
22 | + IO_OR_GS_CODE(); | ||
23 | |||
24 | assert(bytes <= SIZE_MAX); | ||
25 | |||
26 | @@ -XXX,XX +XXX,XX @@ static inline int coroutine_fn blk_co_pwrite(BlockBackend *blk, int64_t offset, | ||
27 | BdrvRequestFlags flags) | ||
28 | { | ||
29 | QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes); | ||
30 | + IO_OR_GS_CODE(); | ||
31 | |||
32 | assert(bytes <= SIZE_MAX); | ||
33 | |||
34 | diff --git a/block/block-backend.c b/block/block-backend.c | ||
35 | index XXXXXXX..XXXXXXX 100644 | ||
36 | --- a/block/block-backend.c | ||
37 | +++ b/block/block-backend.c | ||
38 | @@ -XXX,XX +XXX,XX @@ void monitor_remove_blk(BlockBackend *blk) | ||
39 | */ | ||
40 | const char *blk_name(const BlockBackend *blk) | ||
41 | { | ||
42 | + IO_CODE(); | ||
43 | return blk->name ?: ""; | ||
44 | } | 12 | } |
45 | 13 | ||
46 | @@ -XXX,XX +XXX,XX @@ BlockBackend *blk_by_name(const char *name) | 14 | +static void test_graph_change(void) |
47 | */ | 15 | +{ |
48 | BlockDriverState *blk_bs(BlockBackend *blk) | 16 | + BlockBackend *blk_a, *blk_b; |
49 | { | 17 | + BlockDriverState *bs_a, *bs_b, *backing; |
50 | + IO_CODE(); | 18 | + BDRVTestState *a_s, *b_s, *backing_s; |
51 | return blk->root ? blk->root->bs : NULL; | ||
52 | } | ||
53 | |||
54 | @@ -XXX,XX +XXX,XX @@ DeviceState *blk_get_attached_dev(BlockBackend *blk) | ||
55 | char *blk_get_attached_dev_id(BlockBackend *blk) | ||
56 | { | ||
57 | DeviceState *dev = blk->dev; | ||
58 | + IO_CODE(); | ||
59 | |||
60 | if (!dev) { | ||
61 | return g_strdup(""); | ||
62 | @@ -XXX,XX +XXX,XX @@ void blk_iostatus_enable(BlockBackend *blk) | ||
63 | * enables it _and_ the VM is configured to stop on errors */ | ||
64 | bool blk_iostatus_is_enabled(const BlockBackend *blk) | ||
65 | { | ||
66 | + IO_CODE(); | ||
67 | return (blk->iostatus_enabled && | ||
68 | (blk->on_write_error == BLOCKDEV_ON_ERROR_ENOSPC || | ||
69 | blk->on_write_error == BLOCKDEV_ON_ERROR_STOP || | ||
70 | @@ -XXX,XX +XXX,XX @@ void blk_iostatus_reset(BlockBackend *blk) | ||
71 | |||
72 | void blk_iostatus_set_err(BlockBackend *blk, int error) | ||
73 | { | ||
74 | + IO_CODE(); | ||
75 | assert(blk_iostatus_is_enabled(blk)); | ||
76 | if (blk->iostatus == BLOCK_DEVICE_IO_STATUS_OK) { | ||
77 | blk->iostatus = error == ENOSPC ? BLOCK_DEVICE_IO_STATUS_NOSPACE : | ||
78 | @@ -XXX,XX +XXX,XX @@ void blk_iostatus_set_err(BlockBackend *blk, int error) | ||
79 | |||
80 | void blk_set_allow_write_beyond_eof(BlockBackend *blk, bool allow) | ||
81 | { | ||
82 | + IO_CODE(); | ||
83 | blk->allow_write_beyond_eof = allow; | ||
84 | } | ||
85 | |||
86 | void blk_set_allow_aio_context_change(BlockBackend *blk, bool allow) | ||
87 | { | ||
88 | + IO_CODE(); | ||
89 | blk->allow_aio_context_change = allow; | ||
90 | } | ||
91 | |||
92 | void blk_set_disable_request_queuing(BlockBackend *blk, bool disable) | ||
93 | { | ||
94 | + IO_CODE(); | ||
95 | blk->disable_request_queuing = disable; | ||
96 | } | ||
97 | |||
98 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn blk_co_preadv(BlockBackend *blk, int64_t offset, | ||
99 | BdrvRequestFlags flags) | ||
100 | { | ||
101 | int ret; | ||
102 | + IO_OR_GS_CODE(); | ||
103 | |||
104 | blk_inc_in_flight(blk); | ||
105 | ret = blk_co_do_preadv(blk, offset, bytes, qiov, flags); | ||
106 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn blk_co_pwritev_part(BlockBackend *blk, int64_t offset, | ||
107 | BdrvRequestFlags flags) | ||
108 | { | ||
109 | int ret; | ||
110 | + IO_OR_GS_CODE(); | ||
111 | |||
112 | blk_inc_in_flight(blk); | ||
113 | ret = blk_co_do_pwritev_part(blk, offset, bytes, qiov, qiov_offset, flags); | ||
114 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn blk_co_pwritev(BlockBackend *blk, int64_t offset, | ||
115 | int64_t bytes, QEMUIOVector *qiov, | ||
116 | BdrvRequestFlags flags) | ||
117 | { | ||
118 | + IO_OR_GS_CODE(); | ||
119 | return blk_co_pwritev_part(blk, offset, bytes, qiov, 0, flags); | ||
120 | } | ||
121 | |||
122 | @@ -XXX,XX +XXX,XX @@ typedef struct BlkRwCo { | ||
123 | int blk_pwrite_zeroes(BlockBackend *blk, int64_t offset, | ||
124 | int64_t bytes, BdrvRequestFlags flags) | ||
125 | { | ||
126 | + IO_OR_GS_CODE(); | ||
127 | return blk_pwritev_part(blk, offset, bytes, NULL, 0, | ||
128 | flags | BDRV_REQ_ZERO_WRITE); | ||
129 | } | ||
130 | @@ -XXX,XX +XXX,XX @@ int blk_make_zero(BlockBackend *blk, BdrvRequestFlags flags) | ||
131 | |||
132 | void blk_inc_in_flight(BlockBackend *blk) | ||
133 | { | ||
134 | + IO_CODE(); | ||
135 | qatomic_inc(&blk->in_flight); | ||
136 | } | ||
137 | |||
138 | void blk_dec_in_flight(BlockBackend *blk) | ||
139 | { | ||
140 | + IO_CODE(); | ||
141 | qatomic_dec(&blk->in_flight); | ||
142 | aio_wait_kick(); | ||
143 | } | ||
144 | @@ -XXX,XX +XXX,XX @@ BlockAIOCB *blk_abort_aio_request(BlockBackend *blk, | ||
145 | void *opaque, int ret) | ||
146 | { | ||
147 | struct BlockBackendAIOCB *acb; | ||
148 | + IO_CODE(); | ||
149 | |||
150 | blk_inc_in_flight(blk); | ||
151 | acb = blk_aio_get(&block_backend_aiocb_info, blk, cb, opaque); | ||
152 | @@ -XXX,XX +XXX,XX @@ BlockAIOCB *blk_aio_pwrite_zeroes(BlockBackend *blk, int64_t offset, | ||
153 | int64_t bytes, BdrvRequestFlags flags, | ||
154 | BlockCompletionFunc *cb, void *opaque) | ||
155 | { | ||
156 | + IO_CODE(); | ||
157 | return blk_aio_prwv(blk, offset, bytes, NULL, blk_aio_write_entry, | ||
158 | flags | BDRV_REQ_ZERO_WRITE, cb, opaque); | ||
159 | } | ||
160 | @@ -XXX,XX +XXX,XX @@ int blk_pread(BlockBackend *blk, int64_t offset, void *buf, int bytes) | ||
161 | { | ||
162 | int ret; | ||
163 | QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes); | ||
164 | + IO_OR_GS_CODE(); | ||
165 | |||
166 | blk_inc_in_flight(blk); | ||
167 | ret = blk_do_preadv(blk, offset, bytes, &qiov, 0); | ||
168 | @@ -XXX,XX +XXX,XX @@ int blk_pwrite(BlockBackend *blk, int64_t offset, const void *buf, int bytes, | ||
169 | { | ||
170 | int ret; | ||
171 | QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes); | ||
172 | + IO_OR_GS_CODE(); | ||
173 | |||
174 | ret = blk_pwritev_part(blk, offset, bytes, &qiov, 0, flags); | ||
175 | |||
176 | @@ -XXX,XX +XXX,XX @@ int blk_pwrite(BlockBackend *blk, int64_t offset, const void *buf, int bytes, | ||
177 | |||
178 | int64_t blk_getlength(BlockBackend *blk) | ||
179 | { | ||
180 | + IO_CODE(); | ||
181 | if (!blk_is_available(blk)) { | ||
182 | return -ENOMEDIUM; | ||
183 | } | ||
184 | @@ -XXX,XX +XXX,XX @@ int64_t blk_getlength(BlockBackend *blk) | ||
185 | |||
186 | void blk_get_geometry(BlockBackend *blk, uint64_t *nb_sectors_ptr) | ||
187 | { | ||
188 | + IO_CODE(); | ||
189 | if (!blk_bs(blk)) { | ||
190 | *nb_sectors_ptr = 0; | ||
191 | } else { | ||
192 | @@ -XXX,XX +XXX,XX @@ void blk_get_geometry(BlockBackend *blk, uint64_t *nb_sectors_ptr) | ||
193 | |||
194 | int64_t blk_nb_sectors(BlockBackend *blk) | ||
195 | { | ||
196 | + IO_CODE(); | ||
197 | if (!blk_is_available(blk)) { | ||
198 | return -ENOMEDIUM; | ||
199 | } | ||
200 | @@ -XXX,XX +XXX,XX @@ BlockAIOCB *blk_aio_preadv(BlockBackend *blk, int64_t offset, | ||
201 | QEMUIOVector *qiov, BdrvRequestFlags flags, | ||
202 | BlockCompletionFunc *cb, void *opaque) | ||
203 | { | ||
204 | + IO_CODE(); | ||
205 | assert((uint64_t)qiov->size <= INT64_MAX); | ||
206 | return blk_aio_prwv(blk, offset, qiov->size, qiov, | ||
207 | blk_aio_read_entry, flags, cb, opaque); | ||
208 | @@ -XXX,XX +XXX,XX @@ BlockAIOCB *blk_aio_pwritev(BlockBackend *blk, int64_t offset, | ||
209 | QEMUIOVector *qiov, BdrvRequestFlags flags, | ||
210 | BlockCompletionFunc *cb, void *opaque) | ||
211 | { | ||
212 | + IO_CODE(); | ||
213 | assert((uint64_t)qiov->size <= INT64_MAX); | ||
214 | return blk_aio_prwv(blk, offset, qiov->size, qiov, | ||
215 | blk_aio_write_entry, flags, cb, opaque); | ||
216 | @@ -XXX,XX +XXX,XX @@ void blk_aio_cancel(BlockAIOCB *acb) | ||
217 | |||
218 | void blk_aio_cancel_async(BlockAIOCB *acb) | ||
219 | { | ||
220 | + IO_CODE(); | ||
221 | bdrv_aio_cancel_async(acb); | ||
222 | } | ||
223 | |||
224 | @@ -XXX,XX +XXX,XX @@ blk_co_do_ioctl(BlockBackend *blk, unsigned long int req, void *buf) | ||
225 | int blk_ioctl(BlockBackend *blk, unsigned long int req, void *buf) | ||
226 | { | ||
227 | int ret; | ||
228 | + IO_OR_GS_CODE(); | ||
229 | |||
230 | blk_inc_in_flight(blk); | ||
231 | ret = blk_do_ioctl(blk, req, buf); | ||
232 | @@ -XXX,XX +XXX,XX @@ static void blk_aio_ioctl_entry(void *opaque) | ||
233 | BlockAIOCB *blk_aio_ioctl(BlockBackend *blk, unsigned long int req, void *buf, | ||
234 | BlockCompletionFunc *cb, void *opaque) | ||
235 | { | ||
236 | + IO_CODE(); | ||
237 | return blk_aio_prwv(blk, req, 0, buf, blk_aio_ioctl_entry, 0, cb, opaque); | ||
238 | } | ||
239 | |||
240 | @@ -XXX,XX +XXX,XX @@ BlockAIOCB *blk_aio_pdiscard(BlockBackend *blk, | ||
241 | int64_t offset, int64_t bytes, | ||
242 | BlockCompletionFunc *cb, void *opaque) | ||
243 | { | ||
244 | + IO_CODE(); | ||
245 | return blk_aio_prwv(blk, offset, bytes, NULL, blk_aio_pdiscard_entry, 0, | ||
246 | cb, opaque); | ||
247 | } | ||
248 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn blk_co_pdiscard(BlockBackend *blk, int64_t offset, | ||
249 | int64_t bytes) | ||
250 | { | ||
251 | int ret; | ||
252 | + IO_OR_GS_CODE(); | ||
253 | |||
254 | blk_inc_in_flight(blk); | ||
255 | ret = blk_co_do_pdiscard(blk, offset, bytes); | ||
256 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn blk_co_pdiscard(BlockBackend *blk, int64_t offset, | ||
257 | int blk_pdiscard(BlockBackend *blk, int64_t offset, int64_t bytes) | ||
258 | { | ||
259 | int ret; | ||
260 | + IO_OR_GS_CODE(); | ||
261 | |||
262 | blk_inc_in_flight(blk); | ||
263 | ret = blk_do_pdiscard(blk, offset, bytes); | ||
264 | @@ -XXX,XX +XXX,XX @@ static void blk_aio_flush_entry(void *opaque) | ||
265 | BlockAIOCB *blk_aio_flush(BlockBackend *blk, | ||
266 | BlockCompletionFunc *cb, void *opaque) | ||
267 | { | ||
268 | + IO_CODE(); | ||
269 | return blk_aio_prwv(blk, 0, 0, NULL, blk_aio_flush_entry, 0, cb, opaque); | ||
270 | } | ||
271 | |||
272 | int coroutine_fn blk_co_flush(BlockBackend *blk) | ||
273 | { | ||
274 | int ret; | ||
275 | + IO_OR_GS_CODE(); | ||
276 | |||
277 | blk_inc_in_flight(blk); | ||
278 | ret = blk_co_do_flush(blk); | ||
279 | @@ -XXX,XX +XXX,XX @@ void blk_set_on_error(BlockBackend *blk, BlockdevOnError on_read_error, | ||
280 | |||
281 | BlockdevOnError blk_get_on_error(BlockBackend *blk, bool is_read) | ||
282 | { | ||
283 | + IO_CODE(); | ||
284 | return is_read ? blk->on_read_error : blk->on_write_error; | ||
285 | } | ||
286 | |||
287 | @@ -XXX,XX +XXX,XX @@ BlockErrorAction blk_get_error_action(BlockBackend *blk, bool is_read, | ||
288 | int error) | ||
289 | { | ||
290 | BlockdevOnError on_err = blk_get_on_error(blk, is_read); | ||
291 | + IO_CODE(); | ||
292 | |||
293 | switch (on_err) { | ||
294 | case BLOCKDEV_ON_ERROR_ENOSPC: | ||
295 | @@ -XXX,XX +XXX,XX @@ void blk_error_action(BlockBackend *blk, BlockErrorAction action, | ||
296 | bool is_read, int error) | ||
297 | { | ||
298 | assert(error >= 0); | ||
299 | + IO_CODE(); | ||
300 | |||
301 | if (action == BLOCK_ERROR_ACTION_STOP) { | ||
302 | /* First set the iostatus, so that "info block" returns an iostatus | ||
303 | @@ -XXX,XX +XXX,XX @@ bool blk_supports_write_perm(BlockBackend *blk) | ||
304 | */ | ||
305 | bool blk_is_writable(BlockBackend *blk) | ||
306 | { | ||
307 | + IO_CODE(); | ||
308 | return blk->perm & BLK_PERM_WRITE; | ||
309 | } | ||
310 | |||
311 | @@ -XXX,XX +XXX,XX @@ bool blk_is_sg(BlockBackend *blk) | ||
312 | |||
313 | bool blk_enable_write_cache(BlockBackend *blk) | ||
314 | { | ||
315 | + IO_CODE(); | ||
316 | return blk->enable_write_cache; | ||
317 | } | ||
318 | |||
319 | @@ -XXX,XX +XXX,XX @@ void blk_activate(BlockBackend *blk, Error **errp) | ||
320 | bool blk_is_inserted(BlockBackend *blk) | ||
321 | { | ||
322 | BlockDriverState *bs = blk_bs(blk); | ||
323 | + IO_CODE(); | ||
324 | |||
325 | return bs && bdrv_is_inserted(bs); | ||
326 | } | ||
327 | |||
328 | bool blk_is_available(BlockBackend *blk) | ||
329 | { | ||
330 | + IO_CODE(); | ||
331 | return blk_is_inserted(blk) && !blk_dev_is_tray_open(blk); | ||
332 | } | ||
333 | |||
334 | void blk_lock_medium(BlockBackend *blk, bool locked) | ||
335 | { | ||
336 | BlockDriverState *bs = blk_bs(blk); | ||
337 | + IO_CODE(); | ||
338 | |||
339 | if (bs) { | ||
340 | bdrv_lock_medium(bs, locked); | ||
341 | @@ -XXX,XX +XXX,XX @@ void blk_eject(BlockBackend *blk, bool eject_flag) | ||
342 | { | ||
343 | BlockDriverState *bs = blk_bs(blk); | ||
344 | char *id; | ||
345 | + IO_CODE(); | ||
346 | |||
347 | if (bs) { | ||
348 | bdrv_eject(bs, eject_flag); | ||
349 | @@ -XXX,XX +XXX,XX @@ int blk_get_flags(BlockBackend *blk) | ||
350 | uint32_t blk_get_request_alignment(BlockBackend *blk) | ||
351 | { | ||
352 | BlockDriverState *bs = blk_bs(blk); | ||
353 | + IO_CODE(); | ||
354 | return bs ? bs->bl.request_alignment : BDRV_SECTOR_SIZE; | ||
355 | } | ||
356 | |||
357 | @@ -XXX,XX +XXX,XX @@ uint64_t blk_get_max_hw_transfer(BlockBackend *blk) | ||
358 | { | ||
359 | BlockDriverState *bs = blk_bs(blk); | ||
360 | uint64_t max = INT_MAX; | ||
361 | + IO_CODE(); | ||
362 | |||
363 | if (bs) { | ||
364 | max = MIN_NON_ZERO(max, bs->bl.max_hw_transfer); | ||
365 | @@ -XXX,XX +XXX,XX @@ uint32_t blk_get_max_transfer(BlockBackend *blk) | ||
366 | { | ||
367 | BlockDriverState *bs = blk_bs(blk); | ||
368 | uint32_t max = INT_MAX; | ||
369 | + IO_CODE(); | ||
370 | |||
371 | if (bs) { | ||
372 | max = MIN_NON_ZERO(max, bs->bl.max_transfer); | ||
373 | @@ -XXX,XX +XXX,XX @@ uint32_t blk_get_max_transfer(BlockBackend *blk) | ||
374 | |||
375 | int blk_get_max_hw_iov(BlockBackend *blk) | ||
376 | { | ||
377 | + IO_CODE(); | ||
378 | return MIN_NON_ZERO(blk->root->bs->bl.max_hw_iov, | ||
379 | blk->root->bs->bl.max_iov); | ||
380 | } | ||
381 | |||
382 | int blk_get_max_iov(BlockBackend *blk) | ||
383 | { | ||
384 | + IO_CODE(); | ||
385 | return blk->root->bs->bl.max_iov; | ||
386 | } | ||
387 | |||
388 | void blk_set_guest_block_size(BlockBackend *blk, int align) | ||
389 | { | ||
390 | + IO_CODE(); | ||
391 | blk->guest_block_size = align; | ||
392 | } | ||
393 | |||
394 | void *blk_try_blockalign(BlockBackend *blk, size_t size) | ||
395 | { | ||
396 | + IO_CODE(); | ||
397 | return qemu_try_blockalign(blk ? blk_bs(blk) : NULL, size); | ||
398 | } | ||
399 | |||
400 | void *blk_blockalign(BlockBackend *blk, size_t size) | ||
401 | { | ||
402 | + IO_CODE(); | ||
403 | return qemu_blockalign(blk ? blk_bs(blk) : NULL, size); | ||
404 | } | ||
405 | |||
406 | @@ -XXX,XX +XXX,XX @@ void blk_op_unblock_all(BlockBackend *blk, Error *reason) | ||
407 | AioContext *blk_get_aio_context(BlockBackend *blk) | ||
408 | { | ||
409 | BlockDriverState *bs = blk_bs(blk); | ||
410 | + IO_CODE(); | ||
411 | |||
412 | if (bs) { | ||
413 | AioContext *ctx = bdrv_get_aio_context(blk_bs(blk)); | ||
414 | @@ -XXX,XX +XXX,XX @@ void blk_add_insert_bs_notifier(BlockBackend *blk, Notifier *notify) | ||
415 | void blk_io_plug(BlockBackend *blk) | ||
416 | { | ||
417 | BlockDriverState *bs = blk_bs(blk); | ||
418 | + IO_CODE(); | ||
419 | |||
420 | if (bs) { | ||
421 | bdrv_io_plug(bs); | ||
422 | @@ -XXX,XX +XXX,XX @@ void blk_io_plug(BlockBackend *blk) | ||
423 | void blk_io_unplug(BlockBackend *blk) | ||
424 | { | ||
425 | BlockDriverState *bs = blk_bs(blk); | ||
426 | + IO_CODE(); | ||
427 | |||
428 | if (bs) { | ||
429 | bdrv_io_unplug(bs); | ||
430 | @@ -XXX,XX +XXX,XX @@ void blk_io_unplug(BlockBackend *blk) | ||
431 | |||
432 | BlockAcctStats *blk_get_stats(BlockBackend *blk) | ||
433 | { | ||
434 | + IO_CODE(); | ||
435 | return &blk->stats; | ||
436 | } | ||
437 | |||
438 | void *blk_aio_get(const AIOCBInfo *aiocb_info, BlockBackend *blk, | ||
439 | BlockCompletionFunc *cb, void *opaque) | ||
440 | { | ||
441 | + IO_CODE(); | ||
442 | return qemu_aio_get(aiocb_info, blk_bs(blk), cb, opaque); | ||
443 | } | ||
444 | |||
445 | int coroutine_fn blk_co_pwrite_zeroes(BlockBackend *blk, int64_t offset, | ||
446 | int64_t bytes, BdrvRequestFlags flags) | ||
447 | { | ||
448 | + IO_OR_GS_CODE(); | ||
449 | return blk_co_pwritev(blk, offset, bytes, NULL, | ||
450 | flags | BDRV_REQ_ZERO_WRITE); | ||
451 | } | ||
452 | @@ -XXX,XX +XXX,XX @@ int blk_pwrite_compressed(BlockBackend *blk, int64_t offset, const void *buf, | ||
453 | int64_t bytes) | ||
454 | { | ||
455 | QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes); | ||
456 | + IO_OR_GS_CODE(); | ||
457 | return blk_pwritev_part(blk, offset, bytes, &qiov, 0, | ||
458 | BDRV_REQ_WRITE_COMPRESSED); | ||
459 | } | ||
460 | @@ -XXX,XX +XXX,XX @@ int blk_pwrite_compressed(BlockBackend *blk, int64_t offset, const void *buf, | ||
461 | int blk_truncate(BlockBackend *blk, int64_t offset, bool exact, | ||
462 | PreallocMode prealloc, BdrvRequestFlags flags, Error **errp) | ||
463 | { | ||
464 | + IO_OR_GS_CODE(); | ||
465 | if (!blk_is_available(blk)) { | ||
466 | error_setg(errp, "No medium inserted"); | ||
467 | return -ENOMEDIUM; | ||
468 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn blk_co_copy_range(BlockBackend *blk_in, int64_t off_in, | ||
469 | BdrvRequestFlags write_flags) | ||
470 | { | ||
471 | int r; | ||
472 | + IO_CODE(); | ||
473 | + | 19 | + |
474 | r = blk_check_byte_request(blk_in, off_in, bytes); | 20 | + blk_a = blk_new(BLK_PERM_ALL, BLK_PERM_ALL); |
475 | if (r) { | 21 | + bs_a = bdrv_new_open_driver(&bdrv_test, "test-node-a", BDRV_O_RDWR, |
476 | return r; | 22 | + &error_abort); |
23 | + a_s = bs_a->opaque; | ||
24 | + blk_insert_bs(blk_a, bs_a, &error_abort); | ||
25 | + | ||
26 | + blk_b = blk_new(BLK_PERM_ALL, BLK_PERM_ALL); | ||
27 | + bs_b = bdrv_new_open_driver(&bdrv_test, "test-node-b", BDRV_O_RDWR, | ||
28 | + &error_abort); | ||
29 | + b_s = bs_b->opaque; | ||
30 | + blk_insert_bs(blk_b, bs_b, &error_abort); | ||
31 | + | ||
32 | + backing = bdrv_new_open_driver(&bdrv_test, "backing", 0, &error_abort); | ||
33 | + backing_s = backing->opaque; | ||
34 | + bdrv_set_backing_hd(bs_a, backing, &error_abort); | ||
35 | + | ||
36 | + g_assert_cmpint(bs_a->quiesce_counter, ==, 0); | ||
37 | + g_assert_cmpint(bs_b->quiesce_counter, ==, 0); | ||
38 | + g_assert_cmpint(backing->quiesce_counter, ==, 0); | ||
39 | + g_assert_cmpint(a_s->drain_count, ==, 0); | ||
40 | + g_assert_cmpint(b_s->drain_count, ==, 0); | ||
41 | + g_assert_cmpint(backing_s->drain_count, ==, 0); | ||
42 | + | ||
43 | + do_drain_begin(BDRV_SUBTREE_DRAIN, bs_a); | ||
44 | + do_drain_begin(BDRV_SUBTREE_DRAIN, bs_a); | ||
45 | + do_drain_begin(BDRV_SUBTREE_DRAIN, bs_a); | ||
46 | + do_drain_begin(BDRV_SUBTREE_DRAIN, bs_b); | ||
47 | + do_drain_begin(BDRV_SUBTREE_DRAIN, bs_b); | ||
48 | + | ||
49 | + bdrv_set_backing_hd(bs_b, backing, &error_abort); | ||
50 | + g_assert_cmpint(bs_a->quiesce_counter, ==, 5); | ||
51 | + g_assert_cmpint(bs_b->quiesce_counter, ==, 5); | ||
52 | + g_assert_cmpint(backing->quiesce_counter, ==, 5); | ||
53 | + g_assert_cmpint(a_s->drain_count, ==, 5); | ||
54 | + g_assert_cmpint(b_s->drain_count, ==, 5); | ||
55 | + g_assert_cmpint(backing_s->drain_count, ==, 5); | ||
56 | + | ||
57 | + bdrv_set_backing_hd(bs_b, NULL, &error_abort); | ||
58 | + g_assert_cmpint(bs_a->quiesce_counter, ==, 3); | ||
59 | + g_assert_cmpint(bs_b->quiesce_counter, ==, 2); | ||
60 | + g_assert_cmpint(backing->quiesce_counter, ==, 3); | ||
61 | + g_assert_cmpint(a_s->drain_count, ==, 3); | ||
62 | + g_assert_cmpint(b_s->drain_count, ==, 2); | ||
63 | + g_assert_cmpint(backing_s->drain_count, ==, 3); | ||
64 | + | ||
65 | + bdrv_set_backing_hd(bs_b, backing, &error_abort); | ||
66 | + g_assert_cmpint(bs_a->quiesce_counter, ==, 5); | ||
67 | + g_assert_cmpint(bs_b->quiesce_counter, ==, 5); | ||
68 | + g_assert_cmpint(backing->quiesce_counter, ==, 5); | ||
69 | + g_assert_cmpint(a_s->drain_count, ==, 5); | ||
70 | + g_assert_cmpint(b_s->drain_count, ==, 5); | ||
71 | + g_assert_cmpint(backing_s->drain_count, ==, 5); | ||
72 | + | ||
73 | + do_drain_end(BDRV_SUBTREE_DRAIN, bs_b); | ||
74 | + do_drain_end(BDRV_SUBTREE_DRAIN, bs_b); | ||
75 | + do_drain_end(BDRV_SUBTREE_DRAIN, bs_a); | ||
76 | + do_drain_end(BDRV_SUBTREE_DRAIN, bs_a); | ||
77 | + do_drain_end(BDRV_SUBTREE_DRAIN, bs_a); | ||
78 | + | ||
79 | + g_assert_cmpint(bs_a->quiesce_counter, ==, 0); | ||
80 | + g_assert_cmpint(bs_b->quiesce_counter, ==, 0); | ||
81 | + g_assert_cmpint(backing->quiesce_counter, ==, 0); | ||
82 | + g_assert_cmpint(a_s->drain_count, ==, 0); | ||
83 | + g_assert_cmpint(b_s->drain_count, ==, 0); | ||
84 | + g_assert_cmpint(backing_s->drain_count, ==, 0); | ||
85 | + | ||
86 | + bdrv_unref(backing); | ||
87 | + bdrv_unref(bs_a); | ||
88 | + bdrv_unref(bs_b); | ||
89 | + blk_unref(blk_a); | ||
90 | + blk_unref(blk_b); | ||
91 | +} | ||
92 | + | ||
93 | |||
94 | typedef struct TestBlockJob { | ||
95 | BlockJob common; | ||
96 | @@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv) | ||
97 | |||
98 | g_test_add_func("/bdrv-drain/nested", test_nested); | ||
99 | g_test_add_func("/bdrv-drain/multiparent", test_multiparent); | ||
100 | + g_test_add_func("/bdrv-drain/graph-change", test_graph_change); | ||
101 | |||
102 | g_test_add_func("/bdrv-drain/blockjob/drain_all", test_blockjob_drain_all); | ||
103 | g_test_add_func("/bdrv-drain/blockjob/drain", test_blockjob_drain); | ||
477 | -- | 104 | -- |
478 | 2.35.1 | 105 | 2.13.6 |
106 | |||
107 | diff view generated by jsdifflib |
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | 1 | Since commit bde70715, base is the only node that is reopened in |
---|---|---|---|
2 | commit_start(). This means that the code, which still involves an | ||
3 | explicit BlockReopenQueue, can now be simplified by using bdrv_reopen(). | ||
2 | 4 | ||
3 | block_crypto_amend_options_generic_luks uses the block layer | 5 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
4 | permission API, therefore it should be called with the BQL held. | 6 | Reviewed-by: Fam Zheng <famz@redhat.com> |
7 | --- | ||
8 | block/commit.c | 8 +------- | ||
9 | 1 file changed, 1 insertion(+), 7 deletions(-) | ||
5 | 10 | ||
6 | However, the same function is being called by two BlockDriver | 11 | diff --git a/block/commit.c b/block/commit.c |
7 | callbacks: bdrv_amend_options (under BQL) and bdrv_co_amend (I/O). | ||
8 | |||
9 | The latter is I/O because it is invoked by block/amend.c's | ||
10 | blockdev_amend_run(), a .run callback of the amend JobDriver. | ||
11 | |||
12 | Therefore we want to change this function to still perform | ||
13 | the permission check, but making sure it is done under BQL regardless | ||
14 | of the caller context. | ||
15 | |||
16 | Remove the permission check in block_crypto_amend_options_generic_luks() | ||
17 | and: | ||
18 | - in block_crypto_amend_options_luks() (BQL case, called by | ||
19 | .bdrv_amend_options()), reuse helper functions | ||
20 | block_crypto_amend_{prepare/cleanup} that take care of checking | ||
21 | permissions. | ||
22 | |||
23 | - for block_crypto_co_amend_luks() (I/O case, called by | ||
24 | .bdrv_co_amend()), don't check for permissions but delegate | ||
25 | .bdrv_amend_pre_run() and .bdrv_amend_clean() to do it, | ||
26 | performing these checks before and after the job runs in its aiocontext. | ||
27 | |||
28 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
29 | Message-Id: <20220209105452.1694545-3-eesposit@redhat.com> | ||
30 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
31 | --- | ||
32 | block/crypto.c | 35 +++++++++++++++-------------------- | ||
33 | 1 file changed, 15 insertions(+), 20 deletions(-) | ||
34 | |||
35 | diff --git a/block/crypto.c b/block/crypto.c | ||
36 | index XXXXXXX..XXXXXXX 100644 | 12 | index XXXXXXX..XXXXXXX 100644 |
37 | --- a/block/crypto.c | 13 | --- a/block/commit.c |
38 | +++ b/block/crypto.c | 14 | +++ b/block/commit.c |
39 | @@ -XXX,XX +XXX,XX @@ block_crypto_amend_options_generic_luks(BlockDriverState *bs, | 15 | @@ -XXX,XX +XXX,XX @@ void commit_start(const char *job_id, BlockDriverState *bs, |
40 | Error **errp) | 16 | const char *filter_node_name, Error **errp) |
41 | { | 17 | { |
42 | BlockCrypto *crypto = bs->opaque; | 18 | CommitBlockJob *s; |
43 | - int ret; | 19 | - BlockReopenQueue *reopen_queue = NULL; |
44 | 20 | int orig_base_flags; | |
45 | assert(crypto); | 21 | BlockDriverState *iter; |
46 | assert(crypto->block); | 22 | BlockDriverState *commit_top_bs = NULL; |
47 | 23 | @@ -XXX,XX +XXX,XX @@ void commit_start(const char *job_id, BlockDriverState *bs, | |
48 | - /* apply for exclusive read/write permissions to the underlying file*/ | 24 | /* convert base to r/w, if necessary */ |
49 | - crypto->updating_keys = true; | 25 | orig_base_flags = bdrv_get_flags(base); |
50 | - ret = bdrv_child_refresh_perms(bs, bs->file, errp); | 26 | if (!(orig_base_flags & BDRV_O_RDWR)) { |
51 | - if (ret) { | 27 | - reopen_queue = bdrv_reopen_queue(reopen_queue, base, NULL, |
52 | - goto cleanup; | 28 | - orig_base_flags | BDRV_O_RDWR); |
53 | - } | 29 | - } |
54 | - | 30 | - |
55 | - ret = qcrypto_block_amend_options(crypto->block, | 31 | - if (reopen_queue) { |
56 | - block_crypto_read_func, | 32 | - bdrv_reopen_multiple(bdrv_get_aio_context(bs), reopen_queue, &local_err); |
57 | - block_crypto_write_func, | 33 | + bdrv_reopen(base, orig_base_flags | BDRV_O_RDWR, &local_err); |
58 | - bs, | 34 | if (local_err != NULL) { |
59 | - amend_options, | 35 | error_propagate(errp, local_err); |
60 | - force, | 36 | goto fail; |
61 | - errp); | ||
62 | -cleanup: | ||
63 | - /* release exclusive read/write permissions to the underlying file*/ | ||
64 | - crypto->updating_keys = false; | ||
65 | - bdrv_child_refresh_perms(bs, bs->file, errp); | ||
66 | - return ret; | ||
67 | + return qcrypto_block_amend_options(crypto->block, | ||
68 | + block_crypto_read_func, | ||
69 | + block_crypto_write_func, | ||
70 | + bs, | ||
71 | + amend_options, | ||
72 | + force, | ||
73 | + errp); | ||
74 | } | ||
75 | |||
76 | static int | ||
77 | @@ -XXX,XX +XXX,XX @@ block_crypto_amend_options_luks(BlockDriverState *bs, | ||
78 | if (!amend_options) { | ||
79 | goto cleanup; | ||
80 | } | ||
81 | + | ||
82 | + ret = block_crypto_amend_prepare(bs, errp); | ||
83 | + if (ret) { | ||
84 | + goto perm_cleanup; | ||
85 | + } | ||
86 | ret = block_crypto_amend_options_generic_luks(bs, amend_options, | ||
87 | force, errp); | ||
88 | + | ||
89 | +perm_cleanup: | ||
90 | + block_crypto_amend_cleanup(bs); | ||
91 | cleanup: | ||
92 | qapi_free_QCryptoBlockAmendOptions(amend_options); | ||
93 | return ret; | ||
94 | -- | 37 | -- |
95 | 2.35.1 | 38 | 2.13.6 |
39 | |||
40 | diff view generated by jsdifflib |
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | 1 | The bdrv_reopen*() implementation doesn't like it if the graph is |
---|---|---|---|
2 | changed between queuing nodes for reopen and actually reopening them | ||
3 | (one of the reasons is that queuing can be recursive). | ||
2 | 4 | ||
3 | Split bdrv_co_invalidate cache in two: the Global State (under BQL) | 5 | So instead of draining the device only in bdrv_reopen_multiple(), |
4 | code that takes care of permissions and running GS callbacks, | 6 | require that callers already drained all affected nodes, and assert this |
5 | and leave only the I/O code (->bdrv_co_invalidate_cache) running in | 7 | in bdrv_reopen_queue(). |
6 | the I/O coroutine. | ||
7 | 8 | ||
8 | The only side effect is that bdrv_co_invalidate_cache is not | ||
9 | recursive anymore, and so is every direct call to | ||
10 | bdrv_invalidate_cache(). | ||
11 | |||
12 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
13 | Message-Id: <20220209105452.1694545-6-eesposit@redhat.com> | ||
14 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 9 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
10 | Reviewed-by: Fam Zheng <famz@redhat.com> | ||
15 | --- | 11 | --- |
16 | block.c | 37 +++++++++++++++++++++++-------------- | 12 | block.c | 23 ++++++++++++++++------- |
17 | 1 file changed, 23 insertions(+), 14 deletions(-) | 13 | block/replication.c | 6 ++++++ |
14 | qemu-io-cmds.c | 3 +++ | ||
15 | 3 files changed, 25 insertions(+), 7 deletions(-) | ||
18 | 16 | ||
19 | diff --git a/block.c b/block.c | 17 | diff --git a/block.c b/block.c |
20 | index XXXXXXX..XXXXXXX 100644 | 18 | index XXXXXXX..XXXXXXX 100644 |
21 | --- a/block.c | 19 | --- a/block.c |
22 | +++ b/block.c | 20 | +++ b/block.c |
23 | @@ -XXX,XX +XXX,XX @@ void bdrv_init_with_whitelist(void) | 21 | @@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_open(const char *filename, const char *reference, |
22 | * returns a pointer to bs_queue, which is either the newly allocated | ||
23 | * bs_queue, or the existing bs_queue being used. | ||
24 | * | ||
25 | + * bs must be drained between bdrv_reopen_queue() and bdrv_reopen_multiple(). | ||
26 | */ | ||
27 | static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue, | ||
28 | BlockDriverState *bs, | ||
29 | @@ -XXX,XX +XXX,XX @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue, | ||
30 | BdrvChild *child; | ||
31 | QDict *old_options, *explicit_options; | ||
32 | |||
33 | + /* Make sure that the caller remembered to use a drained section. This is | ||
34 | + * important to avoid graph changes between the recursive queuing here and | ||
35 | + * bdrv_reopen_multiple(). */ | ||
36 | + assert(bs->quiesce_counter > 0); | ||
37 | + | ||
38 | if (bs_queue == NULL) { | ||
39 | bs_queue = g_new0(BlockReopenQueue, 1); | ||
40 | QSIMPLEQ_INIT(bs_queue); | ||
41 | @@ -XXX,XX +XXX,XX @@ BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue, | ||
42 | * If all devices prepare successfully, then the changes are committed | ||
43 | * to all devices. | ||
44 | * | ||
45 | + * All affected nodes must be drained between bdrv_reopen_queue() and | ||
46 | + * bdrv_reopen_multiple(). | ||
47 | */ | ||
48 | int bdrv_reopen_multiple(AioContext *ctx, BlockReopenQueue *bs_queue, Error **errp) | ||
49 | { | ||
50 | @@ -XXX,XX +XXX,XX @@ int bdrv_reopen_multiple(AioContext *ctx, BlockReopenQueue *bs_queue, Error **er | ||
51 | |||
52 | assert(bs_queue != NULL); | ||
53 | |||
54 | - aio_context_release(ctx); | ||
55 | - bdrv_drain_all_begin(); | ||
56 | - aio_context_acquire(ctx); | ||
57 | - | ||
58 | QSIMPLEQ_FOREACH(bs_entry, bs_queue, entry) { | ||
59 | + assert(bs_entry->state.bs->quiesce_counter > 0); | ||
60 | if (bdrv_reopen_prepare(&bs_entry->state, bs_queue, &local_err)) { | ||
61 | error_propagate(errp, local_err); | ||
62 | goto cleanup; | ||
63 | @@ -XXX,XX +XXX,XX @@ cleanup: | ||
64 | } | ||
65 | g_free(bs_queue); | ||
66 | |||
67 | - bdrv_drain_all_end(); | ||
68 | - | ||
69 | return ret; | ||
24 | } | 70 | } |
25 | 71 | ||
26 | int bdrv_activate(BlockDriverState *bs, Error **errp) | 72 | @@ -XXX,XX +XXX,XX @@ int bdrv_reopen(BlockDriverState *bs, int bdrv_flags, Error **errp) |
27 | -{ | ||
28 | - return bdrv_invalidate_cache(bs, errp); | ||
29 | -} | ||
30 | - | ||
31 | -int coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs, Error **errp) | ||
32 | { | 73 | { |
33 | BdrvChild *child, *parent; | 74 | int ret = -1; |
34 | Error *local_err = NULL; | 75 | Error *local_err = NULL; |
35 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs, Error **errp) | 76 | - BlockReopenQueue *queue = bdrv_reopen_queue(NULL, bs, NULL, bdrv_flags); |
77 | + BlockReopenQueue *queue; | ||
78 | |||
79 | + bdrv_subtree_drained_begin(bs); | ||
80 | + | ||
81 | + queue = bdrv_reopen_queue(NULL, bs, NULL, bdrv_flags); | ||
82 | ret = bdrv_reopen_multiple(bdrv_get_aio_context(bs), queue, &local_err); | ||
83 | if (local_err != NULL) { | ||
84 | error_propagate(errp, local_err); | ||
36 | } | 85 | } |
37 | 86 | + | |
38 | QLIST_FOREACH(child, &bs->children, next) { | 87 | + bdrv_subtree_drained_end(bs); |
39 | - bdrv_co_invalidate_cache(child->bs, &local_err); | 88 | + |
40 | + bdrv_activate(child->bs, &local_err); | 89 | return ret; |
41 | if (local_err) { | ||
42 | error_propagate(errp, local_err); | ||
43 | return -EINVAL; | ||
44 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs, Error **errp) | ||
45 | * Note that the required permissions of inactive images are always a | ||
46 | * subset of the permissions required after activating the image. This | ||
47 | * allows us to just get the permissions upfront without restricting | ||
48 | - * drv->bdrv_invalidate_cache(). | ||
49 | + * bdrv_co_invalidate_cache(). | ||
50 | * | ||
51 | * It also means that in error cases, we don't have to try and revert to | ||
52 | * the old permissions (which is an operation that could fail, too). We can | ||
53 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs, Error **errp) | ||
54 | return ret; | ||
55 | } | ||
56 | |||
57 | - if (bs->drv->bdrv_co_invalidate_cache) { | ||
58 | - bs->drv->bdrv_co_invalidate_cache(bs, &local_err); | ||
59 | - if (local_err) { | ||
60 | - bs->open_flags |= BDRV_O_INACTIVE; | ||
61 | - error_propagate(errp, local_err); | ||
62 | - return -EINVAL; | ||
63 | - } | ||
64 | + ret = bdrv_invalidate_cache(bs, errp); | ||
65 | + if (ret < 0) { | ||
66 | + bs->open_flags |= BDRV_O_INACTIVE; | ||
67 | + return ret; | ||
68 | } | ||
69 | |||
70 | FOR_EACH_DIRTY_BITMAP(bs, bm) { | ||
71 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs, Error **errp) | ||
72 | return 0; | ||
73 | } | 90 | } |
74 | 91 | ||
75 | +int coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs, Error **errp) | 92 | diff --git a/block/replication.c b/block/replication.c |
76 | +{ | 93 | index XXXXXXX..XXXXXXX 100644 |
77 | + Error *local_err = NULL; | 94 | --- a/block/replication.c |
95 | +++ b/block/replication.c | ||
96 | @@ -XXX,XX +XXX,XX @@ static void reopen_backing_file(BlockDriverState *bs, bool writable, | ||
97 | new_secondary_flags = s->orig_secondary_flags; | ||
98 | } | ||
99 | |||
100 | + bdrv_subtree_drained_begin(s->hidden_disk->bs); | ||
101 | + bdrv_subtree_drained_begin(s->secondary_disk->bs); | ||
78 | + | 102 | + |
79 | + assert(!(bs->open_flags & BDRV_O_INACTIVE)); | 103 | if (orig_hidden_flags != new_hidden_flags) { |
104 | reopen_queue = bdrv_reopen_queue(reopen_queue, s->hidden_disk->bs, NULL, | ||
105 | new_hidden_flags); | ||
106 | @@ -XXX,XX +XXX,XX @@ static void reopen_backing_file(BlockDriverState *bs, bool writable, | ||
107 | reopen_queue, &local_err); | ||
108 | error_propagate(errp, local_err); | ||
109 | } | ||
80 | + | 110 | + |
81 | + if (bs->drv->bdrv_co_invalidate_cache) { | 111 | + bdrv_subtree_drained_end(s->hidden_disk->bs); |
82 | + bs->drv->bdrv_co_invalidate_cache(bs, &local_err); | 112 | + bdrv_subtree_drained_end(s->secondary_disk->bs); |
83 | + if (local_err) { | 113 | } |
84 | + error_propagate(errp, local_err); | 114 | |
85 | + return -EINVAL; | 115 | static void backup_job_cleanup(BlockDriverState *bs) |
86 | + } | 116 | diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c |
87 | + } | 117 | index XXXXXXX..XXXXXXX 100644 |
118 | --- a/qemu-io-cmds.c | ||
119 | +++ b/qemu-io-cmds.c | ||
120 | @@ -XXX,XX +XXX,XX @@ static int reopen_f(BlockBackend *blk, int argc, char **argv) | ||
121 | opts = qopts ? qemu_opts_to_qdict(qopts, NULL) : NULL; | ||
122 | qemu_opts_reset(&reopen_opts); | ||
123 | |||
124 | + bdrv_subtree_drained_begin(bs); | ||
125 | brq = bdrv_reopen_queue(NULL, bs, opts, flags); | ||
126 | bdrv_reopen_multiple(bdrv_get_aio_context(bs), brq, &local_err); | ||
127 | + bdrv_subtree_drained_end(bs); | ||
88 | + | 128 | + |
89 | + return 0; | 129 | if (local_err) { |
90 | +} | 130 | error_report_err(local_err); |
91 | + | 131 | } else { |
92 | void bdrv_activate_all(Error **errp) | ||
93 | { | ||
94 | BlockDriverState *bs; | ||
95 | -- | 132 | -- |
96 | 2.35.1 | 133 | 2.13.6 |
134 | |||
135 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Stefan Hajnoczi <stefanha@redhat.com> | ||
2 | 1 | ||
3 | Compiler optimizations can cache TLS values across coroutine yield | ||
4 | points, resulting in stale values from the previous thread when a | ||
5 | coroutine is re-entered by a new thread. | ||
6 | |||
7 | Serge Guelton developed an __attribute__((noinline)) wrapper and tested | ||
8 | it with clang and gcc. I formatted his idea according to QEMU's coding | ||
9 | style and wrote documentation. | ||
10 | |||
11 | The compiler can still optimize based on analyzing noinline code, so an | ||
12 | asm volatile barrier with an output constraint is required to prevent | ||
13 | unwanted optimizations. | ||
14 | |||
15 | Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=1952483 | ||
16 | Suggested-by: Serge Guelton <sguelton@redhat.com> | ||
17 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
18 | Message-Id: <20220222140150.27240-2-stefanha@redhat.com> | ||
19 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
20 | --- | ||
21 | include/qemu/coroutine-tls.h | 165 +++++++++++++++++++++++++++++++++++ | ||
22 | 1 file changed, 165 insertions(+) | ||
23 | create mode 100644 include/qemu/coroutine-tls.h | ||
24 | |||
25 | diff --git a/include/qemu/coroutine-tls.h b/include/qemu/coroutine-tls.h | ||
26 | new file mode 100644 | ||
27 | index XXXXXXX..XXXXXXX | ||
28 | --- /dev/null | ||
29 | +++ b/include/qemu/coroutine-tls.h | ||
30 | @@ -XXX,XX +XXX,XX @@ | ||
31 | +/* | ||
32 | + * QEMU Thread Local Storage for coroutines | ||
33 | + * | ||
34 | + * Copyright Red Hat | ||
35 | + * | ||
36 | + * SPDX-License-Identifier: LGPL-2.1-or-later | ||
37 | + * | ||
38 | + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. | ||
39 | + * See the COPYING.LIB file in the top-level directory. | ||
40 | + * | ||
41 | + * It is forbidden to access Thread Local Storage in coroutines because | ||
42 | + * compiler optimizations may cause values to be cached across coroutine | ||
43 | + * re-entry. Coroutines can run in more than one thread through the course of | ||
44 | + * their life, leading bugs when stale TLS values from the wrong thread are | ||
45 | + * used as a result of compiler optimization. | ||
46 | + * | ||
47 | + * An example is: | ||
48 | + * | ||
49 | + * ..code-block:: c | ||
50 | + * :caption: A coroutine that may see the wrong TLS value | ||
51 | + * | ||
52 | + * static __thread AioContext *current_aio_context; | ||
53 | + * ... | ||
54 | + * static void coroutine_fn foo(void) | ||
55 | + * { | ||
56 | + * aio_notify(current_aio_context); | ||
57 | + * qemu_coroutine_yield(); | ||
58 | + * aio_notify(current_aio_context); // <-- may be stale after yielding! | ||
59 | + * } | ||
60 | + * | ||
61 | + * This header provides macros for safely defining variables in Thread Local | ||
62 | + * Storage: | ||
63 | + * | ||
64 | + * ..code-block:: c | ||
65 | + * :caption: A coroutine that safely uses TLS | ||
66 | + * | ||
67 | + * QEMU_DEFINE_STATIC_CO_TLS(AioContext *, current_aio_context) | ||
68 | + * ... | ||
69 | + * static void coroutine_fn foo(void) | ||
70 | + * { | ||
71 | + * aio_notify(get_current_aio_context()); | ||
72 | + * qemu_coroutine_yield(); | ||
73 | + * aio_notify(get_current_aio_context()); // <-- safe | ||
74 | + * } | ||
75 | + */ | ||
76 | + | ||
77 | +#ifndef QEMU_COROUTINE_TLS_H | ||
78 | +#define QEMU_COROUTINE_TLS_H | ||
79 | + | ||
80 | +/* | ||
81 | + * To stop the compiler from caching TLS values we define accessor functions | ||
82 | + * with __attribute__((noinline)) plus asm volatile("") to prevent | ||
83 | + * optimizations that override noinline. | ||
84 | + * | ||
85 | + * The compiler can still analyze noinline code and make optimizations based on | ||
86 | + * that knowledge, so an inline asm output operand is used to prevent | ||
87 | + * optimizations that make assumptions about the address of the TLS variable. | ||
88 | + * | ||
89 | + * This is fragile and ultimately needs to be solved by a mechanism that is | ||
90 | + * guaranteed to work by the compiler (e.g. stackless coroutines), but for now | ||
91 | + * we use this approach to prevent issues. | ||
92 | + */ | ||
93 | + | ||
94 | +/** | ||
95 | + * QEMU_DECLARE_CO_TLS: | ||
96 | + * @type: the variable's C type | ||
97 | + * @var: the variable name | ||
98 | + * | ||
99 | + * Declare an extern variable in Thread Local Storage from a header file: | ||
100 | + * | ||
101 | + * .. code-block:: c | ||
102 | + * :caption: Declaring an extern variable in Thread Local Storage | ||
103 | + * | ||
104 | + * QEMU_DECLARE_CO_TLS(int, my_count) | ||
105 | + * ... | ||
106 | + * int c = get_my_count(); | ||
107 | + * set_my_count(c + 1); | ||
108 | + * *get_ptr_my_count() = 0; | ||
109 | + * | ||
110 | + * This is a coroutine-safe replacement for the __thread keyword and is | ||
111 | + * equivalent to the following code: | ||
112 | + * | ||
113 | + * .. code-block:: c | ||
114 | + * :caption: Declaring a TLS variable using __thread | ||
115 | + * | ||
116 | + * extern __thread int my_count; | ||
117 | + * ... | ||
118 | + * int c = my_count; | ||
119 | + * my_count = c + 1; | ||
120 | + * *(&my_count) = 0; | ||
121 | + */ | ||
122 | +#define QEMU_DECLARE_CO_TLS(type, var) \ | ||
123 | + __attribute__((noinline)) type get_##var(void); \ | ||
124 | + __attribute__((noinline)) void set_##var(type v); \ | ||
125 | + __attribute__((noinline)) type *get_ptr_##var(void); | ||
126 | + | ||
127 | +/** | ||
128 | + * QEMU_DEFINE_CO_TLS: | ||
129 | + * @type: the variable's C type | ||
130 | + * @var: the variable name | ||
131 | + * | ||
132 | + * Define a variable in Thread Local Storage that was previously declared from | ||
133 | + * a header file with QEMU_DECLARE_CO_TLS(): | ||
134 | + * | ||
135 | + * .. code-block:: c | ||
136 | + * :caption: Defining a variable in Thread Local Storage | ||
137 | + * | ||
138 | + * QEMU_DEFINE_CO_TLS(int, my_count) | ||
139 | + * | ||
140 | + * This is a coroutine-safe replacement for the __thread keyword and is | ||
141 | + * equivalent to the following code: | ||
142 | + * | ||
143 | + * .. code-block:: c | ||
144 | + * :caption: Defining a TLS variable using __thread | ||
145 | + * | ||
146 | + * __thread int my_count; | ||
147 | + */ | ||
148 | +#define QEMU_DEFINE_CO_TLS(type, var) \ | ||
149 | + static __thread type co_tls_##var; \ | ||
150 | + type get_##var(void) { asm volatile(""); return co_tls_##var; } \ | ||
151 | + void set_##var(type v) { asm volatile(""); co_tls_##var = v; } \ | ||
152 | + type *get_ptr_##var(void) \ | ||
153 | + { type *ptr = &co_tls_##var; asm volatile("" : "+rm" (ptr)); return ptr; } | ||
154 | + | ||
155 | +/** | ||
156 | + * QEMU_DEFINE_STATIC_CO_TLS: | ||
157 | + * @type: the variable's C type | ||
158 | + * @var: the variable name | ||
159 | + * | ||
160 | + * Define a static variable in Thread Local Storage: | ||
161 | + * | ||
162 | + * .. code-block:: c | ||
163 | + * :caption: Defining a static variable in Thread Local Storage | ||
164 | + * | ||
165 | + * QEMU_DEFINE_STATIC_CO_TLS(int, my_count) | ||
166 | + * ... | ||
167 | + * int c = get_my_count(); | ||
168 | + * set_my_count(c + 1); | ||
169 | + * *get_ptr_my_count() = 0; | ||
170 | + * | ||
171 | + * This is a coroutine-safe replacement for the __thread keyword and is | ||
172 | + * equivalent to the following code: | ||
173 | + * | ||
174 | + * .. code-block:: c | ||
175 | + * :caption: Defining a static TLS variable using __thread | ||
176 | + * | ||
177 | + * static __thread int my_count; | ||
178 | + * ... | ||
179 | + * int c = my_count; | ||
180 | + * my_count = c + 1; | ||
181 | + * *(&my_count) = 0; | ||
182 | + */ | ||
183 | +#define QEMU_DEFINE_STATIC_CO_TLS(type, var) \ | ||
184 | + static __thread type co_tls_##var; \ | ||
185 | + static __attribute__((noinline, unused)) \ | ||
186 | + type get_##var(void) \ | ||
187 | + { asm volatile(""); return co_tls_##var; } \ | ||
188 | + static __attribute__((noinline, unused)) \ | ||
189 | + void set_##var(type v) \ | ||
190 | + { asm volatile(""); co_tls_##var = v; } \ | ||
191 | + static __attribute__((noinline, unused)) \ | ||
192 | + type *get_ptr_##var(void) \ | ||
193 | + { type *ptr = &co_tls_##var; asm volatile("" : "+rm" (ptr)); return ptr; } | ||
194 | + | ||
195 | +#endif /* QEMU_COROUTINE_TLS_H */ | ||
196 | -- | ||
197 | 2.35.1 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Hanna Reitz <hreitz@redhat.com> | ||
2 | 1 | ||
3 | In contrast to qemu-nbd (where it is called --fork) and the system | ||
4 | emulator, QSD does not have a --daemonize switch yet. Just like them, | ||
5 | QSD allows setting up block devices and exports on the command line. | ||
6 | When doing so, it is often necessary for whoever invoked the QSD to wait | ||
7 | until these exports are fully set up. A --daemonize switch allows | ||
8 | precisely this, by virtue of the parent process exiting once everything | ||
9 | is set up. | ||
10 | |||
11 | Note that there are alternative ways of waiting for all exports to be | ||
12 | set up, for example: | ||
13 | - Passing the --pidfile option and waiting until the respective file | ||
14 | exists (but I do not know if there is a way of implementing this | ||
15 | without a busy wait loop) | ||
16 | - Set up some network server (e.g. on a Unix socket) and have the QSD | ||
17 | connect to it after all arguments have been processed by appending | ||
18 | corresponding --chardev and --monitor options to the command line, | ||
19 | and then wait until the QSD connects | ||
20 | |||
21 | Having a --daemonize option would make this simpler, though, without | ||
22 | having to rely on additional tools (to set up a network server) or busy | ||
23 | waiting. | ||
24 | |||
25 | Implementing a --daemonize switch means having to fork the QSD process. | ||
26 | Ideally, we should do this as early as possible: All the parent process | ||
27 | has to do is to wait for the child process to signal completion of its | ||
28 | set-up phase, and therefore there is basically no initialization that | ||
29 | needs to be done before the fork. On the other hand, forking after | ||
30 | initialization steps means having to consider how those steps (like | ||
31 | setting up the block layer or QMP) interact with a later fork, which is | ||
32 | often not trivial. | ||
33 | |||
34 | In order to fork this early, we must scan the command line for | ||
35 | --daemonize long before our current process_options() call. Instead of | ||
36 | adding custom new code to do so, just reuse process_options() and give | ||
37 | it a @pre_init_pass argument to distinguish the two passes. I believe | ||
38 | there are some other switches but --daemonize that deserve parsing in | ||
39 | the first pass: | ||
40 | |||
41 | - --help and --version are supposed to only print some text and then | ||
42 | immediately exit (so any initialization we do would be for naught). | ||
43 | This changes behavior, because now "--blockdev inv-drv --help" will | ||
44 | print a help text instead of complaining about the --blockdev | ||
45 | argument. | ||
46 | Note that this is similar in behavior to other tools, though: "--help" | ||
47 | is generally immediately acted upon when finding it in the argument | ||
48 | list, potentially before other arguments (even ones before it) are | ||
49 | acted on. For example, "ls /does-not-exist --help" prints a help text | ||
50 | and does not complain about ENOENT. | ||
51 | |||
52 | - --pidfile does not need initialization, and is already exempted from | ||
53 | the sequential order that process_options() claims to strictly follow | ||
54 | (the PID file is only created after all arguments are processed, not | ||
55 | at the time the --pidfile argument appears), so it makes sense to | ||
56 | include it in the same category as --daemonize. | ||
57 | |||
58 | - Invalid arguments should always be reported as soon as possible. (The | ||
59 | same caveat with --help applies: That means that "--blockdev inv-drv | ||
60 | --inv-arg" will now complain about --inv-arg, not inv-drv.) | ||
61 | |||
62 | This patch does make some references to --daemonize without having | ||
63 | implemented it yet, but that will happen in the next patch. | ||
64 | |||
65 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
66 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
67 | Message-Id: <20220303164814.284974-3-hreitz@redhat.com> | ||
68 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
69 | --- | ||
70 | storage-daemon/qemu-storage-daemon.c | 43 ++++++++++++++++++++++++---- | ||
71 | 1 file changed, 38 insertions(+), 5 deletions(-) | ||
72 | |||
73 | diff --git a/storage-daemon/qemu-storage-daemon.c b/storage-daemon/qemu-storage-daemon.c | ||
74 | index XXXXXXX..XXXXXXX 100644 | ||
75 | --- a/storage-daemon/qemu-storage-daemon.c | ||
76 | +++ b/storage-daemon/qemu-storage-daemon.c | ||
77 | @@ -XXX,XX +XXX,XX @@ static int getopt_set_loc(int argc, char **argv, const char *optstring, | ||
78 | return c; | ||
79 | } | ||
80 | |||
81 | -static void process_options(int argc, char *argv[]) | ||
82 | +/** | ||
83 | + * Process QSD command-line arguments. | ||
84 | + * | ||
85 | + * This is done in two passes: | ||
86 | + * | ||
87 | + * First (@pre_init_pass is true), we do a pass where all global | ||
88 | + * arguments pertaining to the QSD process (like --help or --daemonize) | ||
89 | + * are processed. This pass is done before most of the QEMU-specific | ||
90 | + * initialization steps (e.g. initializing the block layer or QMP), and | ||
91 | + * so must only process arguments that are not really QEMU-specific. | ||
92 | + * | ||
93 | + * Second (@pre_init_pass is false), we (sequentially) process all | ||
94 | + * QEMU/QSD-specific arguments. Many of these arguments are effectively | ||
95 | + * translated to QMP commands (like --blockdev for blockdev-add, or | ||
96 | + * --export for block-export-add). | ||
97 | + */ | ||
98 | +static void process_options(int argc, char *argv[], bool pre_init_pass) | ||
99 | { | ||
100 | int c; | ||
101 | |||
102 | @@ -XXX,XX +XXX,XX @@ static void process_options(int argc, char *argv[]) | ||
103 | }; | ||
104 | |||
105 | /* | ||
106 | - * In contrast to the system emulator, options are processed in the order | ||
107 | - * they are given on the command lines. This means that things must be | ||
108 | - * defined first before they can be referenced in another option. | ||
109 | + * In contrast to the system emulator, QEMU-specific options are processed | ||
110 | + * in the order they are given on the command lines. This means that things | ||
111 | + * must be defined first before they can be referenced in another option. | ||
112 | */ | ||
113 | + optind = 1; | ||
114 | while ((c = getopt_set_loc(argc, argv, "-hT:V", long_options)) != -1) { | ||
115 | + bool handle_option_pre_init; | ||
116 | + | ||
117 | + /* Should this argument be processed in the pre-init pass? */ | ||
118 | + handle_option_pre_init = | ||
119 | + c == '?' || | ||
120 | + c == 'h' || | ||
121 | + c == 'V' || | ||
122 | + c == OPTION_PIDFILE; | ||
123 | + | ||
124 | + /* Process every option only in its respective pass */ | ||
125 | + if (pre_init_pass != handle_option_pre_init) { | ||
126 | + continue; | ||
127 | + } | ||
128 | + | ||
129 | switch (c) { | ||
130 | case '?': | ||
131 | exit(EXIT_FAILURE); | ||
132 | @@ -XXX,XX +XXX,XX @@ int main(int argc, char *argv[]) | ||
133 | qemu_init_exec_dir(argv[0]); | ||
134 | os_setup_signal_handling(); | ||
135 | |||
136 | + process_options(argc, argv, true); | ||
137 | + | ||
138 | module_call_init(MODULE_INIT_QOM); | ||
139 | module_call_init(MODULE_INIT_TRACE); | ||
140 | qemu_add_opts(&qemu_trace_opts); | ||
141 | @@ -XXX,XX +XXX,XX @@ int main(int argc, char *argv[]) | ||
142 | qemu_set_log(LOG_TRACE); | ||
143 | |||
144 | qemu_init_main_loop(&error_fatal); | ||
145 | - process_options(argc, argv); | ||
146 | + process_options(argc, argv, false); | ||
147 | |||
148 | /* | ||
149 | * Write the pid file after creating chardevs, exports, and NBD servers but | ||
150 | -- | ||
151 | 2.35.1 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Hanna Reitz <hreitz@redhat.com> | ||
2 | 1 | ||
3 | To implement this, we reuse the existing daemonizing functions from the | ||
4 | system emulator, which mainly do the following: | ||
5 | - Fork off a child process, and set up a pipe between parent and child | ||
6 | - The parent process waits until the child sends a status byte over the | ||
7 | pipe (0 means that the child was set up successfully; anything else | ||
8 | (including errors or EOF) means that the child was not set up | ||
9 | successfully), and then exits with an appropriate exit status | ||
10 | - The child process enters a new session (forking off again), changes | ||
11 | the umask, and will ignore terminal signals from then on | ||
12 | - Once set-up is complete, the child will chdir to /, redirect all | ||
13 | standard I/O streams to /dev/null, and tell the parent that set-up has | ||
14 | been completed successfully | ||
15 | |||
16 | In contrast to qemu-nbd's --fork implementation, during the set up | ||
17 | phase, error messages are not piped through the parent process. | ||
18 | qemu-nbd mainly does this to detect errors, though (while os_daemonize() | ||
19 | has the child explicitly signal success after set up); because we do not | ||
20 | redirect stderr after forking, error messages continue to appear on | ||
21 | whatever the parent's stderr was (until set up is complete). | ||
22 | |||
23 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
24 | Message-Id: <20220303164814.284974-4-hreitz@redhat.com> | ||
25 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
26 | --- | ||
27 | docs/tools/qemu-storage-daemon.rst | 7 +++++++ | ||
28 | storage-daemon/qemu-storage-daemon.c | 15 +++++++++++++++ | ||
29 | 2 files changed, 22 insertions(+) | ||
30 | |||
31 | diff --git a/docs/tools/qemu-storage-daemon.rst b/docs/tools/qemu-storage-daemon.rst | ||
32 | index XXXXXXX..XXXXXXX 100644 | ||
33 | --- a/docs/tools/qemu-storage-daemon.rst | ||
34 | +++ b/docs/tools/qemu-storage-daemon.rst | ||
35 | @@ -XXX,XX +XXX,XX @@ Standard options: | ||
36 | created but before accepting connections. The daemon has started successfully | ||
37 | when the pid file is written and clients may begin connecting. | ||
38 | |||
39 | +.. option:: --daemonize | ||
40 | + | ||
41 | + Daemonize the process. The parent process will exit once startup is complete | ||
42 | + (i.e., after the pid file has been or would have been written) or failure | ||
43 | + occurs. Its exit code reflects whether the child has started up successfully | ||
44 | + or failed to do so. | ||
45 | + | ||
46 | Examples | ||
47 | -------- | ||
48 | Launch the daemon with QMP monitor socket ``qmp.sock`` so clients can execute | ||
49 | diff --git a/storage-daemon/qemu-storage-daemon.c b/storage-daemon/qemu-storage-daemon.c | ||
50 | index XXXXXXX..XXXXXXX 100644 | ||
51 | --- a/storage-daemon/qemu-storage-daemon.c | ||
52 | +++ b/storage-daemon/qemu-storage-daemon.c | ||
53 | @@ -XXX,XX +XXX,XX @@ static void help(void) | ||
54 | " --chardev <options> configure a character device backend\n" | ||
55 | " (see the qemu(1) man page for possible options)\n" | ||
56 | "\n" | ||
57 | +" --daemonize daemonize the process, and have the parent exit\n" | ||
58 | +" once startup is complete\n" | ||
59 | +"\n" | ||
60 | " --export [type=]nbd,id=<id>,node-name=<node-name>[,name=<export-name>]\n" | ||
61 | " [,writable=on|off][,bitmap=<name>]\n" | ||
62 | " export the specified block node over NBD\n" | ||
63 | @@ -XXX,XX +XXX,XX @@ QEMU_HELP_BOTTOM "\n", | ||
64 | enum { | ||
65 | OPTION_BLOCKDEV = 256, | ||
66 | OPTION_CHARDEV, | ||
67 | + OPTION_DAEMONIZE, | ||
68 | OPTION_EXPORT, | ||
69 | OPTION_MONITOR, | ||
70 | OPTION_NBD_SERVER, | ||
71 | @@ -XXX,XX +XXX,XX @@ static void process_options(int argc, char *argv[], bool pre_init_pass) | ||
72 | static const struct option long_options[] = { | ||
73 | {"blockdev", required_argument, NULL, OPTION_BLOCKDEV}, | ||
74 | {"chardev", required_argument, NULL, OPTION_CHARDEV}, | ||
75 | + {"daemonize", no_argument, NULL, OPTION_DAEMONIZE}, | ||
76 | {"export", required_argument, NULL, OPTION_EXPORT}, | ||
77 | {"help", no_argument, NULL, 'h'}, | ||
78 | {"monitor", required_argument, NULL, OPTION_MONITOR}, | ||
79 | @@ -XXX,XX +XXX,XX @@ static void process_options(int argc, char *argv[], bool pre_init_pass) | ||
80 | c == '?' || | ||
81 | c == 'h' || | ||
82 | c == 'V' || | ||
83 | + c == OPTION_DAEMONIZE || | ||
84 | c == OPTION_PIDFILE; | ||
85 | |||
86 | /* Process every option only in its respective pass */ | ||
87 | @@ -XXX,XX +XXX,XX @@ static void process_options(int argc, char *argv[], bool pre_init_pass) | ||
88 | qemu_opts_del(opts); | ||
89 | break; | ||
90 | } | ||
91 | + case OPTION_DAEMONIZE: | ||
92 | + if (os_set_daemonize(true) < 0) { | ||
93 | + error_report("--daemonize not supported in this build"); | ||
94 | + exit(EXIT_FAILURE); | ||
95 | + } | ||
96 | + break; | ||
97 | case OPTION_EXPORT: | ||
98 | { | ||
99 | Visitor *v; | ||
100 | @@ -XXX,XX +XXX,XX @@ int main(int argc, char *argv[]) | ||
101 | |||
102 | process_options(argc, argv, true); | ||
103 | |||
104 | + os_daemonize(); | ||
105 | + | ||
106 | module_call_init(MODULE_INIT_QOM); | ||
107 | module_call_init(MODULE_INIT_TRACE); | ||
108 | qemu_add_opts(&qemu_trace_opts); | ||
109 | @@ -XXX,XX +XXX,XX @@ int main(int argc, char *argv[]) | ||
110 | * it. | ||
111 | */ | ||
112 | pid_file_init(); | ||
113 | + os_setup_post(); | ||
114 | |||
115 | while (!exit_requested) { | ||
116 | main_loop_wait(false); | ||
117 | -- | ||
118 | 2.35.1 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Hanna Reitz <hreitz@redhat.com> | ||
2 | 1 | ||
3 | 185 tests quitting qemu while a block job is active. It does not | ||
4 | specifically test quitting qemu while a mirror or active commit job is | ||
5 | in its READY phase. | ||
6 | |||
7 | Add two test cases for this, where we respectively mirror or commit to | ||
8 | an external QSD instance, which provides a throttled block device. qemu | ||
9 | is supposed to cancel the job so that it can quit as soon as possible | ||
10 | instead of waiting for the job to complete (which it did before 6.2). | ||
11 | |||
12 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
13 | Message-Id: <20220303164814.284974-5-hreitz@redhat.com> | ||
14 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
15 | --- | ||
16 | tests/qemu-iotests/185 | 190 ++++++++++++++++++++++++++++++++++++- | ||
17 | tests/qemu-iotests/185.out | 48 ++++++++++ | ||
18 | 2 files changed, 237 insertions(+), 1 deletion(-) | ||
19 | |||
20 | diff --git a/tests/qemu-iotests/185 b/tests/qemu-iotests/185 | ||
21 | index XXXXXXX..XXXXXXX 100755 | ||
22 | --- a/tests/qemu-iotests/185 | ||
23 | +++ b/tests/qemu-iotests/185 | ||
24 | @@ -XXX,XX +XXX,XX @@ _cleanup() | ||
25 | _rm_test_img "${TEST_IMG}.copy" | ||
26 | _cleanup_test_img | ||
27 | _cleanup_qemu | ||
28 | + | ||
29 | + if [ -f "$TEST_DIR/qsd.pid" ]; then | ||
30 | + kill -SIGKILL "$(cat "$TEST_DIR/qsd.pid")" | ||
31 | + rm -f "$TEST_DIR/qsd.pid" | ||
32 | + fi | ||
33 | + rm -f "$SOCK_DIR/qsd.sock" | ||
34 | } | ||
35 | trap "_cleanup; exit \$status" 0 1 2 3 15 | ||
36 | |||
37 | @@ -XXX,XX +XXX,XX @@ _supported_fmt qcow2 | ||
38 | _supported_proto file | ||
39 | _supported_os Linux | ||
40 | |||
41 | -size=64M | ||
42 | +size=$((64 * 1048576)) | ||
43 | TEST_IMG="${TEST_IMG}.base" _make_test_img $size | ||
44 | |||
45 | echo | ||
46 | @@ -XXX,XX +XXX,XX @@ wait=1 _cleanup_qemu | grep -v 'JOB_STATUS_CHANGE' | ||
47 | |||
48 | _check_test_img | ||
49 | |||
50 | +echo | ||
51 | +echo === Start mirror to throttled QSD and exit qemu === | ||
52 | +echo | ||
53 | + | ||
54 | +# Mirror to a throttled QSD instance (so that qemu cannot drain the | ||
55 | +# throttling), wait for READY, then write some data to the device, | ||
56 | +# and then quit qemu. | ||
57 | +# (qemu should force-cancel the job and not wait for the data to be | ||
58 | +# written to the target.) | ||
59 | + | ||
60 | +_make_test_img $size | ||
61 | + | ||
62 | +# Will be used by this and the next case | ||
63 | +set_up_throttled_qsd() { | ||
64 | + $QSD \ | ||
65 | + --object throttle-group,id=thrgr,limits.bps-total=1048576 \ | ||
66 | + --blockdev null-co,node-name=null,size=$size \ | ||
67 | + --blockdev throttle,node-name=throttled,throttle-group=thrgr,file=null \ | ||
68 | + --nbd-server addr.type=unix,addr.path="$SOCK_DIR/qsd.sock" \ | ||
69 | + --export nbd,id=exp,node-name=throttled,name=target,writable=true \ | ||
70 | + --pidfile "$TEST_DIR/qsd.pid" \ | ||
71 | + --daemonize | ||
72 | +} | ||
73 | + | ||
74 | +set_up_throttled_qsd | ||
75 | + | ||
76 | +# Need a virtio-blk device so that qemu-io writes will not block the monitor | ||
77 | +_launch_qemu \ | ||
78 | + --blockdev file,node-name=source-proto,filename="$TEST_IMG" \ | ||
79 | + --blockdev qcow2,node-name=source-fmt,file=source-proto \ | ||
80 | + --device virtio-blk,id=vblk,drive=source-fmt \ | ||
81 | + --blockdev "{\"driver\": \"nbd\", | ||
82 | + \"node-name\": \"target\", | ||
83 | + \"server\": { | ||
84 | + \"type\": \"unix\", | ||
85 | + \"path\": \"$SOCK_DIR/qsd.sock\" | ||
86 | + }, | ||
87 | + \"export\": \"target\"}" | ||
88 | + | ||
89 | +h=$QEMU_HANDLE | ||
90 | +_send_qemu_cmd $h '{"execute": "qmp_capabilities"}' 'return' | ||
91 | + | ||
92 | +# Use sync=top, so the first pass will not copy the whole image | ||
93 | +_send_qemu_cmd $h \ | ||
94 | + '{"execute": "blockdev-mirror", | ||
95 | + "arguments": { | ||
96 | + "job-id": "mirror", | ||
97 | + "device": "source-fmt", | ||
98 | + "target": "target", | ||
99 | + "sync": "top" | ||
100 | + }}' \ | ||
101 | + 'return' \ | ||
102 | + | grep -v JOB_STATUS_CHANGE # Ignore these events during creation | ||
103 | + | ||
104 | +# This too will be used by this and the next case | ||
105 | +# $1: QEMU handle | ||
106 | +# $2: Image size | ||
107 | +wait_for_job_and_quit() { | ||
108 | + h=$1 | ||
109 | + size=$2 | ||
110 | + | ||
111 | + # List of expected events | ||
112 | + capture_events='BLOCK_JOB_READY JOB_STATUS_CHANGE' | ||
113 | + _wait_event $h 'BLOCK_JOB_READY' | ||
114 | + QEMU_EVENTS= # Ignore all JOB_STATUS_CHANGE events that came before READY | ||
115 | + | ||
116 | + # Write something to the device for post-READY mirroring. Write it in | ||
117 | + # blocks matching the cluster size, each spaced one block apart, so | ||
118 | + # that the mirror job will have to spawn one request per cluster. | ||
119 | + # Because the number of concurrent requests is limited (to 16), this | ||
120 | + # limits the number of bytes concurrently in flight, which speeds up | ||
121 | + # cancelling the job (in-flight requests still are waited for). | ||
122 | + # To limit the number of bytes in flight, we could alternatively pass | ||
123 | + # something for blockdev-mirror's @buf-size parameter, but | ||
124 | + # block-commit does not have such a parameter, so we need to figure | ||
125 | + # something out that works for both. | ||
126 | + | ||
127 | + cluster_size=65536 | ||
128 | + step=$((cluster_size * 2)) | ||
129 | + | ||
130 | + echo '--- Writing data to the virtio-blk device ---' | ||
131 | + | ||
132 | + for ofs in $(seq 0 $step $((size - step))); do | ||
133 | + qemu_io_cmd="qemu-io -d vblk/virtio-backend " | ||
134 | + qemu_io_cmd+="\\\"aio_write $ofs $cluster_size\\\"" | ||
135 | + | ||
136 | + # Do not include these requests in the reference output | ||
137 | + # (it's just too much) | ||
138 | + silent=yes _send_qemu_cmd $h \ | ||
139 | + "{\"execute\": \"human-monitor-command\", | ||
140 | + \"arguments\": { | ||
141 | + \"command-line\": \"$qemu_io_cmd\" | ||
142 | + }}" \ | ||
143 | + 'return' | ||
144 | + done | ||
145 | + | ||
146 | + # Wait until the job's length is updated to reflect the write requests | ||
147 | + | ||
148 | + # We have written to half of the device, so this is the expected job length | ||
149 | + final_len=$((size / 2)) | ||
150 | + timeout=100 # unit: 0.1 seconds | ||
151 | + while true; do | ||
152 | + len=$( | ||
153 | + _send_qemu_cmd $h \ | ||
154 | + '{"execute": "query-block-jobs"}' \ | ||
155 | + 'return.*"len": [0-9]\+' \ | ||
156 | + | grep 'return.*"len": [0-9]\+' \ | ||
157 | + | sed -e 's/.*"len": \([0-9]\+\).*/\1/' | ||
158 | + ) | ||
159 | + if [ "$len" -eq "$final_len" ]; then | ||
160 | + break | ||
161 | + fi | ||
162 | + timeout=$((timeout - 1)) | ||
163 | + if [ "$timeout" -eq 0 ]; then | ||
164 | + echo "ERROR: Timeout waiting for job to reach len=$final_len" | ||
165 | + break | ||
166 | + fi | ||
167 | + sleep 0.1 | ||
168 | + done | ||
169 | + | ||
170 | + sleep 1 | ||
171 | + | ||
172 | + _send_qemu_cmd $h \ | ||
173 | + '{"execute": "quit"}' \ | ||
174 | + 'return' | ||
175 | + | ||
176 | + # List of expected events | ||
177 | + capture_events='BLOCK_JOB_CANCELLED JOB_STATUS_CHANGE SHUTDOWN' | ||
178 | + _wait_event $h 'SHUTDOWN' | ||
179 | + QEMU_EVENTS= # Ignore all JOB_STATUS_CHANGE events that came before SHUTDOWN | ||
180 | + _wait_event $h 'JOB_STATUS_CHANGE' # standby | ||
181 | + _wait_event $h 'JOB_STATUS_CHANGE' # ready | ||
182 | + _wait_event $h 'JOB_STATUS_CHANGE' # aborting | ||
183 | + # Filter the offset (depends on when exactly `quit` was issued) | ||
184 | + _wait_event $h 'BLOCK_JOB_CANCELLED' \ | ||
185 | + | sed -e 's/"offset": [0-9]\+/"offset": (filtered)/' | ||
186 | + _wait_event $h 'JOB_STATUS_CHANGE' # concluded | ||
187 | + _wait_event $h 'JOB_STATUS_CHANGE' # null | ||
188 | + | ||
189 | + wait=yes _cleanup_qemu | ||
190 | + | ||
191 | + kill -SIGTERM "$(cat "$TEST_DIR/qsd.pid")" | ||
192 | +} | ||
193 | + | ||
194 | +wait_for_job_and_quit $h $size | ||
195 | + | ||
196 | +echo | ||
197 | +echo === Start active commit to throttled QSD and exit qemu === | ||
198 | +echo | ||
199 | + | ||
200 | +# Same as the above, but instead of mirroring, do an active commit | ||
201 | + | ||
202 | +_make_test_img $size | ||
203 | + | ||
204 | +set_up_throttled_qsd | ||
205 | + | ||
206 | +_launch_qemu \ | ||
207 | + --blockdev "{\"driver\": \"nbd\", | ||
208 | + \"node-name\": \"target\", | ||
209 | + \"server\": { | ||
210 | + \"type\": \"unix\", | ||
211 | + \"path\": \"$SOCK_DIR/qsd.sock\" | ||
212 | + }, | ||
213 | + \"export\": \"target\"}" \ | ||
214 | + --blockdev file,node-name=source-proto,filename="$TEST_IMG" \ | ||
215 | + --blockdev qcow2,node-name=source-fmt,file=source-proto,backing=target \ | ||
216 | + --device virtio-blk,id=vblk,drive=source-fmt | ||
217 | + | ||
218 | +h=$QEMU_HANDLE | ||
219 | +_send_qemu_cmd $h '{"execute": "qmp_capabilities"}' 'return' | ||
220 | + | ||
221 | +_send_qemu_cmd $h \ | ||
222 | + '{"execute": "block-commit", | ||
223 | + "arguments": { | ||
224 | + "job-id": "commit", | ||
225 | + "device": "source-fmt" | ||
226 | + }}' \ | ||
227 | + 'return' \ | ||
228 | + | grep -v JOB_STATUS_CHANGE # Ignore these events during creation | ||
229 | + | ||
230 | +wait_for_job_and_quit $h $size | ||
231 | + | ||
232 | # success, all done | ||
233 | echo "*** done" | ||
234 | rm -f $seq.full | ||
235 | diff --git a/tests/qemu-iotests/185.out b/tests/qemu-iotests/185.out | ||
236 | index XXXXXXX..XXXXXXX 100644 | ||
237 | --- a/tests/qemu-iotests/185.out | ||
238 | +++ b/tests/qemu-iotests/185.out | ||
239 | @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 cluster_size=65536 extended_l2=off | ||
240 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} | ||
241 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "disk", "len": 67108864, "offset": 524288, "speed": 65536, "type": "stream"}} | ||
242 | No errors were found on the image. | ||
243 | + | ||
244 | +=== Start mirror to throttled QSD and exit qemu === | ||
245 | + | ||
246 | +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 | ||
247 | +{"execute": "qmp_capabilities"} | ||
248 | +{"return": {}} | ||
249 | +{"execute": "blockdev-mirror", | ||
250 | + "arguments": { | ||
251 | + "job-id": "mirror", | ||
252 | + "device": "source-fmt", | ||
253 | + "target": "target", | ||
254 | + "sync": "top" | ||
255 | + }} | ||
256 | +{"return": {}} | ||
257 | +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "mirror", "len": 0, "offset": 0, "speed": 0, "type": "mirror"}} | ||
258 | +--- Writing data to the virtio-blk device --- | ||
259 | +{"execute": "quit"} | ||
260 | +{"return": {}} | ||
261 | +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} | ||
262 | +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "standby", "id": "mirror"}} | ||
263 | +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "mirror"}} | ||
264 | +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "mirror"}} | ||
265 | +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "mirror", "len": 33554432, "offset": (filtered), "speed": 0, "type": "mirror"}} | ||
266 | +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "mirror"}} | ||
267 | +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "mirror"}} | ||
268 | + | ||
269 | +=== Start active commit to throttled QSD and exit qemu === | ||
270 | + | ||
271 | +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 | ||
272 | +{"execute": "qmp_capabilities"} | ||
273 | +{"return": {}} | ||
274 | +{"execute": "block-commit", | ||
275 | + "arguments": { | ||
276 | + "job-id": "commit", | ||
277 | + "device": "source-fmt" | ||
278 | + }} | ||
279 | +{"return": {}} | ||
280 | +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "commit", "len": 0, "offset": 0, "speed": 0, "type": "commit"}} | ||
281 | +--- Writing data to the virtio-blk device --- | ||
282 | +{"execute": "quit"} | ||
283 | +{"return": {}} | ||
284 | +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} | ||
285 | +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "standby", "id": "commit"}} | ||
286 | +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "commit"}} | ||
287 | +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "commit"}} | ||
288 | +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "commit", "len": 33554432, "offset": (filtered), "speed": 0, "type": "commit"}} | ||
289 | +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "commit"}} | ||
290 | +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "commit"}} | ||
291 | *** done | ||
292 | -- | ||
293 | 2.35.1 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
2 | 1 | ||
3 | Righ now, IO_CODE and IO_OR_GS_CODE are nop, as there isn't | ||
4 | really a way to check that a function is only called in I/O. | ||
5 | On the other side, we can use qemu_in_main_thread() to check if | ||
6 | we are in the main loop. | ||
7 | |||
8 | The usage of macros makes easy to extend them in the future without | ||
9 | making changes in all callers. They will also visually help understanding | ||
10 | in which category each function is, without looking at the header. | ||
11 | |||
12 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
13 | Message-Id: <20220303151616.325444-3-eesposit@redhat.com> | ||
14 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
15 | --- | ||
16 | include/qemu/main-loop.h | 18 ++++++++++++++++++ | ||
17 | 1 file changed, 18 insertions(+) | ||
18 | |||
19 | diff --git a/include/qemu/main-loop.h b/include/qemu/main-loop.h | ||
20 | index XXXXXXX..XXXXXXX 100644 | ||
21 | --- a/include/qemu/main-loop.h | ||
22 | +++ b/include/qemu/main-loop.h | ||
23 | @@ -XXX,XX +XXX,XX @@ bool qemu_mutex_iothread_locked(void); | ||
24 | */ | ||
25 | bool qemu_in_main_thread(void); | ||
26 | |||
27 | +/* Mark and check that the function is part of the global state API. */ | ||
28 | +#define GLOBAL_STATE_CODE() \ | ||
29 | + do { \ | ||
30 | + assert(qemu_in_main_thread()); \ | ||
31 | + } while (0) | ||
32 | + | ||
33 | +/* Mark and check that the function is part of the I/O API. */ | ||
34 | +#define IO_CODE() \ | ||
35 | + do { \ | ||
36 | + /* nop */ \ | ||
37 | + } while (0) | ||
38 | + | ||
39 | +/* Mark and check that the function is part of the "I/O OR GS" API. */ | ||
40 | +#define IO_OR_GS_CODE() \ | ||
41 | + do { \ | ||
42 | + /* nop */ \ | ||
43 | + } while (0) | ||
44 | + | ||
45 | /** | ||
46 | * qemu_mutex_lock_iothread: Lock the main loop mutex. | ||
47 | * | ||
48 | -- | ||
49 | 2.35.1 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
2 | 1 | ||
3 | Allow writable exports to get BLK_PERM_RESIZE permission | ||
4 | from creation, in fuse_export_create(). | ||
5 | In this way, there is no need to give the permission in | ||
6 | fuse_do_truncate(), which might be run in an iothread. | ||
7 | |||
8 | Permissions should be set only in the main thread, so | ||
9 | in any case if an iothread tries to set RESIZE, it will | ||
10 | be blocked. | ||
11 | |||
12 | Also assert in fuse_do_truncate that if we give the | ||
13 | RESIZE permission we can then restore the original ones. | ||
14 | |||
15 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
16 | Reviewed-by: Hanna Reitz <hreitz@redhat.com> | ||
17 | Message-Id: <20220303151616.325444-7-eesposit@redhat.com> | ||
18 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
19 | --- | ||
20 | block/export/fuse.c | 25 ++++++++++++++++++------- | ||
21 | 1 file changed, 18 insertions(+), 7 deletions(-) | ||
22 | |||
23 | diff --git a/block/export/fuse.c b/block/export/fuse.c | ||
24 | index XXXXXXX..XXXXXXX 100644 | ||
25 | --- a/block/export/fuse.c | ||
26 | +++ b/block/export/fuse.c | ||
27 | @@ -XXX,XX +XXX,XX @@ static int fuse_export_create(BlockExport *blk_exp, | ||
28 | |||
29 | assert(blk_exp_args->type == BLOCK_EXPORT_TYPE_FUSE); | ||
30 | |||
31 | - /* For growable exports, take the RESIZE permission */ | ||
32 | - if (args->growable) { | ||
33 | + /* For growable and writable exports, take the RESIZE permission */ | ||
34 | + if (args->growable || blk_exp_args->writable) { | ||
35 | uint64_t blk_perm, blk_shared_perm; | ||
36 | |||
37 | blk_get_perm(exp->common.blk, &blk_perm, &blk_shared_perm); | ||
38 | @@ -XXX,XX +XXX,XX @@ static int fuse_do_truncate(const FuseExport *exp, int64_t size, | ||
39 | { | ||
40 | uint64_t blk_perm, blk_shared_perm; | ||
41 | BdrvRequestFlags truncate_flags = 0; | ||
42 | - int ret; | ||
43 | + bool add_resize_perm; | ||
44 | + int ret, ret_check; | ||
45 | + | ||
46 | + /* Growable and writable exports have a permanent RESIZE permission */ | ||
47 | + add_resize_perm = !exp->growable && !exp->writable; | ||
48 | |||
49 | if (req_zero_write) { | ||
50 | truncate_flags |= BDRV_REQ_ZERO_WRITE; | ||
51 | } | ||
52 | |||
53 | - /* Growable exports have a permanent RESIZE permission */ | ||
54 | - if (!exp->growable) { | ||
55 | + if (add_resize_perm) { | ||
56 | + | ||
57 | + if (!qemu_in_main_thread()) { | ||
58 | + /* Changing permissions like below only works in the main thread */ | ||
59 | + return -EPERM; | ||
60 | + } | ||
61 | + | ||
62 | blk_get_perm(exp->common.blk, &blk_perm, &blk_shared_perm); | ||
63 | |||
64 | ret = blk_set_perm(exp->common.blk, blk_perm | BLK_PERM_RESIZE, | ||
65 | @@ -XXX,XX +XXX,XX @@ static int fuse_do_truncate(const FuseExport *exp, int64_t size, | ||
66 | ret = blk_truncate(exp->common.blk, size, true, prealloc, | ||
67 | truncate_flags, NULL); | ||
68 | |||
69 | - if (!exp->growable) { | ||
70 | + if (add_resize_perm) { | ||
71 | /* Must succeed, because we are only giving up the RESIZE permission */ | ||
72 | - blk_set_perm(exp->common.blk, blk_perm, blk_shared_perm, &error_abort); | ||
73 | + ret_check = blk_set_perm(exp->common.blk, blk_perm, | ||
74 | + blk_shared_perm, &error_abort); | ||
75 | + assert(ret_check == 0); | ||
76 | } | ||
77 | |||
78 | return ret; | ||
79 | -- | ||
80 | 2.35.1 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
2 | 1 | ||
3 | Now that we "covered" the three main cases where the | ||
4 | permission API was being used under BQL (fuse, | ||
5 | amend and invalidate_cache), we can safely assert for | ||
6 | the permission functions implemented in block.c | ||
7 | |||
8 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
9 | Message-Id: <20220303151616.325444-11-eesposit@redhat.com> | ||
10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
11 | --- | ||
12 | block.c | 12 ++++++++++++ | ||
13 | 1 file changed, 12 insertions(+) | ||
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 bool bdrv_a_allow_b(BdrvChild *a, BdrvChild *b, Error **errp) | ||
20 | |||
21 | assert(a->bs); | ||
22 | assert(a->bs == b->bs); | ||
23 | + GLOBAL_STATE_CODE(); | ||
24 | |||
25 | if ((b->perm & a->shared_perm) == b->perm) { | ||
26 | return true; | ||
27 | @@ -XXX,XX +XXX,XX @@ static bool bdrv_a_allow_b(BdrvChild *a, BdrvChild *b, Error **errp) | ||
28 | static bool bdrv_parent_perms_conflict(BlockDriverState *bs, Error **errp) | ||
29 | { | ||
30 | BdrvChild *a, *b; | ||
31 | + GLOBAL_STATE_CODE(); | ||
32 | |||
33 | /* | ||
34 | * During the loop we'll look at each pair twice. That's correct because | ||
35 | @@ -XXX,XX +XXX,XX @@ static void bdrv_child_set_perm_abort(void *opaque) | ||
36 | { | ||
37 | BdrvChildSetPermState *s = opaque; | ||
38 | |||
39 | + GLOBAL_STATE_CODE(); | ||
40 | + | ||
41 | s->child->perm = s->old_perm; | ||
42 | s->child->shared_perm = s->old_shared_perm; | ||
43 | } | ||
44 | @@ -XXX,XX +XXX,XX @@ static void bdrv_child_set_perm(BdrvChild *c, uint64_t perm, | ||
45 | uint64_t shared, Transaction *tran) | ||
46 | { | ||
47 | BdrvChildSetPermState *s = g_new(BdrvChildSetPermState, 1); | ||
48 | + GLOBAL_STATE_CODE(); | ||
49 | |||
50 | *s = (BdrvChildSetPermState) { | ||
51 | .child = c, | ||
52 | @@ -XXX,XX +XXX,XX @@ static int bdrv_node_refresh_perm(BlockDriverState *bs, BlockReopenQueue *q, | ||
53 | BdrvChild *c; | ||
54 | int ret; | ||
55 | uint64_t cumulative_perms, cumulative_shared_perms; | ||
56 | + GLOBAL_STATE_CODE(); | ||
57 | |||
58 | bdrv_get_cumulative_perm(bs, &cumulative_perms, &cumulative_shared_perms); | ||
59 | |||
60 | @@ -XXX,XX +XXX,XX @@ static int bdrv_list_refresh_perms(GSList *list, BlockReopenQueue *q, | ||
61 | { | ||
62 | int ret; | ||
63 | BlockDriverState *bs; | ||
64 | + GLOBAL_STATE_CODE(); | ||
65 | |||
66 | for ( ; list; list = list->next) { | ||
67 | bs = list->data; | ||
68 | @@ -XXX,XX +XXX,XX @@ static int bdrv_refresh_perms(BlockDriverState *bs, Error **errp) | ||
69 | int ret; | ||
70 | Transaction *tran = tran_new(); | ||
71 | g_autoptr(GSList) list = bdrv_topological_dfs(NULL, NULL, bs); | ||
72 | + GLOBAL_STATE_CODE(); | ||
73 | |||
74 | ret = bdrv_list_refresh_perms(list, NULL, tran, errp); | ||
75 | tran_finalize(tran, ret); | ||
76 | @@ -XXX,XX +XXX,XX @@ static void bdrv_filter_default_perms(BlockDriverState *bs, BdrvChild *c, | ||
77 | uint64_t perm, uint64_t shared, | ||
78 | uint64_t *nperm, uint64_t *nshared) | ||
79 | { | ||
80 | + GLOBAL_STATE_CODE(); | ||
81 | *nperm = perm & DEFAULT_PERM_PASSTHROUGH; | ||
82 | *nshared = (shared & DEFAULT_PERM_PASSTHROUGH) | DEFAULT_PERM_UNCHANGED; | ||
83 | } | ||
84 | @@ -XXX,XX +XXX,XX @@ static void bdrv_default_perms_for_cow(BlockDriverState *bs, BdrvChild *c, | ||
85 | uint64_t *nperm, uint64_t *nshared) | ||
86 | { | ||
87 | assert(role & BDRV_CHILD_COW); | ||
88 | + GLOBAL_STATE_CODE(); | ||
89 | |||
90 | /* | ||
91 | * We want consistent read from backing files if the parent needs it. | ||
92 | @@ -XXX,XX +XXX,XX @@ static void bdrv_default_perms_for_storage(BlockDriverState *bs, BdrvChild *c, | ||
93 | { | ||
94 | int flags; | ||
95 | |||
96 | + GLOBAL_STATE_CODE(); | ||
97 | assert(role & (BDRV_CHILD_METADATA | BDRV_CHILD_DATA)); | ||
98 | |||
99 | flags = bdrv_reopen_get_flags(reopen_queue, bs); | ||
100 | @@ -XXX,XX +XXX,XX @@ static void xdbg_graph_add_edge(XDbgBlockGraphConstructor *gr, void *parent, | ||
101 | { | ||
102 | BlockPermission qapi_perm; | ||
103 | XDbgBlockGraphEdge *edge; | ||
104 | + GLOBAL_STATE_CODE(); | ||
105 | |||
106 | edge = g_new0(XDbgBlockGraphEdge, 1); | ||
107 | |||
108 | -- | ||
109 | 2.35.1 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
2 | 1 | ||
3 | Since the I/O functions are not many, keep a single file. | ||
4 | Also split the function pointers in BlockJobDriver. | ||
5 | |||
6 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
7 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
8 | Message-Id: <20220303151616.325444-16-eesposit@redhat.com> | ||
9 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
10 | --- | ||
11 | include/block/blockjob_int.h | 28 ++++++++++++++++++++++++++++ | ||
12 | 1 file changed, 28 insertions(+) | ||
13 | |||
14 | diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h | ||
15 | index XXXXXXX..XXXXXXX 100644 | ||
16 | --- a/include/block/blockjob_int.h | ||
17 | +++ b/include/block/blockjob_int.h | ||
18 | @@ -XXX,XX +XXX,XX @@ struct BlockJobDriver { | ||
19 | /** Generic JobDriver callbacks and settings */ | ||
20 | JobDriver job_driver; | ||
21 | |||
22 | + /* | ||
23 | + * I/O API functions. These functions are thread-safe. | ||
24 | + * | ||
25 | + * See include/block/block-io.h for more information about | ||
26 | + * the I/O API. | ||
27 | + */ | ||
28 | + | ||
29 | /* | ||
30 | * Returns whether the job has pending requests for the child or will | ||
31 | * submit new requests before the next pause point. This callback is polled | ||
32 | @@ -XXX,XX +XXX,XX @@ struct BlockJobDriver { | ||
33 | */ | ||
34 | bool (*drained_poll)(BlockJob *job); | ||
35 | |||
36 | + /* | ||
37 | + * Global state (GS) API. These functions run under the BQL. | ||
38 | + * | ||
39 | + * See include/block/block-global-state.h for more information about | ||
40 | + * the GS API. | ||
41 | + */ | ||
42 | + | ||
43 | /* | ||
44 | * If the callback is not NULL, it will be invoked before the job is | ||
45 | * resumed in a new AioContext. This is the place to move any resources | ||
46 | @@ -XXX,XX +XXX,XX @@ struct BlockJobDriver { | ||
47 | void (*set_speed)(BlockJob *job, int64_t speed); | ||
48 | }; | ||
49 | |||
50 | +/* | ||
51 | + * Global state (GS) API. These functions run under the BQL. | ||
52 | + * | ||
53 | + * See include/block/block-global-state.h for more information about | ||
54 | + * the GS API. | ||
55 | + */ | ||
56 | + | ||
57 | /** | ||
58 | * block_job_create: | ||
59 | * @job_id: The id of the newly-created job, or %NULL to have one | ||
60 | @@ -XXX,XX +XXX,XX @@ void block_job_free(Job *job); | ||
61 | */ | ||
62 | void block_job_user_resume(Job *job); | ||
63 | |||
64 | +/* | ||
65 | + * I/O API functions. These functions are thread-safe. | ||
66 | + * | ||
67 | + * See include/block/block-io.h for more information about | ||
68 | + * the I/O API. | ||
69 | + */ | ||
70 | + | ||
71 | /** | ||
72 | * block_job_ratelimit_get_delay: | ||
73 | * | ||
74 | -- | ||
75 | 2.35.1 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
2 | 1 | ||
3 | blockjob functions run always under the BQL lock. | ||
4 | |||
5 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
6 | Message-Id: <20220303151616.325444-19-eesposit@redhat.com> | ||
7 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
8 | --- | ||
9 | include/block/blockjob.h | 29 ++++++++++++++++++++++------- | ||
10 | 1 file changed, 22 insertions(+), 7 deletions(-) | ||
11 | |||
12 | diff --git a/include/block/blockjob.h b/include/block/blockjob.h | ||
13 | index XXXXXXX..XXXXXXX 100644 | ||
14 | --- a/include/block/blockjob.h | ||
15 | +++ b/include/block/blockjob.h | ||
16 | @@ -XXX,XX +XXX,XX @@ typedef struct BlockJob { | ||
17 | GSList *nodes; | ||
18 | } BlockJob; | ||
19 | |||
20 | +/* | ||
21 | + * Global state (GS) API. These functions run under the BQL. | ||
22 | + * | ||
23 | + * See include/block/block-global-state.h for more information about | ||
24 | + * the GS API. | ||
25 | + */ | ||
26 | + | ||
27 | /** | ||
28 | * block_job_next: | ||
29 | * @job: A block job, or %NULL. | ||
30 | @@ -XXX,XX +XXX,XX @@ BlockJobInfo *block_job_query(BlockJob *job, Error **errp); | ||
31 | */ | ||
32 | void block_job_iostatus_reset(BlockJob *job); | ||
33 | |||
34 | +/* | ||
35 | + * block_job_get_aio_context: | ||
36 | + * | ||
37 | + * Returns aio context associated with a block job. | ||
38 | + */ | ||
39 | +AioContext *block_job_get_aio_context(BlockJob *job); | ||
40 | + | ||
41 | + | ||
42 | +/* | ||
43 | + * Common functions that are neither I/O nor Global State. | ||
44 | + * | ||
45 | + * See include/block/block-common.h for more information about | ||
46 | + * the Common API. | ||
47 | + */ | ||
48 | + | ||
49 | /** | ||
50 | * block_job_is_internal: | ||
51 | * @job: The job to determine if it is user-visible or not. | ||
52 | @@ -XXX,XX +XXX,XX @@ bool block_job_is_internal(BlockJob *job); | ||
53 | */ | ||
54 | const BlockJobDriver *block_job_driver(BlockJob *job); | ||
55 | |||
56 | -/* | ||
57 | - * block_job_get_aio_context: | ||
58 | - * | ||
59 | - * Returns aio context associated with a block job. | ||
60 | - */ | ||
61 | -AioContext *block_job_get_aio_context(BlockJob *job); | ||
62 | - | ||
63 | #endif | ||
64 | -- | ||
65 | 2.35.1 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
2 | 1 | ||
3 | blockdev functions run always under the BQL lock. | ||
4 | |||
5 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
6 | Message-Id: <20220303151616.325444-21-eesposit@redhat.com> | ||
7 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
8 | --- | ||
9 | include/sysemu/blockdev.h | 13 ++++++++++--- | ||
10 | 1 file changed, 10 insertions(+), 3 deletions(-) | ||
11 | |||
12 | diff --git a/include/sysemu/blockdev.h b/include/sysemu/blockdev.h | ||
13 | index XXXXXXX..XXXXXXX 100644 | ||
14 | --- a/include/sysemu/blockdev.h | ||
15 | +++ b/include/sysemu/blockdev.h | ||
16 | @@ -XXX,XX +XXX,XX @@ | ||
17 | #include "block/block.h" | ||
18 | #include "qemu/queue.h" | ||
19 | |||
20 | -void blockdev_mark_auto_del(BlockBackend *blk); | ||
21 | -void blockdev_auto_del(BlockBackend *blk); | ||
22 | - | ||
23 | typedef enum { | ||
24 | IF_DEFAULT = -1, /* for use with drive_add() only */ | ||
25 | /* | ||
26 | @@ -XXX,XX +XXX,XX @@ struct DriveInfo { | ||
27 | QTAILQ_ENTRY(DriveInfo) next; | ||
28 | }; | ||
29 | |||
30 | +/* | ||
31 | + * Global state (GS) API. These functions run under the BQL. | ||
32 | + * | ||
33 | + * See include/block/block-global-state.h for more information about | ||
34 | + * the GS API. | ||
35 | + */ | ||
36 | + | ||
37 | +void blockdev_mark_auto_del(BlockBackend *blk); | ||
38 | +void blockdev_auto_del(BlockBackend *blk); | ||
39 | + | ||
40 | DriveInfo *blk_legacy_dinfo(BlockBackend *blk); | ||
41 | DriveInfo *blk_set_legacy_dinfo(BlockBackend *blk, DriveInfo *dinfo); | ||
42 | BlockBackend *blk_by_legacy_dinfo(DriveInfo *dinfo); | ||
43 | -- | ||
44 | 2.35.1 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
2 | 1 | ||
3 | Snapshots run also under the BQL, so they all are | ||
4 | in the global state API. The aiocontext lock that they hold | ||
5 | is currently an overkill and in future could be removed. | ||
6 | |||
7 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
8 | Message-Id: <20220303151616.325444-23-eesposit@redhat.com> | ||
9 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
10 | --- | ||
11 | include/block/snapshot.h | 13 +++++++++++-- | ||
12 | block/snapshot.c | 28 ++++++++++++++++++++++++++++ | ||
13 | migration/savevm.c | 2 ++ | ||
14 | 3 files changed, 41 insertions(+), 2 deletions(-) | ||
15 | |||
16 | diff --git a/include/block/snapshot.h b/include/block/snapshot.h | ||
17 | index XXXXXXX..XXXXXXX 100644 | ||
18 | --- a/include/block/snapshot.h | ||
19 | +++ b/include/block/snapshot.h | ||
20 | @@ -XXX,XX +XXX,XX @@ typedef struct QEMUSnapshotInfo { | ||
21 | uint64_t icount; /* record/replay step */ | ||
22 | } QEMUSnapshotInfo; | ||
23 | |||
24 | +/* | ||
25 | + * Global state (GS) API. These functions run under the BQL. | ||
26 | + * | ||
27 | + * See include/block/block-global-state.h for more information about | ||
28 | + * the GS API. | ||
29 | + */ | ||
30 | + | ||
31 | int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info, | ||
32 | const char *name); | ||
33 | bool bdrv_snapshot_find_by_id_and_name(BlockDriverState *bs, | ||
34 | @@ -XXX,XX +XXX,XX @@ int bdrv_snapshot_load_tmp_by_id_or_name(BlockDriverState *bs, | ||
35 | Error **errp); | ||
36 | |||
37 | |||
38 | -/* Group operations. All block drivers are involved. | ||
39 | +/* | ||
40 | + * Group operations. All block drivers are involved. | ||
41 | * These functions will properly handle dataplane (take aio_context_acquire | ||
42 | - * when appropriate for appropriate block drivers */ | ||
43 | + * when appropriate for appropriate block drivers | ||
44 | + */ | ||
45 | |||
46 | bool bdrv_all_can_snapshot(bool has_devices, strList *devices, | ||
47 | Error **errp); | ||
48 | diff --git a/block/snapshot.c b/block/snapshot.c | ||
49 | index XXXXXXX..XXXXXXX 100644 | ||
50 | --- a/block/snapshot.c | ||
51 | +++ b/block/snapshot.c | ||
52 | @@ -XXX,XX +XXX,XX @@ int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info, | ||
53 | QEMUSnapshotInfo *sn_tab, *sn; | ||
54 | int nb_sns, i, ret; | ||
55 | |||
56 | + GLOBAL_STATE_CODE(); | ||
57 | + | ||
58 | ret = -ENOENT; | ||
59 | nb_sns = bdrv_snapshot_list(bs, &sn_tab); | ||
60 | if (nb_sns < 0) { | ||
61 | @@ -XXX,XX +XXX,XX @@ bool bdrv_snapshot_find_by_id_and_name(BlockDriverState *bs, | ||
62 | bool ret = false; | ||
63 | |||
64 | assert(id || name); | ||
65 | + GLOBAL_STATE_CODE(); | ||
66 | |||
67 | nb_sns = bdrv_snapshot_list(bs, &sn_tab); | ||
68 | if (nb_sns < 0) { | ||
69 | @@ -XXX,XX +XXX,XX @@ static BlockDriverState *bdrv_snapshot_fallback(BlockDriverState *bs) | ||
70 | int bdrv_can_snapshot(BlockDriverState *bs) | ||
71 | { | ||
72 | BlockDriver *drv = bs->drv; | ||
73 | + GLOBAL_STATE_CODE(); | ||
74 | if (!drv || !bdrv_is_inserted(bs) || bdrv_is_read_only(bs)) { | ||
75 | return 0; | ||
76 | } | ||
77 | @@ -XXX,XX +XXX,XX @@ int bdrv_snapshot_create(BlockDriverState *bs, | ||
78 | { | ||
79 | BlockDriver *drv = bs->drv; | ||
80 | BlockDriverState *fallback_bs = bdrv_snapshot_fallback(bs); | ||
81 | + | ||
82 | + GLOBAL_STATE_CODE(); | ||
83 | + | ||
84 | if (!drv) { | ||
85 | return -ENOMEDIUM; | ||
86 | } | ||
87 | @@ -XXX,XX +XXX,XX @@ int bdrv_snapshot_goto(BlockDriverState *bs, | ||
88 | BdrvChild **fallback_ptr; | ||
89 | int ret, open_ret; | ||
90 | |||
91 | + GLOBAL_STATE_CODE(); | ||
92 | + | ||
93 | if (!drv) { | ||
94 | error_setg(errp, "Block driver is closed"); | ||
95 | return -ENOMEDIUM; | ||
96 | @@ -XXX,XX +XXX,XX @@ int bdrv_snapshot_delete(BlockDriverState *bs, | ||
97 | BlockDriverState *fallback_bs = bdrv_snapshot_fallback(bs); | ||
98 | int ret; | ||
99 | |||
100 | + GLOBAL_STATE_CODE(); | ||
101 | + | ||
102 | if (!drv) { | ||
103 | error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM, bdrv_get_device_name(bs)); | ||
104 | return -ENOMEDIUM; | ||
105 | @@ -XXX,XX +XXX,XX @@ int bdrv_snapshot_list(BlockDriverState *bs, | ||
106 | { | ||
107 | BlockDriver *drv = bs->drv; | ||
108 | BlockDriverState *fallback_bs = bdrv_snapshot_fallback(bs); | ||
109 | + | ||
110 | + GLOBAL_STATE_CODE(); | ||
111 | if (!drv) { | ||
112 | return -ENOMEDIUM; | ||
113 | } | ||
114 | @@ -XXX,XX +XXX,XX @@ int bdrv_snapshot_load_tmp(BlockDriverState *bs, | ||
115 | { | ||
116 | BlockDriver *drv = bs->drv; | ||
117 | |||
118 | + GLOBAL_STATE_CODE(); | ||
119 | + | ||
120 | if (!drv) { | ||
121 | error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM, bdrv_get_device_name(bs)); | ||
122 | return -ENOMEDIUM; | ||
123 | @@ -XXX,XX +XXX,XX @@ int bdrv_snapshot_load_tmp_by_id_or_name(BlockDriverState *bs, | ||
124 | int ret; | ||
125 | Error *local_err = NULL; | ||
126 | |||
127 | + GLOBAL_STATE_CODE(); | ||
128 | + | ||
129 | ret = bdrv_snapshot_load_tmp(bs, id_or_name, NULL, &local_err); | ||
130 | if (ret == -ENOENT || ret == -EINVAL) { | ||
131 | error_free(local_err); | ||
132 | @@ -XXX,XX +XXX,XX @@ bool bdrv_all_can_snapshot(bool has_devices, strList *devices, | ||
133 | g_autoptr(GList) bdrvs = NULL; | ||
134 | GList *iterbdrvs; | ||
135 | |||
136 | + GLOBAL_STATE_CODE(); | ||
137 | + | ||
138 | if (bdrv_all_get_snapshot_devices(has_devices, devices, &bdrvs, errp) < 0) { | ||
139 | return false; | ||
140 | } | ||
141 | @@ -XXX,XX +XXX,XX @@ int bdrv_all_delete_snapshot(const char *name, | ||
142 | g_autoptr(GList) bdrvs = NULL; | ||
143 | GList *iterbdrvs; | ||
144 | |||
145 | + GLOBAL_STATE_CODE(); | ||
146 | + | ||
147 | if (bdrv_all_get_snapshot_devices(has_devices, devices, &bdrvs, errp) < 0) { | ||
148 | return -1; | ||
149 | } | ||
150 | @@ -XXX,XX +XXX,XX @@ int bdrv_all_goto_snapshot(const char *name, | ||
151 | g_autoptr(GList) bdrvs = NULL; | ||
152 | GList *iterbdrvs; | ||
153 | |||
154 | + GLOBAL_STATE_CODE(); | ||
155 | + | ||
156 | if (bdrv_all_get_snapshot_devices(has_devices, devices, &bdrvs, errp) < 0) { | ||
157 | return -1; | ||
158 | } | ||
159 | @@ -XXX,XX +XXX,XX @@ int bdrv_all_has_snapshot(const char *name, | ||
160 | g_autoptr(GList) bdrvs = NULL; | ||
161 | GList *iterbdrvs; | ||
162 | |||
163 | + GLOBAL_STATE_CODE(); | ||
164 | + | ||
165 | if (bdrv_all_get_snapshot_devices(has_devices, devices, &bdrvs, errp) < 0) { | ||
166 | return -1; | ||
167 | } | ||
168 | @@ -XXX,XX +XXX,XX @@ int bdrv_all_create_snapshot(QEMUSnapshotInfo *sn, | ||
169 | { | ||
170 | g_autoptr(GList) bdrvs = NULL; | ||
171 | GList *iterbdrvs; | ||
172 | + GLOBAL_STATE_CODE(); | ||
173 | |||
174 | if (bdrv_all_get_snapshot_devices(has_devices, devices, &bdrvs, errp) < 0) { | ||
175 | return -1; | ||
176 | @@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_all_find_vmstate_bs(const char *vmstate_bs, | ||
177 | g_autoptr(GList) bdrvs = NULL; | ||
178 | GList *iterbdrvs; | ||
179 | |||
180 | + GLOBAL_STATE_CODE(); | ||
181 | + | ||
182 | if (bdrv_all_get_snapshot_devices(has_devices, devices, &bdrvs, errp) < 0) { | ||
183 | return NULL; | ||
184 | } | ||
185 | diff --git a/migration/savevm.c b/migration/savevm.c | ||
186 | index XXXXXXX..XXXXXXX 100644 | ||
187 | --- a/migration/savevm.c | ||
188 | +++ b/migration/savevm.c | ||
189 | @@ -XXX,XX +XXX,XX @@ bool save_snapshot(const char *name, bool overwrite, const char *vmstate, | ||
190 | g_autoptr(GDateTime) now = g_date_time_new_now_local(); | ||
191 | AioContext *aio_context; | ||
192 | |||
193 | + GLOBAL_STATE_CODE(); | ||
194 | + | ||
195 | if (migration_is_blocked(errp)) { | ||
196 | return false; | ||
197 | } | ||
198 | -- | ||
199 | 2.35.1 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
2 | 1 | ||
3 | copy-before-write functions always run under BQL. | ||
4 | |||
5 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
6 | Message-Id: <20220303151616.325444-24-eesposit@redhat.com> | ||
7 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
8 | --- | ||
9 | block/copy-before-write.h | 7 +++++++ | ||
10 | block/copy-before-write.c | 2 ++ | ||
11 | 2 files changed, 9 insertions(+) | ||
12 | |||
13 | diff --git a/block/copy-before-write.h b/block/copy-before-write.h | ||
14 | index XXXXXXX..XXXXXXX 100644 | ||
15 | --- a/block/copy-before-write.h | ||
16 | +++ b/block/copy-before-write.h | ||
17 | @@ -XXX,XX +XXX,XX @@ | ||
18 | #include "block/block_int.h" | ||
19 | #include "block/block-copy.h" | ||
20 | |||
21 | +/* | ||
22 | + * Global state (GS) API. These functions run under the BQL. | ||
23 | + * | ||
24 | + * See include/block/block-global-state.h for more information about | ||
25 | + * the GS API. | ||
26 | + */ | ||
27 | + | ||
28 | BlockDriverState *bdrv_cbw_append(BlockDriverState *source, | ||
29 | BlockDriverState *target, | ||
30 | const char *filter_node_name, | ||
31 | diff --git a/block/copy-before-write.c b/block/copy-before-write.c | ||
32 | index XXXXXXX..XXXXXXX 100644 | ||
33 | --- a/block/copy-before-write.c | ||
34 | +++ b/block/copy-before-write.c | ||
35 | @@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_cbw_append(BlockDriverState *source, | ||
36 | QDict *opts; | ||
37 | |||
38 | assert(source->total_sectors == target->total_sectors); | ||
39 | + GLOBAL_STATE_CODE(); | ||
40 | |||
41 | opts = qdict_new(); | ||
42 | qdict_put_str(opts, "driver", "copy-before-write"); | ||
43 | @@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_cbw_append(BlockDriverState *source, | ||
44 | |||
45 | void bdrv_cbw_drop(BlockDriverState *bs) | ||
46 | { | ||
47 | + GLOBAL_STATE_CODE(); | ||
48 | bdrv_drop_filter(bs, &error_abort); | ||
49 | bdrv_unref(bs); | ||
50 | } | ||
51 | -- | ||
52 | 2.35.1 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
2 | 1 | ||
3 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
4 | Message-Id: <20220303151616.325444-28-eesposit@redhat.com> | ||
5 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
6 | --- | ||
7 | include/block/block_int-common.h | 81 ++++++++++++++++++-------------- | ||
8 | 1 file changed, 47 insertions(+), 34 deletions(-) | ||
9 | |||
10 | diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h | ||
11 | index XXXXXXX..XXXXXXX 100644 | ||
12 | --- a/include/block/block_int-common.h | ||
13 | +++ b/include/block/block_int-common.h | ||
14 | @@ -XXX,XX +XXX,XX @@ struct BdrvChildClass { | ||
15 | */ | ||
16 | bool parent_is_bds; | ||
17 | |||
18 | + /* | ||
19 | + * Global state (GS) API. These functions run under the BQL. | ||
20 | + * | ||
21 | + * See include/block/block-global-state.h for more information about | ||
22 | + * the GS API. | ||
23 | + */ | ||
24 | void (*inherit_options)(BdrvChildRole role, bool parent_is_format, | ||
25 | int *child_flags, QDict *child_options, | ||
26 | int parent_flags, QDict *parent_options); | ||
27 | - | ||
28 | void (*change_media)(BdrvChild *child, bool load); | ||
29 | - void (*resize)(BdrvChild *child); | ||
30 | - | ||
31 | - /* | ||
32 | - * Returns a name that is supposedly more useful for human users than the | ||
33 | - * node name for identifying the node in question (in particular, a BB | ||
34 | - * name), or NULL if the parent can't provide a better name. | ||
35 | - */ | ||
36 | - const char *(*get_name)(BdrvChild *child); | ||
37 | |||
38 | /* | ||
39 | * Returns a malloced string that describes the parent of the child for a | ||
40 | @@ -XXX,XX +XXX,XX @@ struct BdrvChildClass { | ||
41 | */ | ||
42 | char *(*get_parent_desc)(BdrvChild *child); | ||
43 | |||
44 | + /* | ||
45 | + * Notifies the parent that the child has been activated/inactivated (e.g. | ||
46 | + * when migration is completing) and it can start/stop requesting | ||
47 | + * permissions and doing I/O on it. | ||
48 | + */ | ||
49 | + void (*activate)(BdrvChild *child, Error **errp); | ||
50 | + int (*inactivate)(BdrvChild *child); | ||
51 | + | ||
52 | + void (*attach)(BdrvChild *child); | ||
53 | + void (*detach)(BdrvChild *child); | ||
54 | + | ||
55 | + /* | ||
56 | + * Notifies the parent that the filename of its child has changed (e.g. | ||
57 | + * because the direct child was removed from the backing chain), so that it | ||
58 | + * can update its reference. | ||
59 | + */ | ||
60 | + int (*update_filename)(BdrvChild *child, BlockDriverState *new_base, | ||
61 | + const char *filename, Error **errp); | ||
62 | + | ||
63 | + bool (*can_set_aio_ctx)(BdrvChild *child, AioContext *ctx, | ||
64 | + GSList **ignore, Error **errp); | ||
65 | + void (*set_aio_ctx)(BdrvChild *child, AioContext *ctx, GSList **ignore); | ||
66 | + | ||
67 | + AioContext *(*get_parent_aio_context)(BdrvChild *child); | ||
68 | + | ||
69 | + /* | ||
70 | + * I/O API functions. These functions are thread-safe. | ||
71 | + * | ||
72 | + * See include/block/block-io.h for more information about | ||
73 | + * the I/O API. | ||
74 | + */ | ||
75 | + | ||
76 | + void (*resize)(BdrvChild *child); | ||
77 | + | ||
78 | + /* | ||
79 | + * Returns a name that is supposedly more useful for human users than the | ||
80 | + * node name for identifying the node in question (in particular, a BB | ||
81 | + * name), or NULL if the parent can't provide a better name. | ||
82 | + */ | ||
83 | + const char *(*get_name)(BdrvChild *child); | ||
84 | + | ||
85 | /* | ||
86 | * If this pair of functions is implemented, the parent doesn't issue new | ||
87 | * requests after returning from .drained_begin() until .drained_end() is | ||
88 | @@ -XXX,XX +XXX,XX @@ struct BdrvChildClass { | ||
89 | * activity on the child has stopped. | ||
90 | */ | ||
91 | bool (*drained_poll)(BdrvChild *child); | ||
92 | - | ||
93 | - /* | ||
94 | - * Notifies the parent that the child has been activated/inactivated (e.g. | ||
95 | - * when migration is completing) and it can start/stop requesting | ||
96 | - * permissions and doing I/O on it. | ||
97 | - */ | ||
98 | - void (*activate)(BdrvChild *child, Error **errp); | ||
99 | - int (*inactivate)(BdrvChild *child); | ||
100 | - | ||
101 | - void (*attach)(BdrvChild *child); | ||
102 | - void (*detach)(BdrvChild *child); | ||
103 | - | ||
104 | - /* | ||
105 | - * Notifies the parent that the filename of its child has changed (e.g. | ||
106 | - * because the direct child was removed from the backing chain), so that it | ||
107 | - * can update its reference. | ||
108 | - */ | ||
109 | - int (*update_filename)(BdrvChild *child, BlockDriverState *new_base, | ||
110 | - const char *filename, Error **errp); | ||
111 | - | ||
112 | - bool (*can_set_aio_ctx)(BdrvChild *child, AioContext *ctx, | ||
113 | - GSList **ignore, Error **errp); | ||
114 | - void (*set_aio_ctx)(BdrvChild *child, AioContext *ctx, GSList **ignore); | ||
115 | - | ||
116 | - AioContext *(*get_parent_aio_context)(BdrvChild *child); | ||
117 | }; | ||
118 | |||
119 | extern const BdrvChildClass child_of_bds; | ||
120 | -- | ||
121 | 2.35.1 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
2 | 1 | ||
3 | The job API will be handled separately in another serie. | ||
4 | |||
5 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
6 | Message-Id: <20220303151616.325444-31-eesposit@redhat.com> | ||
7 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
8 | --- | ||
9 | include/qemu/job.h | 22 ++++++++++++++++++++++ | ||
10 | 1 file changed, 22 insertions(+) | ||
11 | |||
12 | diff --git a/include/qemu/job.h b/include/qemu/job.h | ||
13 | index XXXXXXX..XXXXXXX 100644 | ||
14 | --- a/include/qemu/job.h | ||
15 | +++ b/include/qemu/job.h | ||
16 | @@ -XXX,XX +XXX,XX @@ typedef struct Job { | ||
17 | * Callbacks and other information about a Job driver. | ||
18 | */ | ||
19 | struct JobDriver { | ||
20 | + | ||
21 | + /* | ||
22 | + * These fields are initialized when this object is created, | ||
23 | + * and are never changed afterwards | ||
24 | + */ | ||
25 | + | ||
26 | /** Derived Job struct size */ | ||
27 | size_t instance_size; | ||
28 | |||
29 | @@ -XXX,XX +XXX,XX @@ struct JobDriver { | ||
30 | * aborted. If it returns zero, the job moves into the WAITING state. If it | ||
31 | * is the last job to complete in its transaction, all jobs in the | ||
32 | * transaction move from WAITING to PENDING. | ||
33 | + * | ||
34 | + * This callback must be run in the job's context. | ||
35 | */ | ||
36 | int coroutine_fn (*run)(Job *job, Error **errp); | ||
37 | |||
38 | + /* | ||
39 | + * Functions run without regard to the BQL that may run in any | ||
40 | + * arbitrary thread. These functions do not need to be thread-safe | ||
41 | + * because the caller ensures that they are invoked from one | ||
42 | + * thread at time. | ||
43 | + */ | ||
44 | + | ||
45 | /** | ||
46 | * If the callback is not NULL, it will be invoked when the job transitions | ||
47 | * into the paused state. Paused jobs must not perform any asynchronous | ||
48 | @@ -XXX,XX +XXX,XX @@ struct JobDriver { | ||
49 | */ | ||
50 | void coroutine_fn (*resume)(Job *job); | ||
51 | |||
52 | + /* | ||
53 | + * Global state (GS) API. These functions run under the BQL. | ||
54 | + * | ||
55 | + * See include/block/block-global-state.h for more information about | ||
56 | + * the GS API. | ||
57 | + */ | ||
58 | + | ||
59 | /** | ||
60 | * Called when the job is resumed by the user (i.e. user_paused becomes | ||
61 | * false). .user_resume is called before .resume. | ||
62 | -- | ||
63 | 2.35.1 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
2 | 1 | ||
3 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
4 | Message-Id: <20220303151616.325444-32-eesposit@redhat.com> | ||
5 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
6 | --- | ||
7 | job.c | 10 ++++++++++ | ||
8 | 1 file changed, 10 insertions(+) | ||
9 | |||
10 | diff --git a/job.c b/job.c | ||
11 | index XXXXXXX..XXXXXXX 100644 | ||
12 | --- a/job.c | ||
13 | +++ b/job.c | ||
14 | @@ -XXX,XX +XXX,XX @@ void job_ref(Job *job) | ||
15 | |||
16 | void job_unref(Job *job) | ||
17 | { | ||
18 | + GLOBAL_STATE_CODE(); | ||
19 | + | ||
20 | if (--job->refcnt == 0) { | ||
21 | assert(job->status == JOB_STATUS_NULL); | ||
22 | assert(!timer_pending(&job->sleep_timer)); | ||
23 | @@ -XXX,XX +XXX,XX @@ bool job_user_paused(Job *job) | ||
24 | void job_user_resume(Job *job, Error **errp) | ||
25 | { | ||
26 | assert(job); | ||
27 | + GLOBAL_STATE_CODE(); | ||
28 | if (!job->user_paused || job->pause_count <= 0) { | ||
29 | error_setg(errp, "Can't resume a job that was not paused"); | ||
30 | return; | ||
31 | @@ -XXX,XX +XXX,XX @@ static void job_update_rc(Job *job) | ||
32 | static void job_commit(Job *job) | ||
33 | { | ||
34 | assert(!job->ret); | ||
35 | + GLOBAL_STATE_CODE(); | ||
36 | if (job->driver->commit) { | ||
37 | job->driver->commit(job); | ||
38 | } | ||
39 | @@ -XXX,XX +XXX,XX @@ static void job_commit(Job *job) | ||
40 | static void job_abort(Job *job) | ||
41 | { | ||
42 | assert(job->ret); | ||
43 | + GLOBAL_STATE_CODE(); | ||
44 | if (job->driver->abort) { | ||
45 | job->driver->abort(job); | ||
46 | } | ||
47 | @@ -XXX,XX +XXX,XX @@ static void job_abort(Job *job) | ||
48 | |||
49 | static void job_clean(Job *job) | ||
50 | { | ||
51 | + GLOBAL_STATE_CODE(); | ||
52 | if (job->driver->clean) { | ||
53 | job->driver->clean(job); | ||
54 | } | ||
55 | @@ -XXX,XX +XXX,XX @@ static int job_finalize_single(Job *job) | ||
56 | |||
57 | static void job_cancel_async(Job *job, bool force) | ||
58 | { | ||
59 | + GLOBAL_STATE_CODE(); | ||
60 | if (job->driver->cancel) { | ||
61 | force = job->driver->cancel(job, force); | ||
62 | } else { | ||
63 | @@ -XXX,XX +XXX,XX @@ static void job_completed_txn_abort(Job *job) | ||
64 | |||
65 | static int job_prepare(Job *job) | ||
66 | { | ||
67 | + GLOBAL_STATE_CODE(); | ||
68 | if (job->ret == 0 && job->driver->prepare) { | ||
69 | job->ret = job->driver->prepare(job); | ||
70 | job_update_rc(job); | ||
71 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn job_co_entry(void *opaque) | ||
72 | Job *job = opaque; | ||
73 | |||
74 | assert(job && job->driver && job->driver->run); | ||
75 | + assert(job->aio_context == qemu_get_current_aio_context()); | ||
76 | job_pause_point(job); | ||
77 | job->ret = job->driver->run(job, &job->err); | ||
78 | job->deferred_to_main_loop = true; | ||
79 | @@ -XXX,XX +XXX,XX @@ void job_complete(Job *job, Error **errp) | ||
80 | { | ||
81 | /* Should not be reachable via external interface for internal jobs */ | ||
82 | assert(job->id); | ||
83 | + GLOBAL_STATE_CODE(); | ||
84 | if (job_apply_verb(job, JOB_VERB_COMPLETE, errp)) { | ||
85 | return; | ||
86 | } | ||
87 | -- | ||
88 | 2.35.1 | diff view generated by jsdifflib |