1 | The following changes since commit 16aaacb307ed607b9780c12702c44f0fe52edc7e: | 1 | The following changes since commit 6629bf78aac7e53f83fd0bcbdbe322e2302dfd1f: |
---|---|---|---|
2 | 2 | ||
3 | Merge remote-tracking branch 'remotes/cohuck/tags/s390x-20200430' into staging (2020-04-30 14:00:36 +0100) | 3 | Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20220302' into staging (2022-03-03 14:46:48 +0000) |
4 | 4 | ||
5 | are available in the Git repository at: | 5 | are available in the Git repository at: |
6 | 6 | ||
7 | git://repo.or.cz/qemu/kevin.git tags/for-upstream | 7 | https://gitlab.com/kmwolf/qemu.git tags/for-upstream |
8 | 8 | ||
9 | for you to fetch changes up to eaae29ef89d498d0eac553c77b554f310a47f809: | 9 | for you to fetch changes up to a5df6d1db7db37636c8624bf4a9df9da645853aa: |
10 | 10 | ||
11 | qemu-storage-daemon: Fix non-string --object properties (2020-04-30 17:51:07 +0200) | 11 | block/amend: Keep strong reference to BDS (2022-03-04 17:15:33 +0100) |
12 | 12 | ||
13 | ---------------------------------------------------------------- | 13 | ---------------------------------------------------------------- |
14 | Block layer patches: | 14 | Block layer patches |
15 | 15 | ||
16 | - Fix resize (extending) of short overlays | 16 | - qemu-storage-daemon: Add --daemonize |
17 | - nvme: introduce PMR support from NVMe 1.4 spec | 17 | - Fix x-blockdev-amend and block node activation code which incorrectly |
18 | - qemu-storage-daemon: Fix non-string --object properties | 18 | executed code in the iothread that must run in the main thread. |
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 | ||
19 | 25 | ||
20 | ---------------------------------------------------------------- | 26 | ---------------------------------------------------------------- |
21 | Alberto Garcia (1): | 27 | Emanuele Giuseppe Esposito (36): |
22 | qcow2: Add incompatibility note between backing files and raw external data files | 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 | ||
23 | 64 | ||
24 | Andrzej Jakowski (1): | 65 | Hanna Reitz (9): |
25 | nvme: introduce PMR support from NVMe 1.4 spec | 66 | os-posix: Add os_set_daemonize() |
67 | qsd: Add pre-init argument parsing pass | ||
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 | ||
26 | 75 | ||
27 | Kevin Wolf (12): | 76 | Stefan Hajnoczi (4): |
28 | block: Add flags to BlockDriver.bdrv_co_truncate() | 77 | tls: add macros for coroutine-safe TLS variables |
29 | block: Add flags to bdrv(_co)_truncate() | 78 | util/async: replace __thread with QEMU TLS macros |
30 | block-backend: Add flags to blk_truncate() | 79 | rcu: use coroutine TLS macros |
31 | qcow2: Support BDRV_REQ_ZERO_WRITE for truncate | 80 | cpus: use coroutine TLS macros for iothread_locked |
32 | raw-format: Support BDRV_REQ_ZERO_WRITE for truncate | ||
33 | file-posix: Support BDRV_REQ_ZERO_WRITE for truncate | ||
34 | block: truncate: Don't make backing file data visible | ||
35 | iotests: Filter testfiles out in filter_img_info() | ||
36 | iotests: Test committing to short backing file | ||
37 | qcow2: Forward ZERO_WRITE flag for full preallocation | ||
38 | qom: Factor out user_creatable_add_dict() | ||
39 | qemu-storage-daemon: Fix non-string --object properties | ||
40 | 81 | ||
41 | Paolo Bonzini (1): | 82 | Thomas Huth (1): |
42 | qemu-iotests: allow qcow2 external discarded clusters to contain stale data | 83 | tests/qemu-iotests: Rework the checks and spots using GNU sed |
43 | 84 | ||
44 | docs/interop/qcow2.txt | 3 + | 85 | docs/tools/qemu-storage-daemon.rst | 7 + |
45 | hw/block/nvme.h | 2 + | 86 | block/copy-before-write.h | 7 + |
46 | include/block/block.h | 5 +- | 87 | block/coroutines.h | 81 +- |
47 | include/block/block_int.h | 10 +- | 88 | include/block/block-common.h | 418 ++++++ |
48 | include/block/nvme.h | 172 ++++++++++++++++++++++++++ | 89 | include/block/block-global-state.h | 253 ++++ |
49 | include/qom/object_interfaces.h | 16 +++ | 90 | include/block/block-io.h | 368 +++++ |
50 | include/sysemu/block-backend.h | 2 +- | 91 | include/block/block.h | 878 +----------- |
51 | block.c | 3 +- | 92 | include/block/block_int-common.h | 1222 ++++++++++++++++ |
52 | block/block-backend.c | 4 +- | 93 | include/block/block_int-global-state.h | 329 +++++ |
53 | block/commit.c | 4 +- | 94 | include/block/block_int-io.h | 185 +++ |
54 | block/crypto.c | 7 +- | 95 | include/block/block_int.h | 1475 +------------------- |
55 | block/file-posix.c | 6 +- | 96 | include/block/blockjob.h | 29 +- |
56 | block/file-win32.c | 2 +- | 97 | include/block/blockjob_int.h | 28 + |
57 | block/gluster.c | 1 + | 98 | include/block/snapshot.h | 13 +- |
58 | block/io.c | 43 ++++++- | 99 | include/qemu/coroutine-tls.h | 165 +++ |
59 | block/iscsi.c | 2 +- | 100 | include/qemu/job.h | 22 + |
60 | block/mirror.c | 2 +- | 101 | include/qemu/main-loop.h | 42 + |
61 | block/nfs.c | 3 +- | 102 | include/qemu/rcu.h | 7 +- |
62 | block/parallels.c | 6 +- | 103 | include/sysemu/block-backend-common.h | 102 ++ |
63 | block/qcow.c | 4 +- | 104 | include/sysemu/block-backend-global-state.h | 116 ++ |
64 | block/qcow2-cluster.c | 2 +- | 105 | include/sysemu/block-backend-io.h | 161 +++ |
65 | block/qcow2-refcount.c | 2 +- | 106 | include/sysemu/block-backend.h | 269 +--- |
66 | block/qcow2.c | 73 +++++++++-- | 107 | include/sysemu/blockdev.h | 13 +- |
67 | block/qed.c | 3 +- | 108 | include/sysemu/os-posix.h | 1 + |
68 | block/raw-format.c | 6 +- | 109 | include/sysemu/os-win32.h | 8 + |
69 | block/rbd.c | 1 + | 110 | block.c | 321 ++++- |
70 | block/sheepdog.c | 4 +- | 111 | block/amend.c | 28 + |
71 | block/ssh.c | 2 +- | 112 | block/backup.c | 1 + |
72 | block/vdi.c | 2 +- | 113 | block/block-backend.c | 166 ++- |
73 | block/vhdx-log.c | 2 +- | 114 | block/commit.c | 4 + |
74 | block/vhdx.c | 6 +- | 115 | block/copy-before-write.c | 2 + |
75 | block/vmdk.c | 8 +- | 116 | block/create.c | 2 + |
76 | block/vpc.c | 2 +- | 117 | block/crypto.c | 68 +- |
77 | blockdev.c | 2 +- | 118 | block/dirty-bitmap.c | 5 + |
78 | hw/block/nvme.c | 109 ++++++++++++++++ | 119 | block/export/export.c | 2 +- |
79 | qemu-img.c | 2 +- | 120 | block/export/fuse.c | 25 +- |
80 | qemu-io-cmds.c | 2 +- | 121 | block/io.c | 75 +- |
81 | qemu-storage-daemon.c | 4 +- | 122 | block/mirror.c | 4 + |
82 | qom/object_interfaces.c | 31 +++++ | 123 | block/monitor/bitmap-qmp-cmds.c | 6 + |
83 | qom/qom-qmp-cmds.c | 24 +--- | 124 | block/nbd.c | 1 + |
84 | tests/test-block-iothread.c | 9 +- | 125 | block/parallels.c | 2 +- |
85 | tests/qemu-iotests/iotests.py | 5 +- | 126 | block/snapshot.c | 28 + |
86 | hw/block/Makefile.objs | 2 +- | 127 | block/stream.c | 2 + |
87 | hw/block/trace-events | 4 + | 128 | blockdev.c | 29 + |
88 | tests/qemu-iotests/244 | 10 +- | 129 | blockjob.c | 16 + |
89 | tests/qemu-iotests/244.out | 9 +- | 130 | hw/block/pflash_cfi01.c | 2 +- |
90 | tests/qemu-iotests/274 | 155 +++++++++++++++++++++++ | 131 | hw/nvram/spapr_nvram.c | 2 +- |
91 | tests/qemu-iotests/274.out | 268 ++++++++++++++++++++++++++++++++++++++++ | 132 | job.c | 10 + |
92 | tests/qemu-iotests/group | 1 + | 133 | migration/block.c | 2 +- |
93 | 49 files changed, 951 insertions(+), 96 deletions(-) | 134 | migration/migration.c | 14 +- |
94 | create mode 100755 tests/qemu-iotests/274 | 135 | migration/savevm.c | 8 +- |
95 | create mode 100644 tests/qemu-iotests/274.out | 136 | monitor/qmp-cmds.c | 2 +- |
96 | 137 | os-posix.c | 6 + | |
97 | 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 | This adds a new BdrvRequestFlags parameter to the .bdrv_co_truncate() | 1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
---|---|---|---|
2 | driver callbacks, and a supported_truncate_flags field in | 2 | |
3 | BlockDriverState that allows drivers to advertise support for request | 3 | Move the permission API calls into driver-specific callbacks |
4 | flags in the context of truncate. | 4 | that always run under BQL. In this case, bdrv_crypto_luks |
5 | 5 | needs to perform permission checks before and after | |
6 | For now, we always pass 0 and no drivers declare support for any flag. | 6 | qcrypto_block_amend_options(). The problem is that the caller, |
7 | 7 | block_crypto_amend_options_generic_luks(), can also run in I/O | |
8 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 8 | from .bdrv_co_amend(). This does not comply with Global State-I/O API split, |
9 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 9 | as permissions API must always run under BQL. |
10 | Reviewed-by: Alberto Garcia <berto@igalia.com> | 10 | |
11 | Reviewed-by: Max Reitz <mreitz@redhat.com> | 11 | Firstly, introduce .bdrv_amend_pre_run() and .bdrv_amend_clean() |
12 | Message-Id: <20200424125448.63318-2-kwolf@redhat.com> | 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> | ||
13 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 36 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
14 | --- | 37 | --- |
15 | include/block/block_int.h | 10 +++++++++- | 38 | include/block/block_int.h | 14 ++++++++++++++ |
16 | block/crypto.c | 3 ++- | 39 | block/amend.c | 25 +++++++++++++++++++++++++ |
17 | block/file-posix.c | 2 +- | 40 | block/crypto.c | 33 +++++++++++++++++++++++++++++++++ |
18 | block/file-win32.c | 2 +- | 41 | tests/qemu-iotests/296 | 8 ++++++-- |
19 | block/gluster.c | 1 + | 42 | tests/qemu-iotests/296.out | 17 +++++------------ |
20 | block/io.c | 8 +++++++- | 43 | 5 files changed, 83 insertions(+), 14 deletions(-) |
21 | block/iscsi.c | 2 +- | ||
22 | block/nfs.c | 3 ++- | ||
23 | block/qcow2.c | 2 +- | ||
24 | block/qed.c | 1 + | ||
25 | block/raw-format.c | 2 +- | ||
26 | block/rbd.c | 1 + | ||
27 | block/sheepdog.c | 4 ++-- | ||
28 | block/ssh.c | 2 +- | ||
29 | tests/test-block-iothread.c | 3 ++- | ||
30 | 15 files changed, 33 insertions(+), 13 deletions(-) | ||
31 | 44 | ||
32 | diff --git a/include/block/block_int.h b/include/block/block_int.h | 45 | diff --git a/include/block/block_int.h b/include/block/block_int.h |
33 | index XXXXXXX..XXXXXXX 100644 | 46 | index XXXXXXX..XXXXXXX 100644 |
34 | --- a/include/block/block_int.h | 47 | --- a/include/block/block_int.h |
35 | +++ b/include/block/block_int.h | 48 | +++ b/include/block/block_int.h |
36 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { | 49 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { |
50 | * on those children. | ||
37 | */ | 51 | */ |
38 | int coroutine_fn (*bdrv_co_truncate)(BlockDriverState *bs, int64_t offset, | 52 | bool is_format; |
39 | bool exact, PreallocMode prealloc, | 53 | + |
40 | - Error **errp); | ||
41 | + BdrvRequestFlags flags, Error **errp); | ||
42 | |||
43 | int64_t (*bdrv_getlength)(BlockDriverState *bs); | ||
44 | bool has_variable_length; | ||
45 | @@ -XXX,XX +XXX,XX @@ struct BlockDriverState { | ||
46 | /* Flags honored during pwrite_zeroes (so far: BDRV_REQ_FUA, | ||
47 | * BDRV_REQ_MAY_UNMAP, BDRV_REQ_WRITE_UNCHANGED) */ | ||
48 | unsigned int supported_zero_flags; | ||
49 | + /* | 54 | + /* |
50 | + * Flags honoured during truncate (so far: BDRV_REQ_ZERO_WRITE). | 55 | + * This function is invoked under BQL before .bdrv_co_amend() |
51 | + * | 56 | + * (which in contrast does not necessarily run under the BQL) |
52 | + * If BDRV_REQ_ZERO_WRITE is given, the truncate operation must make sure | 57 | + * to allow driver-specific initialization code that requires |
53 | + * that any added space reads as all zeros. If this can't be guaranteed, | 58 | + * the BQL, like setting up specific permission flags. |
54 | + * the operation must fail. | ||
55 | + */ | 59 | + */ |
56 | + unsigned int supported_truncate_flags; | 60 | + int (*bdrv_amend_pre_run)(BlockDriverState *bs, Error **errp); |
57 | 61 | + /* | |
58 | /* the following member gives a name to every node on the bs graph. */ | 62 | + * This function is invoked under BQL after .bdrv_co_amend() |
59 | char node_name[32]; | 63 | + * to allow cleaning up what was done in .bdrv_amend_pre_run(). |
64 | + */ | ||
65 | + void (*bdrv_amend_clean)(BlockDriverState *bs); | ||
66 | + | ||
67 | /* | ||
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 | +{ | ||
80 | + if (s->bs->drv->bdrv_amend_pre_run) { | ||
81 | + return s->bs->drv->bdrv_amend_pre_run(s->bs, errp); | ||
82 | + } | ||
83 | + | ||
84 | + return 0; | ||
85 | +} | ||
86 | + | ||
87 | +static void blockdev_amend_clean(Job *job) | ||
88 | +{ | ||
89 | + BlockdevAmendJob *s = container_of(job, BlockdevAmendJob, common); | ||
90 | + | ||
91 | + if (s->bs->drv->bdrv_amend_clean) { | ||
92 | + s->bs->drv->bdrv_amend_clean(s->bs); | ||
93 | + } | ||
94 | +} | ||
95 | + | ||
96 | static const JobDriver blockdev_amend_job_driver = { | ||
97 | .instance_size = sizeof(BlockdevAmendJob), | ||
98 | .job_type = JOB_TYPE_AMEND, | ||
99 | .run = blockdev_amend_run, | ||
100 | + .clean = blockdev_amend_clean, | ||
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 | + | ||
109 | + if (blockdev_amend_pre_run(s, errp)) { | ||
110 | + job_early_fail(&s->common); | ||
111 | + return; | ||
112 | + } | ||
113 | + | ||
114 | job_start(&s->common); | ||
115 | } | ||
60 | diff --git a/block/crypto.c b/block/crypto.c | 116 | diff --git a/block/crypto.c b/block/crypto.c |
61 | index XXXXXXX..XXXXXXX 100644 | 117 | index XXXXXXX..XXXXXXX 100644 |
62 | --- a/block/crypto.c | 118 | --- a/block/crypto.c |
63 | +++ b/block/crypto.c | 119 | +++ b/block/crypto.c |
64 | @@ -XXX,XX +XXX,XX @@ static int block_crypto_co_create_generic(BlockDriverState *bs, | 120 | @@ -XXX,XX +XXX,XX @@ block_crypto_get_specific_info_luks(BlockDriverState *bs, Error **errp) |
65 | 121 | return spec_info; | |
66 | static int coroutine_fn | 122 | } |
67 | block_crypto_co_truncate(BlockDriverState *bs, int64_t offset, bool exact, | 123 | |
68 | - PreallocMode prealloc, Error **errp) | 124 | +static int |
69 | + PreallocMode prealloc, BdrvRequestFlags flags, | 125 | +block_crypto_amend_prepare(BlockDriverState *bs, Error **errp) |
70 | + Error **errp) | 126 | +{ |
71 | { | 127 | + BlockCrypto *crypto = bs->opaque; |
72 | BlockCrypto *crypto = bs->opaque; | 128 | + int ret; |
73 | uint64_t payload_offset = | 129 | + |
74 | diff --git a/block/file-posix.c b/block/file-posix.c | 130 | + /* apply for exclusive read/write permissions to the underlying file */ |
75 | index XXXXXXX..XXXXXXX 100644 | 131 | + crypto->updating_keys = true; |
76 | --- a/block/file-posix.c | 132 | + ret = bdrv_child_refresh_perms(bs, bs->file, errp); |
77 | +++ b/block/file-posix.c | 133 | + if (ret < 0) { |
78 | @@ -XXX,XX +XXX,XX @@ raw_regular_truncate(BlockDriverState *bs, int fd, int64_t offset, | 134 | + /* Well, in this case we will not be updating any keys */ |
79 | 135 | + crypto->updating_keys = false; | |
80 | static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset, | 136 | + } |
81 | bool exact, PreallocMode prealloc, | 137 | + return ret; |
82 | - Error **errp) | 138 | +} |
83 | + BdrvRequestFlags flags, Error **errp) | 139 | + |
84 | { | 140 | +static void |
85 | BDRVRawState *s = bs->opaque; | 141 | +block_crypto_amend_cleanup(BlockDriverState *bs) |
86 | struct stat st; | 142 | +{ |
87 | diff --git a/block/file-win32.c b/block/file-win32.c | 143 | + BlockCrypto *crypto = bs->opaque; |
88 | index XXXXXXX..XXXXXXX 100644 | 144 | + Error *errp = NULL; |
89 | --- a/block/file-win32.c | 145 | + |
90 | +++ b/block/file-win32.c | 146 | + /* release exclusive read/write permissions to the underlying file */ |
91 | @@ -XXX,XX +XXX,XX @@ static void raw_close(BlockDriverState *bs) | 147 | + crypto->updating_keys = false; |
92 | 148 | + bdrv_child_refresh_perms(bs, bs->file, &errp); | |
93 | static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset, | 149 | + |
94 | bool exact, PreallocMode prealloc, | 150 | + if (errp) { |
95 | - Error **errp) | 151 | + error_report_err(errp); |
96 | + BdrvRequestFlags flags, Error **errp) | 152 | + } |
97 | { | 153 | +} |
98 | BDRVRawState *s = bs->opaque; | 154 | + |
99 | LONG low, high; | 155 | static int |
100 | diff --git a/block/gluster.c b/block/gluster.c | 156 | block_crypto_amend_options_generic_luks(BlockDriverState *bs, |
101 | index XXXXXXX..XXXXXXX 100644 | 157 | QCryptoBlockAmendOptions *amend_options, |
102 | --- a/block/gluster.c | 158 | @@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_crypto_luks = { |
103 | +++ b/block/gluster.c | 159 | .bdrv_get_specific_info = block_crypto_get_specific_info_luks, |
104 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int qemu_gluster_co_truncate(BlockDriverState *bs, | 160 | .bdrv_amend_options = block_crypto_amend_options_luks, |
105 | int64_t offset, | 161 | .bdrv_co_amend = block_crypto_co_amend_luks, |
106 | bool exact, | 162 | + .bdrv_amend_pre_run = block_crypto_amend_prepare, |
107 | PreallocMode prealloc, | 163 | + .bdrv_amend_clean = block_crypto_amend_cleanup, |
108 | + BdrvRequestFlags flags, | 164 | |
109 | Error **errp) | 165 | .is_format = true, |
110 | { | 166 | |
111 | BDRVGlusterState *s = bs->opaque; | 167 | diff --git a/tests/qemu-iotests/296 b/tests/qemu-iotests/296 |
112 | diff --git a/block/io.c b/block/io.c | 168 | index XXXXXXX..XXXXXXX 100755 |
113 | index XXXXXXX..XXXXXXX 100644 | 169 | --- a/tests/qemu-iotests/296 |
114 | --- a/block/io.c | 170 | +++ b/tests/qemu-iotests/296 |
115 | +++ b/block/io.c | 171 | @@ -XXX,XX +XXX,XX @@ class EncryptionSetupTestCase(iotests.QMPTestCase): |
116 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact, | ||
117 | BlockDriverState *bs = child->bs; | ||
118 | BlockDriver *drv = bs->drv; | ||
119 | BdrvTrackedRequest req; | ||
120 | + BdrvRequestFlags flags = 0; | ||
121 | int64_t old_size, new_bytes; | ||
122 | int ret; | ||
123 | |||
124 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact, | ||
125 | } | ||
126 | |||
127 | if (drv->bdrv_co_truncate) { | ||
128 | - ret = drv->bdrv_co_truncate(bs, offset, exact, prealloc, errp); | ||
129 | + if (flags & ~bs->supported_truncate_flags) { | ||
130 | + error_setg(errp, "Block driver does not support requested flags"); | ||
131 | + ret = -ENOTSUP; | ||
132 | + goto out; | ||
133 | + } | ||
134 | + ret = drv->bdrv_co_truncate(bs, offset, exact, prealloc, flags, errp); | ||
135 | } else if (bs->file && drv->is_filter) { | ||
136 | ret = bdrv_co_truncate(bs->file, offset, exact, prealloc, errp); | ||
137 | } else { | ||
138 | diff --git a/block/iscsi.c b/block/iscsi.c | ||
139 | index XXXXXXX..XXXXXXX 100644 | ||
140 | --- a/block/iscsi.c | ||
141 | +++ b/block/iscsi.c | ||
142 | @@ -XXX,XX +XXX,XX @@ static void iscsi_reopen_commit(BDRVReopenState *reopen_state) | ||
143 | |||
144 | static int coroutine_fn iscsi_co_truncate(BlockDriverState *bs, int64_t offset, | ||
145 | bool exact, PreallocMode prealloc, | ||
146 | - Error **errp) | ||
147 | + BdrvRequestFlags flags, Error **errp) | ||
148 | { | ||
149 | IscsiLun *iscsilun = bs->opaque; | ||
150 | int64_t cur_length; | ||
151 | diff --git a/block/nfs.c b/block/nfs.c | ||
152 | index XXXXXXX..XXXXXXX 100644 | ||
153 | --- a/block/nfs.c | ||
154 | +++ b/block/nfs.c | ||
155 | @@ -XXX,XX +XXX,XX @@ static int64_t nfs_get_allocated_file_size(BlockDriverState *bs) | ||
156 | |||
157 | static int coroutine_fn | ||
158 | nfs_file_co_truncate(BlockDriverState *bs, int64_t offset, bool exact, | ||
159 | - PreallocMode prealloc, Error **errp) | ||
160 | + PreallocMode prealloc, BdrvRequestFlags flags, | ||
161 | + Error **errp) | ||
162 | { | ||
163 | NFSClient *client = bs->opaque; | ||
164 | int ret; | ||
165 | diff --git a/block/qcow2.c b/block/qcow2.c | ||
166 | index XXXXXXX..XXXXXXX 100644 | ||
167 | --- a/block/qcow2.c | ||
168 | +++ b/block/qcow2.c | ||
169 | @@ -XXX,XX +XXX,XX @@ fail: | ||
170 | |||
171 | static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset, | ||
172 | bool exact, PreallocMode prealloc, | ||
173 | - Error **errp) | ||
174 | + BdrvRequestFlags flags, Error **errp) | ||
175 | { | ||
176 | BDRVQcow2State *s = bs->opaque; | ||
177 | uint64_t old_length; | ||
178 | diff --git a/block/qed.c b/block/qed.c | ||
179 | index XXXXXXX..XXXXXXX 100644 | ||
180 | --- a/block/qed.c | ||
181 | +++ b/block/qed.c | ||
182 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_qed_co_truncate(BlockDriverState *bs, | ||
183 | int64_t offset, | ||
184 | bool exact, | ||
185 | PreallocMode prealloc, | ||
186 | + BdrvRequestFlags flags, | ||
187 | Error **errp) | ||
188 | { | ||
189 | BDRVQEDState *s = bs->opaque; | ||
190 | diff --git a/block/raw-format.c b/block/raw-format.c | ||
191 | index XXXXXXX..XXXXXXX 100644 | ||
192 | --- a/block/raw-format.c | ||
193 | +++ b/block/raw-format.c | ||
194 | @@ -XXX,XX +XXX,XX @@ static void raw_refresh_limits(BlockDriverState *bs, Error **errp) | ||
195 | |||
196 | static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset, | ||
197 | bool exact, PreallocMode prealloc, | ||
198 | - Error **errp) | ||
199 | + BdrvRequestFlags flags, Error **errp) | ||
200 | { | ||
201 | BDRVRawState *s = bs->opaque; | ||
202 | |||
203 | diff --git a/block/rbd.c b/block/rbd.c | ||
204 | index XXXXXXX..XXXXXXX 100644 | ||
205 | --- a/block/rbd.c | ||
206 | +++ b/block/rbd.c | ||
207 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn qemu_rbd_co_truncate(BlockDriverState *bs, | ||
208 | int64_t offset, | ||
209 | bool exact, | ||
210 | PreallocMode prealloc, | ||
211 | + BdrvRequestFlags flags, | ||
212 | Error **errp) | ||
213 | { | ||
214 | int r; | ||
215 | diff --git a/block/sheepdog.c b/block/sheepdog.c | ||
216 | index XXXXXXX..XXXXXXX 100644 | ||
217 | --- a/block/sheepdog.c | ||
218 | +++ b/block/sheepdog.c | ||
219 | @@ -XXX,XX +XXX,XX @@ static int64_t sd_getlength(BlockDriverState *bs) | ||
220 | |||
221 | static int coroutine_fn sd_co_truncate(BlockDriverState *bs, int64_t offset, | ||
222 | bool exact, PreallocMode prealloc, | ||
223 | - Error **errp) | ||
224 | + BdrvRequestFlags flags, Error **errp) | ||
225 | { | ||
226 | BDRVSheepdogState *s = bs->opaque; | ||
227 | int ret, fd; | ||
228 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int sd_co_writev(BlockDriverState *bs, int64_t sector_num, | ||
229 | |||
230 | assert(!flags); | ||
231 | if (offset > s->inode.vdi_size) { | ||
232 | - ret = sd_co_truncate(bs, offset, false, PREALLOC_MODE_OFF, NULL); | ||
233 | + ret = sd_co_truncate(bs, offset, false, PREALLOC_MODE_OFF, 0, NULL); | ||
234 | if (ret < 0) { | ||
235 | return ret; | ||
236 | } | 172 | } |
237 | diff --git a/block/ssh.c b/block/ssh.c | 173 | |
238 | index XXXXXXX..XXXXXXX 100644 | 174 | result = vm.qmp('x-blockdev-amend', **args) |
239 | --- a/block/ssh.c | 175 | - assert result['return'] == {} |
240 | +++ b/block/ssh.c | 176 | - vm.run_job('job0') |
241 | @@ -XXX,XX +XXX,XX @@ static int64_t ssh_getlength(BlockDriverState *bs) | 177 | + iotests.log(result) |
242 | 178 | + # Run the job only if it was created | |
243 | static int coroutine_fn ssh_co_truncate(BlockDriverState *bs, int64_t offset, | 179 | + event = ('JOB_STATUS_CHANGE', |
244 | bool exact, PreallocMode prealloc, | 180 | + {'data': {'id': 'job0', 'status': 'created'}}) |
245 | - Error **errp) | 181 | + if vm.events_wait([event], timeout=0.0) is not None: |
246 | + BdrvRequestFlags flags, Error **errp) | 182 | + vm.run_job('job0') |
247 | { | 183 | |
248 | BDRVSSHState *s = bs->opaque; | 184 | # test that when the image opened by two qemu processes, |
249 | 185 | # neither of them can update the encryption keys | |
250 | diff --git a/tests/test-block-iothread.c b/tests/test-block-iothread.c | 186 | diff --git a/tests/qemu-iotests/296.out b/tests/qemu-iotests/296.out |
251 | index XXXXXXX..XXXXXXX 100644 | 187 | index XXXXXXX..XXXXXXX 100644 |
252 | --- a/tests/test-block-iothread.c | 188 | --- a/tests/qemu-iotests/296.out |
253 | +++ b/tests/test-block-iothread.c | 189 | +++ b/tests/qemu-iotests/296.out |
254 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_test_co_pdiscard(BlockDriverState *bs, | 190 | @@ -XXX,XX +XXX,XX @@ |
255 | 191 | ||
256 | static int coroutine_fn | 192 | -{"execute": "job-dismiss", "arguments": {"id": "job0"}} |
257 | bdrv_test_co_truncate(BlockDriverState *bs, int64_t offset, bool exact, | 193 | {"return": {}} |
258 | - PreallocMode prealloc, Error **errp) | 194 | -Job failed: Failed to get shared "consistent read" lock |
259 | + PreallocMode prealloc, BdrvRequestFlags flags, | 195 | {"execute": "job-dismiss", "arguments": {"id": "job0"}} |
260 | + Error **errp) | 196 | {"return": {}} |
261 | { | 197 | -Job failed: Failed to get shared "consistent read" lock |
262 | return 0; | 198 | -{"execute": "job-dismiss", "arguments": {"id": "job0"}} |
263 | } | 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": {}} | ||
264 | -- | 222 | -- |
265 | 2.25.3 | 223 | 2.35.1 |
266 | |||
267 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
1 | 2 | ||
3 | block_crypto_amend_options_generic_luks uses the block layer | ||
4 | permission API, therefore it should be called with the BQL held. | ||
5 | |||
6 | However, the same function is being called by two BlockDriver | ||
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 | ||
37 | --- a/block/crypto.c | ||
38 | +++ b/block/crypto.c | ||
39 | @@ -XXX,XX +XXX,XX @@ block_crypto_amend_options_generic_luks(BlockDriverState *bs, | ||
40 | Error **errp) | ||
41 | { | ||
42 | BlockCrypto *crypto = bs->opaque; | ||
43 | - int ret; | ||
44 | |||
45 | assert(crypto); | ||
46 | assert(crypto->block); | ||
47 | |||
48 | - /* apply for exclusive read/write permissions to the underlying file*/ | ||
49 | - crypto->updating_keys = true; | ||
50 | - ret = bdrv_child_refresh_perms(bs, bs->file, errp); | ||
51 | - if (ret) { | ||
52 | - goto cleanup; | ||
53 | - } | ||
54 | - | ||
55 | - ret = qcrypto_block_amend_options(crypto->block, | ||
56 | - block_crypto_read_func, | ||
57 | - block_crypto_write_func, | ||
58 | - bs, | ||
59 | - amend_options, | ||
60 | - force, | ||
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 | -- | ||
95 | 2.35.1 | diff view generated by jsdifflib |
1 | Now that block drivers can support flags for .bdrv_co_truncate, expose | 1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
---|---|---|---|
2 | the parameter in the node level interfaces bdrv_co_truncate() and | ||
3 | bdrv_truncate(). | ||
4 | 2 | ||
5 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 3 | This function is currently just a wrapper for bdrv_invalidate_cache(), |
6 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 4 | but in future will contain the code of bdrv_co_invalidate_cache() that |
7 | Reviewed-by: Alberto Garcia <berto@igalia.com> | 5 | has to always be protected by BQL, and leave the rest in the I/O |
8 | Reviewed-by: Max Reitz <mreitz@redhat.com> | 6 | coroutine. |
9 | Message-Id: <20200424125448.63318-3-kwolf@redhat.com> | 7 | |
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> | ||
10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 13 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
11 | --- | 14 | --- |
12 | include/block/block.h | 5 +++-- | 15 | include/block/block.h | 1 + |
13 | block/block-backend.c | 2 +- | 16 | block.c | 7 ++++++- |
14 | block/crypto.c | 2 +- | 17 | block/block-backend.c | 2 +- |
15 | block/io.c | 12 +++++++----- | 18 | block/export/export.c | 2 +- |
16 | block/parallels.c | 6 +++--- | 19 | block/parallels.c | 2 +- |
17 | block/qcow.c | 4 ++-- | 20 | tests/unit/test-block-iothread.c | 2 +- |
18 | block/qcow2-refcount.c | 2 +- | 21 | 6 files changed, 11 insertions(+), 5 deletions(-) |
19 | block/qcow2.c | 15 +++++++++------ | ||
20 | block/raw-format.c | 2 +- | ||
21 | block/vhdx-log.c | 2 +- | ||
22 | block/vhdx.c | 2 +- | ||
23 | block/vmdk.c | 2 +- | ||
24 | tests/test-block-iothread.c | 6 +++--- | ||
25 | 13 files changed, 34 insertions(+), 28 deletions(-) | ||
26 | 22 | ||
27 | diff --git a/include/block/block.h b/include/block/block.h | 23 | diff --git a/include/block/block.h b/include/block/block.h |
28 | index XXXXXXX..XXXXXXX 100644 | 24 | index XXXXXXX..XXXXXXX 100644 |
29 | --- a/include/block/block.h | 25 | --- a/include/block/block.h |
30 | +++ b/include/block/block.h | 26 | +++ b/include/block/block.h |
31 | @@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs, | 27 | @@ -XXX,XX +XXX,XX @@ int bdrv_co_ioctl(BlockDriverState *bs, int req, void *buf); |
32 | void bdrv_refresh_filename(BlockDriverState *bs); | 28 | int generated_co_wrapper bdrv_invalidate_cache(BlockDriverState *bs, |
33 | 29 | Error **errp); | |
34 | int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact, | 30 | void bdrv_invalidate_cache_all(Error **errp); |
35 | - PreallocMode prealloc, Error **errp); | 31 | +int bdrv_activate(BlockDriverState *bs, Error **errp); |
36 | + PreallocMode prealloc, BdrvRequestFlags flags, | 32 | int bdrv_inactivate_all(void); |
37 | + Error **errp); | 33 | |
38 | int bdrv_truncate(BdrvChild *child, int64_t offset, bool exact, | 34 | /* Ensure contents are flushed to disk. */ |
39 | - PreallocMode prealloc, Error **errp); | 35 | diff --git a/block.c b/block.c |
40 | + PreallocMode prealloc, BdrvRequestFlags flags, Error **errp); | 36 | index XXXXXXX..XXXXXXX 100644 |
41 | 37 | --- a/block.c | |
42 | int64_t bdrv_nb_sectors(BlockDriverState *bs); | 38 | +++ b/block.c |
43 | int64_t bdrv_getlength(BlockDriverState *bs); | 39 | @@ -XXX,XX +XXX,XX @@ void bdrv_init_with_whitelist(void) |
40 | bdrv_init(); | ||
41 | } | ||
42 | |||
43 | +int bdrv_activate(BlockDriverState *bs, Error **errp) | ||
44 | +{ | ||
45 | + return bdrv_invalidate_cache(bs, errp); | ||
46 | +} | ||
47 | + | ||
48 | int coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs, Error **errp) | ||
49 | { | ||
50 | BdrvChild *child, *parent; | ||
51 | @@ -XXX,XX +XXX,XX @@ void bdrv_invalidate_cache_all(Error **errp) | ||
52 | int ret; | ||
53 | |||
54 | aio_context_acquire(aio_context); | ||
55 | - ret = bdrv_invalidate_cache(bs, errp); | ||
56 | + ret = bdrv_activate(bs, errp); | ||
57 | aio_context_release(aio_context); | ||
58 | if (ret < 0) { | ||
59 | bdrv_next_cleanup(&it); | ||
44 | diff --git a/block/block-backend.c b/block/block-backend.c | 60 | diff --git a/block/block-backend.c b/block/block-backend.c |
45 | index XXXXXXX..XXXXXXX 100644 | 61 | index XXXXXXX..XXXXXXX 100644 |
46 | --- a/block/block-backend.c | 62 | --- a/block/block-backend.c |
47 | +++ b/block/block-backend.c | 63 | +++ b/block/block-backend.c |
48 | @@ -XXX,XX +XXX,XX @@ int blk_truncate(BlockBackend *blk, int64_t offset, bool exact, | 64 | @@ -XXX,XX +XXX,XX @@ void blk_invalidate_cache(BlockBackend *blk, Error **errp) |
49 | return -ENOMEDIUM; | 65 | return; |
50 | } | 66 | } |
51 | 67 | ||
52 | - return bdrv_truncate(blk->root, offset, exact, prealloc, errp); | 68 | - bdrv_invalidate_cache(bs, errp); |
53 | + return bdrv_truncate(blk->root, offset, exact, prealloc, 0, errp); | 69 | + bdrv_activate(bs, errp); |
54 | } | 70 | } |
55 | 71 | ||
56 | int blk_save_vmstate(BlockBackend *blk, const uint8_t *buf, | 72 | bool blk_is_inserted(BlockBackend *blk) |
57 | diff --git a/block/crypto.c b/block/crypto.c | 73 | diff --git a/block/export/export.c b/block/export/export.c |
58 | index XXXXXXX..XXXXXXX 100644 | 74 | index XXXXXXX..XXXXXXX 100644 |
59 | --- a/block/crypto.c | 75 | --- a/block/export/export.c |
60 | +++ b/block/crypto.c | 76 | +++ b/block/export/export.c |
61 | @@ -XXX,XX +XXX,XX @@ block_crypto_co_truncate(BlockDriverState *bs, int64_t offset, bool exact, | 77 | @@ -XXX,XX +XXX,XX @@ BlockExport *blk_exp_add(BlockExportOptions *export, Error **errp) |
62 | 78 | * access since the export could be available before migration handover. | |
63 | offset += payload_offset; | 79 | * ctx was acquired in the caller. |
64 | 80 | */ | |
65 | - return bdrv_co_truncate(bs->file, offset, exact, prealloc, errp); | 81 | - bdrv_invalidate_cache(bs, NULL); |
66 | + return bdrv_co_truncate(bs->file, offset, exact, prealloc, 0, errp); | 82 | + bdrv_activate(bs, NULL); |
67 | } | 83 | |
68 | 84 | perm = BLK_PERM_CONSISTENT_READ; | |
69 | static void block_crypto_close(BlockDriverState *bs) | 85 | if (export->writable) { |
70 | diff --git a/block/io.c b/block/io.c | ||
71 | index XXXXXXX..XXXXXXX 100644 | ||
72 | --- a/block/io.c | ||
73 | +++ b/block/io.c | ||
74 | @@ -XXX,XX +XXX,XX @@ static void bdrv_parent_cb_resize(BlockDriverState *bs) | ||
75 | * 'offset' bytes in length. | ||
76 | */ | ||
77 | int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact, | ||
78 | - PreallocMode prealloc, Error **errp) | ||
79 | + PreallocMode prealloc, BdrvRequestFlags flags, | ||
80 | + Error **errp) | ||
81 | { | ||
82 | BlockDriverState *bs = child->bs; | ||
83 | BlockDriver *drv = bs->drv; | ||
84 | BdrvTrackedRequest req; | ||
85 | - BdrvRequestFlags flags = 0; | ||
86 | int64_t old_size, new_bytes; | ||
87 | int ret; | ||
88 | |||
89 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact, | ||
90 | } | ||
91 | ret = drv->bdrv_co_truncate(bs, offset, exact, prealloc, flags, errp); | ||
92 | } else if (bs->file && drv->is_filter) { | ||
93 | - ret = bdrv_co_truncate(bs->file, offset, exact, prealloc, errp); | ||
94 | + ret = bdrv_co_truncate(bs->file, offset, exact, prealloc, flags, errp); | ||
95 | } else { | ||
96 | error_setg(errp, "Image format driver does not support resize"); | ||
97 | ret = -ENOTSUP; | ||
98 | @@ -XXX,XX +XXX,XX @@ typedef struct TruncateCo { | ||
99 | int64_t offset; | ||
100 | bool exact; | ||
101 | PreallocMode prealloc; | ||
102 | + BdrvRequestFlags flags; | ||
103 | Error **errp; | ||
104 | int ret; | ||
105 | } TruncateCo; | ||
106 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_truncate_co_entry(void *opaque) | ||
107 | { | ||
108 | TruncateCo *tco = opaque; | ||
109 | tco->ret = bdrv_co_truncate(tco->child, tco->offset, tco->exact, | ||
110 | - tco->prealloc, tco->errp); | ||
111 | + tco->prealloc, tco->flags, tco->errp); | ||
112 | aio_wait_kick(); | ||
113 | } | ||
114 | |||
115 | int bdrv_truncate(BdrvChild *child, int64_t offset, bool exact, | ||
116 | - PreallocMode prealloc, Error **errp) | ||
117 | + PreallocMode prealloc, BdrvRequestFlags flags, Error **errp) | ||
118 | { | ||
119 | Coroutine *co; | ||
120 | TruncateCo tco = { | ||
121 | @@ -XXX,XX +XXX,XX @@ int bdrv_truncate(BdrvChild *child, int64_t offset, bool exact, | ||
122 | .offset = offset, | ||
123 | .exact = exact, | ||
124 | .prealloc = prealloc, | ||
125 | + .flags = flags, | ||
126 | .errp = errp, | ||
127 | .ret = NOT_DONE, | ||
128 | }; | ||
129 | diff --git a/block/parallels.c b/block/parallels.c | 86 | diff --git a/block/parallels.c b/block/parallels.c |
130 | index XXXXXXX..XXXXXXX 100644 | 87 | index XXXXXXX..XXXXXXX 100644 |
131 | --- a/block/parallels.c | 88 | --- a/block/parallels.c |
132 | +++ b/block/parallels.c | 89 | +++ b/block/parallels.c |
133 | @@ -XXX,XX +XXX,XX @@ static int64_t allocate_clusters(BlockDriverState *bs, int64_t sector_num, | 90 | @@ -XXX,XX +XXX,XX @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags, |
134 | } else { | 91 | s->bat_dirty_bmap = |
135 | ret = bdrv_truncate(bs->file, | 92 | bitmap_new(DIV_ROUND_UP(s->header_size, s->bat_dirty_block)); |
136 | (s->data_end + space) << BDRV_SECTOR_BITS, | 93 | |
137 | - false, PREALLOC_MODE_OFF, NULL); | 94 | - /* Disable migration until bdrv_invalidate_cache method is added */ |
138 | + false, PREALLOC_MODE_OFF, 0, NULL); | 95 | + /* Disable migration until bdrv_activate method is added */ |
139 | } | 96 | error_setg(&s->migration_blocker, "The Parallels format used by node '%s' " |
140 | if (ret < 0) { | 97 | "does not support live migration", |
141 | return ret; | 98 | bdrv_get_device_or_node_name(bs)); |
142 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn parallels_co_check(BlockDriverState *bs, | 99 | diff --git a/tests/unit/test-block-iothread.c b/tests/unit/test-block-iothread.c |
143 | * That means we have to pass exact=true. | ||
144 | */ | ||
145 | ret = bdrv_truncate(bs->file, res->image_end_offset, true, | ||
146 | - PREALLOC_MODE_OFF, &local_err); | ||
147 | + PREALLOC_MODE_OFF, 0, &local_err); | ||
148 | if (ret < 0) { | ||
149 | error_report_err(local_err); | ||
150 | res->check_errors++; | ||
151 | @@ -XXX,XX +XXX,XX @@ static void parallels_close(BlockDriverState *bs) | ||
152 | |||
153 | /* errors are ignored, so we might as well pass exact=true */ | ||
154 | bdrv_truncate(bs->file, s->data_end << BDRV_SECTOR_BITS, true, | ||
155 | - PREALLOC_MODE_OFF, NULL); | ||
156 | + PREALLOC_MODE_OFF, 0, NULL); | ||
157 | } | ||
158 | |||
159 | g_free(s->bat_dirty_bmap); | ||
160 | diff --git a/block/qcow.c b/block/qcow.c | ||
161 | index XXXXXXX..XXXXXXX 100644 | 100 | index XXXXXXX..XXXXXXX 100644 |
162 | --- a/block/qcow.c | 101 | --- a/tests/unit/test-block-iothread.c |
163 | +++ b/block/qcow.c | 102 | +++ b/tests/unit/test-block-iothread.c |
164 | @@ -XXX,XX +XXX,XX @@ static int get_cluster_offset(BlockDriverState *bs, | 103 | @@ -XXX,XX +XXX,XX @@ static void test_sync_op_check(BdrvChild *c) |
165 | return -E2BIG; | 104 | static void test_sync_op_invalidate_cache(BdrvChild *c) |
166 | } | 105 | { |
167 | ret = bdrv_truncate(bs->file, cluster_offset + s->cluster_size, | 106 | /* Early success: Image is not inactive */ |
168 | - false, PREALLOC_MODE_OFF, NULL); | 107 | - bdrv_invalidate_cache(c->bs, NULL); |
169 | + false, PREALLOC_MODE_OFF, 0, NULL); | 108 | + bdrv_activate(c->bs, NULL); |
170 | if (ret < 0) { | ||
171 | return ret; | ||
172 | } | ||
173 | @@ -XXX,XX +XXX,XX @@ static int qcow_make_empty(BlockDriverState *bs) | ||
174 | l1_length) < 0) | ||
175 | return -1; | ||
176 | ret = bdrv_truncate(bs->file, s->l1_table_offset + l1_length, false, | ||
177 | - PREALLOC_MODE_OFF, NULL); | ||
178 | + PREALLOC_MODE_OFF, 0, NULL); | ||
179 | if (ret < 0) | ||
180 | return ret; | ||
181 | |||
182 | diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c | ||
183 | index XXXXXXX..XXXXXXX 100644 | ||
184 | --- a/block/qcow2-refcount.c | ||
185 | +++ b/block/qcow2-refcount.c | ||
186 | @@ -XXX,XX +XXX,XX @@ static int check_refblocks(BlockDriverState *bs, BdrvCheckResult *res, | ||
187 | } | ||
188 | |||
189 | ret = bdrv_truncate(bs->file, offset + s->cluster_size, false, | ||
190 | - PREALLOC_MODE_OFF, &local_err); | ||
191 | + PREALLOC_MODE_OFF, 0, &local_err); | ||
192 | if (ret < 0) { | ||
193 | error_report_err(local_err); | ||
194 | goto resize_fail; | ||
195 | diff --git a/block/qcow2.c b/block/qcow2.c | ||
196 | index XXXXXXX..XXXXXXX 100644 | ||
197 | --- a/block/qcow2.c | ||
198 | +++ b/block/qcow2.c | ||
199 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn preallocate_co(BlockDriverState *bs, uint64_t offset, | ||
200 | mode = PREALLOC_MODE_OFF; | ||
201 | } | ||
202 | ret = bdrv_co_truncate(s->data_file, host_offset + cur_bytes, false, | ||
203 | - mode, errp); | ||
204 | + mode, 0, errp); | ||
205 | if (ret < 0) { | ||
206 | return ret; | ||
207 | } | ||
208 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset, | ||
209 | * always fulfilled, so there is no need to pass it on.) | ||
210 | */ | ||
211 | bdrv_co_truncate(bs->file, (last_cluster + 1) * s->cluster_size, | ||
212 | - false, PREALLOC_MODE_OFF, &local_err); | ||
213 | + false, PREALLOC_MODE_OFF, 0, &local_err); | ||
214 | if (local_err) { | ||
215 | warn_reportf_err(local_err, | ||
216 | "Failed to truncate the tail of the image: "); | ||
217 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset, | ||
218 | * file should be resized to the exact target size, too, | ||
219 | * so we pass @exact here. | ||
220 | */ | ||
221 | - ret = bdrv_co_truncate(s->data_file, offset, exact, prealloc, errp); | ||
222 | + ret = bdrv_co_truncate(s->data_file, offset, exact, prealloc, 0, | ||
223 | + errp); | ||
224 | if (ret < 0) { | ||
225 | goto fail; | ||
226 | } | ||
227 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset, | ||
228 | new_file_size = allocation_start + | ||
229 | nb_new_data_clusters * s->cluster_size; | ||
230 | /* Image file grows, so @exact does not matter */ | ||
231 | - ret = bdrv_co_truncate(bs->file, new_file_size, false, prealloc, errp); | ||
232 | + ret = bdrv_co_truncate(bs->file, new_file_size, false, prealloc, 0, | ||
233 | + errp); | ||
234 | if (ret < 0) { | ||
235 | error_prepend(errp, "Failed to resize underlying file: "); | ||
236 | qcow2_free_clusters(bs, allocation_start, | ||
237 | @@ -XXX,XX +XXX,XX @@ qcow2_co_pwritev_compressed_part(BlockDriverState *bs, | ||
238 | if (len < 0) { | ||
239 | return len; | ||
240 | } | ||
241 | - return bdrv_co_truncate(bs->file, len, false, PREALLOC_MODE_OFF, NULL); | ||
242 | + return bdrv_co_truncate(bs->file, len, false, PREALLOC_MODE_OFF, 0, | ||
243 | + NULL); | ||
244 | } | ||
245 | |||
246 | if (offset_into_cluster(s, offset)) { | ||
247 | @@ -XXX,XX +XXX,XX @@ static int make_completely_empty(BlockDriverState *bs) | ||
248 | } | ||
249 | |||
250 | ret = bdrv_truncate(bs->file, (3 + l1_clusters) * s->cluster_size, false, | ||
251 | - PREALLOC_MODE_OFF, &local_err); | ||
252 | + PREALLOC_MODE_OFF, 0, &local_err); | ||
253 | if (ret < 0) { | ||
254 | error_report_err(local_err); | ||
255 | goto fail; | ||
256 | diff --git a/block/raw-format.c b/block/raw-format.c | ||
257 | index XXXXXXX..XXXXXXX 100644 | ||
258 | --- a/block/raw-format.c | ||
259 | +++ b/block/raw-format.c | ||
260 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset, | ||
261 | |||
262 | s->size = offset; | ||
263 | offset += s->offset; | ||
264 | - return bdrv_co_truncate(bs->file, offset, exact, prealloc, errp); | ||
265 | + return bdrv_co_truncate(bs->file, offset, exact, prealloc, 0, errp); | ||
266 | } | 109 | } |
267 | 110 | ||
268 | static void raw_eject(BlockDriverState *bs, bool eject_flag) | 111 | |
269 | diff --git a/block/vhdx-log.c b/block/vhdx-log.c | ||
270 | index XXXXXXX..XXXXXXX 100644 | ||
271 | --- a/block/vhdx-log.c | ||
272 | +++ b/block/vhdx-log.c | ||
273 | @@ -XXX,XX +XXX,XX @@ static int vhdx_log_flush(BlockDriverState *bs, BDRVVHDXState *s, | ||
274 | goto exit; | ||
275 | } | ||
276 | ret = bdrv_truncate(bs->file, new_file_size, false, | ||
277 | - PREALLOC_MODE_OFF, NULL); | ||
278 | + PREALLOC_MODE_OFF, 0, NULL); | ||
279 | if (ret < 0) { | ||
280 | goto exit; | ||
281 | } | ||
282 | diff --git a/block/vhdx.c b/block/vhdx.c | ||
283 | index XXXXXXX..XXXXXXX 100644 | ||
284 | --- a/block/vhdx.c | ||
285 | +++ b/block/vhdx.c | ||
286 | @@ -XXX,XX +XXX,XX @@ static int vhdx_allocate_block(BlockDriverState *bs, BDRVVHDXState *s, | ||
287 | } | ||
288 | |||
289 | return bdrv_truncate(bs->file, *new_offset + s->block_size, false, | ||
290 | - PREALLOC_MODE_OFF, NULL); | ||
291 | + PREALLOC_MODE_OFF, 0, NULL); | ||
292 | } | ||
293 | |||
294 | /* | ||
295 | diff --git a/block/vmdk.c b/block/vmdk.c | ||
296 | index XXXXXXX..XXXXXXX 100644 | ||
297 | --- a/block/vmdk.c | ||
298 | +++ b/block/vmdk.c | ||
299 | @@ -XXX,XX +XXX,XX @@ vmdk_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset, | ||
300 | } | ||
301 | length = QEMU_ALIGN_UP(length, BDRV_SECTOR_SIZE); | ||
302 | ret = bdrv_truncate(s->extents[i].file, length, false, | ||
303 | - PREALLOC_MODE_OFF, NULL); | ||
304 | + PREALLOC_MODE_OFF, 0, NULL); | ||
305 | if (ret < 0) { | ||
306 | return ret; | ||
307 | } | ||
308 | diff --git a/tests/test-block-iothread.c b/tests/test-block-iothread.c | ||
309 | index XXXXXXX..XXXXXXX 100644 | ||
310 | --- a/tests/test-block-iothread.c | ||
311 | +++ b/tests/test-block-iothread.c | ||
312 | @@ -XXX,XX +XXX,XX @@ static void test_sync_op_truncate(BdrvChild *c) | ||
313 | int ret; | ||
314 | |||
315 | /* Normal success path */ | ||
316 | - ret = bdrv_truncate(c, 65536, false, PREALLOC_MODE_OFF, NULL); | ||
317 | + ret = bdrv_truncate(c, 65536, false, PREALLOC_MODE_OFF, 0, NULL); | ||
318 | g_assert_cmpint(ret, ==, 0); | ||
319 | |||
320 | /* Early error: Negative offset */ | ||
321 | - ret = bdrv_truncate(c, -2, false, PREALLOC_MODE_OFF, NULL); | ||
322 | + ret = bdrv_truncate(c, -2, false, PREALLOC_MODE_OFF, 0, NULL); | ||
323 | g_assert_cmpint(ret, ==, -EINVAL); | ||
324 | |||
325 | /* Error: Read-only image */ | ||
326 | c->bs->read_only = true; | ||
327 | c->bs->open_flags &= ~BDRV_O_RDWR; | ||
328 | |||
329 | - ret = bdrv_truncate(c, 65536, false, PREALLOC_MODE_OFF, NULL); | ||
330 | + ret = bdrv_truncate(c, 65536, false, PREALLOC_MODE_OFF, 0, NULL); | ||
331 | g_assert_cmpint(ret, ==, -EACCES); | ||
332 | |||
333 | c->bs->read_only = false; | ||
334 | -- | 112 | -- |
335 | 2.25.3 | 113 | 2.35.1 |
336 | |||
337 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | 1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | |
2 | |||
3 | Following the bdrv_activate renaming, change also the name | ||
4 | of the respective callers. | ||
5 | |||
6 | bdrv_invalidate_cache_all -> bdrv_activate_all | ||
7 | blk_invalidate_cache -> blk_activate | ||
8 | test_sync_op_invalidate_cache -> test_sync_op_activate | ||
9 | |||
10 | No functional change intended. | ||
11 | |||
12 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
13 | Reviewed-by: Juan Quintela <quintela@redhat.com> | ||
14 | Reviewed-by: Hanna Reitz <hreitz@redhat.com> | ||
15 | Message-Id: <20220209105452.1694545-5-eesposit@redhat.com> | ||
16 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
17 | --- | ||
18 | include/block/block.h | 2 +- | ||
19 | include/sysemu/block-backend.h | 2 +- | ||
20 | block.c | 2 +- | ||
21 | block/block-backend.c | 2 +- | ||
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 | |||
31 | diff --git a/include/block/block.h b/include/block/block.h | ||
32 | index XXXXXXX..XXXXXXX 100644 | ||
33 | --- a/include/block/block.h | ||
34 | +++ b/include/block/block.h | ||
35 | @@ -XXX,XX +XXX,XX @@ int bdrv_co_ioctl(BlockDriverState *bs, int req, void *buf); | ||
36 | /* Invalidate any cached metadata used by image formats */ | ||
37 | int generated_co_wrapper bdrv_invalidate_cache(BlockDriverState *bs, | ||
38 | Error **errp); | ||
39 | -void bdrv_invalidate_cache_all(Error **errp); | ||
40 | int bdrv_activate(BlockDriverState *bs, Error **errp); | ||
41 | +void bdrv_activate_all(Error **errp); | ||
42 | int bdrv_inactivate_all(void); | ||
43 | |||
44 | /* Ensure contents are flushed to disk. */ | ||
45 | diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h | ||
46 | index XXXXXXX..XXXXXXX 100644 | ||
47 | --- a/include/sysemu/block-backend.h | ||
48 | +++ b/include/sysemu/block-backend.h | ||
49 | @@ -XXX,XX +XXX,XX @@ bool blk_is_writable(BlockBackend *blk); | ||
50 | bool blk_is_sg(BlockBackend *blk); | ||
51 | bool blk_enable_write_cache(BlockBackend *blk); | ||
52 | void blk_set_enable_write_cache(BlockBackend *blk, bool wce); | ||
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 | ||
59 | index XXXXXXX..XXXXXXX 100644 | ||
60 | --- a/block.c | ||
61 | +++ b/block.c | ||
62 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs, Error **errp) | ||
63 | return 0; | ||
64 | } | ||
65 | |||
66 | -void bdrv_invalidate_cache_all(Error **errp) | ||
67 | +void bdrv_activate_all(Error **errp) | ||
68 | { | ||
69 | BlockDriverState *bs; | ||
70 | BdrvNextIterator it; | ||
71 | diff --git a/block/block-backend.c b/block/block-backend.c | ||
72 | index XXXXXXX..XXXXXXX 100644 | ||
73 | --- a/block/block-backend.c | ||
74 | +++ b/block/block-backend.c | ||
75 | @@ -XXX,XX +XXX,XX @@ void blk_set_enable_write_cache(BlockBackend *blk, bool wce) | ||
76 | blk->enable_write_cache = wce; | ||
77 | } | ||
78 | |||
79 | -void blk_invalidate_cache(BlockBackend *blk, Error **errp) | ||
80 | +void blk_activate(BlockBackend *blk, Error **errp) | ||
81 | { | ||
82 | BlockDriverState *bs = blk_bs(blk); | ||
83 | |||
84 | diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c | ||
85 | index XXXXXXX..XXXXXXX 100644 | ||
86 | --- a/hw/block/pflash_cfi01.c | ||
87 | +++ b/hw/block/pflash_cfi01.c | ||
88 | @@ -XXX,XX +XXX,XX @@ static void postload_update_cb(void *opaque, bool running, RunState state) | ||
89 | { | ||
90 | PFlashCFI01 *pfl = opaque; | ||
91 | |||
92 | - /* This is called after bdrv_invalidate_cache_all. */ | ||
93 | + /* This is called after bdrv_activate_all. */ | ||
94 | qemu_del_vm_change_state_handler(pfl->vmstate); | ||
95 | pfl->vmstate = NULL; | ||
96 | |||
97 | diff --git a/hw/nvram/spapr_nvram.c b/hw/nvram/spapr_nvram.c | ||
98 | index XXXXXXX..XXXXXXX 100644 | ||
99 | --- a/hw/nvram/spapr_nvram.c | ||
100 | +++ b/hw/nvram/spapr_nvram.c | ||
101 | @@ -XXX,XX +XXX,XX @@ static void postload_update_cb(void *opaque, bool running, RunState state) | ||
102 | { | ||
103 | SpaprNvram *nvram = opaque; | ||
104 | |||
105 | - /* This is called after bdrv_invalidate_cache_all. */ | ||
106 | + /* This is called after bdrv_activate_all. */ | ||
107 | |||
108 | qemu_del_vm_change_state_handler(nvram->vmstate); | ||
109 | nvram->vmstate = NULL; | ||
110 | diff --git a/migration/block.c b/migration/block.c | ||
111 | index XXXXXXX..XXXXXXX 100644 | ||
112 | --- a/migration/block.c | ||
113 | +++ b/migration/block.c | ||
114 | @@ -XXX,XX +XXX,XX @@ static int block_load(QEMUFile *f, void *opaque, int version_id) | ||
115 | return -EINVAL; | ||
116 | } | ||
117 | |||
118 | - blk_invalidate_cache(blk, &local_err); | ||
119 | + blk_activate(blk, &local_err); | ||
120 | if (local_err) { | ||
121 | error_report_err(local_err); | ||
122 | return -EINVAL; | ||
123 | diff --git a/migration/migration.c b/migration/migration.c | ||
124 | index XXXXXXX..XXXXXXX 100644 | ||
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; | ||
215 | diff --git a/tests/unit/test-block-iothread.c b/tests/unit/test-block-iothread.c | ||
216 | index XXXXXXX..XXXXXXX 100644 | ||
217 | --- a/tests/unit/test-block-iothread.c | ||
218 | +++ b/tests/unit/test-block-iothread.c | ||
219 | @@ -XXX,XX +XXX,XX @@ static void test_sync_op_check(BdrvChild *c) | ||
220 | g_assert_cmpint(ret, ==, -ENOTSUP); | ||
221 | } | ||
222 | |||
223 | -static void test_sync_op_invalidate_cache(BdrvChild *c) | ||
224 | +static void test_sync_op_activate(BdrvChild *c) | ||
225 | { | ||
226 | /* Early success: Image is not inactive */ | ||
227 | bdrv_activate(c->bs, NULL); | ||
228 | @@ -XXX,XX +XXX,XX @@ const SyncOpTest sync_op_tests[] = { | ||
229 | .name = "/sync-op/check", | ||
230 | .fn = test_sync_op_check, | ||
231 | }, { | ||
232 | - .name = "/sync-op/invalidate_cache", | ||
233 | - .fn = test_sync_op_invalidate_cache, | ||
234 | + .name = "/sync-op/activate", | ||
235 | + .fn = test_sync_op_activate, | ||
236 | }, | ||
237 | }; | ||
238 | |||
239 | -- | ||
240 | 2.35.1 | diff view generated by jsdifflib |
1 | If BDRV_REQ_ZERO_WRITE is set and we're extending the image, calling | 1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
---|---|---|---|
2 | qcow2_cluster_zeroize() with flags=0 does the right thing: It doesn't | ||
3 | undo any previous preallocation, but just adds the zero flag to all | ||
4 | relevant L2 entries. If an external data file is in use, a write_zeroes | ||
5 | request to the data file is made instead. | ||
6 | 2 | ||
7 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 3 | Split bdrv_co_invalidate cache in two: the Global State (under BQL) |
8 | Message-Id: <20200424125448.63318-5-kwolf@redhat.com> | 4 | code that takes care of permissions and running GS callbacks, |
9 | Reviewed-by: Eric Blake <eblake@redhat.com> | 5 | and leave only the I/O code (->bdrv_co_invalidate_cache) running in |
10 | Reviewed-by: Max Reitz <mreitz@redhat.com> | 6 | the I/O coroutine. |
7 | |||
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> | ||
11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 14 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
12 | --- | 15 | --- |
13 | block/qcow2-cluster.c | 2 +- | 16 | block.c | 37 +++++++++++++++++++++++-------------- |
14 | block/qcow2.c | 34 ++++++++++++++++++++++++++++++++++ | 17 | 1 file changed, 23 insertions(+), 14 deletions(-) |
15 | 2 files changed, 35 insertions(+), 1 deletion(-) | ||
16 | 18 | ||
17 | diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c | 19 | diff --git a/block.c b/block.c |
18 | index XXXXXXX..XXXXXXX 100644 | 20 | index XXXXXXX..XXXXXXX 100644 |
19 | --- a/block/qcow2-cluster.c | 21 | --- a/block.c |
20 | +++ b/block/qcow2-cluster.c | 22 | +++ b/block.c |
21 | @@ -XXX,XX +XXX,XX @@ int qcow2_cluster_zeroize(BlockDriverState *bs, uint64_t offset, | 23 | @@ -XXX,XX +XXX,XX @@ void bdrv_init_with_whitelist(void) |
22 | /* Caller must pass aligned values, except at image end */ | 24 | } |
23 | assert(QEMU_IS_ALIGNED(offset, s->cluster_size)); | 25 | |
24 | assert(QEMU_IS_ALIGNED(end_offset, s->cluster_size) || | 26 | int bdrv_activate(BlockDriverState *bs, Error **errp) |
25 | - end_offset == bs->total_sectors << BDRV_SECTOR_BITS); | 27 | -{ |
26 | + end_offset >= bs->total_sectors << BDRV_SECTOR_BITS); | 28 | - return bdrv_invalidate_cache(bs, errp); |
27 | 29 | -} | |
28 | /* The zero flag is only supported by version 3 and newer */ | 30 | - |
29 | if (s->qcow_version < 3) { | 31 | -int coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs, Error **errp) |
30 | diff --git a/block/qcow2.c b/block/qcow2.c | 32 | { |
31 | index XXXXXXX..XXXXXXX 100644 | 33 | BdrvChild *child, *parent; |
32 | --- a/block/qcow2.c | 34 | Error *local_err = NULL; |
33 | +++ b/block/qcow2.c | 35 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs, Error **errp) |
34 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options, | ||
35 | |||
36 | bs->supported_zero_flags = header.version >= 3 ? | ||
37 | BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK : 0; | ||
38 | + bs->supported_truncate_flags = BDRV_REQ_ZERO_WRITE; | ||
39 | |||
40 | /* Repair image if dirty */ | ||
41 | if (!(flags & (BDRV_O_CHECK | BDRV_O_INACTIVE)) && !bs->read_only && | ||
42 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset, | ||
43 | g_assert_not_reached(); | ||
44 | } | 36 | } |
45 | 37 | ||
46 | + if ((flags & BDRV_REQ_ZERO_WRITE) && offset > old_length) { | 38 | QLIST_FOREACH(child, &bs->children, next) { |
47 | + uint64_t zero_start = QEMU_ALIGN_UP(old_length, s->cluster_size); | 39 | - bdrv_co_invalidate_cache(child->bs, &local_err); |
40 | + bdrv_activate(child->bs, &local_err); | ||
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 | } | ||
74 | |||
75 | +int coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs, Error **errp) | ||
76 | +{ | ||
77 | + Error *local_err = NULL; | ||
48 | + | 78 | + |
49 | + /* | 79 | + assert(!(bs->open_flags & BDRV_O_INACTIVE)); |
50 | + * Use zero clusters as much as we can. qcow2_cluster_zeroize() | ||
51 | + * requires a cluster-aligned start. The end may be unaligned if it is | ||
52 | + * at the end of the image (which it is here). | ||
53 | + */ | ||
54 | + ret = qcow2_cluster_zeroize(bs, zero_start, offset - zero_start, 0); | ||
55 | + if (ret < 0) { | ||
56 | + error_setg_errno(errp, -ret, "Failed to zero out new clusters"); | ||
57 | + goto fail; | ||
58 | + } | ||
59 | + | 80 | + |
60 | + /* Write explicit zeros for the unaligned head */ | 81 | + if (bs->drv->bdrv_co_invalidate_cache) { |
61 | + if (zero_start > old_length) { | 82 | + bs->drv->bdrv_co_invalidate_cache(bs, &local_err); |
62 | + uint64_t len = zero_start - old_length; | 83 | + if (local_err) { |
63 | + uint8_t *buf = qemu_blockalign0(bs, len); | 84 | + error_propagate(errp, local_err); |
64 | + QEMUIOVector qiov; | 85 | + return -EINVAL; |
65 | + qemu_iovec_init_buf(&qiov, buf, len); | ||
66 | + | ||
67 | + qemu_co_mutex_unlock(&s->lock); | ||
68 | + ret = qcow2_co_pwritev_part(bs, old_length, len, &qiov, 0, 0); | ||
69 | + qemu_co_mutex_lock(&s->lock); | ||
70 | + | ||
71 | + qemu_vfree(buf); | ||
72 | + if (ret < 0) { | ||
73 | + error_setg_errno(errp, -ret, "Failed to zero out the new area"); | ||
74 | + goto fail; | ||
75 | + } | ||
76 | + } | 86 | + } |
77 | + } | 87 | + } |
78 | + | 88 | + |
79 | if (prealloc != PREALLOC_MODE_OFF) { | 89 | + return 0; |
80 | /* Flush metadata before actually changing the image size */ | 90 | +} |
81 | ret = qcow2_write_caches(bs); | 91 | + |
92 | void bdrv_activate_all(Error **errp) | ||
93 | { | ||
94 | BlockDriverState *bs; | ||
82 | -- | 95 | -- |
83 | 2.25.3 | 96 | 2.35.1 |
84 | |||
85 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Stefan Hajnoczi <stefanha@redhat.com> | ||
1 | 2 | ||
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 |
New patch | |||
---|---|---|---|
1 | From: Stefan Hajnoczi <stefanha@redhat.com> | ||
1 | 2 | ||
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> | ||
8 | --- | ||
9 | util/async.c | 12 +++++++----- | ||
10 | 1 file changed, 7 insertions(+), 5 deletions(-) | ||
11 | |||
12 | diff --git a/util/async.c b/util/async.c | ||
13 | index XXXXXXX..XXXXXXX 100644 | ||
14 | --- a/util/async.c | ||
15 | +++ b/util/async.c | ||
16 | @@ -XXX,XX +XXX,XX @@ | ||
17 | #include "qemu/rcu_queue.h" | ||
18 | #include "block/raw-aio.h" | ||
19 | #include "qemu/coroutine_int.h" | ||
20 | +#include "qemu/coroutine-tls.h" | ||
21 | #include "trace.h" | ||
22 | |||
23 | /***********************************************************/ | ||
24 | @@ -XXX,XX +XXX,XX @@ void aio_context_release(AioContext *ctx) | ||
25 | qemu_rec_mutex_unlock(&ctx->lock); | ||
26 | } | ||
27 | |||
28 | -static __thread AioContext *my_aiocontext; | ||
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 | -- | ||
51 | 2.35.1 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Stefan Hajnoczi <stefanha@redhat.com> | ||
1 | 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> | ||
9 | --- | ||
10 | include/qemu/rcu.h | 7 ++++--- | ||
11 | tests/unit/rcutorture.c | 10 +++++----- | ||
12 | tests/unit/test-rcu-list.c | 4 ++-- | ||
13 | util/rcu.c | 10 +++++----- | ||
14 | 4 files changed, 16 insertions(+), 15 deletions(-) | ||
15 | |||
16 | diff --git a/include/qemu/rcu.h b/include/qemu/rcu.h | ||
17 | index XXXXXXX..XXXXXXX 100644 | ||
18 | --- a/include/qemu/rcu.h | ||
19 | +++ b/include/qemu/rcu.h | ||
20 | @@ -XXX,XX +XXX,XX @@ | ||
21 | #include "qemu/atomic.h" | ||
22 | #include "qemu/notify.h" | ||
23 | #include "qemu/sys_membarrier.h" | ||
24 | +#include "qemu/coroutine-tls.h" | ||
25 | |||
26 | #ifdef __cplusplus | ||
27 | extern "C" { | ||
28 | @@ -XXX,XX +XXX,XX @@ struct rcu_reader_data { | ||
29 | NotifierList force_rcu; | ||
30 | }; | ||
31 | |||
32 | -extern __thread struct rcu_reader_data rcu_reader; | ||
33 | +QEMU_DECLARE_CO_TLS(struct rcu_reader_data, rcu_reader) | ||
34 | |||
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 | } | ||
146 | |||
147 | void rcu_unregister_thread(void) | ||
148 | { | ||
149 | qemu_mutex_lock(&rcu_registry_lock); | ||
150 | - QLIST_REMOVE(&rcu_reader, node); | ||
151 | + QLIST_REMOVE(get_ptr_rcu_reader(), node); | ||
152 | qemu_mutex_unlock(&rcu_registry_lock); | ||
153 | } | ||
154 | |||
155 | void rcu_add_force_rcu_notifier(Notifier *n) | ||
156 | { | ||
157 | qemu_mutex_lock(&rcu_registry_lock); | ||
158 | - notifier_list_add(&rcu_reader.force_rcu, n); | ||
159 | + notifier_list_add(&get_ptr_rcu_reader()->force_rcu, n); | ||
160 | qemu_mutex_unlock(&rcu_registry_lock); | ||
161 | } | ||
162 | |||
163 | -- | ||
164 | 2.35.1 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Stefan Hajnoczi <stefanha@redhat.com> | ||
1 | 2 | ||
3 | qemu_mutex_iothread_locked() may be used from coroutines. Standard | ||
4 | __thread variables cannot be used by coroutines. Use the coroutine TLS | ||
5 | macros instead. | ||
6 | |||
7 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
8 | Message-Id: <20220222140150.27240-5-stefanha@redhat.com> | ||
9 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
10 | --- | ||
11 | softmmu/cpus.c | 9 +++++---- | ||
12 | 1 file changed, 5 insertions(+), 4 deletions(-) | ||
13 | |||
14 | diff --git a/softmmu/cpus.c b/softmmu/cpus.c | ||
15 | index XXXXXXX..XXXXXXX 100644 | ||
16 | --- a/softmmu/cpus.c | ||
17 | +++ b/softmmu/cpus.c | ||
18 | @@ -XXX,XX +XXX,XX @@ | ||
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 | } | ||
29 | |||
30 | -static __thread bool iothread_locked = false; | ||
31 | +QEMU_DEFINE_STATIC_CO_TLS(bool, iothread_locked) | ||
32 | |||
33 | bool qemu_mutex_iothread_locked(void) | ||
34 | { | ||
35 | - return iothread_locked; | ||
36 | + return get_iothread_locked(); | ||
37 | } | ||
38 | |||
39 | /* | ||
40 | @@ -XXX,XX +XXX,XX @@ void qemu_mutex_lock_iothread_impl(const char *file, int line) | ||
41 | |||
42 | g_assert(!qemu_mutex_iothread_locked()); | ||
43 | bql_lock(&qemu_global_mutex, file, line); | ||
44 | - iothread_locked = true; | ||
45 | + set_iothread_locked(true); | ||
46 | } | ||
47 | |||
48 | void qemu_mutex_unlock_iothread(void) | ||
49 | { | ||
50 | g_assert(qemu_mutex_iothread_locked()); | ||
51 | - iothread_locked = false; | ||
52 | + set_iothread_locked(false); | ||
53 | qemu_mutex_unlock(&qemu_global_mutex); | ||
54 | } | ||
55 | |||
56 | -- | ||
57 | 2.35.1 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Hanna Reitz <hreitz@redhat.com> | ||
1 | 2 | ||
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> | ||
17 | --- | ||
18 | include/sysemu/os-posix.h | 1 + | ||
19 | include/sysemu/os-win32.h | 8 ++++++++ | ||
20 | os-posix.c | 6 ++++++ | ||
21 | 3 files changed, 15 insertions(+) | ||
22 | |||
23 | diff --git a/include/sysemu/os-posix.h b/include/sysemu/os-posix.h | ||
24 | index XXXXXXX..XXXXXXX 100644 | ||
25 | --- a/include/sysemu/os-posix.h | ||
26 | +++ b/include/sysemu/os-posix.h | ||
27 | @@ -XXX,XX +XXX,XX @@ int os_mlock(void); | ||
28 | typedef struct timeval qemu_timeval; | ||
29 | #define qemu_gettimeofday(tp) gettimeofday(tp, NULL) | ||
30 | |||
31 | +int os_set_daemonize(bool d); | ||
32 | bool is_daemonized(void); | ||
33 | |||
34 | /** | ||
35 | diff --git a/include/sysemu/os-win32.h b/include/sysemu/os-win32.h | ||
36 | index XXXXXXX..XXXXXXX 100644 | ||
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 | +{ | ||
45 | + if (d) { | ||
46 | + return -ENOTSUP; | ||
47 | + } | ||
48 | + return 0; | ||
49 | +} | ||
50 | + | ||
51 | static inline bool is_daemonized(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 | +{ | ||
64 | + daemonize = d; | ||
65 | + return 0; | ||
66 | +} | ||
67 | + | ||
68 | int os_mlock(void) | ||
69 | { | ||
70 | #ifdef HAVE_MLOCKALL | ||
71 | -- | ||
72 | 2.35.1 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Hanna Reitz <hreitz@redhat.com> | ||
1 | 2 | ||
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 |
New patch | |||
---|---|---|---|
1 | From: Hanna Reitz <hreitz@redhat.com> | ||
1 | 2 | ||
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 |
New patch | |||
---|---|---|---|
1 | 1 | From: Hanna Reitz <hreitz@redhat.com> | |
2 | |||
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 |
New patch | |||
---|---|---|---|
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
1 | 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> | ||
23 | --- | ||
24 | include/qemu/main-loop.h | 24 ++++++++++++++++++++++++ | ||
25 | softmmu/cpus.c | 5 +++++ | ||
26 | stubs/iothread-lock.c | 5 +++++ | ||
27 | 3 files changed, 34 insertions(+) | ||
28 | |||
29 | diff --git a/include/qemu/main-loop.h b/include/qemu/main-loop.h | ||
30 | index XXXXXXX..XXXXXXX 100644 | ||
31 | --- a/include/qemu/main-loop.h | ||
32 | +++ b/include/qemu/main-loop.h | ||
33 | @@ -XXX,XX +XXX,XX @@ AioContext *iohandler_get_aio_context(void); | ||
34 | * must always be taken outside other locks. This function helps | ||
35 | * functions take different paths depending on whether the current | ||
36 | * thread is running within the main loop mutex. | ||
37 | + * | ||
38 | + * This function should never be used in the block layer, because | ||
39 | + * unit tests, block layer tools and qemu-storage-daemon do not | ||
40 | + * have a BQL. | ||
41 | + * Please instead refer to qemu_in_main_thread(). | ||
42 | */ | ||
43 | bool qemu_mutex_iothread_locked(void); | ||
44 | |||
45 | +/** | ||
46 | + * qemu_in_main_thread: return whether it's possible to safely access | ||
47 | + * the global state of the block layer. | ||
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 | } | ||
74 | |||
75 | +bool qemu_in_main_thread(void) | ||
76 | +{ | ||
77 | + return qemu_mutex_iothread_locked(); | ||
78 | +} | ||
79 | + | ||
80 | /* | ||
81 | * The BQL is taken from so many places that it is worth profiling the | ||
82 | * callers directly, instead of funneling them all through a single function. | ||
83 | diff --git a/stubs/iothread-lock.c b/stubs/iothread-lock.c | ||
84 | index XXXXXXX..XXXXXXX 100644 | ||
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 | } | ||
90 | |||
91 | +bool qemu_in_main_thread(void) | ||
92 | +{ | ||
93 | + return qemu_get_current_aio_context() == qemu_get_aio_context(); | ||
94 | +} | ||
95 | + | ||
96 | void qemu_mutex_lock_iothread_impl(const char *file, int line) | ||
97 | { | ||
98 | } | ||
99 | -- | ||
100 | 2.35.1 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
1 | 2 | ||
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 |
New patch | |||
---|---|---|---|
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
1 | 2 | ||
3 | block.h currently contains a mix of functions: | ||
4 | some of them run under the BQL and modify the block layer graph, | ||
5 | others are instead thread-safe and perform I/O in iothreads. | ||
6 | Some others can only be called by either the main loop or the | ||
7 | iothread running the AioContext (and not other iothreads), | ||
8 | and using them in another thread would cause deadlocks, and therefore | ||
9 | it is not ideal to define them as I/O. | ||
10 | |||
11 | It is not easy to understand which function is part of which | ||
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 | ||
49 | index XXXXXXX..XXXXXXX | ||
50 | --- /dev/null | ||
51 | +++ b/include/block/block-common.h | ||
52 | @@ -XXX,XX +XXX,XX @@ | ||
53 | +/* | ||
54 | + * QEMU System Emulator block driver | ||
55 | + * | ||
56 | + * Copyright (c) 2003 Fabrice Bellard | ||
57 | + * | ||
58 | + * 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 | ||
60 | + * in the Software without restriction, including without limitation the rights | ||
61 | + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
62 | + * copies of the Software, and to permit persons to whom the Software is | ||
63 | + * furnished to do so, subject to the following conditions: | ||
64 | + * | ||
65 | + * The above copyright notice and this permission notice shall be included in | ||
66 | + * all copies or substantial portions of the Software. | ||
67 | + * | ||
68 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
69 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
70 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
71 | + * 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, | ||
73 | + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
74 | + * THE SOFTWARE. | ||
75 | + */ | ||
76 | +#ifndef BLOCK_COMMON_H | ||
77 | +#define BLOCK_COMMON_H | ||
78 | + | ||
79 | +#include "block/aio.h" | ||
80 | +#include "block/aio-wait.h" | ||
81 | +#include "qemu/iov.h" | ||
82 | +#include "qemu/coroutine.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 | + | ||
89 | +/* | ||
90 | + * generated_co_wrapper | ||
91 | + * | ||
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 | + | ||
99 | +/* block.c */ | ||
100 | +typedef struct BlockDriver BlockDriver; | ||
101 | +typedef struct BdrvChild BdrvChild; | ||
102 | +typedef struct BdrvChildClass BdrvChildClass; | ||
103 | + | ||
104 | +typedef struct BlockDriverInfo { | ||
105 | + /* in bytes, 0 if irrelevant */ | ||
106 | + int cluster_size; | ||
107 | + /* offset at which the VM state can be saved (0 if not possible) */ | ||
108 | + int64_t vm_state_offset; | ||
109 | + bool is_dirty; | ||
110 | + /* | ||
111 | + * True if this block driver only supports compressed writes | ||
112 | + */ | ||
113 | + bool needs_compressed_writes; | ||
114 | +} BlockDriverInfo; | ||
115 | + | ||
116 | +typedef struct BlockFragInfo { | ||
117 | + uint64_t allocated_clusters; | ||
118 | + uint64_t total_clusters; | ||
119 | + uint64_t fragmented_clusters; | ||
120 | + uint64_t compressed_clusters; | ||
121 | +} BlockFragInfo; | ||
122 | + | ||
123 | +typedef enum { | ||
124 | + BDRV_REQ_COPY_ON_READ = 0x1, | ||
125 | + BDRV_REQ_ZERO_WRITE = 0x2, | ||
126 | + | ||
127 | + /* | ||
128 | + * The BDRV_REQ_MAY_UNMAP flag is used in write_zeroes requests to indicate | ||
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 | + | ||
135 | + BDRV_REQ_FUA = 0x10, | ||
136 | + BDRV_REQ_WRITE_COMPRESSED = 0x20, | ||
137 | + | ||
138 | + /* | ||
139 | + * Signifies that this write request will not change the visible disk | ||
140 | + * content. | ||
141 | + */ | ||
142 | + BDRV_REQ_WRITE_UNCHANGED = 0x40, | ||
143 | + | ||
144 | + /* | ||
145 | + * Forces request serialisation. Use only with write requests. | ||
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 | +}; | ||
360 | + | ||
361 | +/* | ||
362 | + * Flags that parent nodes assign to child nodes to specify what kind of | ||
363 | + * role(s) they take. | ||
364 | + * | ||
365 | + * At least one of DATA, METADATA, FILTERED, or COW must be set for | ||
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 | + | ||
375 | + /* | ||
376 | + * This child stores metadata. | ||
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; | ||
641 | + BlockDriverState *bs; | ||
642 | +} BdrvNextIterator; | ||
643 | + | ||
644 | +BlockDriverState *bdrv_first(BdrvNextIterator *it); | ||
645 | +BlockDriverState *bdrv_next(BdrvNextIterator *it); | ||
646 | +void bdrv_next_cleanup(BdrvNextIterator *it); | ||
647 | + | ||
648 | +BlockDriverState *bdrv_next_monitor_owned(BlockDriverState *bs); | ||
649 | +void bdrv_iterate_format(void (*it)(void *opaque, const char *name), | ||
650 | + void *opaque, bool read_only); | ||
651 | +int bdrv_get_flags(BlockDriverState *bs); | ||
652 | +char *bdrv_get_full_backing_filename(BlockDriverState *bs, Error **errp); | ||
653 | +char *bdrv_dirname(BlockDriverState *bs, Error **errp); | ||
654 | + | ||
655 | +void bdrv_img_create(const char *filename, const char *fmt, | ||
656 | + const char *base_filename, const char *base_fmt, | ||
657 | + char *options, uint64_t img_size, int flags, | ||
658 | + bool quiet, Error **errp); | ||
659 | + | ||
660 | +void bdrv_ref(BlockDriverState *bs); | ||
661 | +void bdrv_unref(BlockDriverState *bs); | ||
662 | +void bdrv_unref_child(BlockDriverState *parent, BdrvChild *child); | ||
663 | +BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs, | ||
664 | + BlockDriverState *child_bs, | ||
665 | + const char *child_name, | ||
666 | + const BdrvChildClass *child_class, | ||
667 | + BdrvChildRole child_role, | ||
668 | + Error **errp); | ||
669 | + | ||
670 | +bool bdrv_op_is_blocked(BlockDriverState *bs, BlockOpType op, Error **errp); | ||
671 | +void bdrv_op_block(BlockDriverState *bs, BlockOpType op, Error *reason); | ||
672 | +void bdrv_op_unblock(BlockDriverState *bs, BlockOpType op, Error *reason); | ||
673 | +void bdrv_op_block_all(BlockDriverState *bs, Error *reason); | ||
674 | +void bdrv_op_unblock_all(BlockDriverState *bs, Error *reason); | ||
675 | +bool bdrv_op_blocker_is_empty(BlockDriverState *bs); | ||
676 | + | ||
677 | +int bdrv_debug_breakpoint(BlockDriverState *bs, const char *event, | ||
678 | + const char *tag); | ||
679 | +int bdrv_debug_remove_breakpoint(BlockDriverState *bs, const char *tag); | ||
680 | +int bdrv_debug_resume(BlockDriverState *bs, const char *tag); | ||
681 | +bool bdrv_debug_is_suspended(BlockDriverState *bs, const char *tag); | ||
682 | + | ||
683 | +/** | ||
684 | + * Locks the AioContext of @bs if it's not the current AioContext. This avoids | ||
685 | + * double locking which could lead to deadlocks: This is a coroutine_fn, so we | ||
686 | + * know we already own the lock of the current AioContext. | ||
687 | + * | ||
688 | + * May only be called in the main thread. | ||
689 | + */ | ||
690 | +void coroutine_fn bdrv_co_lock(BlockDriverState *bs); | ||
691 | + | ||
692 | +/** | ||
693 | + * Unlocks the AioContext of @bs if it's not the current AioContext. | ||
694 | + */ | ||
695 | +void coroutine_fn bdrv_co_unlock(BlockDriverState *bs); | ||
696 | + | ||
697 | +void bdrv_set_aio_context_ignore(BlockDriverState *bs, | ||
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 | + | ||
709 | +int bdrv_probe_blocksizes(BlockDriverState *bs, BlockSizes *bsz); | ||
710 | +int bdrv_probe_geometry(BlockDriverState *bs, HDGeometry *geo); | ||
711 | + | ||
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 | ||
1105 | --- a/include/block/block.h | ||
1106 | +++ b/include/block/block.h | ||
1107 | @@ -XXX,XX +XXX,XX @@ | ||
1108 | -#ifndef BLOCK_H | ||
1109 | -#define BLOCK_H | ||
1110 | - | ||
1111 | -#include "block/aio.h" | ||
1112 | -#include "block/aio-wait.h" | ||
1113 | -#include "qemu/iov.h" | ||
1114 | -#include "qemu/coroutine.h" | ||
1115 | -#include "block/accounting.h" | ||
1116 | -#include "block/dirty-bitmap.h" | ||
1117 | -#include "block/blockjob.h" | ||
1118 | -#include "qemu/hbitmap.h" | ||
1119 | -#include "qemu/transactions.h" | ||
1120 | - | ||
1121 | /* | ||
1122 | - * generated_co_wrapper | ||
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 | -- | ||
2035 | 2.35.1 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
1 | 2 | ||
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> | ||
11 | --- | ||
12 | block.c | 125 ++++++++++++++++++++++++++++++++++++++++++++++++- | ||
13 | block/commit.c | 2 + | ||
14 | block/io.c | 11 +++++ | ||
15 | blockdev.c | 1 + | ||
16 | 4 files changed, 137 insertions(+), 2 deletions(-) | ||
17 | |||
18 | diff --git a/block.c b/block.c | ||
19 | index XXXXXXX..XXXXXXX 100644 | ||
20 | --- a/block.c | ||
21 | +++ b/block.c | ||
22 | @@ -XXX,XX +XXX,XX @@ 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 | ||
714 | index XXXXXXX..XXXXXXX 100644 | ||
715 | --- a/block/io.c | ||
716 | +++ b/block/io.c | ||
717 | @@ -XXX,XX +XXX,XX @@ void bdrv_refresh_limits(BlockDriverState *bs, Transaction *tran, Error **errp) | ||
718 | BdrvChild *c; | ||
719 | bool have_limits; | ||
720 | |||
721 | + GLOBAL_STATE_CODE(); | ||
722 | + | ||
723 | if (tran) { | ||
724 | BdrvRefreshLimitsState *s = g_new(BdrvRefreshLimitsState, 1); | ||
725 | *s = (BdrvRefreshLimitsState) { | ||
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) | ||
743 | { | ||
744 | BlockDriverState *bs = NULL; | ||
745 | int drained_end_counter = 0; | ||
746 | + GLOBAL_STATE_CODE(); | ||
747 | |||
748 | /* | ||
749 | * bdrv queue is managed by record/replay, | ||
750 | @@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_end(void) | ||
751 | |||
752 | void bdrv_drain_all(void) | ||
753 | { | ||
754 | + GLOBAL_STATE_CODE(); | ||
755 | bdrv_drain_all_begin(); | ||
756 | bdrv_drain_all_end(); | ||
757 | } | ||
758 | @@ -XXX,XX +XXX,XX @@ int bdrv_flush_all(void) | ||
759 | BlockDriverState *bs = NULL; | ||
760 | int result = 0; | ||
761 | |||
762 | + GLOBAL_STATE_CODE(); | ||
763 | + | ||
764 | /* | ||
765 | * bdrv queue is managed by record/replay, | ||
766 | * creating new flush request for stopping | ||
767 | @@ -XXX,XX +XXX,XX @@ void bdrv_register_buf(BlockDriverState *bs, void *host, size_t size) | ||
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 | } | ||
775 | @@ -XXX,XX +XXX,XX @@ void bdrv_unregister_buf(BlockDriverState *bs, void *host) | ||
776 | { | ||
777 | BdrvChild *child; | ||
778 | |||
779 | + GLOBAL_STATE_CODE(); | ||
780 | if (bs->drv && bs->drv->bdrv_unregister_buf) { | ||
781 | bs->drv->bdrv_unregister_buf(bs, host); | ||
782 | } | ||
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 | -- | ||
804 | 2.35.1 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
1 | 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-6-eesposit@redhat.com> | ||
8 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
9 | --- | ||
10 | include/block/block-io.h | 1 + | ||
11 | block.c | 37 +++++++++++++++++++++++++++++++++- | ||
12 | block/dirty-bitmap.c | 1 + | ||
13 | block/io.c | 43 ++++++++++++++++++++++++++++++++++++++-- | ||
14 | 4 files changed, 79 insertions(+), 3 deletions(-) | ||
15 | |||
16 | diff --git a/include/block/block-io.h b/include/block/block-io.h | ||
17 | index XXXXXXX..XXXXXXX 100644 | ||
18 | --- a/include/block/block-io.h | ||
19 | +++ b/include/block/block-io.h | ||
20 | @@ -XXX,XX +XXX,XX @@ void bdrv_drained_end_no_poll(BlockDriverState *bs, int *drained_end_counter); | ||
21 | |||
22 | #define BDRV_POLL_WHILE(bs, cond) ({ \ | ||
23 | BlockDriverState *bs_ = (bs); \ | ||
24 | + IO_OR_GS_CODE(); \ | ||
25 | AIO_WAIT_WHILE(bdrv_get_aio_context(bs_), \ | ||
26 | cond); }) | ||
27 | |||
28 | diff --git a/block.c b/block.c | ||
29 | index XXXXXXX..XXXXXXX 100644 | ||
30 | --- a/block.c | ||
31 | +++ b/block.c | ||
32 | @@ -XXX,XX +XXX,XX @@ 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 | ||
318 | index XXXXXXX..XXXXXXX 100644 | ||
319 | --- a/block/io.c | ||
320 | +++ b/block/io.c | ||
321 | @@ -XXX,XX +XXX,XX @@ static void bdrv_parent_drained_end_single_no_poll(BdrvChild *c, | ||
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); | ||
350 | } | ||
351 | |||
352 | @@ -XXX,XX +XXX,XX @@ bool bdrv_drain_poll(BlockDriverState *bs, bool recursive, | ||
353 | BdrvChild *ignore_parent, bool ignore_bds_parents) | ||
354 | { | ||
355 | BdrvChild *child, *next; | ||
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 | - | ||
425 | + IO_CODE(); | ||
426 | if (bdrv_get_info(bs, &bdi) < 0 || bdi.cluster_size == 0) { | ||
427 | *cluster_offset = offset; | ||
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 | - | ||
639 | + IO_CODE(); | ||
640 | |||
641 | /* if bs->drv == NULL, bs is closed, so there's nothing to do here */ | ||
642 | if (!drv) { | ||
643 | -- | ||
644 | 2.35.1 | diff view generated by jsdifflib |
1 | From: Andrzej Jakowski <andrzej.jakowski@linux.intel.com> | 1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | This patch introduces support for PMR that has been defined as part of NVMe 1.4 | 3 | Allow writable exports to get BLK_PERM_RESIZE permission |
4 | spec. User can now specify a pmrdev option that should point to HostMemoryBackend. | 4 | from creation, in fuse_export_create(). |
5 | pmrdev memory region will subsequently be exposed as PCI BAR 2 in emulated NVMe | 5 | In this way, there is no need to give the permission in |
6 | device. Guest OS can perform mmio read and writes to the PMR region that will stay | 6 | fuse_do_truncate(), which might be run in an iothread. |
7 | persistent across system reboot. | ||
8 | 7 | ||
9 | Signed-off-by: Andrzej Jakowski <andrzej.jakowski@linux.intel.com> | 8 | Permissions should be set only in the main thread, so |
10 | Reviewed-by: Klaus Jensen <k.jensen@samsung.com> | 9 | in any case if an iothread tries to set RESIZE, it will |
11 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | 10 | be blocked. |
12 | Message-Id: <20200330164656.9348-1-andrzej.jakowski@linux.intel.com> | 11 | |
13 | Reviewed-by: Keith Busch <kbusch@kernel.org> | 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> | ||
14 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 18 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
15 | --- | 19 | --- |
16 | hw/block/nvme.h | 2 + | 20 | block/export/fuse.c | 25 ++++++++++++++++++------- |
17 | include/block/nvme.h | 172 +++++++++++++++++++++++++++++++++++++++++ | 21 | 1 file changed, 18 insertions(+), 7 deletions(-) |
18 | hw/block/nvme.c | 109 ++++++++++++++++++++++++++ | ||
19 | hw/block/Makefile.objs | 2 +- | ||
20 | hw/block/trace-events | 4 + | ||
21 | 5 files changed, 288 insertions(+), 1 deletion(-) | ||
22 | 22 | ||
23 | diff --git a/hw/block/nvme.h b/hw/block/nvme.h | 23 | diff --git a/block/export/fuse.c b/block/export/fuse.c |
24 | index XXXXXXX..XXXXXXX 100644 | 24 | index XXXXXXX..XXXXXXX 100644 |
25 | --- a/hw/block/nvme.h | 25 | --- a/block/export/fuse.c |
26 | +++ b/hw/block/nvme.h | 26 | +++ b/block/export/fuse.c |
27 | @@ -XXX,XX +XXX,XX @@ typedef struct NvmeCtrl { | 27 | @@ -XXX,XX +XXX,XX @@ static int fuse_export_create(BlockExport *blk_exp, |
28 | uint64_t timestamp_set_qemu_clock_ms; /* QEMU clock time */ | 28 | |
29 | 29 | assert(blk_exp_args->type == BLOCK_EXPORT_TYPE_FUSE); | |
30 | char *serial; | 30 | |
31 | + HostMemoryBackend *pmrdev; | 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; | ||
32 | + | 45 | + |
33 | NvmeNamespace *namespaces; | 46 | + /* Growable and writable exports have a permanent RESIZE permission */ |
34 | NvmeSQueue **sq; | 47 | + add_resize_perm = !exp->growable && !exp->writable; |
35 | NvmeCQueue **cq; | 48 | |
36 | diff --git a/include/block/nvme.h b/include/block/nvme.h | 49 | if (req_zero_write) { |
37 | index XXXXXXX..XXXXXXX 100644 | 50 | truncate_flags |= BDRV_REQ_ZERO_WRITE; |
38 | --- a/include/block/nvme.h | 51 | } |
39 | +++ b/include/block/nvme.h | 52 | |
40 | @@ -XXX,XX +XXX,XX @@ typedef struct NvmeBar { | 53 | - /* Growable exports have a permanent RESIZE permission */ |
41 | uint64_t acq; | 54 | - if (!exp->growable) { |
42 | uint32_t cmbloc; | 55 | + if (add_resize_perm) { |
43 | uint32_t cmbsz; | ||
44 | + uint8_t padding[3520]; /* not used by QEMU */ | ||
45 | + uint32_t pmrcap; | ||
46 | + uint32_t pmrctl; | ||
47 | + uint32_t pmrsts; | ||
48 | + uint32_t pmrebs; | ||
49 | + uint32_t pmrswtp; | ||
50 | + uint32_t pmrmsc; | ||
51 | } NvmeBar; | ||
52 | |||
53 | enum NvmeCapShift { | ||
54 | @@ -XXX,XX +XXX,XX @@ enum NvmeCapShift { | ||
55 | CAP_CSS_SHIFT = 37, | ||
56 | CAP_MPSMIN_SHIFT = 48, | ||
57 | CAP_MPSMAX_SHIFT = 52, | ||
58 | + CAP_PMR_SHIFT = 56, | ||
59 | }; | ||
60 | |||
61 | enum NvmeCapMask { | ||
62 | @@ -XXX,XX +XXX,XX @@ enum NvmeCapMask { | ||
63 | CAP_CSS_MASK = 0xff, | ||
64 | CAP_MPSMIN_MASK = 0xf, | ||
65 | CAP_MPSMAX_MASK = 0xf, | ||
66 | + CAP_PMR_MASK = 0x1, | ||
67 | }; | ||
68 | |||
69 | #define NVME_CAP_MQES(cap) (((cap) >> CAP_MQES_SHIFT) & CAP_MQES_MASK) | ||
70 | @@ -XXX,XX +XXX,XX @@ enum NvmeCapMask { | ||
71 | << CAP_MPSMIN_SHIFT) | ||
72 | #define NVME_CAP_SET_MPSMAX(cap, val) (cap |= (uint64_t)(val & CAP_MPSMAX_MASK)\ | ||
73 | << CAP_MPSMAX_SHIFT) | ||
74 | +#define NVME_CAP_SET_PMRS(cap, val) (cap |= (uint64_t)(val & CAP_PMR_MASK)\ | ||
75 | + << CAP_PMR_SHIFT) | ||
76 | |||
77 | enum NvmeCcShift { | ||
78 | CC_EN_SHIFT = 0, | ||
79 | @@ -XXX,XX +XXX,XX @@ enum NvmeCmbszMask { | ||
80 | #define NVME_CMBSZ_GETSIZE(cmbsz) \ | ||
81 | (NVME_CMBSZ_SZ(cmbsz) * (1 << (12 + 4 * NVME_CMBSZ_SZU(cmbsz)))) | ||
82 | |||
83 | +enum NvmePmrcapShift { | ||
84 | + PMRCAP_RDS_SHIFT = 3, | ||
85 | + PMRCAP_WDS_SHIFT = 4, | ||
86 | + PMRCAP_BIR_SHIFT = 5, | ||
87 | + PMRCAP_PMRTU_SHIFT = 8, | ||
88 | + PMRCAP_PMRWBM_SHIFT = 10, | ||
89 | + PMRCAP_PMRTO_SHIFT = 16, | ||
90 | + PMRCAP_CMSS_SHIFT = 24, | ||
91 | +}; | ||
92 | + | 56 | + |
93 | +enum NvmePmrcapMask { | 57 | + if (!qemu_in_main_thread()) { |
94 | + PMRCAP_RDS_MASK = 0x1, | 58 | + /* Changing permissions like below only works in the main thread */ |
95 | + PMRCAP_WDS_MASK = 0x1, | 59 | + return -EPERM; |
96 | + PMRCAP_BIR_MASK = 0x7, | ||
97 | + PMRCAP_PMRTU_MASK = 0x3, | ||
98 | + PMRCAP_PMRWBM_MASK = 0xf, | ||
99 | + PMRCAP_PMRTO_MASK = 0xff, | ||
100 | + PMRCAP_CMSS_MASK = 0x1, | ||
101 | +}; | ||
102 | + | ||
103 | +#define NVME_PMRCAP_RDS(pmrcap) \ | ||
104 | + ((pmrcap >> PMRCAP_RDS_SHIFT) & PMRCAP_RDS_MASK) | ||
105 | +#define NVME_PMRCAP_WDS(pmrcap) \ | ||
106 | + ((pmrcap >> PMRCAP_WDS_SHIFT) & PMRCAP_WDS_MASK) | ||
107 | +#define NVME_PMRCAP_BIR(pmrcap) \ | ||
108 | + ((pmrcap >> PMRCAP_BIR_SHIFT) & PMRCAP_BIR_MASK) | ||
109 | +#define NVME_PMRCAP_PMRTU(pmrcap) \ | ||
110 | + ((pmrcap >> PMRCAP_PMRTU_SHIFT) & PMRCAP_PMRTU_MASK) | ||
111 | +#define NVME_PMRCAP_PMRWBM(pmrcap) \ | ||
112 | + ((pmrcap >> PMRCAP_PMRWBM_SHIFT) & PMRCAP_PMRWBM_MASK) | ||
113 | +#define NVME_PMRCAP_PMRTO(pmrcap) \ | ||
114 | + ((pmrcap >> PMRCAP_PMRTO_SHIFT) & PMRCAP_PMRTO_MASK) | ||
115 | +#define NVME_PMRCAP_CMSS(pmrcap) \ | ||
116 | + ((pmrcap >> PMRCAP_CMSS_SHIFT) & PMRCAP_CMSS_MASK) | ||
117 | + | ||
118 | +#define NVME_PMRCAP_SET_RDS(pmrcap, val) \ | ||
119 | + (pmrcap |= (uint64_t)(val & PMRCAP_RDS_MASK) << PMRCAP_RDS_SHIFT) | ||
120 | +#define NVME_PMRCAP_SET_WDS(pmrcap, val) \ | ||
121 | + (pmrcap |= (uint64_t)(val & PMRCAP_WDS_MASK) << PMRCAP_WDS_SHIFT) | ||
122 | +#define NVME_PMRCAP_SET_BIR(pmrcap, val) \ | ||
123 | + (pmrcap |= (uint64_t)(val & PMRCAP_BIR_MASK) << PMRCAP_BIR_SHIFT) | ||
124 | +#define NVME_PMRCAP_SET_PMRTU(pmrcap, val) \ | ||
125 | + (pmrcap |= (uint64_t)(val & PMRCAP_PMRTU_MASK) << PMRCAP_PMRTU_SHIFT) | ||
126 | +#define NVME_PMRCAP_SET_PMRWBM(pmrcap, val) \ | ||
127 | + (pmrcap |= (uint64_t)(val & PMRCAP_PMRWBM_MASK) << PMRCAP_PMRWBM_SHIFT) | ||
128 | +#define NVME_PMRCAP_SET_PMRTO(pmrcap, val) \ | ||
129 | + (pmrcap |= (uint64_t)(val & PMRCAP_PMRTO_MASK) << PMRCAP_PMRTO_SHIFT) | ||
130 | +#define NVME_PMRCAP_SET_CMSS(pmrcap, val) \ | ||
131 | + (pmrcap |= (uint64_t)(val & PMRCAP_CMSS_MASK) << PMRCAP_CMSS_SHIFT) | ||
132 | + | ||
133 | +enum NvmePmrctlShift { | ||
134 | + PMRCTL_EN_SHIFT = 0, | ||
135 | +}; | ||
136 | + | ||
137 | +enum NvmePmrctlMask { | ||
138 | + PMRCTL_EN_MASK = 0x1, | ||
139 | +}; | ||
140 | + | ||
141 | +#define NVME_PMRCTL_EN(pmrctl) ((pmrctl >> PMRCTL_EN_SHIFT) & PMRCTL_EN_MASK) | ||
142 | + | ||
143 | +#define NVME_PMRCTL_SET_EN(pmrctl, val) \ | ||
144 | + (pmrctl |= (uint64_t)(val & PMRCTL_EN_MASK) << PMRCTL_EN_SHIFT) | ||
145 | + | ||
146 | +enum NvmePmrstsShift { | ||
147 | + PMRSTS_ERR_SHIFT = 0, | ||
148 | + PMRSTS_NRDY_SHIFT = 8, | ||
149 | + PMRSTS_HSTS_SHIFT = 9, | ||
150 | + PMRSTS_CBAI_SHIFT = 12, | ||
151 | +}; | ||
152 | + | ||
153 | +enum NvmePmrstsMask { | ||
154 | + PMRSTS_ERR_MASK = 0xff, | ||
155 | + PMRSTS_NRDY_MASK = 0x1, | ||
156 | + PMRSTS_HSTS_MASK = 0x7, | ||
157 | + PMRSTS_CBAI_MASK = 0x1, | ||
158 | +}; | ||
159 | + | ||
160 | +#define NVME_PMRSTS_ERR(pmrsts) \ | ||
161 | + ((pmrsts >> PMRSTS_ERR_SHIFT) & PMRSTS_ERR_MASK) | ||
162 | +#define NVME_PMRSTS_NRDY(pmrsts) \ | ||
163 | + ((pmrsts >> PMRSTS_NRDY_SHIFT) & PMRSTS_NRDY_MASK) | ||
164 | +#define NVME_PMRSTS_HSTS(pmrsts) \ | ||
165 | + ((pmrsts >> PMRSTS_HSTS_SHIFT) & PMRSTS_HSTS_MASK) | ||
166 | +#define NVME_PMRSTS_CBAI(pmrsts) \ | ||
167 | + ((pmrsts >> PMRSTS_CBAI_SHIFT) & PMRSTS_CBAI_MASK) | ||
168 | + | ||
169 | +#define NVME_PMRSTS_SET_ERR(pmrsts, val) \ | ||
170 | + (pmrsts |= (uint64_t)(val & PMRSTS_ERR_MASK) << PMRSTS_ERR_SHIFT) | ||
171 | +#define NVME_PMRSTS_SET_NRDY(pmrsts, val) \ | ||
172 | + (pmrsts |= (uint64_t)(val & PMRSTS_NRDY_MASK) << PMRSTS_NRDY_SHIFT) | ||
173 | +#define NVME_PMRSTS_SET_HSTS(pmrsts, val) \ | ||
174 | + (pmrsts |= (uint64_t)(val & PMRSTS_HSTS_MASK) << PMRSTS_HSTS_SHIFT) | ||
175 | +#define NVME_PMRSTS_SET_CBAI(pmrsts, val) \ | ||
176 | + (pmrsts |= (uint64_t)(val & PMRSTS_CBAI_MASK) << PMRSTS_CBAI_SHIFT) | ||
177 | + | ||
178 | +enum NvmePmrebsShift { | ||
179 | + PMREBS_PMRSZU_SHIFT = 0, | ||
180 | + PMREBS_RBB_SHIFT = 4, | ||
181 | + PMREBS_PMRWBZ_SHIFT = 8, | ||
182 | +}; | ||
183 | + | ||
184 | +enum NvmePmrebsMask { | ||
185 | + PMREBS_PMRSZU_MASK = 0xf, | ||
186 | + PMREBS_RBB_MASK = 0x1, | ||
187 | + PMREBS_PMRWBZ_MASK = 0xffffff, | ||
188 | +}; | ||
189 | + | ||
190 | +#define NVME_PMREBS_PMRSZU(pmrebs) \ | ||
191 | + ((pmrebs >> PMREBS_PMRSZU_SHIFT) & PMREBS_PMRSZU_MASK) | ||
192 | +#define NVME_PMREBS_RBB(pmrebs) \ | ||
193 | + ((pmrebs >> PMREBS_RBB_SHIFT) & PMREBS_RBB_MASK) | ||
194 | +#define NVME_PMREBS_PMRWBZ(pmrebs) \ | ||
195 | + ((pmrebs >> PMREBS_PMRWBZ_SHIFT) & PMREBS_PMRWBZ_MASK) | ||
196 | + | ||
197 | +#define NVME_PMREBS_SET_PMRSZU(pmrebs, val) \ | ||
198 | + (pmrebs |= (uint64_t)(val & PMREBS_PMRSZU_MASK) << PMREBS_PMRSZU_SHIFT) | ||
199 | +#define NVME_PMREBS_SET_RBB(pmrebs, val) \ | ||
200 | + (pmrebs |= (uint64_t)(val & PMREBS_RBB_MASK) << PMREBS_RBB_SHIFT) | ||
201 | +#define NVME_PMREBS_SET_PMRWBZ(pmrebs, val) \ | ||
202 | + (pmrebs |= (uint64_t)(val & PMREBS_PMRWBZ_MASK) << PMREBS_PMRWBZ_SHIFT) | ||
203 | + | ||
204 | +enum NvmePmrswtpShift { | ||
205 | + PMRSWTP_PMRSWTU_SHIFT = 0, | ||
206 | + PMRSWTP_PMRSWTV_SHIFT = 8, | ||
207 | +}; | ||
208 | + | ||
209 | +enum NvmePmrswtpMask { | ||
210 | + PMRSWTP_PMRSWTU_MASK = 0xf, | ||
211 | + PMRSWTP_PMRSWTV_MASK = 0xffffff, | ||
212 | +}; | ||
213 | + | ||
214 | +#define NVME_PMRSWTP_PMRSWTU(pmrswtp) \ | ||
215 | + ((pmrswtp >> PMRSWTP_PMRSWTU_SHIFT) & PMRSWTP_PMRSWTU_MASK) | ||
216 | +#define NVME_PMRSWTP_PMRSWTV(pmrswtp) \ | ||
217 | + ((pmrswtp >> PMRSWTP_PMRSWTV_SHIFT) & PMRSWTP_PMRSWTV_MASK) | ||
218 | + | ||
219 | +#define NVME_PMRSWTP_SET_PMRSWTU(pmrswtp, val) \ | ||
220 | + (pmrswtp |= (uint64_t)(val & PMRSWTP_PMRSWTU_MASK) << PMRSWTP_PMRSWTU_SHIFT) | ||
221 | +#define NVME_PMRSWTP_SET_PMRSWTV(pmrswtp, val) \ | ||
222 | + (pmrswtp |= (uint64_t)(val & PMRSWTP_PMRSWTV_MASK) << PMRSWTP_PMRSWTV_SHIFT) | ||
223 | + | ||
224 | +enum NvmePmrmscShift { | ||
225 | + PMRMSC_CMSE_SHIFT = 1, | ||
226 | + PMRMSC_CBA_SHIFT = 12, | ||
227 | +}; | ||
228 | + | ||
229 | +enum NvmePmrmscMask { | ||
230 | + PMRMSC_CMSE_MASK = 0x1, | ||
231 | + PMRMSC_CBA_MASK = 0xfffffffffffff, | ||
232 | +}; | ||
233 | + | ||
234 | +#define NVME_PMRMSC_CMSE(pmrmsc) \ | ||
235 | + ((pmrmsc >> PMRMSC_CMSE_SHIFT) & PMRMSC_CMSE_MASK) | ||
236 | +#define NVME_PMRMSC_CBA(pmrmsc) \ | ||
237 | + ((pmrmsc >> PMRMSC_CBA_SHIFT) & PMRMSC_CBA_MASK) | ||
238 | + | ||
239 | +#define NVME_PMRMSC_SET_CMSE(pmrmsc, val) \ | ||
240 | + (pmrmsc |= (uint64_t)(val & PMRMSC_CMSE_MASK) << PMRMSC_CMSE_SHIFT) | ||
241 | +#define NVME_PMRMSC_SET_CBA(pmrmsc, val) \ | ||
242 | + (pmrmsc |= (uint64_t)(val & PMRMSC_CBA_MASK) << PMRMSC_CBA_SHIFT) | ||
243 | + | ||
244 | typedef struct NvmeCmd { | ||
245 | uint8_t opcode; | ||
246 | uint8_t fuse; | ||
247 | diff --git a/hw/block/nvme.c b/hw/block/nvme.c | ||
248 | index XXXXXXX..XXXXXXX 100644 | ||
249 | --- a/hw/block/nvme.c | ||
250 | +++ b/hw/block/nvme.c | ||
251 | @@ -XXX,XX +XXX,XX @@ | ||
252 | * -drive file=<file>,if=none,id=<drive_id> | ||
253 | * -device nvme,drive=<drive_id>,serial=<serial>,id=<id[optional]>, \ | ||
254 | * cmb_size_mb=<cmb_size_mb[optional]>, \ | ||
255 | + * [pmrdev=<mem_backend_file_id>,] \ | ||
256 | * num_queues=<N[optional]> | ||
257 | * | ||
258 | * Note cmb_size_mb denotes size of CMB in MB. CMB is assumed to be at | ||
259 | * offset 0 in BAR2 and supports only WDS, RDS and SQS for now. | ||
260 | + * | ||
261 | + * cmb_size_mb= and pmrdev= options are mutually exclusive due to limitation | ||
262 | + * in available BAR's. cmb_size_mb= will take precedence over pmrdev= when | ||
263 | + * both provided. | ||
264 | + * Enabling pmr emulation can be achieved by pointing to memory-backend-file. | ||
265 | + * For example: | ||
266 | + * -object memory-backend-file,id=<mem_id>,share=on,mem-path=<file_path>, \ | ||
267 | + * size=<size> .... -device nvme,...,pmrdev=<mem_id> | ||
268 | */ | ||
269 | |||
270 | #include "qemu/osdep.h" | ||
271 | @@ -XXX,XX +XXX,XX @@ | ||
272 | #include "sysemu/sysemu.h" | ||
273 | #include "qapi/error.h" | ||
274 | #include "qapi/visitor.h" | ||
275 | +#include "sysemu/hostmem.h" | ||
276 | #include "sysemu/block-backend.h" | ||
277 | +#include "exec/ram_addr.h" | ||
278 | |||
279 | #include "qemu/log.h" | ||
280 | #include "qemu/module.h" | ||
281 | @@ -XXX,XX +XXX,XX @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data, | ||
282 | NVME_GUEST_ERR(nvme_ub_mmiowr_cmbsz_readonly, | ||
283 | "invalid write to read only CMBSZ, ignored"); | ||
284 | return; | ||
285 | + case 0xE00: /* PMRCAP */ | ||
286 | + NVME_GUEST_ERR(nvme_ub_mmiowr_pmrcap_readonly, | ||
287 | + "invalid write to PMRCAP register, ignored"); | ||
288 | + return; | ||
289 | + case 0xE04: /* TODO PMRCTL */ | ||
290 | + break; | ||
291 | + case 0xE08: /* PMRSTS */ | ||
292 | + NVME_GUEST_ERR(nvme_ub_mmiowr_pmrsts_readonly, | ||
293 | + "invalid write to PMRSTS register, ignored"); | ||
294 | + return; | ||
295 | + case 0xE0C: /* PMREBS */ | ||
296 | + NVME_GUEST_ERR(nvme_ub_mmiowr_pmrebs_readonly, | ||
297 | + "invalid write to PMREBS register, ignored"); | ||
298 | + return; | ||
299 | + case 0xE10: /* PMRSWTP */ | ||
300 | + NVME_GUEST_ERR(nvme_ub_mmiowr_pmrswtp_readonly, | ||
301 | + "invalid write to PMRSWTP register, ignored"); | ||
302 | + return; | ||
303 | + case 0xE14: /* TODO PMRMSC */ | ||
304 | + break; | ||
305 | default: | ||
306 | NVME_GUEST_ERR(nvme_ub_mmiowr_invalid, | ||
307 | "invalid MMIO write," | ||
308 | @@ -XXX,XX +XXX,XX @@ static uint64_t nvme_mmio_read(void *opaque, hwaddr addr, unsigned size) | ||
309 | } | ||
310 | |||
311 | if (addr < sizeof(n->bar)) { | ||
312 | + /* | ||
313 | + * When PMRWBM bit 1 is set then read from | ||
314 | + * from PMRSTS should ensure prior writes | ||
315 | + * made it to persistent media | ||
316 | + */ | ||
317 | + if (addr == 0xE08 && | ||
318 | + (NVME_PMRCAP_PMRWBM(n->bar.pmrcap) & 0x02)) { | ||
319 | + qemu_ram_writeback(n->pmrdev->mr.ram_block, | ||
320 | + 0, n->pmrdev->size); | ||
321 | + } | ||
322 | memcpy(&val, ptr + addr, size); | ||
323 | } else { | ||
324 | NVME_GUEST_ERR(nvme_ub_mmiord_invalid_ofs, | ||
325 | @@ -XXX,XX +XXX,XX @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp) | ||
326 | error_setg(errp, "serial property not set"); | ||
327 | return; | ||
328 | } | ||
329 | + | ||
330 | + if (!n->cmb_size_mb && n->pmrdev) { | ||
331 | + if (host_memory_backend_is_mapped(n->pmrdev)) { | ||
332 | + char *path = object_get_canonical_path_component(OBJECT(n->pmrdev)); | ||
333 | + error_setg(errp, "can't use already busy memdev: %s", path); | ||
334 | + g_free(path); | ||
335 | + return; | ||
336 | + } | 60 | + } |
337 | + | 61 | + |
338 | + if (!is_power_of_2(n->pmrdev->size)) { | 62 | blk_get_perm(exp->common.blk, &blk_perm, &blk_shared_perm); |
339 | + error_setg(errp, "pmr backend size needs to be power of 2 in size"); | 63 | |
340 | + return; | 64 | ret = blk_set_perm(exp->common.blk, blk_perm | BLK_PERM_RESIZE, |
341 | + } | 65 | @@ -XXX,XX +XXX,XX @@ static int fuse_do_truncate(const FuseExport *exp, int64_t size, |
342 | + | 66 | ret = blk_truncate(exp->common.blk, size, true, prealloc, |
343 | + host_memory_backend_set_mapped(n->pmrdev, true); | 67 | truncate_flags, NULL); |
344 | + } | 68 | |
345 | + | 69 | - if (!exp->growable) { |
346 | blkconf_blocksizes(&n->conf); | 70 | + if (add_resize_perm) { |
347 | if (!blkconf_apply_backend_options(&n->conf, blk_is_read_only(n->conf.blk), | 71 | /* Must succeed, because we are only giving up the RESIZE permission */ |
348 | false, errp)) { | 72 | - blk_set_perm(exp->common.blk, blk_perm, blk_shared_perm, &error_abort); |
349 | @@ -XXX,XX +XXX,XX @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp) | 73 | + ret_check = blk_set_perm(exp->common.blk, blk_perm, |
350 | PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64 | | 74 | + blk_shared_perm, &error_abort); |
351 | PCI_BASE_ADDRESS_MEM_PREFETCH, &n->ctrl_mem); | 75 | + assert(ret_check == 0); |
352 | |||
353 | + } else if (n->pmrdev) { | ||
354 | + /* Controller Capabilities register */ | ||
355 | + NVME_CAP_SET_PMRS(n->bar.cap, 1); | ||
356 | + | ||
357 | + /* PMR Capabities register */ | ||
358 | + n->bar.pmrcap = 0; | ||
359 | + NVME_PMRCAP_SET_RDS(n->bar.pmrcap, 0); | ||
360 | + NVME_PMRCAP_SET_WDS(n->bar.pmrcap, 0); | ||
361 | + NVME_PMRCAP_SET_BIR(n->bar.pmrcap, 2); | ||
362 | + NVME_PMRCAP_SET_PMRTU(n->bar.pmrcap, 0); | ||
363 | + /* Turn on bit 1 support */ | ||
364 | + NVME_PMRCAP_SET_PMRWBM(n->bar.pmrcap, 0x02); | ||
365 | + NVME_PMRCAP_SET_PMRTO(n->bar.pmrcap, 0); | ||
366 | + NVME_PMRCAP_SET_CMSS(n->bar.pmrcap, 0); | ||
367 | + | ||
368 | + /* PMR Control register */ | ||
369 | + n->bar.pmrctl = 0; | ||
370 | + NVME_PMRCTL_SET_EN(n->bar.pmrctl, 0); | ||
371 | + | ||
372 | + /* PMR Status register */ | ||
373 | + n->bar.pmrsts = 0; | ||
374 | + NVME_PMRSTS_SET_ERR(n->bar.pmrsts, 0); | ||
375 | + NVME_PMRSTS_SET_NRDY(n->bar.pmrsts, 0); | ||
376 | + NVME_PMRSTS_SET_HSTS(n->bar.pmrsts, 0); | ||
377 | + NVME_PMRSTS_SET_CBAI(n->bar.pmrsts, 0); | ||
378 | + | ||
379 | + /* PMR Elasticity Buffer Size register */ | ||
380 | + n->bar.pmrebs = 0; | ||
381 | + NVME_PMREBS_SET_PMRSZU(n->bar.pmrebs, 0); | ||
382 | + NVME_PMREBS_SET_RBB(n->bar.pmrebs, 0); | ||
383 | + NVME_PMREBS_SET_PMRWBZ(n->bar.pmrebs, 0); | ||
384 | + | ||
385 | + /* PMR Sustained Write Throughput register */ | ||
386 | + n->bar.pmrswtp = 0; | ||
387 | + NVME_PMRSWTP_SET_PMRSWTU(n->bar.pmrswtp, 0); | ||
388 | + NVME_PMRSWTP_SET_PMRSWTV(n->bar.pmrswtp, 0); | ||
389 | + | ||
390 | + /* PMR Memory Space Control register */ | ||
391 | + n->bar.pmrmsc = 0; | ||
392 | + NVME_PMRMSC_SET_CMSE(n->bar.pmrmsc, 0); | ||
393 | + NVME_PMRMSC_SET_CBA(n->bar.pmrmsc, 0); | ||
394 | + | ||
395 | + pci_register_bar(pci_dev, NVME_PMRCAP_BIR(n->bar.pmrcap), | ||
396 | + PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64 | | ||
397 | + PCI_BASE_ADDRESS_MEM_PREFETCH, &n->pmrdev->mr); | ||
398 | } | 76 | } |
399 | 77 | ||
400 | for (i = 0; i < n->num_namespaces; i++) { | 78 | return ret; |
401 | @@ -XXX,XX +XXX,XX @@ static void nvme_exit(PCIDevice *pci_dev) | ||
402 | if (n->cmb_size_mb) { | ||
403 | g_free(n->cmbuf); | ||
404 | } | ||
405 | + | ||
406 | + if (n->pmrdev) { | ||
407 | + host_memory_backend_set_mapped(n->pmrdev, false); | ||
408 | + } | ||
409 | msix_uninit_exclusive_bar(pci_dev); | ||
410 | } | ||
411 | |||
412 | static Property nvme_props[] = { | ||
413 | DEFINE_BLOCK_PROPERTIES(NvmeCtrl, conf), | ||
414 | + DEFINE_PROP_LINK("pmrdev", NvmeCtrl, pmrdev, TYPE_MEMORY_BACKEND, | ||
415 | + HostMemoryBackend *), | ||
416 | DEFINE_PROP_STRING("serial", NvmeCtrl, serial), | ||
417 | DEFINE_PROP_UINT32("cmb_size_mb", NvmeCtrl, cmb_size_mb, 0), | ||
418 | DEFINE_PROP_UINT32("num_queues", NvmeCtrl, num_queues, 64), | ||
419 | diff --git a/hw/block/Makefile.objs b/hw/block/Makefile.objs | ||
420 | index XXXXXXX..XXXXXXX 100644 | ||
421 | --- a/hw/block/Makefile.objs | ||
422 | +++ b/hw/block/Makefile.objs | ||
423 | @@ -XXX,XX +XXX,XX @@ common-obj-$(CONFIG_PFLASH_CFI02) += pflash_cfi02.o | ||
424 | common-obj-$(CONFIG_XEN) += xen-block.o | ||
425 | common-obj-$(CONFIG_ECC) += ecc.o | ||
426 | common-obj-$(CONFIG_ONENAND) += onenand.o | ||
427 | -common-obj-$(CONFIG_NVME_PCI) += nvme.o | ||
428 | common-obj-$(CONFIG_SWIM) += swim.o | ||
429 | |||
430 | common-obj-$(CONFIG_SH4) += tc58128.o | ||
431 | |||
432 | obj-$(CONFIG_VIRTIO_BLK) += virtio-blk.o | ||
433 | obj-$(CONFIG_VHOST_USER_BLK) += vhost-user-blk.o | ||
434 | +obj-$(CONFIG_NVME_PCI) += nvme.o | ||
435 | |||
436 | obj-y += dataplane/ | ||
437 | diff --git a/hw/block/trace-events b/hw/block/trace-events | ||
438 | index XXXXXXX..XXXXXXX 100644 | ||
439 | --- a/hw/block/trace-events | ||
440 | +++ b/hw/block/trace-events | ||
441 | @@ -XXX,XX +XXX,XX @@ nvme_ub_mmiowr_ssreset_w1c_unsupported(void) "attempted to W1C CSTS.NSSRO but CA | ||
442 | nvme_ub_mmiowr_ssreset_unsupported(void) "attempted NVM subsystem reset but CAP.NSSRS is zero (not supported)" | ||
443 | nvme_ub_mmiowr_cmbloc_reserved(void) "invalid write to reserved CMBLOC when CMBSZ is zero, ignored" | ||
444 | nvme_ub_mmiowr_cmbsz_readonly(void) "invalid write to read only CMBSZ, ignored" | ||
445 | +nvme_ub_mmiowr_pmrcap_readonly(void) "invalid write to read only PMRCAP, ignored" | ||
446 | +nvme_ub_mmiowr_pmrsts_readonly(void) "invalid write to read only PMRSTS, ignored" | ||
447 | +nvme_ub_mmiowr_pmrebs_readonly(void) "invalid write to read only PMREBS, ignored" | ||
448 | +nvme_ub_mmiowr_pmrswtp_readonly(void) "invalid write to read only PMRSWTP, ignored" | ||
449 | nvme_ub_mmiowr_invalid(uint64_t offset, uint64_t data) "invalid MMIO write, offset=0x%"PRIx64", data=0x%"PRIx64"" | ||
450 | nvme_ub_mmiord_misaligned32(uint64_t offset) "MMIO read not 32-bit aligned, offset=0x%"PRIx64"" | ||
451 | nvme_ub_mmiord_toosmall(uint64_t offset) "MMIO read smaller than 32-bits, offset=0x%"PRIx64"" | ||
452 | -- | 79 | -- |
453 | 2.25.3 | 80 | 2.35.1 |
454 | |||
455 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
1 | 2 | ||
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> | ||
18 | --- | ||
19 | include/sysemu/block-backend-common.h | 84 ++++++ | ||
20 | include/sysemu/block-backend-global-state.h | 116 +++++++++ | ||
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 | |||
29 | diff --git a/include/sysemu/block-backend-common.h b/include/sysemu/block-backend-common.h | ||
30 | new file mode 100644 | ||
31 | index XXXXXXX..XXXXXXX | ||
32 | --- /dev/null | ||
33 | +++ b/include/sysemu/block-backend-common.h | ||
34 | @@ -XXX,XX +XXX,XX @@ | ||
35 | +/* | ||
36 | + * QEMU Block backends | ||
37 | + * | ||
38 | + * Copyright (C) 2014-2016 Red Hat, Inc. | ||
39 | + * | ||
40 | + * Authors: | ||
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 | + | ||
47 | +#ifndef BLOCK_BACKEND_COMMON_H | ||
48 | +#define BLOCK_BACKEND_COMMON_H | ||
49 | + | ||
50 | +#include "qemu/iov.h" | ||
51 | +#include "block/throttle-groups.h" | ||
52 | + | ||
53 | +/* | ||
54 | + * TODO Have to include block/block.h for a bunch of block layer | ||
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 | + | ||
62 | +/* Callbacks for block device models */ | ||
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 | + | ||
109 | +/* | ||
110 | + * This struct is embedded in (the private) BlockBackend struct and contains | ||
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 | + | ||
118 | +#endif /* BLOCK_BACKEND_COMMON_H */ | ||
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 | + | ||
137 | +#ifndef BLOCK_BACKEND_GS_H | ||
138 | +#define BLOCK_BACKEND_GS_H | ||
139 | + | ||
140 | +#include "block-backend-common.h" | ||
141 | + | ||
142 | +/* | ||
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 | +} | ||
375 | + | ||
376 | +static inline int coroutine_fn blk_co_pwrite(BlockBackend *blk, int64_t offset, | ||
377 | + int64_t bytes, void *buf, | ||
378 | + BdrvRequestFlags flags) | ||
379 | +{ | ||
380 | + QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes); | ||
381 | + | ||
382 | + assert(bytes <= SIZE_MAX); | ||
383 | + | ||
384 | + return blk_co_pwritev(blk, offset, bytes, &qiov, flags); | ||
385 | +} | ||
386 | + | ||
387 | +int coroutine_fn blk_co_pdiscard(BlockBackend *blk, int64_t offset, | ||
388 | + int64_t bytes); | ||
389 | + | ||
390 | +int coroutine_fn blk_co_flush(BlockBackend *blk); | ||
391 | +int blk_flush(BlockBackend *blk); | ||
392 | + | ||
393 | +int blk_ioctl(BlockBackend *blk, unsigned long int req, void *buf); | ||
394 | + | ||
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 | -- | ||
717 | 2.35.1 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
1 | 2 | ||
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-9-eesposit@redhat.com> | ||
10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
11 | --- | ||
12 | block/block-backend.c | 78 ++++++++++++++++++++++++++++++++++++++++++ | ||
13 | softmmu/qdev-monitor.c | 2 ++ | ||
14 | 2 files changed, 80 insertions(+) | ||
15 | |||
16 | diff --git a/block/block-backend.c b/block/block-backend.c | ||
17 | index XXXXXXX..XXXXXXX 100644 | ||
18 | --- a/block/block-backend.c | ||
19 | +++ b/block/block-backend.c | ||
20 | @@ -XXX,XX +XXX,XX @@ static void blk_root_activate(BdrvChild *child, Error **errp) | ||
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; | ||
128 | } | ||
129 | @@ -XXX,XX +XXX,XX @@ BlockBackend *blk_by_name(const char *name) | ||
130 | { | ||
131 | BlockBackend *blk = NULL; | ||
132 | |||
133 | + GLOBAL_STATE_CODE(); | ||
134 | assert(name); | ||
135 | while ((blk = blk_next(blk)) != NULL) { | ||
136 | if (!strcmp(name, blk->name)) { | ||
137 | @@ -XXX,XX +XXX,XX @@ static BlockBackend *bdrv_first_blk(BlockDriverState *bs) | ||
138 | */ | ||
139 | bool bdrv_has_blk(BlockDriverState *bs) | ||
140 | { | ||
141 | + GLOBAL_STATE_CODE(); | ||
142 | return bdrv_first_blk(bs) != NULL; | ||
143 | } | ||
144 | |||
145 | @@ -XXX,XX +XXX,XX @@ bool bdrv_is_root_node(BlockDriverState *bs) | ||
146 | { | ||
147 | BdrvChild *c; | ||
148 | |||
149 | + GLOBAL_STATE_CODE(); | ||
150 | QLIST_FOREACH(c, &bs->parents, next_parent) { | ||
151 | if (c->klass != &child_root) { | ||
152 | return false; | ||
153 | @@ -XXX,XX +XXX,XX @@ BlockBackend *blk_by_legacy_dinfo(DriveInfo *dinfo) | ||
154 | */ | ||
155 | BlockBackendPublic *blk_get_public(BlockBackend *blk) | ||
156 | { | ||
157 | + GLOBAL_STATE_CODE(); | ||
158 | return &blk->public; | ||
159 | } | ||
160 | |||
161 | @@ -XXX,XX +XXX,XX @@ BlockBackendPublic *blk_get_public(BlockBackend *blk) | ||
162 | */ | ||
163 | BlockBackend *blk_by_public(BlockBackendPublic *public) | ||
164 | { | ||
165 | + GLOBAL_STATE_CODE(); | ||
166 | return container_of(public, BlockBackend, public); | ||
167 | } | ||
168 | |||
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 | } | ||
218 | @@ -XXX,XX +XXX,XX @@ int blk_attach_dev(BlockBackend *blk, DeviceState *dev) | ||
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 | -- | ||
580 | 2.35.1 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
1 | 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> | ||
9 | --- | ||
10 | include/sysemu/block-backend-io.h | 2 ++ | ||
11 | block/block-backend.c | 58 +++++++++++++++++++++++++++++++ | ||
12 | 2 files changed, 60 insertions(+) | ||
13 | |||
14 | diff --git a/include/sysemu/block-backend-io.h b/include/sysemu/block-backend-io.h | ||
15 | index XXXXXXX..XXXXXXX 100644 | ||
16 | --- a/include/sysemu/block-backend-io.h | ||
17 | +++ b/include/sysemu/block-backend-io.h | ||
18 | @@ -XXX,XX +XXX,XX @@ static inline int coroutine_fn blk_co_pread(BlockBackend *blk, int64_t offset, | ||
19 | BdrvRequestFlags flags) | ||
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 | } | ||
45 | |||
46 | @@ -XXX,XX +XXX,XX @@ BlockBackend *blk_by_name(const char *name) | ||
47 | */ | ||
48 | BlockDriverState *blk_bs(BlockBackend *blk) | ||
49 | { | ||
50 | + IO_CODE(); | ||
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 | + | ||
474 | r = blk_check_byte_request(blk_in, off_in, bytes); | ||
475 | if (r) { | ||
476 | return r; | ||
477 | -- | ||
478 | 2.35.1 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
1 | 2 | ||
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 |
New patch | |||
---|---|---|---|
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
1 | 2 | ||
3 | Similarly to the previous patch, split block_int.h | ||
4 | in block_int-io.h and block_int-global-state.h | ||
5 | |||
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> | ||
15 | --- | ||
16 | include/block/block_int-common.h | 1180 +++++++++++++++++++ | ||
17 | include/block/block_int-global-state.h | 312 +++++ | ||
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 | |||
26 | diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h | ||
27 | new file mode 100644 | ||
28 | index XXXXXXX..XXXXXXX | ||
29 | --- /dev/null | ||
30 | +++ b/include/block/block_int-common.h | ||
31 | @@ -XXX,XX +XXX,XX @@ | ||
32 | +/* | ||
33 | + * QEMU System Emulator block driver | ||
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 | + | ||
58 | +#include "block/accounting.h" | ||
59 | +#include "block/block.h" | ||
60 | +#include "block/aio-wait.h" | ||
61 | +#include "qemu/queue.h" | ||
62 | +#include "qemu/coroutine.h" | ||
63 | +#include "qemu/stats64.h" | ||
64 | +#include "qemu/timer.h" | ||
65 | +#include "qemu/hbitmap.h" | ||
66 | +#include "block/snapshot.h" | ||
67 | +#include "qemu/throttle.h" | ||
68 | +#include "qemu/rcu.h" | ||
69 | + | ||
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 | +}; | ||
104 | + | ||
105 | +/* | ||
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 | +{ | ||
723 | + return drv->bdrv_co_pwritev_compressed || | ||
724 | + drv->bdrv_co_pwritev_compressed_part; | ||
725 | +} | ||
726 | + | ||
727 | +typedef struct BlockLimits { | ||
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 | +{ | ||
1194 | + return child ? child->bs : NULL; | ||
1195 | +} | ||
1196 | + | ||
1197 | +int bdrv_check_request(int64_t offset, int64_t bytes, Error **errp); | ||
1198 | +int get_tmp_filename(char *filename, int size); | ||
1199 | +void bdrv_parse_filename_strip_prefix(const char *filename, const char *prefix, | ||
1200 | + QDict *options); | ||
1201 | + | ||
1202 | + | ||
1203 | +int bdrv_check_qiov_request(int64_t offset, int64_t bytes, | ||
1204 | + QEMUIOVector *qiov, size_t qiov_offset, | ||
1205 | + Error **errp); | ||
1206 | + | ||
1207 | +#ifdef _WIN32 | ||
1208 | +int is_windows_drive(const char *filename); | ||
1209 | +#endif | ||
1210 | + | ||
1211 | +#endif /* BLOCK_INT_COMMON_H */ | ||
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 | + | ||
1244 | +#include "block_int-common.h" | ||
1245 | + | ||
1246 | +/* | ||
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 | + | ||
1253 | +/** | ||
1254 | + * stream_start: | ||
1255 | + * @job_id: The id of the newly-created job, or %NULL to use the | ||
1256 | + * device name of @bs. | ||
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 | + | ||
1286 | +/** | ||
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 | + | ||
1375 | +/* | ||
1376 | + * backup_job_create: | ||
1377 | + * @job_id: The id of the newly-created job, or %NULL to use the | ||
1378 | + * device name of @bs. | ||
1379 | + * @bs: Block device to operate on. | ||
1380 | + * @target: Block device to write to. | ||
1381 | + * @speed: The maximum speed, in bytes per second, or 0 for unlimited. | ||
1382 | + * @sync_mode: What parts of the disk image should be copied to the destination. | ||
1383 | + * @sync_bitmap: The dirty bitmap if sync_mode is 'bitmap' or 'incremental' | ||
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 | +{ | ||
1587 | + QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes); | ||
1588 | + | ||
1589 | + return bdrv_co_preadv(child, offset, bytes, &qiov, flags); | ||
1590 | +} | ||
1591 | + | ||
1592 | +static inline int coroutine_fn bdrv_co_pwrite(BdrvChild *child, | ||
1593 | + int64_t offset, unsigned int bytes, void *buf, BdrvRequestFlags flags) | ||
1594 | +{ | ||
1595 | + QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes); | ||
1596 | + | ||
1597 | + return bdrv_co_pwritev(child, offset, bytes, &qiov, flags); | ||
1598 | +} | ||
1599 | + | ||
1600 | +bool coroutine_fn bdrv_make_request_serialising(BdrvTrackedRequest *req, | ||
1601 | + uint64_t align); | ||
1602 | +BdrvTrackedRequest *coroutine_fn bdrv_co_get_self_request(BlockDriverState *bs); | ||
1603 | + | ||
1604 | +BlockDriver *bdrv_probe_all(const uint8_t *buf, int buf_size, | ||
1605 | + const char *filename); | ||
1606 | + | ||
1607 | +/** | ||
1608 | + * bdrv_wakeup: | ||
1609 | + * @bs: The BlockDriverState for which an I/O operation has been completed. | ||
1610 | + * | ||
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 | -- | ||
3246 | 2.35.1 | diff view generated by jsdifflib |
1 | Now that node level interface bdrv_truncate() supports passing request | 1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
---|---|---|---|
2 | flags to the block driver, expose this on the BlockBackend level, too. | ||
3 | 2 | ||
4 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 3 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
5 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 4 | Message-Id: <20220303151616.325444-13-eesposit@redhat.com> |
6 | Reviewed-by: Alberto Garcia <berto@igalia.com> | ||
7 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
8 | Message-Id: <20200424125448.63318-4-kwolf@redhat.com> | ||
9 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 5 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
10 | --- | 6 | --- |
11 | include/sysemu/block-backend.h | 2 +- | 7 | block.c | 15 +++++++++++++++ |
12 | block.c | 3 ++- | 8 | block/backup.c | 1 + |
13 | block/block-backend.c | 4 ++-- | 9 | block/block-backend.c | 3 +++ |
14 | block/commit.c | 4 ++-- | 10 | block/commit.c | 2 ++ |
15 | block/crypto.c | 2 +- | 11 | block/dirty-bitmap.c | 1 + |
16 | block/mirror.c | 2 +- | 12 | block/io.c | 1 + |
17 | block/qcow2.c | 4 ++-- | 13 | block/mirror.c | 4 ++++ |
18 | block/qed.c | 2 +- | 14 | block/monitor/bitmap-qmp-cmds.c | 6 ++++++ |
19 | block/vdi.c | 2 +- | 15 | block/stream.c | 2 ++ |
20 | block/vhdx.c | 4 ++-- | 16 | blockdev.c | 7 +++++++ |
21 | block/vmdk.c | 6 +++--- | 17 | 10 files changed, 42 insertions(+) |
22 | block/vpc.c | 2 +- | ||
23 | blockdev.c | 2 +- | ||
24 | qemu-img.c | 2 +- | ||
25 | qemu-io-cmds.c | 2 +- | ||
26 | 15 files changed, 22 insertions(+), 21 deletions(-) | ||
27 | 18 | ||
28 | diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h | ||
29 | index XXXXXXX..XXXXXXX 100644 | ||
30 | --- a/include/sysemu/block-backend.h | ||
31 | +++ b/include/sysemu/block-backend.h | ||
32 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn blk_co_pwrite_zeroes(BlockBackend *blk, int64_t offset, | ||
33 | int blk_pwrite_compressed(BlockBackend *blk, int64_t offset, const void *buf, | ||
34 | int bytes); | ||
35 | int blk_truncate(BlockBackend *blk, int64_t offset, bool exact, | ||
36 | - PreallocMode prealloc, Error **errp); | ||
37 | + PreallocMode prealloc, BdrvRequestFlags flags, Error **errp); | ||
38 | int blk_pdiscard(BlockBackend *blk, int64_t offset, int bytes); | ||
39 | int blk_save_vmstate(BlockBackend *blk, const uint8_t *buf, | ||
40 | int64_t pos, int size); | ||
41 | diff --git a/block.c b/block.c | 19 | diff --git a/block.c b/block.c |
42 | index XXXXXXX..XXXXXXX 100644 | 20 | index XXXXXXX..XXXXXXX 100644 |
43 | --- a/block.c | 21 | --- a/block.c |
44 | +++ b/block.c | 22 | +++ b/block.c |
45 | @@ -XXX,XX +XXX,XX @@ static int64_t create_file_fallback_truncate(BlockBackend *blk, | 23 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_create_opts_simple(BlockDriver *drv, |
46 | int64_t size; | 24 | Error *local_err = NULL; |
47 | int ret; | 25 | int ret; |
48 | 26 | ||
49 | - ret = blk_truncate(blk, minimum_size, false, PREALLOC_MODE_OFF, &local_err); | 27 | + GLOBAL_STATE_CODE(); |
50 | + ret = blk_truncate(blk, minimum_size, false, PREALLOC_MODE_OFF, 0, | 28 | + |
51 | + &local_err); | 29 | size = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0); |
52 | if (ret < 0 && ret != -ENOTSUP) { | 30 | buf = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC); |
53 | error_propagate(errp, local_err); | 31 | prealloc = qapi_enum_parse(&PreallocMode_lookup, buf, |
54 | return ret; | 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); | ||
55 | diff --git a/block/block-backend.c b/block/block-backend.c | 113 | diff --git a/block/block-backend.c b/block/block-backend.c |
56 | index XXXXXXX..XXXXXXX 100644 | 114 | index XXXXXXX..XXXXXXX 100644 |
57 | --- a/block/block-backend.c | 115 | --- a/block/block-backend.c |
58 | +++ b/block/block-backend.c | 116 | +++ b/block/block-backend.c |
59 | @@ -XXX,XX +XXX,XX @@ int blk_pwrite_compressed(BlockBackend *blk, int64_t offset, const void *buf, | 117 | @@ -XXX,XX +XXX,XX @@ static void blk_root_change_media(BdrvChild *child, bool load) |
60 | } | 118 | */ |
61 | 119 | bool blk_dev_has_removable_media(BlockBackend *blk) | |
62 | int blk_truncate(BlockBackend *blk, int64_t offset, bool exact, | 120 | { |
63 | - PreallocMode prealloc, Error **errp) | 121 | + GLOBAL_STATE_CODE(); |
64 | + PreallocMode prealloc, BdrvRequestFlags flags, Error **errp) | 122 | return !blk->dev || (blk->dev_ops && blk->dev_ops->change_media_cb); |
65 | { | 123 | } |
66 | if (!blk_is_available(blk)) { | 124 | |
67 | error_setg(errp, "No medium inserted"); | 125 | @@ -XXX,XX +XXX,XX @@ bool blk_dev_has_tray(BlockBackend *blk) |
68 | return -ENOMEDIUM; | 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); | ||
69 | } | 132 | } |
70 | 133 | @@ -XXX,XX +XXX,XX @@ bool blk_dev_is_tray_open(BlockBackend *blk) | |
71 | - return bdrv_truncate(blk->root, offset, exact, prealloc, 0, errp); | 134 | */ |
72 | + return bdrv_truncate(blk->root, offset, exact, prealloc, flags, errp); | 135 | bool blk_dev_is_medium_locked(BlockBackend *blk) |
73 | } | 136 | { |
74 | 137 | + GLOBAL_STATE_CODE(); | |
75 | int blk_save_vmstate(BlockBackend *blk, const uint8_t *buf, | 138 | if (blk->dev_ops && blk->dev_ops->is_medium_locked) { |
139 | return blk->dev_ops->is_medium_locked(blk->dev_opaque); | ||
140 | } | ||
76 | diff --git a/block/commit.c b/block/commit.c | 141 | diff --git a/block/commit.c b/block/commit.c |
77 | index XXXXXXX..XXXXXXX 100644 | 142 | index XXXXXXX..XXXXXXX 100644 |
78 | --- a/block/commit.c | 143 | --- a/block/commit.c |
79 | +++ b/block/commit.c | 144 | +++ b/block/commit.c |
80 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn commit_run(Job *job, Error **errp) | 145 | @@ -XXX,XX +XXX,XX @@ void commit_start(const char *job_id, BlockDriverState *bs, |
81 | } | 146 | uint64_t base_perms, iter_shared_perms; |
82 | 147 | int ret; | |
83 | if (base_len < len) { | 148 | |
84 | - ret = blk_truncate(s->base, len, false, PREALLOC_MODE_OFF, NULL); | 149 | + GLOBAL_STATE_CODE(); |
85 | + ret = blk_truncate(s->base, len, false, PREALLOC_MODE_OFF, 0, NULL); | 150 | + |
86 | if (ret) { | 151 | assert(top != bs); |
87 | goto out; | 152 | if (bdrv_skip_filters(top) == bdrv_skip_filters(base)) { |
88 | } | 153 | error_setg(errp, "Invalid files for merge: top and base are the same"); |
89 | @@ -XXX,XX +XXX,XX @@ int bdrv_commit(BlockDriverState *bs) | 154 | diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c |
90 | * grow the backing file image if possible. If not possible, | 155 | index XXXXXXX..XXXXXXX 100644 |
91 | * we must return an error */ | 156 | --- a/block/dirty-bitmap.c |
92 | if (length > backing_length) { | 157 | +++ b/block/dirty-bitmap.c |
93 | - ret = blk_truncate(backing, length, false, PREALLOC_MODE_OFF, | 158 | @@ -XXX,XX +XXX,XX @@ void bdrv_restore_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap *backup) |
94 | + ret = blk_truncate(backing, length, false, PREALLOC_MODE_OFF, 0, | 159 | { |
95 | &local_err); | 160 | HBitmap *tmp = bitmap->bitmap; |
96 | if (ret < 0) { | 161 | assert(!bdrv_dirty_bitmap_readonly(bitmap)); |
97 | error_report_err(local_err); | 162 | + GLOBAL_STATE_CODE(); |
98 | diff --git a/block/crypto.c b/block/crypto.c | 163 | bitmap->bitmap = backup; |
99 | index XXXXXXX..XXXXXXX 100644 | 164 | hbitmap_free(tmp); |
100 | --- a/block/crypto.c | 165 | } |
101 | +++ b/block/crypto.c | 166 | diff --git a/block/io.c b/block/io.c |
102 | @@ -XXX,XX +XXX,XX @@ static ssize_t block_crypto_init_func(QCryptoBlock *block, | 167 | index XXXXXXX..XXXXXXX 100644 |
103 | * which will be used by the crypto header | 168 | --- a/block/io.c |
104 | */ | 169 | +++ b/block/io.c |
105 | return blk_truncate(data->blk, data->size + headerlen, false, | 170 | @@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void) |
106 | - data->prealloc, errp); | 171 | void bdrv_drain_all_end_quiesce(BlockDriverState *bs) |
107 | + data->prealloc, 0, errp); | 172 | { |
108 | } | 173 | int drained_end_counter = 0; |
109 | 174 | + GLOBAL_STATE_CODE(); | |
110 | 175 | ||
176 | g_assert(bs->quiesce_counter > 0); | ||
177 | g_assert(!bs->refcnt); | ||
111 | diff --git a/block/mirror.c b/block/mirror.c | 178 | diff --git a/block/mirror.c b/block/mirror.c |
112 | index XXXXXXX..XXXXXXX 100644 | 179 | index XXXXXXX..XXXXXXX 100644 |
113 | --- a/block/mirror.c | 180 | --- a/block/mirror.c |
114 | +++ b/block/mirror.c | 181 | +++ b/block/mirror.c |
115 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn mirror_run(Job *job, Error **errp) | 182 | @@ -XXX,XX +XXX,XX @@ void mirror_start(const char *job_id, BlockDriverState *bs, |
116 | 183 | bool is_none_mode; | |
117 | if (s->bdev_length > base_length) { | 184 | BlockDriverState *base; |
118 | ret = blk_truncate(s->target, s->bdev_length, false, | 185 | |
119 | - PREALLOC_MODE_OFF, NULL); | 186 | + GLOBAL_STATE_CODE(); |
120 | + PREALLOC_MODE_OFF, 0, NULL); | 187 | + |
121 | if (ret < 0) { | 188 | if ((mode == MIRROR_SYNC_MODE_INCREMENTAL) || |
122 | goto immediate_exit; | 189 | (mode == MIRROR_SYNC_MODE_BITMAP)) { |
123 | } | 190 | error_setg(errp, "Sync mode '%s' not supported", |
124 | diff --git a/block/qcow2.c b/block/qcow2.c | 191 | @@ -XXX,XX +XXX,XX @@ BlockJob *commit_active_start(const char *job_id, BlockDriverState *bs, |
125 | index XXXXXXX..XXXXXXX 100644 | 192 | bool base_read_only; |
126 | --- a/block/qcow2.c | 193 | BlockJob *job; |
127 | +++ b/block/qcow2.c | 194 | |
128 | @@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp) | 195 | + GLOBAL_STATE_CODE(); |
129 | 196 | + | |
130 | /* Okay, now that we have a valid image, let's give it the right size */ | 197 | base_read_only = bdrv_is_read_only(base); |
131 | ret = blk_truncate(blk, qcow2_opts->size, false, qcow2_opts->preallocation, | 198 | |
132 | - errp); | 199 | if (base_read_only) { |
133 | + 0, errp); | 200 | diff --git a/block/monitor/bitmap-qmp-cmds.c b/block/monitor/bitmap-qmp-cmds.c |
134 | if (ret < 0) { | 201 | index XXXXXXX..XXXXXXX 100644 |
135 | error_prepend(errp, "Could not resize image: "); | 202 | --- a/block/monitor/bitmap-qmp-cmds.c |
136 | goto out; | 203 | +++ b/block/monitor/bitmap-qmp-cmds.c |
137 | @@ -XXX,XX +XXX,XX @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, | 204 | @@ -XXX,XX +XXX,XX @@ BdrvDirtyBitmap *block_dirty_bitmap_lookup(const char *node, |
138 | * Amending image options should ensure that the image has | 205 | BlockDriverState *bs; |
139 | * exactly the given new values, so pass exact=true here. | 206 | BdrvDirtyBitmap *bitmap; |
140 | */ | 207 | |
141 | - ret = blk_truncate(blk, new_size, true, PREALLOC_MODE_OFF, errp); | 208 | + GLOBAL_STATE_CODE(); |
142 | + ret = blk_truncate(blk, new_size, true, PREALLOC_MODE_OFF, 0, errp); | 209 | + |
143 | blk_unref(blk); | 210 | if (!node) { |
144 | if (ret < 0) { | 211 | error_setg(errp, "Node cannot be NULL"); |
145 | return ret; | 212 | return NULL; |
146 | diff --git a/block/qed.c b/block/qed.c | 213 | @@ -XXX,XX +XXX,XX @@ BdrvDirtyBitmap *block_dirty_bitmap_remove(const char *node, const char *name, |
147 | index XXXXXXX..XXXXXXX 100644 | 214 | BdrvDirtyBitmap *bitmap; |
148 | --- a/block/qed.c | 215 | AioContext *aio_context; |
149 | +++ b/block/qed.c | 216 | |
150 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_qed_co_create(BlockdevCreateOptions *opts, | 217 | + GLOBAL_STATE_CODE(); |
151 | * The QED format associates file length with allocation status, | 218 | + |
152 | * so a new file (which is empty) must have a length of 0. | 219 | bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp); |
153 | */ | 220 | if (!bitmap || !bs) { |
154 | - ret = blk_truncate(blk, 0, true, PREALLOC_MODE_OFF, errp); | 221 | return NULL; |
155 | + ret = blk_truncate(blk, 0, true, PREALLOC_MODE_OFF, 0, errp); | 222 | @@ -XXX,XX +XXX,XX @@ BdrvDirtyBitmap *block_dirty_bitmap_merge(const char *node, const char *target, |
156 | if (ret < 0) { | 223 | BlockDirtyBitmapMergeSourceList *lst; |
157 | goto out; | 224 | Error *local_err = NULL; |
158 | } | 225 | |
159 | diff --git a/block/vdi.c b/block/vdi.c | 226 | + GLOBAL_STATE_CODE(); |
160 | index XXXXXXX..XXXXXXX 100644 | 227 | + |
161 | --- a/block/vdi.c | 228 | dst = block_dirty_bitmap_lookup(node, target, &bs, errp); |
162 | +++ b/block/vdi.c | 229 | if (!dst) { |
163 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn vdi_co_do_create(BlockdevCreateOptions *create_options, | 230 | return NULL; |
164 | 231 | diff --git a/block/stream.c b/block/stream.c | |
165 | if (image_type == VDI_TYPE_STATIC) { | 232 | index XXXXXXX..XXXXXXX 100644 |
166 | ret = blk_truncate(blk, offset + blocks * block_size, false, | 233 | --- a/block/stream.c |
167 | - PREALLOC_MODE_OFF, errp); | 234 | +++ b/block/stream.c |
168 | + PREALLOC_MODE_OFF, 0, errp); | 235 | @@ -XXX,XX +XXX,XX @@ void stream_start(const char *job_id, BlockDriverState *bs, |
169 | if (ret < 0) { | 236 | QDict *opts; |
170 | error_prepend(errp, "Failed to statically allocate file"); | 237 | int ret; |
171 | goto exit; | 238 | |
172 | diff --git a/block/vhdx.c b/block/vhdx.c | 239 | + GLOBAL_STATE_CODE(); |
173 | index XXXXXXX..XXXXXXX 100644 | 240 | + |
174 | --- a/block/vhdx.c | 241 | assert(!(base && bottom)); |
175 | +++ b/block/vhdx.c | 242 | assert(!(backing_file_str && bottom)); |
176 | @@ -XXX,XX +XXX,XX @@ static int vhdx_create_bat(BlockBackend *blk, BDRVVHDXState *s, | 243 | |
177 | /* All zeroes, so we can just extend the file - the end of the BAT | ||
178 | * is the furthest thing we have written yet */ | ||
179 | ret = blk_truncate(blk, data_file_offset, false, PREALLOC_MODE_OFF, | ||
180 | - errp); | ||
181 | + 0, errp); | ||
182 | if (ret < 0) { | ||
183 | goto exit; | ||
184 | } | ||
185 | } else if (type == VHDX_TYPE_FIXED) { | ||
186 | ret = blk_truncate(blk, data_file_offset + image_size, false, | ||
187 | - PREALLOC_MODE_OFF, errp); | ||
188 | + PREALLOC_MODE_OFF, 0, errp); | ||
189 | if (ret < 0) { | ||
190 | goto exit; | ||
191 | } | ||
192 | diff --git a/block/vmdk.c b/block/vmdk.c | ||
193 | index XXXXXXX..XXXXXXX 100644 | ||
194 | --- a/block/vmdk.c | ||
195 | +++ b/block/vmdk.c | ||
196 | @@ -XXX,XX +XXX,XX @@ static int vmdk_init_extent(BlockBackend *blk, | ||
197 | int gd_buf_size; | ||
198 | |||
199 | if (flat) { | ||
200 | - ret = blk_truncate(blk, filesize, false, PREALLOC_MODE_OFF, errp); | ||
201 | + ret = blk_truncate(blk, filesize, false, PREALLOC_MODE_OFF, 0, errp); | ||
202 | goto exit; | ||
203 | } | ||
204 | magic = cpu_to_be32(VMDK4_MAGIC); | ||
205 | @@ -XXX,XX +XXX,XX @@ static int vmdk_init_extent(BlockBackend *blk, | ||
206 | } | ||
207 | |||
208 | ret = blk_truncate(blk, le64_to_cpu(header.grain_offset) << 9, false, | ||
209 | - PREALLOC_MODE_OFF, errp); | ||
210 | + PREALLOC_MODE_OFF, 0, errp); | ||
211 | if (ret < 0) { | ||
212 | goto exit; | ||
213 | } | ||
214 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn vmdk_co_do_create(int64_t size, | ||
215 | /* bdrv_pwrite write padding zeros to align to sector, we don't need that | ||
216 | * for description file */ | ||
217 | if (desc_offset == 0) { | ||
218 | - ret = blk_truncate(blk, desc_len, false, PREALLOC_MODE_OFF, errp); | ||
219 | + ret = blk_truncate(blk, desc_len, false, PREALLOC_MODE_OFF, 0, errp); | ||
220 | if (ret < 0) { | ||
221 | goto exit; | ||
222 | } | ||
223 | diff --git a/block/vpc.c b/block/vpc.c | ||
224 | index XXXXXXX..XXXXXXX 100644 | ||
225 | --- a/block/vpc.c | ||
226 | +++ b/block/vpc.c | ||
227 | @@ -XXX,XX +XXX,XX @@ static int create_fixed_disk(BlockBackend *blk, uint8_t *buf, | ||
228 | /* Add footer to total size */ | ||
229 | total_size += HEADER_SIZE; | ||
230 | |||
231 | - ret = blk_truncate(blk, total_size, false, PREALLOC_MODE_OFF, errp); | ||
232 | + ret = blk_truncate(blk, total_size, false, PREALLOC_MODE_OFF, 0, errp); | ||
233 | if (ret < 0) { | ||
234 | return ret; | ||
235 | } | ||
236 | diff --git a/blockdev.c b/blockdev.c | 244 | diff --git a/blockdev.c b/blockdev.c |
237 | index XXXXXXX..XXXXXXX 100644 | 245 | index XXXXXXX..XXXXXXX 100644 |
238 | --- a/blockdev.c | 246 | --- a/blockdev.c |
239 | +++ b/blockdev.c | 247 | +++ b/blockdev.c |
240 | @@ -XXX,XX +XXX,XX @@ void qmp_block_resize(bool has_device, const char *device, | 248 | @@ -XXX,XX +XXX,XX @@ QTAILQ_HEAD(, BlockDriverState) monitor_bdrv_states = |
241 | } | 249 | |
242 | 250 | void bdrv_set_monitor_owned(BlockDriverState *bs) | |
243 | bdrv_drained_begin(bs); | 251 | { |
244 | - ret = blk_truncate(blk, size, false, PREALLOC_MODE_OFF, errp); | 252 | + GLOBAL_STATE_CODE(); |
245 | + ret = blk_truncate(blk, size, false, PREALLOC_MODE_OFF, 0, errp); | 253 | QTAILQ_INSERT_TAIL(&monitor_bdrv_states, bs, monitor_list); |
246 | bdrv_drained_end(bs); | 254 | } |
247 | 255 | ||
248 | out: | 256 | @@ -XXX,XX +XXX,XX @@ BlockDriverState *bds_tree_init(QDict *bs_opts, Error **errp) |
249 | diff --git a/qemu-img.c b/qemu-img.c | 257 | { |
250 | index XXXXXXX..XXXXXXX 100644 | 258 | int bdrv_flags = 0; |
251 | --- a/qemu-img.c | 259 | |
252 | +++ b/qemu-img.c | 260 | + GLOBAL_STATE_CODE(); |
253 | @@ -XXX,XX +XXX,XX @@ static int img_resize(int argc, char **argv) | 261 | /* bdrv_open() defaults to the values in bdrv_flags (for compatibility |
254 | * resizing, so pass @exact=true. It is of no use to report | 262 | * with other callers) rather than what we want as the real defaults. |
255 | * success when the image has not actually been resized. | 263 | * Apply the defaults here instead. */ |
256 | */ | 264 | @@ -XXX,XX +XXX,XX @@ void blockdev_close_all_bdrv_states(void) |
257 | - ret = blk_truncate(blk, total_size, true, prealloc, &err); | 265 | { |
258 | + ret = blk_truncate(blk, total_size, true, prealloc, 0, &err); | 266 | BlockDriverState *bs, *next_bs; |
259 | if (!ret) { | 267 | |
260 | qprintf(quiet, "Image resized.\n"); | 268 | + GLOBAL_STATE_CODE(); |
261 | } else { | 269 | QTAILQ_FOREACH_SAFE(bs, &monitor_bdrv_states, monitor_list, next_bs) { |
262 | diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c | 270 | AioContext *ctx = bdrv_get_aio_context(bs); |
263 | index XXXXXXX..XXXXXXX 100644 | 271 | |
264 | --- a/qemu-io-cmds.c | 272 | @@ -XXX,XX +XXX,XX @@ void qmp_transaction(TransactionActionList *dev_list, |
265 | +++ b/qemu-io-cmds.c | 273 | BlkActionState *state, *next; |
266 | @@ -XXX,XX +XXX,XX @@ static int truncate_f(BlockBackend *blk, int argc, char **argv) | 274 | Error *local_err = NULL; |
267 | * exact=true. It is better to err on the "emit more errors" side | 275 | |
268 | * than to be overly permissive. | 276 | + GLOBAL_STATE_CODE(); |
269 | */ | 277 | + |
270 | - ret = blk_truncate(blk, offset, true, PREALLOC_MODE_OFF, &local_err); | 278 | QTAILQ_HEAD(, BlkActionState) snap_bdrv_states; |
271 | + ret = blk_truncate(blk, offset, true, PREALLOC_MODE_OFF, 0, &local_err); | 279 | QTAILQ_INIT(&snap_bdrv_states); |
272 | if (ret < 0) { | 280 | |
273 | error_report_err(local_err); | 281 | @@ -XXX,XX +XXX,XX @@ void qmp_blockdev_del(const char *node_name, Error **errp) |
274 | return ret; | 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); | ||
275 | -- | 290 | -- |
276 | 2.25.3 | 291 | 2.35.1 |
277 | |||
278 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
1 | 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-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 | ||
215 | index XXXXXXX..XXXXXXX 100644 | ||
216 | --- a/block/io.c | ||
217 | +++ b/block/io.c | ||
218 | @@ -XXX,XX +XXX,XX @@ void bdrv_subtree_drained_end(BlockDriverState *bs) | ||
219 | void bdrv_apply_subtree_drain(BdrvChild *child, BlockDriverState *new_parent) | ||
220 | { | ||
221 | int i; | ||
222 | + IO_OR_GS_CODE(); | ||
223 | |||
224 | for (i = 0; i < new_parent->recursive_quiesce_counter; i++) { | ||
225 | bdrv_do_drained_begin(child->bs, true, child, false, true); | ||
226 | @@ -XXX,XX +XXX,XX @@ void bdrv_unapply_subtree_drain(BdrvChild *child, BlockDriverState *old_parent) | ||
227 | { | ||
228 | int drained_end_counter = 0; | ||
229 | int i; | ||
230 | + IO_OR_GS_CODE(); | ||
231 | |||
232 | for (i = 0; i < old_parent->recursive_quiesce_counter; i++) { | ||
233 | bdrv_do_drained_end(child->bs, true, child, false, | ||
234 | @@ -XXX,XX +XXX,XX @@ BdrvTrackedRequest *coroutine_fn bdrv_co_get_self_request(BlockDriverState *bs) | ||
235 | { | ||
236 | BdrvTrackedRequest *req; | ||
237 | Coroutine *self = qemu_coroutine_self(); | ||
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 | } | ||
249 | |||
250 | void bdrv_wakeup(BlockDriverState *bs) | ||
251 | { | ||
252 | + IO_CODE(); | ||
253 | aio_wait_kick(); | ||
254 | } | ||
255 | |||
256 | void bdrv_dec_in_flight(BlockDriverState *bs) | ||
257 | { | ||
258 | + IO_CODE(); | ||
259 | qatomic_dec(&bs->in_flight); | ||
260 | bdrv_wakeup(bs); | ||
261 | } | ||
262 | @@ -XXX,XX +XXX,XX @@ bool coroutine_fn bdrv_make_request_serialising(BdrvTrackedRequest *req, | ||
263 | uint64_t align) | ||
264 | { | ||
265 | bool waited; | ||
266 | + IO_CODE(); | ||
267 | |||
268 | qemu_co_mutex_lock(&req->bs->reqs_lock); | ||
269 | |||
270 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_preadv(BdrvChild *child, | ||
271 | int64_t offset, int64_t bytes, QEMUIOVector *qiov, | ||
272 | BdrvRequestFlags flags) | ||
273 | { | ||
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 | -- | ||
319 | 2.35.1 | diff view generated by jsdifflib |
1 | The QMP handler qmp_object_add() and the implementation of --object in | 1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
---|---|---|---|
2 | qemu-storage-daemon can share most of the code. Currently, | ||
3 | qemu-storage-daemon calls qmp_object_add(), but this is not correct | ||
4 | because different visitors need to be used. | ||
5 | 2 | ||
6 | As a first step towards a fix, make qmp_object_add() a wrapper around a | 3 | We want to be sure that the functions that write the child and |
7 | new function user_creatable_add_dict() that can get an additional | 4 | parent list of a bs are under BQL and drain. |
8 | parameter. The handling of "props" is only required for compatibility | ||
9 | and not required for the qemu-storage-daemon command line, so it stays | ||
10 | in qmp_object_add(). | ||
11 | 5 | ||
6 | BQL prevents from concurrent writings from the GS API, while | ||
7 | drains protect from I/O. | ||
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> | ||
12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 16 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
13 | --- | 17 | --- |
14 | include/qom/object_interfaces.h | 12 ++++++++++++ | 18 | include/block/block_int-global-state.h | 17 +++++++++++++++++ |
15 | qom/object_interfaces.c | 27 +++++++++++++++++++++++++++ | 19 | block.c | 4 ++++ |
16 | qom/qom-qmp-cmds.c | 24 +----------------------- | 20 | 2 files changed, 21 insertions(+) |
17 | 3 files changed, 40 insertions(+), 23 deletions(-) | ||
18 | 21 | ||
19 | diff --git a/include/qom/object_interfaces.h b/include/qom/object_interfaces.h | 22 | diff --git a/include/block/block_int-global-state.h b/include/block/block_int-global-state.h |
20 | index XXXXXXX..XXXXXXX 100644 | 23 | index XXXXXXX..XXXXXXX 100644 |
21 | --- a/include/qom/object_interfaces.h | 24 | --- a/include/block/block_int-global-state.h |
22 | +++ b/include/qom/object_interfaces.h | 25 | +++ b/include/block/block_int-global-state.h |
23 | @@ -XXX,XX +XXX,XX @@ Object *user_creatable_add_type(const char *type, const char *id, | 26 | @@ -XXX,XX +XXX,XX @@ void bdrv_remove_aio_context_notifier(BlockDriverState *bs, |
24 | const QDict *qdict, | 27 | */ |
25 | Visitor *v, Error **errp); | 28 | void bdrv_drain_all_end_quiesce(BlockDriverState *bs); |
26 | 29 | ||
27 | +/** | 30 | +/** |
28 | + * user_creatable_add_dict: | 31 | + * Make sure that the function is running under both drain and BQL. |
29 | + * @qdict: the object definition | 32 | + * The latter protects from concurrent writings |
30 | + * @errp: if an error occurs, a pointer to an area to store the error | 33 | + * from the GS API, while the former prevents concurrent reads |
31 | + * | 34 | + * from I/O. |
32 | + * Create an instance of the user creatable object that is defined by | ||
33 | + * @qdict. The object type is taken from the QDict key 'qom-type', its | ||
34 | + * ID from the key 'id'. The remaining entries in @qdict are used to | ||
35 | + * initialize the object properties. | ||
36 | + */ | 35 | + */ |
37 | +void user_creatable_add_dict(QDict *qdict, Error **errp); | 36 | +static inline void assert_bdrv_graph_writable(BlockDriverState *bs) |
37 | +{ | ||
38 | + /* | ||
39 | + * TODO: this function is incomplete. Because the users of this | ||
40 | + * assert lack the necessary drains, check only for BQL. | ||
41 | + * Once the necessary drains are added, | ||
42 | + * assert also for qatomic_read(&bs->quiesce_counter) > 0 | ||
43 | + */ | ||
44 | + assert(qemu_in_main_thread()); | ||
45 | +} | ||
38 | + | 46 | + |
39 | /** | 47 | #endif /* BLOCK_INT_GLOBAL_STATE */ |
40 | * user_creatable_add_opts: | 48 | diff --git a/block.c b/block.c |
41 | * @opts: the object definition | ||
42 | diff --git a/qom/object_interfaces.c b/qom/object_interfaces.c | ||
43 | index XXXXXXX..XXXXXXX 100644 | 49 | index XXXXXXX..XXXXXXX 100644 |
44 | --- a/qom/object_interfaces.c | 50 | --- a/block.c |
45 | +++ b/qom/object_interfaces.c | 51 | +++ b/block.c |
46 | @@ -XXX,XX +XXX,XX @@ | 52 | @@ -XXX,XX +XXX,XX @@ static void bdrv_child_cb_attach(BdrvChild *child) |
47 | #include "qapi/qmp/qerror.h" | 53 | { |
48 | #include "qapi/qmp/qjson.h" | 54 | BlockDriverState *bs = child->opaque; |
49 | #include "qapi/qmp/qstring.h" | 55 | |
50 | +#include "qapi/qobject-input-visitor.h" | 56 | + assert_bdrv_graph_writable(bs); |
51 | #include "qom/object_interfaces.h" | 57 | QLIST_INSERT_HEAD(&bs->children, child, next); |
52 | #include "qemu/help_option.h" | 58 | |
53 | #include "qemu/module.h" | 59 | if (child->role & BDRV_CHILD_COW) { |
54 | @@ -XXX,XX +XXX,XX @@ out: | 60 | @@ -XXX,XX +XXX,XX @@ static void bdrv_child_cb_detach(BdrvChild *child) |
55 | return obj; | 61 | |
62 | bdrv_unapply_subtree_drain(child, bs); | ||
63 | |||
64 | + assert_bdrv_graph_writable(bs); | ||
65 | QLIST_REMOVE(child, next); | ||
56 | } | 66 | } |
57 | 67 | ||
58 | +void user_creatable_add_dict(QDict *qdict, Error **errp) | 68 | @@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_noperm(BdrvChild **childp, |
59 | +{ | 69 | if (child->klass->detach) { |
60 | + Visitor *v; | 70 | child->klass->detach(child); |
61 | + Object *obj; | 71 | } |
62 | + g_autofree char *type = NULL; | 72 | + assert_bdrv_graph_writable(old_bs); |
63 | + g_autofree char *id = NULL; | 73 | QLIST_REMOVE(child, next_parent); |
64 | + | ||
65 | + type = g_strdup(qdict_get_try_str(qdict, "qom-type")); | ||
66 | + if (!type) { | ||
67 | + error_setg(errp, QERR_MISSING_PARAMETER, "qom-type"); | ||
68 | + return; | ||
69 | + } | ||
70 | + qdict_del(qdict, "qom-type"); | ||
71 | + | ||
72 | + id = g_strdup(qdict_get_try_str(qdict, "id")); | ||
73 | + if (!id) { | ||
74 | + error_setg(errp, QERR_MISSING_PARAMETER, "id"); | ||
75 | + return; | ||
76 | + } | ||
77 | + qdict_del(qdict, "id"); | ||
78 | + | ||
79 | + v = qobject_input_visitor_new(QOBJECT(qdict)); | ||
80 | + obj = user_creatable_add_type(type, id, qdict, v, errp); | ||
81 | + visit_free(v); | ||
82 | + object_unref(obj); | ||
83 | +} | ||
84 | |||
85 | Object *user_creatable_add_opts(QemuOpts *opts, Error **errp) | ||
86 | { | ||
87 | diff --git a/qom/qom-qmp-cmds.c b/qom/qom-qmp-cmds.c | ||
88 | index XXXXXXX..XXXXXXX 100644 | ||
89 | --- a/qom/qom-qmp-cmds.c | ||
90 | +++ b/qom/qom-qmp-cmds.c | ||
91 | @@ -XXX,XX +XXX,XX @@ | ||
92 | #include "qapi/qapi-commands-qom.h" | ||
93 | #include "qapi/qmp/qdict.h" | ||
94 | #include "qapi/qmp/qerror.h" | ||
95 | -#include "qapi/qobject-input-visitor.h" | ||
96 | #include "qemu/cutils.h" | ||
97 | #include "qom/object_interfaces.h" | ||
98 | #include "qom/qom-qobject.h" | ||
99 | @@ -XXX,XX +XXX,XX @@ void qmp_object_add(QDict *qdict, QObject **ret_data, Error **errp) | ||
100 | { | ||
101 | QObject *props; | ||
102 | QDict *pdict; | ||
103 | - Visitor *v; | ||
104 | - Object *obj; | ||
105 | - g_autofree char *type = NULL; | ||
106 | - g_autofree char *id = NULL; | ||
107 | - | ||
108 | - type = g_strdup(qdict_get_try_str(qdict, "qom-type")); | ||
109 | - if (!type) { | ||
110 | - error_setg(errp, QERR_MISSING_PARAMETER, "qom-type"); | ||
111 | - return; | ||
112 | - } | ||
113 | - qdict_del(qdict, "qom-type"); | ||
114 | - | ||
115 | - id = g_strdup(qdict_get_try_str(qdict, "id")); | ||
116 | - if (!id) { | ||
117 | - error_setg(errp, QERR_MISSING_PARAMETER, "id"); | ||
118 | - return; | ||
119 | - } | ||
120 | - qdict_del(qdict, "id"); | ||
121 | |||
122 | props = qdict_get(qdict, "props"); | ||
123 | if (props) { | ||
124 | @@ -XXX,XX +XXX,XX @@ void qmp_object_add(QDict *qdict, QObject **ret_data, Error **errp) | ||
125 | qobject_unref(pdict); | ||
126 | } | 74 | } |
127 | 75 | ||
128 | - v = qobject_input_visitor_new(QOBJECT(qdict)); | 76 | @@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_noperm(BdrvChild **childp, |
129 | - obj = user_creatable_add_type(type, id, qdict, v, errp); | 77 | } |
130 | - visit_free(v); | 78 | |
131 | - object_unref(obj); | 79 | if (new_bs) { |
132 | + user_creatable_add_dict(qdict, errp); | 80 | + assert_bdrv_graph_writable(new_bs); |
133 | } | 81 | QLIST_INSERT_HEAD(&new_bs->parents, child, next_parent); |
134 | 82 | ||
135 | void qmp_object_del(const char *id, Error **errp) | 83 | /* |
136 | -- | 84 | -- |
137 | 2.25.3 | 85 | 2.35.1 |
138 | |||
139 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
1 | 2 | ||
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 |
1 | After processing the option string with the keyval parser, we get a | 1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
---|---|---|---|
2 | QDict that contains only strings. This QDict must be fed to a keyval | ||
3 | visitor which converts the strings into the right data types. | ||
4 | 2 | ||
5 | qmp_object_add(), however, uses the normal QObject input visitor, which | 3 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
6 | expects a QDict where all properties already have the QType that matches | 4 | Message-Id: <20220303151616.325444-17-eesposit@redhat.com> |
7 | the data type required by the QOM object type. | ||
8 | |||
9 | Change the --object implementation in qemu-storage-daemon so that it | ||
10 | doesn't call qmp_object_add(), but calls user_creatable_add_dict() | ||
11 | directly instead and pass it a new keyval boolean that decides which | ||
12 | visitor must be used. | ||
13 | |||
14 | Reported-by: Coiby Xu <coiby.xu@gmail.com> | ||
15 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 5 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
16 | --- | 6 | --- |
17 | include/qom/object_interfaces.h | 6 +++++- | 7 | blockjob.c | 5 +++++ |
18 | qemu-storage-daemon.c | 4 +--- | 8 | 1 file changed, 5 insertions(+) |
19 | qom/object_interfaces.c | 8 ++++++-- | ||
20 | qom/qom-qmp-cmds.c | 2 +- | ||
21 | 4 files changed, 13 insertions(+), 7 deletions(-) | ||
22 | 9 | ||
23 | diff --git a/include/qom/object_interfaces.h b/include/qom/object_interfaces.h | 10 | diff --git a/blockjob.c b/blockjob.c |
24 | index XXXXXXX..XXXXXXX 100644 | 11 | index XXXXXXX..XXXXXXX 100644 |
25 | --- a/include/qom/object_interfaces.h | 12 | --- a/blockjob.c |
26 | +++ b/include/qom/object_interfaces.h | 13 | +++ b/blockjob.c |
27 | @@ -XXX,XX +XXX,XX @@ Object *user_creatable_add_type(const char *type, const char *id, | 14 | @@ -XXX,XX +XXX,XX @@ BlockJob *block_job_get(const char *id) |
28 | /** | 15 | void block_job_free(Job *job) |
29 | * user_creatable_add_dict: | 16 | { |
30 | * @qdict: the object definition | 17 | BlockJob *bjob = container_of(job, BlockJob, job); |
31 | + * @keyval: if true, use a keyval visitor for processing @qdict (i.e. | 18 | + GLOBAL_STATE_CODE(); |
32 | + * assume that all @qdict values are strings); otherwise, use | 19 | |
33 | + * the normal QObject visitor (i.e. assume all @qdict values | 20 | block_job_remove_all_bdrv(bjob); |
34 | + * have the QType expected by the QOM object type) | 21 | ratelimit_destroy(&bjob->limit); |
35 | * @errp: if an error occurs, a pointer to an area to store the error | 22 | @@ -XXX,XX +XXX,XX @@ bool block_job_set_speed(BlockJob *job, int64_t speed, Error **errp) |
36 | * | 23 | |
37 | * Create an instance of the user creatable object that is defined by | 24 | int64_t block_job_ratelimit_get_delay(BlockJob *job, uint64_t n) |
38 | @@ -XXX,XX +XXX,XX @@ Object *user_creatable_add_type(const char *type, const char *id, | 25 | { |
39 | * ID from the key 'id'. The remaining entries in @qdict are used to | 26 | + IO_CODE(); |
40 | * initialize the object properties. | 27 | return ratelimit_calculate_delay(&job->limit, n); |
41 | */ | ||
42 | -void user_creatable_add_dict(QDict *qdict, Error **errp); | ||
43 | +void user_creatable_add_dict(QDict *qdict, bool keyval, Error **errp); | ||
44 | |||
45 | /** | ||
46 | * user_creatable_add_opts: | ||
47 | diff --git a/qemu-storage-daemon.c b/qemu-storage-daemon.c | ||
48 | index XXXXXXX..XXXXXXX 100644 | ||
49 | --- a/qemu-storage-daemon.c | ||
50 | +++ b/qemu-storage-daemon.c | ||
51 | @@ -XXX,XX +XXX,XX @@ static void process_options(int argc, char *argv[]) | ||
52 | QemuOpts *opts; | ||
53 | const char *type; | ||
54 | QDict *args; | ||
55 | - QObject *ret_data = NULL; | ||
56 | |||
57 | /* FIXME The keyval parser rejects 'help' arguments, so we must | ||
58 | * unconditionall try QemuOpts first. */ | ||
59 | @@ -XXX,XX +XXX,XX @@ static void process_options(int argc, char *argv[]) | ||
60 | qemu_opts_del(opts); | ||
61 | |||
62 | args = keyval_parse(optarg, "qom-type", &error_fatal); | ||
63 | - qmp_object_add(args, &ret_data, &error_fatal); | ||
64 | + user_creatable_add_dict(args, true, &error_fatal); | ||
65 | qobject_unref(args); | ||
66 | - qobject_unref(ret_data); | ||
67 | break; | ||
68 | } | ||
69 | default: | ||
70 | diff --git a/qom/object_interfaces.c b/qom/object_interfaces.c | ||
71 | index XXXXXXX..XXXXXXX 100644 | ||
72 | --- a/qom/object_interfaces.c | ||
73 | +++ b/qom/object_interfaces.c | ||
74 | @@ -XXX,XX +XXX,XX @@ out: | ||
75 | return obj; | ||
76 | } | 28 | } |
77 | 29 | ||
78 | -void user_creatable_add_dict(QDict *qdict, Error **errp) | 30 | @@ -XXX,XX +XXX,XX @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver, |
79 | +void user_creatable_add_dict(QDict *qdict, bool keyval, Error **errp) | ||
80 | { | 31 | { |
81 | Visitor *v; | 32 | BlockJob *job; |
82 | Object *obj; | 33 | int ret; |
83 | @@ -XXX,XX +XXX,XX @@ void user_creatable_add_dict(QDict *qdict, Error **errp) | 34 | + GLOBAL_STATE_CODE(); |
84 | } | 35 | |
85 | qdict_del(qdict, "id"); | 36 | if (job_id == NULL && !(flags & JOB_INTERNAL)) { |
86 | 37 | job_id = bdrv_get_device_name(bs); | |
87 | - v = qobject_input_visitor_new(QOBJECT(qdict)); | 38 | @@ -XXX,XX +XXX,XX @@ void block_job_iostatus_reset(BlockJob *job) |
88 | + if (keyval) { | 39 | void block_job_user_resume(Job *job) |
89 | + v = qobject_input_visitor_new_keyval(QOBJECT(qdict)); | 40 | { |
90 | + } else { | 41 | BlockJob *bjob = container_of(job, BlockJob, job); |
91 | + v = qobject_input_visitor_new(QOBJECT(qdict)); | 42 | + GLOBAL_STATE_CODE(); |
92 | + } | 43 | block_job_iostatus_reset(bjob); |
93 | obj = user_creatable_add_type(type, id, qdict, v, errp); | ||
94 | visit_free(v); | ||
95 | object_unref(obj); | ||
96 | diff --git a/qom/qom-qmp-cmds.c b/qom/qom-qmp-cmds.c | ||
97 | index XXXXXXX..XXXXXXX 100644 | ||
98 | --- a/qom/qom-qmp-cmds.c | ||
99 | +++ b/qom/qom-qmp-cmds.c | ||
100 | @@ -XXX,XX +XXX,XX @@ void qmp_object_add(QDict *qdict, QObject **ret_data, Error **errp) | ||
101 | qobject_unref(pdict); | ||
102 | } | ||
103 | |||
104 | - user_creatable_add_dict(qdict, errp); | ||
105 | + user_creatable_add_dict(qdict, false, errp); | ||
106 | } | 44 | } |
107 | 45 | ||
108 | void qmp_object_del(const char *id, Error **errp) | 46 | @@ -XXX,XX +XXX,XX @@ BlockErrorAction block_job_error_action(BlockJob *job, BlockdevOnError on_err, |
47 | int is_read, int error) | ||
48 | { | ||
49 | BlockErrorAction action; | ||
50 | + IO_CODE(); | ||
51 | |||
52 | switch (on_err) { | ||
53 | case BLOCKDEV_ON_ERROR_ENOSPC: | ||
109 | -- | 54 | -- |
110 | 2.25.3 | 55 | 2.35.1 |
111 | |||
112 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
1 | 2 | ||
3 | Following the assertion derived from the API split, | ||
4 | propagate the assertion also in the static functions. | ||
5 | |||
6 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
7 | Message-Id: <20220303151616.325444-18-eesposit@redhat.com> | ||
8 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
9 | --- | ||
10 | block.c | 46 ++++++++++++++++++++++++++++++++++++++++++- | ||
11 | block/block-backend.c | 3 +++ | ||
12 | 2 files changed, 48 insertions(+), 1 deletion(-) | ||
13 | |||
14 | diff --git a/block.c b/block.c | ||
15 | index XXXXXXX..XXXXXXX 100644 | ||
16 | --- a/block.c | ||
17 | +++ b/block.c | ||
18 | @@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_new(void) | ||
19 | static BlockDriver *bdrv_do_find_format(const char *format_name) | ||
20 | { | ||
21 | BlockDriver *drv1; | ||
22 | + GLOBAL_STATE_CODE(); | ||
23 | |||
24 | QLIST_FOREACH(drv1, &bdrv_drivers, list) { | ||
25 | if (!strcmp(drv1->format_name, format_name)) { | ||
26 | @@ -XXX,XX +XXX,XX @@ static int64_t create_file_fallback_truncate(BlockBackend *blk, | ||
27 | int64_t size; | ||
28 | int ret; | ||
29 | |||
30 | + GLOBAL_STATE_CODE(); | ||
31 | + | ||
32 | ret = blk_truncate(blk, minimum_size, false, PREALLOC_MODE_OFF, 0, | ||
33 | &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 | -- | ||
338 | 2.35.1 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
1 | 2 | ||
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 |
New patch | |||
---|---|---|---|
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
1 | 2 | ||
3 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
4 | Message-Id: <20220303151616.325444-20-eesposit@redhat.com> | ||
5 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
6 | --- | ||
7 | blockjob.c | 11 +++++++++++ | ||
8 | 1 file changed, 11 insertions(+) | ||
9 | |||
10 | diff --git a/blockjob.c b/blockjob.c | ||
11 | index XXXXXXX..XXXXXXX 100644 | ||
12 | --- a/blockjob.c | ||
13 | +++ b/blockjob.c | ||
14 | @@ -XXX,XX +XXX,XX @@ static bool is_block_job(Job *job) | ||
15 | BlockJob *block_job_next(BlockJob *bjob) | ||
16 | { | ||
17 | Job *job = bjob ? &bjob->job : NULL; | ||
18 | + GLOBAL_STATE_CODE(); | ||
19 | |||
20 | do { | ||
21 | job = job_next(job); | ||
22 | @@ -XXX,XX +XXX,XX @@ BlockJob *block_job_next(BlockJob *bjob) | ||
23 | BlockJob *block_job_get(const char *id) | ||
24 | { | ||
25 | Job *job = job_get(id); | ||
26 | + GLOBAL_STATE_CODE(); | ||
27 | |||
28 | if (job && is_block_job(job)) { | ||
29 | return container_of(job, BlockJob, job); | ||
30 | @@ -XXX,XX +XXX,XX @@ static const BdrvChildClass child_job = { | ||
31 | |||
32 | void block_job_remove_all_bdrv(BlockJob *job) | ||
33 | { | ||
34 | + GLOBAL_STATE_CODE(); | ||
35 | /* | ||
36 | * bdrv_root_unref_child() may reach child_job_[can_]set_aio_ctx(), | ||
37 | * which will also traverse job->nodes, so consume the list one by | ||
38 | @@ -XXX,XX +XXX,XX @@ void block_job_remove_all_bdrv(BlockJob *job) | ||
39 | bool block_job_has_bdrv(BlockJob *job, BlockDriverState *bs) | ||
40 | { | ||
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 | -- | ||
88 | 2.35.1 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
1 | 2 | ||
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 |
New patch | |||
---|---|---|---|
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
1 | 2 | ||
3 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
4 | Message-Id: <20220303151616.325444-22-eesposit@redhat.com> | ||
5 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
6 | --- | ||
7 | block/block-backend.c | 3 +++ | ||
8 | blockdev.c | 16 ++++++++++++++++ | ||
9 | 2 files changed, 19 insertions(+) | ||
10 | |||
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 | ||
40 | index XXXXXXX..XXXXXXX 100644 | ||
41 | --- a/blockdev.c | ||
42 | +++ b/blockdev.c | ||
43 | @@ -XXX,XX +XXX,XX @@ void override_max_devs(BlockInterfaceType type, int max_devs) | ||
44 | BlockBackend *blk; | ||
45 | DriveInfo *dinfo; | ||
46 | |||
47 | + GLOBAL_STATE_CODE(); | ||
48 | + | ||
49 | if (max_devs <= 0) { | ||
50 | return; | ||
51 | } | ||
52 | @@ -XXX,XX +XXX,XX @@ void blockdev_mark_auto_del(BlockBackend *blk) | ||
53 | DriveInfo *dinfo = blk_legacy_dinfo(blk); | ||
54 | BlockJob *job; | ||
55 | |||
56 | + GLOBAL_STATE_CODE(); | ||
57 | + | ||
58 | if (!dinfo) { | ||
59 | return; | ||
60 | } | ||
61 | @@ -XXX,XX +XXX,XX @@ void blockdev_mark_auto_del(BlockBackend *blk) | ||
62 | void blockdev_auto_del(BlockBackend *blk) | ||
63 | { | ||
64 | DriveInfo *dinfo = blk_legacy_dinfo(blk); | ||
65 | + GLOBAL_STATE_CODE(); | ||
66 | |||
67 | if (dinfo && dinfo->auto_del) { | ||
68 | monitor_remove_blk(blk); | ||
69 | @@ -XXX,XX +XXX,XX @@ QemuOpts *drive_add(BlockInterfaceType type, int index, const char *file, | ||
70 | { | ||
71 | QemuOpts *opts; | ||
72 | |||
73 | + GLOBAL_STATE_CODE(); | ||
74 | + | ||
75 | opts = qemu_opts_parse_noisily(qemu_find_opts("drive"), optstr, false); | ||
76 | if (!opts) { | ||
77 | return NULL; | ||
78 | @@ -XXX,XX +XXX,XX @@ DriveInfo *drive_get(BlockInterfaceType type, int bus, int unit) | ||
79 | BlockBackend *blk; | ||
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 | -- | ||
123 | 2.35.1 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
1 | 2 | ||
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 |
New patch | |||
---|---|---|---|
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
1 | 2 | ||
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 |
New patch | |||
---|---|---|---|
1 | 1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | |
2 | |||
3 | block coroutines functions run in different aiocontext, and are | ||
4 | not protected by the BQL. Therefore are I/O. | ||
5 | |||
6 | On the other side, generated_co_wrapper functions use BDRV_POLL_WHILE, | ||
7 | meaning the caller can either be the main loop or a specific iothread. | ||
8 | |||
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 | ||
214 | index XXXXXXX..XXXXXXX 100644 | ||
215 | --- a/block/io.c | ||
216 | +++ b/block/io.c | ||
217 | @@ -XXX,XX +XXX,XX @@ bdrv_co_common_block_status_above(BlockDriverState *bs, | ||
218 | BlockDriverState *p; | ||
219 | int64_t eof = 0; | ||
220 | int dummy; | ||
221 | + IO_CODE(); | ||
222 | |||
223 | assert(!include_base || base); /* Can't include NULL base */ | ||
224 | |||
225 | @@ -XXX,XX +XXX,XX @@ bdrv_co_readv_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos) | ||
226 | BlockDriver *drv = bs->drv; | ||
227 | BlockDriverState *child_bs = bdrv_primary_bs(bs); | ||
228 | int ret; | ||
229 | + IO_CODE(); | ||
230 | |||
231 | ret = bdrv_check_qiov_request(pos, qiov->size, qiov, 0, NULL); | ||
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 | |||
253 | -- | ||
254 | 2.35.1 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
1 | 2 | ||
3 | Similar to the header split, also the function pointers in BlockDriver | ||
4 | can be split in I/O and global state. | ||
5 | |||
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> | ||
9 | --- | ||
10 | include/block/block_int-common.h | 445 ++++++++++++++++--------------- | ||
11 | 1 file changed, 237 insertions(+), 208 deletions(-) | ||
12 | |||
13 | diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h | ||
14 | index XXXXXXX..XXXXXXX 100644 | ||
15 | --- a/include/block/block_int-common.h | ||
16 | +++ b/include/block/block_int-common.h | ||
17 | @@ -XXX,XX +XXX,XX @@ typedef struct BdrvTrackedRequest { | ||
18 | |||
19 | |||
20 | struct BlockDriver { | ||
21 | + /* | ||
22 | + * These fields are initialized when this object is created, | ||
23 | + * and are never changed afterwards. | ||
24 | + */ | ||
25 | + | ||
26 | const char *format_name; | ||
27 | int instance_size; | ||
28 | |||
29 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { | ||
30 | */ | ||
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 | - | ||
345 | /* | ||
346 | * Invalidate any cached meta-data. | ||
347 | */ | ||
348 | void coroutine_fn (*bdrv_co_invalidate_cache)(BlockDriverState *bs, | ||
349 | Error **errp); | ||
350 | - int (*bdrv_inactivate)(BlockDriverState *bs); | ||
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 | - | ||
366 | /* | ||
367 | * Truncate @bs to @offset bytes using the given @prealloc mode | ||
368 | * when growing. Modes other than PREALLOC_MODE_OFF should be | ||
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 | -- | ||
585 | 2.35.1 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
1 | 2 | ||
3 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
4 | Message-Id: <20220303151616.325444-27-eesposit@redhat.com> | ||
5 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
6 | --- | ||
7 | block.c | 17 +++++++++++++++++ | ||
8 | block/create.c | 2 ++ | ||
9 | 2 files changed, 19 insertions(+) | ||
10 | |||
11 | diff --git a/block.c b/block.c | ||
12 | index XXXXXXX..XXXXXXX 100644 | ||
13 | --- a/block.c | ||
14 | +++ b/block.c | ||
15 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_create_co_entry(void *opaque) | ||
16 | |||
17 | CreateCo *cco = opaque; | ||
18 | assert(cco->drv); | ||
19 | + GLOBAL_STATE_CODE(); | ||
20 | |||
21 | ret = cco->drv->bdrv_co_create_opts(cco->drv, | ||
22 | cco->filename, cco->opts, &local_err); | ||
23 | @@ -XXX,XX +XXX,XX @@ int refresh_total_sectors(BlockDriverState *bs, int64_t hint) | ||
24 | static void bdrv_join_options(BlockDriverState *bs, QDict *options, | ||
25 | QDict *old_options) | ||
26 | { | ||
27 | + GLOBAL_STATE_CODE(); | ||
28 | if (bs->drv && bs->drv->bdrv_join_options) { | ||
29 | bs->drv->bdrv_join_options(options, old_options); | ||
30 | } else { | ||
31 | @@ -XXX,XX +XXX,XX @@ static int bdrv_open_driver(BlockDriverState *bs, BlockDriver *drv, | ||
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 | -- | ||
151 | 2.35.1 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
1 | 2 | ||
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 |
New patch | |||
---|---|---|---|
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
1 | 2 | ||
3 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
4 | Message-Id: <20220303151616.325444-29-eesposit@redhat.com> | ||
5 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
6 | --- | ||
7 | block.c | 10 +++++++++- | ||
8 | 1 file changed, 9 insertions(+), 1 deletion(-) | ||
9 | |||
10 | diff --git a/block.c b/block.c | ||
11 | index XXXXXXX..XXXXXXX 100644 | ||
12 | --- a/block.c | ||
13 | +++ b/block.c | ||
14 | @@ -XXX,XX +XXX,XX @@ const BdrvChildClass child_of_bds = { | ||
15 | |||
16 | AioContext *bdrv_child_get_parent_aio_context(BdrvChild *c) | ||
17 | { | ||
18 | - IO_CODE(); | ||
19 | + GLOBAL_STATE_CODE(); | ||
20 | return c->klass->get_parent_aio_context(c); | ||
21 | } | ||
22 | |||
23 | @@ -XXX,XX +XXX,XX @@ bool bdrv_is_writable(BlockDriverState *bs) | ||
24 | |||
25 | static char *bdrv_child_user_desc(BdrvChild *c) | ||
26 | { | ||
27 | + GLOBAL_STATE_CODE(); | ||
28 | return c->klass->get_parent_desc(c); | ||
29 | } | ||
30 | |||
31 | @@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_noperm(BdrvChild **childp, | ||
32 | |||
33 | assert(!child->frozen); | ||
34 | assert(old_bs != new_bs); | ||
35 | + GLOBAL_STATE_CODE(); | ||
36 | |||
37 | if (old_bs && new_bs) { | ||
38 | assert(bdrv_get_aio_context(old_bs) == bdrv_get_aio_context(new_bs)); | ||
39 | @@ -XXX,XX +XXX,XX @@ static void bdrv_attach_child_common_abort(void *opaque) | ||
40 | BdrvChild *child = *s->child; | ||
41 | BlockDriverState *bs = child->bs; | ||
42 | |||
43 | + GLOBAL_STATE_CODE(); | ||
44 | /* | ||
45 | * Pass free_empty_child=false, because we still need the child | ||
46 | * for the AioContext operations on the parent below; those | ||
47 | @@ -XXX,XX +XXX,XX @@ void bdrv_unref_child(BlockDriverState *parent, BdrvChild *child) | ||
48 | static void bdrv_parent_cb_change_media(BlockDriverState *bs, bool load) | ||
49 | { | ||
50 | BdrvChild *c; | ||
51 | + GLOBAL_STATE_CODE(); | ||
52 | QLIST_FOREACH(c, &bs->parents, next_parent) { | ||
53 | if (c->klass->change_media) { | ||
54 | c->klass->change_media(c, load); | ||
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 | } | ||
87 | -- | ||
88 | 2.35.1 | diff view generated by jsdifflib |
1 | The BDRV_REQ_ZERO_WRITE is currently implemented in a way that first the | 1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
---|---|---|---|
2 | image is possibly preallocated and then the zero flag is added to all | ||
3 | clusters. This means that a copy-on-write operation may be needed when | ||
4 | writing to these clusters, despite having used preallocation, negating | ||
5 | one of the major benefits of preallocation. | ||
6 | 2 | ||
7 | Instead, try to forward the BDRV_REQ_ZERO_WRITE to the protocol driver, | 3 | Assertions in the callers of the function pointrs are already |
8 | and if the protocol driver can ensure that the new area reads as zeros, | 4 | added by previous patches. |
9 | we can skip setting the zero flag in the qcow2 layer. | ||
10 | 5 | ||
11 | Unfortunately, the same approach doesn't work for metadata | 6 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
12 | preallocation, so we'll still set the zero flag there. | 7 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> |
13 | 8 | Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> | |
14 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 9 | Message-Id: <20220303151616.325444-30-eesposit@redhat.com> |
15 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
16 | Message-Id: <20200424142701.67053-1-kwolf@redhat.com> | ||
17 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
18 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
19 | --- | 11 | --- |
20 | block/qcow2.c | 22 +++++++++++++++++++--- | 12 | include/sysemu/block-backend-common.h | 28 ++++++++++++++++++++++----- |
21 | tests/qemu-iotests/274.out | 4 ++-- | 13 | 1 file changed, 23 insertions(+), 5 deletions(-) |
22 | 2 files changed, 21 insertions(+), 5 deletions(-) | ||
23 | 14 | ||
24 | diff --git a/block/qcow2.c b/block/qcow2.c | 15 | diff --git a/include/sysemu/block-backend-common.h b/include/sysemu/block-backend-common.h |
25 | index XXXXXXX..XXXXXXX 100644 | 16 | index XXXXXXX..XXXXXXX 100644 |
26 | --- a/block/qcow2.c | 17 | --- a/include/sysemu/block-backend-common.h |
27 | +++ b/block/qcow2.c | 18 | +++ b/include/sysemu/block-backend-common.h |
28 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset, | 19 | @@ -XXX,XX +XXX,XX @@ |
29 | /* Allocate the data area */ | 20 | |
30 | new_file_size = allocation_start + | 21 | /* Callbacks for block device models */ |
31 | nb_new_data_clusters * s->cluster_size; | 22 | typedef struct BlockDevOps { |
32 | - /* Image file grows, so @exact does not matter */ | 23 | + |
33 | - ret = bdrv_co_truncate(bs->file, new_file_size, false, prealloc, 0, | 24 | + /* |
34 | - errp); | 25 | + * Global state (GS) API. These functions run under the BQL. |
35 | + /* | 26 | + * |
36 | + * Image file grows, so @exact does not matter. | 27 | + * See include/block/block-global-state.h for more information about |
37 | + * | 28 | + * the GS API. |
38 | + * If we need to zero out the new area, try first whether the protocol | 29 | + */ |
39 | + * driver can already take care of this. | 30 | + |
40 | + */ | 31 | /* |
41 | + if (flags & BDRV_REQ_ZERO_WRITE) { | 32 | * Runs when virtual media changed (monitor commands eject, change) |
42 | + ret = bdrv_co_truncate(bs->file, new_file_size, false, prealloc, | 33 | * Argument load is true on load and false on eject. |
43 | + BDRV_REQ_ZERO_WRITE, NULL); | 34 | @@ -XXX,XX +XXX,XX @@ typedef struct BlockDevOps { |
44 | + if (ret >= 0) { | 35 | * true, even if they do not support eject requests. |
45 | + flags &= ~BDRV_REQ_ZERO_WRITE; | 36 | */ |
46 | + } | 37 | void (*eject_request_cb)(void *opaque, bool force); |
47 | + } else { | 38 | - /* |
48 | + ret = -1; | 39 | - * Is the virtual tray open? |
49 | + } | 40 | - * Device models implement this only when the device has a tray. |
50 | + if (ret < 0) { | 41 | - */ |
51 | + ret = bdrv_co_truncate(bs->file, new_file_size, false, prealloc, 0, | 42 | - bool (*is_tray_open)(void *opaque); |
52 | + errp); | 43 | + |
53 | + } | 44 | /* |
54 | if (ret < 0) { | 45 | * Is the virtual medium locked into the device? |
55 | error_prepend(errp, "Failed to resize underlying file: "); | 46 | * Device models implement this only when device has such a lock. |
56 | qcow2_free_clusters(bs, allocation_start, | 47 | */ |
57 | diff --git a/tests/qemu-iotests/274.out b/tests/qemu-iotests/274.out | 48 | bool (*is_medium_locked)(void *opaque); |
58 | index XXXXXXX..XXXXXXX 100644 | 49 | + |
59 | --- a/tests/qemu-iotests/274.out | 50 | + /* |
60 | +++ b/tests/qemu-iotests/274.out | 51 | + * I/O API functions. These functions are thread-safe. |
61 | @@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 9437184 | 52 | + * |
62 | 10 MiB (0xa00000) bytes allocated at offset 5 MiB (0x500000) | 53 | + * See include/block/block-io.h for more information about |
63 | 54 | + * the I/O API. | |
64 | [{ "start": 0, "length": 5242880, "depth": 1, "zero": true, "data": false}, | 55 | + */ |
65 | -{ "start": 5242880, "length": 10485760, "depth": 0, "zero": true, "data": false, "offset": 327680}] | 56 | + |
66 | +{ "start": 5242880, "length": 10485760, "depth": 0, "zero": false, "data": true, "offset": 327680}] | 57 | + /* |
67 | 58 | + * Is the virtual tray open? | |
68 | === preallocation=full === | 59 | + * Device models implement this only when the device has a tray. |
69 | Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=16777216 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | 60 | + */ |
70 | @@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 11534336 | 61 | + bool (*is_tray_open)(void *opaque); |
71 | 4 MiB (0x400000) bytes allocated at offset 8 MiB (0x800000) | 62 | + |
72 | 63 | /* | |
73 | [{ "start": 0, "length": 8388608, "depth": 1, "zero": true, "data": false}, | 64 | * Runs when the size changed (e.g. monitor command block_resize) |
74 | -{ "start": 8388608, "length": 4194304, "depth": 0, "zero": true, "data": false, "offset": 327680}] | 65 | */ |
75 | +{ "start": 8388608, "length": 4194304, "depth": 0, "zero": false, "data": true, "offset": 327680}] | ||
76 | |||
77 | === preallocation=off === | ||
78 | Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=393216 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
79 | -- | 66 | -- |
80 | 2.25.3 | 67 | 2.35.1 |
81 | 68 | ||
82 | 69 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
1 | 2 | ||
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 |
1 | For regular files, we always get BDRV_REQ_ZERO_WRITE behaviour from the | 1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
---|---|---|---|
2 | OS, so we can advertise the flag and just ignore it. | ||
3 | 2 | ||
4 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 3 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
5 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 4 | Message-Id: <20220303151616.325444-32-eesposit@redhat.com> |
6 | Reviewed-by: Alberto Garcia <berto@igalia.com> | ||
7 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
8 | Message-Id: <20200424125448.63318-7-kwolf@redhat.com> | ||
9 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 5 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
10 | --- | 6 | --- |
11 | block/file-posix.c | 4 ++++ | 7 | job.c | 10 ++++++++++ |
12 | 1 file changed, 4 insertions(+) | 8 | 1 file changed, 10 insertions(+) |
13 | 9 | ||
14 | diff --git a/block/file-posix.c b/block/file-posix.c | 10 | diff --git a/job.c b/job.c |
15 | index XXXXXXX..XXXXXXX 100644 | 11 | index XXXXXXX..XXXXXXX 100644 |
16 | --- a/block/file-posix.c | 12 | --- a/job.c |
17 | +++ b/block/file-posix.c | 13 | +++ b/job.c |
18 | @@ -XXX,XX +XXX,XX @@ static int raw_open_common(BlockDriverState *bs, QDict *options, | 14 | @@ -XXX,XX +XXX,XX @@ void job_ref(Job *job) |
19 | #endif | 15 | |
20 | 16 | void job_unref(Job *job) | |
21 | bs->supported_zero_flags = BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK; | 17 | { |
22 | + if (S_ISREG(st.st_mode)) { | 18 | + GLOBAL_STATE_CODE(); |
23 | + /* When extending regular files, we get zeros from the OS */ | 19 | + |
24 | + bs->supported_truncate_flags = BDRV_REQ_ZERO_WRITE; | 20 | if (--job->refcnt == 0) { |
25 | + } | 21 | assert(job->status == JOB_STATUS_NULL); |
26 | ret = 0; | 22 | assert(!timer_pending(&job->sleep_timer)); |
27 | fail: | 23 | @@ -XXX,XX +XXX,XX @@ bool job_user_paused(Job *job) |
28 | if (filename && (bdrv_flags & BDRV_O_TEMPORARY)) { | 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 | } | ||
29 | -- | 87 | -- |
30 | 2.25.3 | 88 | 2.35.1 |
31 | |||
32 | diff view generated by jsdifflib |
1 | When extending the size of an image that has a backing file larger than | 1 | From: Hanna Reitz <hreitz@redhat.com> |
---|---|---|---|
2 | its old size, make sure that the backing file data doesn't become | ||
3 | visible in the guest, but the added area is properly zeroed out. | ||
4 | 2 | ||
5 | Consider the following scenario where the overlay is shorter than its | 3 | bdrv_refresh_limits() recurses down to the node's children. That does |
6 | backing file: | 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. | ||
7 | 10 | ||
8 | base.qcow2: AAAAAAAA | 11 | Consequently, we should actually propagate block limits changes upwards, |
9 | overlay.qcow2: BBBB | 12 | not downwards. That is a separate and pre-existing issue, though, and |
13 | so will not be addressed in this patch. | ||
10 | 14 | ||
11 | When resizing (extending) overlay.qcow2, the new blocks should not stay | 15 | The problem with recursing is that bdrv_refresh_limits() is not atomic. |
12 | unallocated and make the additional As from base.qcow2 visible like | 16 | It begins with zeroing BDS.bl, and only then sets proper, valid limits. |
13 | before this patch, but zeros should be read. | 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. | ||
14 | 21 | ||
15 | A similar case happens with the various variants of a commit job when an | 22 | A non-recursive bdrv_refresh_limits() only requires the node in question |
16 | intermediate file is short (- for unallocated): | 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 | ||
17 | 32 | ||
18 | base.qcow2: A-A-AAAA | 33 | So we can resolve the bug by making bdrv_refresh_limits() non-recursive. |
19 | mid.qcow2: BB-B | ||
20 | top.qcow2: C--C--C- | ||
21 | 34 | ||
22 | After commit top.qcow2 to mid.qcow2, the following happens: | 35 | Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=1879437 |
23 | 36 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | |
24 | mid.qcow2: CB-C00C0 (correct result) | 37 | Reviewed-by: Eric Blake <eblake@redhat.com> |
25 | mid.qcow2: CB-C--C- (before this fix) | 38 | Message-Id: <20220216105355.30729-2-hreitz@redhat.com> |
26 | 39 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | |
27 | Without the fix, blocks that previously read as zeros on top.qcow2 | ||
28 | suddenly turn into A. | ||
29 | |||
30 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
31 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
32 | Message-Id: <20200424125448.63318-8-kwolf@redhat.com> | ||
33 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
34 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 40 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
35 | --- | 41 | --- |
36 | block/io.c | 25 +++++++++++++++++++++++++ | 42 | block/io.c | 4 ---- |
37 | 1 file changed, 25 insertions(+) | 43 | 1 file changed, 4 deletions(-) |
38 | 44 | ||
39 | diff --git a/block/io.c b/block/io.c | 45 | diff --git a/block/io.c b/block/io.c |
40 | index XXXXXXX..XXXXXXX 100644 | 46 | index XXXXXXX..XXXXXXX 100644 |
41 | --- a/block/io.c | 47 | --- a/block/io.c |
42 | +++ b/block/io.c | 48 | +++ b/block/io.c |
43 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact, | 49 | @@ -XXX,XX +XXX,XX @@ void bdrv_refresh_limits(BlockDriverState *bs, Transaction *tran, Error **errp) |
44 | goto out; | 50 | QLIST_FOREACH(c, &bs->children, next) { |
45 | } | 51 | if (c->role & (BDRV_CHILD_DATA | BDRV_CHILD_FILTERED | BDRV_CHILD_COW)) |
46 | 52 | { | |
47 | + /* | 53 | - bdrv_refresh_limits(c->bs, tran, errp); |
48 | + * If the image has a backing file that is large enough that it would | 54 | - if (*errp) { |
49 | + * provide data for the new area, we cannot leave it unallocated because | 55 | - return; |
50 | + * then the backing file content would become visible. Instead, zero-fill | 56 | - } |
51 | + * the new area. | 57 | bdrv_merge_limits(&bs->bl, &c->bs->bl); |
52 | + * | 58 | have_limits = true; |
53 | + * Note that if the image has a backing file, but was opened without the | 59 | } |
54 | + * backing file, taking care of keeping things consistent with that backing | ||
55 | + * file is the user's responsibility. | ||
56 | + */ | ||
57 | + if (new_bytes && bs->backing) { | ||
58 | + int64_t backing_len; | ||
59 | + | ||
60 | + backing_len = bdrv_getlength(backing_bs(bs)); | ||
61 | + if (backing_len < 0) { | ||
62 | + ret = backing_len; | ||
63 | + error_setg_errno(errp, -ret, "Could not get backing file size"); | ||
64 | + goto out; | ||
65 | + } | ||
66 | + | ||
67 | + if (backing_len > old_size) { | ||
68 | + flags |= BDRV_REQ_ZERO_WRITE; | ||
69 | + } | ||
70 | + } | ||
71 | + | ||
72 | if (drv->bdrv_co_truncate) { | ||
73 | if (flags & ~bs->supported_truncate_flags) { | ||
74 | error_setg(errp, "Block driver does not support requested flags"); | ||
75 | -- | 60 | -- |
76 | 2.25.3 | 61 | 2.35.1 |
77 | 62 | ||
78 | 63 | diff view generated by jsdifflib |
1 | We want to keep TEST_IMG for the full path of the main test image, but | 1 | From: Hanna Reitz <hreitz@redhat.com> |
---|---|---|---|
2 | filter_testfiles() must be called for other test images before replacing | ||
3 | other things like the image format because the test directory path could | ||
4 | contain the format as a substring. | ||
5 | 2 | ||
6 | Insert a filter_testfiles() call between both. | 3 | Add a parameter to optionally open a QMP connection when creating a |
4 | QemuStorageDaemon instance. | ||
7 | 5 | ||
8 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 6 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> |
9 | Reviewed-by: Max Reitz <mreitz@redhat.com> | 7 | Message-Id: <20220216105355.30729-3-hreitz@redhat.com> |
10 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 8 | Reviewed-by: Eric Blake <eblake@redhat.com> |
11 | Message-Id: <20200424125448.63318-9-kwolf@redhat.com> | 9 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> |
12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
13 | --- | 11 | --- |
14 | tests/qemu-iotests/iotests.py | 5 +++-- | 12 | tests/qemu-iotests/iotests.py | 32 +++++++++++++++++++++++++++++++- |
15 | 1 file changed, 3 insertions(+), 2 deletions(-) | 13 | 1 file changed, 31 insertions(+), 1 deletion(-) |
16 | 14 | ||
17 | diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py | 15 | diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py |
18 | index XXXXXXX..XXXXXXX 100644 | 16 | index XXXXXXX..XXXXXXX 100644 |
19 | --- a/tests/qemu-iotests/iotests.py | 17 | --- a/tests/qemu-iotests/iotests.py |
20 | +++ b/tests/qemu-iotests/iotests.py | 18 | +++ b/tests/qemu-iotests/iotests.py |
21 | @@ -XXX,XX +XXX,XX @@ def filter_img_info(output, filename): | 19 | @@ -XXX,XX +XXX,XX @@ |
22 | for line in output.split('\n'): | 20 | |
23 | if 'disk size' in line or 'actual-size' in line: | 21 | from qemu.machine import qtest |
24 | continue | 22 | from qemu.qmp import QMPMessage |
25 | - line = line.replace(filename, 'TEST_IMG') \ | 23 | +from qemu.aqmp.legacy import QEMUMonitorProtocol |
26 | - .replace(imgfmt, 'IMGFMT') | 24 | |
27 | + line = line.replace(filename, 'TEST_IMG') | 25 | # Use this logger for logging messages directly from the iotests module |
28 | + line = filter_testfiles(line) | 26 | logger = logging.getLogger('qemu.iotests') |
29 | + line = line.replace(imgfmt, 'IMGFMT') | 27 | @@ -XXX,XX +XXX,XX @@ def cmd(self, cmd): |
30 | line = re.sub('iters: [0-9]+', 'iters: XXX', line) | 28 | |
31 | line = re.sub('uuid: [-a-f0-9]+', 'uuid: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX', line) | 29 | |
32 | line = re.sub('cid: [0-9]+', 'cid: XXXXXXXXXX', line) | 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: | ||
33 | -- | 84 | -- |
34 | 2.25.3 | 85 | 2.35.1 |
35 | |||
36 | diff view generated by jsdifflib |
1 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 1 | From: Hanna Reitz <hreitz@redhat.com> |
---|---|---|---|
2 | Message-Id: <20200424125448.63318-10-kwolf@redhat.com> | 2 | |
3 | Reviewed-by: Max Reitz <mreitz@redhat.com> | 3 | Test the following scenario: |
4 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 4 | 1. Some block node (null-co) attached to a user (here: NBD server) that |
5 | performs I/O and keeps the node in an I/O thread | ||
6 | 2. Repeatedly run blockdev-add/blockdev-del to add/remove an overlay | ||
7 | to/from that node | ||
8 | |||
9 | Each blockdev-add triggers bdrv_refresh_limits(), and because | ||
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> | ||
5 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 22 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
6 | --- | 23 | --- |
7 | tests/qemu-iotests/274 | 155 +++++++++++++++++++++ | 24 | .../qemu-iotests/tests/graph-changes-while-io | 91 +++++++++++++++++++ |
8 | tests/qemu-iotests/274.out | 268 +++++++++++++++++++++++++++++++++++++ | 25 | .../tests/graph-changes-while-io.out | 5 + |
9 | tests/qemu-iotests/group | 1 + | 26 | 2 files changed, 96 insertions(+) |
10 | 3 files changed, 424 insertions(+) | 27 | create mode 100755 tests/qemu-iotests/tests/graph-changes-while-io |
11 | create mode 100755 tests/qemu-iotests/274 | 28 | create mode 100644 tests/qemu-iotests/tests/graph-changes-while-io.out |
12 | create mode 100644 tests/qemu-iotests/274.out | ||
13 | 29 | ||
14 | diff --git a/tests/qemu-iotests/274 b/tests/qemu-iotests/274 | 30 | diff --git a/tests/qemu-iotests/tests/graph-changes-while-io b/tests/qemu-iotests/tests/graph-changes-while-io |
15 | new file mode 100755 | 31 | new file mode 100755 |
16 | index XXXXXXX..XXXXXXX | 32 | index XXXXXXX..XXXXXXX |
17 | --- /dev/null | 33 | --- /dev/null |
18 | +++ b/tests/qemu-iotests/274 | 34 | +++ b/tests/qemu-iotests/tests/graph-changes-while-io |
19 | @@ -XXX,XX +XXX,XX @@ | 35 | @@ -XXX,XX +XXX,XX @@ |
20 | +#!/usr/bin/env python3 | 36 | +#!/usr/bin/env python3 |
37 | +# group: rw | ||
21 | +# | 38 | +# |
22 | +# Copyright (C) 2019 Red Hat, Inc. | 39 | +# Test graph changes while I/O is happening |
40 | +# | ||
41 | +# Copyright (C) 2022 Red Hat, Inc. | ||
23 | +# | 42 | +# |
24 | +# This program is free software; you can redistribute it and/or modify | 43 | +# This program is free software; you can redistribute it and/or modify |
25 | +# it under the terms of the GNU General Public License as published by | 44 | +# it under the terms of the GNU General Public License as published by |
26 | +# the Free Software Foundation; either version 2 of the License, or | 45 | +# the Free Software Foundation; either version 2 of the License, or |
27 | +# (at your option) any later version. | 46 | +# (at your option) any later version. |
... | ... | ||
32 | +# GNU General Public License for more details. | 51 | +# GNU General Public License for more details. |
33 | +# | 52 | +# |
34 | +# You should have received a copy of the GNU General Public License | 53 | +# You should have received a copy of the GNU General Public License |
35 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. | 54 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
36 | +# | 55 | +# |
37 | +# Creator/Owner: Kevin Wolf <kwolf@redhat.com> | ||
38 | +# | ||
39 | +# Some tests for short backing files and short overlays | ||
40 | + | 56 | + |
57 | +import os | ||
58 | +from threading import Thread | ||
41 | +import iotests | 59 | +import iotests |
42 | + | 60 | +from iotests import imgfmt, qemu_img, qemu_img_create, QMPTestCase, \ |
43 | +iotests.verify_image_format(supported_fmts=['qcow2']) | 61 | + QemuStorageDaemon |
44 | +iotests.verify_platform(['linux']) | ||
45 | + | ||
46 | +size_short = 1 * 1024 * 1024 | ||
47 | +size_long = 2 * 1024 * 1024 | ||
48 | +size_diff = size_long - size_short | ||
49 | + | ||
50 | +def create_chain() -> None: | ||
51 | + iotests.qemu_img_log('create', '-f', iotests.imgfmt, base, | ||
52 | + str(size_long)) | ||
53 | + iotests.qemu_img_log('create', '-f', iotests.imgfmt, '-b', base, mid, | ||
54 | + str(size_short)) | ||
55 | + iotests.qemu_img_log('create', '-f', iotests.imgfmt, '-b', mid, top, | ||
56 | + str(size_long)) | ||
57 | + | ||
58 | + iotests.qemu_io_log('-c', 'write -P 1 0 %d' % size_long, base) | ||
59 | + | ||
60 | +def create_vm() -> iotests.VM: | ||
61 | + vm = iotests.VM() | ||
62 | + vm.add_blockdev('file,filename=%s,node-name=base-file' % base) | ||
63 | + vm.add_blockdev('%s,file=base-file,node-name=base' % iotests.imgfmt) | ||
64 | + vm.add_blockdev('file,filename=%s,node-name=mid-file' % mid) | ||
65 | + vm.add_blockdev('%s,file=mid-file,node-name=mid,backing=base' | ||
66 | + % iotests.imgfmt) | ||
67 | + vm.add_drive(top, 'backing=mid,node-name=top') | ||
68 | + return vm | ||
69 | + | ||
70 | +with iotests.FilePath('base') as base, \ | ||
71 | + iotests.FilePath('mid') as mid, \ | ||
72 | + iotests.FilePath('top') as top: | ||
73 | + | ||
74 | + iotests.log('== Commit tests ==') | ||
75 | + | ||
76 | + create_chain() | ||
77 | + | ||
78 | + iotests.log('=== Check visible data ===') | ||
79 | + | ||
80 | + iotests.qemu_io_log('-c', 'read -P 1 0 %d' % size_short, top) | ||
81 | + iotests.qemu_io_log('-c', 'read -P 0 %d %d' % (size_short, size_diff), top) | ||
82 | + | ||
83 | + iotests.log('=== Checking allocation status ===') | ||
84 | + | ||
85 | + iotests.qemu_io_log('-c', 'alloc 0 %d' % size_short, | ||
86 | + '-c', 'alloc %d %d' % (size_short, size_diff), | ||
87 | + base) | ||
88 | + | ||
89 | + iotests.qemu_io_log('-c', 'alloc 0 %d' % size_short, | ||
90 | + '-c', 'alloc %d %d' % (size_short, size_diff), | ||
91 | + mid) | ||
92 | + | ||
93 | + iotests.qemu_io_log('-c', 'alloc 0 %d' % size_short, | ||
94 | + '-c', 'alloc %d %d' % (size_short, size_diff), | ||
95 | + top) | ||
96 | + | ||
97 | + iotests.log('=== Checking map ===') | ||
98 | + | ||
99 | + iotests.qemu_img_log('map', '--output=json', base) | ||
100 | + iotests.qemu_img_log('map', '--output=human', base) | ||
101 | + iotests.qemu_img_log('map', '--output=json', mid) | ||
102 | + iotests.qemu_img_log('map', '--output=human', mid) | ||
103 | + iotests.qemu_img_log('map', '--output=json', top) | ||
104 | + iotests.qemu_img_log('map', '--output=human', top) | ||
105 | + | ||
106 | + iotests.log('=== Testing qemu-img commit (top -> mid) ===') | ||
107 | + | ||
108 | + iotests.qemu_img_log('commit', top) | ||
109 | + iotests.img_info_log(mid) | ||
110 | + iotests.qemu_io_log('-c', 'read -P 1 0 %d' % size_short, mid) | ||
111 | + iotests.qemu_io_log('-c', 'read -P 0 %d %d' % (size_short, size_diff), mid) | ||
112 | + | ||
113 | + iotests.log('=== Testing HMP commit (top -> mid) ===') | ||
114 | + | ||
115 | + create_chain() | ||
116 | + with create_vm() as vm: | ||
117 | + vm.launch() | ||
118 | + vm.qmp_log('human-monitor-command', command_line='commit drive0') | ||
119 | + | ||
120 | + iotests.img_info_log(mid) | ||
121 | + iotests.qemu_io_log('-c', 'read -P 1 0 %d' % size_short, mid) | ||
122 | + iotests.qemu_io_log('-c', 'read -P 0 %d %d' % (size_short, size_diff), mid) | ||
123 | + | ||
124 | + iotests.log('=== Testing QMP active commit (top -> mid) ===') | ||
125 | + | ||
126 | + create_chain() | ||
127 | + with create_vm() as vm: | ||
128 | + vm.launch() | ||
129 | + vm.qmp_log('block-commit', device='top', base_node='mid', | ||
130 | + job_id='job0', auto_dismiss=False) | ||
131 | + vm.run_job('job0', wait=5) | ||
132 | + | ||
133 | + iotests.img_info_log(mid) | ||
134 | + iotests.qemu_io_log('-c', 'read -P 1 0 %d' % size_short, mid) | ||
135 | + iotests.qemu_io_log('-c', 'read -P 0 %d %d' % (size_short, size_diff), mid) | ||
136 | + | 62 | + |
137 | + | 63 | + |
138 | + iotests.log('== Resize tests ==') | 64 | +top = os.path.join(iotests.test_dir, 'top.img') |
65 | +nbd_sock = os.path.join(iotests.sock_dir, 'nbd.sock') | ||
139 | + | 66 | + |
140 | + # Use different sizes for different allocation modes: | ||
141 | + # | ||
142 | + # We want to have at least one test where 32 bit truncation in the size of | ||
143 | + # the overlapping area becomes visible. This is covered by the | ||
144 | + # prealloc='off' case (1G to 6G is an overlap of 5G). | ||
145 | + # | ||
146 | + # However, we can only do this for modes that don't preallocate data | ||
147 | + # because otherwise we might run out of space on the test host. | ||
148 | + # | ||
149 | + # We also want to test some unaligned combinations. | ||
150 | + for (prealloc, base_size, top_size_old, top_size_new, off) in [ | ||
151 | + ('off', '6G', '1G', '8G', '5G'), | ||
152 | + ('metadata', '32G', '30G', '33G', '31G'), | ||
153 | + ('falloc', '10M', '5M', '15M', '9M'), | ||
154 | + ('full', '16M', '8M', '12M', '11M'), | ||
155 | + ('off', '384k', '253k', '512k', '253k'), | ||
156 | + ('off', '400k', '256k', '512k', '336k'), | ||
157 | + ('off', '512k', '256k', '500k', '436k')]: | ||
158 | + | 67 | + |
159 | + iotests.log('=== preallocation=%s ===' % prealloc) | 68 | +def do_qemu_img_bench() -> None: |
160 | + iotests.qemu_img_log('create', '-f', iotests.imgfmt, base, base_size) | 69 | + """ |
161 | + iotests.qemu_img_log('create', '-f', iotests.imgfmt, '-b', base, top, | 70 | + Do some I/O requests on `nbd_sock`. |
162 | + top_size_old) | 71 | + """ |
163 | + iotests.qemu_io_log('-c', 'write -P 1 %s 64k' % off, base) | 72 | + assert qemu_img('bench', '-f', 'raw', '-c', '2000000', |
73 | + f'nbd+unix:///node0?socket={nbd_sock}') == 0 | ||
164 | + | 74 | + |
165 | + # After this, top_size_old to base_size should be allocated/zeroed. | 75 | + |
166 | + # | 76 | +class TestGraphChangesWhileIO(QMPTestCase): |
167 | + # In theory, leaving base_size to top_size_new unallocated would be | 77 | + def setUp(self) -> None: |
168 | + # correct, but in practice, if we zero out anything, we zero out | 78 | + # Create an overlay that can be added at runtime on top of the |
169 | + # everything up to top_size_new. | 79 | + # null-co block node that will receive I/O |
170 | + iotests.qemu_img_log('resize', '-f', iotests.imgfmt, | 80 | + assert qemu_img_create('-f', imgfmt, '-F', 'raw', '-b', 'null-co://', |
171 | + '--preallocation', prealloc, top, top_size_new) | 81 | + top) == 0 |
172 | + iotests.qemu_io_log('-c', 'read -P 0 %s 64k' % off, top) | 82 | + |
173 | + iotests.qemu_io_log('-c', 'map', top) | 83 | + # QSD instance with a null-co block node in an I/O thread, |
174 | + iotests.qemu_img_log('map', '--output=json', top) | 84 | + # exported over NBD (on `nbd_sock`, export name "node0") |
175 | diff --git a/tests/qemu-iotests/274.out b/tests/qemu-iotests/274.out | 85 | + self.qsd = QemuStorageDaemon( |
86 | + '--object', 'iothread,id=iothread0', | ||
87 | + '--blockdev', 'null-co,node-name=node0,read-zeroes=true', | ||
88 | + '--nbd-server', f'addr.type=unix,addr.path={nbd_sock}', | ||
89 | + '--export', 'nbd,id=exp0,node-name=node0,iothread=iothread0,' + | ||
90 | + 'fixed-iothread=true,writable=true', | ||
91 | + qmp=True | ||
92 | + ) | ||
93 | + | ||
94 | + def tearDown(self) -> None: | ||
95 | + self.qsd.stop() | ||
96 | + | ||
97 | + def test_blockdev_add_while_io(self) -> None: | ||
98 | + # Run qemu-img bench in the background | ||
99 | + bench_thr = Thread(target=do_qemu_img_bench) | ||
100 | + bench_thr.start() | ||
101 | + | ||
102 | + # While qemu-img bench is running, repeatedly add and remove an | ||
103 | + # overlay to/from node0 | ||
104 | + while bench_thr.is_alive(): | ||
105 | + result = self.qsd.qmp('blockdev-add', { | ||
106 | + 'driver': imgfmt, | ||
107 | + 'node-name': 'overlay', | ||
108 | + 'backing': 'node0', | ||
109 | + 'file': { | ||
110 | + 'driver': 'file', | ||
111 | + 'filename': top | ||
112 | + } | ||
113 | + }) | ||
114 | + self.assert_qmp(result, 'return', {}) | ||
115 | + | ||
116 | + result = self.qsd.qmp('blockdev-del', { | ||
117 | + 'node-name': 'overlay' | ||
118 | + }) | ||
119 | + self.assert_qmp(result, 'return', {}) | ||
120 | + | ||
121 | + bench_thr.join() | ||
122 | + | ||
123 | +if __name__ == '__main__': | ||
124 | + # Format must support raw backing files | ||
125 | + iotests.main(supported_fmts=['qcow', 'qcow2', 'qed'], | ||
126 | + supported_protocols=['file']) | ||
127 | diff --git a/tests/qemu-iotests/tests/graph-changes-while-io.out b/tests/qemu-iotests/tests/graph-changes-while-io.out | ||
176 | new file mode 100644 | 128 | new file mode 100644 |
177 | index XXXXXXX..XXXXXXX | 129 | index XXXXXXX..XXXXXXX |
178 | --- /dev/null | 130 | --- /dev/null |
179 | +++ b/tests/qemu-iotests/274.out | 131 | +++ b/tests/qemu-iotests/tests/graph-changes-while-io.out |
180 | @@ -XXX,XX +XXX,XX @@ | 132 | @@ -XXX,XX +XXX,XX @@ |
181 | +== Commit tests == | 133 | +. |
182 | +Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=2097152 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | 134 | +---------------------------------------------------------------------- |
135 | +Ran 1 tests | ||
183 | + | 136 | + |
184 | +Formatting 'TEST_DIR/PID-mid', fmt=qcow2 size=1048576 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16 | 137 | +OK |
185 | + | ||
186 | +Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=2097152 backing_file=TEST_DIR/PID-mid cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
187 | + | ||
188 | +wrote 2097152/2097152 bytes at offset 0 | ||
189 | +2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
190 | + | ||
191 | +=== Check visible data === | ||
192 | +read 1048576/1048576 bytes at offset 0 | ||
193 | +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
194 | + | ||
195 | +read 1048576/1048576 bytes at offset 1048576 | ||
196 | +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
197 | + | ||
198 | +=== Checking allocation status === | ||
199 | +1048576/1048576 bytes allocated at offset 0 bytes | ||
200 | +1048576/1048576 bytes allocated at offset 1 MiB | ||
201 | + | ||
202 | +0/1048576 bytes allocated at offset 0 bytes | ||
203 | +0/0 bytes allocated at offset 1 MiB | ||
204 | + | ||
205 | +0/1048576 bytes allocated at offset 0 bytes | ||
206 | +0/1048576 bytes allocated at offset 1 MiB | ||
207 | + | ||
208 | +=== Checking map === | ||
209 | +[{ "start": 0, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": 327680}] | ||
210 | + | ||
211 | +Offset Length Mapped to File | ||
212 | +0 0x200000 0x50000 TEST_DIR/PID-base | ||
213 | + | ||
214 | +[{ "start": 0, "length": 1048576, "depth": 1, "zero": false, "data": true, "offset": 327680}] | ||
215 | + | ||
216 | +Offset Length Mapped to File | ||
217 | +0 0x100000 0x50000 TEST_DIR/PID-base | ||
218 | + | ||
219 | +[{ "start": 0, "length": 1048576, "depth": 2, "zero": false, "data": true, "offset": 327680}, | ||
220 | +{ "start": 1048576, "length": 1048576, "depth": 0, "zero": true, "data": false}] | ||
221 | + | ||
222 | +Offset Length Mapped to File | ||
223 | +0 0x100000 0x50000 TEST_DIR/PID-base | ||
224 | + | ||
225 | +=== Testing qemu-img commit (top -> mid) === | ||
226 | +Image committed. | ||
227 | + | ||
228 | +image: TEST_IMG | ||
229 | +file format: IMGFMT | ||
230 | +virtual size: 2 MiB (2097152 bytes) | ||
231 | +cluster_size: 65536 | ||
232 | +backing file: TEST_DIR/PID-base | ||
233 | +Format specific information: | ||
234 | + compat: 1.1 | ||
235 | + lazy refcounts: false | ||
236 | + refcount bits: 16 | ||
237 | + corrupt: false | ||
238 | + | ||
239 | +read 1048576/1048576 bytes at offset 0 | ||
240 | +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
241 | + | ||
242 | +read 1048576/1048576 bytes at offset 1048576 | ||
243 | +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
244 | + | ||
245 | +=== Testing HMP commit (top -> mid) === | ||
246 | +Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=2097152 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
247 | + | ||
248 | +Formatting 'TEST_DIR/PID-mid', fmt=qcow2 size=1048576 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
249 | + | ||
250 | +Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=2097152 backing_file=TEST_DIR/PID-mid cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
251 | + | ||
252 | +wrote 2097152/2097152 bytes at offset 0 | ||
253 | +2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
254 | + | ||
255 | +{"execute": "human-monitor-command", "arguments": {"command-line": "commit drive0"}} | ||
256 | +{"return": ""} | ||
257 | +image: TEST_IMG | ||
258 | +file format: IMGFMT | ||
259 | +virtual size: 2 MiB (2097152 bytes) | ||
260 | +cluster_size: 65536 | ||
261 | +backing file: TEST_DIR/PID-base | ||
262 | +Format specific information: | ||
263 | + compat: 1.1 | ||
264 | + lazy refcounts: false | ||
265 | + refcount bits: 16 | ||
266 | + corrupt: false | ||
267 | + | ||
268 | +read 1048576/1048576 bytes at offset 0 | ||
269 | +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
270 | + | ||
271 | +read 1048576/1048576 bytes at offset 1048576 | ||
272 | +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
273 | + | ||
274 | +=== Testing QMP active commit (top -> mid) === | ||
275 | +Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=2097152 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
276 | + | ||
277 | +Formatting 'TEST_DIR/PID-mid', fmt=qcow2 size=1048576 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
278 | + | ||
279 | +Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=2097152 backing_file=TEST_DIR/PID-mid cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
280 | + | ||
281 | +wrote 2097152/2097152 bytes at offset 0 | ||
282 | +2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
283 | + | ||
284 | +{"execute": "block-commit", "arguments": {"auto-dismiss": false, "base-node": "mid", "device": "top", "job-id": "job0"}} | ||
285 | +{"return": {}} | ||
286 | +{"execute": "job-complete", "arguments": {"id": "job0"}} | ||
287 | +{"return": {}} | ||
288 | +{"data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} | ||
289 | +{"data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} | ||
290 | +{"execute": "job-dismiss", "arguments": {"id": "job0"}} | ||
291 | +{"return": {}} | ||
292 | +image: TEST_IMG | ||
293 | +file format: IMGFMT | ||
294 | +virtual size: 2 MiB (2097152 bytes) | ||
295 | +cluster_size: 65536 | ||
296 | +backing file: TEST_DIR/PID-base | ||
297 | +Format specific information: | ||
298 | + compat: 1.1 | ||
299 | + lazy refcounts: false | ||
300 | + refcount bits: 16 | ||
301 | + corrupt: false | ||
302 | + | ||
303 | +read 1048576/1048576 bytes at offset 0 | ||
304 | +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
305 | + | ||
306 | +read 1048576/1048576 bytes at offset 1048576 | ||
307 | +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
308 | + | ||
309 | +== Resize tests == | ||
310 | +=== preallocation=off === | ||
311 | +Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=6442450944 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
312 | + | ||
313 | +Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=1073741824 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
314 | + | ||
315 | +wrote 65536/65536 bytes at offset 5368709120 | ||
316 | +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
317 | + | ||
318 | +Image resized. | ||
319 | + | ||
320 | +read 65536/65536 bytes at offset 5368709120 | ||
321 | +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
322 | + | ||
323 | +1 GiB (0x40000000) bytes not allocated at offset 0 bytes (0x0) | ||
324 | +7 GiB (0x1c0000000) bytes allocated at offset 1 GiB (0x40000000) | ||
325 | + | ||
326 | +[{ "start": 0, "length": 1073741824, "depth": 1, "zero": true, "data": false}, | ||
327 | +{ "start": 1073741824, "length": 7516192768, "depth": 0, "zero": true, "data": false}] | ||
328 | + | ||
329 | +=== preallocation=metadata === | ||
330 | +Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=34359738368 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
331 | + | ||
332 | +Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=32212254720 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
333 | + | ||
334 | +wrote 65536/65536 bytes at offset 33285996544 | ||
335 | +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
336 | + | ||
337 | +Image resized. | ||
338 | + | ||
339 | +read 65536/65536 bytes at offset 33285996544 | ||
340 | +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
341 | + | ||
342 | +30 GiB (0x780000000) bytes not allocated at offset 0 bytes (0x0) | ||
343 | +3 GiB (0xc0000000) bytes allocated at offset 30 GiB (0x780000000) | ||
344 | + | ||
345 | +[{ "start": 0, "length": 32212254720, "depth": 1, "zero": true, "data": false}, | ||
346 | +{ "start": 32212254720, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 327680}, | ||
347 | +{ "start": 32749125632, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 537264128}, | ||
348 | +{ "start": 33285996544, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 1074200576}, | ||
349 | +{ "start": 33822867456, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 1611137024}, | ||
350 | +{ "start": 34359738368, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 2148139008}, | ||
351 | +{ "start": 34896609280, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 2685075456}] | ||
352 | + | ||
353 | +=== preallocation=falloc === | ||
354 | +Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=10485760 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
355 | + | ||
356 | +Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=5242880 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
357 | + | ||
358 | +wrote 65536/65536 bytes at offset 9437184 | ||
359 | +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
360 | + | ||
361 | +Image resized. | ||
362 | + | ||
363 | +read 65536/65536 bytes at offset 9437184 | ||
364 | +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
365 | + | ||
366 | +5 MiB (0x500000) bytes not allocated at offset 0 bytes (0x0) | ||
367 | +10 MiB (0xa00000) bytes allocated at offset 5 MiB (0x500000) | ||
368 | + | ||
369 | +[{ "start": 0, "length": 5242880, "depth": 1, "zero": true, "data": false}, | ||
370 | +{ "start": 5242880, "length": 10485760, "depth": 0, "zero": true, "data": false, "offset": 327680}] | ||
371 | + | ||
372 | +=== preallocation=full === | ||
373 | +Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=16777216 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
374 | + | ||
375 | +Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=8388608 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
376 | + | ||
377 | +wrote 65536/65536 bytes at offset 11534336 | ||
378 | +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
379 | + | ||
380 | +Image resized. | ||
381 | + | ||
382 | +read 65536/65536 bytes at offset 11534336 | ||
383 | +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
384 | + | ||
385 | +8 MiB (0x800000) bytes not allocated at offset 0 bytes (0x0) | ||
386 | +4 MiB (0x400000) bytes allocated at offset 8 MiB (0x800000) | ||
387 | + | ||
388 | +[{ "start": 0, "length": 8388608, "depth": 1, "zero": true, "data": false}, | ||
389 | +{ "start": 8388608, "length": 4194304, "depth": 0, "zero": true, "data": false, "offset": 327680}] | ||
390 | + | ||
391 | +=== preallocation=off === | ||
392 | +Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=393216 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
393 | + | ||
394 | +Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=259072 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
395 | + | ||
396 | +wrote 65536/65536 bytes at offset 259072 | ||
397 | +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
398 | + | ||
399 | +Image resized. | ||
400 | + | ||
401 | +read 65536/65536 bytes at offset 259072 | ||
402 | +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
403 | + | ||
404 | +192 KiB (0x30000) bytes not allocated at offset 0 bytes (0x0) | ||
405 | +320 KiB (0x50000) bytes allocated at offset 192 KiB (0x30000) | ||
406 | + | ||
407 | +[{ "start": 0, "length": 196608, "depth": 1, "zero": true, "data": false}, | ||
408 | +{ "start": 196608, "length": 65536, "depth": 0, "zero": false, "data": true, "offset": 327680}, | ||
409 | +{ "start": 262144, "length": 262144, "depth": 0, "zero": true, "data": false}] | ||
410 | + | ||
411 | +=== preallocation=off === | ||
412 | +Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=409600 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
413 | + | ||
414 | +Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=262144 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
415 | + | ||
416 | +wrote 65536/65536 bytes at offset 344064 | ||
417 | +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
418 | + | ||
419 | +Image resized. | ||
420 | + | ||
421 | +read 65536/65536 bytes at offset 344064 | ||
422 | +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
423 | + | ||
424 | +256 KiB (0x40000) bytes not allocated at offset 0 bytes (0x0) | ||
425 | +256 KiB (0x40000) bytes allocated at offset 256 KiB (0x40000) | ||
426 | + | ||
427 | +[{ "start": 0, "length": 262144, "depth": 1, "zero": true, "data": false}, | ||
428 | +{ "start": 262144, "length": 262144, "depth": 0, "zero": true, "data": false}] | ||
429 | + | ||
430 | +=== preallocation=off === | ||
431 | +Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=524288 cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
432 | + | ||
433 | +Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=262144 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16 | ||
434 | + | ||
435 | +wrote 65536/65536 bytes at offset 446464 | ||
436 | +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
437 | + | ||
438 | +Image resized. | ||
439 | + | ||
440 | +read 65536/65536 bytes at offset 446464 | ||
441 | +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
442 | + | ||
443 | +256 KiB (0x40000) bytes not allocated at offset 0 bytes (0x0) | ||
444 | +244 KiB (0x3d000) bytes allocated at offset 256 KiB (0x40000) | ||
445 | + | ||
446 | +[{ "start": 0, "length": 262144, "depth": 1, "zero": true, "data": false}, | ||
447 | +{ "start": 262144, "length": 249856, "depth": 0, "zero": true, "data": false}] | ||
448 | + | ||
449 | diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group | ||
450 | index XXXXXXX..XXXXXXX 100644 | ||
451 | --- a/tests/qemu-iotests/group | ||
452 | +++ b/tests/qemu-iotests/group | ||
453 | @@ -XXX,XX +XXX,XX @@ | ||
454 | 270 rw backing quick | ||
455 | 272 rw | ||
456 | 273 backing quick | ||
457 | +274 rw backing | ||
458 | 277 rw quick | ||
459 | 279 rw backing quick | ||
460 | 280 rw migration quick | ||
461 | -- | 138 | -- |
462 | 2.25.3 | 139 | 2.35.1 |
463 | |||
464 | diff view generated by jsdifflib |
1 | From: Paolo Bonzini <pbonzini@redhat.com> | 1 | From: Thomas Huth <thuth@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Test 244 checks the expected behavior of qcow2 external data files | 3 | Instead of failing the iotests if GNU sed is not available (or skipping |
4 | with respect to zero and discarded clusters. Filesystems however | 4 | them completely in the check-block.sh script), it would be better to |
5 | are free to ignore discard requests, and this seems to be the | 5 | simply skip the bash-based tests that rely on GNU sed, so that the other |
6 | case for overlayfs. Relax the tests to skip checks on the | 6 | tests could still be run. Thus we now explicitely use "gsed" (either as |
7 | external data file for discarded areas, which implies not using | 7 | direct program or as a wrapper around "sed" if it's the GNU version) |
8 | qemu-img compare in the data_file_raw=on case. | 8 | in the spots that rely on the GNU sed behavior. Statements that use the |
9 | 9 | "-r" parameter of sed have been switched to use "-E" instead, since this | |
10 | This fixes docker tests on RHEL8. | 10 | switch is supported by all sed versions on our supported build hosts |
11 | 11 | (most also support "-r", but macOS' sed only supports "-E"). With all | |
12 | Cc: Kevin Wolf <kwolf@redhat.com> | 12 | these changes in place, we then can also remove the sed checks from the |
13 | Cc: qemu-block@nongnu.org | 13 | check-block.sh script, so that "make check-block" can now be run on |
14 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> | 14 | systems without GNU sed, too. |
15 | Message-Id: <20200409191006.24429-1-pbonzini@redhat.com> | 15 | |
16 | Signed-off-by: Thomas Huth <thuth@redhat.com> | ||
17 | Message-Id: <20220216125454.465041-1-thuth@redhat.com> | ||
18 | Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org> | ||
19 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
16 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 20 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
17 | --- | 21 | --- |
18 | tests/qemu-iotests/244 | 10 ++++++++-- | 22 | tests/check-block.sh | 12 ------ |
19 | tests/qemu-iotests/244.out | 9 ++++++--- | 23 | tests/qemu-iotests/271 | 2 +- |
20 | 2 files changed, 14 insertions(+), 5 deletions(-) | 24 | tests/qemu-iotests/common.filter | 65 ++++++++++++++++---------------- |
21 | 25 | tests/qemu-iotests/common.rc | 45 +++++++++++----------- | |
22 | diff --git a/tests/qemu-iotests/244 b/tests/qemu-iotests/244 | 26 | 4 files changed, 57 insertions(+), 67 deletions(-) |
27 | |||
28 | diff --git a/tests/check-block.sh b/tests/check-block.sh | ||
23 | index XXXXXXX..XXXXXXX 100755 | 29 | index XXXXXXX..XXXXXXX 100755 |
24 | --- a/tests/qemu-iotests/244 | 30 | --- a/tests/check-block.sh |
25 | +++ b/tests/qemu-iotests/244 | 31 | +++ b/tests/check-block.sh |
26 | @@ -XXX,XX +XXX,XX @@ $QEMU_IO -c 'read -P 0 0 1M' \ | 32 | @@ -XXX,XX +XXX,XX @@ if LANG=C bash --version | grep -q 'GNU bash, version [123]' ; then |
27 | echo | 33 | skip "bash version too old ==> Not running the qemu-iotests." |
28 | $QEMU_IO -c 'read -P 0 0 1M' \ | 34 | fi |
29 | -c 'read -P 0x11 1M 1M' \ | 35 | |
30 | - -c 'read -P 0 2M 2M' \ | 36 | -if ! (sed --version | grep 'GNU sed') > /dev/null 2>&1 ; then |
31 | -c 'read -P 0x11 4M 1M' \ | 37 | - if ! command -v gsed >/dev/null 2>&1; then |
32 | -c 'read -P 0 5M 1M' \ | 38 | - skip "GNU sed not available ==> Not running the qemu-iotests." |
33 | -f raw "$TEST_IMG.data" | | 39 | - fi |
34 | @@ -XXX,XX +XXX,XX @@ $QEMU_IO -c 'read -P 0 0 1M' \ | 40 | -else |
35 | -f $IMGFMT "$TEST_IMG" | | 41 | - # Double-check that we're not using BusyBox' sed which says |
36 | _filter_qemu_io | 42 | - # that "This is not GNU sed version 4.0" ... |
37 | 43 | - if sed --version | grep -q 'not GNU sed' ; then | |
38 | +# Discarded clusters are only marked as such in the qcow2 metadata, but | 44 | - skip "BusyBox sed not supported ==> Not running the qemu-iotests." |
39 | +# they can contain stale data in the external data file. Instead, zero | 45 | - fi |
40 | +# clusters must be zeroed in the external data file too. | 46 | -fi |
41 | echo | 47 | - |
42 | -$QEMU_IMG compare "$TEST_IMG" "$TEST_IMG.data" | 48 | cd tests/qemu-iotests |
43 | +$QEMU_IO -c 'read -P 0 0 1M' \ | 49 | |
44 | + -c 'read -P 0x11 1M 1M' \ | 50 | # QEMU_CHECK_BLOCK_AUTO is used to disable some unstable sub-tests |
45 | + -c 'read -P 0 3M 3M' \ | 51 | diff --git a/tests/qemu-iotests/271 b/tests/qemu-iotests/271 |
46 | + -f raw "$TEST_IMG".data | | 52 | index XXXXXXX..XXXXXXX 100755 |
47 | + _filter_qemu_io | 53 | --- a/tests/qemu-iotests/271 |
48 | 54 | +++ b/tests/qemu-iotests/271 | |
49 | echo -n "qcow2 file size after I/O: " | 55 | @@ -XXX,XX +XXX,XX @@ _make_test_img -o extended_l2=on 1M |
50 | du -b $TEST_IMG | cut -f1 | 56 | # Second and third writes in _concurrent_io() are independent and may finish in |
51 | diff --git a/tests/qemu-iotests/244.out b/tests/qemu-iotests/244.out | 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 | ||
52 | index XXXXXXX..XXXXXXX 100644 | 65 | index XXXXXXX..XXXXXXX 100644 |
53 | --- a/tests/qemu-iotests/244.out | 66 | --- a/tests/qemu-iotests/common.filter |
54 | +++ b/tests/qemu-iotests/244.out | 67 | +++ b/tests/qemu-iotests/common.filter |
55 | @@ -XXX,XX +XXX,XX @@ read 1048576/1048576 bytes at offset 0 | 68 | @@ -XXX,XX +XXX,XX @@ |
56 | 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | 69 | |
57 | read 1048576/1048576 bytes at offset 1048576 | 70 | _filter_date() |
58 | 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | 71 | { |
59 | -read 2097152/2097152 bytes at offset 2097152 | 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/' |
60 | -2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | 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/' |
61 | read 1048576/1048576 bytes at offset 4194304 | 74 | } |
62 | 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | 75 | |
63 | read 1048576/1048576 bytes at offset 5242880 | 76 | _filter_vmstate_size() |
64 | @@ -XXX,XX +XXX,XX @@ read 1048576/1048576 bytes at offset 1048576 | 77 | { |
65 | read 4194304/4194304 bytes at offset 2097152 | 78 | - $SED -r -e 's/[0-9. ]{5} [KMGT]iB/ SIZE/' \ |
66 | 4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | 79 | - -e 's/[0-9. ]{5} B/ SIZE/' |
67 | 80 | + sed -E -e 's/[0-9. ]{5} [KMGT]iB/ SIZE/' \ | |
68 | -Images are identical. | 81 | + -e 's/[0-9. ]{5} B/ SIZE/' |
69 | +read 1048576/1048576 bytes at offset 0 | 82 | } |
70 | +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | 83 | |
71 | +read 1048576/1048576 bytes at offset 1048576 | 84 | _filter_generated_node_ids() |
72 | +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | 85 | { |
73 | +read 3145728/3145728 bytes at offset 3145728 | 86 | - $SED -re 's/\#block[0-9]{3,}/NODE_NAME/' |
74 | +3 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | 87 | + sed -Ee 's/\#block[0-9]{3,}/NODE_NAME/' |
75 | qcow2 file size after I/O: 327680 | 88 | } |
76 | 89 | ||
77 | === bdrv_co_block_status test for file and offset=0 === | 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 | + | ||
314 | +if ! command -v gsed >/dev/null 2>&1; then | ||
315 | + if sed --version 2>&1 | grep -v 'not GNU sed' | grep 'GNU sed' > /dev/null; | ||
316 | + then | ||
317 | + gsed() | ||
318 | + { | ||
319 | + sed "$@" | ||
320 | + } | ||
321 | + else | ||
322 | + gsed() | ||
323 | + { | ||
324 | + _notrun "GNU sed not available" | ||
325 | + } | ||
326 | + fi | ||
327 | fi | ||
328 | |||
329 | dd() | ||
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 | ||
78 | -- | 356 | -- |
79 | 2.25.3 | 357 | 2.35.1 |
80 | 358 | ||
81 | 359 | diff view generated by jsdifflib |
1 | The raw format driver can simply forward the flag and let its bs->file | 1 | From: Hanna Reitz <hreitz@redhat.com> |
---|---|---|---|
2 | child take care of actually providing the zeros. | ||
3 | 2 | ||
4 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 3 | .bdrv_amend_clean() says block drivers can use it to clean up what was |
5 | Reviewed-by: Max Reitz <mreitz@redhat.com> | 4 | done in .bdrv_amend_pre_run(). Therefore, it should always be called |
6 | Reviewed-by: Eric Blake <eblake@redhat.com> | 5 | after .bdrv_amend_pre_run(), which means we need it to call it in the |
7 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 6 | JobDriver.free() callback, not in JobDriver.clean(). |
8 | Message-Id: <20200424125448.63318-6-kwolf@redhat.com> | 7 | |
8 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
9 | Message-Id: <20220304153729.711387-3-hreitz@redhat.com> | ||
9 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
10 | --- | 11 | --- |
11 | block/raw-format.c | 4 +++- | 12 | block/amend.c | 4 ++-- |
12 | 1 file changed, 3 insertions(+), 1 deletion(-) | 13 | 1 file changed, 2 insertions(+), 2 deletions(-) |
13 | 14 | ||
14 | diff --git a/block/raw-format.c b/block/raw-format.c | 15 | diff --git a/block/amend.c b/block/amend.c |
15 | index XXXXXXX..XXXXXXX 100644 | 16 | index XXXXXXX..XXXXXXX 100644 |
16 | --- a/block/raw-format.c | 17 | --- a/block/amend.c |
17 | +++ b/block/raw-format.c | 18 | +++ b/block/amend.c |
18 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset, | 19 | @@ -XXX,XX +XXX,XX @@ static int blockdev_amend_pre_run(BlockdevAmendJob *s, Error **errp) |
19 | 20 | return 0; | |
20 | s->size = offset; | ||
21 | offset += s->offset; | ||
22 | - return bdrv_co_truncate(bs->file, offset, exact, prealloc, 0, errp); | ||
23 | + return bdrv_co_truncate(bs->file, offset, exact, prealloc, flags, errp); | ||
24 | } | 21 | } |
25 | 22 | ||
26 | static void raw_eject(BlockDriverState *bs, bool eject_flag) | 23 | -static void blockdev_amend_clean(Job *job) |
27 | @@ -XXX,XX +XXX,XX @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags, | 24 | +static void blockdev_amend_free(Job *job) |
28 | bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED | | 25 | { |
29 | ((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK) & | 26 | BlockdevAmendJob *s = container_of(job, BlockdevAmendJob, common); |
30 | bs->file->bs->supported_zero_flags); | 27 | |
31 | + bs->supported_truncate_flags = bs->file->bs->supported_truncate_flags & | 28 | @@ -XXX,XX +XXX,XX @@ static const JobDriver blockdev_amend_job_driver = { |
32 | + BDRV_REQ_ZERO_WRITE; | 29 | .instance_size = sizeof(BlockdevAmendJob), |
33 | 30 | .job_type = JOB_TYPE_AMEND, | |
34 | if (bs->probed && !bdrv_is_read_only(bs)) { | 31 | .run = blockdev_amend_run, |
35 | bdrv_refresh_filename(bs->file->bs); | 32 | - .clean = blockdev_amend_clean, |
33 | + .free = blockdev_amend_free, | ||
34 | }; | ||
35 | |||
36 | void qmp_x_blockdev_amend(const char *job_id, | ||
36 | -- | 37 | -- |
37 | 2.25.3 | 38 | 2.35.1 |
38 | |||
39 | diff view generated by jsdifflib |
1 | From: Alberto Garcia <berto@igalia.com> | 1 | From: Hanna Reitz <hreitz@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Backing files and raw external data files are mutually exclusive. | 3 | Otherwise, the BDS might be freed while the job is running, which would |
4 | The documentation of the raw external data bit (in autoclear_features) | 4 | cause a use-after-free. |
5 | already indicates that, but we should also mention it on the other | ||
6 | side. | ||
7 | 5 | ||
8 | Suggested-by: Eric Blake <eblake@redhat.com> | 6 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> |
9 | Signed-off-by: Alberto Garcia <berto@igalia.com> | 7 | Message-Id: <20220304153729.711387-5-hreitz@redhat.com> |
10 | Message-Id: <20200410121816.8334-1-berto@igalia.com> | ||
11 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 8 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
13 | --- | 9 | --- |
14 | docs/interop/qcow2.txt | 3 +++ | 10 | block/amend.c | 3 +++ |
15 | 1 file changed, 3 insertions(+) | 11 | 1 file changed, 3 insertions(+) |
16 | 12 | ||
17 | diff --git a/docs/interop/qcow2.txt b/docs/interop/qcow2.txt | 13 | diff --git a/block/amend.c b/block/amend.c |
18 | index XXXXXXX..XXXXXXX 100644 | 14 | index XXXXXXX..XXXXXXX 100644 |
19 | --- a/docs/interop/qcow2.txt | 15 | --- a/block/amend.c |
20 | +++ b/docs/interop/qcow2.txt | 16 | +++ b/block/amend.c |
21 | @@ -XXX,XX +XXX,XX @@ The first cluster of a qcow2 image contains the file header: | 17 | @@ -XXX,XX +XXX,XX @@ static void blockdev_amend_free(Job *job) |
22 | is stored (NB: The string is not null terminated). 0 if the | 18 | if (s->bs->drv->bdrv_amend_clean) { |
23 | image doesn't have a backing file. | 19 | s->bs->drv->bdrv_amend_clean(s->bs); |
24 | 20 | } | |
25 | + Note: backing files are incompatible with raw external data | ||
26 | + files (auto-clear feature bit 1). | ||
27 | + | 21 | + |
28 | 16 - 19: backing_file_size | 22 | + bdrv_unref(s->bs); |
29 | Length of the backing file name in bytes. Must not be | 23 | } |
30 | longer than 1023 bytes. Undefined if the image doesn't have | 24 | |
25 | static const JobDriver blockdev_amend_job_driver = { | ||
26 | @@ -XXX,XX +XXX,XX @@ void qmp_x_blockdev_amend(const char *job_id, | ||
27 | return; | ||
28 | } | ||
29 | |||
30 | + bdrv_ref(bs); | ||
31 | s->bs = bs, | ||
32 | s->opts = QAPI_CLONE(BlockdevAmendOptions, options), | ||
33 | s->force = has_force ? force : false; | ||
31 | -- | 34 | -- |
32 | 2.25.3 | 35 | 2.35.1 |
33 | |||
34 | diff view generated by jsdifflib |