1 | The following changes since commit 013a18edbbc59cdad019100c7d03c0494642b74c: | 1 | The following changes since commit f1d33f55c47dfdaf8daacd618588ad3ae4c452d1: |
---|---|---|---|
2 | 2 | ||
3 | Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20200514' into staging (2020-05-14 16:17:55 +0100) | 3 | Merge tag 'pull-testing-gdbstub-plugins-gitdm-061022-3' of https://github.com/stsquad/qemu into staging (2022-10-06 07:11:56 -0400) |
4 | 4 | ||
5 | are available in the Git repository at: | 5 | are available in the Git repository at: |
6 | 6 | ||
7 | git://repo.or.cz/qemu/kevin.git tags/for-upstream | 7 | git://repo.or.cz/qemu/kevin.git tags/for-upstream |
8 | 8 | ||
9 | for you to fetch changes up to 7d8f21a650e562270f5ed5341134c9c2c39dc5e8: | 9 | for you to fetch changes up to a7ca2eb488ff149c898f43abe103f8bd8e3ca3c4: |
10 | 10 | ||
11 | iotests/030: Reduce run time by unthrottling job earlier (2020-05-15 14:12:34 +0200) | 11 | file-posix: Remove unused s->discard_zeroes (2022-10-07 12:11:41 +0200) |
12 | 12 | ||
13 | ---------------------------------------------------------------- | 13 | ---------------------------------------------------------------- |
14 | Block layer patches: | 14 | Block layer patches |
15 | 15 | ||
16 | - Introduce real BdrvChildRole | 16 | - job: replace AioContext lock with job_mutex |
17 | - blk/bdrv_make_empty() functions instead of calling callbacks directly | 17 | - Fixes to make coroutine_fn annotations more accurate |
18 | - mirror: Make sure that source and target size match | 18 | - QAPI schema: Fix incorrect example |
19 | - block-copy: Fix uninitialized variable | 19 | - Code cleanup |
20 | - block/replication: Avoid cancelling the job twice | ||
21 | - ahci: Log lost IRQs | ||
22 | - iotests: Run pylint and mypy in a testcase | ||
23 | - iotests: log messages from notrun() | ||
24 | 20 | ||
25 | ---------------------------------------------------------------- | 21 | ---------------------------------------------------------------- |
26 | John Snow (1): | 22 | Alberto Faria (1): |
27 | iotests: log messages from notrun() | 23 | coroutine: Drop coroutine_fn annotation from qemu_coroutine_self() |
28 | 24 | ||
29 | Kevin Wolf (8): | 25 | Emanuele Giuseppe Esposito (20): |
30 | iotests/109: Don't mirror with mismatched size | 26 | job.c: make job_mutex and job_lock/unlock() public |
31 | iotests/229: Use blkdebug to inject an error | 27 | job.h: categorize fields in struct Job |
32 | mirror: Make sure that source and target size match | 28 | job.c: API functions not used outside should be static |
33 | iotests: Mirror with different source/target size | 29 | aio-wait.h: introduce AIO_WAIT_WHILE_UNLOCKED |
34 | iotests: Fix incomplete type declarations | 30 | job.c: add job_lock/unlock while keeping job.h intact |
35 | iotests: Run pylint and mypy in a testcase | 31 | job: move and update comments from blockjob.c |
36 | replication: Avoid blk_make_empty() on read-only child | 32 | blockjob: introduce block_job _locked() APIs |
37 | iotests/030: Reduce run time by unthrottling job earlier | 33 | jobs: add job lock in find_* functions |
34 | jobs: use job locks also in the unit tests | ||
35 | block/mirror.c: use of job helpers in drivers | ||
36 | jobs: group together API calls under the same job lock | ||
37 | jobs: protect job.aio_context with BQL and job_mutex | ||
38 | blockjob.h: categorize fields in struct BlockJob | ||
39 | blockjob: rename notifier callbacks as _locked | ||
40 | blockjob: protect iostatus field in BlockJob struct | ||
41 | job.h: categorize JobDriver callbacks that need the AioContext lock | ||
42 | job.c: enable job lock/unlock and remove Aiocontext locks | ||
43 | block_job_query: remove atomic read | ||
44 | blockjob: remove unused functions | ||
45 | job: remove unused functions | ||
38 | 46 | ||
39 | Lukas Straub (1): | 47 | Kevin Wolf (2): |
40 | block/replication.c: Avoid cancelling the job twice | 48 | quorum: Remove unnecessary forward declaration |
49 | file-posix: Remove unused s->discard_zeroes | ||
41 | 50 | ||
42 | Max Reitz (38): | 51 | Marc-André Lureau (3): |
43 | block: Add bdrv_make_empty() | 52 | 9p: add missing coroutine_fn annotations |
44 | block: Add blk_make_empty() | 53 | migration: add missing coroutine_fn annotations |
45 | block: Use blk_make_empty() after commits | 54 | test-coroutine: add missing coroutine_fn annotations |
46 | block: Use bdrv_make_empty() where possible | ||
47 | block: Mark commit, mirror, blkreplay as filters | ||
48 | block: Add BlockDriver.is_format | ||
49 | block: Rename BdrvChildRole to BdrvChildClass | ||
50 | block: Add BdrvChildRole and BdrvChildRoleBits | ||
51 | block: Add BdrvChildRole to BdrvChild | ||
52 | block: Pass BdrvChildRole to bdrv_child_perm() | ||
53 | block: Pass BdrvChildRole to .inherit_options() | ||
54 | block: Pass parent_is_format to .inherit_options() | ||
55 | block: Rename bdrv_inherited_options() | ||
56 | block: Add generic bdrv_inherited_options() | ||
57 | block: Use bdrv_inherited_options() | ||
58 | block: Unify bdrv_child_cb_attach() | ||
59 | block: Unify bdrv_child_cb_detach() | ||
60 | block: Add child_of_bds | ||
61 | block: Distinguish paths in *_format_default_perms | ||
62 | block: Pull out bdrv_default_perms_for_cow() | ||
63 | block: Pull out bdrv_default_perms_for_storage() | ||
64 | block: Relax *perms_for_storage for data children | ||
65 | block: Add bdrv_default_perms() | ||
66 | raw-format: Split raw_read_options() | ||
67 | block: Switch child_format users to child_of_bds | ||
68 | block: Drop child_format | ||
69 | block: Make backing files child_of_bds children | ||
70 | block: Drop child_backing | ||
71 | block: Make format drivers use child_of_bds | ||
72 | block: Make filter drivers use child_of_bds | ||
73 | block: Use child_of_bds in remaining places | ||
74 | tests: Use child_of_bds instead of child_file | ||
75 | block: Use bdrv_default_perms() | ||
76 | block: Make bdrv_filter_default_perms() static | ||
77 | block: Drop bdrv_format_default_perms() | ||
78 | block: Drop child_file | ||
79 | block: Pass BdrvChildRole in remaining cases | ||
80 | block: Drop @child_class from bdrv_child_perm() | ||
81 | 55 | ||
82 | Philippe Mathieu-Daudé (3): | 56 | Markus Armbruster (1): |
83 | block/block-copy: Fix uninitialized variable in block_copy_task_entry | 57 | Revert "qapi: fix examples of blockdev-add with qcow2" |
84 | block/block-copy: Simplify block_copy_do_copy() | ||
85 | hw/ide/ahci: Log lost IRQs | ||
86 | 58 | ||
87 | include/block/block.h | 65 ++++- | 59 | Paolo Bonzini (23): |
88 | include/block/block_int.h | 57 ++-- | 60 | block/nvme: separate nvme_get_free_req cases for coroutine/non-coroutine context |
89 | include/sysemu/block-backend.h | 2 + | 61 | block: add missing coroutine_fn annotations |
90 | block.c | 601 ++++++++++++++++++++++++--------------- | 62 | qcow2: remove incorrect coroutine_fn annotations |
91 | block/backup-top.c | 11 +- | 63 | nbd: remove incorrect coroutine_fn annotations |
92 | block/blkdebug.c | 10 +- | 64 | coroutine: remove incorrect coroutine_fn annotations |
93 | block/blklogwrites.c | 16 +- | 65 | blkverify: add missing coroutine_fn annotations |
94 | block/blkreplay.c | 8 +- | 66 | file-posix: add missing coroutine_fn annotations |
95 | block/blkverify.c | 10 +- | 67 | iscsi: add missing coroutine_fn annotations |
96 | block/block-backend.c | 30 +- | 68 | nbd: add missing coroutine_fn annotations |
97 | block/block-copy.c | 14 +- | 69 | nfs: add missing coroutine_fn annotations |
98 | block/bochs.c | 7 +- | 70 | nvme: add missing coroutine_fn annotations |
99 | block/cloop.c | 7 +- | 71 | parallels: add missing coroutine_fn annotations |
100 | block/commit.c | 20 +- | 72 | qcow2: add missing coroutine_fn annotations |
101 | block/copy-on-read.c | 7 +- | 73 | copy-before-write: add missing coroutine_fn annotations |
102 | block/crypto.c | 8 +- | 74 | curl: add missing coroutine_fn annotations |
103 | block/dmg.c | 7 +- | 75 | qed: add missing coroutine_fn annotations |
104 | block/filter-compress.c | 7 +- | 76 | quorum: add missing coroutine_fn annotations |
77 | throttle: add missing coroutine_fn annotations | ||
78 | vmdk: add missing coroutine_fn annotations | ||
79 | job: add missing coroutine_fn annotations | ||
80 | coroutine-lock: add missing coroutine_fn annotations | ||
81 | raw-format: add missing coroutine_fn annotations | ||
82 | job: detect change of aiocontext within job coroutine | ||
83 | |||
84 | qapi/block-core.json | 10 +- | ||
85 | block/qcow2.h | 19 +- | ||
86 | hw/9pfs/9p.h | 9 +- | ||
87 | include/block/aio-wait.h | 17 +- | ||
88 | include/block/blockjob.h | 59 +++- | ||
89 | include/block/nbd.h | 2 +- | ||
90 | include/qemu/coroutine.h | 4 +- | ||
91 | include/qemu/job.h | 306 +++++++++++++----- | ||
92 | block.c | 24 +- | ||
93 | block/blkverify.c | 2 +- | ||
94 | block/block-backend.c | 10 +- | ||
95 | block/copy-before-write.c | 9 +- | ||
96 | block/curl.c | 2 +- | ||
97 | block/file-posix.c | 11 +- | ||
105 | block/io.c | 22 +- | 98 | block/io.c | 22 +- |
106 | block/mirror.c | 25 +- | 99 | block/iscsi.c | 3 +- |
107 | block/parallels.c | 7 +- | 100 | block/mirror.c | 19 +- |
108 | block/qcow.c | 7 +- | 101 | block/nbd.c | 11 +- |
109 | block/qcow2.c | 20 +- | 102 | block/nfs.c | 2 +- |
110 | block/qed.c | 7 +- | 103 | block/nvme.c | 54 ++-- |
111 | block/quorum.c | 8 +- | 104 | block/parallels.c | 5 +- |
112 | block/raw-format.c | 128 +++++---- | 105 | block/qcow2-cluster.c | 21 +- |
113 | block/replication.c | 23 +- | 106 | block/qcow2-refcount.c | 6 +- |
114 | block/throttle.c | 7 +- | 107 | block/qcow2.c | 5 +- |
115 | block/vdi.c | 7 +- | 108 | block/qed.c | 4 +- |
116 | block/vhdx.c | 7 +- | 109 | block/quorum.c | 38 +-- |
117 | block/vmdk.c | 23 +- | 110 | block/raw-format.c | 3 +- |
118 | block/vpc.c | 7 +- | 111 | block/replication.c | 3 + |
119 | block/vvfat.c | 17 +- | 112 | block/throttle.c | 2 +- |
120 | blockjob.c | 7 +- | 113 | block/vmdk.c | 22 +- |
121 | hw/ide/ahci.c | 1 + | 114 | blockdev.c | 129 ++++---- |
122 | qemu-img.c | 19 +- | 115 | blockjob.c | 132 ++++---- |
123 | tests/test-bdrv-drain.c | 72 +++-- | 116 | job-qmp.c | 92 +++--- |
124 | tests/test-bdrv-graph-mod.c | 10 +- | 117 | job.c | 674 +++++++++++++++++++++++++-------------- |
125 | tests/test-block-iothread.c | 17 +- | 118 | migration/migration.c | 3 +- |
126 | tests/qemu-iotests/iotests.py | 19 +- | 119 | monitor/qmp-cmds.c | 7 +- |
127 | tests/qemu-iotests/030 | 6 +- | 120 | qemu-img.c | 17 +- |
128 | tests/qemu-iotests/041 | 45 +++ | 121 | tests/unit/test-bdrv-drain.c | 80 +++-- |
129 | tests/qemu-iotests/041.out | 4 +- | 122 | tests/unit/test-block-iothread.c | 8 +- |
130 | tests/qemu-iotests/098.out | 8 +- | 123 | tests/unit/test-blockjob-txn.c | 24 +- |
131 | tests/qemu-iotests/109 | 10 +- | 124 | tests/unit/test-blockjob.c | 136 ++++---- |
132 | tests/qemu-iotests/109.out | 74 ++--- | 125 | tests/unit/test-coroutine.c | 2 +- |
133 | tests/qemu-iotests/229 | 15 +- | 126 | util/qemu-coroutine-lock.c | 14 +- |
134 | tests/qemu-iotests/229.out | 6 +- | 127 | util/qemu-coroutine.c | 2 +- |
135 | tests/qemu-iotests/297 | 44 +++ | 128 | 44 files changed, 1237 insertions(+), 787 deletions(-) |
136 | tests/qemu-iotests/297.out | 3 + | ||
137 | tests/qemu-iotests/common.filter | 5 + | ||
138 | tests/qemu-iotests/group | 1 + | ||
139 | 52 files changed, 995 insertions(+), 573 deletions(-) | ||
140 | create mode 100755 tests/qemu-iotests/297 | ||
141 | create mode 100644 tests/qemu-iotests/297.out | ||
142 | 129 | ||
143 | 130 | diff view generated by jsdifflib |
1 | From: John Snow <jsnow@redhat.com> | 1 | From: Markus Armbruster <armbru@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Shift the logging initialization up to occur prior to validation checks, | 3 | This reverts commit b6522938327141235b97ab38e40c6c4512587373. |
4 | so that notrun() messages still get printed to console. | ||
5 | 4 | ||
6 | (Also, remove the "debugging messages active" message, because we don't | 5 | Kevin Wolf NAKed this patch, because: |
7 | need to see that hundreds of times per iotest suite run.) | ||
8 | 6 | ||
9 | Signed-off-by: John Snow <jsnow@redhat.com> | 7 | 'file' is a required member (defined in BlockdevOptionsGenericFormat), |
10 | Message-Id: <20200514201614.19941-2-jsnow@redhat.com> | 8 | removing it makes the example invalid. 'data-file' is only an additional |
9 | optional member to be used for external data files (i.e. when the guest | ||
10 | data is kept separate from the metadata in the .qcow2 file). | ||
11 | |||
12 | However, it had already been merged then. Revert. | ||
13 | |||
14 | Signed-off-by: Markus Armbruster <armbru@redhat.com> | ||
15 | Message-Id: <20220930171908.846769-1-armbru@redhat.com> | ||
16 | Reviewed-by: Victor Toso <victortoso@redhat.com> | ||
17 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 18 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
12 | --- | 19 | --- |
13 | tests/qemu-iotests/iotests.py | 11 +++++------ | 20 | qapi/block-core.json | 10 +++++----- |
14 | 1 file changed, 5 insertions(+), 6 deletions(-) | 21 | 1 file changed, 5 insertions(+), 5 deletions(-) |
15 | 22 | ||
16 | diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py | 23 | diff --git a/qapi/block-core.json b/qapi/block-core.json |
17 | index XXXXXXX..XXXXXXX 100644 | 24 | index XXXXXXX..XXXXXXX 100644 |
18 | --- a/tests/qemu-iotests/iotests.py | 25 | --- a/qapi/block-core.json |
19 | +++ b/tests/qemu-iotests/iotests.py | 26 | +++ b/qapi/block-core.json |
20 | @@ -XXX,XX +XXX,XX @@ def execute_setup_common(supported_fmts: Sequence[str] = (), | 27 | @@ -XXX,XX +XXX,XX @@ |
21 | sys.stderr.write('Please run this test via the "check" script\n') | 28 | # -> { "execute": "blockdev-add", |
22 | sys.exit(os.EX_USAGE) | 29 | # "arguments": { "driver": "qcow2", |
23 | 30 | # "node-name": "node1534", | |
24 | + debug = '-d' in sys.argv | 31 | -# "data-file": { "driver": "file", |
25 | + if debug: | 32 | -# "filename": "hd1.qcow2" }, |
26 | + sys.argv.remove('-d') | 33 | +# "file": { "driver": "file", |
27 | + logging.basicConfig(level=(logging.DEBUG if debug else logging.WARN)) | 34 | +# "filename": "hd1.qcow2" }, |
28 | + | 35 | # "backing": null } } |
29 | _verify_image_format(supported_fmts, unsupported_fmts) | 36 | # |
30 | _verify_protocol(supported_protocols, unsupported_protocols) | 37 | # <- { "return": {} } |
31 | _verify_platform(supported=supported_platforms) | 38 | @@ -XXX,XX +XXX,XX @@ |
32 | _verify_cache_mode(supported_cache_modes) | 39 | # "arguments": { |
33 | _verify_aio_mode(supported_aio_modes) | 40 | # "driver": "qcow2", |
34 | 41 | # "node-name": "test1", | |
35 | - debug = '-d' in sys.argv | 42 | -# "data-file": { |
36 | - if debug: | 43 | +# "file": { |
37 | - sys.argv.remove('-d') | 44 | # "driver": "file", |
38 | - logging.basicConfig(level=(logging.DEBUG if debug else logging.WARN)) | 45 | # "filename": "test.qcow2" |
39 | - logger.debug("iotests debugging messages active") | 46 | # } |
40 | - | 47 | @@ -XXX,XX +XXX,XX @@ |
41 | return debug | 48 | # "cache": { |
42 | 49 | # "direct": true | |
43 | def execute_test(*args, test_function=None, **kwargs): | 50 | # }, |
51 | -# "data-file": { | ||
52 | +# "file": { | ||
53 | # "driver": "file", | ||
54 | # "filename": "/tmp/test.qcow2" | ||
55 | # }, | ||
56 | @@ -XXX,XX +XXX,XX @@ | ||
57 | # "arguments": { | ||
58 | # "driver": "qcow2", | ||
59 | # "node-name": "node0", | ||
60 | -# "data-file": { | ||
61 | +# "file": { | ||
62 | # "driver": "file", | ||
63 | # "filename": "test.qcow2" | ||
64 | # } | ||
44 | -- | 65 | -- |
45 | 2.25.4 | 66 | 2.37.3 |
46 | |||
47 | diff view generated by jsdifflib |
1 | From: Max Reitz <mreitz@redhat.com> | 1 | From: Alberto Faria <afaria@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | These calls have no real use for the child role yet, but it will not | 3 | qemu_coroutine_self() can be called from outside coroutine context, |
4 | harm to give one. | 4 | returning the leader coroutine, and several such invocations currently |
5 | exist (mostly in qcow2 tracing calls). | ||
5 | 6 | ||
6 | Notably, the bdrv_root_attach_child() call in blockjob.c is left | 7 | Signed-off-by: Alberto Faria <afaria@redhat.com> |
7 | unmodified because there is not much the generic BlockJob object wants | 8 | Message-Id: <20221005175209.975797-1-afaria@redhat.com> |
8 | from its children. | 9 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> |
9 | 10 | Reviewed-by: Paolo Bonzini <pbonzini@redhat.com> | |
10 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
11 | Message-Id: <20200513110544.176672-34-mreitz@redhat.com> | ||
12 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
13 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
14 | --- | 12 | --- |
15 | block/block-backend.c | 11 +++++++---- | 13 | include/qemu/coroutine.h | 2 +- |
16 | block/vvfat.c | 4 +++- | 14 | 1 file changed, 1 insertion(+), 1 deletion(-) |
17 | 2 files changed, 10 insertions(+), 5 deletions(-) | ||
18 | 15 | ||
19 | diff --git a/block/block-backend.c b/block/block-backend.c | 16 | diff --git a/include/qemu/coroutine.h b/include/qemu/coroutine.h |
20 | index XXXXXXX..XXXXXXX 100644 | 17 | index XXXXXXX..XXXXXXX 100644 |
21 | --- a/block/block-backend.c | 18 | --- a/include/qemu/coroutine.h |
22 | +++ b/block/block-backend.c | 19 | +++ b/include/qemu/coroutine.h |
23 | @@ -XXX,XX +XXX,XX @@ BlockBackend *blk_new_open(const char *filename, const char *reference, | 20 | @@ -XXX,XX +XXX,XX @@ AioContext *coroutine_fn qemu_coroutine_get_aio_context(Coroutine *co); |
24 | return NULL; | 21 | /** |
25 | } | 22 | * Get the currently executing coroutine |
26 | 23 | */ | |
27 | - blk->root = bdrv_root_attach_child(bs, "root", &child_root, 0, blk->ctx, | 24 | -Coroutine *coroutine_fn qemu_coroutine_self(void); |
28 | - perm, BLK_PERM_ALL, blk, errp); | 25 | +Coroutine *qemu_coroutine_self(void); |
29 | + blk->root = bdrv_root_attach_child(bs, "root", &child_root, | 26 | |
30 | + BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, | 27 | /** |
31 | + blk->ctx, perm, BLK_PERM_ALL, blk, errp); | 28 | * Return whether or not currently inside a coroutine |
32 | if (!blk->root) { | ||
33 | blk_unref(blk); | ||
34 | return NULL; | ||
35 | @@ -XXX,XX +XXX,XX @@ int blk_insert_bs(BlockBackend *blk, BlockDriverState *bs, Error **errp) | ||
36 | { | ||
37 | ThrottleGroupMember *tgm = &blk->public.throttle_group_member; | ||
38 | bdrv_ref(bs); | ||
39 | - blk->root = bdrv_root_attach_child(bs, "root", &child_root, 0, blk->ctx, | ||
40 | - blk->perm, blk->shared_perm, blk, errp); | ||
41 | + blk->root = bdrv_root_attach_child(bs, "root", &child_root, | ||
42 | + BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, | ||
43 | + blk->ctx, blk->perm, blk->shared_perm, | ||
44 | + blk, errp); | ||
45 | if (blk->root == NULL) { | ||
46 | return -EPERM; | ||
47 | } | ||
48 | diff --git a/block/vvfat.c b/block/vvfat.c | ||
49 | index XXXXXXX..XXXXXXX 100644 | ||
50 | --- a/block/vvfat.c | ||
51 | +++ b/block/vvfat.c | ||
52 | @@ -XXX,XX +XXX,XX @@ static int enable_write_target(BlockDriverState *bs, Error **errp) | ||
53 | options = qdict_new(); | ||
54 | qdict_put_str(options, "write-target.driver", "qcow"); | ||
55 | s->qcow = bdrv_open_child(s->qcow_filename, options, "write-target", bs, | ||
56 | - &child_vvfat_qcow, 0, false, errp); | ||
57 | + &child_vvfat_qcow, | ||
58 | + BDRV_CHILD_DATA | BDRV_CHILD_METADATA, | ||
59 | + false, errp); | ||
60 | qobject_unref(options); | ||
61 | if (!s->qcow) { | ||
62 | ret = -EINVAL; | ||
63 | -- | 29 | -- |
64 | 2.25.4 | 30 | 2.37.3 |
65 | |||
66 | diff view generated by jsdifflib |
1 | From: Max Reitz <mreitz@redhat.com> | 1 | From: Paolo Bonzini <pbonzini@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Replace child_file by child_of_bds in all remaining places (excluding | 3 | nvme_get_free_req has very difference semantics when called in |
4 | tests). | 4 | coroutine context (where it waits) and in non-coroutine context |
5 | (where it doesn't). Split the two cases to make it clear what | ||
6 | is being requested. | ||
5 | 7 | ||
6 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 8 | Cc: qemu-block@nongnu.org |
7 | Message-Id: <20200513110544.176672-28-mreitz@redhat.com> | 9 | Reviewed-by: Alberto Faria <afaria@redhat.com> |
8 | Reviewed-by: Eric Blake <eblake@redhat.com> | 10 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
11 | Message-Id: <20220922084924.201610-2-pbonzini@redhat.com> | ||
12 | [kwolf: Fixed up coding style] | ||
13 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
9 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 14 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
10 | --- | 15 | --- |
11 | block.c | 3 ++- | 16 | block/nvme.c | 48 ++++++++++++++++++++++++++++-------------------- |
12 | block/backup-top.c | 4 ++-- | 17 | 1 file changed, 28 insertions(+), 20 deletions(-) |
13 | block/blklogwrites.c | 4 ++-- | ||
14 | block/raw-format.c | 15 +++++++++++++-- | ||
15 | 4 files changed, 19 insertions(+), 7 deletions(-) | ||
16 | 18 | ||
17 | diff --git a/block.c b/block.c | 19 | diff --git a/block/nvme.c b/block/nvme.c |
18 | index XXXXXXX..XXXXXXX 100644 | 20 | index XXXXXXX..XXXXXXX 100644 |
19 | --- a/block.c | 21 | --- a/block/nvme.c |
20 | +++ b/block.c | 22 | +++ b/block/nvme.c |
21 | @@ -XXX,XX +XXX,XX @@ static BlockDriverState *bdrv_open_inherit(const char *filename, | 23 | @@ -XXX,XX +XXX,XX @@ static void nvme_kick(NVMeQueuePair *q) |
22 | BlockDriverState *file_bs; | 24 | q->need_kick = 0; |
23 | 25 | } | |
24 | file_bs = bdrv_open_child_bs(filename, options, "file", bs, | 26 | |
25 | - &child_file, 0, true, &local_err); | 27 | -/* Find a free request element if any, otherwise: |
26 | + &child_of_bds, BDRV_CHILD_IMAGE, | 28 | - * a) if in coroutine context, try to wait for one to become available; |
27 | + true, &local_err); | 29 | - * b) if not in coroutine, return NULL; |
28 | if (local_err) { | 30 | - */ |
29 | goto fail; | 31 | -static NVMeRequest *nvme_get_free_req(NVMeQueuePair *q) |
30 | } | 32 | +static NVMeRequest *nvme_get_free_req_nofail_locked(NVMeQueuePair *q) |
31 | diff --git a/block/backup-top.c b/block/backup-top.c | 33 | { |
32 | index XXXXXXX..XXXXXXX 100644 | 34 | NVMeRequest *req; |
33 | --- a/block/backup-top.c | 35 | |
34 | +++ b/block/backup-top.c | 36 | - qemu_mutex_lock(&q->lock); |
35 | @@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_backup_top_append(BlockDriverState *source, | 37 | - |
36 | source->supported_zero_flags); | 38 | - while (q->free_req_head == -1) { |
37 | 39 | - if (qemu_in_coroutine()) { | |
38 | bdrv_ref(target); | 40 | - trace_nvme_free_req_queue_wait(q->s, q->index); |
39 | - state->target = bdrv_attach_child(top, target, "target", &child_file, 0, | 41 | - qemu_co_queue_wait(&q->free_req_queue, &q->lock); |
40 | - errp); | 42 | - } else { |
41 | + state->target = bdrv_attach_child(top, target, "target", &child_of_bds, | 43 | - qemu_mutex_unlock(&q->lock); |
42 | + BDRV_CHILD_DATA, errp); | 44 | - return NULL; |
43 | if (!state->target) { | 45 | - } |
44 | bdrv_unref(target); | 46 | - } |
45 | bdrv_unref(top); | 47 | - |
46 | diff --git a/block/blklogwrites.c b/block/blklogwrites.c | 48 | req = &q->reqs[q->free_req_head]; |
47 | index XXXXXXX..XXXXXXX 100644 | 49 | q->free_req_head = req->free_req_next; |
48 | --- a/block/blklogwrites.c | 50 | req->free_req_next = -1; |
49 | +++ b/block/blklogwrites.c | 51 | - |
50 | @@ -XXX,XX +XXX,XX @@ static int blk_log_writes_open(BlockDriverState *bs, QDict *options, int flags, | 52 | - qemu_mutex_unlock(&q->lock); |
51 | } | 53 | return req; |
52 | 54 | } | |
53 | /* Open the log file */ | 55 | |
54 | - s->log_file = bdrv_open_child(NULL, options, "log", bs, &child_file, 0, | 56 | +/* Return a free request element if any, otherwise return NULL. */ |
55 | - false, &local_err); | 57 | +static NVMeRequest *nvme_get_free_req_nowait(NVMeQueuePair *q) |
56 | + s->log_file = bdrv_open_child(NULL, options, "log", bs, &child_of_bds, | 58 | +{ |
57 | + BDRV_CHILD_METADATA, false, &local_err); | 59 | + QEMU_LOCK_GUARD(&q->lock); |
58 | if (local_err) { | 60 | + if (q->free_req_head == -1) { |
59 | ret = -EINVAL; | 61 | + return NULL; |
60 | error_propagate(errp, local_err); | 62 | + } |
61 | diff --git a/block/raw-format.c b/block/raw-format.c | 63 | + return nvme_get_free_req_nofail_locked(q); |
62 | index XXXXXXX..XXXXXXX 100644 | 64 | +} |
63 | --- a/block/raw-format.c | 65 | + |
64 | +++ b/block/raw-format.c | 66 | +/* |
65 | @@ -XXX,XX +XXX,XX @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags, | 67 | + * Wait for a free request to become available if necessary, then |
66 | BDRVRawState *s = bs->opaque; | 68 | + * return it. |
67 | bool has_size; | 69 | + */ |
68 | uint64_t offset, size; | 70 | +static coroutine_fn NVMeRequest *nvme_get_free_req(NVMeQueuePair *q) |
69 | + BdrvChildRole file_role; | 71 | +{ |
70 | int ret; | 72 | + QEMU_LOCK_GUARD(&q->lock); |
71 | 73 | + | |
72 | ret = raw_read_options(options, &offset, &has_size, &size, errp); | 74 | + while (q->free_req_head == -1) { |
73 | @@ -XXX,XX +XXX,XX @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags, | 75 | + trace_nvme_free_req_queue_wait(q->s, q->index); |
74 | return ret; | 76 | + qemu_co_queue_wait(&q->free_req_queue, &q->lock); |
75 | } | ||
76 | |||
77 | - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, | ||
78 | - false, errp); | ||
79 | + /* | ||
80 | + * Without offset and a size limit, this driver behaves very much | ||
81 | + * like a filter. With any such limit, it does not. | ||
82 | + */ | ||
83 | + if (offset || has_size) { | ||
84 | + file_role = BDRV_CHILD_DATA | BDRV_CHILD_PRIMARY; | ||
85 | + } else { | ||
86 | + file_role = BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY; | ||
87 | + } | 77 | + } |
88 | + | 78 | + |
89 | + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, | 79 | + return nvme_get_free_req_nofail_locked(q); |
90 | + file_role, false, errp); | 80 | +} |
91 | if (!bs->file) { | 81 | + |
92 | return -EINVAL; | 82 | /* With q->lock */ |
83 | static void nvme_put_free_req_locked(NVMeQueuePair *q, NVMeRequest *req) | ||
84 | { | ||
85 | @@ -XXX,XX +XXX,XX @@ static int nvme_admin_cmd_sync(BlockDriverState *bs, NvmeCmd *cmd) | ||
86 | AioContext *aio_context = bdrv_get_aio_context(bs); | ||
87 | NVMeRequest *req; | ||
88 | int ret = -EINPROGRESS; | ||
89 | - req = nvme_get_free_req(q); | ||
90 | + req = nvme_get_free_req_nowait(q); | ||
91 | if (!req) { | ||
92 | return -EBUSY; | ||
93 | } | 93 | } |
94 | -- | 94 | -- |
95 | 2.25.4 | 95 | 2.37.3 |
96 | |||
97 | diff view generated by jsdifflib |
1 | From: Max Reitz <mreitz@redhat.com> | 1 | From: Paolo Bonzini <pbonzini@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Make bdrv_child_cb_detach() call bdrv_backing_detach() for children with | 3 | Callers of coroutine_fn must be coroutine_fn themselves, or the call |
4 | a COW role (and drop the reverse call from bdrv_backing_detach()), so it | 4 | must be within "if (qemu_in_coroutine())". Apply coroutine_fn to |
5 | can be used for any child (with a proper role set). | 5 | functions where this holds. |
6 | 6 | ||
7 | Because so far no child has a proper role set, we need a temporary new | 7 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
8 | callback for child_backing.detach that ensures bdrv_backing_detach() is | 8 | Message-Id: <20220922084924.201610-3-pbonzini@redhat.com> |
9 | called for all COW children that do not have their role set yet. | 9 | [kwolf: Fixed up coding style] |
10 | 10 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | |
11 | (Also, move bdrv_child_cb_detach() down to group it with | ||
12 | bdrv_inherited_options() and bdrv_child_cb_attach().) | ||
13 | |||
14 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
15 | Message-Id: <20200513110544.176672-14-mreitz@redhat.com> | ||
16 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
17 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
18 | --- | 12 | --- |
19 | block.c | 27 ++++++++++++++++++++------- | 13 | block.c | 7 ++++--- |
20 | 1 file changed, 20 insertions(+), 7 deletions(-) | 14 | block/block-backend.c | 10 +++++----- |
15 | block/io.c | 22 +++++++++++----------- | ||
16 | 3 files changed, 20 insertions(+), 19 deletions(-) | ||
21 | 17 | ||
22 | diff --git a/block.c b/block.c | 18 | diff --git a/block.c b/block.c |
23 | index XXXXXXX..XXXXXXX 100644 | 19 | index XXXXXXX..XXXXXXX 100644 |
24 | --- a/block.c | 20 | --- a/block.c |
25 | +++ b/block.c | 21 | +++ b/block.c |
26 | @@ -XXX,XX +XXX,XX @@ static void bdrv_inherited_options(BdrvChildRole role, bool parent_is_format, | 22 | @@ -XXX,XX +XXX,XX @@ static int64_t create_file_fallback_truncate(BlockBackend *blk, |
27 | int *child_flags, QDict *child_options, | 23 | * Helper function for bdrv_create_file_fallback(): Zero the first |
28 | int parent_flags, QDict *parent_options); | 24 | * sector to remove any potentially pre-existing image header. |
29 | static void bdrv_child_cb_attach(BdrvChild *child); | 25 | */ |
30 | +static void bdrv_child_cb_detach(BdrvChild *child); | 26 | -static int create_file_fallback_zero_first_sector(BlockBackend *blk, |
31 | 27 | - int64_t current_size, | |
32 | /* If non-zero, use only whitelisted block drivers */ | 28 | - Error **errp) |
33 | static int use_bdrv_whitelist; | 29 | +static int coroutine_fn |
34 | @@ -XXX,XX +XXX,XX @@ static void bdrv_child_cb_drained_end(BdrvChild *child, | 30 | +create_file_fallback_zero_first_sector(BlockBackend *blk, |
35 | bdrv_drained_end_no_poll(bs, drained_end_counter); | 31 | + int64_t current_size, |
32 | + Error **errp) | ||
33 | { | ||
34 | int64_t bytes_to_clear; | ||
35 | int ret; | ||
36 | diff --git a/block/block-backend.c b/block/block-backend.c | ||
37 | index XXXXXXX..XXXXXXX 100644 | ||
38 | --- a/block/block-backend.c | ||
39 | +++ b/block/block-backend.c | ||
40 | @@ -XXX,XX +XXX,XX @@ static BlockAIOCB *blk_aio_prwv(BlockBackend *blk, int64_t offset, | ||
41 | return &acb->common; | ||
36 | } | 42 | } |
37 | 43 | ||
38 | -static void bdrv_child_cb_detach(BdrvChild *child) | 44 | -static void blk_aio_read_entry(void *opaque) |
39 | -{ | 45 | +static void coroutine_fn blk_aio_read_entry(void *opaque) |
40 | - BlockDriverState *bs = child->opaque; | ||
41 | - bdrv_unapply_subtree_drain(child, bs); | ||
42 | -} | ||
43 | - | ||
44 | static int bdrv_child_cb_inactivate(BdrvChild *child) | ||
45 | { | 46 | { |
46 | BlockDriverState *bs = child->opaque; | 47 | BlkAioEmAIOCB *acb = opaque; |
47 | @@ -XXX,XX +XXX,XX @@ static void bdrv_backing_detach(BdrvChild *c) | 48 | BlkRwCo *rwco = &acb->rwco; |
48 | bdrv_op_unblock_all(c->bs, parent->backing_blocker); | 49 | @@ -XXX,XX +XXX,XX @@ static void blk_aio_read_entry(void *opaque) |
49 | error_free(parent->backing_blocker); | 50 | blk_aio_complete(acb); |
50 | parent->backing_blocker = NULL; | ||
51 | +} | ||
52 | |||
53 | +/* XXX: Will be removed along with child_backing */ | ||
54 | +static void bdrv_child_cb_detach_backing(BdrvChild *c) | ||
55 | +{ | ||
56 | + if (!(c->role & BDRV_CHILD_COW)) { | ||
57 | + bdrv_backing_detach(c); | ||
58 | + } | ||
59 | bdrv_child_cb_detach(c); | ||
60 | } | 51 | } |
61 | 52 | ||
62 | @@ -XXX,XX +XXX,XX @@ const BdrvChildClass child_backing = { | 53 | -static void blk_aio_write_entry(void *opaque) |
63 | .parent_is_bds = true, | 54 | +static void coroutine_fn blk_aio_write_entry(void *opaque) |
64 | .get_parent_desc = bdrv_child_get_parent_desc, | 55 | { |
65 | .attach = bdrv_child_cb_attach_backing, | 56 | BlkAioEmAIOCB *acb = opaque; |
66 | - .detach = bdrv_backing_detach, | 57 | BlkRwCo *rwco = &acb->rwco; |
67 | + .detach = bdrv_child_cb_detach_backing, | 58 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn blk_co_ioctl(BlockBackend *blk, unsigned long int req, |
68 | .inherit_options = bdrv_backing_options, | 59 | return ret; |
69 | .drained_begin = bdrv_child_cb_drained_begin, | ||
70 | .drained_poll = bdrv_child_cb_drained_poll, | ||
71 | @@ -XXX,XX +XXX,XX @@ static void bdrv_child_cb_attach(BdrvChild *child) | ||
72 | bdrv_apply_subtree_drain(child, bs); | ||
73 | } | 60 | } |
74 | 61 | ||
75 | +static void bdrv_child_cb_detach(BdrvChild *child) | 62 | -static void blk_aio_ioctl_entry(void *opaque) |
76 | +{ | 63 | +static void coroutine_fn blk_aio_ioctl_entry(void *opaque) |
77 | + BlockDriverState *bs = child->opaque; | ||
78 | + | ||
79 | + if (child->role & BDRV_CHILD_COW) { | ||
80 | + bdrv_backing_detach(child); | ||
81 | + } | ||
82 | + | ||
83 | + bdrv_unapply_subtree_drain(child, bs); | ||
84 | +} | ||
85 | + | ||
86 | static int bdrv_open_flags(BlockDriverState *bs, int flags) | ||
87 | { | 64 | { |
88 | int open_flags = flags; | 65 | BlkAioEmAIOCB *acb = opaque; |
66 | BlkRwCo *rwco = &acb->rwco; | ||
67 | @@ -XXX,XX +XXX,XX @@ blk_co_do_pdiscard(BlockBackend *blk, int64_t offset, int64_t bytes) | ||
68 | return bdrv_co_pdiscard(blk->root, offset, bytes); | ||
69 | } | ||
70 | |||
71 | -static void blk_aio_pdiscard_entry(void *opaque) | ||
72 | +static void coroutine_fn blk_aio_pdiscard_entry(void *opaque) | ||
73 | { | ||
74 | BlkAioEmAIOCB *acb = opaque; | ||
75 | BlkRwCo *rwco = &acb->rwco; | ||
76 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn blk_co_do_flush(BlockBackend *blk) | ||
77 | return bdrv_co_flush(blk_bs(blk)); | ||
78 | } | ||
79 | |||
80 | -static void blk_aio_flush_entry(void *opaque) | ||
81 | +static void coroutine_fn blk_aio_flush_entry(void *opaque) | ||
82 | { | ||
83 | BlkAioEmAIOCB *acb = opaque; | ||
84 | BlkRwCo *rwco = &acb->rwco; | ||
85 | diff --git a/block/io.c b/block/io.c | ||
86 | index XXXXXXX..XXXXXXX 100644 | ||
87 | --- a/block/io.c | ||
88 | +++ b/block/io.c | ||
89 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn tracked_request_end(BdrvTrackedRequest *req) | ||
90 | /** | ||
91 | * Add an active request to the tracked requests list | ||
92 | */ | ||
93 | -static void tracked_request_begin(BdrvTrackedRequest *req, | ||
94 | - BlockDriverState *bs, | ||
95 | - int64_t offset, | ||
96 | - int64_t bytes, | ||
97 | - enum BdrvTrackedRequestType type) | ||
98 | +static void coroutine_fn tracked_request_begin(BdrvTrackedRequest *req, | ||
99 | + BlockDriverState *bs, | ||
100 | + int64_t offset, | ||
101 | + int64_t bytes, | ||
102 | + enum BdrvTrackedRequestType type) | ||
103 | { | ||
104 | bdrv_check_request(offset, bytes, &error_abort); | ||
105 | |||
106 | @@ -XXX,XX +XXX,XX @@ static bool tracked_request_overlaps(BdrvTrackedRequest *req, | ||
107 | } | ||
108 | |||
109 | /* Called with self->bs->reqs_lock held */ | ||
110 | -static BdrvTrackedRequest * | ||
111 | +static coroutine_fn BdrvTrackedRequest * | ||
112 | bdrv_find_conflicting_request(BdrvTrackedRequest *self) | ||
113 | { | ||
114 | BdrvTrackedRequest *req; | ||
115 | @@ -XXX,XX +XXX,XX @@ static bool bdrv_init_padding(BlockDriverState *bs, | ||
116 | return true; | ||
117 | } | ||
118 | |||
119 | -static int bdrv_padding_rmw_read(BdrvChild *child, | ||
120 | - BdrvTrackedRequest *req, | ||
121 | - BdrvRequestPadding *pad, | ||
122 | - bool zero_middle) | ||
123 | +static coroutine_fn int bdrv_padding_rmw_read(BdrvChild *child, | ||
124 | + BdrvTrackedRequest *req, | ||
125 | + BdrvRequestPadding *pad, | ||
126 | + bool zero_middle) | ||
127 | { | ||
128 | QEMUIOVector local_qiov; | ||
129 | BlockDriverState *bs = child->bs; | ||
130 | @@ -XXX,XX +XXX,XX @@ out: | ||
131 | return ret; | ||
132 | } | ||
133 | |||
134 | -int bdrv_co_ioctl(BlockDriverState *bs, int req, void *buf) | ||
135 | +int coroutine_fn bdrv_co_ioctl(BlockDriverState *bs, int req, void *buf) | ||
136 | { | ||
137 | BlockDriver *drv = bs->drv; | ||
138 | CoroutineIOCompletion co = { | ||
89 | -- | 139 | -- |
90 | 2.25.4 | 140 | 2.37.3 |
91 | |||
92 | diff view generated by jsdifflib |
1 | From: Max Reitz <mreitz@redhat.com> | 1 | From: Paolo Bonzini <pbonzini@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | We can be less restrictive about pure data children than those with | 3 | This is incorrect because qcow2_mark_clean() calls qcow2_flush_caches(). |
4 | metadata on them, so let bdrv_default_perms_for_storage() handle | 4 | qcow2_mark_clean() is called from non-coroutine context in |
5 | metadata children differently from pure data children. | 5 | qcow2_inactivate() and qcow2_amend_options(). |
6 | 6 | ||
7 | As explained in the code, the restrictions on metadata children are | 7 | Reviewed-by: Alberto Faria <afaria@redhat.com> |
8 | strictly stricter than those for pure data children, so in theory we | ||
9 | just have to distinguish between pure-data and all other storage | ||
10 | children (pure metadata or data+metadata). In practice, that is not | ||
11 | obvious, though, so we have two independent code paths for metadata and | ||
12 | for data children, and data+metadata children will go through both | ||
13 | (without the path for data children doing anything meaningful). | ||
14 | |||
15 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
16 | Message-Id: <20200513110544.176672-19-mreitz@redhat.com> | ||
17 | Reviewed-by: Eric Blake <eblake@redhat.com> | 8 | Reviewed-by: Eric Blake <eblake@redhat.com> |
9 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> | ||
10 | Message-Id: <20220922084924.201610-4-pbonzini@redhat.com> | ||
11 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
18 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
19 | --- | 13 | --- |
20 | block.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++---------- | 14 | block/qcow2.h | 4 ++-- |
21 | 1 file changed, 48 insertions(+), 10 deletions(-) | 15 | block/qcow2-refcount.c | 4 ++-- |
16 | 2 files changed, 4 insertions(+), 4 deletions(-) | ||
22 | 17 | ||
23 | diff --git a/block.c b/block.c | 18 | diff --git a/block/qcow2.h b/block/qcow2.h |
24 | index XXXXXXX..XXXXXXX 100644 | 19 | index XXXXXXX..XXXXXXX 100644 |
25 | --- a/block.c | 20 | --- a/block/qcow2.h |
26 | +++ b/block.c | 21 | +++ b/block/qcow2.h |
27 | @@ -XXX,XX +XXX,XX @@ static void bdrv_default_perms_for_storage(BlockDriverState *bs, BdrvChild *c, | 22 | @@ -XXX,XX +XXX,XX @@ void qcow2_free_any_cluster(BlockDriverState *bs, uint64_t l2_entry, |
28 | bdrv_filter_default_perms(bs, c, child_class, role, reopen_queue, | 23 | int qcow2_update_snapshot_refcount(BlockDriverState *bs, |
29 | perm, shared, &perm, &shared); | 24 | int64_t l1_table_offset, int l1_size, int addend); |
30 | 25 | ||
31 | - /* Format drivers may touch metadata even if the guest doesn't write */ | 26 | -int coroutine_fn qcow2_flush_caches(BlockDriverState *bs); |
32 | - if (bdrv_is_writable_after_reopen(bs, reopen_queue)) { | 27 | -int coroutine_fn qcow2_write_caches(BlockDriverState *bs); |
33 | - perm |= BLK_PERM_WRITE | BLK_PERM_RESIZE; | 28 | +int qcow2_flush_caches(BlockDriverState *bs); |
34 | + if (role & BDRV_CHILD_METADATA) { | 29 | +int qcow2_write_caches(BlockDriverState *bs); |
35 | + /* Format drivers may touch metadata even if the guest doesn't write */ | 30 | int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res, |
36 | + if (bdrv_is_writable_after_reopen(bs, reopen_queue)) { | 31 | BdrvCheckMode fix); |
37 | + perm |= BLK_PERM_WRITE | BLK_PERM_RESIZE; | 32 | |
38 | + } | 33 | diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c |
39 | + | 34 | index XXXXXXX..XXXXXXX 100644 |
40 | + /* | 35 | --- a/block/qcow2-refcount.c |
41 | + * bs->file always needs to be consistent because of the | 36 | +++ b/block/qcow2-refcount.c |
42 | + * metadata. We can never allow other users to resize or write | 37 | @@ -XXX,XX +XXX,XX @@ void qcow2_free_any_cluster(BlockDriverState *bs, uint64_t l2_entry, |
43 | + * to it. | ||
44 | + */ | ||
45 | + if (!(flags & BDRV_O_NO_IO)) { | ||
46 | + perm |= BLK_PERM_CONSISTENT_READ; | ||
47 | + } | ||
48 | + shared &= ~(BLK_PERM_WRITE | BLK_PERM_RESIZE); | ||
49 | } | 38 | } |
50 | 39 | } | |
51 | - /* | 40 | |
52 | - * bs->file always needs to be consistent because of the metadata. We | 41 | -int coroutine_fn qcow2_write_caches(BlockDriverState *bs) |
53 | - * can never allow other users to resize or write to it. | 42 | +int qcow2_write_caches(BlockDriverState *bs) |
54 | - */ | 43 | { |
55 | - if (!(flags & BDRV_O_NO_IO)) { | 44 | BDRVQcow2State *s = bs->opaque; |
56 | - perm |= BLK_PERM_CONSISTENT_READ; | 45 | int ret; |
57 | + if (role & BDRV_CHILD_DATA) { | 46 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn qcow2_write_caches(BlockDriverState *bs) |
58 | + /* | 47 | return 0; |
59 | + * Technically, everything in this block is a subset of the | 48 | } |
60 | + * BDRV_CHILD_METADATA path taken above, and so this could | 49 | |
61 | + * be an "else if" branch. However, that is not obvious, and | 50 | -int coroutine_fn qcow2_flush_caches(BlockDriverState *bs) |
62 | + * this function is not performance critical, therefore we let | 51 | +int qcow2_flush_caches(BlockDriverState *bs) |
63 | + * this be an independent "if". | 52 | { |
64 | + */ | 53 | int ret = qcow2_write_caches(bs); |
65 | + | 54 | if (ret < 0) { |
66 | + /* | ||
67 | + * We cannot allow other users to resize the file because the | ||
68 | + * format driver might have some assumptions about the size | ||
69 | + * (e.g. because it is stored in metadata, or because the file | ||
70 | + * is split into fixed-size data files). | ||
71 | + */ | ||
72 | + shared &= ~BLK_PERM_RESIZE; | ||
73 | + | ||
74 | + /* | ||
75 | + * WRITE_UNCHANGED often cannot be performed as such on the | ||
76 | + * data file. For example, the qcow2 driver may still need to | ||
77 | + * write copied clusters on copy-on-read. | ||
78 | + */ | ||
79 | + if (perm & BLK_PERM_WRITE_UNCHANGED) { | ||
80 | + perm |= BLK_PERM_WRITE; | ||
81 | + } | ||
82 | + | ||
83 | + /* | ||
84 | + * If the data file is written to, the format driver may | ||
85 | + * expect to be able to resize it by writing beyond the EOF. | ||
86 | + */ | ||
87 | + if (perm & BLK_PERM_WRITE) { | ||
88 | + perm |= BLK_PERM_RESIZE; | ||
89 | + } | ||
90 | } | ||
91 | - shared &= ~(BLK_PERM_WRITE | BLK_PERM_RESIZE); | ||
92 | |||
93 | if (bs->open_flags & BDRV_O_INACTIVE) { | ||
94 | shared |= BLK_PERM_WRITE | BLK_PERM_RESIZE; | ||
95 | -- | 55 | -- |
96 | 2.25.4 | 56 | 2.37.3 |
97 | |||
98 | diff view generated by jsdifflib |
1 | From: Philippe Mathieu-Daudé <philmd@redhat.com> | 1 | From: Paolo Bonzini <pbonzini@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Fix when building with -Os: | 3 | nbd_co_establish_connection_cancel() cancels a coroutine but is not called |
4 | from coroutine context itself, for example in nbd_cancel_in_flight() | ||
5 | and in timer callbacks reconnect_delay_timer_cb() and open_timer_cb(). | ||
4 | 6 | ||
5 | CC block/block-copy.o | 7 | Reviewed-by: Alberto Faria <afaria@redhat.com> |
6 | block/block-copy.c: In function ‘block_copy_task_entry’: | ||
7 | block/block-copy.c:428:38: error: ‘error_is_read’ may be used uninitialized in this function [-Werror=maybe-uninitialized] | ||
8 | 428 | t->call_state->error_is_read = error_is_read; | ||
9 | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~ | ||
10 | |||
11 | Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com> | ||
12 | Message-Id: <20200507121129.29760-2-philmd@redhat.com> | ||
13 | Reviewed-by: Eric Blake <eblake@redhat.com> | 8 | Reviewed-by: Eric Blake <eblake@redhat.com> |
9 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> | ||
10 | Message-Id: <20220922084924.201610-5-pbonzini@redhat.com> | ||
11 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
14 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
15 | --- | 13 | --- |
16 | block/block-copy.c | 2 +- | 14 | include/block/nbd.h | 2 +- |
17 | 1 file changed, 1 insertion(+), 1 deletion(-) | 15 | 1 file changed, 1 insertion(+), 1 deletion(-) |
18 | 16 | ||
19 | diff --git a/block/block-copy.c b/block/block-copy.c | 17 | diff --git a/include/block/nbd.h b/include/block/nbd.h |
20 | index XXXXXXX..XXXXXXX 100644 | 18 | index XXXXXXX..XXXXXXX 100644 |
21 | --- a/block/block-copy.c | 19 | --- a/include/block/nbd.h |
22 | +++ b/block/block-copy.c | 20 | +++ b/include/block/nbd.h |
23 | @@ -XXX,XX +XXX,XX @@ out: | 21 | @@ -XXX,XX +XXX,XX @@ QIOChannel *coroutine_fn |
24 | static coroutine_fn int block_copy_task_entry(AioTask *task) | 22 | nbd_co_establish_connection(NBDClientConnection *conn, NBDExportInfo *info, |
25 | { | 23 | bool blocking, Error **errp); |
26 | BlockCopyTask *t = container_of(task, BlockCopyTask, task); | 24 | |
27 | - bool error_is_read; | 25 | -void coroutine_fn nbd_co_establish_connection_cancel(NBDClientConnection *conn); |
28 | + bool error_is_read = false; | 26 | +void nbd_co_establish_connection_cancel(NBDClientConnection *conn); |
29 | int ret; | 27 | |
30 | 28 | #endif | |
31 | ret = block_copy_do_copy(t->s, t->offset, t->bytes, t->zeroes, | ||
32 | -- | 29 | -- |
33 | 2.25.4 | 30 | 2.37.3 |
34 | |||
35 | diff view generated by jsdifflib |
1 | From: Max Reitz <mreitz@redhat.com> | 1 | From: Paolo Bonzini <pbonzini@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 3 | qemu_coroutine_get_aio_context inspects a coroutine, but it does |
4 | Message-Id: <20200513110544.176672-33-mreitz@redhat.com> | 4 | not have to be called from the coroutine itself (or from any |
5 | coroutine). | ||
6 | |||
7 | Reviewed-by: Alberto Faria <afaria@redhat.com> | ||
5 | Reviewed-by: Eric Blake <eblake@redhat.com> | 8 | Reviewed-by: Eric Blake <eblake@redhat.com> |
9 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> | ||
10 | Message-Id: <20220922084924.201610-6-pbonzini@redhat.com> | ||
11 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
6 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
7 | --- | 13 | --- |
8 | include/block/block_int.h | 1 - | 14 | include/qemu/coroutine.h | 2 +- |
9 | block.c | 39 ++------------------------------------- | 15 | util/qemu-coroutine.c | 2 +- |
10 | tests/test-bdrv-drain.c | 8 +++----- | 16 | 2 files changed, 2 insertions(+), 2 deletions(-) |
11 | 3 files changed, 5 insertions(+), 43 deletions(-) | ||
12 | 17 | ||
13 | diff --git a/include/block/block_int.h b/include/block/block_int.h | 18 | diff --git a/include/qemu/coroutine.h b/include/qemu/coroutine.h |
14 | index XXXXXXX..XXXXXXX 100644 | 19 | index XXXXXXX..XXXXXXX 100644 |
15 | --- a/include/block/block_int.h | 20 | --- a/include/qemu/coroutine.h |
16 | +++ b/include/block/block_int.h | 21 | +++ b/include/qemu/coroutine.h |
17 | @@ -XXX,XX +XXX,XX @@ struct BdrvChildClass { | 22 | @@ -XXX,XX +XXX,XX @@ void coroutine_fn qemu_coroutine_yield(void); |
18 | }; | 23 | /** |
19 | 24 | * Get the AioContext of the given coroutine | |
20 | extern const BdrvChildClass child_of_bds; | 25 | */ |
21 | -extern const BdrvChildClass child_file; | 26 | -AioContext *coroutine_fn qemu_coroutine_get_aio_context(Coroutine *co); |
22 | 27 | +AioContext *qemu_coroutine_get_aio_context(Coroutine *co); | |
23 | struct BdrvChild { | 28 | |
24 | BlockDriverState *bs; | 29 | /** |
25 | diff --git a/block.c b/block.c | 30 | * Get the currently executing coroutine |
31 | diff --git a/util/qemu-coroutine.c b/util/qemu-coroutine.c | ||
26 | index XXXXXXX..XXXXXXX 100644 | 32 | index XXXXXXX..XXXXXXX 100644 |
27 | --- a/block.c | 33 | --- a/util/qemu-coroutine.c |
28 | +++ b/block.c | 34 | +++ b/util/qemu-coroutine.c |
29 | @@ -XXX,XX +XXX,XX @@ static BlockDriverState *bdrv_open_inherit(const char *filename, | 35 | @@ -XXX,XX +XXX,XX @@ bool qemu_coroutine_entered(Coroutine *co) |
30 | BdrvChildRole child_role, | 36 | return co->caller; |
31 | Error **errp); | ||
32 | |||
33 | -/* TODO: Remove when no longer needed */ | ||
34 | -static void bdrv_inherited_options(BdrvChildRole role, bool parent_is_format, | ||
35 | - int *child_flags, QDict *child_options, | ||
36 | - int parent_flags, QDict *parent_options); | ||
37 | -static void bdrv_child_cb_attach(BdrvChild *child); | ||
38 | -static void bdrv_child_cb_detach(BdrvChild *child); | ||
39 | - | ||
40 | /* If non-zero, use only whitelisted block drivers */ | ||
41 | static int use_bdrv_whitelist; | ||
42 | |||
43 | @@ -XXX,XX +XXX,XX @@ static void bdrv_temp_snapshot_options(int *child_flags, QDict *child_options, | ||
44 | *child_flags &= ~BDRV_O_NATIVE_AIO; | ||
45 | } | 37 | } |
46 | 38 | ||
47 | -/* | 39 | -AioContext *coroutine_fn qemu_coroutine_get_aio_context(Coroutine *co) |
48 | - * Returns the options and flags that bs->file should get if a protocol driver | 40 | +AioContext *qemu_coroutine_get_aio_context(Coroutine *co) |
49 | - * is expected, based on the given options and flags for the parent BDS | ||
50 | - */ | ||
51 | -static void bdrv_protocol_options(BdrvChildRole role, bool parent_is_format, | ||
52 | - int *child_flags, QDict *child_options, | ||
53 | - int parent_flags, QDict *parent_options) | ||
54 | -{ | ||
55 | - bdrv_inherited_options(BDRV_CHILD_IMAGE, true, | ||
56 | - child_flags, child_options, | ||
57 | - parent_flags, parent_options); | ||
58 | -} | ||
59 | - | ||
60 | -const BdrvChildClass child_file = { | ||
61 | - .parent_is_bds = true, | ||
62 | - .get_parent_desc = bdrv_child_get_parent_desc, | ||
63 | - .inherit_options = bdrv_protocol_options, | ||
64 | - .drained_begin = bdrv_child_cb_drained_begin, | ||
65 | - .drained_poll = bdrv_child_cb_drained_poll, | ||
66 | - .drained_end = bdrv_child_cb_drained_end, | ||
67 | - .attach = bdrv_child_cb_attach, | ||
68 | - .detach = bdrv_child_cb_detach, | ||
69 | - .inactivate = bdrv_child_cb_inactivate, | ||
70 | - .can_set_aio_ctx = bdrv_child_cb_can_set_aio_ctx, | ||
71 | - .set_aio_ctx = bdrv_child_cb_set_aio_ctx, | ||
72 | -}; | ||
73 | - | ||
74 | static void bdrv_backing_attach(BdrvChild *c) | ||
75 | { | 41 | { |
76 | BlockDriverState *parent = c->opaque; | 42 | return co->ctx; |
77 | @@ -XXX,XX +XXX,XX @@ static void bdrv_default_perms_for_storage(BlockDriverState *bs, BdrvChild *c, | 43 | } |
78 | { | ||
79 | int flags; | ||
80 | |||
81 | - assert(child_class == &child_file || | ||
82 | - (child_class == &child_of_bds && | ||
83 | - (role & (BDRV_CHILD_METADATA | BDRV_CHILD_DATA)))); | ||
84 | + assert(child_class == &child_of_bds && | ||
85 | + (role & (BDRV_CHILD_METADATA | BDRV_CHILD_DATA))); | ||
86 | |||
87 | flags = bdrv_reopen_get_flags(reopen_queue, bs); | ||
88 | |||
89 | diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c | ||
90 | index XXXXXXX..XXXXXXX 100644 | ||
91 | --- a/tests/test-bdrv-drain.c | ||
92 | +++ b/tests/test-bdrv-drain.c | ||
93 | @@ -XXX,XX +XXX,XX @@ static void bdrv_test_child_perm(BlockDriverState *bs, BdrvChild *c, | ||
94 | uint64_t *nperm, uint64_t *nshared) | ||
95 | { | ||
96 | /* | ||
97 | - * bdrv_default_perms() accepts only these two, so disguise | ||
98 | - * detach_by_driver_cb_parent as one of them. | ||
99 | + * bdrv_default_perms() accepts nothing else, so disguise | ||
100 | + * detach_by_driver_cb_parent. | ||
101 | */ | ||
102 | - if (child_class != &child_file && child_class != &child_of_bds) { | ||
103 | - child_class = &child_of_bds; | ||
104 | - } | ||
105 | + child_class = &child_of_bds; | ||
106 | |||
107 | bdrv_default_perms(bs, c, child_class, role, reopen_queue, | ||
108 | perm, shared, nperm, nshared); | ||
109 | -- | 44 | -- |
110 | 2.25.4 | 45 | 2.37.3 |
111 | |||
112 | diff view generated by jsdifflib |
1 | From: Max Reitz <mreitz@redhat.com> | 1 | From: Paolo Bonzini <pbonzini@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Both users (quorum and blkverify) use child_format for | 3 | Callers of coroutine_fn must be coroutine_fn themselves, or the call |
4 | not-really-filtered children, so the appropriate BdrvChildRole in both | 4 | must be within "if (qemu_in_coroutine())". Apply coroutine_fn to |
5 | cases is DATA. (Note that this will cause bdrv_inherited_options() to | 5 | functions where this holds. |
6 | force-allow format probing.) | ||
7 | 6 | ||
8 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 7 | Reviewed-by: Alberto Faria <afaria@redhat.com> |
9 | Reviewed-by: Eric Blake <eblake@redhat.com> | 8 | Reviewed-by: Eric Blake <eblake@redhat.com> |
10 | Message-Id: <20200513110544.176672-22-mreitz@redhat.com> | 9 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
10 | Message-Id: <20220922084924.201610-8-pbonzini@redhat.com> | ||
11 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
12 | --- | 13 | --- |
13 | block/blkverify.c | 4 ++-- | 14 | block/blkverify.c | 2 +- |
14 | block/quorum.c | 6 ++++-- | 15 | 1 file changed, 1 insertion(+), 1 deletion(-) |
15 | 2 files changed, 6 insertions(+), 4 deletions(-) | ||
16 | 16 | ||
17 | diff --git a/block/blkverify.c b/block/blkverify.c | 17 | diff --git a/block/blkverify.c b/block/blkverify.c |
18 | index XXXXXXX..XXXXXXX 100644 | 18 | index XXXXXXX..XXXXXXX 100644 |
19 | --- a/block/blkverify.c | 19 | --- a/block/blkverify.c |
20 | +++ b/block/blkverify.c | 20 | +++ b/block/blkverify.c |
21 | @@ -XXX,XX +XXX,XX @@ static int blkverify_open(BlockDriverState *bs, QDict *options, int flags, | 21 | @@ -XXX,XX +XXX,XX @@ blkverify_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes, |
22 | 22 | return blkverify_co_prwv(bs, &r, offset, bytes, qiov, qiov, flags, true); | |
23 | /* Open the test file */ | 23 | } |
24 | s->test_file = bdrv_open_child(qemu_opt_get(opts, "x-image"), options, | 24 | |
25 | - "test", bs, &child_format, 0, false, | 25 | -static int blkverify_co_flush(BlockDriverState *bs) |
26 | - &local_err); | 26 | +static int coroutine_fn blkverify_co_flush(BlockDriverState *bs) |
27 | + "test", bs, &child_of_bds, BDRV_CHILD_DATA, | 27 | { |
28 | + false, &local_err); | 28 | BDRVBlkverifyState *s = bs->opaque; |
29 | if (local_err) { | 29 | |
30 | ret = -EINVAL; | ||
31 | error_propagate(errp, local_err); | ||
32 | diff --git a/block/quorum.c b/block/quorum.c | ||
33 | index XXXXXXX..XXXXXXX 100644 | ||
34 | --- a/block/quorum.c | ||
35 | +++ b/block/quorum.c | ||
36 | @@ -XXX,XX +XXX,XX @@ static int quorum_open(BlockDriverState *bs, QDict *options, int flags, | ||
37 | assert(ret < 32); | ||
38 | |||
39 | s->children[i] = bdrv_open_child(NULL, options, indexstr, bs, | ||
40 | - &child_format, 0, false, &local_err); | ||
41 | + &child_of_bds, BDRV_CHILD_DATA, false, | ||
42 | + &local_err); | ||
43 | if (local_err) { | ||
44 | ret = -EINVAL; | ||
45 | goto close_exit; | ||
46 | @@ -XXX,XX +XXX,XX @@ static void quorum_add_child(BlockDriverState *bs, BlockDriverState *child_bs, | ||
47 | /* We can safely add the child now */ | ||
48 | bdrv_ref(child_bs); | ||
49 | |||
50 | - child = bdrv_attach_child(bs, child_bs, indexstr, &child_format, 0, errp); | ||
51 | + child = bdrv_attach_child(bs, child_bs, indexstr, &child_of_bds, | ||
52 | + BDRV_CHILD_DATA, errp); | ||
53 | if (child == NULL) { | ||
54 | s->next_child_index--; | ||
55 | goto out; | ||
56 | -- | 30 | -- |
57 | 2.25.4 | 31 | 2.37.3 |
58 | |||
59 | diff view generated by jsdifflib |
1 | From: Max Reitz <mreitz@redhat.com> | 1 | From: Paolo Bonzini <pbonzini@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 3 | Callers of coroutine_fn must be coroutine_fn themselves, or the call |
4 | must be within "if (qemu_in_coroutine())". Apply coroutine_fn to | ||
5 | functions where this holds. | ||
6 | |||
7 | Reviewed-by: Alberto Faria <afaria@redhat.com> | ||
4 | Reviewed-by: Eric Blake <eblake@redhat.com> | 8 | Reviewed-by: Eric Blake <eblake@redhat.com> |
5 | Message-Id: <20200513110544.176672-32-mreitz@redhat.com> | 9 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
10 | Message-Id: <20220922084924.201610-9-pbonzini@redhat.com> | ||
11 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
6 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
7 | --- | 13 | --- |
8 | include/block/block_int.h | 11 ----------- | 14 | block/file-posix.c | 2 +- |
9 | block.c | 19 ------------------- | 15 | 1 file changed, 1 insertion(+), 1 deletion(-) |
10 | 2 files changed, 30 deletions(-) | ||
11 | 16 | ||
12 | diff --git a/include/block/block_int.h b/include/block/block_int.h | 17 | diff --git a/block/file-posix.c b/block/file-posix.c |
13 | index XXXXXXX..XXXXXXX 100644 | 18 | index XXXXXXX..XXXXXXX 100644 |
14 | --- a/include/block/block_int.h | 19 | --- a/block/file-posix.c |
15 | +++ b/include/block/block_int.h | 20 | +++ b/block/file-posix.c |
16 | @@ -XXX,XX +XXX,XX @@ int bdrv_child_try_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared, | 21 | @@ -XXX,XX +XXX,XX @@ static void raw_aio_unplug(BlockDriverState *bs) |
17 | */ | 22 | #endif |
18 | int bdrv_child_refresh_perms(BlockDriverState *bs, BdrvChild *c, Error **errp); | ||
19 | |||
20 | -/* Default implementation for BlockDriver.bdrv_child_perm() that can be used by | ||
21 | - * (non-raw) image formats: Like above for bs->backing, but for bs->file it | ||
22 | - * requires WRITE | RESIZE for read-write images, always requires | ||
23 | - * CONSISTENT_READ and doesn't share WRITE. */ | ||
24 | -void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c, | ||
25 | - const BdrvChildClass *child_class, | ||
26 | - BdrvChildRole child_role, | ||
27 | - BlockReopenQueue *reopen_queue, | ||
28 | - uint64_t perm, uint64_t shared, | ||
29 | - uint64_t *nperm, uint64_t *nshared); | ||
30 | - | ||
31 | bool bdrv_recurse_can_replace(BlockDriverState *bs, | ||
32 | BlockDriverState *to_replace); | ||
33 | |||
34 | diff --git a/block.c b/block.c | ||
35 | index XXXXXXX..XXXXXXX 100644 | ||
36 | --- a/block.c | ||
37 | +++ b/block.c | ||
38 | @@ -XXX,XX +XXX,XX @@ static void bdrv_default_perms_for_storage(BlockDriverState *bs, BdrvChild *c, | ||
39 | *nshared = shared; | ||
40 | } | 23 | } |
41 | 24 | ||
42 | -void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c, | 25 | -static int raw_co_flush_to_disk(BlockDriverState *bs) |
43 | - const BdrvChildClass *child_class, | 26 | +static int coroutine_fn raw_co_flush_to_disk(BlockDriverState *bs) |
44 | - BdrvChildRole role, | 27 | { |
45 | - BlockReopenQueue *reopen_queue, | 28 | BDRVRawState *s = bs->opaque; |
46 | - uint64_t perm, uint64_t shared, | 29 | RawPosixAIOData acb; |
47 | - uint64_t *nperm, uint64_t *nshared) | ||
48 | -{ | ||
49 | - if (child_class == &child_of_bds) { | ||
50 | - bdrv_default_perms(bs, c, child_class, role, reopen_queue, | ||
51 | - perm, shared, nperm, nshared); | ||
52 | - return; | ||
53 | - } | ||
54 | - | ||
55 | - assert(child_class == &child_file); | ||
56 | - | ||
57 | - bdrv_default_perms_for_storage(bs, c, child_class, role, reopen_queue, | ||
58 | - perm, shared, nperm, nshared); | ||
59 | -} | ||
60 | - | ||
61 | void bdrv_default_perms(BlockDriverState *bs, BdrvChild *c, | ||
62 | const BdrvChildClass *child_class, BdrvChildRole role, | ||
63 | BlockReopenQueue *reopen_queue, | ||
64 | -- | 30 | -- |
65 | 2.25.4 | 31 | 2.37.3 |
66 | |||
67 | diff view generated by jsdifflib |
1 | From: Max Reitz <mreitz@redhat.com> | 1 | From: Paolo Bonzini <pbonzini@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | This callback can be used by BDSs that use child_of_bds with the | 3 | Callers of coroutine_fn must be coroutine_fn themselves, or the call |
4 | appropriate BdrvChildRole for their children. | 4 | must be within "if (qemu_in_coroutine())". Apply coroutine_fn to |
5 | functions where this holds. | ||
5 | 6 | ||
6 | Also, make bdrv_format_default_perms() use it for child_of_bds children | 7 | Reviewed-by: Alberto Faria <afaria@redhat.com> |
7 | (just a temporary solution until we can drop bdrv_format_default_perms() | ||
8 | altogether). | ||
9 | |||
10 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
11 | Message-Id: <20200513110544.176672-20-mreitz@redhat.com> | ||
12 | Reviewed-by: Eric Blake <eblake@redhat.com> | 8 | Reviewed-by: Eric Blake <eblake@redhat.com> |
9 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> | ||
10 | Message-Id: <20220922084924.201610-10-pbonzini@redhat.com> | ||
11 | [kwolf: Fixed up coding style] | ||
12 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
13 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 13 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
14 | --- | 14 | --- |
15 | include/block/block_int.h | 11 +++++++++++ | 15 | block/iscsi.c | 3 ++- |
16 | block.c | 32 ++++++++++++++++++++++++++++++++ | 16 | 1 file changed, 2 insertions(+), 1 deletion(-) |
17 | 2 files changed, 43 insertions(+) | ||
18 | 17 | ||
19 | diff --git a/include/block/block_int.h b/include/block/block_int.h | 18 | diff --git a/block/iscsi.c b/block/iscsi.c |
20 | index XXXXXXX..XXXXXXX 100644 | 19 | index XXXXXXX..XXXXXXX 100644 |
21 | --- a/include/block/block_int.h | 20 | --- a/block/iscsi.c |
22 | +++ b/include/block/block_int.h | 21 | +++ b/block/iscsi.c |
23 | @@ -XXX,XX +XXX,XX @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c, | 22 | @@ -XXX,XX +XXX,XX @@ iscsi_co_generic_cb(struct iscsi_context *iscsi, int status, |
24 | bool bdrv_recurse_can_replace(BlockDriverState *bs, | ||
25 | BlockDriverState *to_replace); | ||
26 | |||
27 | +/* | ||
28 | + * Default implementation for BlockDriver.bdrv_child_perm() that can | ||
29 | + * be used by block filters and image formats, as long as they use the | ||
30 | + * child_of_bds child class and set an appropriate BdrvChildRole. | ||
31 | + */ | ||
32 | +void bdrv_default_perms(BlockDriverState *bs, BdrvChild *c, | ||
33 | + const BdrvChildClass *child_class, BdrvChildRole role, | ||
34 | + BlockReopenQueue *reopen_queue, | ||
35 | + uint64_t perm, uint64_t shared, | ||
36 | + uint64_t *nperm, uint64_t *nshared); | ||
37 | + | ||
38 | /* | ||
39 | * Default implementation for drivers to pass bdrv_co_block_status() to | ||
40 | * their file. | ||
41 | diff --git a/block.c b/block.c | ||
42 | index XXXXXXX..XXXXXXX 100644 | ||
43 | --- a/block.c | ||
44 | +++ b/block.c | ||
45 | @@ -XXX,XX +XXX,XX @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c, | ||
46 | uint64_t *nperm, uint64_t *nshared) | ||
47 | { | ||
48 | bool backing = (child_class == &child_backing); | ||
49 | + | ||
50 | + if (child_class == &child_of_bds) { | ||
51 | + bdrv_default_perms(bs, c, child_class, role, reopen_queue, | ||
52 | + perm, shared, nperm, nshared); | ||
53 | + return; | ||
54 | + } | ||
55 | + | ||
56 | assert(child_class == &child_backing || child_class == &child_file); | ||
57 | |||
58 | if (!backing) { | ||
59 | @@ -XXX,XX +XXX,XX @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c, | ||
60 | } | 23 | } |
61 | } | 24 | } |
62 | 25 | ||
63 | +void bdrv_default_perms(BlockDriverState *bs, BdrvChild *c, | 26 | -static void iscsi_co_init_iscsitask(IscsiLun *iscsilun, struct IscsiTask *iTask) |
64 | + const BdrvChildClass *child_class, BdrvChildRole role, | 27 | +static void coroutine_fn |
65 | + BlockReopenQueue *reopen_queue, | 28 | +iscsi_co_init_iscsitask(IscsiLun *iscsilun, struct IscsiTask *iTask) |
66 | + uint64_t perm, uint64_t shared, | ||
67 | + uint64_t *nperm, uint64_t *nshared) | ||
68 | +{ | ||
69 | + assert(child_class == &child_of_bds); | ||
70 | + | ||
71 | + if (role & BDRV_CHILD_FILTERED) { | ||
72 | + assert(!(role & (BDRV_CHILD_DATA | BDRV_CHILD_METADATA | | ||
73 | + BDRV_CHILD_COW))); | ||
74 | + bdrv_filter_default_perms(bs, c, child_class, role, reopen_queue, | ||
75 | + perm, shared, nperm, nshared); | ||
76 | + } else if (role & BDRV_CHILD_COW) { | ||
77 | + assert(!(role & (BDRV_CHILD_DATA | BDRV_CHILD_METADATA))); | ||
78 | + bdrv_default_perms_for_cow(bs, c, child_class, role, reopen_queue, | ||
79 | + perm, shared, nperm, nshared); | ||
80 | + } else if (role & (BDRV_CHILD_METADATA | BDRV_CHILD_DATA)) { | ||
81 | + bdrv_default_perms_for_storage(bs, c, child_class, role, reopen_queue, | ||
82 | + perm, shared, nperm, nshared); | ||
83 | + } else { | ||
84 | + g_assert_not_reached(); | ||
85 | + } | ||
86 | +} | ||
87 | + | ||
88 | uint64_t bdrv_qapi_perm_to_blk_perm(BlockPermission qapi_perm) | ||
89 | { | 29 | { |
90 | static const uint64_t permissions[] = { | 30 | *iTask = (struct IscsiTask) { |
31 | .co = qemu_coroutine_self(), | ||
91 | -- | 32 | -- |
92 | 2.25.4 | 33 | 2.37.3 |
93 | |||
94 | diff view generated by jsdifflib |
1 | From: Max Reitz <mreitz@redhat.com> | 1 | From: Paolo Bonzini <pbonzini@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | The other two .inherit_options implementations specify exactly for what | 3 | Callers of coroutine_fn must be coroutine_fn themselves, or the call |
4 | case they are used in their name, so do it for this one as well. | 4 | must be within "if (qemu_in_coroutine())". Apply coroutine_fn to |
5 | functions where this holds. | ||
5 | 6 | ||
6 | (The actual intention behind this patch is to follow it up with a | 7 | Reviewed-by: Alberto Faria <afaria@redhat.com> |
7 | generic bdrv_inherited_options() that works for all three cases.) | ||
8 | |||
9 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
10 | Reviewed-by: Eric Blake <eblake@redhat.com> | 8 | Reviewed-by: Eric Blake <eblake@redhat.com> |
11 | Message-Id: <20200513110544.176672-10-mreitz@redhat.com> | 9 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
10 | Message-Id: <20220922084924.201610-11-pbonzini@redhat.com> | ||
11 | [kwolf: Fixed up coding style] | ||
12 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 13 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
13 | --- | 14 | --- |
14 | block.c | 8 ++++---- | 15 | block/nbd.c | 11 ++++++----- |
15 | 1 file changed, 4 insertions(+), 4 deletions(-) | 16 | 1 file changed, 6 insertions(+), 5 deletions(-) |
16 | 17 | ||
17 | diff --git a/block.c b/block.c | 18 | diff --git a/block/nbd.c b/block/nbd.c |
18 | index XXXXXXX..XXXXXXX 100644 | 19 | index XXXXXXX..XXXXXXX 100644 |
19 | --- a/block.c | 20 | --- a/block/nbd.c |
20 | +++ b/block.c | 21 | +++ b/block/nbd.c |
21 | @@ -XXX,XX +XXX,XX @@ static void bdrv_temp_snapshot_options(int *child_flags, QDict *child_options, | 22 | @@ -XXX,XX +XXX,XX @@ static void nbd_iter_request_error(NBDReplyChunkIter *iter, int ret) |
22 | * Returns the options and flags that bs->file should get if a protocol driver | 23 | * nbd_reply_chunk_iter_receive |
23 | * is expected, based on the given options and flags for the parent BDS | 24 | * The pointer stored in @payload requires g_free() to free it. |
24 | */ | 25 | */ |
25 | -static void bdrv_inherited_options(BdrvChildRole role, bool parent_is_format, | 26 | -static bool nbd_reply_chunk_iter_receive(BDRVNBDState *s, |
26 | - int *child_flags, QDict *child_options, | 27 | - NBDReplyChunkIter *iter, |
27 | - int parent_flags, QDict *parent_options) | 28 | - uint64_t handle, |
28 | +static void bdrv_protocol_options(BdrvChildRole role, bool parent_is_format, | 29 | - QEMUIOVector *qiov, NBDReply *reply, |
29 | + int *child_flags, QDict *child_options, | 30 | - void **payload) |
30 | + int parent_flags, QDict *parent_options) | 31 | +static bool coroutine_fn nbd_reply_chunk_iter_receive(BDRVNBDState *s, |
32 | + NBDReplyChunkIter *iter, | ||
33 | + uint64_t handle, | ||
34 | + QEMUIOVector *qiov, | ||
35 | + NBDReply *reply, | ||
36 | + void **payload) | ||
31 | { | 37 | { |
32 | int flags = parent_flags; | 38 | int ret, request_ret; |
33 | 39 | NBDReply local_reply; | |
34 | @@ -XXX,XX +XXX,XX @@ static void bdrv_inherited_options(BdrvChildRole role, bool parent_is_format, | ||
35 | const BdrvChildClass child_file = { | ||
36 | .parent_is_bds = true, | ||
37 | .get_parent_desc = bdrv_child_get_parent_desc, | ||
38 | - .inherit_options = bdrv_inherited_options, | ||
39 | + .inherit_options = bdrv_protocol_options, | ||
40 | .drained_begin = bdrv_child_cb_drained_begin, | ||
41 | .drained_poll = bdrv_child_cb_drained_poll, | ||
42 | .drained_end = bdrv_child_cb_drained_end, | ||
43 | -- | 40 | -- |
44 | 2.25.4 | 41 | 2.37.3 |
45 | |||
46 | diff view generated by jsdifflib |
1 | From: Max Reitz <mreitz@redhat.com> | 1 | From: Paolo Bonzini <pbonzini@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 3 | Callers of coroutine_fn must be coroutine_fn themselves, or the call |
4 | Reviewed-by: Eric Blake <eblake@redhat.com> | 4 | must be within "if (qemu_in_coroutine())". Apply coroutine_fn to |
5 | Message-Id: <20200513110544.176672-31-mreitz@redhat.com> | 5 | functions where this holds. |
6 | |||
7 | Reviewed-by: Alberto Faria <afaria@redhat.com> | ||
8 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> | ||
9 | Message-Id: <20220922084924.201610-12-pbonzini@redhat.com> | ||
10 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
6 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
7 | --- | 12 | --- |
8 | include/block/block_int.h | 10 ---------- | 13 | block/nfs.c | 2 +- |
9 | block.c | 17 +++++++++++------ | 14 | 1 file changed, 1 insertion(+), 1 deletion(-) |
10 | 2 files changed, 11 insertions(+), 16 deletions(-) | ||
11 | 15 | ||
12 | diff --git a/include/block/block_int.h b/include/block/block_int.h | 16 | diff --git a/block/nfs.c b/block/nfs.c |
13 | index XXXXXXX..XXXXXXX 100644 | 17 | index XXXXXXX..XXXXXXX 100644 |
14 | --- a/include/block/block_int.h | 18 | --- a/block/nfs.c |
15 | +++ b/include/block/block_int.h | 19 | +++ b/block/nfs.c |
16 | @@ -XXX,XX +XXX,XX @@ int bdrv_child_try_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared, | 20 | @@ -XXX,XX +XXX,XX @@ static void nfs_process_write(void *arg) |
17 | */ | 21 | qemu_mutex_unlock(&client->mutex); |
18 | int bdrv_child_refresh_perms(BlockDriverState *bs, BdrvChild *c, Error **errp); | ||
19 | |||
20 | -/* Default implementation for BlockDriver.bdrv_child_perm() that can be used by | ||
21 | - * block filters: Forward CONSISTENT_READ, WRITE, WRITE_UNCHANGED and RESIZE to | ||
22 | - * all children */ | ||
23 | -void bdrv_filter_default_perms(BlockDriverState *bs, BdrvChild *c, | ||
24 | - const BdrvChildClass *child_class, | ||
25 | - BdrvChildRole child_role, | ||
26 | - BlockReopenQueue *reopen_queue, | ||
27 | - uint64_t perm, uint64_t shared, | ||
28 | - uint64_t *nperm, uint64_t *nshared); | ||
29 | - | ||
30 | /* Default implementation for BlockDriver.bdrv_child_perm() that can be used by | ||
31 | * (non-raw) image formats: Like above for bs->backing, but for bs->file it | ||
32 | * requires WRITE | RESIZE for read-write images, always requires | ||
33 | diff --git a/block.c b/block.c | ||
34 | index XXXXXXX..XXXXXXX 100644 | ||
35 | --- a/block.c | ||
36 | +++ b/block.c | ||
37 | @@ -XXX,XX +XXX,XX @@ int bdrv_child_refresh_perms(BlockDriverState *bs, BdrvChild *c, Error **errp) | ||
38 | return bdrv_child_try_set_perm(c, perms, shared, errp); | ||
39 | } | 22 | } |
40 | 23 | ||
41 | -void bdrv_filter_default_perms(BlockDriverState *bs, BdrvChild *c, | 24 | -static void nfs_co_init_task(BlockDriverState *bs, NFSRPC *task) |
42 | - const BdrvChildClass *child_class, | 25 | +static void coroutine_fn nfs_co_init_task(BlockDriverState *bs, NFSRPC *task) |
43 | - BdrvChildRole role, | ||
44 | - BlockReopenQueue *reopen_queue, | ||
45 | - uint64_t perm, uint64_t shared, | ||
46 | - uint64_t *nperm, uint64_t *nshared) | ||
47 | +/* | ||
48 | + * Default implementation for .bdrv_child_perm() for block filters: | ||
49 | + * Forward CONSISTENT_READ, WRITE, WRITE_UNCHANGED, and RESIZE to the | ||
50 | + * filtered child. | ||
51 | + */ | ||
52 | +static void bdrv_filter_default_perms(BlockDriverState *bs, BdrvChild *c, | ||
53 | + const BdrvChildClass *child_class, | ||
54 | + BdrvChildRole role, | ||
55 | + BlockReopenQueue *reopen_queue, | ||
56 | + uint64_t perm, uint64_t shared, | ||
57 | + uint64_t *nperm, uint64_t *nshared) | ||
58 | { | 26 | { |
59 | *nperm = perm & DEFAULT_PERM_PASSTHROUGH; | 27 | *task = (NFSRPC) { |
60 | *nshared = (shared & DEFAULT_PERM_PASSTHROUGH) | DEFAULT_PERM_UNCHANGED; | 28 | .co = qemu_coroutine_self(), |
61 | -- | 29 | -- |
62 | 2.25.4 | 30 | 2.37.3 |
63 | |||
64 | diff view generated by jsdifflib |
1 | From: Max Reitz <mreitz@redhat.com> | 1 | From: Paolo Bonzini <pbonzini@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | bdrv_format_default_perms() has one code path for backing files, and one | 3 | Callers of coroutine_fn must be coroutine_fn themselves, or the call |
4 | for storage files. We want to pull them out into their own functions, | 4 | must be within "if (qemu_in_coroutine())". Apply coroutine_fn to |
5 | so make sure they are completely distinct before so the next patches | 5 | functions where this holds. |
6 | will be a bit cleaner. | ||
7 | 6 | ||
8 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 7 | Reviewed-by: Alberto Faria <afaria@redhat.com> |
9 | Reviewed-by: Eric Blake <eblake@redhat.com> | 8 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
10 | Message-Id: <20200513110544.176672-16-mreitz@redhat.com> | 9 | Message-Id: <20220922084924.201610-13-pbonzini@redhat.com> |
10 | [kwolf: Fixed up coding style] | ||
11 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
12 | --- | 13 | --- |
13 | block.c | 19 +++++++++++++------ | 14 | block/nvme.c | 6 ++++-- |
14 | 1 file changed, 13 insertions(+), 6 deletions(-) | 15 | 1 file changed, 4 insertions(+), 2 deletions(-) |
15 | 16 | ||
16 | diff --git a/block.c b/block.c | 17 | diff --git a/block/nvme.c b/block/nvme.c |
17 | index XXXXXXX..XXXXXXX 100644 | 18 | index XXXXXXX..XXXXXXX 100644 |
18 | --- a/block.c | 19 | --- a/block/nvme.c |
19 | +++ b/block.c | 20 | +++ b/block/nvme.c |
20 | @@ -XXX,XX +XXX,XX @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c, | 21 | @@ -XXX,XX +XXX,XX @@ static inline bool nvme_qiov_aligned(BlockDriverState *bs, |
21 | perm |= BLK_PERM_CONSISTENT_READ; | 22 | return true; |
22 | } | ||
23 | shared &= ~(BLK_PERM_WRITE | BLK_PERM_RESIZE); | ||
24 | + | ||
25 | + if (bs->open_flags & BDRV_O_INACTIVE) { | ||
26 | + shared |= BLK_PERM_WRITE | BLK_PERM_RESIZE; | ||
27 | + } | ||
28 | + | ||
29 | + *nperm = perm; | ||
30 | + *nshared = shared; | ||
31 | } else { | ||
32 | /* We want consistent read from backing files if the parent needs it. | ||
33 | * No other operations are performed on backing files. */ | ||
34 | @@ -XXX,XX +XXX,XX @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c, | ||
35 | |||
36 | shared |= BLK_PERM_CONSISTENT_READ | BLK_PERM_GRAPH_MOD | | ||
37 | BLK_PERM_WRITE_UNCHANGED; | ||
38 | - } | ||
39 | |||
40 | - if (bs->open_flags & BDRV_O_INACTIVE) { | ||
41 | - shared |= BLK_PERM_WRITE | BLK_PERM_RESIZE; | ||
42 | - } | ||
43 | + if (bs->open_flags & BDRV_O_INACTIVE) { | ||
44 | + shared |= BLK_PERM_WRITE | BLK_PERM_RESIZE; | ||
45 | + } | ||
46 | |||
47 | - *nperm = perm; | ||
48 | - *nshared = shared; | ||
49 | + *nperm = perm; | ||
50 | + *nshared = shared; | ||
51 | + } | ||
52 | } | 23 | } |
53 | 24 | ||
54 | uint64_t bdrv_qapi_perm_to_blk_perm(BlockPermission qapi_perm) | 25 | -static int nvme_co_prw(BlockDriverState *bs, uint64_t offset, uint64_t bytes, |
26 | - QEMUIOVector *qiov, bool is_write, int flags) | ||
27 | +static coroutine_fn int nvme_co_prw(BlockDriverState *bs, | ||
28 | + uint64_t offset, uint64_t bytes, | ||
29 | + QEMUIOVector *qiov, bool is_write, | ||
30 | + int flags) | ||
31 | { | ||
32 | BDRVNVMeState *s = bs->opaque; | ||
33 | int r; | ||
55 | -- | 34 | -- |
56 | 2.25.4 | 35 | 2.37.3 |
57 | |||
58 | diff view generated by jsdifflib |
1 | From: Max Reitz <mreitz@redhat.com> | 1 | From: Paolo Bonzini <pbonzini@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Commonly, they need to pass the BDRV_CHILD_IMAGE set as the | 3 | Callers of coroutine_fn must be coroutine_fn themselves, or the call |
4 | BdrvChildRole; but there are exceptions for drivers with external data | 4 | must be within "if (qemu_in_coroutine())". Apply coroutine_fn to |
5 | files (qcow2 and vmdk). | 5 | functions where this holds. |
6 | 6 | ||
7 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 7 | Reviewed-by: Alberto Faria <afaria@redhat.com> |
8 | Reviewed-by: Eric Blake <eblake@redhat.com> | 8 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
9 | Message-Id: <20200513110544.176672-26-mreitz@redhat.com> | 9 | Message-Id: <20220922084924.201610-14-pbonzini@redhat.com> |
10 | [kwolf: Fixed up coding style] | ||
11 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
11 | --- | 13 | --- |
12 | block/bochs.c | 4 ++-- | 14 | block/parallels.c | 5 +++-- |
13 | block/cloop.c | 4 ++-- | 15 | 1 file changed, 3 insertions(+), 2 deletions(-) |
14 | block/crypto.c | 4 ++-- | ||
15 | block/dmg.c | 4 ++-- | ||
16 | block/parallels.c | 4 ++-- | ||
17 | block/qcow.c | 4 ++-- | ||
18 | block/qcow2.c | 19 +++++++++++++------ | ||
19 | block/qed.c | 4 ++-- | ||
20 | block/vdi.c | 4 ++-- | ||
21 | block/vhdx.c | 4 ++-- | ||
22 | block/vmdk.c | 20 +++++++++++++++++--- | ||
23 | block/vpc.c | 4 ++-- | ||
24 | 12 files changed, 50 insertions(+), 29 deletions(-) | ||
25 | 16 | ||
26 | diff --git a/block/bochs.c b/block/bochs.c | ||
27 | index XXXXXXX..XXXXXXX 100644 | ||
28 | --- a/block/bochs.c | ||
29 | +++ b/block/bochs.c | ||
30 | @@ -XXX,XX +XXX,XX @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags, | ||
31 | return ret; | ||
32 | } | ||
33 | |||
34 | - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, | ||
35 | - false, errp); | ||
36 | + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, | ||
37 | + BDRV_CHILD_IMAGE, false, errp); | ||
38 | if (!bs->file) { | ||
39 | return -EINVAL; | ||
40 | } | ||
41 | diff --git a/block/cloop.c b/block/cloop.c | ||
42 | index XXXXXXX..XXXXXXX 100644 | ||
43 | --- a/block/cloop.c | ||
44 | +++ b/block/cloop.c | ||
45 | @@ -XXX,XX +XXX,XX @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags, | ||
46 | return ret; | ||
47 | } | ||
48 | |||
49 | - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, | ||
50 | - false, errp); | ||
51 | + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, | ||
52 | + BDRV_CHILD_IMAGE, false, errp); | ||
53 | if (!bs->file) { | ||
54 | return -EINVAL; | ||
55 | } | ||
56 | diff --git a/block/crypto.c b/block/crypto.c | ||
57 | index XXXXXXX..XXXXXXX 100644 | ||
58 | --- a/block/crypto.c | ||
59 | +++ b/block/crypto.c | ||
60 | @@ -XXX,XX +XXX,XX @@ static int block_crypto_open_generic(QCryptoBlockFormat format, | ||
61 | unsigned int cflags = 0; | ||
62 | QDict *cryptoopts = NULL; | ||
63 | |||
64 | - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, | ||
65 | - false, errp); | ||
66 | + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, | ||
67 | + BDRV_CHILD_IMAGE, false, errp); | ||
68 | if (!bs->file) { | ||
69 | return -EINVAL; | ||
70 | } | ||
71 | diff --git a/block/dmg.c b/block/dmg.c | ||
72 | index XXXXXXX..XXXXXXX 100644 | ||
73 | --- a/block/dmg.c | ||
74 | +++ b/block/dmg.c | ||
75 | @@ -XXX,XX +XXX,XX @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags, | ||
76 | return ret; | ||
77 | } | ||
78 | |||
79 | - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, | ||
80 | - false, errp); | ||
81 | + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, | ||
82 | + BDRV_CHILD_IMAGE, false, errp); | ||
83 | if (!bs->file) { | ||
84 | return -EINVAL; | ||
85 | } | ||
86 | diff --git a/block/parallels.c b/block/parallels.c | 17 | diff --git a/block/parallels.c b/block/parallels.c |
87 | index XXXXXXX..XXXXXXX 100644 | 18 | index XXXXXXX..XXXXXXX 100644 |
88 | --- a/block/parallels.c | 19 | --- a/block/parallels.c |
89 | +++ b/block/parallels.c | 20 | +++ b/block/parallels.c |
90 | @@ -XXX,XX +XXX,XX @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags, | 21 | @@ -XXX,XX +XXX,XX @@ static int64_t block_status(BDRVParallelsState *s, int64_t sector_num, |
91 | Error *local_err = NULL; | 22 | return start_off; |
92 | char *buf; | 23 | } |
93 | 24 | ||
94 | - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, | 25 | -static int64_t allocate_clusters(BlockDriverState *bs, int64_t sector_num, |
95 | - false, errp); | 26 | - int nb_sectors, int *pnum) |
96 | + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, | 27 | +static coroutine_fn int64_t allocate_clusters(BlockDriverState *bs, |
97 | + BDRV_CHILD_IMAGE, false, errp); | 28 | + int64_t sector_num, |
98 | if (!bs->file) { | 29 | + int nb_sectors, int *pnum) |
99 | return -EINVAL; | 30 | { |
100 | } | 31 | int ret = 0; |
101 | diff --git a/block/qcow.c b/block/qcow.c | 32 | BDRVParallelsState *s = bs->opaque; |
102 | index XXXXXXX..XXXXXXX 100644 | ||
103 | --- a/block/qcow.c | ||
104 | +++ b/block/qcow.c | ||
105 | @@ -XXX,XX +XXX,XX @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags, | ||
106 | qdict_extract_subqdict(options, &encryptopts, "encrypt."); | ||
107 | encryptfmt = qdict_get_try_str(encryptopts, "format"); | ||
108 | |||
109 | - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, | ||
110 | - false, errp); | ||
111 | + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, | ||
112 | + BDRV_CHILD_IMAGE, false, errp); | ||
113 | if (!bs->file) { | ||
114 | ret = -EINVAL; | ||
115 | goto fail; | ||
116 | diff --git a/block/qcow2.c b/block/qcow2.c | ||
117 | index XXXXXXX..XXXXXXX 100644 | ||
118 | --- a/block/qcow2.c | ||
119 | +++ b/block/qcow2.c | ||
120 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options, | ||
121 | } | ||
122 | |||
123 | /* Open external data file */ | ||
124 | - s->data_file = bdrv_open_child(NULL, options, "data-file", bs, &child_file, | ||
125 | - 0, true, &local_err); | ||
126 | + s->data_file = bdrv_open_child(NULL, options, "data-file", bs, | ||
127 | + &child_of_bds, BDRV_CHILD_DATA, | ||
128 | + true, &local_err); | ||
129 | if (local_err) { | ||
130 | error_propagate(errp, local_err); | ||
131 | ret = -EINVAL; | ||
132 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options, | ||
133 | if (s->incompatible_features & QCOW2_INCOMPAT_DATA_FILE) { | ||
134 | if (!s->data_file && s->image_data_file) { | ||
135 | s->data_file = bdrv_open_child(s->image_data_file, options, | ||
136 | - "data-file", bs, &child_file, 0, | ||
137 | - false, errp); | ||
138 | + "data-file", bs, &child_of_bds, | ||
139 | + BDRV_CHILD_DATA, false, errp); | ||
140 | if (!s->data_file) { | ||
141 | ret = -EINVAL; | ||
142 | goto fail; | ||
143 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options, | ||
144 | ret = -EINVAL; | ||
145 | goto fail; | ||
146 | } | ||
147 | + | ||
148 | + /* No data here */ | ||
149 | + bs->file->role &= ~BDRV_CHILD_DATA; | ||
150 | + | ||
151 | + /* Must succeed because we have given up permissions if anything */ | ||
152 | + bdrv_child_refresh_perms(bs, bs->file, &error_abort); | ||
153 | } else { | ||
154 | if (s->data_file) { | ||
155 | error_setg(errp, "'data-file' can only be set for images with an " | ||
156 | @@ -XXX,XX +XXX,XX @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags, | ||
157 | .ret = -EINPROGRESS | ||
158 | }; | ||
159 | |||
160 | - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, | ||
161 | - false, errp); | ||
162 | + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, | ||
163 | + BDRV_CHILD_IMAGE, false, errp); | ||
164 | if (!bs->file) { | ||
165 | return -EINVAL; | ||
166 | } | ||
167 | diff --git a/block/qed.c b/block/qed.c | ||
168 | index XXXXXXX..XXXXXXX 100644 | ||
169 | --- a/block/qed.c | ||
170 | +++ b/block/qed.c | ||
171 | @@ -XXX,XX +XXX,XX @@ static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags, | ||
172 | .ret = -EINPROGRESS | ||
173 | }; | ||
174 | |||
175 | - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, | ||
176 | - false, errp); | ||
177 | + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, | ||
178 | + BDRV_CHILD_IMAGE, false, errp); | ||
179 | if (!bs->file) { | ||
180 | return -EINVAL; | ||
181 | } | ||
182 | diff --git a/block/vdi.c b/block/vdi.c | ||
183 | index XXXXXXX..XXXXXXX 100644 | ||
184 | --- a/block/vdi.c | ||
185 | +++ b/block/vdi.c | ||
186 | @@ -XXX,XX +XXX,XX @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags, | ||
187 | Error *local_err = NULL; | ||
188 | QemuUUID uuid_link, uuid_parent; | ||
189 | |||
190 | - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, | ||
191 | - false, errp); | ||
192 | + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, | ||
193 | + BDRV_CHILD_IMAGE, false, errp); | ||
194 | if (!bs->file) { | ||
195 | return -EINVAL; | ||
196 | } | ||
197 | diff --git a/block/vhdx.c b/block/vhdx.c | ||
198 | index XXXXXXX..XXXXXXX 100644 | ||
199 | --- a/block/vhdx.c | ||
200 | +++ b/block/vhdx.c | ||
201 | @@ -XXX,XX +XXX,XX @@ static int vhdx_open(BlockDriverState *bs, QDict *options, int flags, | ||
202 | uint64_t signature; | ||
203 | Error *local_err = NULL; | ||
204 | |||
205 | - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, | ||
206 | - false, errp); | ||
207 | + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, | ||
208 | + BDRV_CHILD_IMAGE, false, errp); | ||
209 | if (!bs->file) { | ||
210 | return -EINVAL; | ||
211 | } | ||
212 | diff --git a/block/vmdk.c b/block/vmdk.c | ||
213 | index XXXXXXX..XXXXXXX 100644 | ||
214 | --- a/block/vmdk.c | ||
215 | +++ b/block/vmdk.c | ||
216 | @@ -XXX,XX +XXX,XX @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs, | ||
217 | char *desc_file_dir = NULL; | ||
218 | char *extent_path; | ||
219 | BdrvChild *extent_file; | ||
220 | + BdrvChildRole extent_role; | ||
221 | BDRVVmdkState *s = bs->opaque; | ||
222 | VmdkExtent *extent; | ||
223 | char extent_opt_prefix[32]; | ||
224 | @@ -XXX,XX +XXX,XX @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs, | ||
225 | ret = snprintf(extent_opt_prefix, 32, "extents.%d", s->num_extents); | ||
226 | assert(ret < 32); | ||
227 | |||
228 | + extent_role = BDRV_CHILD_DATA; | ||
229 | + if (strcmp(type, "FLAT") != 0 && strcmp(type, "VMFS") != 0) { | ||
230 | + /* non-flat extents have metadata */ | ||
231 | + extent_role |= BDRV_CHILD_METADATA; | ||
232 | + } | ||
233 | + | ||
234 | extent_file = bdrv_open_child(extent_path, options, extent_opt_prefix, | ||
235 | - bs, &child_file, 0, false, &local_err); | ||
236 | + bs, &child_of_bds, extent_role, false, | ||
237 | + &local_err); | ||
238 | g_free(extent_path); | ||
239 | if (local_err) { | ||
240 | error_propagate(errp, local_err); | ||
241 | @@ -XXX,XX +XXX,XX @@ static int vmdk_open(BlockDriverState *bs, QDict *options, int flags, | ||
242 | uint32_t magic; | ||
243 | Error *local_err = NULL; | ||
244 | |||
245 | - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, | ||
246 | - false, errp); | ||
247 | + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, | ||
248 | + BDRV_CHILD_IMAGE, false, errp); | ||
249 | if (!bs->file) { | ||
250 | return -EINVAL; | ||
251 | } | ||
252 | @@ -XXX,XX +XXX,XX @@ static int vmdk_open(BlockDriverState *bs, QDict *options, int flags, | ||
253 | s->desc_offset = 0x200; | ||
254 | break; | ||
255 | default: | ||
256 | + /* No data in the descriptor file */ | ||
257 | + bs->file->role &= ~BDRV_CHILD_DATA; | ||
258 | + | ||
259 | + /* Must succeed because we have given up permissions if anything */ | ||
260 | + bdrv_child_refresh_perms(bs, bs->file, &error_abort); | ||
261 | + | ||
262 | ret = vmdk_open_desc_file(bs, flags, buf, options, errp); | ||
263 | break; | ||
264 | } | ||
265 | diff --git a/block/vpc.c b/block/vpc.c | ||
266 | index XXXXXXX..XXXXXXX 100644 | ||
267 | --- a/block/vpc.c | ||
268 | +++ b/block/vpc.c | ||
269 | @@ -XXX,XX +XXX,XX @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags, | ||
270 | int ret; | ||
271 | int64_t bs_size; | ||
272 | |||
273 | - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, | ||
274 | - false, errp); | ||
275 | + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, | ||
276 | + BDRV_CHILD_IMAGE, false, errp); | ||
277 | if (!bs->file) { | ||
278 | return -EINVAL; | ||
279 | } | ||
280 | -- | 33 | -- |
281 | 2.25.4 | 34 | 2.37.3 |
282 | |||
283 | diff view generated by jsdifflib |
1 | From: Max Reitz <mreitz@redhat.com> | 1 | From: Paolo Bonzini <pbonzini@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | bdrv_default_perms() can decide which permission profile to use based on | 3 | Callers of coroutine_fn must be coroutine_fn themselves, or the call |
4 | the BdrvChildRole, so block drivers do not need to select it explicitly. | 4 | must be within "if (qemu_in_coroutine())". Apply coroutine_fn to |
5 | functions where this holds. | ||
5 | 6 | ||
6 | The blkverify driver now no longer shares the WRITE permission for the | 7 | Reviewed-by: Alberto Faria <afaria@redhat.com> |
7 | image to verify. We thus have to adjust two places in | 8 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
8 | test-block-iothread not to take it. (Note that in theory, blkverify | 9 | Message-Id: <20220922084924.201610-15-pbonzini@redhat.com> |
9 | should behave like quorum in this regard and share neither WRITE nor | 10 | [kwolf: Fixed up coding style] |
10 | RESIZE for both of its children. In practice, it does not really | 11 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> |
11 | matter, because blkverify is used only for debugging, so we might as | ||
12 | well keep its permissions rather liberal.) | ||
13 | |||
14 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
15 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
16 | Message-Id: <20200513110544.176672-30-mreitz@redhat.com> | ||
17 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
18 | --- | 13 | --- |
19 | block/backup-top.c | 4 ++-- | 14 | block/qcow2.h | 15 ++++++++------- |
20 | block/blkdebug.c | 4 ++-- | 15 | block/qcow2-cluster.c | 21 ++++++++++++--------- |
21 | block/blklogwrites.c | 9 ++------- | 16 | block/qcow2-refcount.c | 2 +- |
22 | block/blkreplay.c | 2 +- | 17 | block/qcow2.c | 5 +++-- |
23 | block/blkverify.c | 2 +- | 18 | 4 files changed, 24 insertions(+), 19 deletions(-) |
24 | block/bochs.c | 2 +- | ||
25 | block/cloop.c | 2 +- | ||
26 | block/crypto.c | 2 +- | ||
27 | block/dmg.c | 2 +- | ||
28 | block/filter-compress.c | 2 +- | ||
29 | block/parallels.c | 2 +- | ||
30 | block/qcow.c | 2 +- | ||
31 | block/qcow2.c | 2 +- | ||
32 | block/qed.c | 2 +- | ||
33 | block/raw-format.c | 2 +- | ||
34 | block/throttle.c | 2 +- | ||
35 | block/vdi.c | 2 +- | ||
36 | block/vhdx.c | 2 +- | ||
37 | block/vmdk.c | 2 +- | ||
38 | block/vpc.c | 2 +- | ||
39 | tests/test-bdrv-drain.c | 10 +++++----- | ||
40 | tests/test-bdrv-graph-mod.c | 2 +- | ||
41 | tests/test-block-iothread.c | 17 ++++++++++++++--- | ||
42 | 23 files changed, 43 insertions(+), 37 deletions(-) | ||
43 | 19 | ||
44 | diff --git a/block/backup-top.c b/block/backup-top.c | 20 | diff --git a/block/qcow2.h b/block/qcow2.h |
45 | index XXXXXXX..XXXXXXX 100644 | 21 | index XXXXXXX..XXXXXXX 100644 |
46 | --- a/block/backup-top.c | 22 | --- a/block/qcow2.h |
47 | +++ b/block/backup-top.c | 23 | +++ b/block/qcow2.h |
48 | @@ -XXX,XX +XXX,XX @@ static void backup_top_child_perm(BlockDriverState *bs, BdrvChild *c, | 24 | @@ -XXX,XX +XXX,XX @@ int qcow2_change_refcount_order(BlockDriverState *bs, int refcount_order, |
49 | *nperm = BLK_PERM_WRITE; | 25 | void *cb_opaque, Error **errp); |
50 | } else { | 26 | int qcow2_shrink_reftable(BlockDriverState *bs); |
51 | /* Source child */ | 27 | int64_t qcow2_get_last_cluster(BlockDriverState *bs, int64_t size); |
52 | - bdrv_filter_default_perms(bs, c, child_class, role, reopen_queue, | 28 | -int qcow2_detect_metadata_preallocation(BlockDriverState *bs); |
53 | - perm, shared, nperm, nshared); | 29 | +int coroutine_fn qcow2_detect_metadata_preallocation(BlockDriverState *bs); |
54 | + bdrv_default_perms(bs, c, child_class, role, reopen_queue, | 30 | |
55 | + perm, shared, nperm, nshared); | 31 | /* qcow2-cluster.c functions */ |
56 | 32 | int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size, | |
57 | if (perm & BLK_PERM_WRITE) { | 33 | @@ -XXX,XX +XXX,XX @@ int qcow2_encrypt_sectors(BDRVQcow2State *s, int64_t sector_num, |
58 | *nperm = *nperm | BLK_PERM_CONSISTENT_READ; | 34 | int qcow2_get_host_offset(BlockDriverState *bs, uint64_t offset, |
59 | diff --git a/block/blkdebug.c b/block/blkdebug.c | 35 | unsigned int *bytes, uint64_t *host_offset, |
36 | QCow2SubclusterType *subcluster_type); | ||
37 | -int qcow2_alloc_host_offset(BlockDriverState *bs, uint64_t offset, | ||
38 | - unsigned int *bytes, uint64_t *host_offset, | ||
39 | - QCowL2Meta **m); | ||
40 | +int coroutine_fn qcow2_alloc_host_offset(BlockDriverState *bs, uint64_t offset, | ||
41 | + unsigned int *bytes, | ||
42 | + uint64_t *host_offset, QCowL2Meta **m); | ||
43 | int qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs, | ||
44 | uint64_t offset, | ||
45 | int compressed_size, | ||
46 | @@ -XXX,XX +XXX,XX @@ int qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs, | ||
47 | void qcow2_parse_compressed_l2_entry(BlockDriverState *bs, uint64_t l2_entry, | ||
48 | uint64_t *coffset, int *csize); | ||
49 | |||
50 | -int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m); | ||
51 | +int coroutine_fn qcow2_alloc_cluster_link_l2(BlockDriverState *bs, | ||
52 | + QCowL2Meta *m); | ||
53 | void qcow2_alloc_cluster_abort(BlockDriverState *bs, QCowL2Meta *m); | ||
54 | int qcow2_cluster_discard(BlockDriverState *bs, uint64_t offset, | ||
55 | uint64_t bytes, enum qcow2_discard_type type, | ||
56 | bool full_discard); | ||
57 | -int qcow2_subcluster_zeroize(BlockDriverState *bs, uint64_t offset, | ||
58 | - uint64_t bytes, int flags); | ||
59 | +int coroutine_fn qcow2_subcluster_zeroize(BlockDriverState *bs, uint64_t offset, | ||
60 | + uint64_t bytes, int flags); | ||
61 | |||
62 | int qcow2_expand_zero_clusters(BlockDriverState *bs, | ||
63 | BlockDriverAmendStatusCB *status_cb, | ||
64 | diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c | ||
60 | index XXXXXXX..XXXXXXX 100644 | 65 | index XXXXXXX..XXXXXXX 100644 |
61 | --- a/block/blkdebug.c | 66 | --- a/block/qcow2-cluster.c |
62 | +++ b/block/blkdebug.c | 67 | +++ b/block/qcow2-cluster.c |
63 | @@ -XXX,XX +XXX,XX @@ static void blkdebug_child_perm(BlockDriverState *bs, BdrvChild *c, | 68 | @@ -XXX,XX +XXX,XX @@ int qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs, |
69 | return 0; | ||
70 | } | ||
71 | |||
72 | -static int perform_cow(BlockDriverState *bs, QCowL2Meta *m) | ||
73 | +static int coroutine_fn perform_cow(BlockDriverState *bs, QCowL2Meta *m) | ||
64 | { | 74 | { |
65 | BDRVBlkdebugState *s = bs->opaque; | 75 | BDRVQcow2State *s = bs->opaque; |
66 | 76 | Qcow2COWRegion *start = &m->cow_start; | |
67 | - bdrv_filter_default_perms(bs, c, child_class, role, reopen_queue, | 77 | @@ -XXX,XX +XXX,XX @@ fail: |
68 | - perm, shared, nperm, nshared); | 78 | return ret; |
69 | + bdrv_default_perms(bs, c, child_class, role, reopen_queue, | 79 | } |
70 | + perm, shared, nperm, nshared); | 80 | |
71 | 81 | -int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m) | |
72 | *nperm |= s->take_child_perms; | 82 | +int coroutine_fn qcow2_alloc_cluster_link_l2(BlockDriverState *bs, |
73 | *nshared &= ~s->unshare_child_perms; | 83 | + QCowL2Meta *m) |
74 | diff --git a/block/blklogwrites.c b/block/blklogwrites.c | 84 | { |
85 | BDRVQcow2State *s = bs->opaque; | ||
86 | int i, j = 0, l2_index, ret; | ||
87 | @@ -XXX,XX +XXX,XX @@ static int count_single_write_clusters(BlockDriverState *bs, int nb_clusters, | ||
88 | * information on cluster allocation may be invalid now. The caller | ||
89 | * must start over anyway, so consider *cur_bytes undefined. | ||
90 | */ | ||
91 | -static int handle_dependencies(BlockDriverState *bs, uint64_t guest_offset, | ||
92 | - uint64_t *cur_bytes, QCowL2Meta **m) | ||
93 | +static int coroutine_fn handle_dependencies(BlockDriverState *bs, | ||
94 | + uint64_t guest_offset, | ||
95 | + uint64_t *cur_bytes, QCowL2Meta **m) | ||
96 | { | ||
97 | BDRVQcow2State *s = bs->opaque; | ||
98 | QCowL2Meta *old_alloc; | ||
99 | @@ -XXX,XX +XXX,XX @@ out: | ||
100 | * | ||
101 | * Return 0 on success and -errno in error cases | ||
102 | */ | ||
103 | -int qcow2_alloc_host_offset(BlockDriverState *bs, uint64_t offset, | ||
104 | - unsigned int *bytes, uint64_t *host_offset, | ||
105 | - QCowL2Meta **m) | ||
106 | +int coroutine_fn qcow2_alloc_host_offset(BlockDriverState *bs, uint64_t offset, | ||
107 | + unsigned int *bytes, | ||
108 | + uint64_t *host_offset, | ||
109 | + QCowL2Meta **m) | ||
110 | { | ||
111 | BDRVQcow2State *s = bs->opaque; | ||
112 | uint64_t start, remaining; | ||
113 | @@ -XXX,XX +XXX,XX @@ out: | ||
114 | return ret; | ||
115 | } | ||
116 | |||
117 | -int qcow2_subcluster_zeroize(BlockDriverState *bs, uint64_t offset, | ||
118 | - uint64_t bytes, int flags) | ||
119 | +int coroutine_fn qcow2_subcluster_zeroize(BlockDriverState *bs, uint64_t offset, | ||
120 | + uint64_t bytes, int flags) | ||
121 | { | ||
122 | BDRVQcow2State *s = bs->opaque; | ||
123 | uint64_t end_offset = offset + bytes; | ||
124 | diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c | ||
75 | index XXXXXXX..XXXXXXX 100644 | 125 | index XXXXXXX..XXXXXXX 100644 |
76 | --- a/block/blklogwrites.c | 126 | --- a/block/qcow2-refcount.c |
77 | +++ b/block/blklogwrites.c | 127 | +++ b/block/qcow2-refcount.c |
78 | @@ -XXX,XX +XXX,XX @@ static void blk_log_writes_child_perm(BlockDriverState *bs, BdrvChild *c, | 128 | @@ -XXX,XX +XXX,XX @@ int64_t qcow2_get_last_cluster(BlockDriverState *bs, int64_t size) |
79 | return; | 129 | return -EIO; |
80 | } | ||
81 | |||
82 | - if (!strcmp(c->name, "log")) { | ||
83 | - bdrv_format_default_perms(bs, c, child_class, role, ro_q, perm, shrd, | ||
84 | - nperm, nshrd); | ||
85 | - } else { | ||
86 | - bdrv_filter_default_perms(bs, c, child_class, role, ro_q, perm, shrd, | ||
87 | - nperm, nshrd); | ||
88 | - } | ||
89 | + bdrv_default_perms(bs, c, child_class, role, ro_q, perm, shrd, | ||
90 | + nperm, nshrd); | ||
91 | } | 130 | } |
92 | 131 | ||
93 | static void blk_log_writes_refresh_limits(BlockDriverState *bs, Error **errp) | 132 | -int qcow2_detect_metadata_preallocation(BlockDriverState *bs) |
94 | diff --git a/block/blkreplay.c b/block/blkreplay.c | 133 | +int coroutine_fn qcow2_detect_metadata_preallocation(BlockDriverState *bs) |
95 | index XXXXXXX..XXXXXXX 100644 | 134 | { |
96 | --- a/block/blkreplay.c | 135 | BDRVQcow2State *s = bs->opaque; |
97 | +++ b/block/blkreplay.c | 136 | int64_t i, end_cluster, cluster_count = 0, threshold; |
98 | @@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_blkreplay = { | ||
99 | .is_filter = true, | ||
100 | |||
101 | .bdrv_open = blkreplay_open, | ||
102 | - .bdrv_child_perm = bdrv_filter_default_perms, | ||
103 | + .bdrv_child_perm = bdrv_default_perms, | ||
104 | .bdrv_getlength = blkreplay_getlength, | ||
105 | |||
106 | .bdrv_co_preadv = blkreplay_co_preadv, | ||
107 | diff --git a/block/blkverify.c b/block/blkverify.c | ||
108 | index XXXXXXX..XXXXXXX 100644 | ||
109 | --- a/block/blkverify.c | ||
110 | +++ b/block/blkverify.c | ||
111 | @@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_blkverify = { | ||
112 | .bdrv_parse_filename = blkverify_parse_filename, | ||
113 | .bdrv_file_open = blkverify_open, | ||
114 | .bdrv_close = blkverify_close, | ||
115 | - .bdrv_child_perm = bdrv_filter_default_perms, | ||
116 | + .bdrv_child_perm = bdrv_default_perms, | ||
117 | .bdrv_getlength = blkverify_getlength, | ||
118 | .bdrv_refresh_filename = blkverify_refresh_filename, | ||
119 | .bdrv_dirname = blkverify_dirname, | ||
120 | diff --git a/block/bochs.c b/block/bochs.c | ||
121 | index XXXXXXX..XXXXXXX 100644 | ||
122 | --- a/block/bochs.c | ||
123 | +++ b/block/bochs.c | ||
124 | @@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_bochs = { | ||
125 | .instance_size = sizeof(BDRVBochsState), | ||
126 | .bdrv_probe = bochs_probe, | ||
127 | .bdrv_open = bochs_open, | ||
128 | - .bdrv_child_perm = bdrv_format_default_perms, | ||
129 | + .bdrv_child_perm = bdrv_default_perms, | ||
130 | .bdrv_refresh_limits = bochs_refresh_limits, | ||
131 | .bdrv_co_preadv = bochs_co_preadv, | ||
132 | .bdrv_close = bochs_close, | ||
133 | diff --git a/block/cloop.c b/block/cloop.c | ||
134 | index XXXXXXX..XXXXXXX 100644 | ||
135 | --- a/block/cloop.c | ||
136 | +++ b/block/cloop.c | ||
137 | @@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_cloop = { | ||
138 | .instance_size = sizeof(BDRVCloopState), | ||
139 | .bdrv_probe = cloop_probe, | ||
140 | .bdrv_open = cloop_open, | ||
141 | - .bdrv_child_perm = bdrv_format_default_perms, | ||
142 | + .bdrv_child_perm = bdrv_default_perms, | ||
143 | .bdrv_refresh_limits = cloop_refresh_limits, | ||
144 | .bdrv_co_preadv = cloop_co_preadv, | ||
145 | .bdrv_close = cloop_close, | ||
146 | diff --git a/block/crypto.c b/block/crypto.c | ||
147 | index XXXXXXX..XXXXXXX 100644 | ||
148 | --- a/block/crypto.c | ||
149 | +++ b/block/crypto.c | ||
150 | @@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_crypto_luks = { | ||
151 | .bdrv_close = block_crypto_close, | ||
152 | /* This driver doesn't modify LUKS metadata except when creating image. | ||
153 | * Allow share-rw=on as a special case. */ | ||
154 | - .bdrv_child_perm = bdrv_filter_default_perms, | ||
155 | + .bdrv_child_perm = bdrv_default_perms, | ||
156 | .bdrv_co_create = block_crypto_co_create_luks, | ||
157 | .bdrv_co_create_opts = block_crypto_co_create_opts_luks, | ||
158 | .bdrv_co_truncate = block_crypto_co_truncate, | ||
159 | diff --git a/block/dmg.c b/block/dmg.c | ||
160 | index XXXXXXX..XXXXXXX 100644 | ||
161 | --- a/block/dmg.c | ||
162 | +++ b/block/dmg.c | ||
163 | @@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_dmg = { | ||
164 | .bdrv_probe = dmg_probe, | ||
165 | .bdrv_open = dmg_open, | ||
166 | .bdrv_refresh_limits = dmg_refresh_limits, | ||
167 | - .bdrv_child_perm = bdrv_format_default_perms, | ||
168 | + .bdrv_child_perm = bdrv_default_perms, | ||
169 | .bdrv_co_preadv = dmg_co_preadv, | ||
170 | .bdrv_close = dmg_close, | ||
171 | .is_format = true, | ||
172 | diff --git a/block/filter-compress.c b/block/filter-compress.c | ||
173 | index XXXXXXX..XXXXXXX 100644 | ||
174 | --- a/block/filter-compress.c | ||
175 | +++ b/block/filter-compress.c | ||
176 | @@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_compress = { | ||
177 | .format_name = "compress", | ||
178 | |||
179 | .bdrv_open = compress_open, | ||
180 | - .bdrv_child_perm = bdrv_filter_default_perms, | ||
181 | + .bdrv_child_perm = bdrv_default_perms, | ||
182 | |||
183 | .bdrv_getlength = compress_getlength, | ||
184 | |||
185 | diff --git a/block/parallels.c b/block/parallels.c | ||
186 | index XXXXXXX..XXXXXXX 100644 | ||
187 | --- a/block/parallels.c | ||
188 | +++ b/block/parallels.c | ||
189 | @@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_parallels = { | ||
190 | .bdrv_probe = parallels_probe, | ||
191 | .bdrv_open = parallels_open, | ||
192 | .bdrv_close = parallels_close, | ||
193 | - .bdrv_child_perm = bdrv_format_default_perms, | ||
194 | + .bdrv_child_perm = bdrv_default_perms, | ||
195 | .bdrv_co_block_status = parallels_co_block_status, | ||
196 | .bdrv_has_zero_init = bdrv_has_zero_init_1, | ||
197 | .bdrv_co_flush_to_os = parallels_co_flush_to_os, | ||
198 | diff --git a/block/qcow.c b/block/qcow.c | ||
199 | index XXXXXXX..XXXXXXX 100644 | ||
200 | --- a/block/qcow.c | ||
201 | +++ b/block/qcow.c | ||
202 | @@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_qcow = { | ||
203 | .bdrv_probe = qcow_probe, | ||
204 | .bdrv_open = qcow_open, | ||
205 | .bdrv_close = qcow_close, | ||
206 | - .bdrv_child_perm = bdrv_format_default_perms, | ||
207 | + .bdrv_child_perm = bdrv_default_perms, | ||
208 | .bdrv_reopen_prepare = qcow_reopen_prepare, | ||
209 | .bdrv_co_create = qcow_co_create, | ||
210 | .bdrv_co_create_opts = qcow_co_create_opts, | ||
211 | diff --git a/block/qcow2.c b/block/qcow2.c | 137 | diff --git a/block/qcow2.c b/block/qcow2.c |
212 | index XXXXXXX..XXXXXXX 100644 | 138 | index XXXXXXX..XXXXXXX 100644 |
213 | --- a/block/qcow2.c | 139 | --- a/block/qcow2.c |
214 | +++ b/block/qcow2.c | 140 | +++ b/block/qcow2.c |
215 | @@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_qcow2 = { | 141 | @@ -XXX,XX +XXX,XX @@ static bool merge_cow(uint64_t offset, unsigned bytes, |
216 | .bdrv_reopen_commit_post = qcow2_reopen_commit_post, | 142 | * Return 1 if the COW regions read as zeroes, 0 if not, < 0 on error. |
217 | .bdrv_reopen_abort = qcow2_reopen_abort, | 143 | * Note that returning 0 does not guarantee non-zero data. |
218 | .bdrv_join_options = qcow2_join_options, | 144 | */ |
219 | - .bdrv_child_perm = bdrv_format_default_perms, | 145 | -static int is_zero_cow(BlockDriverState *bs, QCowL2Meta *m) |
220 | + .bdrv_child_perm = bdrv_default_perms, | 146 | +static int coroutine_fn is_zero_cow(BlockDriverState *bs, QCowL2Meta *m) |
221 | .bdrv_co_create_opts = qcow2_co_create_opts, | ||
222 | .bdrv_co_create = qcow2_co_create, | ||
223 | .bdrv_has_zero_init = qcow2_has_zero_init, | ||
224 | diff --git a/block/qed.c b/block/qed.c | ||
225 | index XXXXXXX..XXXXXXX 100644 | ||
226 | --- a/block/qed.c | ||
227 | +++ b/block/qed.c | ||
228 | @@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_qed = { | ||
229 | .bdrv_open = bdrv_qed_open, | ||
230 | .bdrv_close = bdrv_qed_close, | ||
231 | .bdrv_reopen_prepare = bdrv_qed_reopen_prepare, | ||
232 | - .bdrv_child_perm = bdrv_format_default_perms, | ||
233 | + .bdrv_child_perm = bdrv_default_perms, | ||
234 | .bdrv_co_create = bdrv_qed_co_create, | ||
235 | .bdrv_co_create_opts = bdrv_qed_co_create_opts, | ||
236 | .bdrv_has_zero_init = bdrv_has_zero_init_1, | ||
237 | diff --git a/block/raw-format.c b/block/raw-format.c | ||
238 | index XXXXXXX..XXXXXXX 100644 | ||
239 | --- a/block/raw-format.c | ||
240 | +++ b/block/raw-format.c | ||
241 | @@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_raw = { | ||
242 | .bdrv_reopen_commit = &raw_reopen_commit, | ||
243 | .bdrv_reopen_abort = &raw_reopen_abort, | ||
244 | .bdrv_open = &raw_open, | ||
245 | - .bdrv_child_perm = bdrv_filter_default_perms, | ||
246 | + .bdrv_child_perm = bdrv_default_perms, | ||
247 | .bdrv_co_create_opts = &raw_co_create_opts, | ||
248 | .bdrv_co_preadv = &raw_co_preadv, | ||
249 | .bdrv_co_pwritev = &raw_co_pwritev, | ||
250 | diff --git a/block/throttle.c b/block/throttle.c | ||
251 | index XXXXXXX..XXXXXXX 100644 | ||
252 | --- a/block/throttle.c | ||
253 | +++ b/block/throttle.c | ||
254 | @@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_throttle = { | ||
255 | .bdrv_close = throttle_close, | ||
256 | .bdrv_co_flush = throttle_co_flush, | ||
257 | |||
258 | - .bdrv_child_perm = bdrv_filter_default_perms, | ||
259 | + .bdrv_child_perm = bdrv_default_perms, | ||
260 | |||
261 | .bdrv_getlength = throttle_getlength, | ||
262 | |||
263 | diff --git a/block/vdi.c b/block/vdi.c | ||
264 | index XXXXXXX..XXXXXXX 100644 | ||
265 | --- a/block/vdi.c | ||
266 | +++ b/block/vdi.c | ||
267 | @@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_vdi = { | ||
268 | .bdrv_open = vdi_open, | ||
269 | .bdrv_close = vdi_close, | ||
270 | .bdrv_reopen_prepare = vdi_reopen_prepare, | ||
271 | - .bdrv_child_perm = bdrv_format_default_perms, | ||
272 | + .bdrv_child_perm = bdrv_default_perms, | ||
273 | .bdrv_co_create = vdi_co_create, | ||
274 | .bdrv_co_create_opts = vdi_co_create_opts, | ||
275 | .bdrv_has_zero_init = vdi_has_zero_init, | ||
276 | diff --git a/block/vhdx.c b/block/vhdx.c | ||
277 | index XXXXXXX..XXXXXXX 100644 | ||
278 | --- a/block/vhdx.c | ||
279 | +++ b/block/vhdx.c | ||
280 | @@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_vhdx = { | ||
281 | .bdrv_open = vhdx_open, | ||
282 | .bdrv_close = vhdx_close, | ||
283 | .bdrv_reopen_prepare = vhdx_reopen_prepare, | ||
284 | - .bdrv_child_perm = bdrv_format_default_perms, | ||
285 | + .bdrv_child_perm = bdrv_default_perms, | ||
286 | .bdrv_co_readv = vhdx_co_readv, | ||
287 | .bdrv_co_writev = vhdx_co_writev, | ||
288 | .bdrv_co_create = vhdx_co_create, | ||
289 | diff --git a/block/vmdk.c b/block/vmdk.c | ||
290 | index XXXXXXX..XXXXXXX 100644 | ||
291 | --- a/block/vmdk.c | ||
292 | +++ b/block/vmdk.c | ||
293 | @@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_vmdk = { | ||
294 | .bdrv_open = vmdk_open, | ||
295 | .bdrv_co_check = vmdk_co_check, | ||
296 | .bdrv_reopen_prepare = vmdk_reopen_prepare, | ||
297 | - .bdrv_child_perm = bdrv_format_default_perms, | ||
298 | + .bdrv_child_perm = bdrv_default_perms, | ||
299 | .bdrv_co_preadv = vmdk_co_preadv, | ||
300 | .bdrv_co_pwritev = vmdk_co_pwritev, | ||
301 | .bdrv_co_pwritev_compressed = vmdk_co_pwritev_compressed, | ||
302 | diff --git a/block/vpc.c b/block/vpc.c | ||
303 | index XXXXXXX..XXXXXXX 100644 | ||
304 | --- a/block/vpc.c | ||
305 | +++ b/block/vpc.c | ||
306 | @@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_vpc = { | ||
307 | .bdrv_open = vpc_open, | ||
308 | .bdrv_close = vpc_close, | ||
309 | .bdrv_reopen_prepare = vpc_reopen_prepare, | ||
310 | - .bdrv_child_perm = bdrv_format_default_perms, | ||
311 | + .bdrv_child_perm = bdrv_default_perms, | ||
312 | .bdrv_co_create = vpc_co_create, | ||
313 | .bdrv_co_create_opts = vpc_co_create_opts, | ||
314 | |||
315 | diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c | ||
316 | index XXXXXXX..XXXXXXX 100644 | ||
317 | --- a/tests/test-bdrv-drain.c | ||
318 | +++ b/tests/test-bdrv-drain.c | ||
319 | @@ -XXX,XX +XXX,XX @@ static void bdrv_test_child_perm(BlockDriverState *bs, BdrvChild *c, | ||
320 | uint64_t *nperm, uint64_t *nshared) | ||
321 | { | 147 | { |
322 | /* | 148 | /* |
323 | - * bdrv_format_default_perms() accepts only these two, so disguise | 149 | * This check is designed for optimization shortcut so it must be |
324 | + * bdrv_default_perms() accepts only these two, so disguise | 150 | @@ -XXX,XX +XXX,XX @@ static int is_zero_cow(BlockDriverState *bs, QCowL2Meta *m) |
325 | * detach_by_driver_cb_parent as one of them. | 151 | m->cow_end.nb_bytes); |
326 | */ | ||
327 | if (child_class != &child_file && child_class != &child_of_bds) { | ||
328 | child_class = &child_of_bds; | ||
329 | } | ||
330 | |||
331 | - bdrv_format_default_perms(bs, c, child_class, role, reopen_queue, | ||
332 | - perm, shared, nperm, nshared); | ||
333 | + bdrv_default_perms(bs, c, child_class, role, reopen_queue, | ||
334 | + perm, shared, nperm, nshared); | ||
335 | } | 152 | } |
336 | 153 | ||
337 | static int bdrv_test_change_backing_file(BlockDriverState *bs, | 154 | -static int handle_alloc_space(BlockDriverState *bs, QCowL2Meta *l2meta) |
338 | @@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_test_top_driver = { | 155 | +static int coroutine_fn handle_alloc_space(BlockDriverState *bs, |
339 | .bdrv_close = bdrv_test_top_close, | 156 | + QCowL2Meta *l2meta) |
340 | .bdrv_co_preadv = bdrv_test_top_co_preadv, | 157 | { |
341 | 158 | BDRVQcow2State *s = bs->opaque; | |
342 | - .bdrv_child_perm = bdrv_format_default_perms, | 159 | QCowL2Meta *m; |
343 | + .bdrv_child_perm = bdrv_default_perms, | ||
344 | }; | ||
345 | |||
346 | typedef struct TestCoDeleteByDrainData { | ||
347 | @@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_replace_test = { | ||
348 | .bdrv_co_drain_begin = bdrv_replace_test_co_drain_begin, | ||
349 | .bdrv_co_drain_end = bdrv_replace_test_co_drain_end, | ||
350 | |||
351 | - .bdrv_child_perm = bdrv_format_default_perms, | ||
352 | + .bdrv_child_perm = bdrv_default_perms, | ||
353 | }; | ||
354 | |||
355 | static void coroutine_fn test_replace_child_mid_drain_read_co(void *opaque) | ||
356 | diff --git a/tests/test-bdrv-graph-mod.c b/tests/test-bdrv-graph-mod.c | ||
357 | index XXXXXXX..XXXXXXX 100644 | ||
358 | --- a/tests/test-bdrv-graph-mod.c | ||
359 | +++ b/tests/test-bdrv-graph-mod.c | ||
360 | @@ -XXX,XX +XXX,XX @@ | ||
361 | |||
362 | static BlockDriver bdrv_pass_through = { | ||
363 | .format_name = "pass-through", | ||
364 | - .bdrv_child_perm = bdrv_filter_default_perms, | ||
365 | + .bdrv_child_perm = bdrv_default_perms, | ||
366 | }; | ||
367 | |||
368 | static void no_perm_default_perms(BlockDriverState *bs, BdrvChild *c, | ||
369 | diff --git a/tests/test-block-iothread.c b/tests/test-block-iothread.c | ||
370 | index XXXXXXX..XXXXXXX 100644 | ||
371 | --- a/tests/test-block-iothread.c | ||
372 | +++ b/tests/test-block-iothread.c | ||
373 | @@ -XXX,XX +XXX,XX @@ static void test_propagate_basic(void) | ||
374 | BlockDriverState *bs_a, *bs_b, *bs_verify; | ||
375 | QDict *options; | ||
376 | |||
377 | - /* Create bs_a and its BlockBackend */ | ||
378 | - blk = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL); | ||
379 | + /* | ||
380 | + * Create bs_a and its BlockBackend. We cannot take the RESIZE | ||
381 | + * permission because blkverify will not share it on the test | ||
382 | + * image. | ||
383 | + */ | ||
384 | + blk = blk_new(qemu_get_aio_context(), BLK_PERM_ALL & ~BLK_PERM_RESIZE, | ||
385 | + BLK_PERM_ALL); | ||
386 | bs_a = bdrv_new_open_driver(&bdrv_test, "bs_a", BDRV_O_RDWR, &error_abort); | ||
387 | blk_insert_bs(blk, bs_a, &error_abort); | ||
388 | |||
389 | @@ -XXX,XX +XXX,XX @@ static void test_propagate_diamond(void) | ||
390 | qdict_put_str(options, "raw", "bs_c"); | ||
391 | |||
392 | bs_verify = bdrv_open(NULL, NULL, options, BDRV_O_RDWR, &error_abort); | ||
393 | - blk = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL); | ||
394 | + /* | ||
395 | + * Do not take the RESIZE permission: This would require the same | ||
396 | + * from bs_c and thus from bs_a; however, blkverify will not share | ||
397 | + * it on bs_b, and thus it will not be available for bs_a. | ||
398 | + */ | ||
399 | + blk = blk_new(qemu_get_aio_context(), BLK_PERM_ALL & ~BLK_PERM_RESIZE, | ||
400 | + BLK_PERM_ALL); | ||
401 | blk_insert_bs(blk, bs_verify, &error_abort); | ||
402 | |||
403 | /* Switch the AioContext */ | ||
404 | -- | 160 | -- |
405 | 2.25.4 | 161 | 2.37.3 |
406 | |||
407 | diff view generated by jsdifflib |
1 | test_overlapping_3() throttles its active commit job so it can be sure | 1 | From: Paolo Bonzini <pbonzini@redhat.com> |
---|---|---|---|
2 | the job is still busy when it checks that you can't start a conflicting | ||
3 | streaming job. | ||
4 | 2 | ||
5 | However, it only sets the commit job back to full speed when it is | 3 | Callers of coroutine_fn must be coroutine_fn themselves, or the call |
6 | ready, which takes a few seconds while it's throttled. We can already | 4 | must be within "if (qemu_in_coroutine())". Apply coroutine_fn to |
7 | reset the limit after having checked that block-stream returns an error | 5 | functions where this holds. |
8 | and save these seconds. | ||
9 | 6 | ||
10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 7 | Reviewed-by: Alberto Faria <afaria@redhat.com> |
11 | Message-Id: <20200513100025.33543-1-kwolf@redhat.com> | 8 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
12 | Reviewed-by: Alberto Garcia <berto@igalia.com> | 9 | Message-Id: <20220922084924.201610-16-pbonzini@redhat.com> |
10 | [kwolf: Fixed up coding style] | ||
11 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
13 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
14 | --- | 13 | --- |
15 | tests/qemu-iotests/030 | 6 +++--- | 14 | block/copy-before-write.c | 9 +++++---- |
16 | 1 file changed, 3 insertions(+), 3 deletions(-) | 15 | 1 file changed, 5 insertions(+), 4 deletions(-) |
17 | 16 | ||
18 | diff --git a/tests/qemu-iotests/030 b/tests/qemu-iotests/030 | 17 | diff --git a/block/copy-before-write.c b/block/copy-before-write.c |
19 | index XXXXXXX..XXXXXXX 100755 | 18 | index XXXXXXX..XXXXXXX 100644 |
20 | --- a/tests/qemu-iotests/030 | 19 | --- a/block/copy-before-write.c |
21 | +++ b/tests/qemu-iotests/030 | 20 | +++ b/block/copy-before-write.c |
22 | @@ -XXX,XX +XXX,XX @@ class TestParallelOps(iotests.QMPTestCase): | 21 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn cbw_co_flush(BlockDriverState *bs) |
23 | self.assert_qmp(result, 'error/desc', | 22 | * It's guaranteed that guest writes will not interact in the region until |
24 | "Node 'node5' is busy: block device is in use by block job: commit") | 23 | * cbw_snapshot_read_unlock() called. |
25 | 24 | */ | |
26 | + result = self.vm.qmp('block-job-set-speed', device='commit-drive0', speed=0) | 25 | -static BlockReq *cbw_snapshot_read_lock(BlockDriverState *bs, |
27 | + self.assert_qmp(result, 'return', {}) | 26 | - int64_t offset, int64_t bytes, |
28 | + | 27 | - int64_t *pnum, BdrvChild **file) |
29 | event = self.vm.event_wait(name='BLOCK_JOB_READY') | 28 | +static coroutine_fn BlockReq * |
30 | self.assert_qmp(event, 'data/device', 'commit-drive0') | 29 | +cbw_snapshot_read_lock(BlockDriverState *bs, int64_t offset, int64_t bytes, |
31 | self.assert_qmp(event, 'data/type', 'commit') | 30 | + int64_t *pnum, BdrvChild **file) |
32 | self.assert_qmp_absent(event, 'data/error') | 31 | { |
33 | 32 | BDRVCopyBeforeWriteState *s = bs->opaque; | |
34 | - result = self.vm.qmp('block-job-set-speed', device='commit-drive0', speed=0) | 33 | BlockReq *req = g_new(BlockReq, 1); |
35 | - self.assert_qmp(result, 'return', {}) | 34 | @@ -XXX,XX +XXX,XX @@ static BlockReq *cbw_snapshot_read_lock(BlockDriverState *bs, |
36 | - | 35 | return req; |
37 | result = self.vm.qmp('block-job-complete', device='commit-drive0') | 36 | } |
38 | self.assert_qmp(result, 'return', {}) | 37 | |
38 | -static void cbw_snapshot_read_unlock(BlockDriverState *bs, BlockReq *req) | ||
39 | +static coroutine_fn void | ||
40 | +cbw_snapshot_read_unlock(BlockDriverState *bs, BlockReq *req) | ||
41 | { | ||
42 | BDRVCopyBeforeWriteState *s = bs->opaque; | ||
39 | 43 | ||
40 | -- | 44 | -- |
41 | 2.25.4 | 45 | 2.37.3 |
42 | |||
43 | diff view generated by jsdifflib |
1 | From: Max Reitz <mreitz@redhat.com> | 1 | From: Paolo Bonzini <pbonzini@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Any current user of child_file, child_format, and child_backing can and | 3 | Callers of coroutine_fn must be coroutine_fn themselves, or the call |
4 | should use this generic BdrvChildClass instead, as it can handle all of | 4 | must be within "if (qemu_in_coroutine())". Apply coroutine_fn to |
5 | these cases. However, to be able to do so, the users must pass the | 5 | functions where this holds. |
6 | appropriate BdrvChildRole when the child is created/attached. (The | ||
7 | following commits will take care of that.) | ||
8 | 6 | ||
9 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 7 | Reviewed-by: Alberto Faria <afaria@redhat.com> |
10 | Message-Id: <20200513110544.176672-15-mreitz@redhat.com> | 8 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
11 | Reviewed-by: Eric Blake <eblake@redhat.com> | 9 | Message-Id: <20220922084924.201610-17-pbonzini@redhat.com> |
10 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
13 | --- | 12 | --- |
14 | include/block/block_int.h | 1 + | 13 | block/curl.c | 2 +- |
15 | block.c | 24 ++++++++++++++++++++++++ | 14 | 1 file changed, 1 insertion(+), 1 deletion(-) |
16 | 2 files changed, 25 insertions(+) | ||
17 | 15 | ||
18 | diff --git a/include/block/block_int.h b/include/block/block_int.h | 16 | diff --git a/block/curl.c b/block/curl.c |
19 | index XXXXXXX..XXXXXXX 100644 | 17 | index XXXXXXX..XXXXXXX 100644 |
20 | --- a/include/block/block_int.h | 18 | --- a/block/curl.c |
21 | +++ b/include/block/block_int.h | 19 | +++ b/block/curl.c |
22 | @@ -XXX,XX +XXX,XX @@ struct BdrvChildClass { | 20 | @@ -XXX,XX +XXX,XX @@ out_noclean: |
23 | void (*set_aio_ctx)(BdrvChild *child, AioContext *ctx, GSList **ignore); | 21 | return -EINVAL; |
24 | }; | ||
25 | |||
26 | +extern const BdrvChildClass child_of_bds; | ||
27 | extern const BdrvChildClass child_file; | ||
28 | extern const BdrvChildClass child_format; | ||
29 | extern const BdrvChildClass child_backing; | ||
30 | diff --git a/block.c b/block.c | ||
31 | index XXXXXXX..XXXXXXX 100644 | ||
32 | --- a/block.c | ||
33 | +++ b/block.c | ||
34 | @@ -XXX,XX +XXX,XX @@ static void bdrv_child_cb_detach(BdrvChild *child) | ||
35 | bdrv_unapply_subtree_drain(child, bs); | ||
36 | } | 22 | } |
37 | 23 | ||
38 | +static int bdrv_child_cb_update_filename(BdrvChild *c, BlockDriverState *base, | 24 | -static void curl_setup_preadv(BlockDriverState *bs, CURLAIOCB *acb) |
39 | + const char *filename, Error **errp) | 25 | +static void coroutine_fn curl_setup_preadv(BlockDriverState *bs, CURLAIOCB *acb) |
40 | +{ | ||
41 | + if (c->role & BDRV_CHILD_COW) { | ||
42 | + return bdrv_backing_update_filename(c, base, filename, errp); | ||
43 | + } | ||
44 | + return 0; | ||
45 | +} | ||
46 | + | ||
47 | +const BdrvChildClass child_of_bds = { | ||
48 | + .parent_is_bds = true, | ||
49 | + .get_parent_desc = bdrv_child_get_parent_desc, | ||
50 | + .inherit_options = bdrv_inherited_options, | ||
51 | + .drained_begin = bdrv_child_cb_drained_begin, | ||
52 | + .drained_poll = bdrv_child_cb_drained_poll, | ||
53 | + .drained_end = bdrv_child_cb_drained_end, | ||
54 | + .attach = bdrv_child_cb_attach, | ||
55 | + .detach = bdrv_child_cb_detach, | ||
56 | + .inactivate = bdrv_child_cb_inactivate, | ||
57 | + .can_set_aio_ctx = bdrv_child_cb_can_set_aio_ctx, | ||
58 | + .set_aio_ctx = bdrv_child_cb_set_aio_ctx, | ||
59 | + .update_filename = bdrv_child_cb_update_filename, | ||
60 | +}; | ||
61 | + | ||
62 | static int bdrv_open_flags(BlockDriverState *bs, int flags) | ||
63 | { | 26 | { |
64 | int open_flags = flags; | 27 | CURLState *state; |
28 | int running; | ||
65 | -- | 29 | -- |
66 | 2.25.4 | 30 | 2.37.3 |
67 | |||
68 | diff view generated by jsdifflib |
1 | From: Philippe Mathieu-Daudé <f4bug@amsat.org> | 1 | From: Paolo Bonzini <pbonzini@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | One might find interesting to look at AHCI IRQs. | 3 | Callers of coroutine_fn must be coroutine_fn themselves, or the call |
4 | must be within "if (qemu_in_coroutine())". Apply coroutine_fn to | ||
5 | functions where this holds. | ||
4 | 6 | ||
5 | Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org> | 7 | Reviewed-by: Alberto Faria <afaria@redhat.com> |
6 | Message-Id: <20200504094858.5975-1-f4bug@amsat.org> | 8 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
7 | Reviewed-by: John Snow <jsnow@redhat.com> | 9 | Message-Id: <20220922084924.201610-18-pbonzini@redhat.com> |
8 | Acked-by: John Snow <jsnow@redhat.com> | 10 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> |
9 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
10 | --- | 12 | --- |
11 | hw/ide/ahci.c | 1 + | 13 | block/qed.c | 4 ++-- |
12 | 1 file changed, 1 insertion(+) | 14 | 1 file changed, 2 insertions(+), 2 deletions(-) |
13 | 15 | ||
14 | diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c | 16 | diff --git a/block/qed.c b/block/qed.c |
15 | index XXXXXXX..XXXXXXX 100644 | 17 | index XXXXXXX..XXXXXXX 100644 |
16 | --- a/hw/ide/ahci.c | 18 | --- a/block/qed.c |
17 | +++ b/hw/ide/ahci.c | 19 | +++ b/block/qed.c |
18 | @@ -XXX,XX +XXX,XX @@ static void ahci_cmd_done(IDEDMA *dma) | 20 | @@ -XXX,XX +XXX,XX @@ static CachedL2Table *qed_new_l2_table(BDRVQEDState *s) |
19 | 21 | return l2_table; | |
20 | static void ahci_irq_set(void *opaque, int n, int level) | 22 | } |
23 | |||
24 | -static bool qed_plug_allocating_write_reqs(BDRVQEDState *s) | ||
25 | +static bool coroutine_fn qed_plug_allocating_write_reqs(BDRVQEDState *s) | ||
21 | { | 26 | { |
22 | + qemu_log_mask(LOG_UNIMP, "ahci: IRQ#%d level:%d\n", n, level); | 27 | qemu_co_mutex_lock(&s->table_lock); |
28 | |||
29 | @@ -XXX,XX +XXX,XX @@ static bool qed_plug_allocating_write_reqs(BDRVQEDState *s) | ||
30 | return true; | ||
23 | } | 31 | } |
24 | 32 | ||
25 | static const IDEDMAOps ahci_dma_ops = { | 33 | -static void qed_unplug_allocating_write_reqs(BDRVQEDState *s) |
34 | +static void coroutine_fn qed_unplug_allocating_write_reqs(BDRVQEDState *s) | ||
35 | { | ||
36 | qemu_co_mutex_lock(&s->table_lock); | ||
37 | assert(s->allocating_write_reqs_plugged); | ||
26 | -- | 38 | -- |
27 | 2.25.4 | 39 | 2.37.3 |
28 | |||
29 | diff view generated by jsdifflib |
1 | From: Max Reitz <mreitz@redhat.com> | 1 | From: Paolo Bonzini <pbonzini@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | This structure nearly only contains parent callbacks for child state | 3 | Callers of coroutine_fn must be coroutine_fn themselves, or the call |
4 | changes. It cannot really reflect a child's role, because different | 4 | must be within "if (qemu_in_coroutine())". Apply coroutine_fn to |
5 | roles may overlap (as we will see when real roles are introduced), and | 5 | functions where this holds. |
6 | because parents can have custom callbacks even when the child fulfills a | ||
7 | standard role. | ||
8 | 6 | ||
9 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 7 | Reviewed-by: Alberto Faria <afaria@redhat.com> |
10 | Reviewed-by: Eric Blake <eblake@redhat.com> | 8 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
11 | Reviewed-by: Alberto Garcia <berto@igalia.com> | 9 | Message-Id: <20220922084924.201610-19-pbonzini@redhat.com> |
12 | Message-Id: <20200513110544.176672-4-mreitz@redhat.com> | 10 | [kwolf: Fixed up coding style] |
11 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
13 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
14 | --- | 13 | --- |
15 | include/block/block.h | 6 +- | 14 | block/quorum.c | 36 +++++++++++++++++++----------------- |
16 | include/block/block_int.h | 22 +++--- | 15 | 1 file changed, 19 insertions(+), 17 deletions(-) |
17 | block.c | 142 ++++++++++++++++++------------------ | ||
18 | block/backup-top.c | 8 +- | ||
19 | block/blkdebug.c | 4 +- | ||
20 | block/blklogwrites.c | 8 +- | ||
21 | block/block-backend.c | 6 +- | ||
22 | block/commit.c | 2 +- | ||
23 | block/copy-on-read.c | 2 +- | ||
24 | block/io.c | 22 +++--- | ||
25 | block/mirror.c | 2 +- | ||
26 | block/quorum.c | 2 +- | ||
27 | block/replication.c | 2 +- | ||
28 | block/vvfat.c | 6 +- | ||
29 | blockjob.c | 2 +- | ||
30 | tests/test-bdrv-drain.c | 36 ++++----- | ||
31 | tests/test-bdrv-graph-mod.c | 2 +- | ||
32 | 17 files changed, 141 insertions(+), 133 deletions(-) | ||
33 | 16 | ||
34 | diff --git a/include/block/block.h b/include/block/block.h | ||
35 | index XXXXXXX..XXXXXXX 100644 | ||
36 | --- a/include/block/block.h | ||
37 | +++ b/include/block/block.h | ||
38 | @@ -XXX,XX +XXX,XX @@ | ||
39 | /* block.c */ | ||
40 | typedef struct BlockDriver BlockDriver; | ||
41 | typedef struct BdrvChild BdrvChild; | ||
42 | -typedef struct BdrvChildRole BdrvChildRole; | ||
43 | +typedef struct BdrvChildClass BdrvChildClass; | ||
44 | |||
45 | typedef struct BlockDriverInfo { | ||
46 | /* in bytes, 0 if irrelevant */ | ||
47 | @@ -XXX,XX +XXX,XX @@ int bdrv_parse_discard_flags(const char *mode, int *flags); | ||
48 | BdrvChild *bdrv_open_child(const char *filename, | ||
49 | QDict *options, const char *bdref_key, | ||
50 | BlockDriverState* parent, | ||
51 | - const BdrvChildRole *child_role, | ||
52 | + const BdrvChildClass *child_class, | ||
53 | bool allow_none, Error **errp); | ||
54 | BlockDriverState *bdrv_open_blockdev_ref(BlockdevRef *ref, Error **errp); | ||
55 | void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd, | ||
56 | @@ -XXX,XX +XXX,XX @@ void bdrv_unref_child(BlockDriverState *parent, BdrvChild *child); | ||
57 | BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs, | ||
58 | BlockDriverState *child_bs, | ||
59 | const char *child_name, | ||
60 | - const BdrvChildRole *child_role, | ||
61 | + const BdrvChildClass *child_class, | ||
62 | Error **errp); | ||
63 | |||
64 | bool bdrv_op_is_blocked(BlockDriverState *bs, BlockOpType op, Error **errp); | ||
65 | diff --git a/include/block/block_int.h b/include/block/block_int.h | ||
66 | index XXXXXXX..XXXXXXX 100644 | ||
67 | --- a/include/block/block_int.h | ||
68 | +++ b/include/block/block_int.h | ||
69 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { | ||
70 | * the parents in @parent_perm and @parent_shared. | ||
71 | * | ||
72 | * If @c is NULL, return the permissions for attaching a new child for the | ||
73 | - * given @role. | ||
74 | + * given @child_class. | ||
75 | * | ||
76 | * If @reopen_queue is non-NULL, don't return the currently needed | ||
77 | * permissions, but those that will be needed after applying the | ||
78 | * @reopen_queue. | ||
79 | */ | ||
80 | void (*bdrv_child_perm)(BlockDriverState *bs, BdrvChild *c, | ||
81 | - const BdrvChildRole *role, | ||
82 | + const BdrvChildClass *child_class, | ||
83 | BlockReopenQueue *reopen_queue, | ||
84 | uint64_t parent_perm, uint64_t parent_shared, | ||
85 | uint64_t *nperm, uint64_t *nshared); | ||
86 | @@ -XXX,XX +XXX,XX @@ typedef struct BdrvAioNotifier { | ||
87 | QLIST_ENTRY(BdrvAioNotifier) list; | ||
88 | } BdrvAioNotifier; | ||
89 | |||
90 | -struct BdrvChildRole { | ||
91 | +struct BdrvChildClass { | ||
92 | /* If true, bdrv_replace_node() doesn't change the node this BdrvChild | ||
93 | * points to. */ | ||
94 | bool stay_at_node; | ||
95 | @@ -XXX,XX +XXX,XX @@ struct BdrvChildRole { | ||
96 | void (*set_aio_ctx)(BdrvChild *child, AioContext *ctx, GSList **ignore); | ||
97 | }; | ||
98 | |||
99 | -extern const BdrvChildRole child_file; | ||
100 | -extern const BdrvChildRole child_format; | ||
101 | -extern const BdrvChildRole child_backing; | ||
102 | +extern const BdrvChildClass child_file; | ||
103 | +extern const BdrvChildClass child_format; | ||
104 | +extern const BdrvChildClass child_backing; | ||
105 | |||
106 | struct BdrvChild { | ||
107 | BlockDriverState *bs; | ||
108 | char *name; | ||
109 | - const BdrvChildRole *role; | ||
110 | + const BdrvChildClass *klass; | ||
111 | void *opaque; | ||
112 | |||
113 | /** | ||
114 | @@ -XXX,XX +XXX,XX @@ struct BdrvChild { | ||
115 | |||
116 | /* | ||
117 | * How many times the parent of this child has been drained | ||
118 | - * (through role->drained_*). | ||
119 | + * (through klass->drained_*). | ||
120 | * Usually, this is equal to bs->quiesce_counter (potentially | ||
121 | * reduced by bdrv_drain_all_count). It may differ while the | ||
122 | * child is entering or leaving a drained section. | ||
123 | @@ -XXX,XX +XXX,XX @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, | ||
124 | |||
125 | BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs, | ||
126 | const char *child_name, | ||
127 | - const BdrvChildRole *child_role, | ||
128 | + const BdrvChildClass *child_class, | ||
129 | AioContext *ctx, | ||
130 | uint64_t perm, uint64_t shared_perm, | ||
131 | void *opaque, Error **errp); | ||
132 | @@ -XXX,XX +XXX,XX @@ int bdrv_child_refresh_perms(BlockDriverState *bs, BdrvChild *c, Error **errp); | ||
133 | * block filters: Forward CONSISTENT_READ, WRITE, WRITE_UNCHANGED and RESIZE to | ||
134 | * all children */ | ||
135 | void bdrv_filter_default_perms(BlockDriverState *bs, BdrvChild *c, | ||
136 | - const BdrvChildRole *role, | ||
137 | + const BdrvChildClass *child_class, | ||
138 | BlockReopenQueue *reopen_queue, | ||
139 | uint64_t perm, uint64_t shared, | ||
140 | uint64_t *nperm, uint64_t *nshared); | ||
141 | @@ -XXX,XX +XXX,XX @@ void bdrv_filter_default_perms(BlockDriverState *bs, BdrvChild *c, | ||
142 | * requires WRITE | RESIZE for read-write images, always requires | ||
143 | * CONSISTENT_READ and doesn't share WRITE. */ | ||
144 | void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c, | ||
145 | - const BdrvChildRole *role, | ||
146 | + const BdrvChildClass *child_class, | ||
147 | BlockReopenQueue *reopen_queue, | ||
148 | uint64_t perm, uint64_t shared, | ||
149 | uint64_t *nperm, uint64_t *nshared); | ||
150 | diff --git a/block.c b/block.c | ||
151 | index XXXXXXX..XXXXXXX 100644 | ||
152 | --- a/block.c | ||
153 | +++ b/block.c | ||
154 | @@ -XXX,XX +XXX,XX @@ static BlockDriverState *bdrv_open_inherit(const char *filename, | ||
155 | const char *reference, | ||
156 | QDict *options, int flags, | ||
157 | BlockDriverState *parent, | ||
158 | - const BdrvChildRole *child_role, | ||
159 | + const BdrvChildClass *child_class, | ||
160 | Error **errp); | ||
161 | |||
162 | /* If non-zero, use only whitelisted block drivers */ | ||
163 | @@ -XXX,XX +XXX,XX @@ static void bdrv_inherited_options(int *child_flags, QDict *child_options, | ||
164 | *child_flags = flags; | ||
165 | } | ||
166 | |||
167 | -const BdrvChildRole child_file = { | ||
168 | +const BdrvChildClass child_file = { | ||
169 | .parent_is_bds = true, | ||
170 | .get_parent_desc = bdrv_child_get_parent_desc, | ||
171 | .inherit_options = bdrv_inherited_options, | ||
172 | @@ -XXX,XX +XXX,XX @@ static void bdrv_inherited_fmt_options(int *child_flags, QDict *child_options, | ||
173 | *child_flags &= ~(BDRV_O_PROTOCOL | BDRV_O_NO_IO); | ||
174 | } | ||
175 | |||
176 | -const BdrvChildRole child_format = { | ||
177 | +const BdrvChildClass child_format = { | ||
178 | .parent_is_bds = true, | ||
179 | .get_parent_desc = bdrv_child_get_parent_desc, | ||
180 | .inherit_options = bdrv_inherited_fmt_options, | ||
181 | @@ -XXX,XX +XXX,XX @@ static int bdrv_backing_update_filename(BdrvChild *c, BlockDriverState *base, | ||
182 | return ret; | ||
183 | } | ||
184 | |||
185 | -const BdrvChildRole child_backing = { | ||
186 | +const BdrvChildClass child_backing = { | ||
187 | .parent_is_bds = true, | ||
188 | .get_parent_desc = bdrv_child_get_parent_desc, | ||
189 | .attach = bdrv_backing_attach, | ||
190 | @@ -XXX,XX +XXX,XX @@ bool bdrv_is_writable(BlockDriverState *bs) | ||
191 | } | ||
192 | |||
193 | static void bdrv_child_perm(BlockDriverState *bs, BlockDriverState *child_bs, | ||
194 | - BdrvChild *c, const BdrvChildRole *role, | ||
195 | + BdrvChild *c, const BdrvChildClass *child_class, | ||
196 | BlockReopenQueue *reopen_queue, | ||
197 | uint64_t parent_perm, uint64_t parent_shared, | ||
198 | uint64_t *nperm, uint64_t *nshared) | ||
199 | { | ||
200 | assert(bs->drv && bs->drv->bdrv_child_perm); | ||
201 | - bs->drv->bdrv_child_perm(bs, c, role, reopen_queue, | ||
202 | + bs->drv->bdrv_child_perm(bs, c, child_class, reopen_queue, | ||
203 | parent_perm, parent_shared, | ||
204 | nperm, nshared); | ||
205 | /* TODO Take force_share from reopen_queue */ | ||
206 | @@ -XXX,XX +XXX,XX @@ static int bdrv_check_perm(BlockDriverState *bs, BlockReopenQueue *q, | ||
207 | uint64_t cur_perm, cur_shared; | ||
208 | bool child_tighten_restr; | ||
209 | |||
210 | - bdrv_child_perm(bs, c->bs, c, c->role, q, | ||
211 | + bdrv_child_perm(bs, c->bs, c, c->klass, q, | ||
212 | cumulative_perms, cumulative_shared_perms, | ||
213 | &cur_perm, &cur_shared); | ||
214 | ret = bdrv_child_check_perm(c, q, cur_perm, cur_shared, ignore_children, | ||
215 | @@ -XXX,XX +XXX,XX @@ static void bdrv_set_perm(BlockDriverState *bs, uint64_t cumulative_perms, | ||
216 | /* Update all children */ | ||
217 | QLIST_FOREACH(c, &bs->children, next) { | ||
218 | uint64_t cur_perm, cur_shared; | ||
219 | - bdrv_child_perm(bs, c->bs, c, c->role, NULL, | ||
220 | + bdrv_child_perm(bs, c->bs, c, c->klass, NULL, | ||
221 | cumulative_perms, cumulative_shared_perms, | ||
222 | &cur_perm, &cur_shared); | ||
223 | bdrv_child_set_perm(c, cur_perm, cur_shared); | ||
224 | @@ -XXX,XX +XXX,XX @@ void bdrv_get_cumulative_perm(BlockDriverState *bs, uint64_t *perm, | ||
225 | |||
226 | static char *bdrv_child_user_desc(BdrvChild *c) | ||
227 | { | ||
228 | - if (c->role->get_parent_desc) { | ||
229 | - return c->role->get_parent_desc(c); | ||
230 | + if (c->klass->get_parent_desc) { | ||
231 | + return c->klass->get_parent_desc(c); | ||
232 | } | ||
233 | |||
234 | return g_strdup("another user"); | ||
235 | @@ -XXX,XX +XXX,XX @@ int bdrv_child_refresh_perms(BlockDriverState *bs, BdrvChild *c, Error **errp) | ||
236 | uint64_t perms, shared; | ||
237 | |||
238 | bdrv_get_cumulative_perm(bs, &parent_perms, &parent_shared); | ||
239 | - bdrv_child_perm(bs, c->bs, c, c->role, NULL, parent_perms, parent_shared, | ||
240 | + bdrv_child_perm(bs, c->bs, c, c->klass, NULL, parent_perms, parent_shared, | ||
241 | &perms, &shared); | ||
242 | |||
243 | return bdrv_child_try_set_perm(c, perms, shared, errp); | ||
244 | } | ||
245 | |||
246 | void bdrv_filter_default_perms(BlockDriverState *bs, BdrvChild *c, | ||
247 | - const BdrvChildRole *role, | ||
248 | + const BdrvChildClass *child_class, | ||
249 | BlockReopenQueue *reopen_queue, | ||
250 | uint64_t perm, uint64_t shared, | ||
251 | uint64_t *nperm, uint64_t *nshared) | ||
252 | @@ -XXX,XX +XXX,XX @@ void bdrv_filter_default_perms(BlockDriverState *bs, BdrvChild *c, | ||
253 | } | ||
254 | |||
255 | void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c, | ||
256 | - const BdrvChildRole *role, | ||
257 | + const BdrvChildClass *child_class, | ||
258 | BlockReopenQueue *reopen_queue, | ||
259 | uint64_t perm, uint64_t shared, | ||
260 | uint64_t *nperm, uint64_t *nshared) | ||
261 | { | ||
262 | - bool backing = (role == &child_backing); | ||
263 | - assert(role == &child_backing || role == &child_file); | ||
264 | + bool backing = (child_class == &child_backing); | ||
265 | + assert(child_class == &child_backing || child_class == &child_file); | ||
266 | |||
267 | if (!backing) { | ||
268 | int flags = bdrv_reopen_get_flags(reopen_queue, bs); | ||
269 | |||
270 | /* Apart from the modifications below, the same permissions are | ||
271 | * forwarded and left alone as for filters */ | ||
272 | - bdrv_filter_default_perms(bs, c, role, reopen_queue, perm, shared, | ||
273 | - &perm, &shared); | ||
274 | + bdrv_filter_default_perms(bs, c, child_class, reopen_queue, | ||
275 | + perm, shared, &perm, &shared); | ||
276 | |||
277 | /* Format drivers may touch metadata even if the guest doesn't write */ | ||
278 | if (bdrv_is_writable_after_reopen(bs, reopen_queue)) { | ||
279 | @@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_noperm(BdrvChild *child, | ||
280 | * If the new child node is drained but the old one was not, flush | ||
281 | * all outstanding requests to the old child node. | ||
282 | */ | ||
283 | - while (drain_saldo > 0 && child->role->drained_begin) { | ||
284 | + while (drain_saldo > 0 && child->klass->drained_begin) { | ||
285 | bdrv_parent_drained_begin_single(child, true); | ||
286 | drain_saldo--; | ||
287 | } | ||
288 | @@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_noperm(BdrvChild *child, | ||
289 | /* Detach first so that the recursive drain sections coming from @child | ||
290 | * are already gone and we only end the drain sections that came from | ||
291 | * elsewhere. */ | ||
292 | - if (child->role->detach) { | ||
293 | - child->role->detach(child); | ||
294 | + if (child->klass->detach) { | ||
295 | + child->klass->detach(child); | ||
296 | } | ||
297 | QLIST_REMOVE(child, next_parent); | ||
298 | } | ||
299 | @@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_noperm(BdrvChild *child, | ||
300 | /* Attach only after starting new drained sections, so that recursive | ||
301 | * drain sections coming from @child don't get an extra .drained_begin | ||
302 | * callback. */ | ||
303 | - if (child->role->attach) { | ||
304 | - child->role->attach(child); | ||
305 | + if (child->klass->attach) { | ||
306 | + child->klass->attach(child); | ||
307 | } | ||
308 | } | ||
309 | |||
310 | @@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_noperm(BdrvChild *child, | ||
311 | * If the old child node was drained but the new one is not, allow | ||
312 | * requests to come in only after the new node has been attached. | ||
313 | */ | ||
314 | - while (drain_saldo < 0 && child->role->drained_end) { | ||
315 | + while (drain_saldo < 0 && child->klass->drained_end) { | ||
316 | bdrv_parent_drained_end_single(child); | ||
317 | drain_saldo++; | ||
318 | } | ||
319 | @@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child(BdrvChild *child, BlockDriverState *new_bs) | ||
320 | */ | ||
321 | BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs, | ||
322 | const char *child_name, | ||
323 | - const BdrvChildRole *child_role, | ||
324 | + const BdrvChildClass *child_class, | ||
325 | AioContext *ctx, | ||
326 | uint64_t perm, uint64_t shared_perm, | ||
327 | void *opaque, Error **errp) | ||
328 | @@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs, | ||
329 | *child = (BdrvChild) { | ||
330 | .bs = NULL, | ||
331 | .name = g_strdup(child_name), | ||
332 | - .role = child_role, | ||
333 | + .klass = child_class, | ||
334 | .perm = perm, | ||
335 | .shared_perm = shared_perm, | ||
336 | .opaque = opaque, | ||
337 | @@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs, | ||
338 | * try moving the parent into the AioContext of child_bs instead. */ | ||
339 | if (bdrv_get_aio_context(child_bs) != ctx) { | ||
340 | ret = bdrv_try_set_aio_context(child_bs, ctx, &local_err); | ||
341 | - if (ret < 0 && child_role->can_set_aio_ctx) { | ||
342 | + if (ret < 0 && child_class->can_set_aio_ctx) { | ||
343 | GSList *ignore = g_slist_prepend(NULL, child); | ||
344 | ctx = bdrv_get_aio_context(child_bs); | ||
345 | - if (child_role->can_set_aio_ctx(child, ctx, &ignore, NULL)) { | ||
346 | + if (child_class->can_set_aio_ctx(child, ctx, &ignore, NULL)) { | ||
347 | error_free(local_err); | ||
348 | ret = 0; | ||
349 | g_slist_free(ignore); | ||
350 | ignore = g_slist_prepend(NULL, child); | ||
351 | - child_role->set_aio_ctx(child, ctx, &ignore); | ||
352 | + child_class->set_aio_ctx(child, ctx, &ignore); | ||
353 | } | ||
354 | g_slist_free(ignore); | ||
355 | } | ||
356 | @@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs, | ||
357 | BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs, | ||
358 | BlockDriverState *child_bs, | ||
359 | const char *child_name, | ||
360 | - const BdrvChildRole *child_role, | ||
361 | + const BdrvChildClass *child_class, | ||
362 | Error **errp) | ||
363 | { | ||
364 | BdrvChild *child; | ||
365 | @@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs, | ||
366 | bdrv_get_cumulative_perm(parent_bs, &perm, &shared_perm); | ||
367 | |||
368 | assert(parent_bs->drv); | ||
369 | - bdrv_child_perm(parent_bs, child_bs, NULL, child_role, NULL, | ||
370 | + bdrv_child_perm(parent_bs, child_bs, NULL, child_class, NULL, | ||
371 | perm, shared_perm, &perm, &shared_perm); | ||
372 | |||
373 | - child = bdrv_root_attach_child(child_bs, child_name, child_role, | ||
374 | + child = bdrv_root_attach_child(child_bs, child_name, child_class, | ||
375 | bdrv_get_aio_context(parent_bs), | ||
376 | perm, shared_perm, parent_bs, errp); | ||
377 | if (child == NULL) { | ||
378 | @@ -XXX,XX +XXX,XX @@ static void bdrv_parent_cb_change_media(BlockDriverState *bs, bool load) | ||
379 | { | ||
380 | BdrvChild *c; | ||
381 | QLIST_FOREACH(c, &bs->parents, next_parent) { | ||
382 | - if (c->role->change_media) { | ||
383 | - c->role->change_media(c, load); | ||
384 | + if (c->klass->change_media) { | ||
385 | + c->klass->change_media(c, load); | ||
386 | } | ||
387 | } | ||
388 | } | ||
389 | @@ -XXX,XX +XXX,XX @@ free_exit: | ||
390 | |||
391 | static BlockDriverState * | ||
392 | bdrv_open_child_bs(const char *filename, QDict *options, const char *bdref_key, | ||
393 | - BlockDriverState *parent, const BdrvChildRole *child_role, | ||
394 | + BlockDriverState *parent, const BdrvChildClass *child_class, | ||
395 | bool allow_none, Error **errp) | ||
396 | { | ||
397 | BlockDriverState *bs = NULL; | ||
398 | @@ -XXX,XX +XXX,XX @@ bdrv_open_child_bs(const char *filename, QDict *options, const char *bdref_key, | ||
399 | char *bdref_key_dot; | ||
400 | const char *reference; | ||
401 | |||
402 | - assert(child_role != NULL); | ||
403 | + assert(child_class != NULL); | ||
404 | |||
405 | bdref_key_dot = g_strdup_printf("%s.", bdref_key); | ||
406 | qdict_extract_subqdict(options, &image_options, bdref_key_dot); | ||
407 | @@ -XXX,XX +XXX,XX @@ bdrv_open_child_bs(const char *filename, QDict *options, const char *bdref_key, | ||
408 | } | ||
409 | |||
410 | bs = bdrv_open_inherit(filename, reference, image_options, 0, | ||
411 | - parent, child_role, errp); | ||
412 | + parent, child_class, errp); | ||
413 | if (!bs) { | ||
414 | goto done; | ||
415 | } | ||
416 | @@ -XXX,XX +XXX,XX @@ done: | ||
417 | BdrvChild *bdrv_open_child(const char *filename, | ||
418 | QDict *options, const char *bdref_key, | ||
419 | BlockDriverState *parent, | ||
420 | - const BdrvChildRole *child_role, | ||
421 | + const BdrvChildClass *child_class, | ||
422 | bool allow_none, Error **errp) | ||
423 | { | ||
424 | BlockDriverState *bs; | ||
425 | |||
426 | - bs = bdrv_open_child_bs(filename, options, bdref_key, parent, child_role, | ||
427 | + bs = bdrv_open_child_bs(filename, options, bdref_key, parent, child_class, | ||
428 | allow_none, errp); | ||
429 | if (bs == NULL) { | ||
430 | return NULL; | ||
431 | } | ||
432 | |||
433 | - return bdrv_attach_child(parent, bs, bdref_key, child_role, errp); | ||
434 | + return bdrv_attach_child(parent, bs, bdref_key, child_class, errp); | ||
435 | } | ||
436 | |||
437 | -/* TODO Future callers may need to specify parent/child_role in order for | ||
438 | - * option inheritance to work. Existing callers use it for the root node. */ | ||
439 | +/* | ||
440 | + * TODO Future callers may need to specify parent/child_class in order for | ||
441 | + * option inheritance to work. Existing callers use it for the root node. | ||
442 | + */ | ||
443 | BlockDriverState *bdrv_open_blockdev_ref(BlockdevRef *ref, Error **errp) | ||
444 | { | ||
445 | BlockDriverState *bs = NULL; | ||
446 | @@ -XXX,XX +XXX,XX @@ static BlockDriverState *bdrv_open_inherit(const char *filename, | ||
447 | const char *reference, | ||
448 | QDict *options, int flags, | ||
449 | BlockDriverState *parent, | ||
450 | - const BdrvChildRole *child_role, | ||
451 | + const BdrvChildClass *child_class, | ||
452 | Error **errp) | ||
453 | { | ||
454 | int ret; | ||
455 | @@ -XXX,XX +XXX,XX @@ static BlockDriverState *bdrv_open_inherit(const char *filename, | ||
456 | QDict *snapshot_options = NULL; | ||
457 | int snapshot_flags = 0; | ||
458 | |||
459 | - assert(!child_role || !flags); | ||
460 | - assert(!child_role == !parent); | ||
461 | + assert(!child_class || !flags); | ||
462 | + assert(!child_class == !parent); | ||
463 | |||
464 | if (reference) { | ||
465 | bool options_non_empty = options ? qdict_size(options) : false; | ||
466 | @@ -XXX,XX +XXX,XX @@ static BlockDriverState *bdrv_open_inherit(const char *filename, | ||
467 | |||
468 | bs->explicit_options = qdict_clone_shallow(options); | ||
469 | |||
470 | - if (child_role) { | ||
471 | + if (child_class) { | ||
472 | bs->inherits_from = parent; | ||
473 | - child_role->inherit_options(&flags, options, | ||
474 | - parent->open_flags, parent->options); | ||
475 | + child_class->inherit_options(&flags, options, | ||
476 | + parent->open_flags, parent->options); | ||
477 | } | ||
478 | |||
479 | ret = bdrv_fill_options(&options, filename, &flags, &local_err); | ||
480 | @@ -XXX,XX +XXX,XX @@ static bool bdrv_recurse_has_child(BlockDriverState *bs, | ||
481 | static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue, | ||
482 | BlockDriverState *bs, | ||
483 | QDict *options, | ||
484 | - const BdrvChildRole *role, | ||
485 | + const BdrvChildClass *klass, | ||
486 | QDict *parent_options, | ||
487 | int parent_flags, | ||
488 | bool keep_old_opts) | ||
489 | @@ -XXX,XX +XXX,XX @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue, | ||
490 | /* Inherit from parent node */ | ||
491 | if (parent_options) { | ||
492 | flags = 0; | ||
493 | - role->inherit_options(&flags, options, parent_flags, parent_options); | ||
494 | + klass->inherit_options(&flags, options, parent_flags, parent_options); | ||
495 | } else { | ||
496 | flags = bdrv_get_flags(bs); | ||
497 | } | ||
498 | @@ -XXX,XX +XXX,XX @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue, | ||
499 | } | ||
500 | |||
501 | bdrv_reopen_queue_child(bs_queue, child->bs, new_child_options, | ||
502 | - child->role, options, flags, child_keep_old); | ||
503 | + child->klass, options, flags, child_keep_old); | ||
504 | } | ||
505 | |||
506 | return bs_queue; | ||
507 | @@ -XXX,XX +XXX,XX @@ static void bdrv_reopen_perm(BlockReopenQueue *q, BlockDriverState *bs, | ||
508 | } else { | ||
509 | uint64_t nperm, nshared; | ||
510 | |||
511 | - bdrv_child_perm(parent->state.bs, bs, c, c->role, q, | ||
512 | + bdrv_child_perm(parent->state.bs, bs, c, c->klass, q, | ||
513 | parent->state.perm, parent->state.shared_perm, | ||
514 | &nperm, &nshared); | ||
515 | |||
516 | @@ -XXX,XX +XXX,XX @@ static bool should_update_child(BdrvChild *c, BlockDriverState *to) | ||
517 | GHashTable *found; | ||
518 | bool ret; | ||
519 | |||
520 | - if (c->role->stay_at_node) { | ||
521 | + if (c->klass->stay_at_node) { | ||
522 | return false; | ||
523 | } | ||
524 | |||
525 | @@ -XXX,XX +XXX,XX @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base, | ||
526 | } | ||
527 | |||
528 | /* If so, update the backing file path in the image file */ | ||
529 | - if (c->role->update_filename) { | ||
530 | - ret = c->role->update_filename(c, base, backing_file_str, | ||
531 | - &local_err); | ||
532 | + if (c->klass->update_filename) { | ||
533 | + ret = c->klass->update_filename(c, base, backing_file_str, | ||
534 | + &local_err); | ||
535 | if (ret < 0) { | ||
536 | bdrv_abort_perm_update(base); | ||
537 | error_report_err(local_err); | ||
538 | @@ -XXX,XX +XXX,XX @@ const char *bdrv_get_parent_name(const BlockDriverState *bs) | ||
539 | |||
540 | /* If multiple parents have a name, just pick the first one. */ | ||
541 | QLIST_FOREACH(c, &bs->parents, next_parent) { | ||
542 | - if (c->role->get_name) { | ||
543 | - name = c->role->get_name(c); | ||
544 | + if (c->klass->get_name) { | ||
545 | + name = c->klass->get_name(c); | ||
546 | if (name && *name) { | ||
547 | return name; | ||
548 | } | ||
549 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs, | ||
550 | } | ||
551 | |||
552 | QLIST_FOREACH(parent, &bs->parents, next_parent) { | ||
553 | - if (parent->role->activate) { | ||
554 | - parent->role->activate(parent, &local_err); | ||
555 | + if (parent->klass->activate) { | ||
556 | + parent->klass->activate(parent, &local_err); | ||
557 | if (local_err) { | ||
558 | bs->open_flags |= BDRV_O_INACTIVE; | ||
559 | error_propagate(errp, local_err); | ||
560 | @@ -XXX,XX +XXX,XX @@ static bool bdrv_has_bds_parent(BlockDriverState *bs, bool only_active) | ||
561 | BdrvChild *parent; | ||
562 | |||
563 | QLIST_FOREACH(parent, &bs->parents, next_parent) { | ||
564 | - if (parent->role->parent_is_bds) { | ||
565 | + if (parent->klass->parent_is_bds) { | ||
566 | BlockDriverState *parent_bs = parent->opaque; | ||
567 | if (!only_active || !(parent_bs->open_flags & BDRV_O_INACTIVE)) { | ||
568 | return true; | ||
569 | @@ -XXX,XX +XXX,XX @@ static int bdrv_inactivate_recurse(BlockDriverState *bs) | ||
570 | } | ||
571 | |||
572 | QLIST_FOREACH(parent, &bs->parents, next_parent) { | ||
573 | - if (parent->role->inactivate) { | ||
574 | - ret = parent->role->inactivate(parent); | ||
575 | + if (parent->klass->inactivate) { | ||
576 | + ret = parent->klass->inactivate(parent); | ||
577 | if (ret < 0) { | ||
578 | return ret; | ||
579 | } | ||
580 | @@ -XXX,XX +XXX,XX @@ void bdrv_set_aio_context_ignore(BlockDriverState *bs, | ||
581 | if (g_slist_find(*ignore, child)) { | ||
582 | continue; | ||
583 | } | ||
584 | - assert(child->role->set_aio_ctx); | ||
585 | + assert(child->klass->set_aio_ctx); | ||
586 | *ignore = g_slist_prepend(*ignore, child); | ||
587 | - child->role->set_aio_ctx(child, new_context, ignore); | ||
588 | + child->klass->set_aio_ctx(child, new_context, ignore); | ||
589 | } | ||
590 | |||
591 | bdrv_detach_aio_context(bs); | ||
592 | @@ -XXX,XX +XXX,XX @@ static bool bdrv_parent_can_set_aio_context(BdrvChild *c, AioContext *ctx, | ||
593 | } | ||
594 | *ignore = g_slist_prepend(*ignore, c); | ||
595 | |||
596 | - /* A BdrvChildRole that doesn't handle AioContext changes cannot | ||
597 | - * tolerate any AioContext changes */ | ||
598 | - if (!c->role->can_set_aio_ctx) { | ||
599 | + /* | ||
600 | + * A BdrvChildClass that doesn't handle AioContext changes cannot | ||
601 | + * tolerate any AioContext changes | ||
602 | + */ | ||
603 | + if (!c->klass->can_set_aio_ctx) { | ||
604 | char *user = bdrv_child_user_desc(c); | ||
605 | error_setg(errp, "Changing iothreads is not supported by %s", user); | ||
606 | g_free(user); | ||
607 | return false; | ||
608 | } | ||
609 | - if (!c->role->can_set_aio_ctx(c, ctx, ignore, errp)) { | ||
610 | + if (!c->klass->can_set_aio_ctx(c, ctx, ignore, errp)) { | ||
611 | assert(!errp || *errp); | ||
612 | return false; | ||
613 | } | ||
614 | @@ -XXX,XX +XXX,XX @@ void bdrv_refresh_filename(BlockDriverState *bs) | ||
615 | drv->bdrv_gather_child_options(bs, opts, backing_overridden); | ||
616 | } else { | ||
617 | QLIST_FOREACH(child, &bs->children, next) { | ||
618 | - if (child->role == &child_backing && !backing_overridden) { | ||
619 | + if (child->klass == &child_backing && !backing_overridden) { | ||
620 | /* We can skip the backing BDS if it has not been overridden */ | ||
621 | continue; | ||
622 | } | ||
623 | diff --git a/block/backup-top.c b/block/backup-top.c | ||
624 | index XXXXXXX..XXXXXXX 100644 | ||
625 | --- a/block/backup-top.c | ||
626 | +++ b/block/backup-top.c | ||
627 | @@ -XXX,XX +XXX,XX @@ static void backup_top_refresh_filename(BlockDriverState *bs) | ||
628 | } | ||
629 | |||
630 | static void backup_top_child_perm(BlockDriverState *bs, BdrvChild *c, | ||
631 | - const BdrvChildRole *role, | ||
632 | + const BdrvChildClass *child_class, | ||
633 | BlockReopenQueue *reopen_queue, | ||
634 | uint64_t perm, uint64_t shared, | ||
635 | uint64_t *nperm, uint64_t *nshared) | ||
636 | @@ -XXX,XX +XXX,XX @@ static void backup_top_child_perm(BlockDriverState *bs, BdrvChild *c, | ||
637 | return; | ||
638 | } | ||
639 | |||
640 | - if (role == &child_file) { | ||
641 | + if (child_class == &child_file) { | ||
642 | /* | ||
643 | * Target child | ||
644 | * | ||
645 | @@ -XXX,XX +XXX,XX @@ static void backup_top_child_perm(BlockDriverState *bs, BdrvChild *c, | ||
646 | *nperm = BLK_PERM_WRITE; | ||
647 | } else { | ||
648 | /* Source child */ | ||
649 | - bdrv_filter_default_perms(bs, c, role, reopen_queue, perm, shared, | ||
650 | - nperm, nshared); | ||
651 | + bdrv_filter_default_perms(bs, c, child_class, reopen_queue, | ||
652 | + perm, shared, nperm, nshared); | ||
653 | |||
654 | if (perm & BLK_PERM_WRITE) { | ||
655 | *nperm = *nperm | BLK_PERM_CONSISTENT_READ; | ||
656 | diff --git a/block/blkdebug.c b/block/blkdebug.c | ||
657 | index XXXXXXX..XXXXXXX 100644 | ||
658 | --- a/block/blkdebug.c | ||
659 | +++ b/block/blkdebug.c | ||
660 | @@ -XXX,XX +XXX,XX @@ static int blkdebug_reopen_prepare(BDRVReopenState *reopen_state, | ||
661 | } | ||
662 | |||
663 | static void blkdebug_child_perm(BlockDriverState *bs, BdrvChild *c, | ||
664 | - const BdrvChildRole *role, | ||
665 | + const BdrvChildClass *child_class, | ||
666 | BlockReopenQueue *reopen_queue, | ||
667 | uint64_t perm, uint64_t shared, | ||
668 | uint64_t *nperm, uint64_t *nshared) | ||
669 | { | ||
670 | BDRVBlkdebugState *s = bs->opaque; | ||
671 | |||
672 | - bdrv_filter_default_perms(bs, c, role, reopen_queue, perm, shared, | ||
673 | + bdrv_filter_default_perms(bs, c, child_class, reopen_queue, perm, shared, | ||
674 | nperm, nshared); | ||
675 | |||
676 | *nperm |= s->take_child_perms; | ||
677 | diff --git a/block/blklogwrites.c b/block/blklogwrites.c | ||
678 | index XXXXXXX..XXXXXXX 100644 | ||
679 | --- a/block/blklogwrites.c | ||
680 | +++ b/block/blklogwrites.c | ||
681 | @@ -XXX,XX +XXX,XX @@ static int64_t blk_log_writes_getlength(BlockDriverState *bs) | ||
682 | } | ||
683 | |||
684 | static void blk_log_writes_child_perm(BlockDriverState *bs, BdrvChild *c, | ||
685 | - const BdrvChildRole *role, | ||
686 | + const BdrvChildClass *child_class, | ||
687 | BlockReopenQueue *ro_q, | ||
688 | uint64_t perm, uint64_t shrd, | ||
689 | uint64_t *nperm, uint64_t *nshrd) | ||
690 | @@ -XXX,XX +XXX,XX @@ static void blk_log_writes_child_perm(BlockDriverState *bs, BdrvChild *c, | ||
691 | } | ||
692 | |||
693 | if (!strcmp(c->name, "log")) { | ||
694 | - bdrv_format_default_perms(bs, c, role, ro_q, perm, shrd, nperm, nshrd); | ||
695 | + bdrv_format_default_perms(bs, c, child_class, ro_q, perm, shrd, nperm, | ||
696 | + nshrd); | ||
697 | } else { | ||
698 | - bdrv_filter_default_perms(bs, c, role, ro_q, perm, shrd, nperm, nshrd); | ||
699 | + bdrv_filter_default_perms(bs, c, child_class, ro_q, perm, shrd, nperm, | ||
700 | + nshrd); | ||
701 | } | ||
702 | } | ||
703 | |||
704 | diff --git a/block/block-backend.c b/block/block-backend.c | ||
705 | index XXXXXXX..XXXXXXX 100644 | ||
706 | --- a/block/block-backend.c | ||
707 | +++ b/block/block-backend.c | ||
708 | @@ -XXX,XX +XXX,XX @@ static void blk_root_detach(BdrvChild *child) | ||
709 | } | ||
710 | } | ||
711 | |||
712 | -static const BdrvChildRole child_root = { | ||
713 | +static const BdrvChildClass child_root = { | ||
714 | .inherit_options = blk_root_inherit_options, | ||
715 | |||
716 | .change_media = blk_root_change_media, | ||
717 | @@ -XXX,XX +XXX,XX @@ static BlockBackend *bdrv_first_blk(BlockDriverState *bs) | ||
718 | { | ||
719 | BdrvChild *child; | ||
720 | QLIST_FOREACH(child, &bs->parents, next_parent) { | ||
721 | - if (child->role == &child_root) { | ||
722 | + if (child->klass == &child_root) { | ||
723 | return child->opaque; | ||
724 | } | ||
725 | } | ||
726 | @@ -XXX,XX +XXX,XX @@ bool bdrv_is_root_node(BlockDriverState *bs) | ||
727 | BdrvChild *c; | ||
728 | |||
729 | QLIST_FOREACH(c, &bs->parents, next_parent) { | ||
730 | - if (c->role != &child_root) { | ||
731 | + if (c->klass != &child_root) { | ||
732 | return false; | ||
733 | } | ||
734 | } | ||
735 | diff --git a/block/commit.c b/block/commit.c | ||
736 | index XXXXXXX..XXXXXXX 100644 | ||
737 | --- a/block/commit.c | ||
738 | +++ b/block/commit.c | ||
739 | @@ -XXX,XX +XXX,XX @@ static void bdrv_commit_top_refresh_filename(BlockDriverState *bs) | ||
740 | } | ||
741 | |||
742 | static void bdrv_commit_top_child_perm(BlockDriverState *bs, BdrvChild *c, | ||
743 | - const BdrvChildRole *role, | ||
744 | + const BdrvChildClass *child_class, | ||
745 | BlockReopenQueue *reopen_queue, | ||
746 | uint64_t perm, uint64_t shared, | ||
747 | uint64_t *nperm, uint64_t *nshared) | ||
748 | diff --git a/block/copy-on-read.c b/block/copy-on-read.c | ||
749 | index XXXXXXX..XXXXXXX 100644 | ||
750 | --- a/block/copy-on-read.c | ||
751 | +++ b/block/copy-on-read.c | ||
752 | @@ -XXX,XX +XXX,XX @@ static int cor_open(BlockDriverState *bs, QDict *options, int flags, | ||
753 | #define PERM_UNCHANGED (BLK_PERM_ALL & ~PERM_PASSTHROUGH) | ||
754 | |||
755 | static void cor_child_perm(BlockDriverState *bs, BdrvChild *c, | ||
756 | - const BdrvChildRole *role, | ||
757 | + const BdrvChildClass *child_class, | ||
758 | BlockReopenQueue *reopen_queue, | ||
759 | uint64_t perm, uint64_t shared, | ||
760 | uint64_t *nperm, uint64_t *nshared) | ||
761 | diff --git a/block/io.c b/block/io.c | ||
762 | index XXXXXXX..XXXXXXX 100644 | ||
763 | --- a/block/io.c | ||
764 | +++ b/block/io.c | ||
765 | @@ -XXX,XX +XXX,XX @@ static void bdrv_parent_drained_begin(BlockDriverState *bs, BdrvChild *ignore, | ||
766 | BdrvChild *c, *next; | ||
767 | |||
768 | QLIST_FOREACH_SAFE(c, &bs->parents, next_parent, next) { | ||
769 | - if (c == ignore || (ignore_bds_parents && c->role->parent_is_bds)) { | ||
770 | + if (c == ignore || (ignore_bds_parents && c->klass->parent_is_bds)) { | ||
771 | continue; | ||
772 | } | ||
773 | bdrv_parent_drained_begin_single(c, false); | ||
774 | @@ -XXX,XX +XXX,XX @@ static void bdrv_parent_drained_end_single_no_poll(BdrvChild *c, | ||
775 | { | ||
776 | assert(c->parent_quiesce_counter > 0); | ||
777 | c->parent_quiesce_counter--; | ||
778 | - if (c->role->drained_end) { | ||
779 | - c->role->drained_end(c, drained_end_counter); | ||
780 | + if (c->klass->drained_end) { | ||
781 | + c->klass->drained_end(c, drained_end_counter); | ||
782 | } | ||
783 | } | ||
784 | |||
785 | @@ -XXX,XX +XXX,XX @@ static void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore, | ||
786 | BdrvChild *c; | ||
787 | |||
788 | QLIST_FOREACH(c, &bs->parents, next_parent) { | ||
789 | - if (c == ignore || (ignore_bds_parents && c->role->parent_is_bds)) { | ||
790 | + if (c == ignore || (ignore_bds_parents && c->klass->parent_is_bds)) { | ||
791 | continue; | ||
792 | } | ||
793 | bdrv_parent_drained_end_single_no_poll(c, drained_end_counter); | ||
794 | @@ -XXX,XX +XXX,XX @@ static void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore, | ||
795 | |||
796 | static bool bdrv_parent_drained_poll_single(BdrvChild *c) | ||
797 | { | ||
798 | - if (c->role->drained_poll) { | ||
799 | - return c->role->drained_poll(c); | ||
800 | + if (c->klass->drained_poll) { | ||
801 | + return c->klass->drained_poll(c); | ||
802 | } | ||
803 | return false; | ||
804 | } | ||
805 | @@ -XXX,XX +XXX,XX @@ static bool bdrv_parent_drained_poll(BlockDriverState *bs, BdrvChild *ignore, | ||
806 | bool busy = false; | ||
807 | |||
808 | QLIST_FOREACH_SAFE(c, &bs->parents, next_parent, next) { | ||
809 | - if (c == ignore || (ignore_bds_parents && c->role->parent_is_bds)) { | ||
810 | + if (c == ignore || (ignore_bds_parents && c->klass->parent_is_bds)) { | ||
811 | continue; | ||
812 | } | ||
813 | busy |= bdrv_parent_drained_poll_single(c); | ||
814 | @@ -XXX,XX +XXX,XX @@ static bool bdrv_parent_drained_poll(BlockDriverState *bs, BdrvChild *ignore, | ||
815 | void bdrv_parent_drained_begin_single(BdrvChild *c, bool poll) | ||
816 | { | ||
817 | c->parent_quiesce_counter++; | ||
818 | - if (c->role->drained_begin) { | ||
819 | - c->role->drained_begin(c); | ||
820 | + if (c->klass->drained_begin) { | ||
821 | + c->klass->drained_begin(c); | ||
822 | } | ||
823 | if (poll) { | ||
824 | BDRV_POLL_WHILE(c->bs, bdrv_parent_drained_poll_single(c)); | ||
825 | @@ -XXX,XX +XXX,XX @@ static void bdrv_parent_cb_resize(BlockDriverState *bs) | ||
826 | { | ||
827 | BdrvChild *c; | ||
828 | QLIST_FOREACH(c, &bs->parents, next_parent) { | ||
829 | - if (c->role->resize) { | ||
830 | - c->role->resize(c); | ||
831 | + if (c->klass->resize) { | ||
832 | + c->klass->resize(c); | ||
833 | } | ||
834 | } | ||
835 | } | ||
836 | diff --git a/block/mirror.c b/block/mirror.c | ||
837 | index XXXXXXX..XXXXXXX 100644 | ||
838 | --- a/block/mirror.c | ||
839 | +++ b/block/mirror.c | ||
840 | @@ -XXX,XX +XXX,XX @@ static void bdrv_mirror_top_refresh_filename(BlockDriverState *bs) | ||
841 | } | ||
842 | |||
843 | static void bdrv_mirror_top_child_perm(BlockDriverState *bs, BdrvChild *c, | ||
844 | - const BdrvChildRole *role, | ||
845 | + const BdrvChildClass *child_class, | ||
846 | BlockReopenQueue *reopen_queue, | ||
847 | uint64_t perm, uint64_t shared, | ||
848 | uint64_t *nperm, uint64_t *nshared) | ||
849 | diff --git a/block/quorum.c b/block/quorum.c | 17 | diff --git a/block/quorum.c b/block/quorum.c |
850 | index XXXXXXX..XXXXXXX 100644 | 18 | index XXXXXXX..XXXXXXX 100644 |
851 | --- a/block/quorum.c | 19 | --- a/block/quorum.c |
852 | +++ b/block/quorum.c | 20 | +++ b/block/quorum.c |
853 | @@ -XXX,XX +XXX,XX @@ static char *quorum_dirname(BlockDriverState *bs, Error **errp) | 21 | @@ -XXX,XX +XXX,XX @@ static bool quorum_64bits_compare(QuorumVoteValue *a, QuorumVoteValue *b) |
22 | return a->l == b->l; | ||
854 | } | 23 | } |
855 | 24 | ||
856 | static void quorum_child_perm(BlockDriverState *bs, BdrvChild *c, | 25 | -static QuorumAIOCB *quorum_aio_get(BlockDriverState *bs, |
857 | - const BdrvChildRole *role, | 26 | - QEMUIOVector *qiov, |
858 | + const BdrvChildClass *child_class, | 27 | - uint64_t offset, |
859 | BlockReopenQueue *reopen_queue, | 28 | - uint64_t bytes, |
860 | uint64_t perm, uint64_t shared, | 29 | - int flags) |
861 | uint64_t *nperm, uint64_t *nshared) | 30 | +static QuorumAIOCB *coroutine_fn quorum_aio_get(BlockDriverState *bs, |
862 | diff --git a/block/replication.c b/block/replication.c | 31 | + QEMUIOVector *qiov, |
863 | index XXXXXXX..XXXXXXX 100644 | 32 | + uint64_t offset, uint64_t bytes, |
864 | --- a/block/replication.c | 33 | + int flags) |
865 | +++ b/block/replication.c | 34 | { |
866 | @@ -XXX,XX +XXX,XX @@ static void replication_close(BlockDriverState *bs) | 35 | BDRVQuorumState *s = bs->opaque; |
36 | QuorumAIOCB *acb = g_new(QuorumAIOCB, 1); | ||
37 | @@ -XXX,XX +XXX,XX @@ static void quorum_report_bad_versions(BDRVQuorumState *s, | ||
38 | } | ||
867 | } | 39 | } |
868 | 40 | ||
869 | static void replication_child_perm(BlockDriverState *bs, BdrvChild *c, | 41 | -static void quorum_rewrite_entry(void *opaque) |
870 | - const BdrvChildRole *role, | 42 | +static void coroutine_fn quorum_rewrite_entry(void *opaque) |
871 | + const BdrvChildClass *child_class, | 43 | { |
872 | BlockReopenQueue *reopen_queue, | 44 | QuorumCo *co = opaque; |
873 | uint64_t perm, uint64_t shared, | 45 | QuorumAIOCB *acb = co->acb; |
874 | uint64_t *nperm, uint64_t *nshared) | 46 | @@ -XXX,XX +XXX,XX @@ free_exit: |
875 | diff --git a/block/vvfat.c b/block/vvfat.c | 47 | quorum_free_vote_list(&acb->votes); |
876 | index XXXXXXX..XXXXXXX 100644 | ||
877 | --- a/block/vvfat.c | ||
878 | +++ b/block/vvfat.c | ||
879 | @@ -XXX,XX +XXX,XX @@ static void vvfat_qcow_options(int *child_flags, QDict *child_options, | ||
880 | qdict_set_default_str(child_options, BDRV_OPT_CACHE_NO_FLUSH, "on"); | ||
881 | } | 48 | } |
882 | 49 | ||
883 | -static const BdrvChildRole child_vvfat_qcow = { | 50 | -static void read_quorum_children_entry(void *opaque) |
884 | +static const BdrvChildClass child_vvfat_qcow = { | 51 | +static void coroutine_fn read_quorum_children_entry(void *opaque) |
885 | .parent_is_bds = true, | 52 | { |
886 | .inherit_options = vvfat_qcow_options, | 53 | QuorumCo *co = opaque; |
887 | }; | 54 | QuorumAIOCB *acb = co->acb; |
888 | @@ -XXX,XX +XXX,XX @@ err: | 55 | @@ -XXX,XX +XXX,XX @@ static void read_quorum_children_entry(void *opaque) |
56 | } | ||
889 | } | 57 | } |
890 | 58 | ||
891 | static void vvfat_child_perm(BlockDriverState *bs, BdrvChild *c, | 59 | -static int read_quorum_children(QuorumAIOCB *acb) |
892 | - const BdrvChildRole *role, | 60 | +static int coroutine_fn read_quorum_children(QuorumAIOCB *acb) |
893 | + const BdrvChildClass *child_class, | ||
894 | BlockReopenQueue *reopen_queue, | ||
895 | uint64_t perm, uint64_t shared, | ||
896 | uint64_t *nperm, uint64_t *nshared) | ||
897 | { | 61 | { |
898 | BDRVVVFATState *s = bs->opaque; | 62 | BDRVQuorumState *s = acb->bs->opaque; |
899 | 63 | int i; | |
900 | - assert(c == s->qcow || role == &child_backing); | 64 | @@ -XXX,XX +XXX,XX @@ static int read_quorum_children(QuorumAIOCB *acb) |
901 | + assert(c == s->qcow || child_class == &child_backing); | 65 | return acb->vote_ret; |
902 | |||
903 | if (c == s->qcow) { | ||
904 | /* This is a private node, nobody should try to attach to it */ | ||
905 | diff --git a/blockjob.c b/blockjob.c | ||
906 | index XXXXXXX..XXXXXXX 100644 | ||
907 | --- a/blockjob.c | ||
908 | +++ b/blockjob.c | ||
909 | @@ -XXX,XX +XXX,XX @@ static void child_job_set_aio_ctx(BdrvChild *c, AioContext *ctx, | ||
910 | job->job.aio_context = ctx; | ||
911 | } | 66 | } |
912 | 67 | ||
913 | -static const BdrvChildRole child_job = { | 68 | -static int read_fifo_child(QuorumAIOCB *acb) |
914 | +static const BdrvChildClass child_job = { | 69 | +static int coroutine_fn read_fifo_child(QuorumAIOCB *acb) |
915 | .get_parent_desc = child_job_get_parent_desc, | 70 | { |
916 | .drained_begin = child_job_drained_begin, | 71 | BDRVQuorumState *s = acb->bs->opaque; |
917 | .drained_poll = child_job_drained_poll, | 72 | int n, ret; |
918 | diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c | 73 | @@ -XXX,XX +XXX,XX @@ static int read_fifo_child(QuorumAIOCB *acb) |
919 | index XXXXXXX..XXXXXXX 100644 | 74 | return ret; |
920 | --- a/tests/test-bdrv-drain.c | ||
921 | +++ b/tests/test-bdrv-drain.c | ||
922 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_test_co_preadv(BlockDriverState *bs, | ||
923 | } | 75 | } |
924 | 76 | ||
925 | static void bdrv_test_child_perm(BlockDriverState *bs, BdrvChild *c, | 77 | -static int quorum_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes, |
926 | - const BdrvChildRole *role, | 78 | - QEMUIOVector *qiov, BdrvRequestFlags flags) |
927 | + const BdrvChildClass *child_class, | 79 | +static int coroutine_fn quorum_co_preadv(BlockDriverState *bs, |
928 | BlockReopenQueue *reopen_queue, | 80 | + int64_t offset, int64_t bytes, |
929 | uint64_t perm, uint64_t shared, | 81 | + QEMUIOVector *qiov, |
930 | uint64_t *nperm, uint64_t *nshared) | 82 | + BdrvRequestFlags flags) |
931 | { | 83 | { |
932 | - /* bdrv_format_default_perms() accepts only these two, so disguise | 84 | BDRVQuorumState *s = bs->opaque; |
933 | - * detach_by_driver_cb_role as one of them. */ | 85 | QuorumAIOCB *acb = quorum_aio_get(bs, qiov, offset, bytes, flags); |
934 | - if (role != &child_file && role != &child_backing) { | 86 | @@ -XXX,XX +XXX,XX @@ static int quorum_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes, |
935 | - role = &child_file; | 87 | return ret; |
936 | + /* | 88 | } |
937 | + * bdrv_format_default_perms() accepts only these two, so disguise | 89 | |
938 | + * detach_by_driver_cb_parent as one of them. | 90 | -static void write_quorum_entry(void *opaque) |
939 | + */ | 91 | +static void coroutine_fn write_quorum_entry(void *opaque) |
940 | + if (child_class != &child_file && child_class != &child_backing) { | 92 | { |
941 | + child_class = &child_file; | 93 | QuorumCo *co = opaque; |
94 | QuorumAIOCB *acb = co->acb; | ||
95 | @@ -XXX,XX +XXX,XX @@ static void write_quorum_entry(void *opaque) | ||
942 | } | 96 | } |
943 | |||
944 | - bdrv_format_default_perms(bs, c, role, reopen_queue, perm, shared, | ||
945 | + bdrv_format_default_perms(bs, c, child_class, reopen_queue, perm, shared, | ||
946 | nperm, nshared); | ||
947 | } | 97 | } |
948 | 98 | ||
949 | @@ -XXX,XX +XXX,XX @@ static void detach_by_driver_cb_drained_begin(BdrvChild *child) | 99 | -static int quorum_co_pwritev(BlockDriverState *bs, int64_t offset, |
950 | child_file.drained_begin(child); | 100 | - int64_t bytes, QEMUIOVector *qiov, |
101 | - BdrvRequestFlags flags) | ||
102 | +static int coroutine_fn quorum_co_pwritev(BlockDriverState *bs, int64_t offset, | ||
103 | + int64_t bytes, QEMUIOVector *qiov, | ||
104 | + BdrvRequestFlags flags) | ||
105 | { | ||
106 | BDRVQuorumState *s = bs->opaque; | ||
107 | QuorumAIOCB *acb = quorum_aio_get(bs, qiov, offset, bytes, flags); | ||
108 | @@ -XXX,XX +XXX,XX @@ static int quorum_co_pwritev(BlockDriverState *bs, int64_t offset, | ||
109 | return ret; | ||
951 | } | 110 | } |
952 | 111 | ||
953 | -static BdrvChildRole detach_by_driver_cb_role; | 112 | -static int quorum_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, |
954 | +static BdrvChildClass detach_by_driver_cb_class; | 113 | - int64_t bytes, BdrvRequestFlags flags) |
955 | 114 | +static int coroutine_fn quorum_co_pwrite_zeroes(BlockDriverState *bs, | |
956 | /* | 115 | + int64_t offset, int64_t bytes, |
957 | * Initial graph: | 116 | + BdrvRequestFlags flags) |
958 | @@ -XXX,XX +XXX,XX @@ static BdrvChildRole detach_by_driver_cb_role; | 117 | |
959 | * | ||
960 | * by_parent_cb == false: Test that bdrv_drain_invoke() doesn't poll | ||
961 | * | ||
962 | - * PA's BdrvChildRole has a .drained_begin callback that schedules a BH | ||
963 | + * PA's BdrvChildClass has a .drained_begin callback that schedules a BH | ||
964 | * that does the same graph change. If bdrv_drain_invoke() calls it, the | ||
965 | * state is messed up, but if it is only polled in the single | ||
966 | * BDRV_POLL_WHILE() at the end of the drain, this should work fine. | ||
967 | @@ -XXX,XX +XXX,XX @@ static void test_detach_indirect(bool by_parent_cb) | ||
968 | QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, NULL, 0); | ||
969 | |||
970 | if (!by_parent_cb) { | ||
971 | - detach_by_driver_cb_role = child_file; | ||
972 | - detach_by_driver_cb_role.drained_begin = | ||
973 | + detach_by_driver_cb_class = child_file; | ||
974 | + detach_by_driver_cb_class.drained_begin = | ||
975 | detach_by_driver_cb_drained_begin; | ||
976 | } | ||
977 | |||
978 | @@ -XXX,XX +XXX,XX @@ static void test_detach_indirect(bool by_parent_cb) | ||
979 | |||
980 | bdrv_ref(a); | ||
981 | bdrv_attach_child(parent_a, a, "PA-A", | ||
982 | - by_parent_cb ? &child_file : &detach_by_driver_cb_role, | ||
983 | + by_parent_cb ? &child_file : &detach_by_driver_cb_class, | ||
984 | &error_abort); | ||
985 | |||
986 | g_assert_cmpint(parent_a->refcnt, ==, 1); | ||
987 | @@ -XXX,XX +XXX,XX @@ static int drop_intermediate_poll_update_filename(BdrvChild *child, | ||
988 | /** | ||
989 | * Test a poll in the midst of bdrv_drop_intermediate(). | ||
990 | * | ||
991 | - * bdrv_drop_intermediate() calls BdrvChildRole.update_filename(), | ||
992 | + * bdrv_drop_intermediate() calls BdrvChildClass.update_filename(), | ||
993 | * which can yield or poll. This may lead to graph changes, unless | ||
994 | * the whole subtree in question is drained. | ||
995 | * | ||
996 | @@ -XXX,XX +XXX,XX @@ static int drop_intermediate_poll_update_filename(BdrvChild *child, | ||
997 | * | ||
998 | * The solution is for bdrv_drop_intermediate() to drain top's | ||
999 | * subtree. This prevents graph changes from happening just because | ||
1000 | - * BdrvChildRole.update_filename() yields or polls. Thus, the block | ||
1001 | + * BdrvChildClass.update_filename() yields or polls. Thus, the block | ||
1002 | * job is paused during that drained section and must finish before or | ||
1003 | * after. | ||
1004 | * | ||
1005 | @@ -XXX,XX +XXX,XX @@ static int drop_intermediate_poll_update_filename(BdrvChild *child, | ||
1006 | */ | ||
1007 | static void test_drop_intermediate_poll(void) | ||
1008 | { | 118 | { |
1009 | - static BdrvChildRole chain_child_role; | 119 | return quorum_co_pwritev(bs, offset, bytes, NULL, |
1010 | + static BdrvChildClass chain_child_class; | ||
1011 | BlockDriverState *chain[3]; | ||
1012 | TestSimpleBlockJob *job; | ||
1013 | BlockDriverState *job_node; | ||
1014 | @@ -XXX,XX +XXX,XX @@ static void test_drop_intermediate_poll(void) | ||
1015 | int i; | ||
1016 | int ret; | ||
1017 | |||
1018 | - chain_child_role = child_backing; | ||
1019 | - chain_child_role.update_filename = drop_intermediate_poll_update_filename; | ||
1020 | + chain_child_class = child_backing; | ||
1021 | + chain_child_class.update_filename = drop_intermediate_poll_update_filename; | ||
1022 | |||
1023 | for (i = 0; i < 3; i++) { | ||
1024 | char name[32]; | ||
1025 | @@ -XXX,XX +XXX,XX @@ static void test_drop_intermediate_poll(void) | ||
1026 | if (i) { | ||
1027 | /* Takes the reference to chain[i - 1] */ | ||
1028 | chain[i]->backing = bdrv_attach_child(chain[i], chain[i - 1], | ||
1029 | - "chain", &chain_child_role, | ||
1030 | + "chain", &chain_child_class, | ||
1031 | &error_abort); | ||
1032 | } | ||
1033 | } | ||
1034 | diff --git a/tests/test-bdrv-graph-mod.c b/tests/test-bdrv-graph-mod.c | ||
1035 | index XXXXXXX..XXXXXXX 100644 | ||
1036 | --- a/tests/test-bdrv-graph-mod.c | ||
1037 | +++ b/tests/test-bdrv-graph-mod.c | ||
1038 | @@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_pass_through = { | ||
1039 | }; | ||
1040 | |||
1041 | static void no_perm_default_perms(BlockDriverState *bs, BdrvChild *c, | ||
1042 | - const BdrvChildRole *role, | ||
1043 | + const BdrvChildClass *child_class, | ||
1044 | BlockReopenQueue *reopen_queue, | ||
1045 | uint64_t perm, uint64_t shared, | ||
1046 | uint64_t *nperm, uint64_t *nshared) | ||
1047 | -- | 120 | -- |
1048 | 2.25.4 | 121 | 2.37.3 |
1049 | |||
1050 | diff view generated by jsdifflib |
1 | From: Max Reitz <mreitz@redhat.com> | 1 | From: Paolo Bonzini <pbonzini@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Note that some filters have secondary children, namely blkverify (the | 3 | Callers of coroutine_fn must be coroutine_fn themselves, or the call |
4 | image to be verified) and blklogwrites (the log). This patch does not | 4 | must be within "if (qemu_in_coroutine())". Apply coroutine_fn to |
5 | touch those children. | 5 | functions where this holds. |
6 | 6 | ||
7 | Note that for blkverify, the filtered child should not be format-probed. | 7 | Reviewed-by: Alberto Faria <afaria@redhat.com> |
8 | While there is nothing enforcing this here, in practice, it will not be: | 8 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
9 | blkverify implements .bdrv_file_open. The block layer ensures (and in | 9 | Message-Id: <20220922084924.201610-20-pbonzini@redhat.com> |
10 | fact, asserts) that BDRV_O_PROTOCOL is set for every BDS whose driver | 10 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> |
11 | implements .bdrv_file_open. This flag will then be bequeathed to | ||
12 | blkverify's children, and they will thus (by default) not be probed | ||
13 | either. | ||
14 | |||
15 | ("By default" refers to the fact that blkverify's other child (the | ||
16 | non-filtered one) will have BDRV_O_PROTOCOL force-unset, because that is | ||
17 | what happens for all non-filtered children of non-format drivers.) | ||
18 | |||
19 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
20 | Message-Id: <20200513110544.176672-27-mreitz@redhat.com> | ||
21 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
22 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
23 | --- | 12 | --- |
24 | block/blkdebug.c | 4 +++- | 13 | block/throttle.c | 2 +- |
25 | block/blklogwrites.c | 3 ++- | 14 | 1 file changed, 1 insertion(+), 1 deletion(-) |
26 | block/blkreplay.c | 5 +++-- | ||
27 | block/blkverify.c | 4 +++- | ||
28 | block/copy-on-read.c | 5 +++-- | ||
29 | block/filter-compress.c | 5 +++-- | ||
30 | block/replication.c | 3 ++- | ||
31 | block/throttle.c | 5 +++-- | ||
32 | 8 files changed, 22 insertions(+), 12 deletions(-) | ||
33 | 15 | ||
34 | diff --git a/block/blkdebug.c b/block/blkdebug.c | ||
35 | index XXXXXXX..XXXXXXX 100644 | ||
36 | --- a/block/blkdebug.c | ||
37 | +++ b/block/blkdebug.c | ||
38 | @@ -XXX,XX +XXX,XX @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags, | ||
39 | |||
40 | /* Open the image file */ | ||
41 | bs->file = bdrv_open_child(qemu_opt_get(opts, "x-image"), options, "image", | ||
42 | - bs, &child_file, 0, false, &local_err); | ||
43 | + bs, &child_of_bds, | ||
44 | + BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, | ||
45 | + false, &local_err); | ||
46 | if (local_err) { | ||
47 | ret = -EINVAL; | ||
48 | error_propagate(errp, local_err); | ||
49 | diff --git a/block/blklogwrites.c b/block/blklogwrites.c | ||
50 | index XXXXXXX..XXXXXXX 100644 | ||
51 | --- a/block/blklogwrites.c | ||
52 | +++ b/block/blklogwrites.c | ||
53 | @@ -XXX,XX +XXX,XX @@ static int blk_log_writes_open(BlockDriverState *bs, QDict *options, int flags, | ||
54 | } | ||
55 | |||
56 | /* Open the file */ | ||
57 | - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, false, | ||
58 | + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, | ||
59 | + BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, false, | ||
60 | &local_err); | ||
61 | if (local_err) { | ||
62 | ret = -EINVAL; | ||
63 | diff --git a/block/blkreplay.c b/block/blkreplay.c | ||
64 | index XXXXXXX..XXXXXXX 100644 | ||
65 | --- a/block/blkreplay.c | ||
66 | +++ b/block/blkreplay.c | ||
67 | @@ -XXX,XX +XXX,XX @@ static int blkreplay_open(BlockDriverState *bs, QDict *options, int flags, | ||
68 | int ret; | ||
69 | |||
70 | /* Open the image file */ | ||
71 | - bs->file = bdrv_open_child(NULL, options, "image", | ||
72 | - bs, &child_file, 0, false, &local_err); | ||
73 | + bs->file = bdrv_open_child(NULL, options, "image", bs, &child_of_bds, | ||
74 | + BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, | ||
75 | + false, &local_err); | ||
76 | if (local_err) { | ||
77 | ret = -EINVAL; | ||
78 | error_propagate(errp, local_err); | ||
79 | diff --git a/block/blkverify.c b/block/blkverify.c | ||
80 | index XXXXXXX..XXXXXXX 100644 | ||
81 | --- a/block/blkverify.c | ||
82 | +++ b/block/blkverify.c | ||
83 | @@ -XXX,XX +XXX,XX @@ static int blkverify_open(BlockDriverState *bs, QDict *options, int flags, | ||
84 | |||
85 | /* Open the raw file */ | ||
86 | bs->file = bdrv_open_child(qemu_opt_get(opts, "x-raw"), options, "raw", | ||
87 | - bs, &child_file, 0, false, &local_err); | ||
88 | + bs, &child_of_bds, | ||
89 | + BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, | ||
90 | + false, &local_err); | ||
91 | if (local_err) { | ||
92 | ret = -EINVAL; | ||
93 | error_propagate(errp, local_err); | ||
94 | diff --git a/block/copy-on-read.c b/block/copy-on-read.c | ||
95 | index XXXXXXX..XXXXXXX 100644 | ||
96 | --- a/block/copy-on-read.c | ||
97 | +++ b/block/copy-on-read.c | ||
98 | @@ -XXX,XX +XXX,XX @@ | ||
99 | static int cor_open(BlockDriverState *bs, QDict *options, int flags, | ||
100 | Error **errp) | ||
101 | { | ||
102 | - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, false, | ||
103 | - errp); | ||
104 | + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, | ||
105 | + BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, | ||
106 | + false, errp); | ||
107 | if (!bs->file) { | ||
108 | return -EINVAL; | ||
109 | } | ||
110 | diff --git a/block/filter-compress.c b/block/filter-compress.c | ||
111 | index XXXXXXX..XXXXXXX 100644 | ||
112 | --- a/block/filter-compress.c | ||
113 | +++ b/block/filter-compress.c | ||
114 | @@ -XXX,XX +XXX,XX @@ | ||
115 | static int compress_open(BlockDriverState *bs, QDict *options, int flags, | ||
116 | Error **errp) | ||
117 | { | ||
118 | - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, false, | ||
119 | - errp); | ||
120 | + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, | ||
121 | + BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, | ||
122 | + false, errp); | ||
123 | if (!bs->file) { | ||
124 | return -EINVAL; | ||
125 | } | ||
126 | diff --git a/block/replication.c b/block/replication.c | ||
127 | index XXXXXXX..XXXXXXX 100644 | ||
128 | --- a/block/replication.c | ||
129 | +++ b/block/replication.c | ||
130 | @@ -XXX,XX +XXX,XX @@ static int replication_open(BlockDriverState *bs, QDict *options, | ||
131 | const char *mode; | ||
132 | const char *top_id; | ||
133 | |||
134 | - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, | ||
135 | + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, | ||
136 | + BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, | ||
137 | false, errp); | ||
138 | if (!bs->file) { | ||
139 | return -EINVAL; | ||
140 | diff --git a/block/throttle.c b/block/throttle.c | 16 | diff --git a/block/throttle.c b/block/throttle.c |
141 | index XXXXXXX..XXXXXXX 100644 | 17 | index XXXXXXX..XXXXXXX 100644 |
142 | --- a/block/throttle.c | 18 | --- a/block/throttle.c |
143 | +++ b/block/throttle.c | 19 | +++ b/block/throttle.c |
144 | @@ -XXX,XX +XXX,XX @@ static int throttle_open(BlockDriverState *bs, QDict *options, | 20 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn throttle_co_pwritev_compressed(BlockDriverState *bs, |
145 | char *group; | 21 | BDRV_REQ_WRITE_COMPRESSED); |
146 | int ret; | 22 | } |
147 | 23 | ||
148 | - bs->file = bdrv_open_child(NULL, options, "file", bs, | 24 | -static int throttle_co_flush(BlockDriverState *bs) |
149 | - &child_file, 0, false, errp); | 25 | +static int coroutine_fn throttle_co_flush(BlockDriverState *bs) |
150 | + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, | 26 | { |
151 | + BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, | 27 | return bdrv_co_flush(bs->file->bs); |
152 | + false, errp); | 28 | } |
153 | if (!bs->file) { | ||
154 | return -EINVAL; | ||
155 | } | ||
156 | -- | 29 | -- |
157 | 2.25.4 | 30 | 2.37.3 |
158 | |||
159 | diff view generated by jsdifflib |
1 | From: Max Reitz <mreitz@redhat.com> | 1 | From: Paolo Bonzini <pbonzini@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | We want to unify child_format and child_file at some point. One of the | 3 | Callers of coroutine_fn must be coroutine_fn themselves, or the call |
4 | important things that set format drivers apart from other drivers is | 4 | must be within "if (qemu_in_coroutine())". Apply coroutine_fn to |
5 | that they do not expect other format nodes under them (except in the | 5 | functions where this holds. |
6 | backing chain), i.e. we must not probe formats inside of formats. That | ||
7 | means we need something on which to distinguish format drivers from | ||
8 | others, and hence this flag. | ||
9 | 6 | ||
10 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 7 | Reviewed-by: Alberto Faria <afaria@redhat.com> |
11 | Reviewed-by: Eric Blake <eblake@redhat.com> | 8 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
12 | Reviewed-by: Alberto Garcia <berto@igalia.com> | 9 | Message-Id: <20220922084924.201610-21-pbonzini@redhat.com> |
13 | Message-Id: <20200513110544.176672-3-mreitz@redhat.com> | 10 | [kwolf: Fixed up coding style] |
11 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
14 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
15 | --- | 13 | --- |
16 | include/block/block_int.h | 7 +++++++ | 14 | block/vmdk.c | 22 ++++++++++++---------- |
17 | block/bochs.c | 1 + | 15 | 1 file changed, 12 insertions(+), 10 deletions(-) |
18 | block/cloop.c | 1 + | ||
19 | block/crypto.c | 2 ++ | ||
20 | block/dmg.c | 1 + | ||
21 | block/parallels.c | 1 + | ||
22 | block/qcow.c | 1 + | ||
23 | block/qcow2.c | 1 + | ||
24 | block/qed.c | 1 + | ||
25 | block/raw-format.c | 1 + | ||
26 | block/vdi.c | 1 + | ||
27 | block/vhdx.c | 1 + | ||
28 | block/vmdk.c | 1 + | ||
29 | block/vpc.c | 1 + | ||
30 | 14 files changed, 21 insertions(+) | ||
31 | 16 | ||
32 | diff --git a/include/block/block_int.h b/include/block/block_int.h | ||
33 | index XXXXXXX..XXXXXXX 100644 | ||
34 | --- a/include/block/block_int.h | ||
35 | +++ b/include/block/block_int.h | ||
36 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { | ||
37 | * must implement them and return -ENOTSUP. | ||
38 | */ | ||
39 | bool is_filter; | ||
40 | + /* | ||
41 | + * Set to true if the BlockDriver is a format driver. Format nodes | ||
42 | + * generally do not expect their children to be other format nodes | ||
43 | + * (except for backing files), and so format probing is disabled | ||
44 | + * on those children. | ||
45 | + */ | ||
46 | + bool is_format; | ||
47 | /* | ||
48 | * Return true if @to_replace can be replaced by a BDS with the | ||
49 | * same data as @bs without it affecting @bs's behavior (that is, | ||
50 | diff --git a/block/bochs.c b/block/bochs.c | ||
51 | index XXXXXXX..XXXXXXX 100644 | ||
52 | --- a/block/bochs.c | ||
53 | +++ b/block/bochs.c | ||
54 | @@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_bochs = { | ||
55 | .bdrv_refresh_limits = bochs_refresh_limits, | ||
56 | .bdrv_co_preadv = bochs_co_preadv, | ||
57 | .bdrv_close = bochs_close, | ||
58 | + .is_format = true, | ||
59 | }; | ||
60 | |||
61 | static void bdrv_bochs_init(void) | ||
62 | diff --git a/block/cloop.c b/block/cloop.c | ||
63 | index XXXXXXX..XXXXXXX 100644 | ||
64 | --- a/block/cloop.c | ||
65 | +++ b/block/cloop.c | ||
66 | @@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_cloop = { | ||
67 | .bdrv_refresh_limits = cloop_refresh_limits, | ||
68 | .bdrv_co_preadv = cloop_co_preadv, | ||
69 | .bdrv_close = cloop_close, | ||
70 | + .is_format = true, | ||
71 | }; | ||
72 | |||
73 | static void bdrv_cloop_init(void) | ||
74 | diff --git a/block/crypto.c b/block/crypto.c | ||
75 | index XXXXXXX..XXXXXXX 100644 | ||
76 | --- a/block/crypto.c | ||
77 | +++ b/block/crypto.c | ||
78 | @@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_crypto_luks = { | ||
79 | .bdrv_get_info = block_crypto_get_info_luks, | ||
80 | .bdrv_get_specific_info = block_crypto_get_specific_info_luks, | ||
81 | |||
82 | + .is_format = true, | ||
83 | + | ||
84 | .strong_runtime_opts = block_crypto_strong_runtime_opts, | ||
85 | }; | ||
86 | |||
87 | diff --git a/block/dmg.c b/block/dmg.c | ||
88 | index XXXXXXX..XXXXXXX 100644 | ||
89 | --- a/block/dmg.c | ||
90 | +++ b/block/dmg.c | ||
91 | @@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_dmg = { | ||
92 | .bdrv_child_perm = bdrv_format_default_perms, | ||
93 | .bdrv_co_preadv = dmg_co_preadv, | ||
94 | .bdrv_close = dmg_close, | ||
95 | + .is_format = true, | ||
96 | }; | ||
97 | |||
98 | static void bdrv_dmg_init(void) | ||
99 | diff --git a/block/parallels.c b/block/parallels.c | ||
100 | index XXXXXXX..XXXXXXX 100644 | ||
101 | --- a/block/parallels.c | ||
102 | +++ b/block/parallels.c | ||
103 | @@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_parallels = { | ||
104 | .bdrv_co_flush_to_os = parallels_co_flush_to_os, | ||
105 | .bdrv_co_readv = parallels_co_readv, | ||
106 | .bdrv_co_writev = parallels_co_writev, | ||
107 | + .is_format = true, | ||
108 | .supports_backing = true, | ||
109 | .bdrv_co_create = parallels_co_create, | ||
110 | .bdrv_co_create_opts = parallels_co_create_opts, | ||
111 | diff --git a/block/qcow.c b/block/qcow.c | ||
112 | index XXXXXXX..XXXXXXX 100644 | ||
113 | --- a/block/qcow.c | ||
114 | +++ b/block/qcow.c | ||
115 | @@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_qcow = { | ||
116 | .bdrv_co_create = qcow_co_create, | ||
117 | .bdrv_co_create_opts = qcow_co_create_opts, | ||
118 | .bdrv_has_zero_init = bdrv_has_zero_init_1, | ||
119 | + .is_format = true, | ||
120 | .supports_backing = true, | ||
121 | .bdrv_refresh_limits = qcow_refresh_limits, | ||
122 | |||
123 | diff --git a/block/qcow2.c b/block/qcow2.c | ||
124 | index XXXXXXX..XXXXXXX 100644 | ||
125 | --- a/block/qcow2.c | ||
126 | +++ b/block/qcow2.c | ||
127 | @@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_qcow2 = { | ||
128 | .bdrv_save_vmstate = qcow2_save_vmstate, | ||
129 | .bdrv_load_vmstate = qcow2_load_vmstate, | ||
130 | |||
131 | + .is_format = true, | ||
132 | .supports_backing = true, | ||
133 | .bdrv_change_backing_file = qcow2_change_backing_file, | ||
134 | |||
135 | diff --git a/block/qed.c b/block/qed.c | ||
136 | index XXXXXXX..XXXXXXX 100644 | ||
137 | --- a/block/qed.c | ||
138 | +++ b/block/qed.c | ||
139 | @@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_qed = { | ||
140 | .format_name = "qed", | ||
141 | .instance_size = sizeof(BDRVQEDState), | ||
142 | .create_opts = &qed_create_opts, | ||
143 | + .is_format = true, | ||
144 | .supports_backing = true, | ||
145 | |||
146 | .bdrv_probe = bdrv_qed_probe, | ||
147 | diff --git a/block/raw-format.c b/block/raw-format.c | ||
148 | index XXXXXXX..XXXXXXX 100644 | ||
149 | --- a/block/raw-format.c | ||
150 | +++ b/block/raw-format.c | ||
151 | @@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_raw = { | ||
152 | .bdrv_co_copy_range_to = &raw_co_copy_range_to, | ||
153 | .bdrv_co_truncate = &raw_co_truncate, | ||
154 | .bdrv_getlength = &raw_getlength, | ||
155 | + .is_format = true, | ||
156 | .has_variable_length = true, | ||
157 | .bdrv_measure = &raw_measure, | ||
158 | .bdrv_get_info = &raw_get_info, | ||
159 | diff --git a/block/vdi.c b/block/vdi.c | ||
160 | index XXXXXXX..XXXXXXX 100644 | ||
161 | --- a/block/vdi.c | ||
162 | +++ b/block/vdi.c | ||
163 | @@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_vdi = { | ||
164 | |||
165 | .bdrv_get_info = vdi_get_info, | ||
166 | |||
167 | + .is_format = true, | ||
168 | .create_opts = &vdi_create_opts, | ||
169 | .bdrv_co_check = vdi_co_check, | ||
170 | }; | ||
171 | diff --git a/block/vhdx.c b/block/vhdx.c | ||
172 | index XXXXXXX..XXXXXXX 100644 | ||
173 | --- a/block/vhdx.c | ||
174 | +++ b/block/vhdx.c | ||
175 | @@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_vhdx = { | ||
176 | .bdrv_co_check = vhdx_co_check, | ||
177 | .bdrv_has_zero_init = vhdx_has_zero_init, | ||
178 | |||
179 | + .is_format = true, | ||
180 | .create_opts = &vhdx_create_opts, | ||
181 | }; | ||
182 | |||
183 | diff --git a/block/vmdk.c b/block/vmdk.c | 17 | diff --git a/block/vmdk.c b/block/vmdk.c |
184 | index XXXXXXX..XXXXXXX 100644 | 18 | index XXXXXXX..XXXXXXX 100644 |
185 | --- a/block/vmdk.c | 19 | --- a/block/vmdk.c |
186 | +++ b/block/vmdk.c | 20 | +++ b/block/vmdk.c |
187 | @@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_vmdk = { | 21 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn vmdk_co_block_status(BlockDriverState *bs, |
188 | .bdrv_get_info = vmdk_get_info, | 22 | return ret; |
189 | .bdrv_gather_child_options = vmdk_gather_child_options, | 23 | } |
190 | 24 | ||
191 | + .is_format = true, | 25 | -static int vmdk_write_extent(VmdkExtent *extent, int64_t cluster_offset, |
192 | .supports_backing = true, | 26 | - int64_t offset_in_cluster, QEMUIOVector *qiov, |
193 | .create_opts = &vmdk_create_opts, | 27 | - uint64_t qiov_offset, uint64_t n_bytes, |
194 | }; | 28 | - uint64_t offset) |
195 | diff --git a/block/vpc.c b/block/vpc.c | 29 | +static int coroutine_fn |
196 | index XXXXXXX..XXXXXXX 100644 | 30 | +vmdk_write_extent(VmdkExtent *extent, int64_t cluster_offset, |
197 | --- a/block/vpc.c | 31 | + int64_t offset_in_cluster, QEMUIOVector *qiov, |
198 | +++ b/block/vpc.c | 32 | + uint64_t qiov_offset, uint64_t n_bytes, |
199 | @@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_vpc = { | 33 | + uint64_t offset) |
200 | 34 | { | |
201 | .bdrv_get_info = vpc_get_info, | 35 | int ret; |
202 | 36 | VmdkGrainMarker *data = NULL; | |
203 | + .is_format = true, | 37 | @@ -XXX,XX +XXX,XX @@ static int vmdk_write_extent(VmdkExtent *extent, int64_t cluster_offset, |
204 | .create_opts = &vpc_create_opts, | 38 | return ret; |
205 | .bdrv_has_zero_init = vpc_has_zero_init, | 39 | } |
206 | .strong_runtime_opts = vpc_strong_runtime_opts, | 40 | |
41 | -static int vmdk_read_extent(VmdkExtent *extent, int64_t cluster_offset, | ||
42 | - int64_t offset_in_cluster, QEMUIOVector *qiov, | ||
43 | - int bytes) | ||
44 | +static int coroutine_fn | ||
45 | +vmdk_read_extent(VmdkExtent *extent, int64_t cluster_offset, | ||
46 | + int64_t offset_in_cluster, QEMUIOVector *qiov, | ||
47 | + int bytes) | ||
48 | { | ||
49 | int ret; | ||
50 | int cluster_bytes, buf_bytes; | ||
51 | @@ -XXX,XX +XXX,XX @@ fail: | ||
52 | * | ||
53 | * Returns: error code with 0 for success. | ||
54 | */ | ||
55 | -static int vmdk_pwritev(BlockDriverState *bs, uint64_t offset, | ||
56 | - uint64_t bytes, QEMUIOVector *qiov, | ||
57 | - bool zeroed, bool zero_dry_run) | ||
58 | +static int coroutine_fn vmdk_pwritev(BlockDriverState *bs, uint64_t offset, | ||
59 | + uint64_t bytes, QEMUIOVector *qiov, | ||
60 | + bool zeroed, bool zero_dry_run) | ||
61 | { | ||
62 | BDRVVmdkState *s = bs->opaque; | ||
63 | VmdkExtent *extent = NULL; | ||
207 | -- | 64 | -- |
208 | 2.25.4 | 65 | 2.37.3 |
209 | |||
210 | diff view generated by jsdifflib |
1 | From: Max Reitz <mreitz@redhat.com> | 1 | From: Paolo Bonzini <pbonzini@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 3 | Callers of coroutine_fn must be coroutine_fn themselves, or the call |
4 | Reviewed-by: Eric Blake <eblake@redhat.com> | 4 | must be within "if (qemu_in_coroutine())". Apply coroutine_fn to |
5 | Message-Id: <20200513110544.176672-29-mreitz@redhat.com> | 5 | functions where this holds. |
6 | |||
7 | Reviewed-by: Alberto Faria <afaria@redhat.com> | ||
8 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> | ||
9 | Message-Id: <20220922084924.201610-22-pbonzini@redhat.com> | ||
10 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
6 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
7 | --- | 12 | --- |
8 | tests/test-bdrv-drain.c | 29 +++++++++++++++++------------ | 13 | include/qemu/job.h | 2 +- |
9 | tests/test-bdrv-graph-mod.c | 6 ++++-- | 14 | job.c | 2 +- |
10 | 2 files changed, 21 insertions(+), 14 deletions(-) | 15 | 2 files changed, 2 insertions(+), 2 deletions(-) |
11 | 16 | ||
12 | diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c | 17 | diff --git a/include/qemu/job.h b/include/qemu/job.h |
13 | index XXXXXXX..XXXXXXX 100644 | 18 | index XXXXXXX..XXXXXXX 100644 |
14 | --- a/tests/test-bdrv-drain.c | 19 | --- a/include/qemu/job.h |
15 | +++ b/tests/test-bdrv-drain.c | 20 | +++ b/include/qemu/job.h |
16 | @@ -XXX,XX +XXX,XX @@ static void bdrv_test_child_perm(BlockDriverState *bs, BdrvChild *c, | 21 | @@ -XXX,XX +XXX,XX @@ void coroutine_fn job_pause_point(Job *job); |
17 | * detach_by_driver_cb_parent as one of them. | 22 | * |
18 | */ | 23 | * Yield the job coroutine. |
19 | if (child_class != &child_file && child_class != &child_of_bds) { | 24 | */ |
20 | - child_class = &child_file; | 25 | -void job_yield(Job *job); |
21 | + child_class = &child_of_bds; | 26 | +void coroutine_fn job_yield(Job *job); |
27 | |||
28 | /** | ||
29 | * @job: The job that calls the function. | ||
30 | diff --git a/job.c b/job.c | ||
31 | index XXXXXXX..XXXXXXX 100644 | ||
32 | --- a/job.c | ||
33 | +++ b/job.c | ||
34 | @@ -XXX,XX +XXX,XX @@ void coroutine_fn job_pause_point(Job *job) | ||
22 | } | 35 | } |
23 | |||
24 | bdrv_format_default_perms(bs, c, child_class, role, reopen_queue, | ||
25 | @@ -XXX,XX +XXX,XX @@ static void do_test_delete_by_drain(bool detach_instead_of_delete, | ||
26 | |||
27 | null_bs = bdrv_open("null-co://", NULL, NULL, BDRV_O_RDWR | BDRV_O_PROTOCOL, | ||
28 | &error_abort); | ||
29 | - bdrv_attach_child(bs, null_bs, "null-child", &child_file, 0, &error_abort); | ||
30 | + bdrv_attach_child(bs, null_bs, "null-child", &child_of_bds, | ||
31 | + BDRV_CHILD_DATA, &error_abort); | ||
32 | |||
33 | /* This child will be the one to pass to requests through to, and | ||
34 | * it will stall until a drain occurs */ | ||
35 | @@ -XXX,XX +XXX,XX @@ static void do_test_delete_by_drain(bool detach_instead_of_delete, | ||
36 | &error_abort); | ||
37 | child_bs->total_sectors = 65536 >> BDRV_SECTOR_BITS; | ||
38 | /* Takes our reference to child_bs */ | ||
39 | - tts->wait_child = bdrv_attach_child(bs, child_bs, "wait-child", &child_file, | ||
40 | - 0, &error_abort); | ||
41 | + tts->wait_child = bdrv_attach_child(bs, child_bs, "wait-child", | ||
42 | + &child_of_bds, | ||
43 | + BDRV_CHILD_DATA | BDRV_CHILD_PRIMARY, | ||
44 | + &error_abort); | ||
45 | |||
46 | /* This child is just there to be deleted | ||
47 | * (for detach_instead_of_delete == true) */ | ||
48 | null_bs = bdrv_open("null-co://", NULL, NULL, BDRV_O_RDWR | BDRV_O_PROTOCOL, | ||
49 | &error_abort); | ||
50 | - bdrv_attach_child(bs, null_bs, "null-child", &child_file, 0, &error_abort); | ||
51 | + bdrv_attach_child(bs, null_bs, "null-child", &child_of_bds, BDRV_CHILD_DATA, | ||
52 | + &error_abort); | ||
53 | |||
54 | blk = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL); | ||
55 | blk_insert_bs(blk, bs, &error_abort); | ||
56 | @@ -XXX,XX +XXX,XX @@ static void detach_indirect_bh(void *opaque) | ||
57 | |||
58 | bdrv_ref(data->c); | ||
59 | data->child_c = bdrv_attach_child(data->parent_b, data->c, "PB-C", | ||
60 | - &child_file, 0, &error_abort); | ||
61 | + &child_of_bds, BDRV_CHILD_DATA, | ||
62 | + &error_abort); | ||
63 | } | 36 | } |
64 | 37 | ||
65 | static void detach_by_parent_aio_cb(void *opaque, int ret) | 38 | -void job_yield(Job *job) |
66 | @@ -XXX,XX +XXX,XX @@ static void detach_by_driver_cb_drained_begin(BdrvChild *child) | 39 | +void coroutine_fn job_yield(Job *job) |
67 | { | 40 | { |
68 | aio_bh_schedule_oneshot(qemu_get_current_aio_context(), | 41 | assert(job->busy); |
69 | detach_indirect_bh, &detach_by_parent_data); | ||
70 | - child_file.drained_begin(child); | ||
71 | + child_of_bds.drained_begin(child); | ||
72 | } | ||
73 | |||
74 | static BdrvChildClass detach_by_driver_cb_class; | ||
75 | @@ -XXX,XX +XXX,XX @@ static void test_detach_indirect(bool by_parent_cb) | ||
76 | QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, NULL, 0); | ||
77 | |||
78 | if (!by_parent_cb) { | ||
79 | - detach_by_driver_cb_class = child_file; | ||
80 | + detach_by_driver_cb_class = child_of_bds; | ||
81 | detach_by_driver_cb_class.drained_begin = | ||
82 | detach_by_driver_cb_drained_begin; | ||
83 | } | ||
84 | @@ -XXX,XX +XXX,XX @@ static void test_detach_indirect(bool by_parent_cb) | ||
85 | /* Set child relationships */ | ||
86 | bdrv_ref(b); | ||
87 | bdrv_ref(a); | ||
88 | - child_b = bdrv_attach_child(parent_b, b, "PB-B", &child_file, 0, | ||
89 | - &error_abort); | ||
90 | + child_b = bdrv_attach_child(parent_b, b, "PB-B", &child_of_bds, | ||
91 | + BDRV_CHILD_DATA, &error_abort); | ||
92 | child_a = bdrv_attach_child(parent_b, a, "PB-A", &child_of_bds, | ||
93 | BDRV_CHILD_COW, &error_abort); | ||
94 | |||
95 | bdrv_ref(a); | ||
96 | bdrv_attach_child(parent_a, a, "PA-A", | ||
97 | - by_parent_cb ? &child_file : &detach_by_driver_cb_class, | ||
98 | - 0, &error_abort); | ||
99 | + by_parent_cb ? &child_of_bds : &detach_by_driver_cb_class, | ||
100 | + BDRV_CHILD_DATA, &error_abort); | ||
101 | |||
102 | g_assert_cmpint(parent_a->refcnt, ==, 1); | ||
103 | g_assert_cmpint(parent_b->refcnt, ==, 1); | ||
104 | diff --git a/tests/test-bdrv-graph-mod.c b/tests/test-bdrv-graph-mod.c | ||
105 | index XXXXXXX..XXXXXXX 100644 | ||
106 | --- a/tests/test-bdrv-graph-mod.c | ||
107 | +++ b/tests/test-bdrv-graph-mod.c | ||
108 | @@ -XXX,XX +XXX,XX @@ static void test_update_perm_tree(void) | ||
109 | |||
110 | blk_insert_bs(root, bs, &error_abort); | ||
111 | |||
112 | - bdrv_attach_child(filter, bs, "child", &child_file, 0, &error_abort); | ||
113 | + bdrv_attach_child(filter, bs, "child", &child_of_bds, | ||
114 | + BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, &error_abort); | ||
115 | |||
116 | bdrv_append(filter, bs, &local_err); | ||
117 | |||
118 | @@ -XXX,XX +XXX,XX @@ static void test_should_update_child(void) | ||
119 | bdrv_set_backing_hd(target, bs, &error_abort); | ||
120 | |||
121 | g_assert(target->backing->bs == bs); | ||
122 | - bdrv_attach_child(filter, target, "target", &child_file, 0, &error_abort); | ||
123 | + bdrv_attach_child(filter, target, "target", &child_of_bds, | ||
124 | + BDRV_CHILD_DATA, &error_abort); | ||
125 | bdrv_append(filter, bs, &error_abort); | ||
126 | g_assert(target->backing->bs == bs); | ||
127 | 42 | ||
128 | -- | 43 | -- |
129 | 2.25.4 | 44 | 2.37.3 |
130 | |||
131 | diff view generated by jsdifflib |
1 | From: Max Reitz <mreitz@redhat.com> | 1 | From: Paolo Bonzini <pbonzini@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Implementations should decide the necessary permissions based on @role. | 3 | Callers of coroutine_fn must be coroutine_fn themselves, or the call |
4 | must be within "if (qemu_in_coroutine())". Apply coroutine_fn to | ||
5 | functions where this holds. | ||
4 | 6 | ||
5 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 7 | Reviewed-by: Alberto Faria <afaria@redhat.com> |
6 | Message-Id: <20200513110544.176672-35-mreitz@redhat.com> | 8 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
7 | Reviewed-by: Eric Blake <eblake@redhat.com> | 9 | Message-Id: <20220922084924.201610-23-pbonzini@redhat.com> |
10 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
8 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
9 | --- | 12 | --- |
10 | include/block/block_int.h | 4 +--- | 13 | util/qemu-coroutine-lock.c | 14 +++++++------- |
11 | block.c | 39 +++++++++++++++---------------------- | 14 | 1 file changed, 7 insertions(+), 7 deletions(-) |
12 | block/backup-top.c | 3 +-- | ||
13 | block/blkdebug.c | 3 +-- | ||
14 | block/blklogwrites.c | 3 +-- | ||
15 | block/commit.c | 1 - | ||
16 | block/copy-on-read.c | 1 - | ||
17 | block/mirror.c | 1 - | ||
18 | block/quorum.c | 1 - | ||
19 | block/replication.c | 1 - | ||
20 | block/vvfat.c | 4 +--- | ||
21 | tests/test-bdrv-drain.c | 19 +----------------- | ||
22 | tests/test-bdrv-graph-mod.c | 1 - | ||
23 | 13 files changed, 22 insertions(+), 59 deletions(-) | ||
24 | 15 | ||
25 | diff --git a/include/block/block_int.h b/include/block/block_int.h | 16 | diff --git a/util/qemu-coroutine-lock.c b/util/qemu-coroutine-lock.c |
26 | index XXXXXXX..XXXXXXX 100644 | 17 | index XXXXXXX..XXXXXXX 100644 |
27 | --- a/include/block/block_int.h | 18 | --- a/util/qemu-coroutine-lock.c |
28 | +++ b/include/block/block_int.h | 19 | +++ b/util/qemu-coroutine-lock.c |
29 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { | 20 | @@ -XXX,XX +XXX,XX @@ typedef struct CoWaitRecord { |
30 | * @reopen_queue. | 21 | QSLIST_ENTRY(CoWaitRecord) next; |
31 | */ | 22 | } CoWaitRecord; |
32 | void (*bdrv_child_perm)(BlockDriverState *bs, BdrvChild *c, | 23 | |
33 | - const BdrvChildClass *child_class, | 24 | -static void push_waiter(CoMutex *mutex, CoWaitRecord *w) |
34 | BdrvChildRole role, | 25 | +static void coroutine_fn push_waiter(CoMutex *mutex, CoWaitRecord *w) |
35 | BlockReopenQueue *reopen_queue, | 26 | { |
36 | uint64_t parent_perm, uint64_t parent_shared, | 27 | w->co = qemu_coroutine_self(); |
37 | @@ -XXX,XX +XXX,XX @@ bool bdrv_recurse_can_replace(BlockDriverState *bs, | 28 | QSLIST_INSERT_HEAD_ATOMIC(&mutex->from_push, w, next); |
38 | * child_of_bds child class and set an appropriate BdrvChildRole. | 29 | @@ -XXX,XX +XXX,XX @@ void qemu_co_rwlock_init(CoRwlock *lock) |
39 | */ | ||
40 | void bdrv_default_perms(BlockDriverState *bs, BdrvChild *c, | ||
41 | - const BdrvChildClass *child_class, BdrvChildRole role, | ||
42 | - BlockReopenQueue *reopen_queue, | ||
43 | + BdrvChildRole role, BlockReopenQueue *reopen_queue, | ||
44 | uint64_t perm, uint64_t shared, | ||
45 | uint64_t *nperm, uint64_t *nshared); | ||
46 | |||
47 | diff --git a/block.c b/block.c | ||
48 | index XXXXXXX..XXXXXXX 100644 | ||
49 | --- a/block.c | ||
50 | +++ b/block.c | ||
51 | @@ -XXX,XX +XXX,XX @@ bool bdrv_is_writable(BlockDriverState *bs) | ||
52 | } | 30 | } |
53 | 31 | ||
54 | static void bdrv_child_perm(BlockDriverState *bs, BlockDriverState *child_bs, | 32 | /* Releases the internal CoMutex. */ |
55 | - BdrvChild *c, const BdrvChildClass *child_class, | 33 | -static void qemu_co_rwlock_maybe_wake_one(CoRwlock *lock) |
56 | - BdrvChildRole role, BlockReopenQueue *reopen_queue, | 34 | +static void coroutine_fn qemu_co_rwlock_maybe_wake_one(CoRwlock *lock) |
57 | + BdrvChild *c, BdrvChildRole role, | ||
58 | + BlockReopenQueue *reopen_queue, | ||
59 | uint64_t parent_perm, uint64_t parent_shared, | ||
60 | uint64_t *nperm, uint64_t *nshared) | ||
61 | { | 35 | { |
62 | assert(bs->drv && bs->drv->bdrv_child_perm); | 36 | CoRwTicket *tkt = QSIMPLEQ_FIRST(&lock->tickets); |
63 | - bs->drv->bdrv_child_perm(bs, c, child_class, role, reopen_queue, | 37 | Coroutine *co = NULL; |
64 | + bs->drv->bdrv_child_perm(bs, c, role, reopen_queue, | 38 | @@ -XXX,XX +XXX,XX @@ static void qemu_co_rwlock_maybe_wake_one(CoRwlock *lock) |
65 | parent_perm, parent_shared, | 39 | } |
66 | nperm, nshared); | ||
67 | /* TODO Take force_share from reopen_queue */ | ||
68 | @@ -XXX,XX +XXX,XX @@ static int bdrv_check_perm(BlockDriverState *bs, BlockReopenQueue *q, | ||
69 | uint64_t cur_perm, cur_shared; | ||
70 | bool child_tighten_restr; | ||
71 | |||
72 | - bdrv_child_perm(bs, c->bs, c, c->klass, c->role, q, | ||
73 | + bdrv_child_perm(bs, c->bs, c, c->role, q, | ||
74 | cumulative_perms, cumulative_shared_perms, | ||
75 | &cur_perm, &cur_shared); | ||
76 | ret = bdrv_child_check_perm(c, q, cur_perm, cur_shared, ignore_children, | ||
77 | @@ -XXX,XX +XXX,XX @@ static void bdrv_set_perm(BlockDriverState *bs, uint64_t cumulative_perms, | ||
78 | /* Update all children */ | ||
79 | QLIST_FOREACH(c, &bs->children, next) { | ||
80 | uint64_t cur_perm, cur_shared; | ||
81 | - bdrv_child_perm(bs, c->bs, c, c->klass, c->role, NULL, | ||
82 | + bdrv_child_perm(bs, c->bs, c, c->role, NULL, | ||
83 | cumulative_perms, cumulative_shared_perms, | ||
84 | &cur_perm, &cur_shared); | ||
85 | bdrv_child_set_perm(c, cur_perm, cur_shared); | ||
86 | @@ -XXX,XX +XXX,XX @@ int bdrv_child_refresh_perms(BlockDriverState *bs, BdrvChild *c, Error **errp) | ||
87 | uint64_t perms, shared; | ||
88 | |||
89 | bdrv_get_cumulative_perm(bs, &parent_perms, &parent_shared); | ||
90 | - bdrv_child_perm(bs, c->bs, c, c->klass, c->role, NULL, | ||
91 | + bdrv_child_perm(bs, c->bs, c, c->role, NULL, | ||
92 | parent_perms, parent_shared, &perms, &shared); | ||
93 | |||
94 | return bdrv_child_try_set_perm(c, perms, shared, errp); | ||
95 | @@ -XXX,XX +XXX,XX @@ int bdrv_child_refresh_perms(BlockDriverState *bs, BdrvChild *c, Error **errp) | ||
96 | * filtered child. | ||
97 | */ | ||
98 | static void bdrv_filter_default_perms(BlockDriverState *bs, BdrvChild *c, | ||
99 | - const BdrvChildClass *child_class, | ||
100 | BdrvChildRole role, | ||
101 | BlockReopenQueue *reopen_queue, | ||
102 | uint64_t perm, uint64_t shared, | ||
103 | @@ -XXX,XX +XXX,XX @@ static void bdrv_filter_default_perms(BlockDriverState *bs, BdrvChild *c, | ||
104 | } | 40 | } |
105 | 41 | ||
106 | static void bdrv_default_perms_for_cow(BlockDriverState *bs, BdrvChild *c, | 42 | -void qemu_co_rwlock_rdlock(CoRwlock *lock) |
107 | - const BdrvChildClass *child_class, | 43 | +void coroutine_fn qemu_co_rwlock_rdlock(CoRwlock *lock) |
108 | BdrvChildRole role, | ||
109 | BlockReopenQueue *reopen_queue, | ||
110 | uint64_t perm, uint64_t shared, | ||
111 | uint64_t *nperm, uint64_t *nshared) | ||
112 | { | 44 | { |
113 | - assert(child_class == &child_of_bds && (role & BDRV_CHILD_COW)); | 45 | Coroutine *self = qemu_coroutine_self(); |
114 | + assert(role & BDRV_CHILD_COW); | 46 | |
115 | 47 | @@ -XXX,XX +XXX,XX @@ void qemu_co_rwlock_rdlock(CoRwlock *lock) | |
116 | /* | 48 | self->locks_held++; |
117 | * We want consistent read from backing files if the parent needs it. | ||
118 | @@ -XXX,XX +XXX,XX @@ static void bdrv_default_perms_for_cow(BlockDriverState *bs, BdrvChild *c, | ||
119 | } | 49 | } |
120 | 50 | ||
121 | static void bdrv_default_perms_for_storage(BlockDriverState *bs, BdrvChild *c, | 51 | -void qemu_co_rwlock_unlock(CoRwlock *lock) |
122 | - const BdrvChildClass *child_class, | 52 | +void coroutine_fn qemu_co_rwlock_unlock(CoRwlock *lock) |
123 | BdrvChildRole role, | ||
124 | BlockReopenQueue *reopen_queue, | ||
125 | uint64_t perm, uint64_t shared, | ||
126 | @@ -XXX,XX +XXX,XX @@ static void bdrv_default_perms_for_storage(BlockDriverState *bs, BdrvChild *c, | ||
127 | { | 53 | { |
128 | int flags; | 54 | Coroutine *self = qemu_coroutine_self(); |
129 | 55 | ||
130 | - assert(child_class == &child_of_bds && | 56 | @@ -XXX,XX +XXX,XX @@ void qemu_co_rwlock_unlock(CoRwlock *lock) |
131 | - (role & (BDRV_CHILD_METADATA | BDRV_CHILD_DATA))); | 57 | qemu_co_rwlock_maybe_wake_one(lock); |
132 | + assert(role & (BDRV_CHILD_METADATA | BDRV_CHILD_DATA)); | ||
133 | |||
134 | flags = bdrv_reopen_get_flags(reopen_queue, bs); | ||
135 | |||
136 | @@ -XXX,XX +XXX,XX @@ static void bdrv_default_perms_for_storage(BlockDriverState *bs, BdrvChild *c, | ||
137 | * Apart from the modifications below, the same permissions are | ||
138 | * forwarded and left alone as for filters | ||
139 | */ | ||
140 | - bdrv_filter_default_perms(bs, c, child_class, role, reopen_queue, | ||
141 | + bdrv_filter_default_perms(bs, c, role, reopen_queue, | ||
142 | perm, shared, &perm, &shared); | ||
143 | |||
144 | if (role & BDRV_CHILD_METADATA) { | ||
145 | @@ -XXX,XX +XXX,XX @@ static void bdrv_default_perms_for_storage(BlockDriverState *bs, BdrvChild *c, | ||
146 | } | 58 | } |
147 | 59 | ||
148 | void bdrv_default_perms(BlockDriverState *bs, BdrvChild *c, | 60 | -void qemu_co_rwlock_downgrade(CoRwlock *lock) |
149 | - const BdrvChildClass *child_class, BdrvChildRole role, | 61 | +void coroutine_fn qemu_co_rwlock_downgrade(CoRwlock *lock) |
150 | - BlockReopenQueue *reopen_queue, | ||
151 | + BdrvChildRole role, BlockReopenQueue *reopen_queue, | ||
152 | uint64_t perm, uint64_t shared, | ||
153 | uint64_t *nperm, uint64_t *nshared) | ||
154 | { | 62 | { |
155 | - assert(child_class == &child_of_bds); | 63 | qemu_co_mutex_lock(&lock->mutex); |
156 | - | 64 | assert(lock->owners == -1); |
157 | if (role & BDRV_CHILD_FILTERED) { | 65 | @@ -XXX,XX +XXX,XX @@ void qemu_co_rwlock_downgrade(CoRwlock *lock) |
158 | assert(!(role & (BDRV_CHILD_DATA | BDRV_CHILD_METADATA | | 66 | qemu_co_rwlock_maybe_wake_one(lock); |
159 | BDRV_CHILD_COW))); | ||
160 | - bdrv_filter_default_perms(bs, c, child_class, role, reopen_queue, | ||
161 | + bdrv_filter_default_perms(bs, c, role, reopen_queue, | ||
162 | perm, shared, nperm, nshared); | ||
163 | } else if (role & BDRV_CHILD_COW) { | ||
164 | assert(!(role & (BDRV_CHILD_DATA | BDRV_CHILD_METADATA))); | ||
165 | - bdrv_default_perms_for_cow(bs, c, child_class, role, reopen_queue, | ||
166 | + bdrv_default_perms_for_cow(bs, c, role, reopen_queue, | ||
167 | perm, shared, nperm, nshared); | ||
168 | } else if (role & (BDRV_CHILD_METADATA | BDRV_CHILD_DATA)) { | ||
169 | - bdrv_default_perms_for_storage(bs, c, child_class, role, reopen_queue, | ||
170 | + bdrv_default_perms_for_storage(bs, c, role, reopen_queue, | ||
171 | perm, shared, nperm, nshared); | ||
172 | } else { | ||
173 | g_assert_not_reached(); | ||
174 | @@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs, | ||
175 | bdrv_get_cumulative_perm(parent_bs, &perm, &shared_perm); | ||
176 | |||
177 | assert(parent_bs->drv); | ||
178 | - bdrv_child_perm(parent_bs, child_bs, NULL, child_class, child_role, NULL, | ||
179 | + bdrv_child_perm(parent_bs, child_bs, NULL, child_role, NULL, | ||
180 | perm, shared_perm, &perm, &shared_perm); | ||
181 | |||
182 | child = bdrv_root_attach_child(child_bs, child_name, child_class, | ||
183 | @@ -XXX,XX +XXX,XX @@ int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp) | ||
184 | if (state->replace_backing_bs && state->new_backing_bs) { | ||
185 | uint64_t nperm, nshared; | ||
186 | bdrv_child_perm(state->bs, state->new_backing_bs, | ||
187 | - NULL, &child_of_bds, bdrv_backing_role(state->bs), | ||
188 | + NULL, bdrv_backing_role(state->bs), | ||
189 | bs_queue, state->perm, state->shared_perm, | ||
190 | &nperm, &nshared); | ||
191 | ret = bdrv_check_update_perm(state->new_backing_bs, NULL, | ||
192 | @@ -XXX,XX +XXX,XX @@ static void bdrv_reopen_perm(BlockReopenQueue *q, BlockDriverState *bs, | ||
193 | } else { | ||
194 | uint64_t nperm, nshared; | ||
195 | |||
196 | - bdrv_child_perm(parent->state.bs, bs, c, c->klass, c->role, q, | ||
197 | + bdrv_child_perm(parent->state.bs, bs, c, c->role, q, | ||
198 | parent->state.perm, parent->state.shared_perm, | ||
199 | &nperm, &nshared); | ||
200 | |||
201 | diff --git a/block/backup-top.c b/block/backup-top.c | ||
202 | index XXXXXXX..XXXXXXX 100644 | ||
203 | --- a/block/backup-top.c | ||
204 | +++ b/block/backup-top.c | ||
205 | @@ -XXX,XX +XXX,XX @@ static void backup_top_refresh_filename(BlockDriverState *bs) | ||
206 | } | 67 | } |
207 | 68 | ||
208 | static void backup_top_child_perm(BlockDriverState *bs, BdrvChild *c, | 69 | -void qemu_co_rwlock_wrlock(CoRwlock *lock) |
209 | - const BdrvChildClass *child_class, | 70 | +void coroutine_fn qemu_co_rwlock_wrlock(CoRwlock *lock) |
210 | BdrvChildRole role, | 71 | { |
211 | BlockReopenQueue *reopen_queue, | 72 | Coroutine *self = qemu_coroutine_self(); |
212 | uint64_t perm, uint64_t shared, | 73 | |
213 | @@ -XXX,XX +XXX,XX @@ static void backup_top_child_perm(BlockDriverState *bs, BdrvChild *c, | 74 | @@ -XXX,XX +XXX,XX @@ void qemu_co_rwlock_wrlock(CoRwlock *lock) |
214 | *nperm = BLK_PERM_WRITE; | 75 | self->locks_held++; |
215 | } else { | ||
216 | /* Source child */ | ||
217 | - bdrv_default_perms(bs, c, child_class, role, reopen_queue, | ||
218 | + bdrv_default_perms(bs, c, role, reopen_queue, | ||
219 | perm, shared, nperm, nshared); | ||
220 | |||
221 | if (perm & BLK_PERM_WRITE) { | ||
222 | diff --git a/block/blkdebug.c b/block/blkdebug.c | ||
223 | index XXXXXXX..XXXXXXX 100644 | ||
224 | --- a/block/blkdebug.c | ||
225 | +++ b/block/blkdebug.c | ||
226 | @@ -XXX,XX +XXX,XX @@ static int blkdebug_reopen_prepare(BDRVReopenState *reopen_state, | ||
227 | } | 76 | } |
228 | 77 | ||
229 | static void blkdebug_child_perm(BlockDriverState *bs, BdrvChild *c, | 78 | -void qemu_co_rwlock_upgrade(CoRwlock *lock) |
230 | - const BdrvChildClass *child_class, | 79 | +void coroutine_fn qemu_co_rwlock_upgrade(CoRwlock *lock) |
231 | BdrvChildRole role, | ||
232 | BlockReopenQueue *reopen_queue, | ||
233 | uint64_t perm, uint64_t shared, | ||
234 | @@ -XXX,XX +XXX,XX @@ static void blkdebug_child_perm(BlockDriverState *bs, BdrvChild *c, | ||
235 | { | 80 | { |
236 | BDRVBlkdebugState *s = bs->opaque; | 81 | qemu_co_mutex_lock(&lock->mutex); |
237 | 82 | assert(lock->owners > 0); | |
238 | - bdrv_default_perms(bs, c, child_class, role, reopen_queue, | ||
239 | + bdrv_default_perms(bs, c, role, reopen_queue, | ||
240 | perm, shared, nperm, nshared); | ||
241 | |||
242 | *nperm |= s->take_child_perms; | ||
243 | diff --git a/block/blklogwrites.c b/block/blklogwrites.c | ||
244 | index XXXXXXX..XXXXXXX 100644 | ||
245 | --- a/block/blklogwrites.c | ||
246 | +++ b/block/blklogwrites.c | ||
247 | @@ -XXX,XX +XXX,XX @@ static int64_t blk_log_writes_getlength(BlockDriverState *bs) | ||
248 | } | ||
249 | |||
250 | static void blk_log_writes_child_perm(BlockDriverState *bs, BdrvChild *c, | ||
251 | - const BdrvChildClass *child_class, | ||
252 | BdrvChildRole role, | ||
253 | BlockReopenQueue *ro_q, | ||
254 | uint64_t perm, uint64_t shrd, | ||
255 | @@ -XXX,XX +XXX,XX @@ static void blk_log_writes_child_perm(BlockDriverState *bs, BdrvChild *c, | ||
256 | return; | ||
257 | } | ||
258 | |||
259 | - bdrv_default_perms(bs, c, child_class, role, ro_q, perm, shrd, | ||
260 | + bdrv_default_perms(bs, c, role, ro_q, perm, shrd, | ||
261 | nperm, nshrd); | ||
262 | } | ||
263 | |||
264 | diff --git a/block/commit.c b/block/commit.c | ||
265 | index XXXXXXX..XXXXXXX 100644 | ||
266 | --- a/block/commit.c | ||
267 | +++ b/block/commit.c | ||
268 | @@ -XXX,XX +XXX,XX @@ static void bdrv_commit_top_refresh_filename(BlockDriverState *bs) | ||
269 | } | ||
270 | |||
271 | static void bdrv_commit_top_child_perm(BlockDriverState *bs, BdrvChild *c, | ||
272 | - const BdrvChildClass *child_class, | ||
273 | BdrvChildRole role, | ||
274 | BlockReopenQueue *reopen_queue, | ||
275 | uint64_t perm, uint64_t shared, | ||
276 | diff --git a/block/copy-on-read.c b/block/copy-on-read.c | ||
277 | index XXXXXXX..XXXXXXX 100644 | ||
278 | --- a/block/copy-on-read.c | ||
279 | +++ b/block/copy-on-read.c | ||
280 | @@ -XXX,XX +XXX,XX @@ static int cor_open(BlockDriverState *bs, QDict *options, int flags, | ||
281 | #define PERM_UNCHANGED (BLK_PERM_ALL & ~PERM_PASSTHROUGH) | ||
282 | |||
283 | static void cor_child_perm(BlockDriverState *bs, BdrvChild *c, | ||
284 | - const BdrvChildClass *child_class, | ||
285 | BdrvChildRole role, | ||
286 | BlockReopenQueue *reopen_queue, | ||
287 | uint64_t perm, uint64_t shared, | ||
288 | diff --git a/block/mirror.c b/block/mirror.c | ||
289 | index XXXXXXX..XXXXXXX 100644 | ||
290 | --- a/block/mirror.c | ||
291 | +++ b/block/mirror.c | ||
292 | @@ -XXX,XX +XXX,XX @@ static void bdrv_mirror_top_refresh_filename(BlockDriverState *bs) | ||
293 | } | ||
294 | |||
295 | static void bdrv_mirror_top_child_perm(BlockDriverState *bs, BdrvChild *c, | ||
296 | - const BdrvChildClass *child_class, | ||
297 | BdrvChildRole role, | ||
298 | BlockReopenQueue *reopen_queue, | ||
299 | uint64_t perm, uint64_t shared, | ||
300 | diff --git a/block/quorum.c b/block/quorum.c | ||
301 | index XXXXXXX..XXXXXXX 100644 | ||
302 | --- a/block/quorum.c | ||
303 | +++ b/block/quorum.c | ||
304 | @@ -XXX,XX +XXX,XX @@ static char *quorum_dirname(BlockDriverState *bs, Error **errp) | ||
305 | } | ||
306 | |||
307 | static void quorum_child_perm(BlockDriverState *bs, BdrvChild *c, | ||
308 | - const BdrvChildClass *child_class, | ||
309 | BdrvChildRole role, | ||
310 | BlockReopenQueue *reopen_queue, | ||
311 | uint64_t perm, uint64_t shared, | ||
312 | diff --git a/block/replication.c b/block/replication.c | ||
313 | index XXXXXXX..XXXXXXX 100644 | ||
314 | --- a/block/replication.c | ||
315 | +++ b/block/replication.c | ||
316 | @@ -XXX,XX +XXX,XX @@ static void replication_close(BlockDriverState *bs) | ||
317 | } | ||
318 | |||
319 | static void replication_child_perm(BlockDriverState *bs, BdrvChild *c, | ||
320 | - const BdrvChildClass *child_class, | ||
321 | BdrvChildRole role, | ||
322 | BlockReopenQueue *reopen_queue, | ||
323 | uint64_t perm, uint64_t shared, | ||
324 | diff --git a/block/vvfat.c b/block/vvfat.c | ||
325 | index XXXXXXX..XXXXXXX 100644 | ||
326 | --- a/block/vvfat.c | ||
327 | +++ b/block/vvfat.c | ||
328 | @@ -XXX,XX +XXX,XX @@ err: | ||
329 | } | ||
330 | |||
331 | static void vvfat_child_perm(BlockDriverState *bs, BdrvChild *c, | ||
332 | - const BdrvChildClass *child_class, | ||
333 | BdrvChildRole role, | ||
334 | BlockReopenQueue *reopen_queue, | ||
335 | uint64_t perm, uint64_t shared, | ||
336 | @@ -XXX,XX +XXX,XX @@ static void vvfat_child_perm(BlockDriverState *bs, BdrvChild *c, | ||
337 | { | ||
338 | BDRVVVFATState *s = bs->opaque; | ||
339 | |||
340 | - assert(c == s->qcow || | ||
341 | - (child_class == &child_of_bds && (role & BDRV_CHILD_COW))); | ||
342 | + assert(c == s->qcow || (role & BDRV_CHILD_COW)); | ||
343 | |||
344 | if (c == s->qcow) { | ||
345 | /* This is a private node, nobody should try to attach to it */ | ||
346 | diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c | ||
347 | index XXXXXXX..XXXXXXX 100644 | ||
348 | --- a/tests/test-bdrv-drain.c | ||
349 | +++ b/tests/test-bdrv-drain.c | ||
350 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_test_co_preadv(BlockDriverState *bs, | ||
351 | return 0; | ||
352 | } | ||
353 | |||
354 | -static void bdrv_test_child_perm(BlockDriverState *bs, BdrvChild *c, | ||
355 | - const BdrvChildClass *child_class, | ||
356 | - BdrvChildRole role, | ||
357 | - BlockReopenQueue *reopen_queue, | ||
358 | - uint64_t perm, uint64_t shared, | ||
359 | - uint64_t *nperm, uint64_t *nshared) | ||
360 | -{ | ||
361 | - /* | ||
362 | - * bdrv_default_perms() accepts nothing else, so disguise | ||
363 | - * detach_by_driver_cb_parent. | ||
364 | - */ | ||
365 | - child_class = &child_of_bds; | ||
366 | - | ||
367 | - bdrv_default_perms(bs, c, child_class, role, reopen_queue, | ||
368 | - perm, shared, nperm, nshared); | ||
369 | -} | ||
370 | - | ||
371 | static int bdrv_test_change_backing_file(BlockDriverState *bs, | ||
372 | const char *backing_file, | ||
373 | const char *backing_fmt) | ||
374 | @@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_test = { | ||
375 | .bdrv_co_drain_begin = bdrv_test_co_drain_begin, | ||
376 | .bdrv_co_drain_end = bdrv_test_co_drain_end, | ||
377 | |||
378 | - .bdrv_child_perm = bdrv_test_child_perm, | ||
379 | + .bdrv_child_perm = bdrv_default_perms, | ||
380 | |||
381 | .bdrv_change_backing_file = bdrv_test_change_backing_file, | ||
382 | }; | ||
383 | diff --git a/tests/test-bdrv-graph-mod.c b/tests/test-bdrv-graph-mod.c | ||
384 | index XXXXXXX..XXXXXXX 100644 | ||
385 | --- a/tests/test-bdrv-graph-mod.c | ||
386 | +++ b/tests/test-bdrv-graph-mod.c | ||
387 | @@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_pass_through = { | ||
388 | }; | ||
389 | |||
390 | static void no_perm_default_perms(BlockDriverState *bs, BdrvChild *c, | ||
391 | - const BdrvChildClass *child_class, | ||
392 | BdrvChildRole role, | ||
393 | BlockReopenQueue *reopen_queue, | ||
394 | uint64_t perm, uint64_t shared, | ||
395 | -- | 83 | -- |
396 | 2.25.4 | 84 | 2.37.3 |
397 | |||
398 | diff view generated by jsdifflib |
1 | From: Max Reitz <mreitz@redhat.com> | 1 | From: Paolo Bonzini <pbonzini@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Split raw_read_options() into one function that actually just reads the | 3 | Callers of coroutine_fn must be coroutine_fn themselves, or the call |
4 | options, and another that applies them. This will allow us to detect | 4 | must be within "if (qemu_in_coroutine())". Apply coroutine_fn to |
5 | whether the user has specified any options before attaching the file | 5 | functions where this holds. |
6 | child (so we can decide on its role based on the options). | ||
7 | 6 | ||
8 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 7 | Reviewed-by: Alberto Faria <afaria@redhat.com> |
9 | Reviewed-by: Eric Blake <eblake@redhat.com> | 8 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
10 | Message-Id: <20200513110544.176672-21-mreitz@redhat.com> | 9 | Message-Id: <20220922084924.201610-24-pbonzini@redhat.com> |
10 | [kwolf: Fixed up coding style] | ||
11 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
12 | --- | 13 | --- |
13 | block/raw-format.c | 110 ++++++++++++++++++++++++++------------------- | 14 | block/raw-format.c | 3 ++- |
14 | 1 file changed, 65 insertions(+), 45 deletions(-) | 15 | 1 file changed, 2 insertions(+), 1 deletion(-) |
15 | 16 | ||
16 | diff --git a/block/raw-format.c b/block/raw-format.c | 17 | diff --git a/block/raw-format.c b/block/raw-format.c |
17 | index XXXXXXX..XXXXXXX 100644 | 18 | index XXXXXXX..XXXXXXX 100644 |
18 | --- a/block/raw-format.c | 19 | --- a/block/raw-format.c |
19 | +++ b/block/raw-format.c | 20 | +++ b/block/raw-format.c |
20 | @@ -XXX,XX +XXX,XX @@ static QemuOptsList raw_create_opts = { | 21 | @@ -XXX,XX +XXX,XX @@ static void raw_lock_medium(BlockDriverState *bs, bool locked) |
21 | } | 22 | bdrv_lock_medium(bs->file->bs, locked); |
22 | }; | ||
23 | |||
24 | -static int raw_read_options(QDict *options, BlockDriverState *bs, | ||
25 | - BDRVRawState *s, Error **errp) | ||
26 | +static int raw_read_options(QDict *options, uint64_t *offset, bool *has_size, | ||
27 | + uint64_t *size, Error **errp) | ||
28 | { | ||
29 | Error *local_err = NULL; | ||
30 | QemuOpts *opts = NULL; | ||
31 | - int64_t real_size = 0; | ||
32 | int ret; | ||
33 | |||
34 | - real_size = bdrv_getlength(bs->file->bs); | ||
35 | - if (real_size < 0) { | ||
36 | - error_setg_errno(errp, -real_size, "Could not get image size"); | ||
37 | - return real_size; | ||
38 | - } | ||
39 | - | ||
40 | opts = qemu_opts_create(&raw_runtime_opts, NULL, 0, &error_abort); | ||
41 | qemu_opts_absorb_qdict(opts, options, &local_err); | ||
42 | if (local_err) { | ||
43 | @@ -XXX,XX +XXX,XX @@ static int raw_read_options(QDict *options, BlockDriverState *bs, | ||
44 | goto end; | ||
45 | } | ||
46 | |||
47 | - s->offset = qemu_opt_get_size(opts, "offset", 0); | ||
48 | - if (s->offset > real_size) { | ||
49 | - error_setg(errp, "Offset (%" PRIu64 ") cannot be greater than " | ||
50 | - "size of the containing file (%" PRId64 ")", | ||
51 | - s->offset, real_size); | ||
52 | - ret = -EINVAL; | ||
53 | - goto end; | ||
54 | - } | ||
55 | + *offset = qemu_opt_get_size(opts, "offset", 0); | ||
56 | + *has_size = qemu_opt_find(opts, "size"); | ||
57 | + *size = qemu_opt_get_size(opts, "size", 0); | ||
58 | |||
59 | - if (qemu_opt_find(opts, "size") != NULL) { | ||
60 | - s->size = qemu_opt_get_size(opts, "size", 0); | ||
61 | - s->has_size = true; | ||
62 | - } else { | ||
63 | - s->has_size = false; | ||
64 | - s->size = real_size - s->offset; | ||
65 | + ret = 0; | ||
66 | +end: | ||
67 | + qemu_opts_del(opts); | ||
68 | + return ret; | ||
69 | +} | ||
70 | + | ||
71 | +static int raw_apply_options(BlockDriverState *bs, BDRVRawState *s, | ||
72 | + uint64_t offset, bool has_size, uint64_t size, | ||
73 | + Error **errp) | ||
74 | +{ | ||
75 | + int64_t real_size = 0; | ||
76 | + | ||
77 | + real_size = bdrv_getlength(bs->file->bs); | ||
78 | + if (real_size < 0) { | ||
79 | + error_setg_errno(errp, -real_size, "Could not get image size"); | ||
80 | + return real_size; | ||
81 | } | ||
82 | |||
83 | /* Check size and offset */ | ||
84 | - if ((real_size - s->offset) < s->size) { | ||
85 | + if (offset > real_size) { | ||
86 | + error_setg(errp, "Offset (%" PRIu64 ") cannot be greater than " | ||
87 | + "size of the containing file (%" PRId64 ")", | ||
88 | + s->offset, real_size); | ||
89 | + return -EINVAL; | ||
90 | + } | ||
91 | + | ||
92 | + if (has_size && (real_size - offset) < size) { | ||
93 | error_setg(errp, "The sum of offset (%" PRIu64 ") and size " | ||
94 | - "(%" PRIu64 ") has to be smaller or equal to the " | ||
95 | - " actual size of the containing file (%" PRId64 ")", | ||
96 | - s->offset, s->size, real_size); | ||
97 | - ret = -EINVAL; | ||
98 | - goto end; | ||
99 | + "(%" PRIu64 ") has to be smaller or equal to the " | ||
100 | + " actual size of the containing file (%" PRId64 ")", | ||
101 | + s->offset, s->size, real_size); | ||
102 | + return -EINVAL; | ||
103 | } | ||
104 | |||
105 | /* Make sure size is multiple of BDRV_SECTOR_SIZE to prevent rounding | ||
106 | * up and leaking out of the specified area. */ | ||
107 | - if (s->has_size && !QEMU_IS_ALIGNED(s->size, BDRV_SECTOR_SIZE)) { | ||
108 | + if (has_size && !QEMU_IS_ALIGNED(size, BDRV_SECTOR_SIZE)) { | ||
109 | error_setg(errp, "Specified size is not multiple of %llu", | ||
110 | - BDRV_SECTOR_SIZE); | ||
111 | - ret = -EINVAL; | ||
112 | - goto end; | ||
113 | + BDRV_SECTOR_SIZE); | ||
114 | + return -EINVAL; | ||
115 | } | ||
116 | |||
117 | - ret = 0; | ||
118 | - | ||
119 | -end: | ||
120 | + s->offset = offset; | ||
121 | + s->has_size = has_size; | ||
122 | + s->size = has_size ? size : real_size - offset; | ||
123 | |||
124 | - qemu_opts_del(opts); | ||
125 | - | ||
126 | - return ret; | ||
127 | + return 0; | ||
128 | } | 23 | } |
129 | 24 | ||
130 | static int raw_reopen_prepare(BDRVReopenState *reopen_state, | 25 | -static int raw_co_ioctl(BlockDriverState *bs, unsigned long int req, void *buf) |
131 | BlockReopenQueue *queue, Error **errp) | 26 | +static int coroutine_fn raw_co_ioctl(BlockDriverState *bs, |
132 | { | 27 | + unsigned long int req, void *buf) |
133 | + bool has_size; | ||
134 | + uint64_t offset, size; | ||
135 | + int ret; | ||
136 | + | ||
137 | assert(reopen_state != NULL); | ||
138 | assert(reopen_state->bs != NULL); | ||
139 | |||
140 | reopen_state->opaque = g_new0(BDRVRawState, 1); | ||
141 | |||
142 | - return raw_read_options( | ||
143 | - reopen_state->options, | ||
144 | - reopen_state->bs, | ||
145 | - reopen_state->opaque, | ||
146 | - errp); | ||
147 | + ret = raw_read_options(reopen_state->options, &offset, &has_size, &size, | ||
148 | + errp); | ||
149 | + if (ret < 0) { | ||
150 | + return ret; | ||
151 | + } | ||
152 | + | ||
153 | + ret = raw_apply_options(reopen_state->bs, reopen_state->opaque, | ||
154 | + offset, has_size, size, errp); | ||
155 | + if (ret < 0) { | ||
156 | + return ret; | ||
157 | + } | ||
158 | + | ||
159 | + return 0; | ||
160 | } | ||
161 | |||
162 | static void raw_reopen_commit(BDRVReopenState *state) | ||
163 | @@ -XXX,XX +XXX,XX @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags, | ||
164 | Error **errp) | ||
165 | { | 28 | { |
166 | BDRVRawState *s = bs->opaque; | 29 | BDRVRawState *s = bs->opaque; |
167 | + bool has_size; | 30 | if (s->offset || s->has_size) { |
168 | + uint64_t offset, size; | ||
169 | int ret; | ||
170 | |||
171 | + ret = raw_read_options(options, &offset, &has_size, &size, errp); | ||
172 | + if (ret < 0) { | ||
173 | + return ret; | ||
174 | + } | ||
175 | + | ||
176 | bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, | ||
177 | false, errp); | ||
178 | if (!bs->file) { | ||
179 | @@ -XXX,XX +XXX,XX @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags, | ||
180 | bs->file->bs->filename); | ||
181 | } | ||
182 | |||
183 | - ret = raw_read_options(options, bs, s, errp); | ||
184 | + ret = raw_apply_options(bs, s, offset, has_size, size, errp); | ||
185 | if (ret < 0) { | ||
186 | return ret; | ||
187 | } | ||
188 | -- | 31 | -- |
189 | 2.25.4 | 32 | 2.37.3 |
190 | |||
191 | diff view generated by jsdifflib |
1 | From: Max Reitz <mreitz@redhat.com> | 1 | From: Marc-André Lureau <marcandre.lureau@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Let child_file's, child_format's, and child_backing's .inherit_options() | 3 | Callers of coroutine_fn must be coroutine_fn themselves, or the call |
4 | implementations fall back to bdrv_inherited_options() to show that it | 4 | must be within "if (qemu_in_coroutine())". Apply coroutine_fn to |
5 | would really work for all of these cases, if only the parents passed the | 5 | functions where this holds. |
6 | appropriate BdrvChildRole and parent_is_format values. | ||
7 | 6 | ||
8 | (Also, make bdrv_open_inherit(), the only place to explicitly call | 7 | Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> |
9 | bdrv_backing_options(), call bdrv_inherited_options() instead.) | 8 | Acked-by: Greg Kurz <groug@kaod.org> |
10 | 9 | Reviewed-by: Alberto Faria <afaria@redhat.com> | |
11 | This patch should incur only two visible changes, both for child_format | 10 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
12 | children, both of which are effectively bug fixes: | 11 | Message-Id: <20220922084924.201610-25-pbonzini@redhat.com> |
13 | 12 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | |
14 | First, they no longer have discard=unmap set by default. This reason it | ||
15 | was set is because bdrv_inherited_fmt_options() fell through to | ||
16 | bdrv_protocol_options(), and that set it because "format drivers take | ||
17 | care to send flushes and respect unmap policy". None of the drivers | ||
18 | that use child_format for their children (quorum and blkverify) are | ||
19 | format drivers, though, so this reasoning does not apply here. | ||
20 | |||
21 | Second, they no longer have BDRV_O_NO_IO force-cleared. child_format | ||
22 | was used solely for children that do not store any metadata and as such | ||
23 | will not be accessed by their parents as long as those parents do not | ||
24 | receive I/O themselves. Thus, such children should inherit | ||
25 | BDRV_O_NO_IO. | ||
26 | |||
27 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
28 | Message-Id: <20200513110544.176672-12-mreitz@redhat.com> | ||
29 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
30 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 13 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
31 | --- | 14 | --- |
32 | block.c | 71 +++++++++++++++------------------------------------------ | 15 | hw/9pfs/9p.h | 9 ++++++--- |
33 | 1 file changed, 19 insertions(+), 52 deletions(-) | 16 | 1 file changed, 6 insertions(+), 3 deletions(-) |
34 | 17 | ||
35 | diff --git a/block.c b/block.c | 18 | diff --git a/hw/9pfs/9p.h b/hw/9pfs/9p.h |
36 | index XXXXXXX..XXXXXXX 100644 | 19 | index XXXXXXX..XXXXXXX 100644 |
37 | --- a/block.c | 20 | --- a/hw/9pfs/9p.h |
38 | +++ b/block.c | 21 | +++ b/hw/9pfs/9p.h |
39 | @@ -XXX,XX +XXX,XX @@ static BlockDriverState *bdrv_open_inherit(const char *filename, | 22 | @@ -XXX,XX +XXX,XX @@ typedef struct V9fsGetlock |
40 | BdrvChildRole child_role, | 23 | extern int open_fd_hw; |
41 | Error **errp); | 24 | extern int total_open_fd; |
42 | 25 | ||
43 | +/* TODO: Remove when no longer needed */ | 26 | -static inline void v9fs_path_write_lock(V9fsState *s) |
44 | +static void bdrv_inherited_options(BdrvChildRole role, bool parent_is_format, | 27 | +static inline void coroutine_fn |
45 | + int *child_flags, QDict *child_options, | 28 | +v9fs_path_write_lock(V9fsState *s) |
46 | + int parent_flags, QDict *parent_options); | ||
47 | + | ||
48 | /* If non-zero, use only whitelisted block drivers */ | ||
49 | static int use_bdrv_whitelist; | ||
50 | |||
51 | @@ -XXX,XX +XXX,XX @@ static void bdrv_protocol_options(BdrvChildRole role, bool parent_is_format, | ||
52 | int *child_flags, QDict *child_options, | ||
53 | int parent_flags, QDict *parent_options) | ||
54 | { | 29 | { |
55 | - int flags = parent_flags; | 30 | if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) { |
56 | - | 31 | qemu_co_rwlock_wrlock(&s->rename_lock); |
57 | - /* Enable protocol handling, disable format probing for bs->file */ | 32 | } |
58 | - flags |= BDRV_O_PROTOCOL; | ||
59 | - | ||
60 | - /* If the cache mode isn't explicitly set, inherit direct and no-flush from | ||
61 | - * the parent. */ | ||
62 | - qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_DIRECT); | ||
63 | - qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_NO_FLUSH); | ||
64 | - qdict_copy_default(child_options, parent_options, BDRV_OPT_FORCE_SHARE); | ||
65 | - | ||
66 | - /* Inherit the read-only option from the parent if it's not set */ | ||
67 | - qdict_copy_default(child_options, parent_options, BDRV_OPT_READ_ONLY); | ||
68 | - qdict_copy_default(child_options, parent_options, BDRV_OPT_AUTO_READ_ONLY); | ||
69 | - | ||
70 | - /* Our block drivers take care to send flushes and respect unmap policy, | ||
71 | - * so we can default to enable both on lower layers regardless of the | ||
72 | - * corresponding parent options. */ | ||
73 | - qdict_set_default_str(child_options, BDRV_OPT_DISCARD, "unmap"); | ||
74 | - | ||
75 | - /* Clear flags that only apply to the top layer */ | ||
76 | - flags &= ~(BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING | BDRV_O_COPY_ON_READ | | ||
77 | - BDRV_O_NO_IO); | ||
78 | - | ||
79 | - *child_flags = flags; | ||
80 | + bdrv_inherited_options(BDRV_CHILD_IMAGE, true, | ||
81 | + child_flags, child_options, | ||
82 | + parent_flags, parent_options); | ||
83 | } | 33 | } |
84 | 34 | ||
85 | const BdrvChildClass child_file = { | 35 | -static inline void v9fs_path_read_lock(V9fsState *s) |
86 | @@ -XXX,XX +XXX,XX @@ static void bdrv_inherited_fmt_options(BdrvChildRole role, | 36 | +static inline void coroutine_fn |
87 | int *child_flags, QDict *child_options, | 37 | +v9fs_path_read_lock(V9fsState *s) |
88 | int parent_flags, QDict *parent_options) | ||
89 | { | 38 | { |
90 | - child_file.inherit_options(role, parent_is_format, | 39 | if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) { |
91 | - child_flags, child_options, | 40 | qemu_co_rwlock_rdlock(&s->rename_lock); |
92 | - parent_flags, parent_options); | 41 | } |
93 | - | ||
94 | - *child_flags &= ~(BDRV_O_PROTOCOL | BDRV_O_NO_IO); | ||
95 | + bdrv_inherited_options(BDRV_CHILD_DATA, false, | ||
96 | + child_flags, child_options, | ||
97 | + parent_flags, parent_options); | ||
98 | } | 42 | } |
99 | 43 | ||
100 | const BdrvChildClass child_format = { | 44 | -static inline void v9fs_path_unlock(V9fsState *s) |
101 | @@ -XXX,XX +XXX,XX @@ static void bdrv_backing_options(BdrvChildRole role, bool parent_is_format, | 45 | +static inline void coroutine_fn |
102 | int *child_flags, QDict *child_options, | 46 | +v9fs_path_unlock(V9fsState *s) |
103 | int parent_flags, QDict *parent_options) | ||
104 | { | 47 | { |
105 | - int flags = parent_flags; | 48 | if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) { |
106 | - | 49 | qemu_co_rwlock_unlock(&s->rename_lock); |
107 | - /* The cache mode is inherited unmodified for backing files; except WCE, | ||
108 | - * which is only applied on the top level (BlockBackend) */ | ||
109 | - qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_DIRECT); | ||
110 | - qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_NO_FLUSH); | ||
111 | - qdict_copy_default(child_options, parent_options, BDRV_OPT_FORCE_SHARE); | ||
112 | - | ||
113 | - /* backing files always opened read-only */ | ||
114 | - qdict_set_default_str(child_options, BDRV_OPT_READ_ONLY, "on"); | ||
115 | - qdict_set_default_str(child_options, BDRV_OPT_AUTO_READ_ONLY, "off"); | ||
116 | - flags &= ~BDRV_O_COPY_ON_READ; | ||
117 | - | ||
118 | - /* snapshot=on is handled on the top layer */ | ||
119 | - flags &= ~(BDRV_O_SNAPSHOT | BDRV_O_TEMPORARY); | ||
120 | - | ||
121 | - *child_flags = flags; | ||
122 | + bdrv_inherited_options(BDRV_CHILD_COW, true, | ||
123 | + child_flags, child_options, | ||
124 | + parent_flags, parent_options); | ||
125 | } | ||
126 | |||
127 | static int bdrv_backing_update_filename(BdrvChild *c, BlockDriverState *base, | ||
128 | @@ -XXX,XX +XXX,XX @@ const BdrvChildClass child_backing = { | ||
129 | * Returns the options and flags that a generic child of a BDS should | ||
130 | * get, based on the given options and flags for the parent BDS. | ||
131 | */ | ||
132 | -static void __attribute__((unused)) | ||
133 | - bdrv_inherited_options(BdrvChildRole role, bool parent_is_format, | ||
134 | - int *child_flags, QDict *child_options, | ||
135 | - int parent_flags, QDict *parent_options) | ||
136 | +static void bdrv_inherited_options(BdrvChildRole role, bool parent_is_format, | ||
137 | + int *child_flags, QDict *child_options, | ||
138 | + int parent_flags, QDict *parent_options) | ||
139 | { | ||
140 | int flags = parent_flags; | ||
141 | |||
142 | @@ -XXX,XX +XXX,XX @@ static BlockDriverState *bdrv_open_inherit(const char *filename, | ||
143 | flags, options); | ||
144 | /* Let bdrv_backing_options() override "read-only" */ | ||
145 | qdict_del(options, BDRV_OPT_READ_ONLY); | ||
146 | - bdrv_backing_options(0, true, &flags, options, flags, options); | ||
147 | + bdrv_inherited_options(BDRV_CHILD_COW, true, | ||
148 | + &flags, options, flags, options); | ||
149 | } | ||
150 | |||
151 | bs->open_flags = flags; | ||
152 | -- | 50 | -- |
153 | 2.25.4 | 51 | 2.37.3 |
154 | 52 | ||
155 | 53 | diff view generated by jsdifflib |
1 | This patch makes the raw image the same size as the file in a different | 1 | From: Marc-André Lureau <marcandre.lureau@redhat.com> |
---|---|---|---|
2 | format that is mirrored as raw to it to avoid errors when mirror starts | ||
3 | to enforce that source and target are the same size. | ||
4 | 2 | ||
5 | We check only that the first 512 bytes are zeroed (instead of 64k) | 3 | Callers of coroutine_fn must be coroutine_fn themselves, or the call |
6 | because some image formats create image files that are smaller than 64k, | 4 | must be within "if (qemu_in_coroutine())". Apply coroutine_fn to |
7 | so trying to read 64k would result in I/O errors. Apart from this, 512 | 5 | functions where this holds. |
8 | is more appropriate anyway because the raw format driver protects | ||
9 | specifically the first 512 bytes. | ||
10 | 6 | ||
11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 7 | Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> |
12 | Message-Id: <20200511135825.219437-2-kwolf@redhat.com> | 8 | Reviewed-by: Juan Quintela <quintela@redhat.com> |
13 | Reviewed-by: Max Reitz <mreitz@redhat.com> | 9 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> |
14 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 10 | Reviewed-by: Alberto Faria <afaria@redhat.com> |
11 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> | ||
12 | Message-Id: <20220922084924.201610-26-pbonzini@redhat.com> | ||
13 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
15 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 14 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
16 | --- | 15 | --- |
17 | tests/qemu-iotests/109 | 10 ++--- | 16 | migration/migration.c | 3 ++- |
18 | tests/qemu-iotests/109.out | 74 +++++++++++++------------------- | 17 | 1 file changed, 2 insertions(+), 1 deletion(-) |
19 | tests/qemu-iotests/common.filter | 5 +++ | ||
20 | 3 files changed, 41 insertions(+), 48 deletions(-) | ||
21 | 18 | ||
22 | diff --git a/tests/qemu-iotests/109 b/tests/qemu-iotests/109 | 19 | diff --git a/migration/migration.c b/migration/migration.c |
23 | index XXXXXXX..XXXXXXX 100755 | ||
24 | --- a/tests/qemu-iotests/109 | ||
25 | +++ b/tests/qemu-iotests/109 | ||
26 | @@ -XXX,XX +XXX,XX @@ for fmt in qcow qcow2 qed vdi vmdk vpc; do | ||
27 | echo "=== Writing a $fmt header into raw ===" | ||
28 | echo | ||
29 | |||
30 | - _make_test_img 64M | ||
31 | TEST_IMG="$TEST_IMG.src" IMGFMT=$fmt _make_test_img 64M | ||
32 | + _make_test_img $(du -b "$TEST_IMG.src" | cut -f1) | _filter_img_create_size | ||
33 | |||
34 | # This first test should fail: The image format was probed, we may not | ||
35 | # write an image header at the start of the image | ||
36 | run_qemu "$TEST_IMG" "$TEST_IMG.src" "" "BLOCK_JOB_ERROR" | | ||
37 | _filter_block_job_len | ||
38 | - $QEMU_IO -c 'read -P 0 0 64k' "$TEST_IMG" | _filter_qemu_io | ||
39 | + $QEMU_IO -c 'read -P 0 0 512' "$TEST_IMG" | _filter_qemu_io | ||
40 | |||
41 | |||
42 | # When raw was explicitly specified, the same must succeed | ||
43 | @@ -XXX,XX +XXX,XX @@ for sample_img in empty.bochs iotest-dirtylog-10G-4M.vhdx parallels-v1 \ | ||
44 | |||
45 | # Can't use _use_sample_img because that isn't designed to be used multiple | ||
46 | # times and it overwrites $TEST_IMG (both breaks cleanup) | ||
47 | - _make_test_img 64M | ||
48 | bzcat "$SAMPLE_IMG_DIR/$sample_img.bz2" > "$TEST_IMG.src" | ||
49 | + _make_test_img $(du -b "$TEST_IMG.src" | cut -f1) | _filter_img_create_size | ||
50 | |||
51 | run_qemu "$TEST_IMG" "$TEST_IMG.src" "" "BLOCK_JOB_ERROR" | | ||
52 | _filter_block_job_offset | _filter_block_job_len | ||
53 | - $QEMU_IO -c 'read -P 0 0 64k' "$TEST_IMG" | _filter_qemu_io | ||
54 | + $QEMU_IO -c 'read -P 0 0 512' "$TEST_IMG" | _filter_qemu_io | ||
55 | |||
56 | run_qemu "$TEST_IMG" "$TEST_IMG.src" "'format': 'raw'," "BLOCK_JOB_READY" | ||
57 | $QEMU_IMG compare -f raw -F raw "$TEST_IMG" "$TEST_IMG.src" | ||
58 | @@ -XXX,XX +XXX,XX @@ echo "=== Write legitimate MBR into raw ===" | ||
59 | echo | ||
60 | |||
61 | for sample_img in grub_mbr.raw; do | ||
62 | - _make_test_img 64M | ||
63 | bzcat "$SAMPLE_IMG_DIR/$sample_img.bz2" > "$TEST_IMG.src" | ||
64 | + _make_test_img $(du -b "$TEST_IMG.src" | cut -f1) | _filter_img_create_size | ||
65 | |||
66 | run_qemu "$TEST_IMG" "$TEST_IMG.src" "" "BLOCK_JOB_READY" | ||
67 | $QEMU_IMG compare -f raw -F raw "$TEST_IMG" "$TEST_IMG.src" | ||
68 | diff --git a/tests/qemu-iotests/109.out b/tests/qemu-iotests/109.out | ||
69 | index XXXXXXX..XXXXXXX 100644 | 20 | index XXXXXXX..XXXXXXX 100644 |
70 | --- a/tests/qemu-iotests/109.out | 21 | --- a/migration/migration.c |
71 | +++ b/tests/qemu-iotests/109.out | 22 | +++ b/migration/migration.c |
72 | @@ -XXX,XX +XXX,XX @@ QA output created by 109 | 23 | @@ -XXX,XX +XXX,XX @@ static void process_incoming_migration_bh(void *opaque) |
73 | 24 | migration_incoming_state_destroy(); | |
74 | === Writing a qcow header into raw === | ||
75 | |||
76 | -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 | ||
77 | Formatting 'TEST_DIR/t.raw.src', fmt=IMGFMT size=67108864 | ||
78 | +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=SIZE | ||
79 | { 'execute': 'qmp_capabilities' } | ||
80 | {"return": {}} | ||
81 | {'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'mode': 'existing', 'sync': 'full'}} | ||
82 | @@ -XXX,XX +XXX,XX @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed | ||
83 | {"execute":"quit"} | ||
84 | {"return": {}} | ||
85 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} | ||
86 | -read 65536/65536 bytes at offset 0 | ||
87 | -64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
88 | +read 512/512 bytes at offset 0 | ||
89 | +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
90 | { 'execute': 'qmp_capabilities' } | ||
91 | {"return": {}} | ||
92 | {'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'format': 'IMGFMT', 'mode': 'existing', 'sync': 'full'}} | ||
93 | @@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 0 | ||
94 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 1024, "offset": 1024, "speed": 0, "type": "mirror"}} | ||
95 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}} | ||
96 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}} | ||
97 | -Warning: Image size mismatch! | ||
98 | Images are identical. | ||
99 | |||
100 | === Writing a qcow2 header into raw === | ||
101 | |||
102 | -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 | ||
103 | Formatting 'TEST_DIR/t.raw.src', fmt=IMGFMT size=67108864 | ||
104 | +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=SIZE | ||
105 | { 'execute': 'qmp_capabilities' } | ||
106 | {"return": {}} | ||
107 | {'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'mode': 'existing', 'sync': 'full'}} | ||
108 | @@ -XXX,XX +XXX,XX @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed | ||
109 | {"execute":"quit"} | ||
110 | {"return": {}} | ||
111 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} | ||
112 | -read 65536/65536 bytes at offset 0 | ||
113 | -64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
114 | +read 512/512 bytes at offset 0 | ||
115 | +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
116 | { 'execute': 'qmp_capabilities' } | ||
117 | {"return": {}} | ||
118 | {'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'format': 'IMGFMT', 'mode': 'existing', 'sync': 'full'}} | ||
119 | @@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 0 | ||
120 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 197120, "offset": 197120, "speed": 0, "type": "mirror"}} | ||
121 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}} | ||
122 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}} | ||
123 | -Warning: Image size mismatch! | ||
124 | Images are identical. | ||
125 | |||
126 | === Writing a qed header into raw === | ||
127 | |||
128 | -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 | ||
129 | Formatting 'TEST_DIR/t.raw.src', fmt=IMGFMT size=67108864 | ||
130 | +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=SIZE | ||
131 | { 'execute': 'qmp_capabilities' } | ||
132 | {"return": {}} | ||
133 | {'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'mode': 'existing', 'sync': 'full'}} | ||
134 | @@ -XXX,XX +XXX,XX @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed | ||
135 | {"execute":"quit"} | ||
136 | {"return": {}} | ||
137 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} | ||
138 | -read 65536/65536 bytes at offset 0 | ||
139 | -64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
140 | +read 512/512 bytes at offset 0 | ||
141 | +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
142 | { 'execute': 'qmp_capabilities' } | ||
143 | {"return": {}} | ||
144 | {'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'format': 'IMGFMT', 'mode': 'existing', 'sync': 'full'}} | ||
145 | @@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 0 | ||
146 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 327680, "offset": 327680, "speed": 0, "type": "mirror"}} | ||
147 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}} | ||
148 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}} | ||
149 | -Warning: Image size mismatch! | ||
150 | Images are identical. | ||
151 | |||
152 | === Writing a vdi header into raw === | ||
153 | |||
154 | -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 | ||
155 | Formatting 'TEST_DIR/t.raw.src', fmt=IMGFMT size=67108864 | ||
156 | +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=SIZE | ||
157 | { 'execute': 'qmp_capabilities' } | ||
158 | {"return": {}} | ||
159 | {'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'mode': 'existing', 'sync': 'full'}} | ||
160 | @@ -XXX,XX +XXX,XX @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed | ||
161 | {"execute":"quit"} | ||
162 | {"return": {}} | ||
163 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} | ||
164 | -read 65536/65536 bytes at offset 0 | ||
165 | -64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
166 | +read 512/512 bytes at offset 0 | ||
167 | +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
168 | { 'execute': 'qmp_capabilities' } | ||
169 | {"return": {}} | ||
170 | {'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'format': 'IMGFMT', 'mode': 'existing', 'sync': 'full'}} | ||
171 | @@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 0 | ||
172 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 1024, "offset": 1024, "speed": 0, "type": "mirror"}} | ||
173 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}} | ||
174 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}} | ||
175 | -Warning: Image size mismatch! | ||
176 | Images are identical. | ||
177 | |||
178 | === Writing a vmdk header into raw === | ||
179 | |||
180 | -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 | ||
181 | Formatting 'TEST_DIR/t.raw.src', fmt=IMGFMT size=67108864 | ||
182 | +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=SIZE | ||
183 | { 'execute': 'qmp_capabilities' } | ||
184 | {"return": {}} | ||
185 | {'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'mode': 'existing', 'sync': 'full'}} | ||
186 | @@ -XXX,XX +XXX,XX @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed | ||
187 | {"execute":"quit"} | ||
188 | {"return": {}} | ||
189 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} | ||
190 | -read 65536/65536 bytes at offset 0 | ||
191 | -64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
192 | +read 512/512 bytes at offset 0 | ||
193 | +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
194 | { 'execute': 'qmp_capabilities' } | ||
195 | {"return": {}} | ||
196 | {'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'format': 'IMGFMT', 'mode': 'existing', 'sync': 'full'}} | ||
197 | @@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 0 | ||
198 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 65536, "offset": 65536, "speed": 0, "type": "mirror"}} | ||
199 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}} | ||
200 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}} | ||
201 | -Warning: Image size mismatch! | ||
202 | Images are identical. | ||
203 | |||
204 | === Writing a vpc header into raw === | ||
205 | |||
206 | -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 | ||
207 | Formatting 'TEST_DIR/t.raw.src', fmt=IMGFMT size=67108864 | ||
208 | +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=SIZE | ||
209 | { 'execute': 'qmp_capabilities' } | ||
210 | {"return": {}} | ||
211 | {'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'mode': 'existing', 'sync': 'full'}} | ||
212 | @@ -XXX,XX +XXX,XX @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed | ||
213 | {"execute":"quit"} | ||
214 | {"return": {}} | ||
215 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} | ||
216 | -read 65536/65536 bytes at offset 0 | ||
217 | -64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
218 | +read 512/512 bytes at offset 0 | ||
219 | +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
220 | { 'execute': 'qmp_capabilities' } | ||
221 | {"return": {}} | ||
222 | {'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'format': 'IMGFMT', 'mode': 'existing', 'sync': 'full'}} | ||
223 | @@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 0 | ||
224 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 2560, "offset": 2560, "speed": 0, "type": "mirror"}} | ||
225 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}} | ||
226 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}} | ||
227 | -Warning: Image size mismatch! | ||
228 | Images are identical. | ||
229 | |||
230 | === Copying sample image empty.bochs into raw === | ||
231 | |||
232 | -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 | ||
233 | +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=SIZE | ||
234 | { 'execute': 'qmp_capabilities' } | ||
235 | {"return": {}} | ||
236 | {'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'mode': 'existing', 'sync': 'full'}} | ||
237 | @@ -XXX,XX +XXX,XX @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed | ||
238 | {"execute":"quit"} | ||
239 | {"return": {}} | ||
240 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} | ||
241 | -read 65536/65536 bytes at offset 0 | ||
242 | -64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
243 | +read 512/512 bytes at offset 0 | ||
244 | +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
245 | { 'execute': 'qmp_capabilities' } | ||
246 | {"return": {}} | ||
247 | {'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'format': 'IMGFMT', 'mode': 'existing', 'sync': 'full'}} | ||
248 | @@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 0 | ||
249 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 2560, "offset": 2560, "speed": 0, "type": "mirror"}} | ||
250 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}} | ||
251 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}} | ||
252 | -Warning: Image size mismatch! | ||
253 | Images are identical. | ||
254 | |||
255 | === Copying sample image iotest-dirtylog-10G-4M.vhdx into raw === | ||
256 | |||
257 | -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 | ||
258 | +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=SIZE | ||
259 | { 'execute': 'qmp_capabilities' } | ||
260 | {"return": {}} | ||
261 | {'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'mode': 'existing', 'sync': 'full'}} | ||
262 | @@ -XXX,XX +XXX,XX @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed | ||
263 | {"execute":"quit"} | ||
264 | {"return": {}} | ||
265 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} | ||
266 | -read 65536/65536 bytes at offset 0 | ||
267 | -64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
268 | +read 512/512 bytes at offset 0 | ||
269 | +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
270 | { 'execute': 'qmp_capabilities' } | ||
271 | {"return": {}} | ||
272 | {'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'format': 'IMGFMT', 'mode': 'existing', 'sync': 'full'}} | ||
273 | @@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 0 | ||
274 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 31457280, "offset": 31457280, "speed": 0, "type": "mirror"}} | ||
275 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}} | ||
276 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}} | ||
277 | -Warning: Image size mismatch! | ||
278 | Images are identical. | ||
279 | |||
280 | === Copying sample image parallels-v1 into raw === | ||
281 | |||
282 | -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 | ||
283 | +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=SIZE | ||
284 | { 'execute': 'qmp_capabilities' } | ||
285 | {"return": {}} | ||
286 | {'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'mode': 'existing', 'sync': 'full'}} | ||
287 | @@ -XXX,XX +XXX,XX @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed | ||
288 | {"execute":"quit"} | ||
289 | {"return": {}} | ||
290 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} | ||
291 | -read 65536/65536 bytes at offset 0 | ||
292 | -64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
293 | +read 512/512 bytes at offset 0 | ||
294 | +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
295 | { 'execute': 'qmp_capabilities' } | ||
296 | {"return": {}} | ||
297 | {'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'format': 'IMGFMT', 'mode': 'existing', 'sync': 'full'}} | ||
298 | @@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 0 | ||
299 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 327680, "offset": 327680, "speed": 0, "type": "mirror"}} | ||
300 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}} | ||
301 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}} | ||
302 | -Warning: Image size mismatch! | ||
303 | Images are identical. | ||
304 | |||
305 | === Copying sample image simple-pattern.cloop into raw === | ||
306 | |||
307 | -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 | ||
308 | +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=SIZE | ||
309 | { 'execute': 'qmp_capabilities' } | ||
310 | {"return": {}} | ||
311 | {'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'mode': 'existing', 'sync': 'full'}} | ||
312 | @@ -XXX,XX +XXX,XX @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed | ||
313 | {"execute":"quit"} | ||
314 | {"return": {}} | ||
315 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} | ||
316 | -read 65536/65536 bytes at offset 0 | ||
317 | -64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
318 | +read 512/512 bytes at offset 0 | ||
319 | +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
320 | { 'execute': 'qmp_capabilities' } | ||
321 | {"return": {}} | ||
322 | {'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'format': 'IMGFMT', 'mode': 'existing', 'sync': 'full'}} | ||
323 | @@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 0 | ||
324 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 2048, "offset": 2048, "speed": 0, "type": "mirror"}} | ||
325 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}} | ||
326 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}} | ||
327 | -Warning: Image size mismatch! | ||
328 | Images are identical. | ||
329 | |||
330 | === Write legitimate MBR into raw === | ||
331 | |||
332 | -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 | ||
333 | +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=SIZE | ||
334 | { 'execute': 'qmp_capabilities' } | ||
335 | {"return": {}} | ||
336 | {'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'mode': 'existing', 'sync': 'full'}} | ||
337 | @@ -XXX,XX +XXX,XX @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed | ||
338 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 512, "offset": 512, "speed": 0, "type": "mirror"}} | ||
339 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}} | ||
340 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}} | ||
341 | -Warning: Image size mismatch! | ||
342 | Images are identical. | ||
343 | { 'execute': 'qmp_capabilities' } | ||
344 | {"return": {}} | ||
345 | @@ -XXX,XX +XXX,XX @@ Images are identical. | ||
346 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 512, "offset": 512, "speed": 0, "type": "mirror"}} | ||
347 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}} | ||
348 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}} | ||
349 | -Warning: Image size mismatch! | ||
350 | Images are identical. | ||
351 | *** done | ||
352 | diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter | ||
353 | index XXXXXXX..XXXXXXX 100644 | ||
354 | --- a/tests/qemu-iotests/common.filter | ||
355 | +++ b/tests/qemu-iotests/common.filter | ||
356 | @@ -XXX,XX +XXX,XX @@ _filter_img_create() | ||
357 | -e "s# compression_type=[a-zA-Z0-9]\\+##g" | ||
358 | } | 25 | } |
359 | 26 | ||
360 | +_filter_img_create_size() | 27 | -static void process_incoming_migration_co(void *opaque) |
361 | +{ | 28 | +static void coroutine_fn |
362 | + $SED -e "s# size=[0-9]\\+# size=SIZE#g" | 29 | +process_incoming_migration_co(void *opaque) |
363 | +} | ||
364 | + | ||
365 | _filter_img_info() | ||
366 | { | 30 | { |
367 | if [[ "$1" == "--format-specific" ]]; then | 31 | MigrationIncomingState *mis = migration_incoming_get_current(); |
32 | PostcopyState ps; | ||
368 | -- | 33 | -- |
369 | 2.25.4 | 34 | 2.37.3 |
370 | 35 | ||
371 | 36 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | 229 relies on the mirror running into an I/O error when the target is | ||
2 | smaller than the source. After changing mirror to catch this condition | ||
3 | while starting the job, this test case won't get a job that is paused | ||
4 | for an I/O error any more. Use blkdebug instead to inject an error. | ||
5 | 1 | ||
6 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
7 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
8 | Message-Id: <20200511135825.219437-3-kwolf@redhat.com> | ||
9 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
10 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
12 | --- | ||
13 | tests/qemu-iotests/229 | 15 +++++++++++---- | ||
14 | tests/qemu-iotests/229.out | 6 +++--- | ||
15 | 2 files changed, 14 insertions(+), 7 deletions(-) | ||
16 | |||
17 | diff --git a/tests/qemu-iotests/229 b/tests/qemu-iotests/229 | ||
18 | index XXXXXXX..XXXXXXX 100755 | ||
19 | --- a/tests/qemu-iotests/229 | ||
20 | +++ b/tests/qemu-iotests/229 | ||
21 | @@ -XXX,XX +XXX,XX @@ _cleanup() | ||
22 | _cleanup_test_img | ||
23 | _rm_test_img "$TEST_IMG" | ||
24 | _rm_test_img "$DEST_IMG" | ||
25 | + rm -f "$TEST_DIR/blkdebug.conf" | ||
26 | } | ||
27 | trap "_cleanup; exit \$status" 0 1 2 3 15 | ||
28 | |||
29 | @@ -XXX,XX +XXX,XX @@ _supported_os Linux | ||
30 | |||
31 | DEST_IMG="$TEST_DIR/d.$IMGFMT" | ||
32 | TEST_IMG="$TEST_DIR/b.$IMGFMT" | ||
33 | +BLKDEBUG_CONF="$TEST_DIR/blkdebug.conf" | ||
34 | |||
35 | _make_test_img 2M | ||
36 | - | ||
37 | -# destination for mirror will be too small, causing error | ||
38 | -TEST_IMG=$DEST_IMG _make_test_img 1M | ||
39 | +TEST_IMG=$DEST_IMG _make_test_img 2M | ||
40 | |||
41 | $QEMU_IO -c 'write 0 2M' "$TEST_IMG" | _filter_qemu_io | ||
42 | |||
43 | @@ -XXX,XX +XXX,XX @@ echo | ||
44 | echo '=== Starting drive-mirror, causing error & stop ===' | ||
45 | echo | ||
46 | |||
47 | +cat > "$BLKDEBUG_CONF" <<EOF | ||
48 | +[inject-error] | ||
49 | +event = "write_aio" | ||
50 | +errno = "5" | ||
51 | +once = "on" | ||
52 | +EOF | ||
53 | + | ||
54 | _send_qemu_cmd $QEMU_HANDLE \ | ||
55 | "{'execute': 'drive-mirror', | ||
56 | 'arguments': {'device': 'testdisk', | ||
57 | 'format': '$IMGFMT', | ||
58 | - 'target': '$DEST_IMG', | ||
59 | + 'target': 'blkdebug:$BLKDEBUG_CONF:$DEST_IMG', | ||
60 | 'sync': 'full', | ||
61 | 'mode': 'existing', | ||
62 | 'on-source-error': 'stop', | ||
63 | diff --git a/tests/qemu-iotests/229.out b/tests/qemu-iotests/229.out | ||
64 | index XXXXXXX..XXXXXXX 100644 | ||
65 | --- a/tests/qemu-iotests/229.out | ||
66 | +++ b/tests/qemu-iotests/229.out | ||
67 | @@ -XXX,XX +XXX,XX @@ | ||
68 | QA output created by 229 | ||
69 | Formatting 'TEST_DIR/b.IMGFMT', fmt=IMGFMT size=2097152 | ||
70 | -Formatting 'TEST_DIR/d.IMGFMT', fmt=IMGFMT size=1048576 | ||
71 | +Formatting 'TEST_DIR/d.IMGFMT', fmt=IMGFMT size=2097152 | ||
72 | wrote 2097152/2097152 bytes at offset 0 | ||
73 | 2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
74 | {'execute': 'qmp_capabilities'} | ||
75 | @@ -XXX,XX +XXX,XX @@ wrote 2097152/2097152 bytes at offset 0 | ||
76 | |||
77 | === Starting drive-mirror, causing error & stop === | ||
78 | |||
79 | -{'execute': 'drive-mirror', 'arguments': {'device': 'testdisk', 'format': 'IMGFMT', 'target': 'TEST_DIR/d.IMGFMT', 'sync': 'full', 'mode': 'existing', 'on-source-error': 'stop', 'on-target-error': 'stop' }} | ||
80 | +{'execute': 'drive-mirror', 'arguments': {'device': 'testdisk', 'format': 'IMGFMT', 'target': 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/d.IMGFMT', 'sync': 'full', 'mode': 'existing', 'on-source-error': 'stop', 'on-target-error': 'stop' }} | ||
81 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "testdisk"}} | ||
82 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "testdisk"}} | ||
83 | {"return": {}} | ||
84 | @@ -XXX,XX +XXX,XX @@ wrote 2097152/2097152 bytes at offset 0 | ||
85 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "testdisk"}} | ||
86 | {"return": {}} | ||
87 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "testdisk"}} | ||
88 | -{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "testdisk", "len": 2097152, "offset": 1048576, "speed": 0, "type": "mirror"}} | ||
89 | +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "testdisk", "len": 2097152, "offset": 2097152, "speed": 0, "type": "mirror"}} | ||
90 | *** done | ||
91 | -- | ||
92 | 2.25.4 | ||
93 | |||
94 | diff view generated by jsdifflib |
1 | This is just a bandaid to keep tests/test-replication working after | 1 | From: Marc-André Lureau <marcandre.lureau@redhat.com> |
---|---|---|---|
2 | bdrv_make_empty() starts to assert that we're not trying to call it on a | ||
3 | read-only child. | ||
4 | 2 | ||
5 | For the real solution in the future, replication should not steal the | 3 | Callers of coroutine_fn must be coroutine_fn themselves, or the call |
6 | BdrvChild from its backing file (this is never correct to do!), but | 4 | must be within "if (qemu_in_coroutine())". Apply coroutine_fn to |
7 | instead have its own child node references, with the appropriate | 5 | functions where this holds. |
8 | permissions. | ||
9 | 6 | ||
7 | Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> | ||
8 | Reviewed-by: Alberto Faria <afaria@redhat.com> | ||
9 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> | ||
10 | Message-Id: <20220922084924.201610-27-pbonzini@redhat.com> | ||
11 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
11 | --- | 13 | --- |
12 | block/replication.c | 13 +++++++++++-- | 14 | tests/unit/test-coroutine.c | 2 +- |
13 | 1 file changed, 11 insertions(+), 2 deletions(-) | 15 | 1 file changed, 1 insertion(+), 1 deletion(-) |
14 | 16 | ||
15 | diff --git a/block/replication.c b/block/replication.c | 17 | diff --git a/tests/unit/test-coroutine.c b/tests/unit/test-coroutine.c |
16 | index XXXXXXX..XXXXXXX 100644 | 18 | index XXXXXXX..XXXXXXX 100644 |
17 | --- a/block/replication.c | 19 | --- a/tests/unit/test-coroutine.c |
18 | +++ b/block/replication.c | 20 | +++ b/tests/unit/test-coroutine.c |
19 | @@ -XXX,XX +XXX,XX @@ static void secondary_do_checkpoint(BDRVReplicationState *s, Error **errp) | 21 | @@ -XXX,XX +XXX,XX @@ static void perf_baseline(void) |
20 | return; | 22 | g_test_message("Function call %u iterations: %f s", maxcycles, duration); |
21 | } | 23 | } |
22 | 24 | ||
23 | - ret = s->hidden_disk->bs->drv->bdrv_make_empty(s->hidden_disk->bs); | 25 | -static __attribute__((noinline)) void perf_cost_func(void *opaque) |
24 | + BlockBackend *blk = blk_new(qemu_get_current_aio_context(), | 26 | +static __attribute__((noinline)) void coroutine_fn perf_cost_func(void *opaque) |
25 | + BLK_PERM_WRITE, BLK_PERM_ALL); | 27 | { |
26 | + blk_insert_bs(blk, s->hidden_disk->bs, &local_err); | 28 | qemu_coroutine_yield(); |
27 | + if (local_err) { | ||
28 | + error_propagate(errp, local_err); | ||
29 | + blk_unref(blk); | ||
30 | + return; | ||
31 | + } | ||
32 | + | ||
33 | + ret = blk_make_empty(blk, errp); | ||
34 | + blk_unref(blk); | ||
35 | if (ret < 0) { | ||
36 | - error_setg(errp, "Cannot make hidden disk empty"); | ||
37 | return; | ||
38 | } | ||
39 | } | 29 | } |
40 | -- | 30 | -- |
41 | 2.25.4 | 31 | 2.37.3 |
42 | 32 | ||
43 | 33 | diff view generated by jsdifflib |
1 | From: Max Reitz <mreitz@redhat.com> | 1 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
---|---|---|---|
2 | 2 | Message-Id: <20221006122607.162769-1-kwolf@redhat.com> | |
3 | For now, all callers pass 0 and no callee evaluates this value. Later | 3 | Reviewed-by: Peter Maydell <peter.maydell@linaro.org> |
4 | patches will change both. | 4 | Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org> |
5 | |||
6 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
7 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
8 | Message-Id: <20200513110544.176672-7-mreitz@redhat.com> | ||
9 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 5 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
10 | --- | 6 | --- |
11 | include/block/block_int.h | 5 ++++- | 7 | block/quorum.c | 2 -- |
12 | block.c | 22 ++++++++++++---------- | 8 | 1 file changed, 2 deletions(-) |
13 | block/backup-top.c | 3 ++- | ||
14 | block/blkdebug.c | 5 +++-- | ||
15 | block/blklogwrites.c | 9 +++++---- | ||
16 | block/commit.c | 1 + | ||
17 | block/copy-on-read.c | 1 + | ||
18 | block/mirror.c | 1 + | ||
19 | block/quorum.c | 1 + | ||
20 | block/replication.c | 1 + | ||
21 | block/vvfat.c | 1 + | ||
22 | tests/test-bdrv-drain.c | 5 +++-- | ||
23 | tests/test-bdrv-graph-mod.c | 1 + | ||
24 | 13 files changed, 36 insertions(+), 20 deletions(-) | ||
25 | 9 | ||
26 | diff --git a/include/block/block_int.h b/include/block/block_int.h | ||
27 | index XXXXXXX..XXXXXXX 100644 | ||
28 | --- a/include/block/block_int.h | ||
29 | +++ b/include/block/block_int.h | ||
30 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { | ||
31 | * the parents in @parent_perm and @parent_shared. | ||
32 | * | ||
33 | * If @c is NULL, return the permissions for attaching a new child for the | ||
34 | - * given @child_class. | ||
35 | + * given @child_class and @role. | ||
36 | * | ||
37 | * If @reopen_queue is non-NULL, don't return the currently needed | ||
38 | * permissions, but those that will be needed after applying the | ||
39 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { | ||
40 | */ | ||
41 | void (*bdrv_child_perm)(BlockDriverState *bs, BdrvChild *c, | ||
42 | const BdrvChildClass *child_class, | ||
43 | + BdrvChildRole role, | ||
44 | BlockReopenQueue *reopen_queue, | ||
45 | uint64_t parent_perm, uint64_t parent_shared, | ||
46 | uint64_t *nperm, uint64_t *nshared); | ||
47 | @@ -XXX,XX +XXX,XX @@ int bdrv_child_refresh_perms(BlockDriverState *bs, BdrvChild *c, Error **errp); | ||
48 | * all children */ | ||
49 | void bdrv_filter_default_perms(BlockDriverState *bs, BdrvChild *c, | ||
50 | const BdrvChildClass *child_class, | ||
51 | + BdrvChildRole child_role, | ||
52 | BlockReopenQueue *reopen_queue, | ||
53 | uint64_t perm, uint64_t shared, | ||
54 | uint64_t *nperm, uint64_t *nshared); | ||
55 | @@ -XXX,XX +XXX,XX @@ void bdrv_filter_default_perms(BlockDriverState *bs, BdrvChild *c, | ||
56 | * CONSISTENT_READ and doesn't share WRITE. */ | ||
57 | void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c, | ||
58 | const BdrvChildClass *child_class, | ||
59 | + BdrvChildRole child_role, | ||
60 | BlockReopenQueue *reopen_queue, | ||
61 | uint64_t perm, uint64_t shared, | ||
62 | uint64_t *nperm, uint64_t *nshared); | ||
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 @@ bool bdrv_is_writable(BlockDriverState *bs) | ||
68 | |||
69 | static void bdrv_child_perm(BlockDriverState *bs, BlockDriverState *child_bs, | ||
70 | BdrvChild *c, const BdrvChildClass *child_class, | ||
71 | - BlockReopenQueue *reopen_queue, | ||
72 | + BdrvChildRole role, BlockReopenQueue *reopen_queue, | ||
73 | uint64_t parent_perm, uint64_t parent_shared, | ||
74 | uint64_t *nperm, uint64_t *nshared) | ||
75 | { | ||
76 | assert(bs->drv && bs->drv->bdrv_child_perm); | ||
77 | - bs->drv->bdrv_child_perm(bs, c, child_class, reopen_queue, | ||
78 | + bs->drv->bdrv_child_perm(bs, c, child_class, role, reopen_queue, | ||
79 | parent_perm, parent_shared, | ||
80 | nperm, nshared); | ||
81 | /* TODO Take force_share from reopen_queue */ | ||
82 | @@ -XXX,XX +XXX,XX @@ static int bdrv_check_perm(BlockDriverState *bs, BlockReopenQueue *q, | ||
83 | uint64_t cur_perm, cur_shared; | ||
84 | bool child_tighten_restr; | ||
85 | |||
86 | - bdrv_child_perm(bs, c->bs, c, c->klass, q, | ||
87 | + bdrv_child_perm(bs, c->bs, c, c->klass, c->role, q, | ||
88 | cumulative_perms, cumulative_shared_perms, | ||
89 | &cur_perm, &cur_shared); | ||
90 | ret = bdrv_child_check_perm(c, q, cur_perm, cur_shared, ignore_children, | ||
91 | @@ -XXX,XX +XXX,XX @@ static void bdrv_set_perm(BlockDriverState *bs, uint64_t cumulative_perms, | ||
92 | /* Update all children */ | ||
93 | QLIST_FOREACH(c, &bs->children, next) { | ||
94 | uint64_t cur_perm, cur_shared; | ||
95 | - bdrv_child_perm(bs, c->bs, c, c->klass, NULL, | ||
96 | + bdrv_child_perm(bs, c->bs, c, c->klass, c->role, NULL, | ||
97 | cumulative_perms, cumulative_shared_perms, | ||
98 | &cur_perm, &cur_shared); | ||
99 | bdrv_child_set_perm(c, cur_perm, cur_shared); | ||
100 | @@ -XXX,XX +XXX,XX @@ int bdrv_child_refresh_perms(BlockDriverState *bs, BdrvChild *c, Error **errp) | ||
101 | uint64_t perms, shared; | ||
102 | |||
103 | bdrv_get_cumulative_perm(bs, &parent_perms, &parent_shared); | ||
104 | - bdrv_child_perm(bs, c->bs, c, c->klass, NULL, parent_perms, parent_shared, | ||
105 | - &perms, &shared); | ||
106 | + bdrv_child_perm(bs, c->bs, c, c->klass, c->role, NULL, | ||
107 | + parent_perms, parent_shared, &perms, &shared); | ||
108 | |||
109 | return bdrv_child_try_set_perm(c, perms, shared, errp); | ||
110 | } | ||
111 | |||
112 | void bdrv_filter_default_perms(BlockDriverState *bs, BdrvChild *c, | ||
113 | const BdrvChildClass *child_class, | ||
114 | + BdrvChildRole role, | ||
115 | BlockReopenQueue *reopen_queue, | ||
116 | uint64_t perm, uint64_t shared, | ||
117 | uint64_t *nperm, uint64_t *nshared) | ||
118 | @@ -XXX,XX +XXX,XX @@ void bdrv_filter_default_perms(BlockDriverState *bs, BdrvChild *c, | ||
119 | |||
120 | void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c, | ||
121 | const BdrvChildClass *child_class, | ||
122 | + BdrvChildRole role, | ||
123 | BlockReopenQueue *reopen_queue, | ||
124 | uint64_t perm, uint64_t shared, | ||
125 | uint64_t *nperm, uint64_t *nshared) | ||
126 | @@ -XXX,XX +XXX,XX @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c, | ||
127 | |||
128 | /* Apart from the modifications below, the same permissions are | ||
129 | * forwarded and left alone as for filters */ | ||
130 | - bdrv_filter_default_perms(bs, c, child_class, reopen_queue, | ||
131 | + bdrv_filter_default_perms(bs, c, child_class, role, reopen_queue, | ||
132 | perm, shared, &perm, &shared); | ||
133 | |||
134 | /* Format drivers may touch metadata even if the guest doesn't write */ | ||
135 | @@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs, | ||
136 | bdrv_get_cumulative_perm(parent_bs, &perm, &shared_perm); | ||
137 | |||
138 | assert(parent_bs->drv); | ||
139 | - bdrv_child_perm(parent_bs, child_bs, NULL, child_class, NULL, | ||
140 | + bdrv_child_perm(parent_bs, child_bs, NULL, child_class, child_role, NULL, | ||
141 | perm, shared_perm, &perm, &shared_perm); | ||
142 | |||
143 | child = bdrv_root_attach_child(child_bs, child_name, child_class, | ||
144 | @@ -XXX,XX +XXX,XX @@ int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp) | ||
145 | if (state->replace_backing_bs && state->new_backing_bs) { | ||
146 | uint64_t nperm, nshared; | ||
147 | bdrv_child_perm(state->bs, state->new_backing_bs, | ||
148 | - NULL, &child_backing, bs_queue, | ||
149 | + NULL, &child_backing, 0, bs_queue, | ||
150 | state->perm, state->shared_perm, | ||
151 | &nperm, &nshared); | ||
152 | ret = bdrv_check_update_perm(state->new_backing_bs, NULL, | ||
153 | @@ -XXX,XX +XXX,XX @@ static void bdrv_reopen_perm(BlockReopenQueue *q, BlockDriverState *bs, | ||
154 | } else { | ||
155 | uint64_t nperm, nshared; | ||
156 | |||
157 | - bdrv_child_perm(parent->state.bs, bs, c, c->klass, q, | ||
158 | + bdrv_child_perm(parent->state.bs, bs, c, c->klass, c->role, q, | ||
159 | parent->state.perm, parent->state.shared_perm, | ||
160 | &nperm, &nshared); | ||
161 | |||
162 | diff --git a/block/backup-top.c b/block/backup-top.c | ||
163 | index XXXXXXX..XXXXXXX 100644 | ||
164 | --- a/block/backup-top.c | ||
165 | +++ b/block/backup-top.c | ||
166 | @@ -XXX,XX +XXX,XX @@ static void backup_top_refresh_filename(BlockDriverState *bs) | ||
167 | |||
168 | static void backup_top_child_perm(BlockDriverState *bs, BdrvChild *c, | ||
169 | const BdrvChildClass *child_class, | ||
170 | + BdrvChildRole role, | ||
171 | BlockReopenQueue *reopen_queue, | ||
172 | uint64_t perm, uint64_t shared, | ||
173 | uint64_t *nperm, uint64_t *nshared) | ||
174 | @@ -XXX,XX +XXX,XX @@ static void backup_top_child_perm(BlockDriverState *bs, BdrvChild *c, | ||
175 | *nperm = BLK_PERM_WRITE; | ||
176 | } else { | ||
177 | /* Source child */ | ||
178 | - bdrv_filter_default_perms(bs, c, child_class, reopen_queue, | ||
179 | + bdrv_filter_default_perms(bs, c, child_class, role, reopen_queue, | ||
180 | perm, shared, nperm, nshared); | ||
181 | |||
182 | if (perm & BLK_PERM_WRITE) { | ||
183 | diff --git a/block/blkdebug.c b/block/blkdebug.c | ||
184 | index XXXXXXX..XXXXXXX 100644 | ||
185 | --- a/block/blkdebug.c | ||
186 | +++ b/block/blkdebug.c | ||
187 | @@ -XXX,XX +XXX,XX @@ static int blkdebug_reopen_prepare(BDRVReopenState *reopen_state, | ||
188 | |||
189 | static void blkdebug_child_perm(BlockDriverState *bs, BdrvChild *c, | ||
190 | const BdrvChildClass *child_class, | ||
191 | + BdrvChildRole role, | ||
192 | BlockReopenQueue *reopen_queue, | ||
193 | uint64_t perm, uint64_t shared, | ||
194 | uint64_t *nperm, uint64_t *nshared) | ||
195 | { | ||
196 | BDRVBlkdebugState *s = bs->opaque; | ||
197 | |||
198 | - bdrv_filter_default_perms(bs, c, child_class, reopen_queue, perm, shared, | ||
199 | - nperm, nshared); | ||
200 | + bdrv_filter_default_perms(bs, c, child_class, role, reopen_queue, | ||
201 | + perm, shared, nperm, nshared); | ||
202 | |||
203 | *nperm |= s->take_child_perms; | ||
204 | *nshared &= ~s->unshare_child_perms; | ||
205 | diff --git a/block/blklogwrites.c b/block/blklogwrites.c | ||
206 | index XXXXXXX..XXXXXXX 100644 | ||
207 | --- a/block/blklogwrites.c | ||
208 | +++ b/block/blklogwrites.c | ||
209 | @@ -XXX,XX +XXX,XX @@ static int64_t blk_log_writes_getlength(BlockDriverState *bs) | ||
210 | |||
211 | static void blk_log_writes_child_perm(BlockDriverState *bs, BdrvChild *c, | ||
212 | const BdrvChildClass *child_class, | ||
213 | + BdrvChildRole role, | ||
214 | BlockReopenQueue *ro_q, | ||
215 | uint64_t perm, uint64_t shrd, | ||
216 | uint64_t *nperm, uint64_t *nshrd) | ||
217 | @@ -XXX,XX +XXX,XX @@ static void blk_log_writes_child_perm(BlockDriverState *bs, BdrvChild *c, | ||
218 | } | ||
219 | |||
220 | if (!strcmp(c->name, "log")) { | ||
221 | - bdrv_format_default_perms(bs, c, child_class, ro_q, perm, shrd, nperm, | ||
222 | - nshrd); | ||
223 | + bdrv_format_default_perms(bs, c, child_class, role, ro_q, perm, shrd, | ||
224 | + nperm, nshrd); | ||
225 | } else { | ||
226 | - bdrv_filter_default_perms(bs, c, child_class, ro_q, perm, shrd, nperm, | ||
227 | - nshrd); | ||
228 | + bdrv_filter_default_perms(bs, c, child_class, role, ro_q, perm, shrd, | ||
229 | + nperm, nshrd); | ||
230 | } | ||
231 | } | ||
232 | |||
233 | diff --git a/block/commit.c b/block/commit.c | ||
234 | index XXXXXXX..XXXXXXX 100644 | ||
235 | --- a/block/commit.c | ||
236 | +++ b/block/commit.c | ||
237 | @@ -XXX,XX +XXX,XX @@ static void bdrv_commit_top_refresh_filename(BlockDriverState *bs) | ||
238 | |||
239 | static void bdrv_commit_top_child_perm(BlockDriverState *bs, BdrvChild *c, | ||
240 | const BdrvChildClass *child_class, | ||
241 | + BdrvChildRole role, | ||
242 | BlockReopenQueue *reopen_queue, | ||
243 | uint64_t perm, uint64_t shared, | ||
244 | uint64_t *nperm, uint64_t *nshared) | ||
245 | diff --git a/block/copy-on-read.c b/block/copy-on-read.c | ||
246 | index XXXXXXX..XXXXXXX 100644 | ||
247 | --- a/block/copy-on-read.c | ||
248 | +++ b/block/copy-on-read.c | ||
249 | @@ -XXX,XX +XXX,XX @@ static int cor_open(BlockDriverState *bs, QDict *options, int flags, | ||
250 | |||
251 | static void cor_child_perm(BlockDriverState *bs, BdrvChild *c, | ||
252 | const BdrvChildClass *child_class, | ||
253 | + BdrvChildRole role, | ||
254 | BlockReopenQueue *reopen_queue, | ||
255 | uint64_t perm, uint64_t shared, | ||
256 | uint64_t *nperm, uint64_t *nshared) | ||
257 | diff --git a/block/mirror.c b/block/mirror.c | ||
258 | index XXXXXXX..XXXXXXX 100644 | ||
259 | --- a/block/mirror.c | ||
260 | +++ b/block/mirror.c | ||
261 | @@ -XXX,XX +XXX,XX @@ static void bdrv_mirror_top_refresh_filename(BlockDriverState *bs) | ||
262 | |||
263 | static void bdrv_mirror_top_child_perm(BlockDriverState *bs, BdrvChild *c, | ||
264 | const BdrvChildClass *child_class, | ||
265 | + BdrvChildRole role, | ||
266 | BlockReopenQueue *reopen_queue, | ||
267 | uint64_t perm, uint64_t shared, | ||
268 | uint64_t *nperm, uint64_t *nshared) | ||
269 | diff --git a/block/quorum.c b/block/quorum.c | 10 | diff --git a/block/quorum.c b/block/quorum.c |
270 | index XXXXXXX..XXXXXXX 100644 | 11 | index XXXXXXX..XXXXXXX 100644 |
271 | --- a/block/quorum.c | 12 | --- a/block/quorum.c |
272 | +++ b/block/quorum.c | 13 | +++ b/block/quorum.c |
273 | @@ -XXX,XX +XXX,XX @@ static char *quorum_dirname(BlockDriverState *bs, Error **errp) | 14 | @@ -XXX,XX +XXX,XX @@ static bool quorum_has_too_much_io_failed(QuorumAIOCB *acb) |
274 | 15 | return false; | |
275 | static void quorum_child_perm(BlockDriverState *bs, BdrvChild *c, | ||
276 | const BdrvChildClass *child_class, | ||
277 | + BdrvChildRole role, | ||
278 | BlockReopenQueue *reopen_queue, | ||
279 | uint64_t perm, uint64_t shared, | ||
280 | uint64_t *nperm, uint64_t *nshared) | ||
281 | diff --git a/block/replication.c b/block/replication.c | ||
282 | index XXXXXXX..XXXXXXX 100644 | ||
283 | --- a/block/replication.c | ||
284 | +++ b/block/replication.c | ||
285 | @@ -XXX,XX +XXX,XX @@ static void replication_close(BlockDriverState *bs) | ||
286 | |||
287 | static void replication_child_perm(BlockDriverState *bs, BdrvChild *c, | ||
288 | const BdrvChildClass *child_class, | ||
289 | + BdrvChildRole role, | ||
290 | BlockReopenQueue *reopen_queue, | ||
291 | uint64_t perm, uint64_t shared, | ||
292 | uint64_t *nperm, uint64_t *nshared) | ||
293 | diff --git a/block/vvfat.c b/block/vvfat.c | ||
294 | index XXXXXXX..XXXXXXX 100644 | ||
295 | --- a/block/vvfat.c | ||
296 | +++ b/block/vvfat.c | ||
297 | @@ -XXX,XX +XXX,XX @@ err: | ||
298 | |||
299 | static void vvfat_child_perm(BlockDriverState *bs, BdrvChild *c, | ||
300 | const BdrvChildClass *child_class, | ||
301 | + BdrvChildRole role, | ||
302 | BlockReopenQueue *reopen_queue, | ||
303 | uint64_t perm, uint64_t shared, | ||
304 | uint64_t *nperm, uint64_t *nshared) | ||
305 | diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c | ||
306 | index XXXXXXX..XXXXXXX 100644 | ||
307 | --- a/tests/test-bdrv-drain.c | ||
308 | +++ b/tests/test-bdrv-drain.c | ||
309 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_test_co_preadv(BlockDriverState *bs, | ||
310 | |||
311 | static void bdrv_test_child_perm(BlockDriverState *bs, BdrvChild *c, | ||
312 | const BdrvChildClass *child_class, | ||
313 | + BdrvChildRole role, | ||
314 | BlockReopenQueue *reopen_queue, | ||
315 | uint64_t perm, uint64_t shared, | ||
316 | uint64_t *nperm, uint64_t *nshared) | ||
317 | @@ -XXX,XX +XXX,XX @@ static void bdrv_test_child_perm(BlockDriverState *bs, BdrvChild *c, | ||
318 | child_class = &child_file; | ||
319 | } | ||
320 | |||
321 | - bdrv_format_default_perms(bs, c, child_class, reopen_queue, perm, shared, | ||
322 | - nperm, nshared); | ||
323 | + bdrv_format_default_perms(bs, c, child_class, role, reopen_queue, | ||
324 | + perm, shared, nperm, nshared); | ||
325 | } | 16 | } |
326 | 17 | ||
327 | static int bdrv_test_change_backing_file(BlockDriverState *bs, | 18 | -static int read_fifo_child(QuorumAIOCB *acb); |
328 | diff --git a/tests/test-bdrv-graph-mod.c b/tests/test-bdrv-graph-mod.c | 19 | - |
329 | index XXXXXXX..XXXXXXX 100644 | 20 | static void quorum_copy_qiov(QEMUIOVector *dest, QEMUIOVector *source) |
330 | --- a/tests/test-bdrv-graph-mod.c | 21 | { |
331 | +++ b/tests/test-bdrv-graph-mod.c | 22 | int i; |
332 | @@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_pass_through = { | ||
333 | |||
334 | static void no_perm_default_perms(BlockDriverState *bs, BdrvChild *c, | ||
335 | const BdrvChildClass *child_class, | ||
336 | + BdrvChildRole role, | ||
337 | BlockReopenQueue *reopen_queue, | ||
338 | uint64_t perm, uint64_t shared, | ||
339 | uint64_t *nperm, uint64_t *nshared) | ||
340 | -- | 23 | -- |
341 | 2.25.4 | 24 | 2.37.3 |
342 | 25 | ||
343 | 26 | diff view generated by jsdifflib |
1 | From: Max Reitz <mreitz@redhat.com> | 1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 3 | job mutex will be used to protect the job struct elements and list, |
4 | Reviewed-by: Eric Blake <eblake@redhat.com> | 4 | replacing AioContext locks. |
5 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | 5 | |
6 | Message-Id: <20200429141126.85159-3-mreitz@redhat.com> | 6 | Right now use a shared lock for all jobs, in order to keep things |
7 | simple. Once the AioContext lock is gone, we can introduce per-job | ||
8 | locks. | ||
9 | |||
10 | To simplify the switch from aiocontext to job lock, introduce | ||
11 | *nop* lock/unlock functions and macros. | ||
12 | We want to always call job_lock/unlock outside the AioContext locks, | ||
13 | and not vice-versa, otherwise we might get a deadlock. This is not | ||
14 | straightforward to do, and that's why we start with nop functions. | ||
15 | Once everything is protected by job_lock/unlock, we can change the nop into | ||
16 | an actual mutex and remove the aiocontext lock. | ||
17 | |||
18 | Since job_mutex is already being used, add static | ||
19 | real_job_{lock/unlock} for the existing usage. | ||
20 | |||
21 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
22 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
23 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> | ||
24 | Message-Id: <20220926093214.506243-2-eesposit@redhat.com> | ||
7 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 25 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
8 | --- | 26 | --- |
9 | block/replication.c | 3 +-- | 27 | include/qemu/job.h | 24 ++++++++++++++++++++++++ |
10 | block/vvfat.c | 4 +--- | 28 | job.c | 35 +++++++++++++++++++++++------------ |
11 | 2 files changed, 2 insertions(+), 5 deletions(-) | 29 | 2 files changed, 47 insertions(+), 12 deletions(-) |
12 | 30 | ||
13 | diff --git a/block/replication.c b/block/replication.c | 31 | diff --git a/include/qemu/job.h b/include/qemu/job.h |
14 | index XXXXXXX..XXXXXXX 100644 | 32 | index XXXXXXX..XXXXXXX 100644 |
15 | --- a/block/replication.c | 33 | --- a/include/qemu/job.h |
16 | +++ b/block/replication.c | 34 | +++ b/include/qemu/job.h |
17 | @@ -XXX,XX +XXX,XX @@ static void secondary_do_checkpoint(BDRVReplicationState *s, Error **errp) | 35 | @@ -XXX,XX +XXX,XX @@ typedef enum JobCreateFlags { |
36 | JOB_MANUAL_DISMISS = 0x04, | ||
37 | } JobCreateFlags; | ||
38 | |||
39 | +extern QemuMutex job_mutex; | ||
40 | + | ||
41 | +#define JOB_LOCK_GUARD() /* QEMU_LOCK_GUARD(&job_mutex) */ | ||
42 | + | ||
43 | +#define WITH_JOB_LOCK_GUARD() /* WITH_QEMU_LOCK_GUARD(&job_mutex) */ | ||
44 | + | ||
45 | +/** | ||
46 | + * job_lock: | ||
47 | + * | ||
48 | + * Take the mutex protecting the list of jobs and their status. | ||
49 | + * Most functions called by the monitor need to call job_lock | ||
50 | + * and job_unlock manually. On the other hand, function called | ||
51 | + * by the block jobs themselves and by the block layer will take the | ||
52 | + * lock for you. | ||
53 | + */ | ||
54 | +void job_lock(void); | ||
55 | + | ||
56 | +/** | ||
57 | + * job_unlock: | ||
58 | + * | ||
59 | + * Release the mutex protecting the list of jobs and their status. | ||
60 | + */ | ||
61 | +void job_unlock(void); | ||
62 | + | ||
63 | /** | ||
64 | * Allocate and return a new job transaction. Jobs can be added to the | ||
65 | * transaction using job_txn_add_job(). | ||
66 | diff --git a/job.c b/job.c | ||
67 | index XXXXXXX..XXXXXXX 100644 | ||
68 | --- a/job.c | ||
69 | +++ b/job.c | ||
70 | @@ -XXX,XX +XXX,XX @@ | ||
71 | #include "trace/trace-root.h" | ||
72 | #include "qapi/qapi-events-job.h" | ||
73 | |||
74 | +/* | ||
75 | + * job_mutex protects the jobs list, but also makes the | ||
76 | + * struct job fields thread-safe. | ||
77 | + */ | ||
78 | +QemuMutex job_mutex; | ||
79 | + | ||
80 | static QLIST_HEAD(, Job) jobs = QLIST_HEAD_INITIALIZER(jobs); | ||
81 | |||
82 | /* Job State Transition Table */ | ||
83 | @@ -XXX,XX +XXX,XX @@ struct JobTxn { | ||
84 | int refcnt; | ||
85 | }; | ||
86 | |||
87 | -/* Right now, this mutex is only needed to synchronize accesses to job->busy | ||
88 | - * and job->sleep_timer, such as concurrent calls to job_do_yield and | ||
89 | - * job_enter. */ | ||
90 | -static QemuMutex job_mutex; | ||
91 | +void job_lock(void) | ||
92 | +{ | ||
93 | + /* nop */ | ||
94 | +} | ||
95 | + | ||
96 | +void job_unlock(void) | ||
97 | +{ | ||
98 | + /* nop */ | ||
99 | +} | ||
100 | |||
101 | -static void job_lock(void) | ||
102 | +static void real_job_lock(void) | ||
103 | { | ||
104 | qemu_mutex_lock(&job_mutex); | ||
105 | } | ||
106 | |||
107 | -static void job_unlock(void) | ||
108 | +static void real_job_unlock(void) | ||
109 | { | ||
110 | qemu_mutex_unlock(&job_mutex); | ||
111 | } | ||
112 | @@ -XXX,XX +XXX,XX @@ void job_enter_cond(Job *job, bool(*fn)(Job *job)) | ||
18 | return; | 113 | return; |
19 | } | 114 | } |
20 | 115 | ||
21 | - ret = s->active_disk->bs->drv->bdrv_make_empty(s->active_disk->bs); | 116 | - job_lock(); |
22 | + ret = bdrv_make_empty(s->active_disk, errp); | 117 | + real_job_lock(); |
23 | if (ret < 0) { | 118 | if (job->busy) { |
24 | - error_setg(errp, "Cannot make active disk empty"); | 119 | - job_unlock(); |
120 | + real_job_unlock(); | ||
25 | return; | 121 | return; |
26 | } | 122 | } |
27 | 123 | ||
28 | diff --git a/block/vvfat.c b/block/vvfat.c | 124 | if (fn && !fn(job)) { |
29 | index XXXXXXX..XXXXXXX 100644 | 125 | - job_unlock(); |
30 | --- a/block/vvfat.c | 126 | + real_job_unlock(); |
31 | +++ b/block/vvfat.c | 127 | return; |
32 | @@ -XXX,XX +XXX,XX @@ static int do_commit(BDRVVVFATState* s) | ||
33 | return ret; | ||
34 | } | 128 | } |
35 | 129 | ||
36 | - if (s->qcow->bs->drv && s->qcow->bs->drv->bdrv_make_empty) { | 130 | assert(!job->deferred_to_main_loop); |
37 | - s->qcow->bs->drv->bdrv_make_empty(s->qcow->bs); | 131 | timer_del(&job->sleep_timer); |
38 | - } | 132 | job->busy = true; |
39 | + bdrv_make_empty(s->qcow, NULL); | 133 | - job_unlock(); |
40 | 134 | + real_job_unlock(); | |
41 | memset(s->used_clusters, 0, sector2cluster(s, s->sector_count)); | 135 | aio_co_enter(job->aio_context, job->co); |
42 | 136 | } | |
137 | |||
138 | @@ -XXX,XX +XXX,XX @@ void job_enter(Job *job) | ||
139 | * called explicitly. */ | ||
140 | static void coroutine_fn job_do_yield(Job *job, uint64_t ns) | ||
141 | { | ||
142 | - job_lock(); | ||
143 | + real_job_lock(); | ||
144 | if (ns != -1) { | ||
145 | timer_mod(&job->sleep_timer, ns); | ||
146 | } | ||
147 | job->busy = false; | ||
148 | job_event_idle(job); | ||
149 | - job_unlock(); | ||
150 | + real_job_unlock(); | ||
151 | qemu_coroutine_yield(); | ||
152 | |||
153 | /* Set by job_enter_cond() before re-entering the coroutine. */ | ||
43 | -- | 154 | -- |
44 | 2.25.4 | 155 | 2.37.3 |
45 | |||
46 | diff view generated by jsdifflib |
1 | From: Max Reitz <mreitz@redhat.com> | 1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | This mask will supplement BdrvChildClass when it comes to what role (or | 3 | Categorize the fields in struct Job to understand which ones |
4 | combination of roles) a child takes for its parent. It consists of | 4 | need to be protected by the job mutex and which don't. |
5 | BdrvChildRoleBits values (which is an enum). | ||
6 | 5 | ||
7 | Because empty enums are not allowed, let us just start with it filled. | 6 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
8 | 7 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> | |
9 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 8 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> |
10 | Message-Id: <20200513110544.176672-5-mreitz@redhat.com> | 9 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> |
11 | Reviewed-by: Eric Blake <eblake@redhat.com> | 10 | Message-Id: <20220926093214.506243-3-eesposit@redhat.com> |
12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
13 | --- | 12 | --- |
14 | include/block/block.h | 56 +++++++++++++++++++++++++++++++++++++++++++ | 13 | include/qemu/job.h | 61 +++++++++++++++++++++++++++------------------- |
15 | 1 file changed, 56 insertions(+) | 14 | 1 file changed, 36 insertions(+), 25 deletions(-) |
16 | 15 | ||
17 | diff --git a/include/block/block.h b/include/block/block.h | 16 | diff --git a/include/qemu/job.h b/include/qemu/job.h |
18 | index XXXXXXX..XXXXXXX 100644 | 17 | index XXXXXXX..XXXXXXX 100644 |
19 | --- a/include/block/block.h | 18 | --- a/include/qemu/job.h |
20 | +++ b/include/block/block.h | 19 | +++ b/include/qemu/job.h |
21 | @@ -XXX,XX +XXX,XX @@ enum { | 20 | @@ -XXX,XX +XXX,XX @@ typedef struct JobTxn JobTxn; |
22 | DEFAULT_PERM_UNCHANGED = BLK_PERM_ALL & ~DEFAULT_PERM_PASSTHROUGH, | 21 | * Long-running operation. |
23 | }; | 22 | */ |
24 | 23 | typedef struct Job { | |
25 | +/* | 24 | + |
26 | + * Flags that parent nodes assign to child nodes to specify what kind of | 25 | + /* Fields set at initialization (job_create), and never modified */ |
27 | + * role(s) they take. | 26 | + |
28 | + * | 27 | /** The ID of the job. May be NULL for internal jobs. */ |
29 | + * At least one of DATA, METADATA, FILTERED, or COW must be set for | 28 | char *id; |
30 | + * every child. | 29 | |
31 | + */ | 30 | - /** The type of this job. */ |
32 | +enum BdrvChildRoleBits { | 31 | + /** |
33 | + /* | 32 | + * The type of this job. |
34 | + * This child stores data. | 33 | + * All callbacks are called with job_mutex *not* held. |
35 | + * Any node may have an arbitrary number of such children. | ||
36 | + */ | 34 | + */ |
37 | + BDRV_CHILD_DATA = (1 << 0), | 35 | const JobDriver *driver; |
36 | |||
37 | - /** Reference count of the block job */ | ||
38 | - int refcnt; | ||
39 | - | ||
40 | - /** Current state; See @JobStatus for details. */ | ||
41 | - JobStatus status; | ||
42 | - | ||
43 | - /** AioContext to run the job coroutine in */ | ||
44 | - AioContext *aio_context; | ||
45 | - | ||
46 | /** | ||
47 | * The coroutine that executes the job. If not NULL, it is reentered when | ||
48 | * busy is false and the job is cancelled. | ||
49 | + * Initialized in job_start() | ||
50 | */ | ||
51 | Coroutine *co; | ||
52 | |||
53 | + /** True if this job should automatically finalize itself */ | ||
54 | + bool auto_finalize; | ||
38 | + | 55 | + |
39 | + /* | 56 | + /** True if this job should automatically dismiss itself */ |
40 | + * This child stores metadata. | 57 | + bool auto_dismiss; |
41 | + * Any node may have an arbitrary number of metadata-storing | ||
42 | + * children. | ||
43 | + */ | ||
44 | + BDRV_CHILD_METADATA = (1 << 1), | ||
45 | + | 58 | + |
46 | + /* | 59 | + /** The completion function that will be called when the job completes. */ |
47 | + * A child that always presents exactly the same visible data as | 60 | + BlockCompletionFunc *cb; |
48 | + * the parent, e.g. by virtue of the parent forwarding all reads | ||
49 | + * and writes. | ||
50 | + * This flag is mutually exclusive with DATA, METADATA, and COW. | ||
51 | + * Any node may have at most one filtered child at a time. | ||
52 | + */ | ||
53 | + BDRV_CHILD_FILTERED = (1 << 2), | ||
54 | + | 61 | + |
55 | + /* | 62 | + /** The opaque value that is passed to the completion function. */ |
56 | + * Child from which to read all data that isn’t allocated in the | 63 | + void *opaque; |
57 | + * parent (i.e., the backing child); such data is copied to the | ||
58 | + * parent through COW (and optionally COR). | ||
59 | + * This field is mutually exclusive with DATA, METADATA, and | ||
60 | + * FILTERED. | ||
61 | + * Any node may have at most one such backing child at a time. | ||
62 | + */ | ||
63 | + BDRV_CHILD_COW = (1 << 3), | ||
64 | + | 64 | + |
65 | + /* | 65 | + /* ProgressMeter API is thread-safe */ |
66 | + * The primary child. For most drivers, this is the child whose | 66 | + ProgressMeter progress; |
67 | + * filename applies best to the parent node. | ||
68 | + * Any node may have at most one primary child at a time. | ||
69 | + */ | ||
70 | + BDRV_CHILD_PRIMARY = (1 << 4), | ||
71 | + | 67 | + |
72 | + /* Useful combination of flags */ | ||
73 | + BDRV_CHILD_IMAGE = BDRV_CHILD_DATA | ||
74 | + | BDRV_CHILD_METADATA | ||
75 | + | BDRV_CHILD_PRIMARY, | ||
76 | +}; | ||
77 | + | 68 | + |
78 | +/* Mask of BdrvChildRoleBits values */ | 69 | + /** Protected by AioContext lock */ |
79 | +typedef unsigned int BdrvChildRole; | ||
80 | + | 70 | + |
81 | char *bdrv_perm_names(uint64_t perm); | 71 | + /** AioContext to run the job coroutine in */ |
82 | uint64_t bdrv_qapi_perm_to_blk_perm(BlockPermission qapi_perm); | 72 | + AioContext *aio_context; |
73 | + | ||
74 | + /** Reference count of the block job */ | ||
75 | + int refcnt; | ||
76 | + | ||
77 | + /** Current state; See @JobStatus for details. */ | ||
78 | + JobStatus status; | ||
79 | + | ||
80 | /** | ||
81 | * Timer that is used by @job_sleep_ns. Accessed under job_mutex (in | ||
82 | * job.c). | ||
83 | @@ -XXX,XX +XXX,XX @@ typedef struct Job { | ||
84 | /** Set to true when the job has deferred work to the main loop. */ | ||
85 | bool deferred_to_main_loop; | ||
86 | |||
87 | - /** True if this job should automatically finalize itself */ | ||
88 | - bool auto_finalize; | ||
89 | - | ||
90 | - /** True if this job should automatically dismiss itself */ | ||
91 | - bool auto_dismiss; | ||
92 | - | ||
93 | - ProgressMeter progress; | ||
94 | - | ||
95 | /** | ||
96 | * Return code from @run and/or @prepare callback(s). | ||
97 | * Not final until the job has reached the CONCLUDED status. | ||
98 | @@ -XXX,XX +XXX,XX @@ typedef struct Job { | ||
99 | */ | ||
100 | Error *err; | ||
101 | |||
102 | - /** The completion function that will be called when the job completes. */ | ||
103 | - BlockCompletionFunc *cb; | ||
104 | - | ||
105 | - /** The opaque value that is passed to the completion function. */ | ||
106 | - void *opaque; | ||
107 | - | ||
108 | /** Notifiers called when a cancelled job is finalised */ | ||
109 | NotifierList on_finalize_cancelled; | ||
110 | |||
111 | @@ -XXX,XX +XXX,XX @@ typedef struct Job { | ||
112 | |||
113 | /** | ||
114 | * Callbacks and other information about a Job driver. | ||
115 | + * All callbacks are invoked with job_mutex *not* held. | ||
116 | */ | ||
117 | struct JobDriver { | ||
118 | |||
119 | @@ -XXX,XX +XXX,XX @@ void coroutine_fn job_yield(Job *job); | ||
120 | */ | ||
121 | void coroutine_fn job_sleep_ns(Job *job, int64_t ns); | ||
122 | |||
123 | - | ||
124 | /** Returns the JobType of a given Job. */ | ||
125 | JobType job_type(const Job *job); | ||
83 | 126 | ||
84 | -- | 127 | -- |
85 | 2.25.4 | 128 | 2.37.3 |
86 | |||
87 | diff view generated by jsdifflib |
1 | From: Max Reitz <mreitz@redhat.com> | 1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Make bdrv_child_cb_attach() call bdrv_backing_attach() for children with | 3 | job_event_* functions can all be static, as they are not used |
4 | a COW role (and drop the reverse call from bdrv_backing_attach()), so it | 4 | outside job.c. |
5 | can be used for any child (with a proper role set). | ||
6 | 5 | ||
7 | Because so far no child has a proper role set, we need a temporary new | 6 | Same applies for job_txn_add_job(). |
8 | callback for child_backing.attach that ensures bdrv_backing_attach() is | ||
9 | called for all COW children that do not have their role set yet. | ||
10 | 7 | ||
11 | (Also, move bdrv_child_cb_attach() down to group it with | 8 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
12 | bdrv_inherited_options().) | 9 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> |
13 | 10 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> | |
14 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 11 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> |
15 | Message-Id: <20200513110544.176672-13-mreitz@redhat.com> | 12 | Message-Id: <20220926093214.506243-4-eesposit@redhat.com> |
16 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
17 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 13 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
18 | --- | 14 | --- |
19 | block.c | 27 ++++++++++++++++++++------- | 15 | include/qemu/job.h | 18 ------------------ |
20 | 1 file changed, 20 insertions(+), 7 deletions(-) | 16 | job.c | 22 +++++++++++++++++++--- |
17 | 2 files changed, 19 insertions(+), 21 deletions(-) | ||
21 | 18 | ||
22 | diff --git a/block.c b/block.c | 19 | diff --git a/include/qemu/job.h b/include/qemu/job.h |
23 | index XXXXXXX..XXXXXXX 100644 | 20 | index XXXXXXX..XXXXXXX 100644 |
24 | --- a/block.c | 21 | --- a/include/qemu/job.h |
25 | +++ b/block.c | 22 | +++ b/include/qemu/job.h |
26 | @@ -XXX,XX +XXX,XX @@ static BlockDriverState *bdrv_open_inherit(const char *filename, | 23 | @@ -XXX,XX +XXX,XX @@ JobTxn *job_txn_new(void); |
27 | static void bdrv_inherited_options(BdrvChildRole role, bool parent_is_format, | 24 | */ |
28 | int *child_flags, QDict *child_options, | 25 | void job_txn_unref(JobTxn *txn); |
29 | int parent_flags, QDict *parent_options); | 26 | |
30 | +static void bdrv_child_cb_attach(BdrvChild *child); | 27 | -/** |
31 | 28 | - * @txn: The transaction (may be NULL) | |
32 | /* If non-zero, use only whitelisted block drivers */ | 29 | - * @job: Job to add to the transaction |
33 | static int use_bdrv_whitelist; | 30 | - * |
34 | @@ -XXX,XX +XXX,XX @@ static void bdrv_child_cb_drained_end(BdrvChild *child, | 31 | - * Add @job to the transaction. The @job must not already be in a transaction. |
35 | bdrv_drained_end_no_poll(bs, drained_end_counter); | 32 | - * The caller must call either job_txn_unref() or job_completed() to release |
33 | - * the reference that is automatically grabbed here. | ||
34 | - * | ||
35 | - * If @txn is NULL, the function does nothing. | ||
36 | - */ | ||
37 | -void job_txn_add_job(JobTxn *txn, Job *job); | ||
38 | - | ||
39 | /** | ||
40 | * Create a new long-running job and return it. | ||
41 | * | ||
42 | @@ -XXX,XX +XXX,XX @@ void job_progress_set_remaining(Job *job, uint64_t remaining); | ||
43 | */ | ||
44 | void job_progress_increase_remaining(Job *job, uint64_t delta); | ||
45 | |||
46 | -/** To be called when a cancelled job is finalised. */ | ||
47 | -void job_event_cancelled(Job *job); | ||
48 | - | ||
49 | -/** To be called when a successfully completed job is finalised. */ | ||
50 | -void job_event_completed(Job *job); | ||
51 | - | ||
52 | /** | ||
53 | * Conditionally enter the job coroutine if the job is ready to run, not | ||
54 | * already busy and fn() returns true. fn() is called while under the job_lock | ||
55 | diff --git a/job.c b/job.c | ||
56 | index XXXXXXX..XXXXXXX 100644 | ||
57 | --- a/job.c | ||
58 | +++ b/job.c | ||
59 | @@ -XXX,XX +XXX,XX @@ void job_txn_unref(JobTxn *txn) | ||
60 | } | ||
36 | } | 61 | } |
37 | 62 | ||
38 | -static void bdrv_child_cb_attach(BdrvChild *child) | 63 | -void job_txn_add_job(JobTxn *txn, Job *job) |
39 | -{ | 64 | +/** |
40 | - BlockDriverState *bs = child->opaque; | 65 | + * @txn: The transaction (may be NULL) |
41 | - bdrv_apply_subtree_drain(child, bs); | 66 | + * @job: Job to add to the transaction |
42 | -} | 67 | + * |
43 | - | 68 | + * Add @job to the transaction. The @job must not already be in a transaction. |
44 | static void bdrv_child_cb_detach(BdrvChild *child) | 69 | + * The caller must call either job_txn_unref() or job_completed() to release |
70 | + * the reference that is automatically grabbed here. | ||
71 | + * | ||
72 | + * If @txn is NULL, the function does nothing. | ||
73 | + */ | ||
74 | +static void job_txn_add_job(JobTxn *txn, Job *job) | ||
45 | { | 75 | { |
46 | BlockDriverState *bs = child->opaque; | 76 | if (!txn) { |
47 | @@ -XXX,XX +XXX,XX @@ static void bdrv_backing_attach(BdrvChild *c) | 77 | return; |
48 | parent->backing_blocker); | 78 | @@ -XXX,XX +XXX,XX @@ void job_progress_increase_remaining(Job *job, uint64_t delta) |
49 | bdrv_op_unblock(backing_hd, BLOCK_OP_TYPE_BACKUP_TARGET, | 79 | progress_increase_remaining(&job->progress, delta); |
50 | parent->backing_blocker); | ||
51 | +} | ||
52 | |||
53 | +/* XXX: Will be removed along with child_backing */ | ||
54 | +static void bdrv_child_cb_attach_backing(BdrvChild *c) | ||
55 | +{ | ||
56 | + if (!(c->role & BDRV_CHILD_COW)) { | ||
57 | + bdrv_backing_attach(c); | ||
58 | + } | ||
59 | bdrv_child_cb_attach(c); | ||
60 | } | 80 | } |
61 | 81 | ||
62 | @@ -XXX,XX +XXX,XX @@ static int bdrv_backing_update_filename(BdrvChild *c, BlockDriverState *base, | 82 | -void job_event_cancelled(Job *job) |
63 | const BdrvChildClass child_backing = { | 83 | +/** |
64 | .parent_is_bds = true, | 84 | + * To be called when a cancelled job is finalised. |
65 | .get_parent_desc = bdrv_child_get_parent_desc, | 85 | + */ |
66 | - .attach = bdrv_backing_attach, | 86 | +static void job_event_cancelled(Job *job) |
67 | + .attach = bdrv_child_cb_attach_backing, | 87 | { |
68 | .detach = bdrv_backing_detach, | 88 | notifier_list_notify(&job->on_finalize_cancelled, job); |
69 | .inherit_options = bdrv_backing_options, | ||
70 | .drained_begin = bdrv_child_cb_drained_begin, | ||
71 | @@ -XXX,XX +XXX,XX @@ static void bdrv_inherited_options(BdrvChildRole role, bool parent_is_format, | ||
72 | *child_flags = flags; | ||
73 | } | 89 | } |
74 | 90 | ||
75 | +static void bdrv_child_cb_attach(BdrvChild *child) | 91 | -void job_event_completed(Job *job) |
76 | +{ | 92 | +/** |
77 | + BlockDriverState *bs = child->opaque; | 93 | + * To be called when a successfully completed job is finalised. |
78 | + | 94 | + */ |
79 | + if (child->role & BDRV_CHILD_COW) { | 95 | +static void job_event_completed(Job *job) |
80 | + bdrv_backing_attach(child); | ||
81 | + } | ||
82 | + | ||
83 | + bdrv_apply_subtree_drain(child, bs); | ||
84 | +} | ||
85 | + | ||
86 | static int bdrv_open_flags(BlockDriverState *bs, int flags) | ||
87 | { | 96 | { |
88 | int open_flags = flags; | 97 | notifier_list_notify(&job->on_finalize_completed, job); |
98 | } | ||
89 | -- | 99 | -- |
90 | 2.25.4 | 100 | 2.37.3 |
91 | |||
92 | diff view generated by jsdifflib |
1 | From: Max Reitz <mreitz@redhat.com> | 1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Two callers of BlockDriver.bdrv_make_empty() remain that should not call | 3 | Same as AIO_WAIT_WHILE macro, but if we are in the Main loop |
4 | this method directly. Both do not have access to a BdrvChild, but they | 4 | do not release and then acquire ctx_ 's aiocontext. |
5 | can use a BlockBackend, so we add this function that lets them use it. | ||
6 | 5 | ||
7 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 6 | Once all Aiocontext locks go away, this macro will replace |
8 | Message-Id: <20200429141126.85159-4-mreitz@redhat.com> | 7 | AIO_WAIT_WHILE. |
9 | Reviewed-by: Eric Blake <eblake@redhat.com> | 8 | |
9 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
10 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
11 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> | ||
12 | Message-Id: <20220926093214.506243-5-eesposit@redhat.com> | ||
13 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 14 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
11 | --- | 15 | --- |
12 | include/sysemu/block-backend.h | 2 ++ | 16 | include/block/aio-wait.h | 17 +++++++++++++---- |
13 | block/block-backend.c | 10 ++++++++++ | 17 | 1 file changed, 13 insertions(+), 4 deletions(-) |
14 | 2 files changed, 12 insertions(+) | ||
15 | 18 | ||
16 | diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h | 19 | diff --git a/include/block/aio-wait.h b/include/block/aio-wait.h |
17 | index XXXXXXX..XXXXXXX 100644 | 20 | index XXXXXXX..XXXXXXX 100644 |
18 | --- a/include/sysemu/block-backend.h | 21 | --- a/include/block/aio-wait.h |
19 | +++ b/include/sysemu/block-backend.h | 22 | +++ b/include/block/aio-wait.h |
20 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn blk_co_copy_range(BlockBackend *blk_in, int64_t off_in, | 23 | @@ -XXX,XX +XXX,XX @@ typedef struct { |
21 | 24 | extern AioWait global_aio_wait; | |
22 | const BdrvChild *blk_root(BlockBackend *blk); | 25 | |
23 | 26 | /** | |
24 | +int blk_make_empty(BlockBackend *blk, Error **errp); | 27 | - * AIO_WAIT_WHILE: |
28 | + * AIO_WAIT_WHILE_INTERNAL: | ||
29 | * @ctx: the aio context, or NULL if multiple aio contexts (for which the | ||
30 | * caller does not hold a lock) are involved in the polling condition. | ||
31 | * @cond: wait while this conditional expression is true | ||
32 | + * @unlock: whether to unlock and then lock again @ctx. This apples | ||
33 | + * only when waiting for another AioContext from the main loop. | ||
34 | + * Otherwise it's ignored. | ||
35 | * | ||
36 | * Wait while a condition is true. Use this to implement synchronous | ||
37 | * operations that require event loop activity. | ||
38 | @@ -XXX,XX +XXX,XX @@ extern AioWait global_aio_wait; | ||
39 | * wait on conditions between two IOThreads since that could lead to deadlock, | ||
40 | * go via the main loop instead. | ||
41 | */ | ||
42 | -#define AIO_WAIT_WHILE(ctx, cond) ({ \ | ||
43 | +#define AIO_WAIT_WHILE_INTERNAL(ctx, cond, unlock) ({ \ | ||
44 | bool waited_ = false; \ | ||
45 | AioWait *wait_ = &global_aio_wait; \ | ||
46 | AioContext *ctx_ = (ctx); \ | ||
47 | @@ -XXX,XX +XXX,XX @@ extern AioWait global_aio_wait; | ||
48 | assert(qemu_get_current_aio_context() == \ | ||
49 | qemu_get_aio_context()); \ | ||
50 | while ((cond)) { \ | ||
51 | - if (ctx_) { \ | ||
52 | + if (unlock && ctx_) { \ | ||
53 | aio_context_release(ctx_); \ | ||
54 | } \ | ||
55 | aio_poll(qemu_get_aio_context(), true); \ | ||
56 | - if (ctx_) { \ | ||
57 | + if (unlock && ctx_) { \ | ||
58 | aio_context_acquire(ctx_); \ | ||
59 | } \ | ||
60 | waited_ = true; \ | ||
61 | @@ -XXX,XX +XXX,XX @@ extern AioWait global_aio_wait; | ||
62 | qatomic_dec(&wait_->num_waiters); \ | ||
63 | waited_; }) | ||
64 | |||
65 | +#define AIO_WAIT_WHILE(ctx, cond) \ | ||
66 | + AIO_WAIT_WHILE_INTERNAL(ctx, cond, true) | ||
25 | + | 67 | + |
26 | #endif | 68 | +#define AIO_WAIT_WHILE_UNLOCKED(ctx, cond) \ |
27 | diff --git a/block/block-backend.c b/block/block-backend.c | 69 | + AIO_WAIT_WHILE_INTERNAL(ctx, cond, false) |
28 | index XXXXXXX..XXXXXXX 100644 | ||
29 | --- a/block/block-backend.c | ||
30 | +++ b/block/block-backend.c | ||
31 | @@ -XXX,XX +XXX,XX @@ const BdrvChild *blk_root(BlockBackend *blk) | ||
32 | { | ||
33 | return blk->root; | ||
34 | } | ||
35 | + | 70 | + |
36 | +int blk_make_empty(BlockBackend *blk, Error **errp) | 71 | /** |
37 | +{ | 72 | * aio_wait_kick: |
38 | + if (!blk_is_available(blk)) { | 73 | * Wake up the main thread if it is waiting on AIO_WAIT_WHILE(). During |
39 | + error_setg(errp, "No medium inserted"); | ||
40 | + return -ENOMEDIUM; | ||
41 | + } | ||
42 | + | ||
43 | + return bdrv_make_empty(blk->root, errp); | ||
44 | +} | ||
45 | -- | 74 | -- |
46 | 2.25.4 | 75 | 2.37.3 |
47 | |||
48 | diff view generated by jsdifflib |
1 | From: Max Reitz <mreitz@redhat.com> | 1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Right now, all users of bdrv_make_empty() call the BlockDriver method | 3 | With "intact" we mean that all job.h functions implicitly |
4 | directly. That is not only bad style, it is also wrong, unless the | 4 | take the lock. Therefore API callers are unmodified. |
5 | caller has a BdrvChild with a WRITE or WRITE_UNCHANGED permission. | ||
6 | (WRITE_UNCHANGED suffices, because callers generally use this function | ||
7 | to clear a node with a backing file after a commit operation.) | ||
8 | 5 | ||
9 | Introduce bdrv_make_empty() that verifies that it does. | 6 | This means that: |
7 | - many static functions that will be always called with job lock held | ||
8 | become _locked, and call _locked functions | ||
9 | - all public functions take the lock internally if needed, and call _locked | ||
10 | functions | ||
11 | - all public functions called internally by other functions in job.c will have a | ||
12 | _locked counterpart (sometimes public), to avoid deadlocks (job lock already taken). | ||
13 | These functions are not used for now. | ||
14 | - some public functions called only from exernal files (not job.c) do not | ||
15 | have _locked() counterpart and take the lock inside. Others won't need | ||
16 | the lock at all because use fields only set at initialization and | ||
17 | never modified. | ||
10 | 18 | ||
11 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 19 | job_{lock/unlock} is independent from real_job_{lock/unlock}. |
12 | Message-Id: <20200429141126.85159-2-mreitz@redhat.com> | 20 | |
13 | Reviewed-by: Eric Blake <eblake@redhat.com> | 21 | Note: at this stage, job_{lock/unlock} and job lock guard macros |
22 | are *nop* | ||
23 | |||
24 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
25 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
26 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
27 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> | ||
28 | Message-Id: <20220926093214.506243-6-eesposit@redhat.com> | ||
14 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 29 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
15 | --- | 30 | --- |
16 | include/block/block.h | 1 + | 31 | include/qemu/job.h | 138 +++++++++- |
17 | block.c | 23 +++++++++++++++++++++++ | 32 | job.c | 610 ++++++++++++++++++++++++++++++++------------- |
18 | 2 files changed, 24 insertions(+) | 33 | 2 files changed, 561 insertions(+), 187 deletions(-) |
19 | 34 | ||
20 | diff --git a/include/block/block.h b/include/block/block.h | 35 | diff --git a/include/qemu/job.h b/include/qemu/job.h |
21 | index XXXXXXX..XXXXXXX 100644 | 36 | index XXXXXXX..XXXXXXX 100644 |
22 | --- a/include/block/block.h | 37 | --- a/include/qemu/job.h |
23 | +++ b/include/block/block.h | 38 | +++ b/include/qemu/job.h |
24 | @@ -XXX,XX +XXX,XX @@ BlockMeasureInfo *bdrv_measure(BlockDriver *drv, QemuOpts *opts, | 39 | @@ -XXX,XX +XXX,XX @@ JobTxn *job_txn_new(void); |
25 | void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr); | 40 | */ |
26 | void bdrv_refresh_limits(BlockDriverState *bs, Error **errp); | 41 | void job_txn_unref(JobTxn *txn); |
27 | int bdrv_commit(BlockDriverState *bs); | 42 | |
28 | +int bdrv_make_empty(BdrvChild *c, Error **errp); | 43 | +/* |
29 | int bdrv_change_backing_file(BlockDriverState *bs, | 44 | + * Same as job_txn_unref(), but called with job lock held. |
30 | const char *backing_file, const char *backing_fmt); | 45 | + * Might release the lock temporarily. |
31 | void bdrv_register(BlockDriver *bdrv); | 46 | + */ |
32 | diff --git a/block.c b/block.c | 47 | +void job_txn_unref_locked(JobTxn *txn); |
48 | + | ||
49 | /** | ||
50 | * Create a new long-running job and return it. | ||
51 | + * Called with job_mutex *not* held. | ||
52 | * | ||
53 | * @job_id: The id of the newly-created job, or %NULL for internal jobs | ||
54 | * @driver: The class object for the newly-created job. | ||
55 | @@ -XXX,XX +XXX,XX @@ void *job_create(const char *job_id, const JobDriver *driver, JobTxn *txn, | ||
56 | */ | ||
57 | void job_ref(Job *job); | ||
58 | |||
59 | +/* Same as job_ref(), but called with job lock held. */ | ||
60 | +void job_ref_locked(Job *job); | ||
61 | + | ||
62 | /** | ||
63 | * Release a reference that was previously acquired with job_ref() or | ||
64 | * job_create(). If it's the last reference to the object, it will be freed. | ||
65 | */ | ||
66 | void job_unref(Job *job); | ||
67 | |||
68 | +/* Same as job_unref(), but called with job lock held. */ | ||
69 | +void job_unref_locked(Job *job); | ||
70 | + | ||
71 | /** | ||
72 | * @job: The job that has made progress | ||
73 | * @done: How much progress the job made since the last call | ||
74 | * | ||
75 | * Updates the progress counter of the job. | ||
76 | + * | ||
77 | + * May be called with mutex held or not held. | ||
78 | */ | ||
79 | void job_progress_update(Job *job, uint64_t done); | ||
80 | |||
81 | @@ -XXX,XX +XXX,XX @@ void job_progress_update(Job *job, uint64_t done); | ||
82 | * | ||
83 | * Sets the expected end value of the progress counter of a job so that a | ||
84 | * completion percentage can be calculated when the progress is updated. | ||
85 | + * | ||
86 | + * May be called with mutex held or not held. | ||
87 | */ | ||
88 | void job_progress_set_remaining(Job *job, uint64_t remaining); | ||
89 | |||
90 | @@ -XXX,XX +XXX,XX @@ void job_progress_set_remaining(Job *job, uint64_t remaining); | ||
91 | * length before, and job_progress_update() afterwards. | ||
92 | * (So the operation acts as a parenthesis in regards to the main job | ||
93 | * operation running in background.) | ||
94 | + * | ||
95 | + * May be called with mutex held or not held. | ||
96 | */ | ||
97 | void job_progress_increase_remaining(Job *job, uint64_t delta); | ||
98 | |||
99 | @@ -XXX,XX +XXX,XX @@ void job_progress_increase_remaining(Job *job, uint64_t delta); | ||
100 | */ | ||
101 | void job_enter_cond(Job *job, bool(*fn)(Job *job)); | ||
102 | |||
103 | +/* | ||
104 | + * Same as job_enter_cond(), but called with job lock held. | ||
105 | + * Might release the lock temporarily. | ||
106 | + */ | ||
107 | +void job_enter_cond_locked(Job *job, bool(*fn)(Job *job)); | ||
108 | + | ||
109 | /** | ||
110 | * @job: A job that has not yet been started. | ||
111 | * | ||
112 | * Begins execution of a job. | ||
113 | * Takes ownership of one reference to the job object. | ||
114 | + * | ||
115 | + * Called with job_mutex *not* held. | ||
116 | */ | ||
117 | void job_start(Job *job); | ||
118 | |||
119 | @@ -XXX,XX +XXX,XX @@ void job_start(Job *job); | ||
120 | * @job: The job to enter. | ||
121 | * | ||
122 | * Continue the specified job by entering the coroutine. | ||
123 | + * Called with job_mutex *not* held. | ||
124 | */ | ||
125 | void job_enter(Job *job); | ||
126 | |||
127 | @@ -XXX,XX +XXX,XX @@ void job_enter(Job *job); | ||
128 | * | ||
129 | * Pause now if job_pause() has been called. Jobs that perform lots of I/O | ||
130 | * must call this between requests so that the job can be paused. | ||
131 | + * | ||
132 | + * Called with job_mutex *not* held. | ||
133 | */ | ||
134 | void coroutine_fn job_pause_point(Job *job); | ||
135 | |||
136 | @@ -XXX,XX +XXX,XX @@ void coroutine_fn job_pause_point(Job *job); | ||
137 | * @job: The job that calls the function. | ||
138 | * | ||
139 | * Yield the job coroutine. | ||
140 | + * Called with job_mutex *not* held. | ||
141 | */ | ||
142 | void coroutine_fn job_yield(Job *job); | ||
143 | |||
144 | @@ -XXX,XX +XXX,XX @@ void coroutine_fn job_yield(Job *job); | ||
145 | * Put the job to sleep (assuming that it wasn't canceled) for @ns | ||
146 | * %QEMU_CLOCK_REALTIME nanoseconds. Canceling the job will immediately | ||
147 | * interrupt the wait. | ||
148 | + * | ||
149 | + * Called with job_mutex *not* held. | ||
150 | */ | ||
151 | void coroutine_fn job_sleep_ns(Job *job, int64_t ns); | ||
152 | |||
153 | @@ -XXX,XX +XXX,XX @@ const char *job_type_str(const Job *job); | ||
154 | /** Returns true if the job should not be visible to the management layer. */ | ||
155 | bool job_is_internal(Job *job); | ||
156 | |||
157 | -/** Returns whether the job is being cancelled. */ | ||
158 | +/** | ||
159 | + * Returns whether the job is being cancelled. | ||
160 | + * Called with job_mutex *not* held. | ||
161 | + */ | ||
162 | bool job_is_cancelled(Job *job); | ||
163 | |||
164 | +/* Same as job_is_cancelled(), but called with job lock held. */ | ||
165 | +bool job_is_cancelled_locked(Job *job); | ||
166 | + | ||
167 | /** | ||
168 | * Returns whether the job is scheduled for cancellation (at an | ||
169 | * indefinite point). | ||
170 | + * Called with job_mutex *not* held. | ||
171 | */ | ||
172 | bool job_cancel_requested(Job *job); | ||
173 | |||
174 | -/** Returns whether the job is in a completed state. */ | ||
175 | +/** | ||
176 | + * Returns whether the job is in a completed state. | ||
177 | + * Called with job_mutex *not* held. | ||
178 | + */ | ||
179 | bool job_is_completed(Job *job); | ||
180 | |||
181 | -/** Returns whether the job is ready to be completed. */ | ||
182 | +/* Same as job_is_completed(), but called with job lock held. */ | ||
183 | +bool job_is_completed_locked(Job *job); | ||
184 | + | ||
185 | +/** | ||
186 | + * Returns whether the job is ready to be completed. | ||
187 | + * Called with job_mutex *not* held. | ||
188 | + */ | ||
189 | bool job_is_ready(Job *job); | ||
190 | |||
191 | +/* Same as job_is_ready(), but called with job lock held. */ | ||
192 | +bool job_is_ready_locked(Job *job); | ||
193 | + | ||
194 | /** | ||
195 | * Request @job to pause at the next pause point. Must be paired with | ||
196 | * job_resume(). If the job is supposed to be resumed by user action, call | ||
197 | @@ -XXX,XX +XXX,XX @@ bool job_is_ready(Job *job); | ||
198 | */ | ||
199 | void job_pause(Job *job); | ||
200 | |||
201 | +/* Same as job_pause(), but called with job lock held. */ | ||
202 | +void job_pause_locked(Job *job); | ||
203 | + | ||
204 | /** Resumes a @job paused with job_pause. */ | ||
205 | void job_resume(Job *job); | ||
206 | |||
207 | +/* | ||
208 | + * Same as job_resume(), but called with job lock held. | ||
209 | + * Might release the lock temporarily. | ||
210 | + */ | ||
211 | +void job_resume_locked(Job *job); | ||
212 | + | ||
213 | /** | ||
214 | * Asynchronously pause the specified @job. | ||
215 | * Do not allow a resume until a matching call to job_user_resume. | ||
216 | */ | ||
217 | void job_user_pause(Job *job, Error **errp); | ||
218 | |||
219 | +/* Same as job_user_pause(), but called with job lock held. */ | ||
220 | +void job_user_pause_locked(Job *job, Error **errp); | ||
221 | + | ||
222 | /** Returns true if the job is user-paused. */ | ||
223 | bool job_user_paused(Job *job); | ||
224 | |||
225 | +/* Same as job_user_paused(), but called with job lock held. */ | ||
226 | +bool job_user_paused_locked(Job *job); | ||
227 | + | ||
228 | /** | ||
229 | * Resume the specified @job. | ||
230 | * Must be paired with a preceding job_user_pause. | ||
231 | */ | ||
232 | void job_user_resume(Job *job, Error **errp); | ||
233 | |||
234 | +/* | ||
235 | + * Same as job_user_resume(), but called with job lock held. | ||
236 | + * Might release the lock temporarily. | ||
237 | + */ | ||
238 | +void job_user_resume_locked(Job *job, Error **errp); | ||
239 | + | ||
240 | /** | ||
241 | * Get the next element from the list of block jobs after @job, or the | ||
242 | * first one if @job is %NULL. | ||
243 | @@ -XXX,XX +XXX,XX @@ void job_user_resume(Job *job, Error **errp); | ||
244 | */ | ||
245 | Job *job_next(Job *job); | ||
246 | |||
247 | +/* Same as job_next(), but called with job lock held. */ | ||
248 | +Job *job_next_locked(Job *job); | ||
249 | + | ||
250 | /** | ||
251 | * Get the job identified by @id (which must not be %NULL). | ||
252 | * | ||
253 | @@ -XXX,XX +XXX,XX @@ Job *job_next(Job *job); | ||
254 | */ | ||
255 | Job *job_get(const char *id); | ||
256 | |||
257 | +/* Same as job_get(), but called with job lock held. */ | ||
258 | +Job *job_get_locked(const char *id); | ||
259 | + | ||
260 | /** | ||
261 | * Check whether the verb @verb can be applied to @job in its current state. | ||
262 | * Returns 0 if the verb can be applied; otherwise errp is set and -EPERM | ||
263 | @@ -XXX,XX +XXX,XX @@ Job *job_get(const char *id); | ||
264 | */ | ||
265 | int job_apply_verb(Job *job, JobVerb verb, Error **errp); | ||
266 | |||
267 | -/** The @job could not be started, free it. */ | ||
268 | +/* Same as job_apply_verb, but called with job lock held. */ | ||
269 | +int job_apply_verb_locked(Job *job, JobVerb verb, Error **errp); | ||
270 | + | ||
271 | +/** | ||
272 | + * The @job could not be started, free it. | ||
273 | + * Called with job_mutex *not* held. | ||
274 | + */ | ||
275 | void job_early_fail(Job *job); | ||
276 | |||
277 | -/** Moves the @job from RUNNING to READY */ | ||
278 | +/** | ||
279 | + * Moves the @job from RUNNING to READY. | ||
280 | + * Called with job_mutex *not* held. | ||
281 | + */ | ||
282 | void job_transition_to_ready(Job *job); | ||
283 | |||
284 | /** Asynchronously complete the specified @job. */ | ||
285 | void job_complete(Job *job, Error **errp); | ||
286 | |||
287 | +/* | ||
288 | + * Same as job_complete(), but called with job lock held. | ||
289 | + * Might release the lock temporarily. | ||
290 | + */ | ||
291 | +void job_complete_locked(Job *job, Error **errp); | ||
292 | + | ||
293 | /** | ||
294 | * Asynchronously cancel the specified @job. If @force is true, the job should | ||
295 | * be cancelled immediately without waiting for a consistent state. | ||
296 | */ | ||
297 | void job_cancel(Job *job, bool force); | ||
298 | |||
299 | +/* Same as job_cancel(), but called with job lock held. */ | ||
300 | +void job_cancel_locked(Job *job, bool force); | ||
301 | + | ||
302 | /** | ||
303 | * Cancels the specified job like job_cancel(), but may refuse to do so if the | ||
304 | * operation isn't meaningful in the current state of the job. | ||
305 | */ | ||
306 | void job_user_cancel(Job *job, bool force, Error **errp); | ||
307 | |||
308 | +/* Same as job_user_cancel(), but called with job lock held. */ | ||
309 | +void job_user_cancel_locked(Job *job, bool force, Error **errp); | ||
310 | + | ||
311 | /** | ||
312 | * Synchronously cancel the @job. The completion callback is called | ||
313 | * before the function returns. If @force is false, the job may | ||
314 | @@ -XXX,XX +XXX,XX @@ void job_user_cancel(Job *job, bool force, Error **errp); | ||
315 | */ | ||
316 | int job_cancel_sync(Job *job, bool force); | ||
317 | |||
318 | -/** Synchronously force-cancels all jobs using job_cancel_sync(). */ | ||
319 | +/* Same as job_cancel_sync, but called with job lock held. */ | ||
320 | +int job_cancel_sync_locked(Job *job, bool force); | ||
321 | + | ||
322 | +/** | ||
323 | + * Synchronously force-cancels all jobs using job_cancel_sync_locked(). | ||
324 | + * | ||
325 | + * Called with job_lock *not* held. | ||
326 | + */ | ||
327 | void job_cancel_sync_all(void); | ||
328 | |||
329 | /** | ||
330 | @@ -XXX,XX +XXX,XX @@ void job_cancel_sync_all(void); | ||
331 | */ | ||
332 | int job_complete_sync(Job *job, Error **errp); | ||
333 | |||
334 | +/* Same as job_complete_sync, but called with job lock held. */ | ||
335 | +int job_complete_sync_locked(Job *job, Error **errp); | ||
336 | + | ||
337 | /** | ||
338 | * For a @job that has finished its work and is pending awaiting explicit | ||
339 | * acknowledgement to commit its work, this will commit that work. | ||
340 | @@ -XXX,XX +XXX,XX @@ int job_complete_sync(Job *job, Error **errp); | ||
341 | */ | ||
342 | void job_finalize(Job *job, Error **errp); | ||
343 | |||
344 | +/* Same as job_finalize(), but called with job lock held. */ | ||
345 | +void job_finalize_locked(Job *job, Error **errp); | ||
346 | + | ||
347 | /** | ||
348 | * Remove the concluded @job from the query list and resets the passed pointer | ||
349 | * to %NULL. Returns an error if the job is not actually concluded. | ||
350 | */ | ||
351 | void job_dismiss(Job **job, Error **errp); | ||
352 | |||
353 | +/* Same as job_dismiss(), but called with job lock held. */ | ||
354 | +void job_dismiss_locked(Job **job, Error **errp); | ||
355 | + | ||
356 | /** | ||
357 | * Synchronously finishes the given @job. If @finish is given, it is called to | ||
358 | * trigger completion or cancellation of the job. | ||
359 | @@ -XXX,XX +XXX,XX @@ void job_dismiss(Job **job, Error **errp); | ||
360 | * | ||
361 | * Callers must hold the AioContext lock of job->aio_context. | ||
362 | */ | ||
363 | -int job_finish_sync(Job *job, void (*finish)(Job *, Error **errp), Error **errp); | ||
364 | +int job_finish_sync(Job *job, void (*finish)(Job *, Error **errp), | ||
365 | + Error **errp); | ||
366 | + | ||
367 | +/* | ||
368 | + * Same as job_finish_sync(), but called with job lock held. | ||
369 | + * Might release the lock temporarily. | ||
370 | + */ | ||
371 | +int job_finish_sync_locked(Job *job, void (*finish)(Job *, Error **errp), | ||
372 | + Error **errp); | ||
373 | |||
374 | #endif | ||
375 | diff --git a/job.c b/job.c | ||
33 | index XXXXXXX..XXXXXXX 100644 | 376 | index XXXXXXX..XXXXXXX 100644 |
34 | --- a/block.c | 377 | --- a/job.c |
35 | +++ b/block.c | 378 | +++ b/job.c |
36 | @@ -XXX,XX +XXX,XX @@ void bdrv_del_child(BlockDriverState *parent_bs, BdrvChild *child, Error **errp) | 379 | @@ -XXX,XX +XXX,XX @@ |
37 | 380 | */ | |
38 | parent_bs->drv->bdrv_del_child(parent_bs, child, errp); | 381 | QemuMutex job_mutex; |
39 | } | 382 | |
40 | + | 383 | +/* Protected by job_mutex */ |
41 | +int bdrv_make_empty(BdrvChild *c, Error **errp) | 384 | static QLIST_HEAD(, Job) jobs = QLIST_HEAD_INITIALIZER(jobs); |
42 | +{ | 385 | |
43 | + BlockDriver *drv = c->bs->drv; | 386 | /* Job State Transition Table */ |
387 | @@ -XXX,XX +XXX,XX @@ JobTxn *job_txn_new(void) | ||
388 | return txn; | ||
389 | } | ||
390 | |||
391 | -static void job_txn_ref(JobTxn *txn) | ||
392 | +/* Called with job_mutex held. */ | ||
393 | +static void job_txn_ref_locked(JobTxn *txn) | ||
394 | { | ||
395 | txn->refcnt++; | ||
396 | } | ||
397 | |||
398 | -void job_txn_unref(JobTxn *txn) | ||
399 | +void job_txn_unref_locked(JobTxn *txn) | ||
400 | { | ||
401 | if (txn && --txn->refcnt == 0) { | ||
402 | g_free(txn); | ||
403 | } | ||
404 | } | ||
405 | |||
406 | +void job_txn_unref(JobTxn *txn) | ||
407 | +{ | ||
408 | + JOB_LOCK_GUARD(); | ||
409 | + job_txn_unref_locked(txn); | ||
410 | +} | ||
411 | + | ||
412 | /** | ||
413 | * @txn: The transaction (may be NULL) | ||
414 | * @job: Job to add to the transaction | ||
415 | @@ -XXX,XX +XXX,XX @@ void job_txn_unref(JobTxn *txn) | ||
416 | * the reference that is automatically grabbed here. | ||
417 | * | ||
418 | * If @txn is NULL, the function does nothing. | ||
419 | + * | ||
420 | + * Called with job_mutex held. | ||
421 | */ | ||
422 | -static void job_txn_add_job(JobTxn *txn, Job *job) | ||
423 | +static void job_txn_add_job_locked(JobTxn *txn, Job *job) | ||
424 | { | ||
425 | if (!txn) { | ||
426 | return; | ||
427 | @@ -XXX,XX +XXX,XX @@ static void job_txn_add_job(JobTxn *txn, Job *job) | ||
428 | job->txn = txn; | ||
429 | |||
430 | QLIST_INSERT_HEAD(&txn->jobs, job, txn_list); | ||
431 | - job_txn_ref(txn); | ||
432 | + job_txn_ref_locked(txn); | ||
433 | } | ||
434 | |||
435 | -static void job_txn_del_job(Job *job) | ||
436 | +/* Called with job_mutex held. */ | ||
437 | +static void job_txn_del_job_locked(Job *job) | ||
438 | { | ||
439 | if (job->txn) { | ||
440 | QLIST_REMOVE(job, txn_list); | ||
441 | - job_txn_unref(job->txn); | ||
442 | + job_txn_unref_locked(job->txn); | ||
443 | job->txn = NULL; | ||
444 | } | ||
445 | } | ||
446 | |||
447 | -static int job_txn_apply(Job *job, int fn(Job *)) | ||
448 | +/* Called with job_mutex held, but releases it temporarily. */ | ||
449 | +static int job_txn_apply_locked(Job *job, int fn(Job *)) | ||
450 | { | ||
451 | AioContext *inner_ctx; | ||
452 | Job *other_job, *next; | ||
453 | @@ -XXX,XX +XXX,XX @@ static int job_txn_apply(Job *job, int fn(Job *)) | ||
454 | * we need to release it here to avoid holding the lock twice - which would | ||
455 | * break AIO_WAIT_WHILE from within fn. | ||
456 | */ | ||
457 | - job_ref(job); | ||
458 | + job_ref_locked(job); | ||
459 | aio_context_release(job->aio_context); | ||
460 | |||
461 | QLIST_FOREACH_SAFE(other_job, &txn->jobs, txn_list, next) { | ||
462 | @@ -XXX,XX +XXX,XX @@ static int job_txn_apply(Job *job, int fn(Job *)) | ||
463 | * can't use a local variable to cache it. | ||
464 | */ | ||
465 | aio_context_acquire(job->aio_context); | ||
466 | - job_unref(job); | ||
467 | + job_unref_locked(job); | ||
468 | return rc; | ||
469 | } | ||
470 | |||
471 | @@ -XXX,XX +XXX,XX @@ bool job_is_internal(Job *job) | ||
472 | return (job->id == NULL); | ||
473 | } | ||
474 | |||
475 | -static void job_state_transition(Job *job, JobStatus s1) | ||
476 | +/* Called with job_mutex held. */ | ||
477 | +static void job_state_transition_locked(Job *job, JobStatus s1) | ||
478 | { | ||
479 | JobStatus s0 = job->status; | ||
480 | assert(s1 >= 0 && s1 < JOB_STATUS__MAX); | ||
481 | @@ -XXX,XX +XXX,XX @@ static void job_state_transition(Job *job, JobStatus s1) | ||
482 | } | ||
483 | } | ||
484 | |||
485 | -int job_apply_verb(Job *job, JobVerb verb, Error **errp) | ||
486 | +int job_apply_verb_locked(Job *job, JobVerb verb, Error **errp) | ||
487 | { | ||
488 | JobStatus s0 = job->status; | ||
489 | assert(verb >= 0 && verb < JOB_VERB__MAX); | ||
490 | @@ -XXX,XX +XXX,XX @@ int job_apply_verb(Job *job, JobVerb verb, Error **errp) | ||
491 | return -EPERM; | ||
492 | } | ||
493 | |||
494 | +int job_apply_verb(Job *job, JobVerb verb, Error **errp) | ||
495 | +{ | ||
496 | + JOB_LOCK_GUARD(); | ||
497 | + return job_apply_verb_locked(job, verb, errp); | ||
498 | +} | ||
499 | + | ||
500 | JobType job_type(const Job *job) | ||
501 | { | ||
502 | return job->driver->job_type; | ||
503 | @@ -XXX,XX +XXX,XX @@ const char *job_type_str(const Job *job) | ||
504 | return JobType_str(job_type(job)); | ||
505 | } | ||
506 | |||
507 | -bool job_is_cancelled(Job *job) | ||
508 | +bool job_is_cancelled_locked(Job *job) | ||
509 | { | ||
510 | /* force_cancel may be true only if cancelled is true, too */ | ||
511 | assert(job->cancelled || !job->force_cancel); | ||
512 | return job->force_cancel; | ||
513 | } | ||
514 | |||
515 | -bool job_cancel_requested(Job *job) | ||
516 | +bool job_is_cancelled(Job *job) | ||
517 | +{ | ||
518 | + JOB_LOCK_GUARD(); | ||
519 | + return job_is_cancelled_locked(job); | ||
520 | +} | ||
521 | + | ||
522 | +/* Called with job_mutex held. */ | ||
523 | +static bool job_cancel_requested_locked(Job *job) | ||
524 | { | ||
525 | return job->cancelled; | ||
526 | } | ||
527 | |||
528 | -bool job_is_ready(Job *job) | ||
529 | +bool job_cancel_requested(Job *job) | ||
530 | +{ | ||
531 | + JOB_LOCK_GUARD(); | ||
532 | + return job_cancel_requested_locked(job); | ||
533 | +} | ||
534 | + | ||
535 | +bool job_is_ready_locked(Job *job) | ||
536 | { | ||
537 | switch (job->status) { | ||
538 | case JOB_STATUS_UNDEFINED: | ||
539 | @@ -XXX,XX +XXX,XX @@ bool job_is_ready(Job *job) | ||
540 | return false; | ||
541 | } | ||
542 | |||
543 | -bool job_is_completed(Job *job) | ||
544 | +bool job_is_ready(Job *job) | ||
545 | +{ | ||
546 | + JOB_LOCK_GUARD(); | ||
547 | + return job_is_ready_locked(job); | ||
548 | +} | ||
549 | + | ||
550 | +bool job_is_completed_locked(Job *job) | ||
551 | { | ||
552 | switch (job->status) { | ||
553 | case JOB_STATUS_UNDEFINED: | ||
554 | @@ -XXX,XX +XXX,XX @@ bool job_is_completed(Job *job) | ||
555 | return false; | ||
556 | } | ||
557 | |||
558 | -static bool job_started(Job *job) | ||
559 | +bool job_is_completed(Job *job) | ||
560 | +{ | ||
561 | + JOB_LOCK_GUARD(); | ||
562 | + return job_is_completed_locked(job); | ||
563 | +} | ||
564 | + | ||
565 | +static bool job_started_locked(Job *job) | ||
566 | { | ||
567 | return job->co; | ||
568 | } | ||
569 | |||
570 | -static bool job_should_pause(Job *job) | ||
571 | +/* Called with job_mutex held. */ | ||
572 | +static bool job_should_pause_locked(Job *job) | ||
573 | { | ||
574 | return job->pause_count > 0; | ||
575 | } | ||
576 | |||
577 | -Job *job_next(Job *job) | ||
578 | +Job *job_next_locked(Job *job) | ||
579 | { | ||
580 | if (!job) { | ||
581 | return QLIST_FIRST(&jobs); | ||
582 | @@ -XXX,XX +XXX,XX @@ Job *job_next(Job *job) | ||
583 | return QLIST_NEXT(job, job_list); | ||
584 | } | ||
585 | |||
586 | -Job *job_get(const char *id) | ||
587 | +Job *job_next(Job *job) | ||
588 | +{ | ||
589 | + JOB_LOCK_GUARD(); | ||
590 | + return job_next_locked(job); | ||
591 | +} | ||
592 | + | ||
593 | +Job *job_get_locked(const char *id) | ||
594 | { | ||
595 | Job *job; | ||
596 | |||
597 | @@ -XXX,XX +XXX,XX @@ Job *job_get(const char *id) | ||
598 | return NULL; | ||
599 | } | ||
600 | |||
601 | +Job *job_get(const char *id) | ||
602 | +{ | ||
603 | + JOB_LOCK_GUARD(); | ||
604 | + return job_get_locked(id); | ||
605 | +} | ||
606 | + | ||
607 | +/* Called with job_mutex *not* held. */ | ||
608 | static void job_sleep_timer_cb(void *opaque) | ||
609 | { | ||
610 | Job *job = opaque; | ||
611 | @@ -XXX,XX +XXX,XX @@ void *job_create(const char *job_id, const JobDriver *driver, JobTxn *txn, | ||
612 | { | ||
613 | Job *job; | ||
614 | |||
615 | + JOB_LOCK_GUARD(); | ||
616 | + | ||
617 | if (job_id) { | ||
618 | if (flags & JOB_INTERNAL) { | ||
619 | error_setg(errp, "Cannot specify job ID for internal job"); | ||
620 | @@ -XXX,XX +XXX,XX @@ void *job_create(const char *job_id, const JobDriver *driver, JobTxn *txn, | ||
621 | error_setg(errp, "Invalid job ID '%s'", job_id); | ||
622 | return NULL; | ||
623 | } | ||
624 | - if (job_get(job_id)) { | ||
625 | + if (job_get_locked(job_id)) { | ||
626 | error_setg(errp, "Job ID '%s' already in use", job_id); | ||
627 | return NULL; | ||
628 | } | ||
629 | @@ -XXX,XX +XXX,XX @@ void *job_create(const char *job_id, const JobDriver *driver, JobTxn *txn, | ||
630 | notifier_list_init(&job->on_ready); | ||
631 | notifier_list_init(&job->on_idle); | ||
632 | |||
633 | - job_state_transition(job, JOB_STATUS_CREATED); | ||
634 | + job_state_transition_locked(job, JOB_STATUS_CREATED); | ||
635 | aio_timer_init(qemu_get_aio_context(), &job->sleep_timer, | ||
636 | QEMU_CLOCK_REALTIME, SCALE_NS, | ||
637 | job_sleep_timer_cb, job); | ||
638 | @@ -XXX,XX +XXX,XX @@ void *job_create(const char *job_id, const JobDriver *driver, JobTxn *txn, | ||
639 | * consolidating the job management logic */ | ||
640 | if (!txn) { | ||
641 | txn = job_txn_new(); | ||
642 | - job_txn_add_job(txn, job); | ||
643 | - job_txn_unref(txn); | ||
644 | + job_txn_add_job_locked(txn, job); | ||
645 | + job_txn_unref_locked(txn); | ||
646 | } else { | ||
647 | - job_txn_add_job(txn, job); | ||
648 | + job_txn_add_job_locked(txn, job); | ||
649 | } | ||
650 | |||
651 | return job; | ||
652 | } | ||
653 | |||
654 | -void job_ref(Job *job) | ||
655 | +void job_ref_locked(Job *job) | ||
656 | { | ||
657 | ++job->refcnt; | ||
658 | } | ||
659 | |||
660 | -void job_unref(Job *job) | ||
661 | +void job_ref(Job *job) | ||
662 | +{ | ||
663 | + JOB_LOCK_GUARD(); | ||
664 | + job_ref_locked(job); | ||
665 | +} | ||
666 | + | ||
667 | +void job_unref_locked(Job *job) | ||
668 | { | ||
669 | GLOBAL_STATE_CODE(); | ||
670 | |||
671 | @@ -XXX,XX +XXX,XX @@ void job_unref(Job *job) | ||
672 | assert(!job->txn); | ||
673 | |||
674 | if (job->driver->free) { | ||
675 | + job_unlock(); | ||
676 | job->driver->free(job); | ||
677 | + job_lock(); | ||
678 | } | ||
679 | |||
680 | QLIST_REMOVE(job, job_list); | ||
681 | @@ -XXX,XX +XXX,XX @@ void job_unref(Job *job) | ||
682 | } | ||
683 | } | ||
684 | |||
685 | +void job_unref(Job *job) | ||
686 | +{ | ||
687 | + JOB_LOCK_GUARD(); | ||
688 | + job_unref_locked(job); | ||
689 | +} | ||
690 | + | ||
691 | void job_progress_update(Job *job, uint64_t done) | ||
692 | { | ||
693 | progress_work_done(&job->progress, done); | ||
694 | @@ -XXX,XX +XXX,XX @@ void job_progress_increase_remaining(Job *job, uint64_t delta) | ||
695 | |||
696 | /** | ||
697 | * To be called when a cancelled job is finalised. | ||
698 | + * Called with job_mutex held. | ||
699 | */ | ||
700 | -static void job_event_cancelled(Job *job) | ||
701 | +static void job_event_cancelled_locked(Job *job) | ||
702 | { | ||
703 | notifier_list_notify(&job->on_finalize_cancelled, job); | ||
704 | } | ||
705 | |||
706 | /** | ||
707 | * To be called when a successfully completed job is finalised. | ||
708 | + * Called with job_mutex held. | ||
709 | */ | ||
710 | -static void job_event_completed(Job *job) | ||
711 | +static void job_event_completed_locked(Job *job) | ||
712 | { | ||
713 | notifier_list_notify(&job->on_finalize_completed, job); | ||
714 | } | ||
715 | |||
716 | -static void job_event_pending(Job *job) | ||
717 | +/* Called with job_mutex held. */ | ||
718 | +static void job_event_pending_locked(Job *job) | ||
719 | { | ||
720 | notifier_list_notify(&job->on_pending, job); | ||
721 | } | ||
722 | |||
723 | -static void job_event_ready(Job *job) | ||
724 | +/* Called with job_mutex held. */ | ||
725 | +static void job_event_ready_locked(Job *job) | ||
726 | { | ||
727 | notifier_list_notify(&job->on_ready, job); | ||
728 | } | ||
729 | |||
730 | -static void job_event_idle(Job *job) | ||
731 | +/* Called with job_mutex held. */ | ||
732 | +static void job_event_idle_locked(Job *job) | ||
733 | { | ||
734 | notifier_list_notify(&job->on_idle, job); | ||
735 | } | ||
736 | |||
737 | -void job_enter_cond(Job *job, bool(*fn)(Job *job)) | ||
738 | +void job_enter_cond_locked(Job *job, bool(*fn)(Job *job)) | ||
739 | { | ||
740 | - if (!job_started(job)) { | ||
741 | + if (!job_started_locked(job)) { | ||
742 | return; | ||
743 | } | ||
744 | if (job->deferred_to_main_loop) { | ||
745 | @@ -XXX,XX +XXX,XX @@ void job_enter_cond(Job *job, bool(*fn)(Job *job)) | ||
746 | timer_del(&job->sleep_timer); | ||
747 | job->busy = true; | ||
748 | real_job_unlock(); | ||
749 | + job_unlock(); | ||
750 | aio_co_enter(job->aio_context, job->co); | ||
751 | + job_lock(); | ||
752 | +} | ||
753 | + | ||
754 | +void job_enter_cond(Job *job, bool(*fn)(Job *job)) | ||
755 | +{ | ||
756 | + JOB_LOCK_GUARD(); | ||
757 | + job_enter_cond_locked(job, fn); | ||
758 | } | ||
759 | |||
760 | void job_enter(Job *job) | ||
761 | { | ||
762 | - job_enter_cond(job, NULL); | ||
763 | + JOB_LOCK_GUARD(); | ||
764 | + job_enter_cond_locked(job, NULL); | ||
765 | } | ||
766 | |||
767 | /* Yield, and schedule a timer to reenter the coroutine after @ns nanoseconds. | ||
768 | @@ -XXX,XX +XXX,XX @@ void job_enter(Job *job) | ||
769 | * is allowed and cancels the timer. | ||
770 | * | ||
771 | * If @ns is (uint64_t) -1, no timer is scheduled and job_enter() must be | ||
772 | - * called explicitly. */ | ||
773 | -static void coroutine_fn job_do_yield(Job *job, uint64_t ns) | ||
774 | + * called explicitly. | ||
775 | + * | ||
776 | + * Called with job_mutex held, but releases it temporarily. | ||
777 | + */ | ||
778 | +static void coroutine_fn job_do_yield_locked(Job *job, uint64_t ns) | ||
779 | { | ||
780 | real_job_lock(); | ||
781 | if (ns != -1) { | ||
782 | timer_mod(&job->sleep_timer, ns); | ||
783 | } | ||
784 | job->busy = false; | ||
785 | - job_event_idle(job); | ||
786 | + job_event_idle_locked(job); | ||
787 | real_job_unlock(); | ||
788 | + job_unlock(); | ||
789 | qemu_coroutine_yield(); | ||
790 | + job_lock(); | ||
791 | |||
792 | /* Set by job_enter_cond() before re-entering the coroutine. */ | ||
793 | assert(job->busy); | ||
794 | } | ||
795 | |||
796 | -void coroutine_fn job_pause_point(Job *job) | ||
797 | +/* Called with job_mutex held, but releases it temporarily. */ | ||
798 | +static void coroutine_fn job_pause_point_locked(Job *job) | ||
799 | { | ||
800 | - assert(job && job_started(job)); | ||
801 | + assert(job && job_started_locked(job)); | ||
802 | |||
803 | - if (!job_should_pause(job)) { | ||
804 | + if (!job_should_pause_locked(job)) { | ||
805 | return; | ||
806 | } | ||
807 | - if (job_is_cancelled(job)) { | ||
808 | + if (job_is_cancelled_locked(job)) { | ||
809 | return; | ||
810 | } | ||
811 | |||
812 | if (job->driver->pause) { | ||
813 | + job_unlock(); | ||
814 | job->driver->pause(job); | ||
815 | + job_lock(); | ||
816 | } | ||
817 | |||
818 | - if (job_should_pause(job) && !job_is_cancelled(job)) { | ||
819 | + if (job_should_pause_locked(job) && !job_is_cancelled_locked(job)) { | ||
820 | JobStatus status = job->status; | ||
821 | - job_state_transition(job, status == JOB_STATUS_READY | ||
822 | - ? JOB_STATUS_STANDBY | ||
823 | - : JOB_STATUS_PAUSED); | ||
824 | + job_state_transition_locked(job, status == JOB_STATUS_READY | ||
825 | + ? JOB_STATUS_STANDBY | ||
826 | + : JOB_STATUS_PAUSED); | ||
827 | job->paused = true; | ||
828 | - job_do_yield(job, -1); | ||
829 | + job_do_yield_locked(job, -1); | ||
830 | job->paused = false; | ||
831 | - job_state_transition(job, status); | ||
832 | + job_state_transition_locked(job, status); | ||
833 | } | ||
834 | |||
835 | if (job->driver->resume) { | ||
836 | + job_unlock(); | ||
837 | job->driver->resume(job); | ||
838 | + job_lock(); | ||
839 | } | ||
840 | } | ||
841 | |||
842 | -void coroutine_fn job_yield(Job *job) | ||
843 | +void coroutine_fn job_pause_point(Job *job) | ||
844 | +{ | ||
845 | + JOB_LOCK_GUARD(); | ||
846 | + job_pause_point_locked(job); | ||
847 | +} | ||
848 | + | ||
849 | +static void coroutine_fn job_yield_locked(Job *job) | ||
850 | { | ||
851 | assert(job->busy); | ||
852 | |||
853 | /* Check cancellation *before* setting busy = false, too! */ | ||
854 | - if (job_is_cancelled(job)) { | ||
855 | + if (job_is_cancelled_locked(job)) { | ||
856 | return; | ||
857 | } | ||
858 | |||
859 | - if (!job_should_pause(job)) { | ||
860 | - job_do_yield(job, -1); | ||
861 | + if (!job_should_pause_locked(job)) { | ||
862 | + job_do_yield_locked(job, -1); | ||
863 | } | ||
864 | |||
865 | - job_pause_point(job); | ||
866 | + job_pause_point_locked(job); | ||
867 | +} | ||
868 | + | ||
869 | +void coroutine_fn job_yield(Job *job) | ||
870 | +{ | ||
871 | + JOB_LOCK_GUARD(); | ||
872 | + job_yield_locked(job); | ||
873 | } | ||
874 | |||
875 | void coroutine_fn job_sleep_ns(Job *job, int64_t ns) | ||
876 | { | ||
877 | + JOB_LOCK_GUARD(); | ||
878 | assert(job->busy); | ||
879 | |||
880 | /* Check cancellation *before* setting busy = false, too! */ | ||
881 | - if (job_is_cancelled(job)) { | ||
882 | + if (job_is_cancelled_locked(job)) { | ||
883 | return; | ||
884 | } | ||
885 | |||
886 | - if (!job_should_pause(job)) { | ||
887 | - job_do_yield(job, qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + ns); | ||
888 | + if (!job_should_pause_locked(job)) { | ||
889 | + job_do_yield_locked(job, qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + ns); | ||
890 | } | ||
891 | |||
892 | - job_pause_point(job); | ||
893 | + job_pause_point_locked(job); | ||
894 | } | ||
895 | |||
896 | -/* Assumes the block_job_mutex is held */ | ||
897 | -static bool job_timer_not_pending(Job *job) | ||
898 | +/* Assumes the job_mutex is held */ | ||
899 | +static bool job_timer_not_pending_locked(Job *job) | ||
900 | { | ||
901 | return !timer_pending(&job->sleep_timer); | ||
902 | } | ||
903 | |||
904 | -void job_pause(Job *job) | ||
905 | +void job_pause_locked(Job *job) | ||
906 | { | ||
907 | job->pause_count++; | ||
908 | if (!job->paused) { | ||
909 | - job_enter(job); | ||
910 | + job_enter_cond_locked(job, NULL); | ||
911 | } | ||
912 | } | ||
913 | |||
914 | -void job_resume(Job *job) | ||
915 | +void job_pause(Job *job) | ||
916 | +{ | ||
917 | + JOB_LOCK_GUARD(); | ||
918 | + job_pause_locked(job); | ||
919 | +} | ||
920 | + | ||
921 | +void job_resume_locked(Job *job) | ||
922 | { | ||
923 | assert(job->pause_count > 0); | ||
924 | job->pause_count--; | ||
925 | @@ -XXX,XX +XXX,XX @@ void job_resume(Job *job) | ||
926 | } | ||
927 | |||
928 | /* kick only if no timer is pending */ | ||
929 | - job_enter_cond(job, job_timer_not_pending); | ||
930 | + job_enter_cond_locked(job, job_timer_not_pending_locked); | ||
931 | } | ||
932 | |||
933 | -void job_user_pause(Job *job, Error **errp) | ||
934 | +void job_resume(Job *job) | ||
935 | { | ||
936 | - if (job_apply_verb(job, JOB_VERB_PAUSE, errp)) { | ||
937 | + JOB_LOCK_GUARD(); | ||
938 | + job_resume_locked(job); | ||
939 | +} | ||
940 | + | ||
941 | +void job_user_pause_locked(Job *job, Error **errp) | ||
942 | +{ | ||
943 | + if (job_apply_verb_locked(job, JOB_VERB_PAUSE, errp)) { | ||
944 | return; | ||
945 | } | ||
946 | if (job->user_paused) { | ||
947 | @@ -XXX,XX +XXX,XX @@ void job_user_pause(Job *job, Error **errp) | ||
948 | return; | ||
949 | } | ||
950 | job->user_paused = true; | ||
951 | - job_pause(job); | ||
952 | + job_pause_locked(job); | ||
953 | } | ||
954 | |||
955 | -bool job_user_paused(Job *job) | ||
956 | +void job_user_pause(Job *job, Error **errp) | ||
957 | +{ | ||
958 | + JOB_LOCK_GUARD(); | ||
959 | + job_user_pause_locked(job, errp); | ||
960 | +} | ||
961 | + | ||
962 | +bool job_user_paused_locked(Job *job) | ||
963 | { | ||
964 | return job->user_paused; | ||
965 | } | ||
966 | |||
967 | -void job_user_resume(Job *job, Error **errp) | ||
968 | +bool job_user_paused(Job *job) | ||
969 | +{ | ||
970 | + JOB_LOCK_GUARD(); | ||
971 | + return job_user_paused_locked(job); | ||
972 | +} | ||
973 | + | ||
974 | +void job_user_resume_locked(Job *job, Error **errp) | ||
975 | { | ||
976 | assert(job); | ||
977 | GLOBAL_STATE_CODE(); | ||
978 | @@ -XXX,XX +XXX,XX @@ void job_user_resume(Job *job, Error **errp) | ||
979 | error_setg(errp, "Can't resume a job that was not paused"); | ||
980 | return; | ||
981 | } | ||
982 | - if (job_apply_verb(job, JOB_VERB_RESUME, errp)) { | ||
983 | + if (job_apply_verb_locked(job, JOB_VERB_RESUME, errp)) { | ||
984 | return; | ||
985 | } | ||
986 | if (job->driver->user_resume) { | ||
987 | + job_unlock(); | ||
988 | job->driver->user_resume(job); | ||
989 | + job_lock(); | ||
990 | } | ||
991 | job->user_paused = false; | ||
992 | - job_resume(job); | ||
993 | + job_resume_locked(job); | ||
994 | } | ||
995 | |||
996 | -static void job_do_dismiss(Job *job) | ||
997 | +void job_user_resume(Job *job, Error **errp) | ||
998 | +{ | ||
999 | + JOB_LOCK_GUARD(); | ||
1000 | + job_user_resume_locked(job, errp); | ||
1001 | +} | ||
1002 | + | ||
1003 | +/* Called with job_mutex held, but releases it temporarily. */ | ||
1004 | +static void job_do_dismiss_locked(Job *job) | ||
1005 | { | ||
1006 | assert(job); | ||
1007 | job->busy = false; | ||
1008 | job->paused = false; | ||
1009 | job->deferred_to_main_loop = true; | ||
1010 | |||
1011 | - job_txn_del_job(job); | ||
1012 | + job_txn_del_job_locked(job); | ||
1013 | |||
1014 | - job_state_transition(job, JOB_STATUS_NULL); | ||
1015 | - job_unref(job); | ||
1016 | + job_state_transition_locked(job, JOB_STATUS_NULL); | ||
1017 | + job_unref_locked(job); | ||
1018 | } | ||
1019 | |||
1020 | -void job_dismiss(Job **jobptr, Error **errp) | ||
1021 | +void job_dismiss_locked(Job **jobptr, Error **errp) | ||
1022 | { | ||
1023 | Job *job = *jobptr; | ||
1024 | /* similarly to _complete, this is QMP-interface only. */ | ||
1025 | assert(job->id); | ||
1026 | - if (job_apply_verb(job, JOB_VERB_DISMISS, errp)) { | ||
1027 | + if (job_apply_verb_locked(job, JOB_VERB_DISMISS, errp)) { | ||
1028 | return; | ||
1029 | } | ||
1030 | |||
1031 | - job_do_dismiss(job); | ||
1032 | + job_do_dismiss_locked(job); | ||
1033 | *jobptr = NULL; | ||
1034 | } | ||
1035 | |||
1036 | +void job_dismiss(Job **jobptr, Error **errp) | ||
1037 | +{ | ||
1038 | + JOB_LOCK_GUARD(); | ||
1039 | + job_dismiss_locked(jobptr, errp); | ||
1040 | +} | ||
1041 | + | ||
1042 | void job_early_fail(Job *job) | ||
1043 | { | ||
1044 | + JOB_LOCK_GUARD(); | ||
1045 | assert(job->status == JOB_STATUS_CREATED); | ||
1046 | - job_do_dismiss(job); | ||
1047 | + job_do_dismiss_locked(job); | ||
1048 | } | ||
1049 | |||
1050 | -static void job_conclude(Job *job) | ||
1051 | +/* Called with job_mutex held. */ | ||
1052 | +static void job_conclude_locked(Job *job) | ||
1053 | { | ||
1054 | - job_state_transition(job, JOB_STATUS_CONCLUDED); | ||
1055 | - if (job->auto_dismiss || !job_started(job)) { | ||
1056 | - job_do_dismiss(job); | ||
1057 | + job_state_transition_locked(job, JOB_STATUS_CONCLUDED); | ||
1058 | + if (job->auto_dismiss || !job_started_locked(job)) { | ||
1059 | + job_do_dismiss_locked(job); | ||
1060 | } | ||
1061 | } | ||
1062 | |||
1063 | -static void job_update_rc(Job *job) | ||
1064 | +/* Called with job_mutex held. */ | ||
1065 | +static void job_update_rc_locked(Job *job) | ||
1066 | { | ||
1067 | - if (!job->ret && job_is_cancelled(job)) { | ||
1068 | + if (!job->ret && job_is_cancelled_locked(job)) { | ||
1069 | job->ret = -ECANCELED; | ||
1070 | } | ||
1071 | if (job->ret) { | ||
1072 | if (!job->err) { | ||
1073 | error_setg(&job->err, "%s", strerror(-job->ret)); | ||
1074 | } | ||
1075 | - job_state_transition(job, JOB_STATUS_ABORTING); | ||
1076 | + job_state_transition_locked(job, JOB_STATUS_ABORTING); | ||
1077 | } | ||
1078 | } | ||
1079 | |||
1080 | @@ -XXX,XX +XXX,XX @@ static void job_clean(Job *job) | ||
1081 | } | ||
1082 | } | ||
1083 | |||
1084 | -static int job_finalize_single(Job *job) | ||
1085 | +/* Called with job_mutex held, but releases it temporarily */ | ||
1086 | +static int job_finalize_single_locked(Job *job) | ||
1087 | { | ||
1088 | - assert(job_is_completed(job)); | ||
1089 | + int job_ret; | ||
1090 | + | ||
1091 | + assert(job_is_completed_locked(job)); | ||
1092 | |||
1093 | /* Ensure abort is called for late-transactional failures */ | ||
1094 | - job_update_rc(job); | ||
1095 | + job_update_rc_locked(job); | ||
1096 | + | ||
1097 | + job_ret = job->ret; | ||
1098 | + job_unlock(); | ||
1099 | |||
1100 | - if (!job->ret) { | ||
1101 | + if (!job_ret) { | ||
1102 | job_commit(job); | ||
1103 | } else { | ||
1104 | job_abort(job); | ||
1105 | } | ||
1106 | job_clean(job); | ||
1107 | |||
1108 | + job_lock(); | ||
1109 | + | ||
1110 | if (job->cb) { | ||
1111 | - job->cb(job->opaque, job->ret); | ||
1112 | + job_ret = job->ret; | ||
1113 | + job_unlock(); | ||
1114 | + job->cb(job->opaque, job_ret); | ||
1115 | + job_lock(); | ||
1116 | } | ||
1117 | |||
1118 | /* Emit events only if we actually started */ | ||
1119 | - if (job_started(job)) { | ||
1120 | - if (job_is_cancelled(job)) { | ||
1121 | - job_event_cancelled(job); | ||
1122 | + if (job_started_locked(job)) { | ||
1123 | + if (job_is_cancelled_locked(job)) { | ||
1124 | + job_event_cancelled_locked(job); | ||
1125 | } else { | ||
1126 | - job_event_completed(job); | ||
1127 | + job_event_completed_locked(job); | ||
1128 | } | ||
1129 | } | ||
1130 | |||
1131 | - job_txn_del_job(job); | ||
1132 | - job_conclude(job); | ||
1133 | + job_txn_del_job_locked(job); | ||
1134 | + job_conclude_locked(job); | ||
1135 | return 0; | ||
1136 | } | ||
1137 | |||
1138 | -static void job_cancel_async(Job *job, bool force) | ||
1139 | +/* Called with job_mutex held, but releases it temporarily */ | ||
1140 | +static void job_cancel_async_locked(Job *job, bool force) | ||
1141 | { | ||
1142 | GLOBAL_STATE_CODE(); | ||
1143 | if (job->driver->cancel) { | ||
1144 | + job_unlock(); | ||
1145 | force = job->driver->cancel(job, force); | ||
1146 | + job_lock(); | ||
1147 | } else { | ||
1148 | /* No .cancel() means the job will behave as if force-cancelled */ | ||
1149 | force = true; | ||
1150 | @@ -XXX,XX +XXX,XX @@ static void job_cancel_async(Job *job, bool force) | ||
1151 | if (job->user_paused) { | ||
1152 | /* Do not call job_enter here, the caller will handle it. */ | ||
1153 | if (job->driver->user_resume) { | ||
1154 | + job_unlock(); | ||
1155 | job->driver->user_resume(job); | ||
1156 | + job_lock(); | ||
1157 | } | ||
1158 | job->user_paused = false; | ||
1159 | assert(job->pause_count > 0); | ||
1160 | @@ -XXX,XX +XXX,XX @@ static void job_cancel_async(Job *job, bool force) | ||
1161 | } | ||
1162 | } | ||
1163 | |||
1164 | -static void job_completed_txn_abort(Job *job) | ||
1165 | +/* Called with job_mutex held, but releases it temporarily. */ | ||
1166 | +static void job_completed_txn_abort_locked(Job *job) | ||
1167 | { | ||
1168 | AioContext *ctx; | ||
1169 | JobTxn *txn = job->txn; | ||
1170 | @@ -XXX,XX +XXX,XX @@ static void job_completed_txn_abort(Job *job) | ||
1171 | return; | ||
1172 | } | ||
1173 | txn->aborting = true; | ||
1174 | - job_txn_ref(txn); | ||
1175 | + job_txn_ref_locked(txn); | ||
1176 | |||
1177 | /* | ||
1178 | * We can only hold the single job's AioContext lock while calling | ||
1179 | @@ -XXX,XX +XXX,XX @@ static void job_completed_txn_abort(Job *job) | ||
1180 | * calls of AIO_WAIT_WHILE(), which could deadlock otherwise. | ||
1181 | * Note that the job's AioContext may change when it is finalized. | ||
1182 | */ | ||
1183 | - job_ref(job); | ||
1184 | + job_ref_locked(job); | ||
1185 | aio_context_release(job->aio_context); | ||
1186 | |||
1187 | /* Other jobs are effectively cancelled by us, set the status for | ||
1188 | @@ -XXX,XX +XXX,XX @@ static void job_completed_txn_abort(Job *job) | ||
1189 | * Therefore, pass force=true to terminate all other jobs as quickly | ||
1190 | * as possible. | ||
1191 | */ | ||
1192 | - job_cancel_async(other_job, true); | ||
1193 | + job_cancel_async_locked(other_job, true); | ||
1194 | aio_context_release(ctx); | ||
1195 | } | ||
1196 | } | ||
1197 | @@ -XXX,XX +XXX,XX @@ static void job_completed_txn_abort(Job *job) | ||
1198 | */ | ||
1199 | ctx = other_job->aio_context; | ||
1200 | aio_context_acquire(ctx); | ||
1201 | - if (!job_is_completed(other_job)) { | ||
1202 | - assert(job_cancel_requested(other_job)); | ||
1203 | - job_finish_sync(other_job, NULL, NULL); | ||
1204 | + if (!job_is_completed_locked(other_job)) { | ||
1205 | + assert(job_cancel_requested_locked(other_job)); | ||
1206 | + job_finish_sync_locked(other_job, NULL, NULL); | ||
1207 | } | ||
1208 | - job_finalize_single(other_job); | ||
1209 | + job_finalize_single_locked(other_job); | ||
1210 | aio_context_release(ctx); | ||
1211 | } | ||
1212 | |||
1213 | @@ -XXX,XX +XXX,XX @@ static void job_completed_txn_abort(Job *job) | ||
1214 | * even if the job went away during job_finalize_single(). | ||
1215 | */ | ||
1216 | aio_context_acquire(job->aio_context); | ||
1217 | - job_unref(job); | ||
1218 | + job_unref_locked(job); | ||
1219 | |||
1220 | - job_txn_unref(txn); | ||
1221 | + job_txn_unref_locked(txn); | ||
1222 | } | ||
1223 | |||
1224 | -static int job_prepare(Job *job) | ||
1225 | +/* Called with job_mutex held, but releases it temporarily */ | ||
1226 | +static int job_prepare_locked(Job *job) | ||
1227 | { | ||
44 | + int ret; | 1228 | + int ret; |
45 | + | 1229 | + |
46 | + assert(c->perm & (BLK_PERM_WRITE | BLK_PERM_WRITE_UNCHANGED)); | 1230 | GLOBAL_STATE_CODE(); |
47 | + | 1231 | if (job->ret == 0 && job->driver->prepare) { |
48 | + if (!drv->bdrv_make_empty) { | 1232 | - job->ret = job->driver->prepare(job); |
49 | + error_setg(errp, "%s does not support emptying nodes", | 1233 | - job_update_rc(job); |
50 | + drv->format_name); | 1234 | + job_unlock(); |
51 | + return -ENOTSUP; | 1235 | + ret = job->driver->prepare(job); |
1236 | + job_lock(); | ||
1237 | + job->ret = ret; | ||
1238 | + job_update_rc_locked(job); | ||
1239 | } | ||
1240 | return job->ret; | ||
1241 | } | ||
1242 | |||
1243 | -static int job_needs_finalize(Job *job) | ||
1244 | +/* Called with job_mutex held */ | ||
1245 | +static int job_needs_finalize_locked(Job *job) | ||
1246 | { | ||
1247 | return !job->auto_finalize; | ||
1248 | } | ||
1249 | |||
1250 | -static void job_do_finalize(Job *job) | ||
1251 | +/* Called with job_mutex held */ | ||
1252 | +static void job_do_finalize_locked(Job *job) | ||
1253 | { | ||
1254 | int rc; | ||
1255 | assert(job && job->txn); | ||
1256 | |||
1257 | /* prepare the transaction to complete */ | ||
1258 | - rc = job_txn_apply(job, job_prepare); | ||
1259 | + rc = job_txn_apply_locked(job, job_prepare_locked); | ||
1260 | if (rc) { | ||
1261 | - job_completed_txn_abort(job); | ||
1262 | + job_completed_txn_abort_locked(job); | ||
1263 | } else { | ||
1264 | - job_txn_apply(job, job_finalize_single); | ||
1265 | + job_txn_apply_locked(job, job_finalize_single_locked); | ||
1266 | } | ||
1267 | } | ||
1268 | |||
1269 | -void job_finalize(Job *job, Error **errp) | ||
1270 | +void job_finalize_locked(Job *job, Error **errp) | ||
1271 | { | ||
1272 | assert(job && job->id); | ||
1273 | - if (job_apply_verb(job, JOB_VERB_FINALIZE, errp)) { | ||
1274 | + if (job_apply_verb_locked(job, JOB_VERB_FINALIZE, errp)) { | ||
1275 | return; | ||
1276 | } | ||
1277 | - job_do_finalize(job); | ||
1278 | + job_do_finalize_locked(job); | ||
1279 | } | ||
1280 | |||
1281 | -static int job_transition_to_pending(Job *job) | ||
1282 | +void job_finalize(Job *job, Error **errp) | ||
1283 | { | ||
1284 | - job_state_transition(job, JOB_STATUS_PENDING); | ||
1285 | + JOB_LOCK_GUARD(); | ||
1286 | + job_finalize_locked(job, errp); | ||
1287 | +} | ||
1288 | + | ||
1289 | +/* Called with job_mutex held. */ | ||
1290 | +static int job_transition_to_pending_locked(Job *job) | ||
1291 | +{ | ||
1292 | + job_state_transition_locked(job, JOB_STATUS_PENDING); | ||
1293 | if (!job->auto_finalize) { | ||
1294 | - job_event_pending(job); | ||
1295 | + job_event_pending_locked(job); | ||
1296 | } | ||
1297 | return 0; | ||
1298 | } | ||
1299 | |||
1300 | void job_transition_to_ready(Job *job) | ||
1301 | { | ||
1302 | - job_state_transition(job, JOB_STATUS_READY); | ||
1303 | - job_event_ready(job); | ||
1304 | + JOB_LOCK_GUARD(); | ||
1305 | + job_state_transition_locked(job, JOB_STATUS_READY); | ||
1306 | + job_event_ready_locked(job); | ||
1307 | } | ||
1308 | |||
1309 | -static void job_completed_txn_success(Job *job) | ||
1310 | +/* Called with job_mutex held. */ | ||
1311 | +static void job_completed_txn_success_locked(Job *job) | ||
1312 | { | ||
1313 | JobTxn *txn = job->txn; | ||
1314 | Job *other_job; | ||
1315 | |||
1316 | - job_state_transition(job, JOB_STATUS_WAITING); | ||
1317 | + job_state_transition_locked(job, JOB_STATUS_WAITING); | ||
1318 | |||
1319 | /* | ||
1320 | * Successful completion, see if there are other running jobs in this | ||
1321 | * txn. | ||
1322 | */ | ||
1323 | QLIST_FOREACH(other_job, &txn->jobs, txn_list) { | ||
1324 | - if (!job_is_completed(other_job)) { | ||
1325 | + if (!job_is_completed_locked(other_job)) { | ||
1326 | return; | ||
1327 | } | ||
1328 | assert(other_job->ret == 0); | ||
1329 | } | ||
1330 | |||
1331 | - job_txn_apply(job, job_transition_to_pending); | ||
1332 | + job_txn_apply_locked(job, job_transition_to_pending_locked); | ||
1333 | |||
1334 | /* If no jobs need manual finalization, automatically do so */ | ||
1335 | - if (job_txn_apply(job, job_needs_finalize) == 0) { | ||
1336 | - job_do_finalize(job); | ||
1337 | + if (job_txn_apply_locked(job, job_needs_finalize_locked) == 0) { | ||
1338 | + job_do_finalize_locked(job); | ||
1339 | } | ||
1340 | } | ||
1341 | |||
1342 | -static void job_completed(Job *job) | ||
1343 | +/* Called with job_mutex held. */ | ||
1344 | +static void job_completed_locked(Job *job) | ||
1345 | { | ||
1346 | - assert(job && job->txn && !job_is_completed(job)); | ||
1347 | + assert(job && job->txn && !job_is_completed_locked(job)); | ||
1348 | |||
1349 | - job_update_rc(job); | ||
1350 | + job_update_rc_locked(job); | ||
1351 | trace_job_completed(job, job->ret); | ||
1352 | if (job->ret) { | ||
1353 | - job_completed_txn_abort(job); | ||
1354 | + job_completed_txn_abort_locked(job); | ||
1355 | } else { | ||
1356 | - job_completed_txn_success(job); | ||
1357 | + job_completed_txn_success_locked(job); | ||
1358 | } | ||
1359 | } | ||
1360 | |||
1361 | -/** Useful only as a type shim for aio_bh_schedule_oneshot. */ | ||
1362 | +/** | ||
1363 | + * Useful only as a type shim for aio_bh_schedule_oneshot. | ||
1364 | + * Called with job_mutex *not* held. | ||
1365 | + */ | ||
1366 | static void job_exit(void *opaque) | ||
1367 | { | ||
1368 | Job *job = (Job *)opaque; | ||
1369 | AioContext *ctx; | ||
1370 | + JOB_LOCK_GUARD(); | ||
1371 | |||
1372 | - job_ref(job); | ||
1373 | + job_ref_locked(job); | ||
1374 | aio_context_acquire(job->aio_context); | ||
1375 | |||
1376 | /* This is a lie, we're not quiescent, but still doing the completion | ||
1377 | @@ -XXX,XX +XXX,XX @@ static void job_exit(void *opaque) | ||
1378 | * drain block nodes, and if .drained_poll still returned true, we would | ||
1379 | * deadlock. */ | ||
1380 | job->busy = false; | ||
1381 | - job_event_idle(job); | ||
1382 | + job_event_idle_locked(job); | ||
1383 | |||
1384 | - job_completed(job); | ||
1385 | + job_completed_locked(job); | ||
1386 | |||
1387 | /* | ||
1388 | * Note that calling job_completed can move the job to a different | ||
1389 | @@ -XXX,XX +XXX,XX @@ static void job_exit(void *opaque) | ||
1390 | * the job underneath us. | ||
1391 | */ | ||
1392 | ctx = job->aio_context; | ||
1393 | - job_unref(job); | ||
1394 | + job_unref_locked(job); | ||
1395 | aio_context_release(ctx); | ||
1396 | } | ||
1397 | |||
1398 | @@ -XXX,XX +XXX,XX @@ static void job_exit(void *opaque) | ||
1399 | static void coroutine_fn job_co_entry(void *opaque) | ||
1400 | { | ||
1401 | Job *job = opaque; | ||
1402 | + int ret; | ||
1403 | |||
1404 | assert(job && job->driver && job->driver->run); | ||
1405 | - assert(job->aio_context == qemu_get_current_aio_context()); | ||
1406 | - job_pause_point(job); | ||
1407 | - job->ret = job->driver->run(job, &job->err); | ||
1408 | - job->deferred_to_main_loop = true; | ||
1409 | - job->busy = true; | ||
1410 | + WITH_JOB_LOCK_GUARD() { | ||
1411 | + assert(job->aio_context == qemu_get_current_aio_context()); | ||
1412 | + job_pause_point_locked(job); | ||
52 | + } | 1413 | + } |
53 | + | 1414 | + ret = job->driver->run(job, &job->err); |
54 | + ret = drv->bdrv_make_empty(c->bs); | 1415 | + WITH_JOB_LOCK_GUARD() { |
55 | + if (ret < 0) { | 1416 | + job->ret = ret; |
56 | + error_setg_errno(errp, -ret, "Failed to empty %s", | 1417 | + job->deferred_to_main_loop = true; |
57 | + c->bs->filename); | 1418 | + job->busy = true; |
58 | + return ret; | ||
59 | + } | 1419 | + } |
60 | + | 1420 | aio_bh_schedule_oneshot(qemu_get_aio_context(), job_exit, job); |
61 | + return 0; | 1421 | } |
1422 | |||
1423 | void job_start(Job *job) | ||
1424 | { | ||
1425 | - assert(job && !job_started(job) && job->paused && | ||
1426 | - job->driver && job->driver->run); | ||
1427 | - job->co = qemu_coroutine_create(job_co_entry, job); | ||
1428 | - job->pause_count--; | ||
1429 | - job->busy = true; | ||
1430 | - job->paused = false; | ||
1431 | - job_state_transition(job, JOB_STATUS_RUNNING); | ||
1432 | + assert(qemu_in_main_thread()); | ||
1433 | + | ||
1434 | + WITH_JOB_LOCK_GUARD() { | ||
1435 | + assert(job && !job_started_locked(job) && job->paused && | ||
1436 | + job->driver && job->driver->run); | ||
1437 | + job->co = qemu_coroutine_create(job_co_entry, job); | ||
1438 | + job->pause_count--; | ||
1439 | + job->busy = true; | ||
1440 | + job->paused = false; | ||
1441 | + job_state_transition_locked(job, JOB_STATUS_RUNNING); | ||
1442 | + } | ||
1443 | aio_co_enter(job->aio_context, job->co); | ||
1444 | } | ||
1445 | |||
1446 | -void job_cancel(Job *job, bool force) | ||
1447 | +void job_cancel_locked(Job *job, bool force) | ||
1448 | { | ||
1449 | if (job->status == JOB_STATUS_CONCLUDED) { | ||
1450 | - job_do_dismiss(job); | ||
1451 | + job_do_dismiss_locked(job); | ||
1452 | return; | ||
1453 | } | ||
1454 | - job_cancel_async(job, force); | ||
1455 | - if (!job_started(job)) { | ||
1456 | - job_completed(job); | ||
1457 | + job_cancel_async_locked(job, force); | ||
1458 | + if (!job_started_locked(job)) { | ||
1459 | + job_completed_locked(job); | ||
1460 | } else if (job->deferred_to_main_loop) { | ||
1461 | /* | ||
1462 | * job_cancel_async() ignores soft-cancel requests for jobs | ||
1463 | @@ -XXX,XX +XXX,XX @@ void job_cancel(Job *job, bool force) | ||
1464 | * choose to call job_is_cancelled() to show that we invoke | ||
1465 | * job_completed_txn_abort() only for force-cancelled jobs.) | ||
1466 | */ | ||
1467 | - if (job_is_cancelled(job)) { | ||
1468 | - job_completed_txn_abort(job); | ||
1469 | + if (job_is_cancelled_locked(job)) { | ||
1470 | + job_completed_txn_abort_locked(job); | ||
1471 | } | ||
1472 | } else { | ||
1473 | - job_enter(job); | ||
1474 | + job_enter_cond_locked(job, NULL); | ||
1475 | } | ||
1476 | } | ||
1477 | |||
1478 | -void job_user_cancel(Job *job, bool force, Error **errp) | ||
1479 | +void job_cancel(Job *job, bool force) | ||
1480 | { | ||
1481 | - if (job_apply_verb(job, JOB_VERB_CANCEL, errp)) { | ||
1482 | + JOB_LOCK_GUARD(); | ||
1483 | + job_cancel_locked(job, force); | ||
1484 | +} | ||
1485 | + | ||
1486 | +void job_user_cancel_locked(Job *job, bool force, Error **errp) | ||
1487 | +{ | ||
1488 | + if (job_apply_verb_locked(job, JOB_VERB_CANCEL, errp)) { | ||
1489 | return; | ||
1490 | } | ||
1491 | - job_cancel(job, force); | ||
1492 | + job_cancel_locked(job, force); | ||
1493 | +} | ||
1494 | + | ||
1495 | +void job_user_cancel(Job *job, bool force, Error **errp) | ||
1496 | +{ | ||
1497 | + JOB_LOCK_GUARD(); | ||
1498 | + job_user_cancel_locked(job, force, errp); | ||
1499 | } | ||
1500 | |||
1501 | /* A wrapper around job_cancel() taking an Error ** parameter so it may be | ||
1502 | * used with job_finish_sync() without the need for (rather nasty) function | ||
1503 | - * pointer casts there. */ | ||
1504 | -static void job_cancel_err(Job *job, Error **errp) | ||
1505 | + * pointer casts there. | ||
1506 | + * | ||
1507 | + * Called with job_mutex held. | ||
1508 | + */ | ||
1509 | +static void job_cancel_err_locked(Job *job, Error **errp) | ||
1510 | { | ||
1511 | - job_cancel(job, false); | ||
1512 | + job_cancel_locked(job, false); | ||
1513 | } | ||
1514 | |||
1515 | /** | ||
1516 | * Same as job_cancel_err(), but force-cancel. | ||
1517 | + * Called with job_mutex held. | ||
1518 | */ | ||
1519 | -static void job_force_cancel_err(Job *job, Error **errp) | ||
1520 | +static void job_force_cancel_err_locked(Job *job, Error **errp) | ||
1521 | { | ||
1522 | - job_cancel(job, true); | ||
1523 | + job_cancel_locked(job, true); | ||
1524 | } | ||
1525 | |||
1526 | -int job_cancel_sync(Job *job, bool force) | ||
1527 | +int job_cancel_sync_locked(Job *job, bool force) | ||
1528 | { | ||
1529 | if (force) { | ||
1530 | - return job_finish_sync(job, &job_force_cancel_err, NULL); | ||
1531 | + return job_finish_sync_locked(job, &job_force_cancel_err_locked, NULL); | ||
1532 | } else { | ||
1533 | - return job_finish_sync(job, &job_cancel_err, NULL); | ||
1534 | + return job_finish_sync_locked(job, &job_cancel_err_locked, NULL); | ||
1535 | } | ||
1536 | } | ||
1537 | |||
1538 | +int job_cancel_sync(Job *job, bool force) | ||
1539 | +{ | ||
1540 | + JOB_LOCK_GUARD(); | ||
1541 | + return job_cancel_sync_locked(job, force); | ||
1542 | +} | ||
1543 | + | ||
1544 | void job_cancel_sync_all(void) | ||
1545 | { | ||
1546 | Job *job; | ||
1547 | AioContext *aio_context; | ||
1548 | + JOB_LOCK_GUARD(); | ||
1549 | |||
1550 | - while ((job = job_next(NULL))) { | ||
1551 | + while ((job = job_next_locked(NULL))) { | ||
1552 | aio_context = job->aio_context; | ||
1553 | aio_context_acquire(aio_context); | ||
1554 | - job_cancel_sync(job, true); | ||
1555 | + job_cancel_sync_locked(job, true); | ||
1556 | aio_context_release(aio_context); | ||
1557 | } | ||
1558 | } | ||
1559 | |||
1560 | +int job_complete_sync_locked(Job *job, Error **errp) | ||
1561 | +{ | ||
1562 | + return job_finish_sync_locked(job, job_complete_locked, errp); | ||
1563 | +} | ||
1564 | + | ||
1565 | int job_complete_sync(Job *job, Error **errp) | ||
1566 | { | ||
1567 | - return job_finish_sync(job, job_complete, errp); | ||
1568 | + JOB_LOCK_GUARD(); | ||
1569 | + return job_complete_sync_locked(job, errp); | ||
1570 | } | ||
1571 | |||
1572 | -void job_complete(Job *job, Error **errp) | ||
1573 | +void job_complete_locked(Job *job, Error **errp) | ||
1574 | { | ||
1575 | /* Should not be reachable via external interface for internal jobs */ | ||
1576 | assert(job->id); | ||
1577 | GLOBAL_STATE_CODE(); | ||
1578 | - if (job_apply_verb(job, JOB_VERB_COMPLETE, errp)) { | ||
1579 | + if (job_apply_verb_locked(job, JOB_VERB_COMPLETE, errp)) { | ||
1580 | return; | ||
1581 | } | ||
1582 | - if (job_cancel_requested(job) || !job->driver->complete) { | ||
1583 | + if (job_cancel_requested_locked(job) || !job->driver->complete) { | ||
1584 | error_setg(errp, "The active block job '%s' cannot be completed", | ||
1585 | job->id); | ||
1586 | return; | ||
1587 | } | ||
1588 | |||
1589 | + job_unlock(); | ||
1590 | job->driver->complete(job, errp); | ||
1591 | + job_lock(); | ||
1592 | } | ||
1593 | |||
1594 | -int job_finish_sync(Job *job, void (*finish)(Job *, Error **errp), Error **errp) | ||
1595 | +void job_complete(Job *job, Error **errp) | ||
1596 | +{ | ||
1597 | + JOB_LOCK_GUARD(); | ||
1598 | + job_complete_locked(job, errp); | ||
1599 | +} | ||
1600 | + | ||
1601 | +int job_finish_sync_locked(Job *job, | ||
1602 | + void (*finish)(Job *, Error **errp), | ||
1603 | + Error **errp) | ||
1604 | { | ||
1605 | Error *local_err = NULL; | ||
1606 | int ret; | ||
1607 | |||
1608 | - job_ref(job); | ||
1609 | + job_ref_locked(job); | ||
1610 | |||
1611 | if (finish) { | ||
1612 | finish(job, &local_err); | ||
1613 | } | ||
1614 | if (local_err) { | ||
1615 | error_propagate(errp, local_err); | ||
1616 | - job_unref(job); | ||
1617 | + job_unref_locked(job); | ||
1618 | return -EBUSY; | ||
1619 | } | ||
1620 | |||
1621 | + job_unlock(); | ||
1622 | AIO_WAIT_WHILE(job->aio_context, | ||
1623 | (job_enter(job), !job_is_completed(job))); | ||
1624 | + job_lock(); | ||
1625 | |||
1626 | - ret = (job_is_cancelled(job) && job->ret == 0) ? -ECANCELED : job->ret; | ||
1627 | - job_unref(job); | ||
1628 | + ret = (job_is_cancelled_locked(job) && job->ret == 0) | ||
1629 | + ? -ECANCELED : job->ret; | ||
1630 | + job_unref_locked(job); | ||
1631 | return ret; | ||
1632 | } | ||
1633 | + | ||
1634 | +int job_finish_sync(Job *job, void (*finish)(Job *, Error **errp), Error **errp) | ||
1635 | +{ | ||
1636 | + JOB_LOCK_GUARD(); | ||
1637 | + return job_finish_sync_locked(job, finish, errp); | ||
62 | +} | 1638 | +} |
63 | -- | 1639 | -- |
64 | 2.25.4 | 1640 | 2.37.3 |
65 | |||
66 | diff view generated by jsdifflib |
1 | From: Max Reitz <mreitz@redhat.com> | 1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | After the series this patch belongs to, we want to have a common | 3 | This comment applies more on job, it was left in blockjob as in the past |
4 | BdrvChildClass that encompasses all of child_file, child_format, and | 4 | the whole job logic was implemented there. |
5 | child_backing. Such a single class needs a single .inherit_options() | ||
6 | implementation, and this patch introduces it. | ||
7 | 5 | ||
8 | The next patch will show how the existing implementations can fall back | 6 | Note: at this stage, job_{lock/unlock} and job lock guard macros |
9 | to it just by passing appropriate BdrvChildRole and parent_is_format | 7 | are *nop*. |
10 | values. | ||
11 | 8 | ||
12 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 9 | No functional change intended. |
13 | Message-Id: <20200513110544.176672-11-mreitz@redhat.com> | 10 | |
14 | Reviewed-by: Eric Blake <eblake@redhat.com> | 11 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
12 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> | ||
13 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
14 | Message-Id: <20220926093214.506243-7-eesposit@redhat.com> | ||
15 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
15 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 16 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
16 | --- | 17 | --- |
17 | block.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | 18 | blockjob.c | 20 -------------------- |
18 | 1 file changed, 81 insertions(+) | 19 | job.c | 16 ++++++++++++++++ |
20 | 2 files changed, 16 insertions(+), 20 deletions(-) | ||
19 | 21 | ||
20 | diff --git a/block.c b/block.c | 22 | diff --git a/blockjob.c b/blockjob.c |
21 | index XXXXXXX..XXXXXXX 100644 | 23 | index XXXXXXX..XXXXXXX 100644 |
22 | --- a/block.c | 24 | --- a/blockjob.c |
23 | +++ b/block.c | 25 | +++ b/blockjob.c |
24 | @@ -XXX,XX +XXX,XX @@ const BdrvChildClass child_backing = { | 26 | @@ -XXX,XX +XXX,XX @@ |
25 | .set_aio_ctx = bdrv_child_cb_set_aio_ctx, | 27 | #include "qemu/main-loop.h" |
26 | }; | 28 | #include "qemu/timer.h" |
29 | |||
30 | -/* | ||
31 | - * The block job API is composed of two categories of functions. | ||
32 | - * | ||
33 | - * The first includes functions used by the monitor. The monitor is | ||
34 | - * peculiar in that it accesses the block job list with block_job_get, and | ||
35 | - * therefore needs consistency across block_job_get and the actual operation | ||
36 | - * (e.g. block_job_set_speed). The consistency is achieved with | ||
37 | - * aio_context_acquire/release. These functions are declared in blockjob.h. | ||
38 | - * | ||
39 | - * The second includes functions used by the block job drivers and sometimes | ||
40 | - * by the core block layer. These do not care about locking, because the | ||
41 | - * whole coroutine runs under the AioContext lock, and are declared in | ||
42 | - * blockjob_int.h. | ||
43 | - */ | ||
44 | - | ||
45 | static bool is_block_job(Job *job) | ||
46 | { | ||
47 | return job_type(job) == JOB_TYPE_BACKUP || | ||
48 | @@ -XXX,XX +XXX,XX @@ static void block_job_event_ready(Notifier *n, void *opaque) | ||
49 | } | ||
50 | |||
51 | |||
52 | -/* | ||
53 | - * API for block job drivers and the block layer. These functions are | ||
54 | - * declared in blockjob_int.h. | ||
55 | - */ | ||
56 | - | ||
57 | void *block_job_create(const char *job_id, const BlockJobDriver *driver, | ||
58 | JobTxn *txn, BlockDriverState *bs, uint64_t perm, | ||
59 | uint64_t shared_perm, int64_t speed, int flags, | ||
60 | diff --git a/job.c b/job.c | ||
61 | index XXXXXXX..XXXXXXX 100644 | ||
62 | --- a/job.c | ||
63 | +++ b/job.c | ||
64 | @@ -XXX,XX +XXX,XX @@ | ||
65 | #include "trace/trace-root.h" | ||
66 | #include "qapi/qapi-events-job.h" | ||
27 | 67 | ||
28 | +/* | 68 | +/* |
29 | + * Returns the options and flags that a generic child of a BDS should | 69 | + * The job API is composed of two categories of functions. |
30 | + * get, based on the given options and flags for the parent BDS. | 70 | + * |
71 | + * The first includes functions used by the monitor. The monitor is | ||
72 | + * peculiar in that it accesses the job list with job_get, and | ||
73 | + * therefore needs consistency across job_get and the actual operation | ||
74 | + * (e.g. job_user_cancel). To achieve this consistency, the caller | ||
75 | + * calls job_lock/job_unlock itself around the whole operation. | ||
76 | + * | ||
77 | + * | ||
78 | + * The second includes functions used by the job drivers and sometimes | ||
79 | + * by the core block layer. These delegate the locking to the callee instead. | ||
80 | + * | ||
81 | + * TODO Actually make this true | ||
31 | + */ | 82 | + */ |
32 | +static void __attribute__((unused)) | ||
33 | + bdrv_inherited_options(BdrvChildRole role, bool parent_is_format, | ||
34 | + int *child_flags, QDict *child_options, | ||
35 | + int parent_flags, QDict *parent_options) | ||
36 | +{ | ||
37 | + int flags = parent_flags; | ||
38 | + | 83 | + |
39 | + /* | 84 | /* |
40 | + * First, decide whether to set, clear, or leave BDRV_O_PROTOCOL. | 85 | * job_mutex protects the jobs list, but also makes the |
41 | + * Generally, the question to answer is: Should this child be | 86 | * struct job fields thread-safe. |
42 | + * format-probed by default? | ||
43 | + */ | ||
44 | + | ||
45 | + /* | ||
46 | + * Pure and non-filtered data children of non-format nodes should | ||
47 | + * be probed by default (even when the node itself has BDRV_O_PROTOCOL | ||
48 | + * set). This only affects a very limited set of drivers (namely | ||
49 | + * quorum and blkverify when this comment was written). | ||
50 | + * Force-clear BDRV_O_PROTOCOL then. | ||
51 | + */ | ||
52 | + if (!parent_is_format && | ||
53 | + (role & BDRV_CHILD_DATA) && | ||
54 | + !(role & (BDRV_CHILD_METADATA | BDRV_CHILD_FILTERED))) | ||
55 | + { | ||
56 | + flags &= ~BDRV_O_PROTOCOL; | ||
57 | + } | ||
58 | + | ||
59 | + /* | ||
60 | + * All children of format nodes (except for COW children) and all | ||
61 | + * metadata children in general should never be format-probed. | ||
62 | + * Force-set BDRV_O_PROTOCOL then. | ||
63 | + */ | ||
64 | + if ((parent_is_format && !(role & BDRV_CHILD_COW)) || | ||
65 | + (role & BDRV_CHILD_METADATA)) | ||
66 | + { | ||
67 | + flags |= BDRV_O_PROTOCOL; | ||
68 | + } | ||
69 | + | ||
70 | + /* | ||
71 | + * If the cache mode isn't explicitly set, inherit direct and no-flush from | ||
72 | + * the parent. | ||
73 | + */ | ||
74 | + qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_DIRECT); | ||
75 | + qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_NO_FLUSH); | ||
76 | + qdict_copy_default(child_options, parent_options, BDRV_OPT_FORCE_SHARE); | ||
77 | + | ||
78 | + if (role & BDRV_CHILD_COW) { | ||
79 | + /* backing files are opened read-only by default */ | ||
80 | + qdict_set_default_str(child_options, BDRV_OPT_READ_ONLY, "on"); | ||
81 | + qdict_set_default_str(child_options, BDRV_OPT_AUTO_READ_ONLY, "off"); | ||
82 | + } else { | ||
83 | + /* Inherit the read-only option from the parent if it's not set */ | ||
84 | + qdict_copy_default(child_options, parent_options, BDRV_OPT_READ_ONLY); | ||
85 | + qdict_copy_default(child_options, parent_options, | ||
86 | + BDRV_OPT_AUTO_READ_ONLY); | ||
87 | + } | ||
88 | + | ||
89 | + /* | ||
90 | + * bdrv_co_pdiscard() respects unmap policy for the parent, so we | ||
91 | + * can default to enable it on lower layers regardless of the | ||
92 | + * parent option. | ||
93 | + */ | ||
94 | + qdict_set_default_str(child_options, BDRV_OPT_DISCARD, "unmap"); | ||
95 | + | ||
96 | + /* Clear flags that only apply to the top layer */ | ||
97 | + flags &= ~(BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING | BDRV_O_COPY_ON_READ); | ||
98 | + | ||
99 | + if (role & BDRV_CHILD_METADATA) { | ||
100 | + flags &= ~BDRV_O_NO_IO; | ||
101 | + } | ||
102 | + if (role & BDRV_CHILD_COW) { | ||
103 | + flags &= ~BDRV_O_TEMPORARY; | ||
104 | + } | ||
105 | + | ||
106 | + *child_flags = flags; | ||
107 | +} | ||
108 | + | ||
109 | static int bdrv_open_flags(BlockDriverState *bs, int flags) | ||
110 | { | ||
111 | int open_flags = flags; | ||
112 | -- | 87 | -- |
113 | 2.25.4 | 88 | 2.37.3 |
114 | |||
115 | diff view generated by jsdifflib |
1 | From: Max Reitz <mreitz@redhat.com> | 1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Make all parents of backing files pass the appropriate BdrvChildRole. | 3 | Just as done with job.h, create _locked() functions in blockjob.h |
4 | By doing so, we can switch their BdrvChildClass over to the generic | 4 | |
5 | child_of_bds, which will do the right thing when given a correct | 5 | These functions will be later useful when caller has already taken |
6 | BdrvChildRole. | 6 | the lock. All blockjob _locked functions call job _locked functions. |
7 | 7 | ||
8 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 8 | Note: at this stage, job_{lock/unlock} and job lock guard macros |
9 | Message-Id: <20200513110544.176672-24-mreitz@redhat.com> | 9 | are *nop*. |
10 | Reviewed-by: Eric Blake <eblake@redhat.com> | 10 | |
11 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
12 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> | ||
13 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
14 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
15 | Message-Id: <20220926093214.506243-8-eesposit@redhat.com> | ||
11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 16 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
12 | --- | 17 | --- |
13 | block.c | 26 ++++++++++++++++++++------ | 18 | include/block/blockjob.h | 18 ++++++++++++++ |
14 | block/backup-top.c | 2 +- | 19 | blockjob.c | 52 ++++++++++++++++++++++++++++++++-------- |
15 | block/vvfat.c | 3 ++- | 20 | 2 files changed, 60 insertions(+), 10 deletions(-) |
16 | tests/test-bdrv-drain.c | 13 +++++++------ | 21 | |
17 | 4 files changed, 30 insertions(+), 14 deletions(-) | 22 | diff --git a/include/block/blockjob.h b/include/block/blockjob.h |
18 | |||
19 | diff --git a/block.c b/block.c | ||
20 | index XXXXXXX..XXXXXXX 100644 | 23 | index XXXXXXX..XXXXXXX 100644 |
21 | --- a/block.c | 24 | --- a/include/block/blockjob.h |
22 | +++ b/block.c | 25 | +++ b/include/block/blockjob.h |
23 | @@ -XXX,XX +XXX,XX @@ static bool bdrv_inherits_from_recursive(BlockDriverState *child, | 26 | @@ -XXX,XX +XXX,XX @@ typedef struct BlockJob { |
24 | return child != NULL; | 27 | */ |
25 | } | 28 | BlockJob *block_job_next(BlockJob *job); |
29 | |||
30 | +/* Same as block_job_next(), but called with job lock held. */ | ||
31 | +BlockJob *block_job_next_locked(BlockJob *job); | ||
32 | + | ||
33 | /** | ||
34 | * block_job_get: | ||
35 | * @id: The id of the block job. | ||
36 | @@ -XXX,XX +XXX,XX @@ BlockJob *block_job_next(BlockJob *job); | ||
37 | */ | ||
38 | BlockJob *block_job_get(const char *id); | ||
39 | |||
40 | +/* Same as block_job_get(), but called with job lock held. */ | ||
41 | +BlockJob *block_job_get_locked(const char *id); | ||
42 | + | ||
43 | /** | ||
44 | * block_job_add_bdrv: | ||
45 | * @job: A block job | ||
46 | @@ -XXX,XX +XXX,XX @@ bool block_job_has_bdrv(BlockJob *job, BlockDriverState *bs); | ||
47 | */ | ||
48 | bool block_job_set_speed(BlockJob *job, int64_t speed, Error **errp); | ||
26 | 49 | ||
27 | +/* | 50 | +/* |
28 | + * Return the BdrvChildRole for @bs's backing child. bs->backing is | 51 | + * Same as block_job_set_speed(), but called with job lock held. |
29 | + * mostly used for COW backing children (role = COW), but also for | 52 | + * Might release the lock temporarily. |
30 | + * filtered children (role = FILTERED | PRIMARY). | ||
31 | + */ | 53 | + */ |
32 | +static BdrvChildRole bdrv_backing_role(BlockDriverState *bs) | 54 | +bool block_job_set_speed_locked(BlockJob *job, int64_t speed, Error **errp); |
33 | +{ | 55 | + |
34 | + if (bs->drv && bs->drv->is_filter) { | 56 | /** |
35 | + return BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY; | 57 | * block_job_query: |
36 | + } else { | 58 | * @job: The job to get information about. |
37 | + return BDRV_CHILD_COW; | 59 | @@ -XXX,XX +XXX,XX @@ bool block_job_set_speed(BlockJob *job, int64_t speed, Error **errp); |
38 | + } | 60 | */ |
39 | +} | 61 | BlockJobInfo *block_job_query(BlockJob *job, Error **errp); |
62 | |||
63 | +/* Same as block_job_query(), but called with job lock held. */ | ||
64 | +BlockJobInfo *block_job_query_locked(BlockJob *job, Error **errp); | ||
65 | + | ||
66 | /** | ||
67 | * block_job_iostatus_reset: | ||
68 | * @job: The job whose I/O status should be reset. | ||
69 | @@ -XXX,XX +XXX,XX @@ BlockJobInfo *block_job_query(BlockJob *job, Error **errp); | ||
70 | */ | ||
71 | void block_job_iostatus_reset(BlockJob *job); | ||
72 | |||
73 | +/* Same as block_job_iostatus_reset(), but called with job lock held. */ | ||
74 | +void block_job_iostatus_reset_locked(BlockJob *job); | ||
40 | + | 75 | + |
41 | /* | 76 | /* |
42 | * Sets the backing file link of a BDS. A new reference is created; callers | 77 | * block_job_get_aio_context: |
43 | * which don't need their own reference any more must call bdrv_unref(). | 78 | * |
44 | @@ -XXX,XX +XXX,XX @@ void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd, | 79 | diff --git a/blockjob.c b/blockjob.c |
45 | goto out; | ||
46 | } | ||
47 | |||
48 | - bs->backing = bdrv_attach_child(bs, backing_hd, "backing", &child_backing, | ||
49 | - 0, errp); | ||
50 | + bs->backing = bdrv_attach_child(bs, backing_hd, "backing", &child_of_bds, | ||
51 | + bdrv_backing_role(bs), errp); | ||
52 | /* If backing_hd was already part of bs's backing chain, and | ||
53 | * inherits_from pointed recursively to bs then let's update it to | ||
54 | * point directly to bs (else it will become NULL). */ | ||
55 | @@ -XXX,XX +XXX,XX @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options, | ||
56 | } | ||
57 | |||
58 | backing_hd = bdrv_open_inherit(backing_filename, reference, options, 0, bs, | ||
59 | - &child_backing, 0, errp); | ||
60 | + &child_of_bds, bdrv_backing_role(bs), errp); | ||
61 | if (!backing_hd) { | ||
62 | bs->open_flags |= BDRV_O_NO_BACKING; | ||
63 | error_prepend(errp, "Could not open backing file: "); | ||
64 | @@ -XXX,XX +XXX,XX @@ int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp) | ||
65 | if (state->replace_backing_bs && state->new_backing_bs) { | ||
66 | uint64_t nperm, nshared; | ||
67 | bdrv_child_perm(state->bs, state->new_backing_bs, | ||
68 | - NULL, &child_backing, 0, bs_queue, | ||
69 | - state->perm, state->shared_perm, | ||
70 | + NULL, &child_of_bds, bdrv_backing_role(state->bs), | ||
71 | + bs_queue, state->perm, state->shared_perm, | ||
72 | &nperm, &nshared); | ||
73 | ret = bdrv_check_update_perm(state->new_backing_bs, NULL, | ||
74 | nperm, nshared, NULL, NULL, errp); | ||
75 | @@ -XXX,XX +XXX,XX @@ void bdrv_refresh_filename(BlockDriverState *bs) | ||
76 | drv->bdrv_gather_child_options(bs, opts, backing_overridden); | ||
77 | } else { | ||
78 | QLIST_FOREACH(child, &bs->children, next) { | ||
79 | - if (child->klass == &child_backing && !backing_overridden) { | ||
80 | + if (child == bs->backing && !backing_overridden) { | ||
81 | /* We can skip the backing BDS if it has not been overridden */ | ||
82 | continue; | ||
83 | } | ||
84 | diff --git a/block/backup-top.c b/block/backup-top.c | ||
85 | index XXXXXXX..XXXXXXX 100644 | 80 | index XXXXXXX..XXXXXXX 100644 |
86 | --- a/block/backup-top.c | 81 | --- a/blockjob.c |
87 | +++ b/block/backup-top.c | 82 | +++ b/blockjob.c |
88 | @@ -XXX,XX +XXX,XX @@ static void backup_top_child_perm(BlockDriverState *bs, BdrvChild *c, | 83 | @@ -XXX,XX +XXX,XX @@ static bool is_block_job(Job *job) |
89 | return; | 84 | job_type(job) == JOB_TYPE_STREAM; |
90 | } | 85 | } |
91 | 86 | ||
92 | - if (child_class == &child_file) { | 87 | -BlockJob *block_job_next(BlockJob *bjob) |
93 | + if (!(role & BDRV_CHILD_FILTERED)) { | 88 | +BlockJob *block_job_next_locked(BlockJob *bjob) |
94 | /* | 89 | { |
95 | * Target child | 90 | Job *job = bjob ? &bjob->job : NULL; |
96 | * | 91 | GLOBAL_STATE_CODE(); |
97 | diff --git a/block/vvfat.c b/block/vvfat.c | 92 | |
98 | index XXXXXXX..XXXXXXX 100644 | 93 | do { |
99 | --- a/block/vvfat.c | 94 | - job = job_next(job); |
100 | +++ b/block/vvfat.c | 95 | + job = job_next_locked(job); |
101 | @@ -XXX,XX +XXX,XX @@ static void vvfat_child_perm(BlockDriverState *bs, BdrvChild *c, | 96 | } while (job && !is_block_job(job)); |
102 | { | 97 | |
103 | BDRVVVFATState *s = bs->opaque; | 98 | return job ? container_of(job, BlockJob, job) : NULL; |
104 | 99 | } | |
105 | - assert(c == s->qcow || child_class == &child_backing); | 100 | |
106 | + assert(c == s->qcow || | 101 | -BlockJob *block_job_get(const char *id) |
107 | + (child_class == &child_of_bds && (role & BDRV_CHILD_COW))); | 102 | +BlockJob *block_job_next(BlockJob *bjob) |
108 | 103 | { | |
109 | if (c == s->qcow) { | 104 | - Job *job = job_get(id); |
110 | /* This is a private node, nobody should try to attach to it */ | 105 | + JOB_LOCK_GUARD(); |
111 | diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c | 106 | + return block_job_next_locked(bjob); |
112 | index XXXXXXX..XXXXXXX 100644 | 107 | +} |
113 | --- a/tests/test-bdrv-drain.c | 108 | + |
114 | +++ b/tests/test-bdrv-drain.c | 109 | +BlockJob *block_job_get_locked(const char *id) |
115 | @@ -XXX,XX +XXX,XX @@ static void bdrv_test_child_perm(BlockDriverState *bs, BdrvChild *c, | 110 | +{ |
116 | * bdrv_format_default_perms() accepts only these two, so disguise | 111 | + Job *job = job_get_locked(id); |
117 | * detach_by_driver_cb_parent as one of them. | 112 | GLOBAL_STATE_CODE(); |
118 | */ | 113 | |
119 | - if (child_class != &child_file && child_class != &child_backing) { | 114 | if (job && is_block_job(job)) { |
120 | + if (child_class != &child_file && child_class != &child_of_bds) { | 115 | @@ -XXX,XX +XXX,XX @@ BlockJob *block_job_get(const char *id) |
121 | child_class = &child_file; | 116 | } |
122 | } | 117 | } |
123 | 118 | ||
124 | @@ -XXX,XX +XXX,XX @@ static void test_detach_indirect(bool by_parent_cb) | 119 | +BlockJob *block_job_get(const char *id) |
125 | bdrv_ref(a); | 120 | +{ |
126 | child_b = bdrv_attach_child(parent_b, b, "PB-B", &child_file, 0, | 121 | + JOB_LOCK_GUARD(); |
127 | &error_abort); | 122 | + return block_job_get_locked(id); |
128 | - child_a = bdrv_attach_child(parent_b, a, "PB-A", &child_backing, 0, | 123 | +} |
129 | - &error_abort); | 124 | + |
130 | + child_a = bdrv_attach_child(parent_b, a, "PB-A", &child_of_bds, | 125 | void block_job_free(Job *job) |
131 | + BDRV_CHILD_COW, &error_abort); | 126 | { |
132 | 127 | BlockJob *bjob = container_of(job, BlockJob, job); | |
133 | bdrv_ref(a); | 128 | @@ -XXX,XX +XXX,XX @@ static bool job_timer_pending(Job *job) |
134 | bdrv_attach_child(parent_a, a, "PA-A", | 129 | return timer_pending(&job->sleep_timer); |
135 | @@ -XXX,XX +XXX,XX @@ static void test_drop_intermediate_poll(void) | 130 | } |
136 | int i; | 131 | |
137 | int ret; | 132 | -bool block_job_set_speed(BlockJob *job, int64_t speed, Error **errp) |
138 | 133 | +bool block_job_set_speed_locked(BlockJob *job, int64_t speed, Error **errp) | |
139 | - chain_child_class = child_backing; | 134 | { |
140 | + chain_child_class = child_of_bds; | 135 | const BlockJobDriver *drv = block_job_driver(job); |
141 | chain_child_class.update_filename = drop_intermediate_poll_update_filename; | 136 | int64_t old_speed = job->speed; |
142 | 137 | ||
143 | for (i = 0; i < 3; i++) { | 138 | GLOBAL_STATE_CODE(); |
144 | @@ -XXX,XX +XXX,XX @@ static void test_drop_intermediate_poll(void) | 139 | |
145 | /* Takes the reference to chain[i - 1] */ | 140 | - if (job_apply_verb(&job->job, JOB_VERB_SET_SPEED, errp) < 0) { |
146 | chain[i]->backing = bdrv_attach_child(chain[i], chain[i - 1], | 141 | + if (job_apply_verb_locked(&job->job, JOB_VERB_SET_SPEED, errp) < 0) { |
147 | "chain", &chain_child_class, | 142 | return false; |
148 | - 0, &error_abort); | 143 | } |
149 | + BDRV_CHILD_COW, &error_abort); | 144 | if (speed < 0) { |
150 | } | 145 | @@ -XXX,XX +XXX,XX @@ bool block_job_set_speed(BlockJob *job, int64_t speed, Error **errp) |
151 | } | 146 | job->speed = speed; |
152 | 147 | ||
153 | @@ -XXX,XX +XXX,XX @@ static void do_test_replace_child_mid_drain(int old_drain_count, | 148 | if (drv->set_speed) { |
154 | 149 | + job_unlock(); | |
155 | bdrv_ref(old_child_bs); | 150 | drv->set_speed(job, speed); |
156 | parent_bs->backing = bdrv_attach_child(parent_bs, old_child_bs, "child", | 151 | + job_lock(); |
157 | - &child_backing, 0, &error_abort); | 152 | } |
158 | + &child_of_bds, BDRV_CHILD_COW, | 153 | |
159 | + &error_abort); | 154 | if (speed && speed <= old_speed) { |
160 | 155 | @@ -XXX,XX +XXX,XX @@ bool block_job_set_speed(BlockJob *job, int64_t speed, Error **errp) | |
161 | for (i = 0; i < old_drain_count; i++) { | 156 | } |
162 | bdrv_drained_begin(old_child_bs); | 157 | |
158 | /* kick only if a timer is pending */ | ||
159 | - job_enter_cond(&job->job, job_timer_pending); | ||
160 | + job_enter_cond_locked(&job->job, job_timer_pending); | ||
161 | |||
162 | return true; | ||
163 | } | ||
164 | |||
165 | +bool block_job_set_speed(BlockJob *job, int64_t speed, Error **errp) | ||
166 | +{ | ||
167 | + JOB_LOCK_GUARD(); | ||
168 | + return block_job_set_speed_locked(job, speed, errp); | ||
169 | +} | ||
170 | + | ||
171 | int64_t block_job_ratelimit_get_delay(BlockJob *job, uint64_t n) | ||
172 | { | ||
173 | IO_CODE(); | ||
174 | return ratelimit_calculate_delay(&job->limit, n); | ||
175 | } | ||
176 | |||
177 | -BlockJobInfo *block_job_query(BlockJob *job, Error **errp) | ||
178 | +BlockJobInfo *block_job_query_locked(BlockJob *job, Error **errp) | ||
179 | { | ||
180 | BlockJobInfo *info; | ||
181 | uint64_t progress_current, progress_total; | ||
182 | @@ -XXX,XX +XXX,XX @@ BlockJobInfo *block_job_query(BlockJob *job, Error **errp) | ||
183 | info->len = progress_total; | ||
184 | info->speed = job->speed; | ||
185 | info->io_status = job->iostatus; | ||
186 | - info->ready = job_is_ready(&job->job), | ||
187 | + info->ready = job_is_ready_locked(&job->job), | ||
188 | info->status = job->job.status; | ||
189 | info->auto_finalize = job->job.auto_finalize; | ||
190 | info->auto_dismiss = job->job.auto_dismiss; | ||
191 | @@ -XXX,XX +XXX,XX @@ BlockJobInfo *block_job_query(BlockJob *job, Error **errp) | ||
192 | return info; | ||
193 | } | ||
194 | |||
195 | +BlockJobInfo *block_job_query(BlockJob *job, Error **errp) | ||
196 | +{ | ||
197 | + JOB_LOCK_GUARD(); | ||
198 | + return block_job_query_locked(job, errp); | ||
199 | +} | ||
200 | + | ||
201 | static void block_job_iostatus_set_err(BlockJob *job, int error) | ||
202 | { | ||
203 | if (job->iostatus == BLOCK_DEVICE_IO_STATUS_OK) { | ||
204 | @@ -XXX,XX +XXX,XX @@ fail: | ||
205 | return NULL; | ||
206 | } | ||
207 | |||
208 | -void block_job_iostatus_reset(BlockJob *job) | ||
209 | +void block_job_iostatus_reset_locked(BlockJob *job) | ||
210 | { | ||
211 | GLOBAL_STATE_CODE(); | ||
212 | if (job->iostatus == BLOCK_DEVICE_IO_STATUS_OK) { | ||
213 | @@ -XXX,XX +XXX,XX @@ void block_job_iostatus_reset(BlockJob *job) | ||
214 | job->iostatus = BLOCK_DEVICE_IO_STATUS_OK; | ||
215 | } | ||
216 | |||
217 | +void block_job_iostatus_reset(BlockJob *job) | ||
218 | +{ | ||
219 | + JOB_LOCK_GUARD(); | ||
220 | + block_job_iostatus_reset_locked(job); | ||
221 | +} | ||
222 | + | ||
223 | void block_job_user_resume(Job *job) | ||
224 | { | ||
225 | BlockJob *bjob = container_of(job, BlockJob, job); | ||
163 | -- | 226 | -- |
164 | 2.25.4 | 227 | 2.37.3 |
165 | |||
166 | diff view generated by jsdifflib |
1 | From: Philippe Mathieu-Daudé <philmd@redhat.com> | 1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | block_copy_do_copy() is static, only used in block_copy_task_entry | 3 | Both blockdev.c and job-qmp.c have TOC/TOU conditions, because |
4 | with the error_is_read argument set. No need to check for it, | 4 | they first search for the job and then perform an action on it. |
5 | simplify. | 5 | Therefore, we need to do the search + action under the same |
6 | job mutex critical section. | ||
6 | 7 | ||
7 | Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com> | 8 | Note: at this stage, job_{lock/unlock} and job lock guard macros |
8 | Message-Id: <20200507121129.29760-3-philmd@redhat.com> | 9 | are *nop*. |
9 | Reviewed-by: Eric Blake <eblake@redhat.com> | 10 | |
11 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
12 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> | ||
13 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
14 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
15 | Message-Id: <20220926093214.506243-9-eesposit@redhat.com> | ||
10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 16 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
11 | --- | 17 | --- |
12 | block/block-copy.c | 12 +++--------- | 18 | blockdev.c | 67 +++++++++++++++++++++++++++++++++++++----------------- |
13 | 1 file changed, 3 insertions(+), 9 deletions(-) | 19 | job-qmp.c | 57 ++++++++++++++++++++++++++++++++-------------- |
20 | 2 files changed, 86 insertions(+), 38 deletions(-) | ||
14 | 21 | ||
15 | diff --git a/block/block-copy.c b/block/block-copy.c | 22 | diff --git a/blockdev.c b/blockdev.c |
16 | index XXXXXXX..XXXXXXX 100644 | 23 | index XXXXXXX..XXXXXXX 100644 |
17 | --- a/block/block-copy.c | 24 | --- a/blockdev.c |
18 | +++ b/block/block-copy.c | 25 | +++ b/blockdev.c |
19 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn block_copy_do_copy(BlockCopyState *s, | 26 | @@ -XXX,XX +XXX,XX @@ out: |
20 | ~BDRV_REQ_WRITE_COMPRESSED); | 27 | aio_context_release(aio_context); |
21 | if (ret < 0) { | 28 | } |
22 | trace_block_copy_write_zeroes_fail(s, offset, ret); | 29 | |
23 | - if (error_is_read) { | 30 | -/* Get a block job using its ID and acquire its AioContext */ |
24 | - *error_is_read = false; | 31 | -static BlockJob *find_block_job(const char *id, AioContext **aio_context, |
25 | - } | 32 | - Error **errp) |
26 | + *error_is_read = false; | 33 | +/* |
27 | } | 34 | + * Get a block job using its ID and acquire its AioContext. |
28 | return ret; | 35 | + * Called with job_mutex held. |
29 | } | 36 | + */ |
30 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn block_copy_do_copy(BlockCopyState *s, | 37 | +static BlockJob *find_block_job_locked(const char *id, |
31 | ret = bdrv_co_pread(s->source, offset, nbytes, bounce_buffer, 0); | 38 | + AioContext **aio_context, |
32 | if (ret < 0) { | 39 | + Error **errp) |
33 | trace_block_copy_read_fail(s, offset, ret); | 40 | { |
34 | - if (error_is_read) { | 41 | BlockJob *job; |
35 | - *error_is_read = true; | 42 | |
36 | - } | 43 | @@ -XXX,XX +XXX,XX @@ static BlockJob *find_block_job(const char *id, AioContext **aio_context, |
37 | + *error_is_read = true; | 44 | |
45 | *aio_context = NULL; | ||
46 | |||
47 | - job = block_job_get(id); | ||
48 | + job = block_job_get_locked(id); | ||
49 | |||
50 | if (!job) { | ||
51 | error_set(errp, ERROR_CLASS_DEVICE_NOT_ACTIVE, | ||
52 | @@ -XXX,XX +XXX,XX @@ static BlockJob *find_block_job(const char *id, AioContext **aio_context, | ||
53 | void qmp_block_job_set_speed(const char *device, int64_t speed, Error **errp) | ||
54 | { | ||
55 | AioContext *aio_context; | ||
56 | - BlockJob *job = find_block_job(device, &aio_context, errp); | ||
57 | + BlockJob *job; | ||
58 | + | ||
59 | + JOB_LOCK_GUARD(); | ||
60 | + job = find_block_job_locked(device, &aio_context, errp); | ||
61 | |||
62 | if (!job) { | ||
63 | return; | ||
64 | } | ||
65 | |||
66 | - block_job_set_speed(job, speed, errp); | ||
67 | + block_job_set_speed_locked(job, speed, errp); | ||
68 | aio_context_release(aio_context); | ||
69 | } | ||
70 | |||
71 | @@ -XXX,XX +XXX,XX @@ void qmp_block_job_cancel(const char *device, | ||
72 | bool has_force, bool force, Error **errp) | ||
73 | { | ||
74 | AioContext *aio_context; | ||
75 | - BlockJob *job = find_block_job(device, &aio_context, errp); | ||
76 | + BlockJob *job; | ||
77 | + | ||
78 | + JOB_LOCK_GUARD(); | ||
79 | + job = find_block_job_locked(device, &aio_context, errp); | ||
80 | |||
81 | if (!job) { | ||
82 | return; | ||
83 | @@ -XXX,XX +XXX,XX @@ void qmp_block_job_cancel(const char *device, | ||
84 | force = false; | ||
85 | } | ||
86 | |||
87 | - if (job_user_paused(&job->job) && !force) { | ||
88 | + if (job_user_paused_locked(&job->job) && !force) { | ||
89 | error_setg(errp, "The block job for device '%s' is currently paused", | ||
90 | device); | ||
38 | goto out; | 91 | goto out; |
39 | } | 92 | } |
40 | 93 | ||
41 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn block_copy_do_copy(BlockCopyState *s, | 94 | trace_qmp_block_job_cancel(job); |
42 | s->write_flags); | 95 | - job_user_cancel(&job->job, force, errp); |
43 | if (ret < 0) { | 96 | + job_user_cancel_locked(&job->job, force, errp); |
44 | trace_block_copy_write_fail(s, offset, ret); | 97 | out: |
45 | - if (error_is_read) { | 98 | aio_context_release(aio_context); |
46 | - *error_is_read = false; | 99 | } |
47 | - } | 100 | @@ -XXX,XX +XXX,XX @@ out: |
48 | + *error_is_read = false; | 101 | void qmp_block_job_pause(const char *device, Error **errp) |
49 | goto out; | 102 | { |
50 | } | 103 | AioContext *aio_context; |
104 | - BlockJob *job = find_block_job(device, &aio_context, errp); | ||
105 | + BlockJob *job; | ||
106 | + | ||
107 | + JOB_LOCK_GUARD(); | ||
108 | + job = find_block_job_locked(device, &aio_context, errp); | ||
109 | |||
110 | if (!job) { | ||
111 | return; | ||
112 | } | ||
113 | |||
114 | trace_qmp_block_job_pause(job); | ||
115 | - job_user_pause(&job->job, errp); | ||
116 | + job_user_pause_locked(&job->job, errp); | ||
117 | aio_context_release(aio_context); | ||
118 | } | ||
119 | |||
120 | void qmp_block_job_resume(const char *device, Error **errp) | ||
121 | { | ||
122 | AioContext *aio_context; | ||
123 | - BlockJob *job = find_block_job(device, &aio_context, errp); | ||
124 | + BlockJob *job; | ||
125 | + | ||
126 | + JOB_LOCK_GUARD(); | ||
127 | + job = find_block_job_locked(device, &aio_context, errp); | ||
128 | |||
129 | if (!job) { | ||
130 | return; | ||
131 | } | ||
132 | |||
133 | trace_qmp_block_job_resume(job); | ||
134 | - job_user_resume(&job->job, errp); | ||
135 | + job_user_resume_locked(&job->job, errp); | ||
136 | aio_context_release(aio_context); | ||
137 | } | ||
138 | |||
139 | void qmp_block_job_complete(const char *device, Error **errp) | ||
140 | { | ||
141 | AioContext *aio_context; | ||
142 | - BlockJob *job = find_block_job(device, &aio_context, errp); | ||
143 | + BlockJob *job; | ||
144 | + | ||
145 | + JOB_LOCK_GUARD(); | ||
146 | + job = find_block_job_locked(device, &aio_context, errp); | ||
147 | |||
148 | if (!job) { | ||
149 | return; | ||
150 | } | ||
151 | |||
152 | trace_qmp_block_job_complete(job); | ||
153 | - job_complete(&job->job, errp); | ||
154 | + job_complete_locked(&job->job, errp); | ||
155 | aio_context_release(aio_context); | ||
156 | } | ||
157 | |||
158 | void qmp_block_job_finalize(const char *id, Error **errp) | ||
159 | { | ||
160 | AioContext *aio_context; | ||
161 | - BlockJob *job = find_block_job(id, &aio_context, errp); | ||
162 | + BlockJob *job; | ||
163 | + | ||
164 | + JOB_LOCK_GUARD(); | ||
165 | + job = find_block_job_locked(id, &aio_context, errp); | ||
166 | |||
167 | if (!job) { | ||
168 | return; | ||
169 | } | ||
170 | |||
171 | trace_qmp_block_job_finalize(job); | ||
172 | - job_ref(&job->job); | ||
173 | - job_finalize(&job->job, errp); | ||
174 | + job_ref_locked(&job->job); | ||
175 | + job_finalize_locked(&job->job, errp); | ||
176 | |||
177 | /* | ||
178 | * Job's context might have changed via job_finalize (and job_txn_apply | ||
179 | @@ -XXX,XX +XXX,XX @@ void qmp_block_job_finalize(const char *id, Error **errp) | ||
180 | * one. | ||
181 | */ | ||
182 | aio_context = block_job_get_aio_context(job); | ||
183 | - job_unref(&job->job); | ||
184 | + job_unref_locked(&job->job); | ||
185 | aio_context_release(aio_context); | ||
186 | } | ||
187 | |||
188 | void qmp_block_job_dismiss(const char *id, Error **errp) | ||
189 | { | ||
190 | AioContext *aio_context; | ||
191 | - BlockJob *bjob = find_block_job(id, &aio_context, errp); | ||
192 | + BlockJob *bjob; | ||
193 | Job *job; | ||
194 | |||
195 | + JOB_LOCK_GUARD(); | ||
196 | + bjob = find_block_job_locked(id, &aio_context, errp); | ||
197 | + | ||
198 | if (!bjob) { | ||
199 | return; | ||
200 | } | ||
201 | |||
202 | trace_qmp_block_job_dismiss(bjob); | ||
203 | job = &bjob->job; | ||
204 | - job_dismiss(&job, errp); | ||
205 | + job_dismiss_locked(&job, errp); | ||
206 | aio_context_release(aio_context); | ||
207 | } | ||
208 | |||
209 | diff --git a/job-qmp.c b/job-qmp.c | ||
210 | index XXXXXXX..XXXXXXX 100644 | ||
211 | --- a/job-qmp.c | ||
212 | +++ b/job-qmp.c | ||
213 | @@ -XXX,XX +XXX,XX @@ | ||
214 | #include "qapi/error.h" | ||
215 | #include "trace/trace-root.h" | ||
216 | |||
217 | -/* Get a job using its ID and acquire its AioContext */ | ||
218 | -static Job *find_job(const char *id, AioContext **aio_context, Error **errp) | ||
219 | +/* | ||
220 | + * Get a job using its ID and acquire its AioContext. | ||
221 | + * Called with job_mutex held. | ||
222 | + */ | ||
223 | +static Job *find_job_locked(const char *id, | ||
224 | + AioContext **aio_context, | ||
225 | + Error **errp) | ||
226 | { | ||
227 | Job *job; | ||
228 | |||
229 | *aio_context = NULL; | ||
230 | |||
231 | - job = job_get(id); | ||
232 | + job = job_get_locked(id); | ||
233 | if (!job) { | ||
234 | error_setg(errp, "Job not found"); | ||
235 | return NULL; | ||
236 | @@ -XXX,XX +XXX,XX @@ static Job *find_job(const char *id, AioContext **aio_context, Error **errp) | ||
237 | void qmp_job_cancel(const char *id, Error **errp) | ||
238 | { | ||
239 | AioContext *aio_context; | ||
240 | - Job *job = find_job(id, &aio_context, errp); | ||
241 | + Job *job; | ||
242 | + | ||
243 | + JOB_LOCK_GUARD(); | ||
244 | + job = find_job_locked(id, &aio_context, errp); | ||
245 | |||
246 | if (!job) { | ||
247 | return; | ||
248 | } | ||
249 | |||
250 | trace_qmp_job_cancel(job); | ||
251 | - job_user_cancel(job, true, errp); | ||
252 | + job_user_cancel_locked(job, true, errp); | ||
253 | aio_context_release(aio_context); | ||
254 | } | ||
255 | |||
256 | void qmp_job_pause(const char *id, Error **errp) | ||
257 | { | ||
258 | AioContext *aio_context; | ||
259 | - Job *job = find_job(id, &aio_context, errp); | ||
260 | + Job *job; | ||
261 | + | ||
262 | + JOB_LOCK_GUARD(); | ||
263 | + job = find_job_locked(id, &aio_context, errp); | ||
264 | |||
265 | if (!job) { | ||
266 | return; | ||
267 | } | ||
268 | |||
269 | trace_qmp_job_pause(job); | ||
270 | - job_user_pause(job, errp); | ||
271 | + job_user_pause_locked(job, errp); | ||
272 | aio_context_release(aio_context); | ||
273 | } | ||
274 | |||
275 | void qmp_job_resume(const char *id, Error **errp) | ||
276 | { | ||
277 | AioContext *aio_context; | ||
278 | - Job *job = find_job(id, &aio_context, errp); | ||
279 | + Job *job; | ||
280 | + | ||
281 | + JOB_LOCK_GUARD(); | ||
282 | + job = find_job_locked(id, &aio_context, errp); | ||
283 | |||
284 | if (!job) { | ||
285 | return; | ||
286 | } | ||
287 | |||
288 | trace_qmp_job_resume(job); | ||
289 | - job_user_resume(job, errp); | ||
290 | + job_user_resume_locked(job, errp); | ||
291 | aio_context_release(aio_context); | ||
292 | } | ||
293 | |||
294 | void qmp_job_complete(const char *id, Error **errp) | ||
295 | { | ||
296 | AioContext *aio_context; | ||
297 | - Job *job = find_job(id, &aio_context, errp); | ||
298 | + Job *job; | ||
299 | + | ||
300 | + JOB_LOCK_GUARD(); | ||
301 | + job = find_job_locked(id, &aio_context, errp); | ||
302 | |||
303 | if (!job) { | ||
304 | return; | ||
305 | } | ||
306 | |||
307 | trace_qmp_job_complete(job); | ||
308 | - job_complete(job, errp); | ||
309 | + job_complete_locked(job, errp); | ||
310 | aio_context_release(aio_context); | ||
311 | } | ||
312 | |||
313 | void qmp_job_finalize(const char *id, Error **errp) | ||
314 | { | ||
315 | AioContext *aio_context; | ||
316 | - Job *job = find_job(id, &aio_context, errp); | ||
317 | + Job *job; | ||
318 | + | ||
319 | + JOB_LOCK_GUARD(); | ||
320 | + job = find_job_locked(id, &aio_context, errp); | ||
321 | |||
322 | if (!job) { | ||
323 | return; | ||
324 | } | ||
325 | |||
326 | trace_qmp_job_finalize(job); | ||
327 | - job_ref(job); | ||
328 | - job_finalize(job, errp); | ||
329 | + job_ref_locked(job); | ||
330 | + job_finalize_locked(job, errp); | ||
331 | |||
332 | /* | ||
333 | * Job's context might have changed via job_finalize (and job_txn_apply | ||
334 | @@ -XXX,XX +XXX,XX @@ void qmp_job_finalize(const char *id, Error **errp) | ||
335 | * one. | ||
336 | */ | ||
337 | aio_context = job->aio_context; | ||
338 | - job_unref(job); | ||
339 | + job_unref_locked(job); | ||
340 | aio_context_release(aio_context); | ||
341 | } | ||
342 | |||
343 | void qmp_job_dismiss(const char *id, Error **errp) | ||
344 | { | ||
345 | AioContext *aio_context; | ||
346 | - Job *job = find_job(id, &aio_context, errp); | ||
347 | + Job *job; | ||
348 | + | ||
349 | + JOB_LOCK_GUARD(); | ||
350 | + job = find_job_locked(id, &aio_context, errp); | ||
351 | |||
352 | if (!job) { | ||
353 | return; | ||
354 | } | ||
355 | |||
356 | trace_qmp_job_dismiss(job); | ||
357 | - job_dismiss(&job, errp); | ||
358 | + job_dismiss_locked(&job, errp); | ||
359 | aio_context_release(aio_context); | ||
360 | } | ||
51 | 361 | ||
52 | -- | 362 | -- |
53 | 2.25.4 | 363 | 2.37.3 |
54 | |||
55 | diff view generated by jsdifflib |
1 | From: Max Reitz <mreitz@redhat.com> | 1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | bdrv_commit() already has a BlockBackend pointing to the BDS that we | 3 | Add missing job synchronization in the unit tests, with |
4 | want to empty, it just has the wrong permissions. | 4 | explicit locks. |
5 | 5 | ||
6 | qemu-img commit has no BlockBackend pointing to the old backing file | 6 | We are deliberately using _locked functions wrapped by a guard |
7 | yet, but introducing one is simple. | 7 | instead of a normal call because the normal call will be removed |
8 | 8 | in future, as the only usage is limited to the tests. | |
9 | After this commit, bdrv_make_empty() is the only remaining caller of | 9 | |
10 | BlockDriver.bdrv_make_empty(). | 10 | In other words, if a function like job_pause() is/will be only used |
11 | 11 | in tests to avoid: | |
12 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 12 | |
13 | Message-Id: <20200429141126.85159-5-mreitz@redhat.com> | 13 | WITH_JOB_LOCK_GUARD(){ |
14 | Reviewed-by: Eric Blake <eblake@redhat.com> | 14 | job_pause_locked(); |
15 | [kwolf: Fixed up reference output for 098] | 15 | } |
16 | |||
17 | then it is not worth keeping job_pause(), and just use the guard. | ||
18 | |||
19 | Note: at this stage, job_{lock/unlock} and job lock guard macros | ||
20 | are *nop*. | ||
21 | |||
22 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
23 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> | ||
24 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
25 | Message-Id: <20220926093214.506243-10-eesposit@redhat.com> | ||
16 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 26 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
17 | --- | 27 | --- |
18 | block/commit.c | 16 +++++++++------- | 28 | tests/unit/test-bdrv-drain.c | 76 ++++++++++++-------- |
19 | qemu-img.c | 19 ++++++++++++++----- | 29 | tests/unit/test-block-iothread.c | 8 ++- |
20 | tests/qemu-iotests/098.out | 8 ++++---- | 30 | tests/unit/test-blockjob-txn.c | 24 ++++--- |
21 | 3 files changed, 27 insertions(+), 16 deletions(-) | 31 | tests/unit/test-blockjob.c | 115 +++++++++++++++++++------------ |
22 | 32 | 4 files changed, 140 insertions(+), 83 deletions(-) | |
23 | diff --git a/block/commit.c b/block/commit.c | 33 | |
34 | diff --git a/tests/unit/test-bdrv-drain.c b/tests/unit/test-bdrv-drain.c | ||
24 | index XXXXXXX..XXXXXXX 100644 | 35 | index XXXXXXX..XXXXXXX 100644 |
25 | --- a/block/commit.c | 36 | --- a/tests/unit/test-bdrv-drain.c |
26 | +++ b/block/commit.c | 37 | +++ b/tests/unit/test-bdrv-drain.c |
27 | @@ -XXX,XX +XXX,XX @@ int bdrv_commit(BlockDriverState *bs) | 38 | @@ -XXX,XX +XXX,XX @@ static void test_blockjob_common_drain_node(enum drain_type drain_type, |
28 | } | ||
29 | |||
30 | ctx = bdrv_get_aio_context(bs); | ||
31 | - src = blk_new(ctx, BLK_PERM_CONSISTENT_READ, BLK_PERM_ALL); | ||
32 | + /* WRITE_UNCHANGED is required for bdrv_make_empty() */ | ||
33 | + src = blk_new(ctx, BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED, | ||
34 | + BLK_PERM_ALL); | ||
35 | backing = blk_new(ctx, BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL); | ||
36 | |||
37 | ret = blk_insert_bs(src, bs, &local_err); | ||
38 | @@ -XXX,XX +XXX,XX @@ int bdrv_commit(BlockDriverState *bs) | ||
39 | } | 39 | } |
40 | } | 40 | } |
41 | 41 | ||
42 | - if (drv->bdrv_make_empty) { | 42 | - g_assert_cmpint(job->job.pause_count, ==, 0); |
43 | - ret = drv->bdrv_make_empty(bs); | 43 | - g_assert_false(job->job.paused); |
44 | - if (ret < 0) { | 44 | - g_assert_true(tjob->running); |
45 | - goto ro_cleanup; | 45 | - g_assert_true(job->job.busy); /* We're in qemu_co_sleep_ns() */ |
46 | - } | 46 | + WITH_JOB_LOCK_GUARD() { |
47 | - blk_flush(src); | 47 | + g_assert_cmpint(job->job.pause_count, ==, 0); |
48 | + ret = blk_make_empty(src, NULL); | 48 | + g_assert_false(job->job.paused); |
49 | + /* Ignore -ENOTSUP */ | 49 | + g_assert_true(tjob->running); |
50 | + if (ret < 0 && ret != -ENOTSUP) { | 50 | + g_assert_true(job->job.busy); /* We're in qemu_co_sleep_ns() */ |
51 | + goto ro_cleanup; | 51 | + } |
52 | } | 52 | |
53 | 53 | do_drain_begin_unlocked(drain_type, drain_bs); | |
54 | + blk_flush(src); | 54 | |
55 | - if (drain_type == BDRV_DRAIN_ALL) { | ||
56 | - /* bdrv_drain_all() drains both src and target */ | ||
57 | - g_assert_cmpint(job->job.pause_count, ==, 2); | ||
58 | - } else { | ||
59 | - g_assert_cmpint(job->job.pause_count, ==, 1); | ||
60 | + WITH_JOB_LOCK_GUARD() { | ||
61 | + if (drain_type == BDRV_DRAIN_ALL) { | ||
62 | + /* bdrv_drain_all() drains both src and target */ | ||
63 | + g_assert_cmpint(job->job.pause_count, ==, 2); | ||
64 | + } else { | ||
65 | + g_assert_cmpint(job->job.pause_count, ==, 1); | ||
66 | + } | ||
67 | + g_assert_true(job->job.paused); | ||
68 | + g_assert_false(job->job.busy); /* The job is paused */ | ||
69 | } | ||
70 | - g_assert_true(job->job.paused); | ||
71 | - g_assert_false(job->job.busy); /* The job is paused */ | ||
72 | |||
73 | do_drain_end_unlocked(drain_type, drain_bs); | ||
74 | |||
75 | if (use_iothread) { | ||
76 | - /* paused is reset in the I/O thread, wait for it */ | ||
77 | + /* | ||
78 | + * Here we are waiting for the paused status to change, | ||
79 | + * so don't bother protecting the read every time. | ||
80 | + * | ||
81 | + * paused is reset in the I/O thread, wait for it | ||
82 | + */ | ||
83 | while (job->job.paused) { | ||
84 | aio_poll(qemu_get_aio_context(), false); | ||
85 | } | ||
86 | } | ||
87 | |||
88 | - g_assert_cmpint(job->job.pause_count, ==, 0); | ||
89 | - g_assert_false(job->job.paused); | ||
90 | - g_assert_true(job->job.busy); /* We're in qemu_co_sleep_ns() */ | ||
91 | + WITH_JOB_LOCK_GUARD() { | ||
92 | + g_assert_cmpint(job->job.pause_count, ==, 0); | ||
93 | + g_assert_false(job->job.paused); | ||
94 | + g_assert_true(job->job.busy); /* We're in qemu_co_sleep_ns() */ | ||
95 | + } | ||
96 | |||
97 | do_drain_begin_unlocked(drain_type, target); | ||
98 | |||
99 | - if (drain_type == BDRV_DRAIN_ALL) { | ||
100 | - /* bdrv_drain_all() drains both src and target */ | ||
101 | - g_assert_cmpint(job->job.pause_count, ==, 2); | ||
102 | - } else { | ||
103 | - g_assert_cmpint(job->job.pause_count, ==, 1); | ||
104 | + WITH_JOB_LOCK_GUARD() { | ||
105 | + if (drain_type == BDRV_DRAIN_ALL) { | ||
106 | + /* bdrv_drain_all() drains both src and target */ | ||
107 | + g_assert_cmpint(job->job.pause_count, ==, 2); | ||
108 | + } else { | ||
109 | + g_assert_cmpint(job->job.pause_count, ==, 1); | ||
110 | + } | ||
111 | + g_assert_true(job->job.paused); | ||
112 | + g_assert_false(job->job.busy); /* The job is paused */ | ||
113 | } | ||
114 | - g_assert_true(job->job.paused); | ||
115 | - g_assert_false(job->job.busy); /* The job is paused */ | ||
116 | |||
117 | do_drain_end_unlocked(drain_type, target); | ||
118 | |||
119 | if (use_iothread) { | ||
120 | - /* paused is reset in the I/O thread, wait for it */ | ||
121 | + /* | ||
122 | + * Here we are waiting for the paused status to change, | ||
123 | + * so don't bother protecting the read every time. | ||
124 | + * | ||
125 | + * paused is reset in the I/O thread, wait for it | ||
126 | + */ | ||
127 | while (job->job.paused) { | ||
128 | aio_poll(qemu_get_aio_context(), false); | ||
129 | } | ||
130 | } | ||
131 | |||
132 | - g_assert_cmpint(job->job.pause_count, ==, 0); | ||
133 | - g_assert_false(job->job.paused); | ||
134 | - g_assert_true(job->job.busy); /* We're in qemu_co_sleep_ns() */ | ||
135 | + WITH_JOB_LOCK_GUARD() { | ||
136 | + g_assert_cmpint(job->job.pause_count, ==, 0); | ||
137 | + g_assert_false(job->job.paused); | ||
138 | + g_assert_true(job->job.busy); /* We're in qemu_co_sleep_ns() */ | ||
139 | + } | ||
140 | |||
141 | aio_context_acquire(ctx); | ||
142 | - ret = job_complete_sync(&job->job, &error_abort); | ||
143 | + WITH_JOB_LOCK_GUARD() { | ||
144 | + ret = job_complete_sync_locked(&job->job, &error_abort); | ||
145 | + } | ||
146 | g_assert_cmpint(ret, ==, (result == TEST_JOB_SUCCESS ? 0 : -EIO)); | ||
147 | |||
148 | if (use_iothread) { | ||
149 | diff --git a/tests/unit/test-block-iothread.c b/tests/unit/test-block-iothread.c | ||
150 | index XXXXXXX..XXXXXXX 100644 | ||
151 | --- a/tests/unit/test-block-iothread.c | ||
152 | +++ b/tests/unit/test-block-iothread.c | ||
153 | @@ -XXX,XX +XXX,XX @@ static void test_attach_blockjob(void) | ||
154 | } | ||
155 | |||
156 | aio_context_acquire(ctx); | ||
157 | - job_complete_sync(&tjob->common.job, &error_abort); | ||
158 | + WITH_JOB_LOCK_GUARD() { | ||
159 | + job_complete_sync_locked(&tjob->common.job, &error_abort); | ||
160 | + } | ||
161 | blk_set_aio_context(blk, qemu_get_aio_context(), &error_abort); | ||
162 | aio_context_release(ctx); | ||
163 | |||
164 | @@ -XXX,XX +XXX,XX @@ static void test_propagate_mirror(void) | ||
165 | BLOCKDEV_ON_ERROR_REPORT, BLOCKDEV_ON_ERROR_REPORT, | ||
166 | false, "filter_node", MIRROR_COPY_MODE_BACKGROUND, | ||
167 | &error_abort); | ||
168 | - job = job_get("job0"); | ||
169 | + WITH_JOB_LOCK_GUARD() { | ||
170 | + job = job_get_locked("job0"); | ||
171 | + } | ||
172 | filter = bdrv_find_node("filter_node"); | ||
173 | |||
174 | /* Change the AioContext of src */ | ||
175 | diff --git a/tests/unit/test-blockjob-txn.c b/tests/unit/test-blockjob-txn.c | ||
176 | index XXXXXXX..XXXXXXX 100644 | ||
177 | --- a/tests/unit/test-blockjob-txn.c | ||
178 | +++ b/tests/unit/test-blockjob-txn.c | ||
179 | @@ -XXX,XX +XXX,XX @@ static void test_single_job(int expected) | ||
180 | job = test_block_job_start(1, true, expected, &result, txn); | ||
181 | job_start(&job->job); | ||
182 | |||
183 | - if (expected == -ECANCELED) { | ||
184 | - job_cancel(&job->job, false); | ||
185 | + WITH_JOB_LOCK_GUARD() { | ||
186 | + if (expected == -ECANCELED) { | ||
187 | + job_cancel_locked(&job->job, false); | ||
188 | + } | ||
189 | } | ||
190 | |||
191 | while (result == -EINPROGRESS) { | ||
192 | @@ -XXX,XX +XXX,XX @@ static void test_pair_jobs(int expected1, int expected2) | ||
193 | /* Release our reference now to trigger as many nice | ||
194 | * use-after-free bugs as possible. | ||
195 | */ | ||
196 | - job_txn_unref(txn); | ||
197 | + WITH_JOB_LOCK_GUARD() { | ||
198 | + job_txn_unref_locked(txn); | ||
199 | |||
200 | - if (expected1 == -ECANCELED) { | ||
201 | - job_cancel(&job1->job, false); | ||
202 | - } | ||
203 | - if (expected2 == -ECANCELED) { | ||
204 | - job_cancel(&job2->job, false); | ||
205 | + if (expected1 == -ECANCELED) { | ||
206 | + job_cancel_locked(&job1->job, false); | ||
207 | + } | ||
208 | + if (expected2 == -ECANCELED) { | ||
209 | + job_cancel_locked(&job2->job, false); | ||
210 | + } | ||
211 | } | ||
212 | |||
213 | while (result1 == -EINPROGRESS || result2 == -EINPROGRESS) { | ||
214 | @@ -XXX,XX +XXX,XX @@ static void test_pair_jobs_fail_cancel_race(void) | ||
215 | job_start(&job1->job); | ||
216 | job_start(&job2->job); | ||
217 | |||
218 | - job_cancel(&job1->job, false); | ||
219 | + WITH_JOB_LOCK_GUARD() { | ||
220 | + job_cancel_locked(&job1->job, false); | ||
221 | + } | ||
222 | |||
223 | /* Now make job2 finish before the main loop kicks jobs. This simulates | ||
224 | * the race between a pending kick and another job completing. | ||
225 | diff --git a/tests/unit/test-blockjob.c b/tests/unit/test-blockjob.c | ||
226 | index XXXXXXX..XXXXXXX 100644 | ||
227 | --- a/tests/unit/test-blockjob.c | ||
228 | +++ b/tests/unit/test-blockjob.c | ||
229 | @@ -XXX,XX +XXX,XX @@ static CancelJob *create_common(Job **pjob) | ||
230 | bjob = mk_job(blk, "Steve", &test_cancel_driver, true, | ||
231 | JOB_MANUAL_FINALIZE | JOB_MANUAL_DISMISS); | ||
232 | job = &bjob->job; | ||
233 | - job_ref(job); | ||
234 | - assert(job->status == JOB_STATUS_CREATED); | ||
235 | + WITH_JOB_LOCK_GUARD() { | ||
236 | + job_ref_locked(job); | ||
237 | + assert(job->status == JOB_STATUS_CREATED); | ||
238 | + } | ||
55 | + | 239 | + |
56 | /* | 240 | s = container_of(bjob, CancelJob, common); |
57 | * Make sure all data we wrote to the backing device is actually | 241 | s->blk = blk; |
58 | * stable on disk. | 242 | |
59 | diff --git a/qemu-img.c b/qemu-img.c | 243 | @@ -XXX,XX +XXX,XX @@ static void cancel_common(CancelJob *s) |
60 | index XXXXXXX..XXXXXXX 100644 | 244 | aio_context_acquire(ctx); |
61 | --- a/qemu-img.c | 245 | |
62 | +++ b/qemu-img.c | 246 | job_cancel_sync(&job->job, true); |
63 | @@ -XXX,XX +XXX,XX @@ static int img_commit(int argc, char **argv) | 247 | - if (sts != JOB_STATUS_CREATED && sts != JOB_STATUS_CONCLUDED) { |
64 | goto unref_backing; | 248 | - Job *dummy = &job->job; |
65 | } | 249 | - job_dismiss(&dummy, &error_abort); |
66 | 250 | + WITH_JOB_LOCK_GUARD() { | |
67 | - if (!drop && bs->drv->bdrv_make_empty) { | 251 | + if (sts != JOB_STATUS_CREATED && sts != JOB_STATUS_CONCLUDED) { |
68 | - ret = bs->drv->bdrv_make_empty(bs); | 252 | + Job *dummy = &job->job; |
69 | - if (ret) { | 253 | + job_dismiss_locked(&dummy, &error_abort); |
70 | - error_setg_errno(&local_err, -ret, "Could not empty %s", | 254 | + } |
71 | - filename); | 255 | + assert(job->job.status == JOB_STATUS_NULL); |
72 | + if (!drop) { | 256 | + job_unref_locked(&job->job); |
73 | + BlockBackend *old_backing_blk; | 257 | } |
258 | - assert(job->job.status == JOB_STATUS_NULL); | ||
259 | - job_unref(&job->job); | ||
260 | destroy_blk(blk); | ||
261 | |||
262 | aio_context_release(ctx); | ||
263 | @@ -XXX,XX +XXX,XX @@ static void test_cancel_created(void) | ||
264 | cancel_common(s); | ||
265 | } | ||
266 | |||
267 | +static void assert_job_status_is(Job *job, int status) | ||
268 | +{ | ||
269 | + WITH_JOB_LOCK_GUARD() { | ||
270 | + assert(job->status == status); | ||
271 | + } | ||
272 | +} | ||
74 | + | 273 | + |
75 | + old_backing_blk = blk_new_with_bs(bs, BLK_PERM_WRITE, BLK_PERM_ALL, | 274 | static void test_cancel_running(void) |
76 | + &local_err); | 275 | { |
77 | + if (!old_backing_blk) { | 276 | Job *job; |
78 | + goto unref_backing; | 277 | @@ -XXX,XX +XXX,XX @@ static void test_cancel_running(void) |
79 | + } | 278 | s = create_common(&job); |
80 | + ret = blk_make_empty(old_backing_blk, &local_err); | 279 | |
81 | + blk_unref(old_backing_blk); | 280 | job_start(job); |
82 | + if (ret == -ENOTSUP) { | 281 | - assert(job->status == JOB_STATUS_RUNNING); |
83 | + error_free(local_err); | 282 | + assert_job_status_is(job, JOB_STATUS_RUNNING); |
84 | + local_err = NULL; | 283 | |
85 | + } else if (ret < 0) { | 284 | cancel_common(s); |
86 | goto unref_backing; | 285 | } |
87 | } | 286 | @@ -XXX,XX +XXX,XX @@ static void test_cancel_paused(void) |
88 | } | 287 | s = create_common(&job); |
89 | diff --git a/tests/qemu-iotests/098.out b/tests/qemu-iotests/098.out | 288 | |
90 | index XXXXXXX..XXXXXXX 100644 | 289 | job_start(job); |
91 | --- a/tests/qemu-iotests/098.out | 290 | - assert(job->status == JOB_STATUS_RUNNING); |
92 | +++ b/tests/qemu-iotests/098.out | 291 | - |
93 | @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864 | 292 | - job_user_pause(job, &error_abort); |
94 | Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base | 293 | + WITH_JOB_LOCK_GUARD() { |
95 | wrote 65536/65536 bytes at offset 0 | 294 | + assert(job->status == JOB_STATUS_RUNNING); |
96 | 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | 295 | + job_user_pause_locked(job, &error_abort); |
97 | -qemu-img: Could not empty blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.IMGFMT: Input/output error | 296 | + } |
98 | +qemu-img: Failed to empty blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.IMGFMT: Input/output error | 297 | job_enter(job); |
99 | No errors were found on the image. | 298 | - assert(job->status == JOB_STATUS_PAUSED); |
100 | 299 | + assert_job_status_is(job, JOB_STATUS_PAUSED); | |
101 | === empty_image_prepare === | 300 | |
102 | @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864 | 301 | cancel_common(s); |
103 | Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base | 302 | } |
104 | wrote 65536/65536 bytes at offset 0 | 303 | @@ -XXX,XX +XXX,XX @@ static void test_cancel_ready(void) |
105 | 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | 304 | s = create_common(&job); |
106 | -qemu-img: Could not empty blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.IMGFMT: Input/output error | 305 | |
107 | +qemu-img: Failed to empty blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.IMGFMT: Input/output error | 306 | job_start(job); |
108 | Leaked cluster 4 refcount=1 reference=0 | 307 | - assert(job->status == JOB_STATUS_RUNNING); |
109 | Leaked cluster 5 refcount=1 reference=0 | 308 | + assert_job_status_is(job, JOB_STATUS_RUNNING); |
110 | Repairing cluster 4 refcount=1 reference=0 | 309 | |
111 | @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864 | 310 | s->should_converge = true; |
112 | Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base | 311 | job_enter(job); |
113 | wrote 65536/65536 bytes at offset 0 | 312 | - assert(job->status == JOB_STATUS_READY); |
114 | 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | 313 | + assert_job_status_is(job, JOB_STATUS_READY); |
115 | -qemu-img: Could not empty blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.IMGFMT: Input/output error | 314 | |
116 | +qemu-img: Failed to empty blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.IMGFMT: Input/output error | 315 | cancel_common(s); |
117 | ERROR cluster 0 refcount=0 reference=1 | 316 | } |
118 | ERROR cluster 1 refcount=0 reference=1 | 317 | @@ -XXX,XX +XXX,XX @@ static void test_cancel_standby(void) |
119 | ERROR cluster 3 refcount=0 reference=1 | 318 | s = create_common(&job); |
120 | @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864 | 319 | |
121 | Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base | 320 | job_start(job); |
122 | wrote 65536/65536 bytes at offset 0 | 321 | - assert(job->status == JOB_STATUS_RUNNING); |
123 | 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | 322 | + assert_job_status_is(job, JOB_STATUS_RUNNING); |
124 | -qemu-img: Could not empty blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.IMGFMT: Input/output error | 323 | |
125 | +qemu-img: Failed to empty blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.IMGFMT: Input/output error | 324 | s->should_converge = true; |
126 | ERROR cluster 0 refcount=0 reference=1 | 325 | job_enter(job); |
127 | ERROR cluster 1 refcount=0 reference=1 | 326 | - assert(job->status == JOB_STATUS_READY); |
128 | ERROR cluster 3 refcount=0 reference=1 | 327 | - |
328 | - job_user_pause(job, &error_abort); | ||
329 | + WITH_JOB_LOCK_GUARD() { | ||
330 | + assert(job->status == JOB_STATUS_READY); | ||
331 | + job_user_pause_locked(job, &error_abort); | ||
332 | + } | ||
333 | job_enter(job); | ||
334 | - assert(job->status == JOB_STATUS_STANDBY); | ||
335 | + assert_job_status_is(job, JOB_STATUS_STANDBY); | ||
336 | |||
337 | cancel_common(s); | ||
338 | } | ||
339 | @@ -XXX,XX +XXX,XX @@ static void test_cancel_pending(void) | ||
340 | s = create_common(&job); | ||
341 | |||
342 | job_start(job); | ||
343 | - assert(job->status == JOB_STATUS_RUNNING); | ||
344 | + assert_job_status_is(job, JOB_STATUS_RUNNING); | ||
345 | |||
346 | s->should_converge = true; | ||
347 | job_enter(job); | ||
348 | - assert(job->status == JOB_STATUS_READY); | ||
349 | - | ||
350 | - job_complete(job, &error_abort); | ||
351 | + WITH_JOB_LOCK_GUARD() { | ||
352 | + assert(job->status == JOB_STATUS_READY); | ||
353 | + job_complete_locked(job, &error_abort); | ||
354 | + } | ||
355 | job_enter(job); | ||
356 | while (!job->deferred_to_main_loop) { | ||
357 | aio_poll(qemu_get_aio_context(), true); | ||
358 | } | ||
359 | - assert(job->status == JOB_STATUS_READY); | ||
360 | + assert_job_status_is(job, JOB_STATUS_READY); | ||
361 | aio_poll(qemu_get_aio_context(), true); | ||
362 | - assert(job->status == JOB_STATUS_PENDING); | ||
363 | + assert_job_status_is(job, JOB_STATUS_PENDING); | ||
364 | |||
365 | cancel_common(s); | ||
366 | } | ||
367 | @@ -XXX,XX +XXX,XX @@ static void test_cancel_concluded(void) | ||
368 | s = create_common(&job); | ||
369 | |||
370 | job_start(job); | ||
371 | - assert(job->status == JOB_STATUS_RUNNING); | ||
372 | + assert_job_status_is(job, JOB_STATUS_RUNNING); | ||
373 | |||
374 | s->should_converge = true; | ||
375 | job_enter(job); | ||
376 | - assert(job->status == JOB_STATUS_READY); | ||
377 | - | ||
378 | - job_complete(job, &error_abort); | ||
379 | + WITH_JOB_LOCK_GUARD() { | ||
380 | + assert(job->status == JOB_STATUS_READY); | ||
381 | + job_complete_locked(job, &error_abort); | ||
382 | + } | ||
383 | job_enter(job); | ||
384 | while (!job->deferred_to_main_loop) { | ||
385 | aio_poll(qemu_get_aio_context(), true); | ||
386 | } | ||
387 | - assert(job->status == JOB_STATUS_READY); | ||
388 | + assert_job_status_is(job, JOB_STATUS_READY); | ||
389 | aio_poll(qemu_get_aio_context(), true); | ||
390 | - assert(job->status == JOB_STATUS_PENDING); | ||
391 | + assert_job_status_is(job, JOB_STATUS_PENDING); | ||
392 | |||
393 | aio_context_acquire(job->aio_context); | ||
394 | - job_finalize(job, &error_abort); | ||
395 | + WITH_JOB_LOCK_GUARD() { | ||
396 | + job_finalize_locked(job, &error_abort); | ||
397 | + } | ||
398 | aio_context_release(job->aio_context); | ||
399 | - assert(job->status == JOB_STATUS_CONCLUDED); | ||
400 | + assert_job_status_is(job, JOB_STATUS_CONCLUDED); | ||
401 | |||
402 | cancel_common(s); | ||
403 | } | ||
404 | @@ -XXX,XX +XXX,XX @@ static void test_complete_in_standby(void) | ||
405 | bjob = mk_job(blk, "job", &test_yielding_driver, true, | ||
406 | JOB_MANUAL_FINALIZE | JOB_MANUAL_DISMISS); | ||
407 | job = &bjob->job; | ||
408 | - assert(job->status == JOB_STATUS_CREATED); | ||
409 | + assert_job_status_is(job, JOB_STATUS_CREATED); | ||
410 | |||
411 | /* Wait for the job to become READY */ | ||
412 | job_start(job); | ||
413 | aio_context_acquire(ctx); | ||
414 | + /* | ||
415 | + * Here we are waiting for the status to change, so don't bother | ||
416 | + * protecting the read every time. | ||
417 | + */ | ||
418 | AIO_WAIT_WHILE(ctx, job->status != JOB_STATUS_READY); | ||
419 | aio_context_release(ctx); | ||
420 | |||
421 | /* Begin the drained section, pausing the job */ | ||
422 | bdrv_drain_all_begin(); | ||
423 | - assert(job->status == JOB_STATUS_STANDBY); | ||
424 | + assert_job_status_is(job, JOB_STATUS_STANDBY); | ||
425 | + | ||
426 | /* Lock the IO thread to prevent the job from being run */ | ||
427 | aio_context_acquire(ctx); | ||
428 | /* This will schedule the job to resume it */ | ||
429 | bdrv_drain_all_end(); | ||
430 | |||
431 | - /* But the job cannot run, so it will remain on standby */ | ||
432 | - assert(job->status == JOB_STATUS_STANDBY); | ||
433 | + WITH_JOB_LOCK_GUARD() { | ||
434 | + /* But the job cannot run, so it will remain on standby */ | ||
435 | + assert(job->status == JOB_STATUS_STANDBY); | ||
436 | |||
437 | - /* Even though the job is on standby, this should work */ | ||
438 | - job_complete(job, &error_abort); | ||
439 | + /* Even though the job is on standby, this should work */ | ||
440 | + job_complete_locked(job, &error_abort); | ||
441 | |||
442 | - /* The test is done now, clean up. */ | ||
443 | - job_finish_sync(job, NULL, &error_abort); | ||
444 | - assert(job->status == JOB_STATUS_PENDING); | ||
445 | + /* The test is done now, clean up. */ | ||
446 | + job_finish_sync_locked(job, NULL, &error_abort); | ||
447 | + assert(job->status == JOB_STATUS_PENDING); | ||
448 | |||
449 | - job_finalize(job, &error_abort); | ||
450 | - assert(job->status == JOB_STATUS_CONCLUDED); | ||
451 | + job_finalize_locked(job, &error_abort); | ||
452 | + assert(job->status == JOB_STATUS_CONCLUDED); | ||
453 | |||
454 | - job_dismiss(&job, &error_abort); | ||
455 | + job_dismiss_locked(&job, &error_abort); | ||
456 | + } | ||
457 | |||
458 | destroy_blk(blk); | ||
459 | aio_context_release(ctx); | ||
129 | -- | 460 | -- |
130 | 2.25.4 | 461 | 2.37.3 |
131 | |||
132 | diff view generated by jsdifflib |
1 | From: Max Reitz <mreitz@redhat.com> | 1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | The commit, mirror, and blkreplay block nodes are filters, so they should | 3 | Once job lock is used and aiocontext is removed, mirror has |
4 | be marked as such. | 4 | to perform job operations under the same critical section, |
5 | Note: at this stage, job_{lock/unlock} and job lock guard macros | ||
6 | are *nop*. | ||
5 | 7 | ||
6 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 8 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
7 | Message-Id: <20200513110544.176672-2-mreitz@redhat.com> | 9 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> |
10 | Message-Id: <20220926093214.506243-11-eesposit@redhat.com> | ||
11 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
8 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
9 | --- | 13 | --- |
10 | block/blkreplay.c | 1 + | 14 | block/mirror.c | 13 +++++++++---- |
11 | block/commit.c | 2 ++ | 15 | 1 file changed, 9 insertions(+), 4 deletions(-) |
12 | block/mirror.c | 2 ++ | ||
13 | 3 files changed, 5 insertions(+) | ||
14 | 16 | ||
15 | diff --git a/block/blkreplay.c b/block/blkreplay.c | ||
16 | index XXXXXXX..XXXXXXX 100644 | ||
17 | --- a/block/blkreplay.c | ||
18 | +++ b/block/blkreplay.c | ||
19 | @@ -XXX,XX +XXX,XX @@ static int blkreplay_snapshot_goto(BlockDriverState *bs, | ||
20 | static BlockDriver bdrv_blkreplay = { | ||
21 | .format_name = "blkreplay", | ||
22 | .instance_size = 0, | ||
23 | + .is_filter = true, | ||
24 | |||
25 | .bdrv_open = blkreplay_open, | ||
26 | .bdrv_child_perm = bdrv_filter_default_perms, | ||
27 | diff --git a/block/commit.c b/block/commit.c | ||
28 | index XXXXXXX..XXXXXXX 100644 | ||
29 | --- a/block/commit.c | ||
30 | +++ b/block/commit.c | ||
31 | @@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_commit_top = { | ||
32 | .bdrv_co_block_status = bdrv_co_block_status_from_backing, | ||
33 | .bdrv_refresh_filename = bdrv_commit_top_refresh_filename, | ||
34 | .bdrv_child_perm = bdrv_commit_top_child_perm, | ||
35 | + | ||
36 | + .is_filter = true, | ||
37 | }; | ||
38 | |||
39 | void commit_start(const char *job_id, BlockDriverState *bs, | ||
40 | diff --git a/block/mirror.c b/block/mirror.c | 17 | diff --git a/block/mirror.c b/block/mirror.c |
41 | index XXXXXXX..XXXXXXX 100644 | 18 | index XXXXXXX..XXXXXXX 100644 |
42 | --- a/block/mirror.c | 19 | --- a/block/mirror.c |
43 | +++ b/block/mirror.c | 20 | +++ b/block/mirror.c |
44 | @@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_mirror_top = { | 21 | @@ -XXX,XX +XXX,XX @@ static void mirror_complete(Job *job, Error **errp) |
45 | .bdrv_co_block_status = bdrv_co_block_status_from_backing, | 22 | s->should_complete = true; |
46 | .bdrv_refresh_filename = bdrv_mirror_top_refresh_filename, | 23 | |
47 | .bdrv_child_perm = bdrv_mirror_top_child_perm, | 24 | /* If the job is paused, it will be re-entered when it is resumed */ |
48 | + | 25 | - if (!job->paused) { |
49 | + .is_filter = true, | 26 | - job_enter(job); |
50 | }; | 27 | + WITH_JOB_LOCK_GUARD() { |
51 | 28 | + if (!job->paused) { | |
52 | static BlockJob *mirror_start_job( | 29 | + job_enter_cond_locked(job, NULL); |
30 | + } | ||
31 | } | ||
32 | } | ||
33 | |||
34 | @@ -XXX,XX +XXX,XX @@ static bool mirror_drained_poll(BlockJob *job) | ||
35 | * from one of our own drain sections, to avoid a deadlock waiting for | ||
36 | * ourselves. | ||
37 | */ | ||
38 | - if (!s->common.job.paused && !job_is_cancelled(&job->job) && !s->in_drain) { | ||
39 | - return true; | ||
40 | + WITH_JOB_LOCK_GUARD() { | ||
41 | + if (!s->common.job.paused && !job_is_cancelled_locked(&job->job) | ||
42 | + && !s->in_drain) { | ||
43 | + return true; | ||
44 | + } | ||
45 | } | ||
46 | |||
47 | return !!s->in_flight; | ||
53 | -- | 48 | -- |
54 | 2.25.4 | 49 | 2.37.3 |
55 | |||
56 | diff view generated by jsdifflib |
1 | From: Max Reitz <mreitz@redhat.com> | 1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Right now, bdrv_format_default_perms() is used by format parents | 3 | Now that the API offers also _locked() functions, take advantage |
4 | (generally). We want to switch to a model where most parents use a | 4 | of it and give also the caller control to take the lock and call |
5 | single BdrvChildClass, which then decides the permissions based on the | 5 | _locked functions. |
6 | child role. To do so, we have to split bdrv_format_default_perms() into | 6 | |
7 | separate functions for each such role. | 7 | This makes sense especially when we have for loops, because it |
8 | 8 | makes no sense to have: | |
9 | Note that bdrv_default_perms_for_storage() currently handles all DATA | | 9 | |
10 | METADATA children. A follow-up patch is going to split it further into | 10 | for(job = job_next(); ...) |
11 | one function for each case. | 11 | |
12 | 12 | where each job_next() takes the lock internally. | |
13 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 13 | Instead we want |
14 | Reviewed-by: Eric Blake <eblake@redhat.com> | 14 | |
15 | Message-Id: <20200513110544.176672-18-mreitz@redhat.com> | 15 | JOB_LOCK_GUARD(); |
16 | for(job = job_next_locked(); ...) | ||
17 | |||
18 | In addition, protect also direct field accesses, by either creating a | ||
19 | new critical section or widening the existing ones. | ||
20 | |||
21 | Note: at this stage, job_{lock/unlock} and job lock guard macros | ||
22 | are *nop*. | ||
23 | |||
24 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
25 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> | ||
26 | Message-Id: <20220926093214.506243-12-eesposit@redhat.com> | ||
27 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
16 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 28 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
17 | --- | 29 | --- |
18 | block.c | 71 +++++++++++++++++++++++++++++++++++++-------------------- | 30 | block.c | 17 ++++++++++------- |
19 | 1 file changed, 46 insertions(+), 25 deletions(-) | 31 | blockdev.c | 14 ++++++++++---- |
32 | blockjob.c | 35 ++++++++++++++++++++++------------- | ||
33 | job-qmp.c | 9 ++++++--- | ||
34 | monitor/qmp-cmds.c | 7 +++++-- | ||
35 | qemu-img.c | 15 ++++++++++----- | ||
36 | 6 files changed, 63 insertions(+), 34 deletions(-) | ||
20 | 37 | ||
21 | diff --git a/block.c b/block.c | 38 | diff --git a/block.c b/block.c |
22 | index XXXXXXX..XXXXXXX 100644 | 39 | index XXXXXXX..XXXXXXX 100644 |
23 | --- a/block.c | 40 | --- a/block.c |
24 | +++ b/block.c | 41 | +++ b/block.c |
25 | @@ -XXX,XX +XXX,XX @@ static void bdrv_default_perms_for_cow(BlockDriverState *bs, BdrvChild *c, | 42 | @@ -XXX,XX +XXX,XX @@ static void bdrv_close(BlockDriverState *bs) |
26 | *nshared = shared; | 43 | |
44 | void bdrv_close_all(void) | ||
45 | { | ||
46 | - assert(job_next(NULL) == NULL); | ||
47 | GLOBAL_STATE_CODE(); | ||
48 | + assert(job_next(NULL) == NULL); | ||
49 | |||
50 | /* Drop references from requests still in flight, such as canceled block | ||
51 | * jobs whose AIO context has not been polled yet */ | ||
52 | @@ -XXX,XX +XXX,XX @@ XDbgBlockGraph *bdrv_get_xdbg_block_graph(Error **errp) | ||
53 | } | ||
54 | } | ||
55 | |||
56 | - for (job = block_job_next(NULL); job; job = block_job_next(job)) { | ||
57 | - GSList *el; | ||
58 | + WITH_JOB_LOCK_GUARD() { | ||
59 | + for (job = block_job_next_locked(NULL); job; | ||
60 | + job = block_job_next_locked(job)) { | ||
61 | + GSList *el; | ||
62 | |||
63 | - xdbg_graph_add_node(gr, job, X_DBG_BLOCK_GRAPH_NODE_TYPE_BLOCK_JOB, | ||
64 | - job->job.id); | ||
65 | - for (el = job->nodes; el; el = el->next) { | ||
66 | - xdbg_graph_add_edge(gr, job, (BdrvChild *)el->data); | ||
67 | + xdbg_graph_add_node(gr, job, X_DBG_BLOCK_GRAPH_NODE_TYPE_BLOCK_JOB, | ||
68 | + job->job.id); | ||
69 | + for (el = job->nodes; el; el = el->next) { | ||
70 | + xdbg_graph_add_edge(gr, job, (BdrvChild *)el->data); | ||
71 | + } | ||
72 | } | ||
73 | } | ||
74 | |||
75 | diff --git a/blockdev.c b/blockdev.c | ||
76 | index XXXXXXX..XXXXXXX 100644 | ||
77 | --- a/blockdev.c | ||
78 | +++ b/blockdev.c | ||
79 | @@ -XXX,XX +XXX,XX @@ void blockdev_mark_auto_del(BlockBackend *blk) | ||
80 | return; | ||
81 | } | ||
82 | |||
83 | - for (job = block_job_next(NULL); job; job = block_job_next(job)) { | ||
84 | + JOB_LOCK_GUARD(); | ||
85 | + | ||
86 | + for (job = block_job_next_locked(NULL); job; | ||
87 | + job = block_job_next_locked(job)) { | ||
88 | if (block_job_has_bdrv(job, blk_bs(blk))) { | ||
89 | AioContext *aio_context = job->job.aio_context; | ||
90 | aio_context_acquire(aio_context); | ||
91 | |||
92 | - job_cancel(&job->job, false); | ||
93 | + job_cancel_locked(&job->job, false); | ||
94 | |||
95 | aio_context_release(aio_context); | ||
96 | } | ||
97 | @@ -XXX,XX +XXX,XX @@ BlockJobInfoList *qmp_query_block_jobs(Error **errp) | ||
98 | BlockJobInfoList *head = NULL, **tail = &head; | ||
99 | BlockJob *job; | ||
100 | |||
101 | - for (job = block_job_next(NULL); job; job = block_job_next(job)) { | ||
102 | + JOB_LOCK_GUARD(); | ||
103 | + | ||
104 | + for (job = block_job_next_locked(NULL); job; | ||
105 | + job = block_job_next_locked(job)) { | ||
106 | BlockJobInfo *value; | ||
107 | AioContext *aio_context; | ||
108 | |||
109 | @@ -XXX,XX +XXX,XX @@ BlockJobInfoList *qmp_query_block_jobs(Error **errp) | ||
110 | } | ||
111 | aio_context = block_job_get_aio_context(job); | ||
112 | aio_context_acquire(aio_context); | ||
113 | - value = block_job_query(job, errp); | ||
114 | + value = block_job_query_locked(job, errp); | ||
115 | aio_context_release(aio_context); | ||
116 | if (!value) { | ||
117 | qapi_free_BlockJobInfoList(head); | ||
118 | diff --git a/blockjob.c b/blockjob.c | ||
119 | index XXXXXXX..XXXXXXX 100644 | ||
120 | --- a/blockjob.c | ||
121 | +++ b/blockjob.c | ||
122 | @@ -XXX,XX +XXX,XX @@ static bool child_job_drained_poll(BdrvChild *c) | ||
123 | /* An inactive or completed job doesn't have any pending requests. Jobs | ||
124 | * with !job->busy are either already paused or have a pause point after | ||
125 | * being reentered, so no job driver code will run before they pause. */ | ||
126 | - if (!job->busy || job_is_completed(job)) { | ||
127 | - return false; | ||
128 | + WITH_JOB_LOCK_GUARD() { | ||
129 | + if (!job->busy || job_is_completed_locked(job)) { | ||
130 | + return false; | ||
131 | + } | ||
132 | } | ||
133 | |||
134 | /* Otherwise, assume that it isn't fully stopped yet, but allow the job to | ||
135 | @@ -XXX,XX +XXX,XX @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver, | ||
136 | job->ready_notifier.notify = block_job_event_ready; | ||
137 | job->idle_notifier.notify = block_job_on_idle; | ||
138 | |||
139 | - notifier_list_add(&job->job.on_finalize_cancelled, | ||
140 | - &job->finalize_cancelled_notifier); | ||
141 | - notifier_list_add(&job->job.on_finalize_completed, | ||
142 | - &job->finalize_completed_notifier); | ||
143 | - notifier_list_add(&job->job.on_pending, &job->pending_notifier); | ||
144 | - notifier_list_add(&job->job.on_ready, &job->ready_notifier); | ||
145 | - notifier_list_add(&job->job.on_idle, &job->idle_notifier); | ||
146 | + WITH_JOB_LOCK_GUARD() { | ||
147 | + notifier_list_add(&job->job.on_finalize_cancelled, | ||
148 | + &job->finalize_cancelled_notifier); | ||
149 | + notifier_list_add(&job->job.on_finalize_completed, | ||
150 | + &job->finalize_completed_notifier); | ||
151 | + notifier_list_add(&job->job.on_pending, &job->pending_notifier); | ||
152 | + notifier_list_add(&job->job.on_ready, &job->ready_notifier); | ||
153 | + notifier_list_add(&job->job.on_idle, &job->idle_notifier); | ||
154 | + } | ||
155 | |||
156 | error_setg(&job->blocker, "block device is in use by block job: %s", | ||
157 | job_type_str(&job->job)); | ||
158 | @@ -XXX,XX +XXX,XX @@ BlockErrorAction block_job_error_action(BlockJob *job, BlockdevOnError on_err, | ||
159 | action); | ||
160 | } | ||
161 | if (action == BLOCK_ERROR_ACTION_STOP) { | ||
162 | - if (!job->job.user_paused) { | ||
163 | - job_pause(&job->job); | ||
164 | - /* make the pause user visible, which will be resumed from QMP. */ | ||
165 | - job->job.user_paused = true; | ||
166 | + WITH_JOB_LOCK_GUARD() { | ||
167 | + if (!job->job.user_paused) { | ||
168 | + job_pause_locked(&job->job); | ||
169 | + /* | ||
170 | + * make the pause user visible, which will be | ||
171 | + * resumed from QMP. | ||
172 | + */ | ||
173 | + job->job.user_paused = true; | ||
174 | + } | ||
175 | } | ||
176 | block_job_iostatus_set_err(job, error); | ||
177 | } | ||
178 | diff --git a/job-qmp.c b/job-qmp.c | ||
179 | index XXXXXXX..XXXXXXX 100644 | ||
180 | --- a/job-qmp.c | ||
181 | +++ b/job-qmp.c | ||
182 | @@ -XXX,XX +XXX,XX @@ void qmp_job_dismiss(const char *id, Error **errp) | ||
183 | aio_context_release(aio_context); | ||
27 | } | 184 | } |
28 | 185 | ||
29 | +static void bdrv_default_perms_for_storage(BlockDriverState *bs, BdrvChild *c, | 186 | -static JobInfo *job_query_single(Job *job, Error **errp) |
30 | + const BdrvChildClass *child_class, | 187 | +/* Called with job_mutex held. */ |
31 | + BdrvChildRole role, | 188 | +static JobInfo *job_query_single_locked(Job *job, Error **errp) |
32 | + BlockReopenQueue *reopen_queue, | 189 | { |
33 | + uint64_t perm, uint64_t shared, | 190 | JobInfo *info; |
34 | + uint64_t *nperm, uint64_t *nshared) | 191 | uint64_t progress_current; |
35 | +{ | 192 | @@ -XXX,XX +XXX,XX @@ JobInfoList *qmp_query_jobs(Error **errp) |
36 | + int flags; | 193 | JobInfoList *head = NULL, **tail = &head; |
194 | Job *job; | ||
195 | |||
196 | - for (job = job_next(NULL); job; job = job_next(job)) { | ||
197 | + JOB_LOCK_GUARD(); | ||
37 | + | 198 | + |
38 | + assert(child_class == &child_file || | 199 | + for (job = job_next_locked(NULL); job; job = job_next_locked(job)) { |
39 | + (child_class == &child_of_bds && | 200 | JobInfo *value; |
40 | + (role & (BDRV_CHILD_METADATA | BDRV_CHILD_DATA)))); | 201 | AioContext *aio_context; |
41 | + | 202 | |
42 | + flags = bdrv_reopen_get_flags(reopen_queue, bs); | 203 | @@ -XXX,XX +XXX,XX @@ JobInfoList *qmp_query_jobs(Error **errp) |
43 | + | 204 | } |
44 | + /* | 205 | aio_context = job->aio_context; |
45 | + * Apart from the modifications below, the same permissions are | 206 | aio_context_acquire(aio_context); |
46 | + * forwarded and left alone as for filters | 207 | - value = job_query_single(job, errp); |
47 | + */ | 208 | + value = job_query_single_locked(job, errp); |
48 | + bdrv_filter_default_perms(bs, c, child_class, role, reopen_queue, | 209 | aio_context_release(aio_context); |
49 | + perm, shared, &perm, &shared); | 210 | if (!value) { |
50 | + | 211 | qapi_free_JobInfoList(head); |
51 | + /* Format drivers may touch metadata even if the guest doesn't write */ | 212 | diff --git a/monitor/qmp-cmds.c b/monitor/qmp-cmds.c |
52 | + if (bdrv_is_writable_after_reopen(bs, reopen_queue)) { | 213 | index XXXXXXX..XXXXXXX 100644 |
53 | + perm |= BLK_PERM_WRITE | BLK_PERM_RESIZE; | 214 | --- a/monitor/qmp-cmds.c |
54 | + } | 215 | +++ b/monitor/qmp-cmds.c |
55 | + | 216 | @@ -XXX,XX +XXX,XX @@ void qmp_cont(Error **errp) |
56 | + /* | 217 | blk_iostatus_reset(blk); |
57 | + * bs->file always needs to be consistent because of the metadata. We | 218 | } |
58 | + * can never allow other users to resize or write to it. | 219 | |
59 | + */ | 220 | - for (job = block_job_next(NULL); job; job = block_job_next(job)) { |
60 | + if (!(flags & BDRV_O_NO_IO)) { | 221 | - block_job_iostatus_reset(job); |
61 | + perm |= BLK_PERM_CONSISTENT_READ; | 222 | + WITH_JOB_LOCK_GUARD() { |
62 | + } | 223 | + for (job = block_job_next_locked(NULL); job; |
63 | + shared &= ~(BLK_PERM_WRITE | BLK_PERM_RESIZE); | 224 | + job = block_job_next_locked(job)) { |
64 | + | 225 | + block_job_iostatus_reset_locked(job); |
65 | + if (bs->open_flags & BDRV_O_INACTIVE) { | 226 | + } |
66 | + shared |= BLK_PERM_WRITE | BLK_PERM_RESIZE; | 227 | } |
67 | + } | 228 | |
68 | + | 229 | /* Continuing after completed migration. Images have been inactivated to |
69 | + *nperm = perm; | 230 | diff --git a/qemu-img.c b/qemu-img.c |
70 | + *nshared = shared; | 231 | index XXXXXXX..XXXXXXX 100644 |
71 | +} | 232 | --- a/qemu-img.c |
72 | + | 233 | +++ b/qemu-img.c |
73 | void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c, | 234 | @@ -XXX,XX +XXX,XX @@ static void run_block_job(BlockJob *job, Error **errp) |
74 | const BdrvChildClass *child_class, | 235 | int ret = 0; |
75 | BdrvChildRole role, | 236 | |
76 | @@ -XXX,XX +XXX,XX @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c, | 237 | aio_context_acquire(aio_context); |
77 | assert(child_class == &child_backing || child_class == &child_file); | 238 | - job_ref(&job->job); |
78 | 239 | + job_lock(); | |
79 | if (!backing) { | 240 | + job_ref_locked(&job->job); |
80 | - int flags = bdrv_reopen_get_flags(reopen_queue, bs); | 241 | do { |
81 | - | 242 | float progress = 0.0f; |
82 | - /* Apart from the modifications below, the same permissions are | 243 | + job_unlock(); |
83 | - * forwarded and left alone as for filters */ | 244 | aio_poll(aio_context, true); |
84 | - bdrv_filter_default_perms(bs, c, child_class, role, reopen_queue, | 245 | |
85 | - perm, shared, &perm, &shared); | 246 | progress_get_snapshot(&job->job.progress, &progress_current, |
86 | - | 247 | @@ -XXX,XX +XXX,XX @@ static void run_block_job(BlockJob *job, Error **errp) |
87 | - /* Format drivers may touch metadata even if the guest doesn't write */ | 248 | progress = (float)progress_current / progress_total * 100.f; |
88 | - if (bdrv_is_writable_after_reopen(bs, reopen_queue)) { | 249 | } |
89 | - perm |= BLK_PERM_WRITE | BLK_PERM_RESIZE; | 250 | qemu_progress_print(progress, 0); |
90 | - } | 251 | - } while (!job_is_ready(&job->job) && !job_is_completed(&job->job)); |
91 | - | 252 | + job_lock(); |
92 | - /* bs->file always needs to be consistent because of the metadata. We | 253 | + } while (!job_is_ready_locked(&job->job) && |
93 | - * can never allow other users to resize or write to it. */ | 254 | + !job_is_completed_locked(&job->job)); |
94 | - if (!(flags & BDRV_O_NO_IO)) { | 255 | |
95 | - perm |= BLK_PERM_CONSISTENT_READ; | 256 | - if (!job_is_completed(&job->job)) { |
96 | - } | 257 | - ret = job_complete_sync(&job->job, errp); |
97 | - shared &= ~(BLK_PERM_WRITE | BLK_PERM_RESIZE); | 258 | + if (!job_is_completed_locked(&job->job)) { |
98 | - | 259 | + ret = job_complete_sync_locked(&job->job, errp); |
99 | - if (bs->open_flags & BDRV_O_INACTIVE) { | ||
100 | - shared |= BLK_PERM_WRITE | BLK_PERM_RESIZE; | ||
101 | - } | ||
102 | - | ||
103 | - *nperm = perm; | ||
104 | - *nshared = shared; | ||
105 | + bdrv_default_perms_for_storage(bs, c, child_class, role, reopen_queue, | ||
106 | + perm, shared, nperm, nshared); | ||
107 | } else { | 260 | } else { |
108 | bdrv_default_perms_for_cow(bs, c, child_class, role, reopen_queue, | 261 | ret = job->job.ret; |
109 | perm, shared, nperm, nshared); | 262 | } |
263 | - job_unref(&job->job); | ||
264 | + job_unref_locked(&job->job); | ||
265 | + job_unlock(); | ||
266 | aio_context_release(aio_context); | ||
267 | |||
268 | /* publish completion progress only when success */ | ||
110 | -- | 269 | -- |
111 | 2.25.4 | 270 | 2.37.3 |
112 | |||
113 | diff view generated by jsdifflib |
1 | From: Max Reitz <mreitz@redhat.com> | 1 | From: Paolo Bonzini <pbonzini@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Right now, bdrv_format_default_perms() is used by format parents | 3 | We want to make sure access of job->aio_context is always done |
4 | (generally). We want to switch to a model where most parents use a | 4 | under either BQL or job_mutex. The problem is that using |
5 | single BdrvChildClass, which then decides the permissions based on the | 5 | aio_co_enter(job->aiocontext, job->co) in job_start and job_enter_cond |
6 | child role. To do so, we have to split bdrv_format_default_perms() into | 6 | makes the coroutine immediately resume, so we can't hold the job lock. |
7 | separate functions for each such role. | 7 | And caching it is not safe either, as it might change. |
8 | 8 | ||
9 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 9 | job_start is under BQL, so it can freely read job->aiocontext, but |
10 | Message-Id: <20200513110544.176672-17-mreitz@redhat.com> | 10 | job_enter_cond is not. |
11 | Reviewed-by: Eric Blake <eblake@redhat.com> | 11 | We want to avoid reading job->aio_context in job_enter_cond, therefore: |
12 | 1) use aio_co_wake(), since it doesn't want an aiocontext as argument | ||
13 | but uses job->co->ctx | ||
14 | 2) detect possible discrepancy between job->co->ctx and job->aio_context | ||
15 | by checking right after the coroutine resumes back from yielding if | ||
16 | job->aio_context has changed. If so, reschedule the coroutine to the | ||
17 | new context. | ||
18 | |||
19 | Calling bdrv_try_set_aio_context() will issue the following calls | ||
20 | (simplified): | ||
21 | * in terms of bdrv callbacks: | ||
22 | .drained_begin -> .set_aio_context -> .drained_end | ||
23 | * in terms of child_job functions: | ||
24 | child_job_drained_begin -> child_job_set_aio_context -> child_job_drained_end | ||
25 | * in terms of job functions: | ||
26 | job_pause_locked -> job_set_aio_context -> job_resume_locked | ||
27 | |||
28 | We can see that after setting the new aio_context, job_resume_locked | ||
29 | calls again job_enter_cond, which then invokes aio_co_wake(). But | ||
30 | while job->aiocontext has been set in job_set_aio_context, | ||
31 | job->co->ctx has not changed, so the coroutine would be entering in | ||
32 | the wrong aiocontext. | ||
33 | |||
34 | Using aio_co_schedule in job_resume_locked() might seem as a valid | ||
35 | alternative, but the problem is that the bh resuming the coroutine | ||
36 | is not scheduled immediately, and if in the meanwhile another | ||
37 | bdrv_try_set_aio_context() is run (see test_propagate_mirror() in | ||
38 | test-block-iothread.c), we would have the first schedule in the | ||
39 | wrong aiocontext, and the second set of drains won't even manage | ||
40 | to schedule the coroutine, as job->busy would still be true from | ||
41 | the previous job_resume_locked(). | ||
42 | |||
43 | The solution is to stick with aio_co_wake() and detect every time | ||
44 | the coroutine resumes back from yielding if job->aio_context | ||
45 | has changed. If so, we can reschedule it to the new context. | ||
46 | |||
47 | Check for the aiocontext change in job_do_yield_locked because: | ||
48 | 1) aio_co_reschedule_self requires to be in the running coroutine | ||
49 | 2) since child_job_set_aio_context allows changing the aiocontext only | ||
50 | while the job is paused, this is the exact place where the coroutine | ||
51 | resumes, before running JobDriver's code. | ||
52 | |||
53 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> | ||
54 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
55 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> | ||
56 | Message-Id: <20220926093214.506243-13-eesposit@redhat.com> | ||
57 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 58 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
13 | --- | 59 | --- |
14 | block.c | 62 +++++++++++++++++++++++++++++++++++++-------------------- | 60 | job.c | 19 +++++++++++++++++-- |
15 | 1 file changed, 40 insertions(+), 22 deletions(-) | 61 | 1 file changed, 17 insertions(+), 2 deletions(-) |
16 | 62 | ||
17 | diff --git a/block.c b/block.c | 63 | diff --git a/job.c b/job.c |
18 | index XXXXXXX..XXXXXXX 100644 | 64 | index XXXXXXX..XXXXXXX 100644 |
19 | --- a/block.c | 65 | --- a/job.c |
20 | +++ b/block.c | 66 | +++ b/job.c |
21 | @@ -XXX,XX +XXX,XX @@ void bdrv_filter_default_perms(BlockDriverState *bs, BdrvChild *c, | 67 | @@ -XXX,XX +XXX,XX @@ void job_enter_cond_locked(Job *job, bool(*fn)(Job *job)) |
22 | *nshared = (shared & DEFAULT_PERM_PASSTHROUGH) | DEFAULT_PERM_UNCHANGED; | 68 | job->busy = true; |
69 | real_job_unlock(); | ||
70 | job_unlock(); | ||
71 | - aio_co_enter(job->aio_context, job->co); | ||
72 | + aio_co_wake(job->co); | ||
73 | job_lock(); | ||
23 | } | 74 | } |
24 | 75 | ||
25 | +static void bdrv_default_perms_for_cow(BlockDriverState *bs, BdrvChild *c, | 76 | @@ -XXX,XX +XXX,XX @@ void job_enter(Job *job) |
26 | + const BdrvChildClass *child_class, | 77 | */ |
27 | + BdrvChildRole role, | 78 | static void coroutine_fn job_do_yield_locked(Job *job, uint64_t ns) |
28 | + BlockReopenQueue *reopen_queue, | 79 | { |
29 | + uint64_t perm, uint64_t shared, | 80 | + AioContext *next_aio_context; |
30 | + uint64_t *nperm, uint64_t *nshared) | ||
31 | +{ | ||
32 | + assert(child_class == &child_backing || | ||
33 | + (child_class == &child_of_bds && (role & BDRV_CHILD_COW))); | ||
34 | + | 81 | + |
82 | real_job_lock(); | ||
83 | if (ns != -1) { | ||
84 | timer_mod(&job->sleep_timer, ns); | ||
85 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn job_do_yield_locked(Job *job, uint64_t ns) | ||
86 | qemu_coroutine_yield(); | ||
87 | job_lock(); | ||
88 | |||
89 | - /* Set by job_enter_cond() before re-entering the coroutine. */ | ||
90 | + next_aio_context = job->aio_context; | ||
35 | + /* | 91 | + /* |
36 | + * We want consistent read from backing files if the parent needs it. | 92 | + * Coroutine has resumed, but in the meanwhile the job AioContext |
37 | + * No other operations are performed on backing files. | 93 | + * might have changed via bdrv_try_set_aio_context(), so we need to move |
94 | + * the coroutine too in the new aiocontext. | ||
38 | + */ | 95 | + */ |
39 | + perm &= BLK_PERM_CONSISTENT_READ; | 96 | + while (qemu_get_current_aio_context() != next_aio_context) { |
40 | + | 97 | + job_unlock(); |
41 | + /* | 98 | + aio_co_reschedule_self(next_aio_context); |
42 | + * If the parent can deal with changing data, we're okay with a | 99 | + job_lock(); |
43 | + * writable and resizable backing file. | 100 | + next_aio_context = job->aio_context; |
44 | + * TODO Require !(perm & BLK_PERM_CONSISTENT_READ), too? | ||
45 | + */ | ||
46 | + if (shared & BLK_PERM_WRITE) { | ||
47 | + shared = BLK_PERM_WRITE | BLK_PERM_RESIZE; | ||
48 | + } else { | ||
49 | + shared = 0; | ||
50 | + } | 101 | + } |
51 | + | 102 | + |
52 | + shared |= BLK_PERM_CONSISTENT_READ | BLK_PERM_GRAPH_MOD | | 103 | + /* Set by job_enter_cond_locked() before re-entering the coroutine. */ |
53 | + BLK_PERM_WRITE_UNCHANGED; | 104 | assert(job->busy); |
54 | + | ||
55 | + if (bs->open_flags & BDRV_O_INACTIVE) { | ||
56 | + shared |= BLK_PERM_WRITE | BLK_PERM_RESIZE; | ||
57 | + } | ||
58 | + | ||
59 | + *nperm = perm; | ||
60 | + *nshared = shared; | ||
61 | +} | ||
62 | + | ||
63 | void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c, | ||
64 | const BdrvChildClass *child_class, | ||
65 | BdrvChildRole role, | ||
66 | @@ -XXX,XX +XXX,XX @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c, | ||
67 | *nperm = perm; | ||
68 | *nshared = shared; | ||
69 | } else { | ||
70 | - /* We want consistent read from backing files if the parent needs it. | ||
71 | - * No other operations are performed on backing files. */ | ||
72 | - perm &= BLK_PERM_CONSISTENT_READ; | ||
73 | - | ||
74 | - /* If the parent can deal with changing data, we're okay with a | ||
75 | - * writable and resizable backing file. */ | ||
76 | - /* TODO Require !(perm & BLK_PERM_CONSISTENT_READ), too? */ | ||
77 | - if (shared & BLK_PERM_WRITE) { | ||
78 | - shared = BLK_PERM_WRITE | BLK_PERM_RESIZE; | ||
79 | - } else { | ||
80 | - shared = 0; | ||
81 | - } | ||
82 | - | ||
83 | - shared |= BLK_PERM_CONSISTENT_READ | BLK_PERM_GRAPH_MOD | | ||
84 | - BLK_PERM_WRITE_UNCHANGED; | ||
85 | - | ||
86 | - if (bs->open_flags & BDRV_O_INACTIVE) { | ||
87 | - shared |= BLK_PERM_WRITE | BLK_PERM_RESIZE; | ||
88 | - } | ||
89 | - | ||
90 | - *nperm = perm; | ||
91 | - *nshared = shared; | ||
92 | + bdrv_default_perms_for_cow(bs, c, child_class, role, reopen_queue, | ||
93 | + perm, shared, nperm, nshared); | ||
94 | } | ||
95 | } | 105 | } |
96 | 106 | ||
97 | -- | 107 | -- |
98 | 2.25.4 | 108 | 2.37.3 |
99 | |||
100 | diff view generated by jsdifflib |
1 | From: Max Reitz <mreitz@redhat.com> | 1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | For now, it is always set to 0. Later patches in this series will | 3 | In order to make it thread safe, implement a "fake rwlock", |
4 | ensure that all callers pass an appropriate combination of flags. | 4 | where we allow reads under BQL *or* job_mutex held, but |
5 | writes only under BQL *and* job_mutex. | ||
5 | 6 | ||
6 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 7 | The only write we have is in child_job_set_aio_ctx, which always |
7 | Reviewed-by: Eric Blake <eblake@redhat.com> | 8 | happens under drain (so the job is paused). |
8 | Message-Id: <20200513110544.176672-6-mreitz@redhat.com> | 9 | For this reason, introduce job_set_aio_context and make sure that |
10 | the context is set under BQL, job_mutex and drain. | ||
11 | Also make sure all other places where the aiocontext is read | ||
12 | are protected. | ||
13 | |||
14 | The reads in commit.c and mirror.c are actually safe, because always | ||
15 | done under BQL. | ||
16 | |||
17 | Note: at this stage, job_{lock/unlock} and job lock guard macros | ||
18 | are *nop*. | ||
19 | |||
20 | Suggested-by: Paolo Bonzini <pbonzini@redhat.com> | ||
21 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
22 | Message-Id: <20220926093214.506243-14-eesposit@redhat.com> | ||
23 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
24 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> | ||
9 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 25 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
10 | --- | 26 | --- |
11 | include/block/block.h | 2 ++ | 27 | include/qemu/job.h | 23 ++++++++++++++++++++--- |
12 | include/block/block_int.h | 2 ++ | 28 | block/replication.c | 1 + |
13 | block.c | 11 ++++++++--- | 29 | blockjob.c | 3 ++- |
14 | block/backup-top.c | 3 ++- | 30 | job.c | 12 ++++++++++++ |
15 | block/blkdebug.c | 2 +- | 31 | 4 files changed, 35 insertions(+), 4 deletions(-) |
16 | block/blklogwrites.c | 6 +++--- | ||
17 | block/blkreplay.c | 2 +- | ||
18 | block/blkverify.c | 4 ++-- | ||
19 | block/block-backend.c | 4 ++-- | ||
20 | block/bochs.c | 2 +- | ||
21 | block/cloop.c | 2 +- | ||
22 | block/copy-on-read.c | 2 +- | ||
23 | block/crypto.c | 2 +- | ||
24 | block/dmg.c | 2 +- | ||
25 | block/filter-compress.c | 2 +- | ||
26 | block/parallels.c | 2 +- | ||
27 | block/qcow.c | 2 +- | ||
28 | block/qcow2.c | 6 +++--- | ||
29 | block/qed.c | 2 +- | ||
30 | block/quorum.c | 4 ++-- | ||
31 | block/raw-format.c | 2 +- | ||
32 | block/replication.c | 2 +- | ||
33 | block/throttle.c | 2 +- | ||
34 | block/vdi.c | 2 +- | ||
35 | block/vhdx.c | 2 +- | ||
36 | block/vmdk.c | 4 ++-- | ||
37 | block/vpc.c | 2 +- | ||
38 | block/vvfat.c | 2 +- | ||
39 | blockjob.c | 5 +++-- | ||
40 | tests/test-bdrv-drain.c | 20 +++++++++++--------- | ||
41 | tests/test-bdrv-graph-mod.c | 4 ++-- | ||
42 | 31 files changed, 62 insertions(+), 49 deletions(-) | ||
43 | 32 | ||
44 | diff --git a/include/block/block.h b/include/block/block.h | 33 | diff --git a/include/qemu/job.h b/include/qemu/job.h |
45 | index XXXXXXX..XXXXXXX 100644 | 34 | index XXXXXXX..XXXXXXX 100644 |
46 | --- a/include/block/block.h | 35 | --- a/include/qemu/job.h |
47 | +++ b/include/block/block.h | 36 | +++ b/include/qemu/job.h |
48 | @@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_open_child(const char *filename, | 37 | @@ -XXX,XX +XXX,XX @@ typedef struct Job { |
49 | QDict *options, const char *bdref_key, | 38 | /* ProgressMeter API is thread-safe */ |
50 | BlockDriverState* parent, | 39 | ProgressMeter progress; |
51 | const BdrvChildClass *child_class, | 40 | |
52 | + BdrvChildRole child_role, | 41 | + /** |
53 | bool allow_none, Error **errp); | 42 | + * AioContext to run the job coroutine in. |
54 | BlockDriverState *bdrv_open_blockdev_ref(BlockdevRef *ref, Error **errp); | 43 | + * The job Aiocontext can be read when holding *either* |
55 | void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd, | 44 | + * the BQL (so we are in the main loop) or the job_mutex. |
56 | @@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs, | 45 | + * It can only be written when we hold *both* BQL |
57 | BlockDriverState *child_bs, | 46 | + * and the job_mutex. |
58 | const char *child_name, | 47 | + */ |
59 | const BdrvChildClass *child_class, | 48 | + AioContext *aio_context; |
60 | + BdrvChildRole child_role, | 49 | |
61 | Error **errp); | 50 | - /** Protected by AioContext lock */ |
62 | 51 | ||
63 | bool bdrv_op_is_blocked(BlockDriverState *bs, BlockOpType op, Error **errp); | 52 | - /** AioContext to run the job coroutine in */ |
64 | diff --git a/include/block/block_int.h b/include/block/block_int.h | 53 | - AioContext *aio_context; |
65 | index XXXXXXX..XXXXXXX 100644 | 54 | + /** Protected by AioContext lock */ |
66 | --- a/include/block/block_int.h | 55 | |
67 | +++ b/include/block/block_int.h | 56 | /** Reference count of the block job */ |
68 | @@ -XXX,XX +XXX,XX @@ struct BdrvChild { | 57 | int refcnt; |
69 | BlockDriverState *bs; | 58 | @@ -XXX,XX +XXX,XX @@ int job_finish_sync(Job *job, void (*finish)(Job *, Error **errp), |
70 | char *name; | 59 | int job_finish_sync_locked(Job *job, void (*finish)(Job *, Error **errp), |
71 | const BdrvChildClass *klass; | 60 | Error **errp); |
72 | + BdrvChildRole role; | 61 | |
73 | void *opaque; | 62 | +/** |
74 | 63 | + * Sets the @job->aio_context. | |
75 | /** | 64 | + * Called with job_mutex *not* held. |
76 | @@ -XXX,XX +XXX,XX @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, | 65 | + * |
77 | BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs, | 66 | + * This function must run in the main thread to protect against |
78 | const char *child_name, | 67 | + * concurrent read in job_finish_sync_locked(), takes the job_mutex |
79 | const BdrvChildClass *child_class, | 68 | + * lock to protect against the read in job_do_yield_locked(), and must |
80 | + BdrvChildRole child_role, | 69 | + * be called when the job is quiescent. |
81 | AioContext *ctx, | 70 | + */ |
82 | uint64_t perm, uint64_t shared_perm, | 71 | +void job_set_aio_context(Job *job, AioContext *ctx); |
83 | void *opaque, Error **errp); | 72 | + |
84 | diff --git a/block.c b/block.c | 73 | #endif |
85 | index XXXXXXX..XXXXXXX 100644 | ||
86 | --- a/block.c | ||
87 | +++ b/block.c | ||
88 | @@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child(BdrvChild *child, BlockDriverState *new_bs) | ||
89 | BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs, | ||
90 | const char *child_name, | ||
91 | const BdrvChildClass *child_class, | ||
92 | + BdrvChildRole child_role, | ||
93 | AioContext *ctx, | ||
94 | uint64_t perm, uint64_t shared_perm, | ||
95 | void *opaque, Error **errp) | ||
96 | @@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs, | ||
97 | .bs = NULL, | ||
98 | .name = g_strdup(child_name), | ||
99 | .klass = child_class, | ||
100 | + .role = child_role, | ||
101 | .perm = perm, | ||
102 | .shared_perm = shared_perm, | ||
103 | .opaque = opaque, | ||
104 | @@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs, | ||
105 | BlockDriverState *child_bs, | ||
106 | const char *child_name, | ||
107 | const BdrvChildClass *child_class, | ||
108 | + BdrvChildRole child_role, | ||
109 | Error **errp) | ||
110 | { | ||
111 | BdrvChild *child; | ||
112 | @@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs, | ||
113 | perm, shared_perm, &perm, &shared_perm); | ||
114 | |||
115 | child = bdrv_root_attach_child(child_bs, child_name, child_class, | ||
116 | - bdrv_get_aio_context(parent_bs), | ||
117 | + child_role, bdrv_get_aio_context(parent_bs), | ||
118 | perm, shared_perm, parent_bs, errp); | ||
119 | if (child == NULL) { | ||
120 | return NULL; | ||
121 | @@ -XXX,XX +XXX,XX @@ void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd, | ||
122 | } | ||
123 | |||
124 | bs->backing = bdrv_attach_child(bs, backing_hd, "backing", &child_backing, | ||
125 | - errp); | ||
126 | + 0, errp); | ||
127 | /* If backing_hd was already part of bs's backing chain, and | ||
128 | * inherits_from pointed recursively to bs then let's update it to | ||
129 | * point directly to bs (else it will become NULL). */ | ||
130 | @@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_open_child(const char *filename, | ||
131 | QDict *options, const char *bdref_key, | ||
132 | BlockDriverState *parent, | ||
133 | const BdrvChildClass *child_class, | ||
134 | + BdrvChildRole child_role, | ||
135 | bool allow_none, Error **errp) | ||
136 | { | ||
137 | BlockDriverState *bs; | ||
138 | @@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_open_child(const char *filename, | ||
139 | return NULL; | ||
140 | } | ||
141 | |||
142 | - return bdrv_attach_child(parent, bs, bdref_key, child_class, errp); | ||
143 | + return bdrv_attach_child(parent, bs, bdref_key, child_class, child_role, | ||
144 | + errp); | ||
145 | } | ||
146 | |||
147 | /* | ||
148 | diff --git a/block/backup-top.c b/block/backup-top.c | ||
149 | index XXXXXXX..XXXXXXX 100644 | ||
150 | --- a/block/backup-top.c | ||
151 | +++ b/block/backup-top.c | ||
152 | @@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_backup_top_append(BlockDriverState *source, | ||
153 | source->supported_zero_flags); | ||
154 | |||
155 | bdrv_ref(target); | ||
156 | - state->target = bdrv_attach_child(top, target, "target", &child_file, errp); | ||
157 | + state->target = bdrv_attach_child(top, target, "target", &child_file, 0, | ||
158 | + errp); | ||
159 | if (!state->target) { | ||
160 | bdrv_unref(target); | ||
161 | bdrv_unref(top); | ||
162 | diff --git a/block/blkdebug.c b/block/blkdebug.c | ||
163 | index XXXXXXX..XXXXXXX 100644 | ||
164 | --- a/block/blkdebug.c | ||
165 | +++ b/block/blkdebug.c | ||
166 | @@ -XXX,XX +XXX,XX @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags, | ||
167 | |||
168 | /* Open the image file */ | ||
169 | bs->file = bdrv_open_child(qemu_opt_get(opts, "x-image"), options, "image", | ||
170 | - bs, &child_file, false, &local_err); | ||
171 | + bs, &child_file, 0, false, &local_err); | ||
172 | if (local_err) { | ||
173 | ret = -EINVAL; | ||
174 | error_propagate(errp, local_err); | ||
175 | diff --git a/block/blklogwrites.c b/block/blklogwrites.c | ||
176 | index XXXXXXX..XXXXXXX 100644 | ||
177 | --- a/block/blklogwrites.c | ||
178 | +++ b/block/blklogwrites.c | ||
179 | @@ -XXX,XX +XXX,XX @@ static int blk_log_writes_open(BlockDriverState *bs, QDict *options, int flags, | ||
180 | } | ||
181 | |||
182 | /* Open the file */ | ||
183 | - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, false, | ||
184 | + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, false, | ||
185 | &local_err); | ||
186 | if (local_err) { | ||
187 | ret = -EINVAL; | ||
188 | @@ -XXX,XX +XXX,XX @@ static int blk_log_writes_open(BlockDriverState *bs, QDict *options, int flags, | ||
189 | } | ||
190 | |||
191 | /* Open the log file */ | ||
192 | - s->log_file = bdrv_open_child(NULL, options, "log", bs, &child_file, false, | ||
193 | - &local_err); | ||
194 | + s->log_file = bdrv_open_child(NULL, options, "log", bs, &child_file, 0, | ||
195 | + false, &local_err); | ||
196 | if (local_err) { | ||
197 | ret = -EINVAL; | ||
198 | error_propagate(errp, local_err); | ||
199 | diff --git a/block/blkreplay.c b/block/blkreplay.c | ||
200 | index XXXXXXX..XXXXXXX 100644 | ||
201 | --- a/block/blkreplay.c | ||
202 | +++ b/block/blkreplay.c | ||
203 | @@ -XXX,XX +XXX,XX @@ static int blkreplay_open(BlockDriverState *bs, QDict *options, int flags, | ||
204 | |||
205 | /* Open the image file */ | ||
206 | bs->file = bdrv_open_child(NULL, options, "image", | ||
207 | - bs, &child_file, false, &local_err); | ||
208 | + bs, &child_file, 0, false, &local_err); | ||
209 | if (local_err) { | ||
210 | ret = -EINVAL; | ||
211 | error_propagate(errp, local_err); | ||
212 | diff --git a/block/blkverify.c b/block/blkverify.c | ||
213 | index XXXXXXX..XXXXXXX 100644 | ||
214 | --- a/block/blkverify.c | ||
215 | +++ b/block/blkverify.c | ||
216 | @@ -XXX,XX +XXX,XX @@ static int blkverify_open(BlockDriverState *bs, QDict *options, int flags, | ||
217 | |||
218 | /* Open the raw file */ | ||
219 | bs->file = bdrv_open_child(qemu_opt_get(opts, "x-raw"), options, "raw", | ||
220 | - bs, &child_file, false, &local_err); | ||
221 | + bs, &child_file, 0, false, &local_err); | ||
222 | if (local_err) { | ||
223 | ret = -EINVAL; | ||
224 | error_propagate(errp, local_err); | ||
225 | @@ -XXX,XX +XXX,XX @@ static int blkverify_open(BlockDriverState *bs, QDict *options, int flags, | ||
226 | |||
227 | /* Open the test file */ | ||
228 | s->test_file = bdrv_open_child(qemu_opt_get(opts, "x-image"), options, | ||
229 | - "test", bs, &child_format, false, | ||
230 | + "test", bs, &child_format, 0, false, | ||
231 | &local_err); | ||
232 | if (local_err) { | ||
233 | ret = -EINVAL; | ||
234 | diff --git a/block/block-backend.c b/block/block-backend.c | ||
235 | index XXXXXXX..XXXXXXX 100644 | ||
236 | --- a/block/block-backend.c | ||
237 | +++ b/block/block-backend.c | ||
238 | @@ -XXX,XX +XXX,XX @@ BlockBackend *blk_new_open(const char *filename, const char *reference, | ||
239 | return NULL; | ||
240 | } | ||
241 | |||
242 | - blk->root = bdrv_root_attach_child(bs, "root", &child_root, blk->ctx, | ||
243 | + blk->root = bdrv_root_attach_child(bs, "root", &child_root, 0, blk->ctx, | ||
244 | perm, BLK_PERM_ALL, blk, errp); | ||
245 | if (!blk->root) { | ||
246 | blk_unref(blk); | ||
247 | @@ -XXX,XX +XXX,XX @@ int blk_insert_bs(BlockBackend *blk, BlockDriverState *bs, Error **errp) | ||
248 | { | ||
249 | ThrottleGroupMember *tgm = &blk->public.throttle_group_member; | ||
250 | bdrv_ref(bs); | ||
251 | - blk->root = bdrv_root_attach_child(bs, "root", &child_root, blk->ctx, | ||
252 | + blk->root = bdrv_root_attach_child(bs, "root", &child_root, 0, blk->ctx, | ||
253 | blk->perm, blk->shared_perm, blk, errp); | ||
254 | if (blk->root == NULL) { | ||
255 | return -EPERM; | ||
256 | diff --git a/block/bochs.c b/block/bochs.c | ||
257 | index XXXXXXX..XXXXXXX 100644 | ||
258 | --- a/block/bochs.c | ||
259 | +++ b/block/bochs.c | ||
260 | @@ -XXX,XX +XXX,XX @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags, | ||
261 | return ret; | ||
262 | } | ||
263 | |||
264 | - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, | ||
265 | + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, | ||
266 | false, errp); | ||
267 | if (!bs->file) { | ||
268 | return -EINVAL; | ||
269 | diff --git a/block/cloop.c b/block/cloop.c | ||
270 | index XXXXXXX..XXXXXXX 100644 | ||
271 | --- a/block/cloop.c | ||
272 | +++ b/block/cloop.c | ||
273 | @@ -XXX,XX +XXX,XX @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags, | ||
274 | return ret; | ||
275 | } | ||
276 | |||
277 | - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, | ||
278 | + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, | ||
279 | false, errp); | ||
280 | if (!bs->file) { | ||
281 | return -EINVAL; | ||
282 | diff --git a/block/copy-on-read.c b/block/copy-on-read.c | ||
283 | index XXXXXXX..XXXXXXX 100644 | ||
284 | --- a/block/copy-on-read.c | ||
285 | +++ b/block/copy-on-read.c | ||
286 | @@ -XXX,XX +XXX,XX @@ | ||
287 | static int cor_open(BlockDriverState *bs, QDict *options, int flags, | ||
288 | Error **errp) | ||
289 | { | ||
290 | - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, false, | ||
291 | + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, false, | ||
292 | errp); | ||
293 | if (!bs->file) { | ||
294 | return -EINVAL; | ||
295 | diff --git a/block/crypto.c b/block/crypto.c | ||
296 | index XXXXXXX..XXXXXXX 100644 | ||
297 | --- a/block/crypto.c | ||
298 | +++ b/block/crypto.c | ||
299 | @@ -XXX,XX +XXX,XX @@ static int block_crypto_open_generic(QCryptoBlockFormat format, | ||
300 | unsigned int cflags = 0; | ||
301 | QDict *cryptoopts = NULL; | ||
302 | |||
303 | - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, | ||
304 | + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, | ||
305 | false, errp); | ||
306 | if (!bs->file) { | ||
307 | return -EINVAL; | ||
308 | diff --git a/block/dmg.c b/block/dmg.c | ||
309 | index XXXXXXX..XXXXXXX 100644 | ||
310 | --- a/block/dmg.c | ||
311 | +++ b/block/dmg.c | ||
312 | @@ -XXX,XX +XXX,XX @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags, | ||
313 | return ret; | ||
314 | } | ||
315 | |||
316 | - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, | ||
317 | + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, | ||
318 | false, errp); | ||
319 | if (!bs->file) { | ||
320 | return -EINVAL; | ||
321 | diff --git a/block/filter-compress.c b/block/filter-compress.c | ||
322 | index XXXXXXX..XXXXXXX 100644 | ||
323 | --- a/block/filter-compress.c | ||
324 | +++ b/block/filter-compress.c | ||
325 | @@ -XXX,XX +XXX,XX @@ | ||
326 | static int compress_open(BlockDriverState *bs, QDict *options, int flags, | ||
327 | Error **errp) | ||
328 | { | ||
329 | - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, false, | ||
330 | + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, false, | ||
331 | errp); | ||
332 | if (!bs->file) { | ||
333 | return -EINVAL; | ||
334 | diff --git a/block/parallels.c b/block/parallels.c | ||
335 | index XXXXXXX..XXXXXXX 100644 | ||
336 | --- a/block/parallels.c | ||
337 | +++ b/block/parallels.c | ||
338 | @@ -XXX,XX +XXX,XX @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags, | ||
339 | Error *local_err = NULL; | ||
340 | char *buf; | ||
341 | |||
342 | - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, | ||
343 | + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, | ||
344 | false, errp); | ||
345 | if (!bs->file) { | ||
346 | return -EINVAL; | ||
347 | diff --git a/block/qcow.c b/block/qcow.c | ||
348 | index XXXXXXX..XXXXXXX 100644 | ||
349 | --- a/block/qcow.c | ||
350 | +++ b/block/qcow.c | ||
351 | @@ -XXX,XX +XXX,XX @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags, | ||
352 | qdict_extract_subqdict(options, &encryptopts, "encrypt."); | ||
353 | encryptfmt = qdict_get_try_str(encryptopts, "format"); | ||
354 | |||
355 | - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, | ||
356 | + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, | ||
357 | false, errp); | ||
358 | if (!bs->file) { | ||
359 | ret = -EINVAL; | ||
360 | diff --git a/block/qcow2.c b/block/qcow2.c | ||
361 | index XXXXXXX..XXXXXXX 100644 | ||
362 | --- a/block/qcow2.c | ||
363 | +++ b/block/qcow2.c | ||
364 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options, | ||
365 | |||
366 | /* Open external data file */ | ||
367 | s->data_file = bdrv_open_child(NULL, options, "data-file", bs, &child_file, | ||
368 | - true, &local_err); | ||
369 | + 0, true, &local_err); | ||
370 | if (local_err) { | ||
371 | error_propagate(errp, local_err); | ||
372 | ret = -EINVAL; | ||
373 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options, | ||
374 | if (s->incompatible_features & QCOW2_INCOMPAT_DATA_FILE) { | ||
375 | if (!s->data_file && s->image_data_file) { | ||
376 | s->data_file = bdrv_open_child(s->image_data_file, options, | ||
377 | - "data-file", bs, &child_file, | ||
378 | + "data-file", bs, &child_file, 0, | ||
379 | false, errp); | ||
380 | if (!s->data_file) { | ||
381 | ret = -EINVAL; | ||
382 | @@ -XXX,XX +XXX,XX @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags, | ||
383 | .ret = -EINPROGRESS | ||
384 | }; | ||
385 | |||
386 | - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, | ||
387 | + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, | ||
388 | false, errp); | ||
389 | if (!bs->file) { | ||
390 | return -EINVAL; | ||
391 | diff --git a/block/qed.c b/block/qed.c | ||
392 | index XXXXXXX..XXXXXXX 100644 | ||
393 | --- a/block/qed.c | ||
394 | +++ b/block/qed.c | ||
395 | @@ -XXX,XX +XXX,XX @@ static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags, | ||
396 | .ret = -EINPROGRESS | ||
397 | }; | ||
398 | |||
399 | - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, | ||
400 | + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, | ||
401 | false, errp); | ||
402 | if (!bs->file) { | ||
403 | return -EINVAL; | ||
404 | diff --git a/block/quorum.c b/block/quorum.c | ||
405 | index XXXXXXX..XXXXXXX 100644 | ||
406 | --- a/block/quorum.c | ||
407 | +++ b/block/quorum.c | ||
408 | @@ -XXX,XX +XXX,XX @@ static int quorum_open(BlockDriverState *bs, QDict *options, int flags, | ||
409 | assert(ret < 32); | ||
410 | |||
411 | s->children[i] = bdrv_open_child(NULL, options, indexstr, bs, | ||
412 | - &child_format, false, &local_err); | ||
413 | + &child_format, 0, false, &local_err); | ||
414 | if (local_err) { | ||
415 | ret = -EINVAL; | ||
416 | goto close_exit; | ||
417 | @@ -XXX,XX +XXX,XX @@ static void quorum_add_child(BlockDriverState *bs, BlockDriverState *child_bs, | ||
418 | /* We can safely add the child now */ | ||
419 | bdrv_ref(child_bs); | ||
420 | |||
421 | - child = bdrv_attach_child(bs, child_bs, indexstr, &child_format, errp); | ||
422 | + child = bdrv_attach_child(bs, child_bs, indexstr, &child_format, 0, errp); | ||
423 | if (child == NULL) { | ||
424 | s->next_child_index--; | ||
425 | goto out; | ||
426 | diff --git a/block/raw-format.c b/block/raw-format.c | ||
427 | index XXXXXXX..XXXXXXX 100644 | ||
428 | --- a/block/raw-format.c | ||
429 | +++ b/block/raw-format.c | ||
430 | @@ -XXX,XX +XXX,XX @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags, | ||
431 | BDRVRawState *s = bs->opaque; | ||
432 | int ret; | ||
433 | |||
434 | - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, | ||
435 | + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, | ||
436 | false, errp); | ||
437 | if (!bs->file) { | ||
438 | return -EINVAL; | ||
439 | diff --git a/block/replication.c b/block/replication.c | 74 | diff --git a/block/replication.c b/block/replication.c |
440 | index XXXXXXX..XXXXXXX 100644 | 75 | index XXXXXXX..XXXXXXX 100644 |
441 | --- a/block/replication.c | 76 | --- a/block/replication.c |
442 | +++ b/block/replication.c | 77 | +++ b/block/replication.c |
443 | @@ -XXX,XX +XXX,XX @@ static int replication_open(BlockDriverState *bs, QDict *options, | 78 | @@ -XXX,XX +XXX,XX @@ static void replication_close(BlockDriverState *bs) |
444 | const char *mode; | 79 | { |
445 | const char *top_id; | 80 | BDRVReplicationState *s = bs->opaque; |
446 | 81 | Job *commit_job; | |
447 | - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, | 82 | + GLOBAL_STATE_CODE(); |
448 | + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, | 83 | |
449 | false, errp); | 84 | if (s->stage == BLOCK_REPLICATION_RUNNING) { |
450 | if (!bs->file) { | 85 | replication_stop(s->rs, false, NULL); |
451 | return -EINVAL; | ||
452 | diff --git a/block/throttle.c b/block/throttle.c | ||
453 | index XXXXXXX..XXXXXXX 100644 | ||
454 | --- a/block/throttle.c | ||
455 | +++ b/block/throttle.c | ||
456 | @@ -XXX,XX +XXX,XX @@ static int throttle_open(BlockDriverState *bs, QDict *options, | ||
457 | int ret; | ||
458 | |||
459 | bs->file = bdrv_open_child(NULL, options, "file", bs, | ||
460 | - &child_file, false, errp); | ||
461 | + &child_file, 0, false, errp); | ||
462 | if (!bs->file) { | ||
463 | return -EINVAL; | ||
464 | } | ||
465 | diff --git a/block/vdi.c b/block/vdi.c | ||
466 | index XXXXXXX..XXXXXXX 100644 | ||
467 | --- a/block/vdi.c | ||
468 | +++ b/block/vdi.c | ||
469 | @@ -XXX,XX +XXX,XX @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags, | ||
470 | Error *local_err = NULL; | ||
471 | QemuUUID uuid_link, uuid_parent; | ||
472 | |||
473 | - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, | ||
474 | + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, | ||
475 | false, errp); | ||
476 | if (!bs->file) { | ||
477 | return -EINVAL; | ||
478 | diff --git a/block/vhdx.c b/block/vhdx.c | ||
479 | index XXXXXXX..XXXXXXX 100644 | ||
480 | --- a/block/vhdx.c | ||
481 | +++ b/block/vhdx.c | ||
482 | @@ -XXX,XX +XXX,XX @@ static int vhdx_open(BlockDriverState *bs, QDict *options, int flags, | ||
483 | uint64_t signature; | ||
484 | Error *local_err = NULL; | ||
485 | |||
486 | - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, | ||
487 | + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, | ||
488 | false, errp); | ||
489 | if (!bs->file) { | ||
490 | return -EINVAL; | ||
491 | diff --git a/block/vmdk.c b/block/vmdk.c | ||
492 | index XXXXXXX..XXXXXXX 100644 | ||
493 | --- a/block/vmdk.c | ||
494 | +++ b/block/vmdk.c | ||
495 | @@ -XXX,XX +XXX,XX @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs, | ||
496 | assert(ret < 32); | ||
497 | |||
498 | extent_file = bdrv_open_child(extent_path, options, extent_opt_prefix, | ||
499 | - bs, &child_file, false, &local_err); | ||
500 | + bs, &child_file, 0, false, &local_err); | ||
501 | g_free(extent_path); | ||
502 | if (local_err) { | ||
503 | error_propagate(errp, local_err); | ||
504 | @@ -XXX,XX +XXX,XX @@ static int vmdk_open(BlockDriverState *bs, QDict *options, int flags, | ||
505 | uint32_t magic; | ||
506 | Error *local_err = NULL; | ||
507 | |||
508 | - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, | ||
509 | + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, | ||
510 | false, errp); | ||
511 | if (!bs->file) { | ||
512 | return -EINVAL; | ||
513 | diff --git a/block/vpc.c b/block/vpc.c | ||
514 | index XXXXXXX..XXXXXXX 100644 | ||
515 | --- a/block/vpc.c | ||
516 | +++ b/block/vpc.c | ||
517 | @@ -XXX,XX +XXX,XX @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags, | ||
518 | int ret; | ||
519 | int64_t bs_size; | ||
520 | |||
521 | - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, | ||
522 | + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, | ||
523 | false, errp); | ||
524 | if (!bs->file) { | ||
525 | return -EINVAL; | ||
526 | diff --git a/block/vvfat.c b/block/vvfat.c | ||
527 | index XXXXXXX..XXXXXXX 100644 | ||
528 | --- a/block/vvfat.c | ||
529 | +++ b/block/vvfat.c | ||
530 | @@ -XXX,XX +XXX,XX @@ static int enable_write_target(BlockDriverState *bs, Error **errp) | ||
531 | options = qdict_new(); | ||
532 | qdict_put_str(options, "write-target.driver", "qcow"); | ||
533 | s->qcow = bdrv_open_child(s->qcow_filename, options, "write-target", bs, | ||
534 | - &child_vvfat_qcow, false, errp); | ||
535 | + &child_vvfat_qcow, 0, false, errp); | ||
536 | qobject_unref(options); | ||
537 | if (!s->qcow) { | ||
538 | ret = -EINVAL; | ||
539 | diff --git a/blockjob.c b/blockjob.c | 86 | diff --git a/blockjob.c b/blockjob.c |
540 | index XXXXXXX..XXXXXXX 100644 | 87 | index XXXXXXX..XXXXXXX 100644 |
541 | --- a/blockjob.c | 88 | --- a/blockjob.c |
542 | +++ b/blockjob.c | 89 | +++ b/blockjob.c |
543 | @@ -XXX,XX +XXX,XX @@ int block_job_add_bdrv(BlockJob *job, const char *name, BlockDriverState *bs, | 90 | @@ -XXX,XX +XXX,XX @@ static void child_job_set_aio_ctx(BdrvChild *c, AioContext *ctx, |
544 | if (job->job.aio_context != qemu_get_aio_context()) { | 91 | bdrv_set_aio_context_ignore(sibling->bs, ctx, ignore); |
545 | aio_context_release(job->job.aio_context); | ||
546 | } | 92 | } |
547 | - c = bdrv_root_attach_child(bs, name, &child_job, job->job.aio_context, | 93 | |
548 | - perm, shared_perm, job, errp); | 94 | - job->job.aio_context = ctx; |
549 | + c = bdrv_root_attach_child(bs, name, &child_job, 0, | 95 | + job_set_aio_context(&job->job, ctx); |
550 | + job->job.aio_context, perm, shared_perm, job, | 96 | } |
551 | + errp); | 97 | |
552 | if (job->job.aio_context != qemu_get_aio_context()) { | 98 | static AioContext *child_job_get_parent_aio_context(BdrvChild *c) |
553 | aio_context_acquire(job->job.aio_context); | 99 | { |
554 | } | 100 | BlockJob *job = c->opaque; |
555 | diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c | 101 | + GLOBAL_STATE_CODE(); |
102 | |||
103 | return job->job.aio_context; | ||
104 | } | ||
105 | diff --git a/job.c b/job.c | ||
556 | index XXXXXXX..XXXXXXX 100644 | 106 | index XXXXXXX..XXXXXXX 100644 |
557 | --- a/tests/test-bdrv-drain.c | 107 | --- a/job.c |
558 | +++ b/tests/test-bdrv-drain.c | 108 | +++ b/job.c |
559 | @@ -XXX,XX +XXX,XX @@ static void do_test_delete_by_drain(bool detach_instead_of_delete, | 109 | @@ -XXX,XX +XXX,XX @@ Job *job_get(const char *id) |
560 | 110 | return job_get_locked(id); | |
561 | null_bs = bdrv_open("null-co://", NULL, NULL, BDRV_O_RDWR | BDRV_O_PROTOCOL, | ||
562 | &error_abort); | ||
563 | - bdrv_attach_child(bs, null_bs, "null-child", &child_file, &error_abort); | ||
564 | + bdrv_attach_child(bs, null_bs, "null-child", &child_file, 0, &error_abort); | ||
565 | |||
566 | /* This child will be the one to pass to requests through to, and | ||
567 | * it will stall until a drain occurs */ | ||
568 | @@ -XXX,XX +XXX,XX @@ static void do_test_delete_by_drain(bool detach_instead_of_delete, | ||
569 | child_bs->total_sectors = 65536 >> BDRV_SECTOR_BITS; | ||
570 | /* Takes our reference to child_bs */ | ||
571 | tts->wait_child = bdrv_attach_child(bs, child_bs, "wait-child", &child_file, | ||
572 | - &error_abort); | ||
573 | + 0, &error_abort); | ||
574 | |||
575 | /* This child is just there to be deleted | ||
576 | * (for detach_instead_of_delete == true) */ | ||
577 | null_bs = bdrv_open("null-co://", NULL, NULL, BDRV_O_RDWR | BDRV_O_PROTOCOL, | ||
578 | &error_abort); | ||
579 | - bdrv_attach_child(bs, null_bs, "null-child", &child_file, &error_abort); | ||
580 | + bdrv_attach_child(bs, null_bs, "null-child", &child_file, 0, &error_abort); | ||
581 | |||
582 | blk = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL); | ||
583 | blk_insert_bs(blk, bs, &error_abort); | ||
584 | @@ -XXX,XX +XXX,XX @@ static void detach_indirect_bh(void *opaque) | ||
585 | |||
586 | bdrv_ref(data->c); | ||
587 | data->child_c = bdrv_attach_child(data->parent_b, data->c, "PB-C", | ||
588 | - &child_file, &error_abort); | ||
589 | + &child_file, 0, &error_abort); | ||
590 | } | 111 | } |
591 | 112 | ||
592 | static void detach_by_parent_aio_cb(void *opaque, int ret) | 113 | +void job_set_aio_context(Job *job, AioContext *ctx) |
593 | @@ -XXX,XX +XXX,XX @@ static void test_detach_indirect(bool by_parent_cb) | 114 | +{ |
594 | /* Set child relationships */ | 115 | + /* protect against read in job_finish_sync_locked and job_start */ |
595 | bdrv_ref(b); | 116 | + GLOBAL_STATE_CODE(); |
596 | bdrv_ref(a); | 117 | + /* protect against read in job_do_yield_locked */ |
597 | - child_b = bdrv_attach_child(parent_b, b, "PB-B", &child_file, &error_abort); | 118 | + JOB_LOCK_GUARD(); |
598 | - child_a = bdrv_attach_child(parent_b, a, "PB-A", &child_backing, &error_abort); | 119 | + /* ensure the job is quiescent while the AioContext is changed */ |
599 | + child_b = bdrv_attach_child(parent_b, b, "PB-B", &child_file, 0, | 120 | + assert(job->paused || job_is_completed_locked(job)); |
600 | + &error_abort); | 121 | + job->aio_context = ctx; |
601 | + child_a = bdrv_attach_child(parent_b, a, "PB-A", &child_backing, 0, | 122 | +} |
602 | + &error_abort); | 123 | + |
603 | 124 | /* Called with job_mutex *not* held. */ | |
604 | bdrv_ref(a); | 125 | static void job_sleep_timer_cb(void *opaque) |
605 | bdrv_attach_child(parent_a, a, "PA-A", | 126 | { |
606 | by_parent_cb ? &child_file : &detach_by_driver_cb_class, | 127 | @@ -XXX,XX +XXX,XX @@ int job_finish_sync_locked(Job *job, |
607 | - &error_abort); | 128 | { |
608 | + 0, &error_abort); | 129 | Error *local_err = NULL; |
609 | 130 | int ret; | |
610 | g_assert_cmpint(parent_a->refcnt, ==, 1); | 131 | + GLOBAL_STATE_CODE(); |
611 | g_assert_cmpint(parent_b->refcnt, ==, 1); | 132 | |
612 | @@ -XXX,XX +XXX,XX @@ static void test_drop_intermediate_poll(void) | 133 | job_ref_locked(job); |
613 | /* Takes the reference to chain[i - 1] */ | ||
614 | chain[i]->backing = bdrv_attach_child(chain[i], chain[i - 1], | ||
615 | "chain", &chain_child_class, | ||
616 | - &error_abort); | ||
617 | + 0, &error_abort); | ||
618 | } | ||
619 | } | ||
620 | |||
621 | @@ -XXX,XX +XXX,XX @@ static void do_test_replace_child_mid_drain(int old_drain_count, | ||
622 | |||
623 | bdrv_ref(old_child_bs); | ||
624 | parent_bs->backing = bdrv_attach_child(parent_bs, old_child_bs, "child", | ||
625 | - &child_backing, &error_abort); | ||
626 | + &child_backing, 0, &error_abort); | ||
627 | |||
628 | for (i = 0; i < old_drain_count; i++) { | ||
629 | bdrv_drained_begin(old_child_bs); | ||
630 | diff --git a/tests/test-bdrv-graph-mod.c b/tests/test-bdrv-graph-mod.c | ||
631 | index XXXXXXX..XXXXXXX 100644 | ||
632 | --- a/tests/test-bdrv-graph-mod.c | ||
633 | +++ b/tests/test-bdrv-graph-mod.c | ||
634 | @@ -XXX,XX +XXX,XX @@ static void test_update_perm_tree(void) | ||
635 | |||
636 | blk_insert_bs(root, bs, &error_abort); | ||
637 | |||
638 | - bdrv_attach_child(filter, bs, "child", &child_file, &error_abort); | ||
639 | + bdrv_attach_child(filter, bs, "child", &child_file, 0, &error_abort); | ||
640 | |||
641 | bdrv_append(filter, bs, &local_err); | ||
642 | |||
643 | @@ -XXX,XX +XXX,XX @@ static void test_should_update_child(void) | ||
644 | bdrv_set_backing_hd(target, bs, &error_abort); | ||
645 | |||
646 | g_assert(target->backing->bs == bs); | ||
647 | - bdrv_attach_child(filter, target, "target", &child_file, &error_abort); | ||
648 | + bdrv_attach_child(filter, target, "target", &child_file, 0, &error_abort); | ||
649 | bdrv_append(filter, bs, &error_abort); | ||
650 | g_assert(target->backing->bs == bs); | ||
651 | 134 | ||
652 | -- | 135 | -- |
653 | 2.25.4 | 136 | 2.37.3 |
654 | |||
655 | diff view generated by jsdifflib |
1 | We need to fix only a few places so that iotests.py can pass | 1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
---|---|---|---|
2 | mypy --disallow-incomplete-defs, which seems to be a desirable option to | ||
3 | have enabled in the long run. | ||
4 | 2 | ||
5 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 3 | The same job lock is being used also to protect some of blockjob fields. |
6 | Message-Id: <20200511163529.349329-2-kwolf@redhat.com> | 4 | Categorize them just as done in job.h. |
7 | Reviewed-by: Max Reitz <mreitz@redhat.com> | 5 | |
8 | Reviewed-by: John Snow <jsnow@redhat.com> | 6 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> |
7 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
8 | Message-Id: <20220926093214.506243-15-eesposit@redhat.com> | ||
9 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
9 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
10 | --- | 11 | --- |
11 | tests/qemu-iotests/iotests.py | 8 ++++---- | 12 | include/block/blockjob.h | 32 ++++++++++++++++++++++++++------ |
12 | 1 file changed, 4 insertions(+), 4 deletions(-) | 13 | 1 file changed, 26 insertions(+), 6 deletions(-) |
13 | 14 | ||
14 | diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py | 15 | diff --git a/include/block/blockjob.h b/include/block/blockjob.h |
15 | index XXXXXXX..XXXXXXX 100644 | 16 | index XXXXXXX..XXXXXXX 100644 |
16 | --- a/tests/qemu-iotests/iotests.py | 17 | --- a/include/block/blockjob.h |
17 | +++ b/tests/qemu-iotests/iotests.py | 18 | +++ b/include/block/blockjob.h |
18 | @@ -XXX,XX +XXX,XX @@ def _verify_cache_mode(supported_cache_modes: Sequence[str] = ()) -> None: | 19 | @@ -XXX,XX +XXX,XX @@ typedef struct BlockJobDriver BlockJobDriver; |
19 | if supported_cache_modes and (cachemode not in supported_cache_modes): | 20 | * Long-running operation on a BlockDriverState. |
20 | notrun('not suitable for this cache mode: %s' % cachemode) | 21 | */ |
21 | 22 | typedef struct BlockJob { | |
22 | -def _verify_aio_mode(supported_aio_modes: Sequence[str] = ()): | 23 | - /** Data belonging to the generic Job infrastructure */ |
23 | +def _verify_aio_mode(supported_aio_modes: Sequence[str] = ()) -> None: | 24 | + /** |
24 | if supported_aio_modes and (aiomode not in supported_aio_modes): | 25 | + * Data belonging to the generic Job infrastructure. |
25 | notrun('not suitable for this aio mode: %s' % aiomode) | 26 | + * Protected by job mutex. |
26 | 27 | + */ | |
27 | @@ -XXX,XX +XXX,XX @@ def skip_if_unsupported(required_formats=(), read_only=False): | 28 | Job job; |
28 | '''Skip Test Decorator | 29 | |
29 | Runs the test if all the required formats are whitelisted''' | 30 | - /** Status that is published by the query-block-jobs QMP API */ |
30 | def skip_test_decorator(func): | 31 | + /** |
31 | - def func_wrapper(test_case: QMPTestCase, *args, **kwargs): | 32 | + * Status that is published by the query-block-jobs QMP API. |
32 | + def func_wrapper(test_case: QMPTestCase, *args: List[Any], | 33 | + * Protected by job mutex. |
33 | + **kwargs: Dict[str, Any]) -> None: | 34 | + */ |
34 | if callable(required_formats): | 35 | BlockDeviceIoStatus iostatus; |
35 | fmts = required_formats(test_case) | 36 | |
36 | else: | 37 | - /** Speed that was set with @block_job_set_speed. */ |
37 | @@ -XXX,XX +XXX,XX @@ def skip_if_unsupported(required_formats=(), read_only=False): | 38 | + /** |
38 | if usf_list: | 39 | + * Speed that was set with @block_job_set_speed. |
39 | msg = f'{test_case}: formats {usf_list} are not whitelisted' | 40 | + * Always modified and read under QEMU global mutex (GLOBAL_STATE_CODE). |
40 | test_case.case_skip(msg) | 41 | + */ |
41 | - return None | 42 | int64_t speed; |
42 | else: | 43 | |
43 | - return func(test_case, *args, **kwargs) | 44 | - /** Rate limiting data structure for implementing @speed. */ |
44 | + func(test_case, *args, **kwargs) | 45 | + /** |
45 | return func_wrapper | 46 | + * Rate limiting data structure for implementing @speed. |
46 | return skip_test_decorator | 47 | + * RateLimit API is thread-safe. |
48 | + */ | ||
49 | RateLimit limit; | ||
50 | |||
51 | - /** Block other operations when block job is running */ | ||
52 | + /** | ||
53 | + * Block other operations when block job is running. | ||
54 | + * Always modified and read under QEMU global mutex (GLOBAL_STATE_CODE). | ||
55 | + */ | ||
56 | Error *blocker; | ||
57 | |||
58 | + /** All notifiers are set once in block_job_create() and never modified. */ | ||
59 | + | ||
60 | /** Called when a cancelled job is finalised. */ | ||
61 | Notifier finalize_cancelled_notifier; | ||
62 | |||
63 | @@ -XXX,XX +XXX,XX @@ typedef struct BlockJob { | ||
64 | /** Called when the job coroutine yields or terminates */ | ||
65 | Notifier idle_notifier; | ||
66 | |||
67 | - /** BlockDriverStates that are involved in this block job */ | ||
68 | + /** | ||
69 | + * BlockDriverStates that are involved in this block job. | ||
70 | + * Always modified and read under QEMU global mutex (GLOBAL_STATE_CODE). | ||
71 | + */ | ||
72 | GSList *nodes; | ||
73 | } BlockJob; | ||
47 | 74 | ||
48 | -- | 75 | -- |
49 | 2.25.4 | 76 | 2.37.3 |
50 | |||
51 | diff view generated by jsdifflib |
1 | From: Max Reitz <mreitz@redhat.com> | 1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | We plan to unify the generic .inherit_options() functions. The | 3 | They all are called with job_lock held, in job_event_*_locked() |
4 | resulting common function will need to decide whether to force-enable | ||
5 | format probing, force-disable it, or leave it as-is. To make this | ||
6 | decision, it will need to know whether the parent node is a format node | ||
7 | or not (because we never want format probing if the parent is a format | ||
8 | node already (except for the backing chain)). | ||
9 | 4 | ||
10 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 5 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
11 | Reviewed-by: Eric Blake <eblake@redhat.com> | 6 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> |
12 | Message-Id: <20200513110544.176672-9-mreitz@redhat.com> | 7 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> |
8 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
9 | Message-Id: <20220926093214.506243-16-eesposit@redhat.com> | ||
13 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
14 | --- | 11 | --- |
15 | include/block/block_int.h | 2 +- | 12 | blockjob.c | 25 +++++++++++++++---------- |
16 | block.c | 37 +++++++++++++++++++++++++++---------- | 13 | 1 file changed, 15 insertions(+), 10 deletions(-) |
17 | block/block-backend.c | 2 +- | ||
18 | block/vvfat.c | 2 +- | ||
19 | 4 files changed, 30 insertions(+), 13 deletions(-) | ||
20 | 14 | ||
21 | diff --git a/include/block/block_int.h b/include/block/block_int.h | 15 | diff --git a/blockjob.c b/blockjob.c |
22 | index XXXXXXX..XXXXXXX 100644 | 16 | index XXXXXXX..XXXXXXX 100644 |
23 | --- a/include/block/block_int.h | 17 | --- a/blockjob.c |
24 | +++ b/include/block/block_int.h | 18 | +++ b/blockjob.c |
25 | @@ -XXX,XX +XXX,XX @@ struct BdrvChildClass { | 19 | @@ -XXX,XX +XXX,XX @@ int block_job_add_bdrv(BlockJob *job, const char *name, BlockDriverState *bs, |
26 | * non-BDS parents. */ | 20 | return 0; |
27 | bool parent_is_bds; | 21 | } |
28 | 22 | ||
29 | - void (*inherit_options)(BdrvChildRole role, | 23 | -static void block_job_on_idle(Notifier *n, void *opaque) |
30 | + void (*inherit_options)(BdrvChildRole role, bool parent_is_format, | 24 | +/* Called with job_mutex lock held. */ |
31 | int *child_flags, QDict *child_options, | 25 | +static void block_job_on_idle_locked(Notifier *n, void *opaque) |
32 | int parent_flags, QDict *parent_options); | ||
33 | |||
34 | diff --git a/block.c b/block.c | ||
35 | index XXXXXXX..XXXXXXX 100644 | ||
36 | --- a/block.c | ||
37 | +++ b/block.c | ||
38 | @@ -XXX,XX +XXX,XX @@ static void bdrv_temp_snapshot_options(int *child_flags, QDict *child_options, | ||
39 | * Returns the options and flags that bs->file should get if a protocol driver | ||
40 | * is expected, based on the given options and flags for the parent BDS | ||
41 | */ | ||
42 | -static void bdrv_inherited_options(BdrvChildRole role, | ||
43 | +static void bdrv_inherited_options(BdrvChildRole role, bool parent_is_format, | ||
44 | int *child_flags, QDict *child_options, | ||
45 | int parent_flags, QDict *parent_options) | ||
46 | { | 26 | { |
47 | @@ -XXX,XX +XXX,XX @@ const BdrvChildClass child_file = { | 27 | aio_wait_kick(); |
48 | * flags for the parent BDS | 28 | } |
49 | */ | 29 | @@ -XXX,XX +XXX,XX @@ static void block_job_iostatus_set_err(BlockJob *job, int error) |
50 | static void bdrv_inherited_fmt_options(BdrvChildRole role, | 30 | } |
51 | + bool parent_is_format, | 31 | } |
52 | int *child_flags, QDict *child_options, | 32 | |
53 | int parent_flags, QDict *parent_options) | 33 | -static void block_job_event_cancelled(Notifier *n, void *opaque) |
34 | +/* Called with job_mutex lock held. */ | ||
35 | +static void block_job_event_cancelled_locked(Notifier *n, void *opaque) | ||
54 | { | 36 | { |
55 | - child_file.inherit_options(role, child_flags, child_options, | 37 | BlockJob *job = opaque; |
56 | + child_file.inherit_options(role, parent_is_format, | 38 | uint64_t progress_current, progress_total; |
57 | + child_flags, child_options, | 39 | @@ -XXX,XX +XXX,XX @@ static void block_job_event_cancelled(Notifier *n, void *opaque) |
58 | parent_flags, parent_options); | 40 | job->speed); |
59 | 41 | } | |
60 | *child_flags &= ~(BDRV_O_PROTOCOL | BDRV_O_NO_IO); | 42 | |
61 | @@ -XXX,XX +XXX,XX @@ static void bdrv_backing_detach(BdrvChild *c) | 43 | -static void block_job_event_completed(Notifier *n, void *opaque) |
62 | * Returns the options and flags that bs->backing should get, based on the | 44 | +/* Called with job_mutex lock held. */ |
63 | * given options and flags for the parent BDS | 45 | +static void block_job_event_completed_locked(Notifier *n, void *opaque) |
64 | */ | ||
65 | -static void bdrv_backing_options(BdrvChildRole role, | ||
66 | +static void bdrv_backing_options(BdrvChildRole role, bool parent_is_format, | ||
67 | int *child_flags, QDict *child_options, | ||
68 | int parent_flags, QDict *parent_options) | ||
69 | { | 46 | { |
70 | @@ -XXX,XX +XXX,XX @@ static BlockDriverState *bdrv_open_inherit(const char *filename, | 47 | BlockJob *job = opaque; |
71 | bs->explicit_options = qdict_clone_shallow(options); | 48 | const char *msg = NULL; |
72 | 49 | @@ -XXX,XX +XXX,XX @@ static void block_job_event_completed(Notifier *n, void *opaque) | |
73 | if (child_class) { | 50 | msg); |
74 | + bool parent_is_format; | 51 | } |
75 | + | 52 | |
76 | + if (parent->drv) { | 53 | -static void block_job_event_pending(Notifier *n, void *opaque) |
77 | + parent_is_format = parent->drv->is_format; | 54 | +/* Called with job_mutex lock held. */ |
78 | + } else { | 55 | +static void block_job_event_pending_locked(Notifier *n, void *opaque) |
79 | + /* | ||
80 | + * parent->drv is not set yet because this node is opened for | ||
81 | + * (potential) format probing. That means that @parent is going | ||
82 | + * to be a format node. | ||
83 | + */ | ||
84 | + parent_is_format = true; | ||
85 | + } | ||
86 | + | ||
87 | bs->inherits_from = parent; | ||
88 | - child_class->inherit_options(child_role, &flags, options, | ||
89 | + child_class->inherit_options(child_role, parent_is_format, | ||
90 | + &flags, options, | ||
91 | parent->open_flags, parent->options); | ||
92 | } | ||
93 | |||
94 | @@ -XXX,XX +XXX,XX @@ static BlockDriverState *bdrv_open_inherit(const char *filename, | ||
95 | flags, options); | ||
96 | /* Let bdrv_backing_options() override "read-only" */ | ||
97 | qdict_del(options, BDRV_OPT_READ_ONLY); | ||
98 | - bdrv_backing_options(0, &flags, options, flags, options); | ||
99 | + bdrv_backing_options(0, true, &flags, options, flags, options); | ||
100 | } | ||
101 | |||
102 | bs->open_flags = flags; | ||
103 | @@ -XXX,XX +XXX,XX @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue, | ||
104 | QDict *options, | ||
105 | const BdrvChildClass *klass, | ||
106 | BdrvChildRole role, | ||
107 | + bool parent_is_format, | ||
108 | QDict *parent_options, | ||
109 | int parent_flags, | ||
110 | bool keep_old_opts) | ||
111 | @@ -XXX,XX +XXX,XX @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue, | ||
112 | /* Inherit from parent node */ | ||
113 | if (parent_options) { | ||
114 | flags = 0; | ||
115 | - klass->inherit_options(role, &flags, options, | ||
116 | + klass->inherit_options(role, parent_is_format, &flags, options, | ||
117 | parent_flags, parent_options); | ||
118 | } else { | ||
119 | flags = bdrv_get_flags(bs); | ||
120 | @@ -XXX,XX +XXX,XX @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue, | ||
121 | } | ||
122 | |||
123 | bdrv_reopen_queue_child(bs_queue, child->bs, new_child_options, | ||
124 | - child->klass, child->role, options, flags, | ||
125 | - child_keep_old); | ||
126 | + child->klass, child->role, bs->drv->is_format, | ||
127 | + options, flags, child_keep_old); | ||
128 | } | ||
129 | |||
130 | return bs_queue; | ||
131 | @@ -XXX,XX +XXX,XX @@ BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue, | ||
132 | BlockDriverState *bs, | ||
133 | QDict *options, bool keep_old_opts) | ||
134 | { | 56 | { |
135 | - return bdrv_reopen_queue_child(bs_queue, bs, options, NULL, 0, NULL, 0, | 57 | BlockJob *job = opaque; |
136 | - keep_old_opts); | 58 | |
137 | + return bdrv_reopen_queue_child(bs_queue, bs, options, NULL, 0, false, | 59 | @@ -XXX,XX +XXX,XX @@ static void block_job_event_pending(Notifier *n, void *opaque) |
138 | + NULL, 0, keep_old_opts); | 60 | job->job.id); |
139 | } | 61 | } |
140 | 62 | ||
141 | /* | 63 | -static void block_job_event_ready(Notifier *n, void *opaque) |
142 | diff --git a/block/block-backend.c b/block/block-backend.c | 64 | +/* Called with job_mutex lock held. */ |
143 | index XXXXXXX..XXXXXXX 100644 | 65 | +static void block_job_event_ready_locked(Notifier *n, void *opaque) |
144 | --- a/block/block-backend.c | ||
145 | +++ b/block/block-backend.c | ||
146 | @@ -XXX,XX +XXX,XX @@ static QTAILQ_HEAD(, BlockBackend) block_backends = | ||
147 | static QTAILQ_HEAD(, BlockBackend) monitor_block_backends = | ||
148 | QTAILQ_HEAD_INITIALIZER(monitor_block_backends); | ||
149 | |||
150 | -static void blk_root_inherit_options(BdrvChildRole role, | ||
151 | +static void blk_root_inherit_options(BdrvChildRole role, bool parent_is_format, | ||
152 | int *child_flags, QDict *child_options, | ||
153 | int parent_flags, QDict *parent_options) | ||
154 | { | 66 | { |
155 | diff --git a/block/vvfat.c b/block/vvfat.c | 67 | BlockJob *job = opaque; |
156 | index XXXXXXX..XXXXXXX 100644 | 68 | uint64_t progress_current, progress_total; |
157 | --- a/block/vvfat.c | 69 | @@ -XXX,XX +XXX,XX @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver, |
158 | +++ b/block/vvfat.c | 70 | |
159 | @@ -XXX,XX +XXX,XX @@ static BlockDriver vvfat_write_target = { | 71 | ratelimit_init(&job->limit); |
160 | .bdrv_co_pwritev = write_target_commit, | 72 | |
161 | }; | 73 | - job->finalize_cancelled_notifier.notify = block_job_event_cancelled; |
162 | 74 | - job->finalize_completed_notifier.notify = block_job_event_completed; | |
163 | -static void vvfat_qcow_options(BdrvChildRole role, | 75 | - job->pending_notifier.notify = block_job_event_pending; |
164 | +static void vvfat_qcow_options(BdrvChildRole role, bool parent_is_format, | 76 | - job->ready_notifier.notify = block_job_event_ready; |
165 | int *child_flags, QDict *child_options, | 77 | - job->idle_notifier.notify = block_job_on_idle; |
166 | int parent_flags, QDict *parent_options) | 78 | + job->finalize_cancelled_notifier.notify = block_job_event_cancelled_locked; |
167 | { | 79 | + job->finalize_completed_notifier.notify = block_job_event_completed_locked; |
80 | + job->pending_notifier.notify = block_job_event_pending_locked; | ||
81 | + job->ready_notifier.notify = block_job_event_ready_locked; | ||
82 | + job->idle_notifier.notify = block_job_on_idle_locked; | ||
83 | |||
84 | WITH_JOB_LOCK_GUARD() { | ||
85 | notifier_list_add(&job->job.on_finalize_cancelled, | ||
168 | -- | 86 | -- |
169 | 2.25.4 | 87 | 2.37.3 |
170 | |||
171 | diff view generated by jsdifflib |
1 | If the target is shorter than the source, mirror would copy data until | 1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
---|---|---|---|
2 | it reaches the end of the target and then fail with an I/O error when | ||
3 | trying to write past the end. | ||
4 | 2 | ||
5 | If the target is longer than the source, the mirror job would complete | 3 | iostatus is the only field (together with .job) that needs |
6 | successfully, but the target wouldn't actually be an accurate copy of | 4 | protection using the job mutex. |
7 | the source image (it would contain some additional garbage at the end). | ||
8 | 5 | ||
9 | Fix this by checking that both images have the same size when the job | 6 | It is set in the main loop (GLOBAL_STATE functions) but read |
10 | starts. | 7 | in I/O code (block_job_error_action). |
11 | 8 | ||
12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 9 | In order to protect it, change block_job_iostatus_set_err |
13 | Reviewed-by: Eric Blake <eblake@redhat.com> | 10 | to block_job_iostatus_set_err_locked(), always called under |
14 | Message-Id: <20200511135825.219437-4-kwolf@redhat.com> | 11 | job lock. |
15 | Reviewed-by: Max Reitz <mreitz@redhat.com> | 12 | |
16 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 13 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
14 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
15 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> | ||
16 | Message-Id: <20220926093214.506243-17-eesposit@redhat.com> | ||
17 | [kwolf: Fixed up type of iostatus] | ||
17 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 18 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
18 | --- | 19 | --- |
19 | block/mirror.c | 21 ++++++++++++--------- | 20 | block/mirror.c | 6 +++++- |
20 | 1 file changed, 12 insertions(+), 9 deletions(-) | 21 | blockjob.c | 5 +++-- |
22 | 2 files changed, 8 insertions(+), 3 deletions(-) | ||
21 | 23 | ||
22 | diff --git a/block/mirror.c b/block/mirror.c | 24 | diff --git a/block/mirror.c b/block/mirror.c |
23 | index XXXXXXX..XXXXXXX 100644 | 25 | index XXXXXXX..XXXXXXX 100644 |
24 | --- a/block/mirror.c | 26 | --- a/block/mirror.c |
25 | +++ b/block/mirror.c | 27 | +++ b/block/mirror.c |
26 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn mirror_run(Job *job, Error **errp) | 28 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn mirror_run(Job *job, Error **errp) |
29 | BlockDriverState *bs = s->mirror_top_bs->backing->bs; | ||
27 | BlockDriverState *target_bs = blk_bs(s->target); | 30 | BlockDriverState *target_bs = blk_bs(s->target); |
28 | bool need_drain = true; | 31 | bool need_drain = true; |
32 | + BlockDeviceIoStatus iostatus; | ||
29 | int64_t length; | 33 | int64_t length; |
30 | + int64_t target_length; | 34 | int64_t target_length; |
31 | BlockDriverInfo bdi; | 35 | BlockDriverInfo bdi; |
32 | char backing_filename[2]; /* we only need 2 characters because we are only | ||
33 | checking for a NULL string */ | ||
34 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn mirror_run(Job *job, Error **errp) | 36 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn mirror_run(Job *job, Error **errp) |
35 | goto immediate_exit; | 37 | * We do so every BLKOCK_JOB_SLICE_TIME nanoseconds, or when there is |
38 | * an error, or when the source is clean, whichever comes first. */ | ||
39 | delta = qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - s->last_pause_ns; | ||
40 | + WITH_JOB_LOCK_GUARD() { | ||
41 | + iostatus = s->common.iostatus; | ||
42 | + } | ||
43 | if (delta < BLOCK_JOB_SLICE_TIME && | ||
44 | - s->common.iostatus == BLOCK_DEVICE_IO_STATUS_OK) { | ||
45 | + iostatus == BLOCK_DEVICE_IO_STATUS_OK) { | ||
46 | if (s->in_flight >= MAX_IN_FLIGHT || s->buf_free_count == 0 || | ||
47 | (cnt == 0 && s->in_flight > 0)) { | ||
48 | trace_mirror_yield(s, cnt, s->buf_free_count, s->in_flight); | ||
49 | diff --git a/blockjob.c b/blockjob.c | ||
50 | index XXXXXXX..XXXXXXX 100644 | ||
51 | --- a/blockjob.c | ||
52 | +++ b/blockjob.c | ||
53 | @@ -XXX,XX +XXX,XX @@ BlockJobInfo *block_job_query(BlockJob *job, Error **errp) | ||
54 | return block_job_query_locked(job, errp); | ||
55 | } | ||
56 | |||
57 | -static void block_job_iostatus_set_err(BlockJob *job, int error) | ||
58 | +/* Called with job lock held */ | ||
59 | +static void block_job_iostatus_set_err_locked(BlockJob *job, int error) | ||
60 | { | ||
61 | if (job->iostatus == BLOCK_DEVICE_IO_STATUS_OK) { | ||
62 | job->iostatus = error == ENOSPC ? BLOCK_DEVICE_IO_STATUS_NOSPACE : | ||
63 | @@ -XXX,XX +XXX,XX @@ BlockErrorAction block_job_error_action(BlockJob *job, BlockdevOnError on_err, | ||
64 | */ | ||
65 | job->job.user_paused = true; | ||
66 | } | ||
67 | + block_job_iostatus_set_err_locked(job, error); | ||
68 | } | ||
69 | - block_job_iostatus_set_err(job, error); | ||
36 | } | 70 | } |
37 | 71 | return action; | |
38 | + target_length = blk_getlength(s->target); | 72 | } |
39 | + if (target_length < 0) { | ||
40 | + ret = target_length; | ||
41 | + goto immediate_exit; | ||
42 | + } | ||
43 | + | ||
44 | /* Active commit must resize the base image if its size differs from the | ||
45 | * active layer. */ | ||
46 | if (s->base == blk_bs(s->target)) { | ||
47 | - int64_t base_length; | ||
48 | - | ||
49 | - base_length = blk_getlength(s->target); | ||
50 | - if (base_length < 0) { | ||
51 | - ret = base_length; | ||
52 | - goto immediate_exit; | ||
53 | - } | ||
54 | - | ||
55 | - if (s->bdev_length > base_length) { | ||
56 | + if (s->bdev_length > target_length) { | ||
57 | ret = blk_truncate(s->target, s->bdev_length, false, | ||
58 | PREALLOC_MODE_OFF, 0, NULL); | ||
59 | if (ret < 0) { | ||
60 | goto immediate_exit; | ||
61 | } | ||
62 | } | ||
63 | + } else if (s->bdev_length != target_length) { | ||
64 | + error_setg(errp, "Source and target image have different sizes"); | ||
65 | + ret = -EINVAL; | ||
66 | + goto immediate_exit; | ||
67 | } | ||
68 | |||
69 | if (s->bdev_length == 0) { | ||
70 | -- | 73 | -- |
71 | 2.25.4 | 74 | 2.37.3 |
72 | |||
73 | diff view generated by jsdifflib |
1 | From: Max Reitz <mreitz@redhat.com> | 1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 3 | Some callbacks implementation use bdrv_* APIs that assume the |
4 | Reviewed-by: Eric Blake <eblake@redhat.com> | 4 | AioContext lock is held. Make sure this invariant is documented. |
5 | Message-Id: <20200513110544.176672-23-mreitz@redhat.com> | 5 | |
6 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
7 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> | ||
8 | Message-Id: <20220926093214.506243-18-eesposit@redhat.com> | ||
9 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
6 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
7 | --- | 11 | --- |
8 | include/block/block_int.h | 1 - | 12 | include/qemu/job.h | 27 +++++++++++++++++++++++++-- |
9 | block.c | 29 ----------------------------- | 13 | 1 file changed, 25 insertions(+), 2 deletions(-) |
10 | 2 files changed, 30 deletions(-) | ||
11 | 14 | ||
12 | diff --git a/include/block/block_int.h b/include/block/block_int.h | 15 | diff --git a/include/qemu/job.h b/include/qemu/job.h |
13 | index XXXXXXX..XXXXXXX 100644 | 16 | index XXXXXXX..XXXXXXX 100644 |
14 | --- a/include/block/block_int.h | 17 | --- a/include/qemu/job.h |
15 | +++ b/include/block/block_int.h | 18 | +++ b/include/qemu/job.h |
16 | @@ -XXX,XX +XXX,XX @@ struct BdrvChildClass { | 19 | @@ -XXX,XX +XXX,XX @@ typedef struct Job { |
17 | 20 | /** True if this job should automatically dismiss itself */ | |
18 | extern const BdrvChildClass child_of_bds; | 21 | bool auto_dismiss; |
19 | extern const BdrvChildClass child_file; | 22 | |
20 | -extern const BdrvChildClass child_format; | 23 | - /** The completion function that will be called when the job completes. */ |
21 | extern const BdrvChildClass child_backing; | 24 | + /** |
22 | 25 | + * The completion function that will be called when the job completes. | |
23 | struct BdrvChild { | 26 | + * Called with AioContext lock held, since many callback implementations |
24 | diff --git a/block.c b/block.c | 27 | + * use bdrv_* functions that require to hold the lock. |
25 | index XXXXXXX..XXXXXXX 100644 | 28 | + */ |
26 | --- a/block.c | 29 | BlockCompletionFunc *cb; |
27 | +++ b/block.c | 30 | |
28 | @@ -XXX,XX +XXX,XX @@ const BdrvChildClass child_file = { | 31 | /** The opaque value that is passed to the completion function. */ |
29 | .set_aio_ctx = bdrv_child_cb_set_aio_ctx, | 32 | @@ -XXX,XX +XXX,XX @@ struct JobDriver { |
33 | * | ||
34 | * This callback will not be invoked if the job has already failed. | ||
35 | * If it fails, abort and then clean will be called. | ||
36 | + * | ||
37 | + * Called with AioContext lock held, since many callbacs implementations | ||
38 | + * use bdrv_* functions that require to hold the lock. | ||
39 | */ | ||
40 | int (*prepare)(Job *job); | ||
41 | |||
42 | @@ -XXX,XX +XXX,XX @@ struct JobDriver { | ||
43 | * | ||
44 | * All jobs will complete with a call to either .commit() or .abort() but | ||
45 | * never both. | ||
46 | + * | ||
47 | + * Called with AioContext lock held, since many callback implementations | ||
48 | + * use bdrv_* functions that require to hold the lock. | ||
49 | */ | ||
50 | void (*commit)(Job *job); | ||
51 | |||
52 | @@ -XXX,XX +XXX,XX @@ struct JobDriver { | ||
53 | * | ||
54 | * All jobs will complete with a call to either .commit() or .abort() but | ||
55 | * never both. | ||
56 | + * | ||
57 | + * Called with AioContext lock held, since many callback implementations | ||
58 | + * use bdrv_* functions that require to hold the lock. | ||
59 | */ | ||
60 | void (*abort)(Job *job); | ||
61 | |||
62 | @@ -XXX,XX +XXX,XX @@ struct JobDriver { | ||
63 | * .commit() or .abort(). Regardless of which callback is invoked after | ||
64 | * completion, .clean() will always be called, even if the job does not | ||
65 | * belong to a transaction group. | ||
66 | + * | ||
67 | + * Called with AioContext lock held, since many callbacs implementations | ||
68 | + * use bdrv_* functions that require to hold the lock. | ||
69 | */ | ||
70 | void (*clean)(Job *job); | ||
71 | |||
72 | @@ -XXX,XX +XXX,XX @@ struct JobDriver { | ||
73 | * READY). | ||
74 | * (If the callback is NULL, the job is assumed to terminate | ||
75 | * without I/O.) | ||
76 | + * | ||
77 | + * Called with AioContext lock held, since many callback implementations | ||
78 | + * use bdrv_* functions that require to hold the lock. | ||
79 | */ | ||
80 | bool (*cancel)(Job *job, bool force); | ||
81 | |||
82 | |||
83 | - /** Called when the job is freed */ | ||
84 | + /** | ||
85 | + * Called when the job is freed. | ||
86 | + * Called with AioContext lock held, since many callback implementations | ||
87 | + * use bdrv_* functions that require to hold the lock. | ||
88 | + */ | ||
89 | void (*free)(Job *job); | ||
30 | }; | 90 | }; |
31 | 91 | ||
32 | -/* | ||
33 | - * Returns the options and flags that bs->file should get if the use of formats | ||
34 | - * (and not only protocols) is permitted for it, based on the given options and | ||
35 | - * flags for the parent BDS | ||
36 | - */ | ||
37 | -static void bdrv_inherited_fmt_options(BdrvChildRole role, | ||
38 | - bool parent_is_format, | ||
39 | - int *child_flags, QDict *child_options, | ||
40 | - int parent_flags, QDict *parent_options) | ||
41 | -{ | ||
42 | - bdrv_inherited_options(BDRV_CHILD_DATA, false, | ||
43 | - child_flags, child_options, | ||
44 | - parent_flags, parent_options); | ||
45 | -} | ||
46 | - | ||
47 | -const BdrvChildClass child_format = { | ||
48 | - .parent_is_bds = true, | ||
49 | - .get_parent_desc = bdrv_child_get_parent_desc, | ||
50 | - .inherit_options = bdrv_inherited_fmt_options, | ||
51 | - .drained_begin = bdrv_child_cb_drained_begin, | ||
52 | - .drained_poll = bdrv_child_cb_drained_poll, | ||
53 | - .drained_end = bdrv_child_cb_drained_end, | ||
54 | - .attach = bdrv_child_cb_attach, | ||
55 | - .detach = bdrv_child_cb_detach, | ||
56 | - .inactivate = bdrv_child_cb_inactivate, | ||
57 | - .can_set_aio_ctx = bdrv_child_cb_can_set_aio_ctx, | ||
58 | - .set_aio_ctx = bdrv_child_cb_set_aio_ctx, | ||
59 | -}; | ||
60 | - | ||
61 | static void bdrv_backing_attach(BdrvChild *c) | ||
62 | { | ||
63 | BlockDriverState *parent = c->opaque; | ||
64 | -- | 92 | -- |
65 | 2.25.4 | 93 | 2.37.3 |
66 | |||
67 | diff view generated by jsdifflib |
1 | From: Lukas Straub <lukasstraub2@web.de> | 1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | If qemu in colo secondary mode is stopped, it crashes because | 3 | Change the job_{lock/unlock} and macros to use job_mutex. |
4 | s->backup_job is canceled twice: First with job_cancel_sync_all() | ||
5 | in qemu_cleanup() and then in replication_stop(). | ||
6 | 4 | ||
7 | Fix this by assigning NULL to s->backup_job when the job completes | 5 | Now that they are not nop anymore, remove the aiocontext |
8 | so replication_stop() and replication_do_checkpoint() won't touch | 6 | to avoid deadlocks. |
9 | the job. | ||
10 | 7 | ||
11 | Signed-off-by: Lukas Straub <lukasstraub2@web.de> | 8 | Therefore: |
12 | Message-Id: <20200511090801.7ed5d8f3@luklap> | 9 | - when possible, remove completely the aiocontext lock/unlock pair |
10 | - if it is used by some other function too, reduce the locking | ||
11 | section as much as possible, leaving the job API outside. | ||
12 | - change AIO_WAIT_WHILE in AIO_WAIT_WHILE_UNLOCKED, since we | ||
13 | are not using the aiocontext lock anymore | ||
14 | |||
15 | The only functions that still need the aiocontext lock are: | ||
16 | - the JobDriver callbacks, already documented in job.h | ||
17 | - job_cancel_sync() in replication.c is called with aio_context_lock | ||
18 | taken, but now job is using AIO_WAIT_WHILE_UNLOCKED so we need to | ||
19 | release the lock. | ||
20 | |||
21 | Reduce the locking section to only cover the callback invocation | ||
22 | and document the functions that take the AioContext lock, | ||
23 | to avoid taking it twice. | ||
24 | |||
25 | Also remove real_job_{lock/unlock}, as they are replaced by the | ||
26 | public functions. | ||
27 | |||
28 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
29 | Message-Id: <20220926093214.506243-19-eesposit@redhat.com> | ||
30 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
31 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> | ||
13 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 32 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
14 | --- | 33 | --- |
15 | block/replication.c | 2 ++ | 34 | include/qemu/job.h | 17 ++--- |
16 | 1 file changed, 2 insertions(+) | 35 | block/replication.c | 2 + |
36 | blockdev.c | 72 +++----------------- | ||
37 | job-qmp.c | 46 +++---------- | ||
38 | job.c | 111 +++++++++---------------------- | ||
39 | qemu-img.c | 2 - | ||
40 | tests/unit/test-bdrv-drain.c | 4 +- | ||
41 | tests/unit/test-block-iothread.c | 2 +- | ||
42 | tests/unit/test-blockjob.c | 19 +++--- | ||
43 | 9 files changed, 72 insertions(+), 203 deletions(-) | ||
17 | 44 | ||
45 | diff --git a/include/qemu/job.h b/include/qemu/job.h | ||
46 | index XXXXXXX..XXXXXXX 100644 | ||
47 | --- a/include/qemu/job.h | ||
48 | +++ b/include/qemu/job.h | ||
49 | @@ -XXX,XX +XXX,XX @@ typedef struct Job { | ||
50 | AioContext *aio_context; | ||
51 | |||
52 | |||
53 | - /** Protected by AioContext lock */ | ||
54 | + /** Protected by job_mutex */ | ||
55 | |||
56 | /** Reference count of the block job */ | ||
57 | int refcnt; | ||
58 | @@ -XXX,XX +XXX,XX @@ typedef struct Job { | ||
59 | /** | ||
60 | * Set to false by the job while the coroutine has yielded and may be | ||
61 | * re-entered by job_enter(). There may still be I/O or event loop activity | ||
62 | - * pending. Accessed under block_job_mutex (in blockjob.c). | ||
63 | + * pending. Accessed under job_mutex. | ||
64 | * | ||
65 | * When the job is deferred to the main loop, busy is true as long as the | ||
66 | * bottom half is still pending. | ||
67 | @@ -XXX,XX +XXX,XX @@ typedef enum JobCreateFlags { | ||
68 | |||
69 | extern QemuMutex job_mutex; | ||
70 | |||
71 | -#define JOB_LOCK_GUARD() /* QEMU_LOCK_GUARD(&job_mutex) */ | ||
72 | +#define JOB_LOCK_GUARD() QEMU_LOCK_GUARD(&job_mutex) | ||
73 | |||
74 | -#define WITH_JOB_LOCK_GUARD() /* WITH_QEMU_LOCK_GUARD(&job_mutex) */ | ||
75 | +#define WITH_JOB_LOCK_GUARD() WITH_QEMU_LOCK_GUARD(&job_mutex) | ||
76 | |||
77 | /** | ||
78 | * job_lock: | ||
79 | @@ -XXX,XX +XXX,XX @@ void job_ref_locked(Job *job); | ||
80 | /** | ||
81 | * Release a reference that was previously acquired with job_ref() or | ||
82 | * job_create(). If it's the last reference to the object, it will be freed. | ||
83 | + * | ||
84 | + * Takes AioContext lock internally to invoke a job->driver callback. | ||
85 | */ | ||
86 | void job_unref(Job *job); | ||
87 | |||
88 | @@ -XXX,XX +XXX,XX @@ void job_user_cancel_locked(Job *job, bool force, Error **errp); | ||
89 | * Returns the return value from the job if the job actually completed | ||
90 | * during the call, or -ECANCELED if it was canceled. | ||
91 | * | ||
92 | - * Callers must hold the AioContext lock of job->aio_context. | ||
93 | + * Called with job_lock *not* held. | ||
94 | */ | ||
95 | int job_cancel_sync(Job *job, bool force); | ||
96 | |||
97 | @@ -XXX,XX +XXX,XX @@ void job_cancel_sync_all(void); | ||
98 | * function). | ||
99 | * | ||
100 | * Returns the return value from the job. | ||
101 | - * | ||
102 | - * Callers must hold the AioContext lock of job->aio_context. | ||
103 | + * Called with job_lock *not* held. | ||
104 | */ | ||
105 | int job_complete_sync(Job *job, Error **errp); | ||
106 | |||
107 | @@ -XXX,XX +XXX,XX @@ void job_dismiss_locked(Job **job, Error **errp); | ||
108 | * Returns 0 if the job is successfully completed, -ECANCELED if the job was | ||
109 | * cancelled before completing, and -errno in other error cases. | ||
110 | * | ||
111 | - * Callers must hold the AioContext lock of job->aio_context. | ||
112 | + * Called with job_lock *not* held. | ||
113 | */ | ||
114 | int job_finish_sync(Job *job, void (*finish)(Job *, Error **errp), | ||
115 | Error **errp); | ||
18 | diff --git a/block/replication.c b/block/replication.c | 116 | diff --git a/block/replication.c b/block/replication.c |
19 | index XXXXXXX..XXXXXXX 100644 | 117 | index XXXXXXX..XXXXXXX 100644 |
20 | --- a/block/replication.c | 118 | --- a/block/replication.c |
21 | +++ b/block/replication.c | 119 | +++ b/block/replication.c |
22 | @@ -XXX,XX +XXX,XX @@ static void backup_job_cleanup(BlockDriverState *bs) | 120 | @@ -XXX,XX +XXX,XX @@ static void replication_stop(ReplicationState *rs, bool failover, Error **errp) |
23 | BDRVReplicationState *s = bs->opaque; | 121 | * disk, secondary disk in backup_job_completed(). |
24 | BlockDriverState *top_bs; | 122 | */ |
25 | 123 | if (s->backup_job) { | |
26 | + s->backup_job = NULL; | 124 | + aio_context_release(aio_context); |
125 | job_cancel_sync(&s->backup_job->job, true); | ||
126 | + aio_context_acquire(aio_context); | ||
127 | } | ||
128 | |||
129 | if (!failover) { | ||
130 | diff --git a/blockdev.c b/blockdev.c | ||
131 | index XXXXXXX..XXXXXXX 100644 | ||
132 | --- a/blockdev.c | ||
133 | +++ b/blockdev.c | ||
134 | @@ -XXX,XX +XXX,XX @@ void blockdev_mark_auto_del(BlockBackend *blk) | ||
135 | for (job = block_job_next_locked(NULL); job; | ||
136 | job = block_job_next_locked(job)) { | ||
137 | if (block_job_has_bdrv(job, blk_bs(blk))) { | ||
138 | - AioContext *aio_context = job->job.aio_context; | ||
139 | - aio_context_acquire(aio_context); | ||
140 | - | ||
141 | job_cancel_locked(&job->job, false); | ||
142 | - | ||
143 | - aio_context_release(aio_context); | ||
144 | } | ||
145 | } | ||
146 | |||
147 | @@ -XXX,XX +XXX,XX @@ static void drive_backup_abort(BlkActionState *common) | ||
148 | DriveBackupState *state = DO_UPCAST(DriveBackupState, common, common); | ||
149 | |||
150 | if (state->job) { | ||
151 | - AioContext *aio_context; | ||
152 | - | ||
153 | - aio_context = bdrv_get_aio_context(state->bs); | ||
154 | - aio_context_acquire(aio_context); | ||
155 | - | ||
156 | job_cancel_sync(&state->job->job, true); | ||
157 | - | ||
158 | - aio_context_release(aio_context); | ||
159 | } | ||
160 | } | ||
161 | |||
162 | @@ -XXX,XX +XXX,XX @@ static void blockdev_backup_abort(BlkActionState *common) | ||
163 | BlockdevBackupState *state = DO_UPCAST(BlockdevBackupState, common, common); | ||
164 | |||
165 | if (state->job) { | ||
166 | - AioContext *aio_context; | ||
167 | - | ||
168 | - aio_context = bdrv_get_aio_context(state->bs); | ||
169 | - aio_context_acquire(aio_context); | ||
170 | - | ||
171 | job_cancel_sync(&state->job->job, true); | ||
172 | - | ||
173 | - aio_context_release(aio_context); | ||
174 | } | ||
175 | } | ||
176 | |||
177 | @@ -XXX,XX +XXX,XX @@ out: | ||
178 | } | ||
179 | |||
180 | /* | ||
181 | - * Get a block job using its ID and acquire its AioContext. | ||
182 | - * Called with job_mutex held. | ||
183 | + * Get a block job using its ID. Called with job_mutex held. | ||
184 | */ | ||
185 | -static BlockJob *find_block_job_locked(const char *id, | ||
186 | - AioContext **aio_context, | ||
187 | - Error **errp) | ||
188 | +static BlockJob *find_block_job_locked(const char *id, Error **errp) | ||
189 | { | ||
190 | BlockJob *job; | ||
191 | |||
192 | assert(id != NULL); | ||
193 | |||
194 | - *aio_context = NULL; | ||
195 | - | ||
196 | job = block_job_get_locked(id); | ||
197 | |||
198 | if (!job) { | ||
199 | @@ -XXX,XX +XXX,XX @@ static BlockJob *find_block_job_locked(const char *id, | ||
200 | return NULL; | ||
201 | } | ||
202 | |||
203 | - *aio_context = block_job_get_aio_context(job); | ||
204 | - aio_context_acquire(*aio_context); | ||
205 | - | ||
206 | return job; | ||
207 | } | ||
208 | |||
209 | void qmp_block_job_set_speed(const char *device, int64_t speed, Error **errp) | ||
210 | { | ||
211 | - AioContext *aio_context; | ||
212 | BlockJob *job; | ||
213 | |||
214 | JOB_LOCK_GUARD(); | ||
215 | - job = find_block_job_locked(device, &aio_context, errp); | ||
216 | + job = find_block_job_locked(device, errp); | ||
217 | |||
218 | if (!job) { | ||
219 | return; | ||
220 | } | ||
221 | |||
222 | block_job_set_speed_locked(job, speed, errp); | ||
223 | - aio_context_release(aio_context); | ||
224 | } | ||
225 | |||
226 | void qmp_block_job_cancel(const char *device, | ||
227 | bool has_force, bool force, Error **errp) | ||
228 | { | ||
229 | - AioContext *aio_context; | ||
230 | BlockJob *job; | ||
231 | |||
232 | JOB_LOCK_GUARD(); | ||
233 | - job = find_block_job_locked(device, &aio_context, errp); | ||
234 | + job = find_block_job_locked(device, errp); | ||
235 | |||
236 | if (!job) { | ||
237 | return; | ||
238 | @@ -XXX,XX +XXX,XX @@ void qmp_block_job_cancel(const char *device, | ||
239 | if (job_user_paused_locked(&job->job) && !force) { | ||
240 | error_setg(errp, "The block job for device '%s' is currently paused", | ||
241 | device); | ||
242 | - goto out; | ||
243 | + return; | ||
244 | } | ||
245 | |||
246 | trace_qmp_block_job_cancel(job); | ||
247 | job_user_cancel_locked(&job->job, force, errp); | ||
248 | -out: | ||
249 | - aio_context_release(aio_context); | ||
250 | } | ||
251 | |||
252 | void qmp_block_job_pause(const char *device, Error **errp) | ||
253 | { | ||
254 | - AioContext *aio_context; | ||
255 | BlockJob *job; | ||
256 | |||
257 | JOB_LOCK_GUARD(); | ||
258 | - job = find_block_job_locked(device, &aio_context, errp); | ||
259 | + job = find_block_job_locked(device, errp); | ||
260 | |||
261 | if (!job) { | ||
262 | return; | ||
263 | @@ -XXX,XX +XXX,XX @@ void qmp_block_job_pause(const char *device, Error **errp) | ||
264 | |||
265 | trace_qmp_block_job_pause(job); | ||
266 | job_user_pause_locked(&job->job, errp); | ||
267 | - aio_context_release(aio_context); | ||
268 | } | ||
269 | |||
270 | void qmp_block_job_resume(const char *device, Error **errp) | ||
271 | { | ||
272 | - AioContext *aio_context; | ||
273 | BlockJob *job; | ||
274 | |||
275 | JOB_LOCK_GUARD(); | ||
276 | - job = find_block_job_locked(device, &aio_context, errp); | ||
277 | + job = find_block_job_locked(device, errp); | ||
278 | |||
279 | if (!job) { | ||
280 | return; | ||
281 | @@ -XXX,XX +XXX,XX @@ void qmp_block_job_resume(const char *device, Error **errp) | ||
282 | |||
283 | trace_qmp_block_job_resume(job); | ||
284 | job_user_resume_locked(&job->job, errp); | ||
285 | - aio_context_release(aio_context); | ||
286 | } | ||
287 | |||
288 | void qmp_block_job_complete(const char *device, Error **errp) | ||
289 | { | ||
290 | - AioContext *aio_context; | ||
291 | BlockJob *job; | ||
292 | |||
293 | JOB_LOCK_GUARD(); | ||
294 | - job = find_block_job_locked(device, &aio_context, errp); | ||
295 | + job = find_block_job_locked(device, errp); | ||
296 | |||
297 | if (!job) { | ||
298 | return; | ||
299 | @@ -XXX,XX +XXX,XX @@ void qmp_block_job_complete(const char *device, Error **errp) | ||
300 | |||
301 | trace_qmp_block_job_complete(job); | ||
302 | job_complete_locked(&job->job, errp); | ||
303 | - aio_context_release(aio_context); | ||
304 | } | ||
305 | |||
306 | void qmp_block_job_finalize(const char *id, Error **errp) | ||
307 | { | ||
308 | - AioContext *aio_context; | ||
309 | BlockJob *job; | ||
310 | |||
311 | JOB_LOCK_GUARD(); | ||
312 | - job = find_block_job_locked(id, &aio_context, errp); | ||
313 | + job = find_block_job_locked(id, errp); | ||
314 | |||
315 | if (!job) { | ||
316 | return; | ||
317 | @@ -XXX,XX +XXX,XX @@ void qmp_block_job_finalize(const char *id, Error **errp) | ||
318 | job_ref_locked(&job->job); | ||
319 | job_finalize_locked(&job->job, errp); | ||
320 | |||
321 | - /* | ||
322 | - * Job's context might have changed via job_finalize (and job_txn_apply | ||
323 | - * automatically acquires the new one), so make sure we release the correct | ||
324 | - * one. | ||
325 | - */ | ||
326 | - aio_context = block_job_get_aio_context(job); | ||
327 | job_unref_locked(&job->job); | ||
328 | - aio_context_release(aio_context); | ||
329 | } | ||
330 | |||
331 | void qmp_block_job_dismiss(const char *id, Error **errp) | ||
332 | { | ||
333 | - AioContext *aio_context; | ||
334 | BlockJob *bjob; | ||
335 | Job *job; | ||
336 | |||
337 | JOB_LOCK_GUARD(); | ||
338 | - bjob = find_block_job_locked(id, &aio_context, errp); | ||
339 | + bjob = find_block_job_locked(id, errp); | ||
340 | |||
341 | if (!bjob) { | ||
342 | return; | ||
343 | @@ -XXX,XX +XXX,XX @@ void qmp_block_job_dismiss(const char *id, Error **errp) | ||
344 | trace_qmp_block_job_dismiss(bjob); | ||
345 | job = &bjob->job; | ||
346 | job_dismiss_locked(&job, errp); | ||
347 | - aio_context_release(aio_context); | ||
348 | } | ||
349 | |||
350 | void qmp_change_backing_file(const char *device, | ||
351 | @@ -XXX,XX +XXX,XX @@ BlockJobInfoList *qmp_query_block_jobs(Error **errp) | ||
352 | for (job = block_job_next_locked(NULL); job; | ||
353 | job = block_job_next_locked(job)) { | ||
354 | BlockJobInfo *value; | ||
355 | - AioContext *aio_context; | ||
356 | |||
357 | if (block_job_is_internal(job)) { | ||
358 | continue; | ||
359 | } | ||
360 | - aio_context = block_job_get_aio_context(job); | ||
361 | - aio_context_acquire(aio_context); | ||
362 | value = block_job_query_locked(job, errp); | ||
363 | - aio_context_release(aio_context); | ||
364 | if (!value) { | ||
365 | qapi_free_BlockJobInfoList(head); | ||
366 | return NULL; | ||
367 | diff --git a/job-qmp.c b/job-qmp.c | ||
368 | index XXXXXXX..XXXXXXX 100644 | ||
369 | --- a/job-qmp.c | ||
370 | +++ b/job-qmp.c | ||
371 | @@ -XXX,XX +XXX,XX @@ | ||
372 | #include "trace/trace-root.h" | ||
373 | |||
374 | /* | ||
375 | - * Get a job using its ID and acquire its AioContext. | ||
376 | - * Called with job_mutex held. | ||
377 | + * Get a job using its ID. Called with job_mutex held. | ||
378 | */ | ||
379 | -static Job *find_job_locked(const char *id, | ||
380 | - AioContext **aio_context, | ||
381 | - Error **errp) | ||
382 | +static Job *find_job_locked(const char *id, Error **errp) | ||
383 | { | ||
384 | Job *job; | ||
385 | |||
386 | - *aio_context = NULL; | ||
387 | - | ||
388 | job = job_get_locked(id); | ||
389 | if (!job) { | ||
390 | error_setg(errp, "Job not found"); | ||
391 | return NULL; | ||
392 | } | ||
393 | |||
394 | - *aio_context = job->aio_context; | ||
395 | - aio_context_acquire(*aio_context); | ||
396 | - | ||
397 | return job; | ||
398 | } | ||
399 | |||
400 | void qmp_job_cancel(const char *id, Error **errp) | ||
401 | { | ||
402 | - AioContext *aio_context; | ||
403 | Job *job; | ||
404 | |||
405 | JOB_LOCK_GUARD(); | ||
406 | - job = find_job_locked(id, &aio_context, errp); | ||
407 | + job = find_job_locked(id, errp); | ||
408 | |||
409 | if (!job) { | ||
410 | return; | ||
411 | @@ -XXX,XX +XXX,XX @@ void qmp_job_cancel(const char *id, Error **errp) | ||
412 | |||
413 | trace_qmp_job_cancel(job); | ||
414 | job_user_cancel_locked(job, true, errp); | ||
415 | - aio_context_release(aio_context); | ||
416 | } | ||
417 | |||
418 | void qmp_job_pause(const char *id, Error **errp) | ||
419 | { | ||
420 | - AioContext *aio_context; | ||
421 | Job *job; | ||
422 | |||
423 | JOB_LOCK_GUARD(); | ||
424 | - job = find_job_locked(id, &aio_context, errp); | ||
425 | + job = find_job_locked(id, errp); | ||
426 | |||
427 | if (!job) { | ||
428 | return; | ||
429 | @@ -XXX,XX +XXX,XX @@ void qmp_job_pause(const char *id, Error **errp) | ||
430 | |||
431 | trace_qmp_job_pause(job); | ||
432 | job_user_pause_locked(job, errp); | ||
433 | - aio_context_release(aio_context); | ||
434 | } | ||
435 | |||
436 | void qmp_job_resume(const char *id, Error **errp) | ||
437 | { | ||
438 | - AioContext *aio_context; | ||
439 | Job *job; | ||
440 | |||
441 | JOB_LOCK_GUARD(); | ||
442 | - job = find_job_locked(id, &aio_context, errp); | ||
443 | + job = find_job_locked(id, errp); | ||
444 | |||
445 | if (!job) { | ||
446 | return; | ||
447 | @@ -XXX,XX +XXX,XX @@ void qmp_job_resume(const char *id, Error **errp) | ||
448 | |||
449 | trace_qmp_job_resume(job); | ||
450 | job_user_resume_locked(job, errp); | ||
451 | - aio_context_release(aio_context); | ||
452 | } | ||
453 | |||
454 | void qmp_job_complete(const char *id, Error **errp) | ||
455 | { | ||
456 | - AioContext *aio_context; | ||
457 | Job *job; | ||
458 | |||
459 | JOB_LOCK_GUARD(); | ||
460 | - job = find_job_locked(id, &aio_context, errp); | ||
461 | + job = find_job_locked(id, errp); | ||
462 | |||
463 | if (!job) { | ||
464 | return; | ||
465 | @@ -XXX,XX +XXX,XX @@ void qmp_job_complete(const char *id, Error **errp) | ||
466 | |||
467 | trace_qmp_job_complete(job); | ||
468 | job_complete_locked(job, errp); | ||
469 | - aio_context_release(aio_context); | ||
470 | } | ||
471 | |||
472 | void qmp_job_finalize(const char *id, Error **errp) | ||
473 | { | ||
474 | - AioContext *aio_context; | ||
475 | Job *job; | ||
476 | |||
477 | JOB_LOCK_GUARD(); | ||
478 | - job = find_job_locked(id, &aio_context, errp); | ||
479 | + job = find_job_locked(id, errp); | ||
480 | |||
481 | if (!job) { | ||
482 | return; | ||
483 | @@ -XXX,XX +XXX,XX @@ void qmp_job_finalize(const char *id, Error **errp) | ||
484 | job_ref_locked(job); | ||
485 | job_finalize_locked(job, errp); | ||
486 | |||
487 | - /* | ||
488 | - * Job's context might have changed via job_finalize (and job_txn_apply | ||
489 | - * automatically acquires the new one), so make sure we release the correct | ||
490 | - * one. | ||
491 | - */ | ||
492 | - aio_context = job->aio_context; | ||
493 | job_unref_locked(job); | ||
494 | - aio_context_release(aio_context); | ||
495 | } | ||
496 | |||
497 | void qmp_job_dismiss(const char *id, Error **errp) | ||
498 | { | ||
499 | - AioContext *aio_context; | ||
500 | Job *job; | ||
501 | |||
502 | JOB_LOCK_GUARD(); | ||
503 | - job = find_job_locked(id, &aio_context, errp); | ||
504 | + job = find_job_locked(id, errp); | ||
505 | |||
506 | if (!job) { | ||
507 | return; | ||
508 | @@ -XXX,XX +XXX,XX @@ void qmp_job_dismiss(const char *id, Error **errp) | ||
509 | |||
510 | trace_qmp_job_dismiss(job); | ||
511 | job_dismiss_locked(&job, errp); | ||
512 | - aio_context_release(aio_context); | ||
513 | } | ||
514 | |||
515 | /* Called with job_mutex held. */ | ||
516 | @@ -XXX,XX +XXX,XX @@ JobInfoList *qmp_query_jobs(Error **errp) | ||
517 | |||
518 | for (job = job_next_locked(NULL); job; job = job_next_locked(job)) { | ||
519 | JobInfo *value; | ||
520 | - AioContext *aio_context; | ||
521 | |||
522 | if (job_is_internal(job)) { | ||
523 | continue; | ||
524 | } | ||
525 | - aio_context = job->aio_context; | ||
526 | - aio_context_acquire(aio_context); | ||
527 | value = job_query_single_locked(job, errp); | ||
528 | - aio_context_release(aio_context); | ||
529 | if (!value) { | ||
530 | qapi_free_JobInfoList(head); | ||
531 | return NULL; | ||
532 | diff --git a/job.c b/job.c | ||
533 | index XXXXXXX..XXXXXXX 100644 | ||
534 | --- a/job.c | ||
535 | +++ b/job.c | ||
536 | @@ -XXX,XX +XXX,XX @@ | ||
537 | * | ||
538 | * The second includes functions used by the job drivers and sometimes | ||
539 | * by the core block layer. These delegate the locking to the callee instead. | ||
540 | - * | ||
541 | - * TODO Actually make this true | ||
542 | */ | ||
543 | |||
544 | /* | ||
545 | @@ -XXX,XX +XXX,XX @@ struct JobTxn { | ||
546 | }; | ||
547 | |||
548 | void job_lock(void) | ||
549 | -{ | ||
550 | - /* nop */ | ||
551 | -} | ||
552 | - | ||
553 | -void job_unlock(void) | ||
554 | -{ | ||
555 | - /* nop */ | ||
556 | -} | ||
557 | - | ||
558 | -static void real_job_lock(void) | ||
559 | { | ||
560 | qemu_mutex_lock(&job_mutex); | ||
561 | } | ||
562 | |||
563 | -static void real_job_unlock(void) | ||
564 | +void job_unlock(void) | ||
565 | { | ||
566 | qemu_mutex_unlock(&job_mutex); | ||
567 | } | ||
568 | @@ -XXX,XX +XXX,XX @@ static void job_txn_del_job_locked(Job *job) | ||
569 | /* Called with job_mutex held, but releases it temporarily. */ | ||
570 | static int job_txn_apply_locked(Job *job, int fn(Job *)) | ||
571 | { | ||
572 | - AioContext *inner_ctx; | ||
573 | Job *other_job, *next; | ||
574 | JobTxn *txn = job->txn; | ||
575 | int rc = 0; | ||
576 | @@ -XXX,XX +XXX,XX @@ static int job_txn_apply_locked(Job *job, int fn(Job *)) | ||
577 | * break AIO_WAIT_WHILE from within fn. | ||
578 | */ | ||
579 | job_ref_locked(job); | ||
580 | - aio_context_release(job->aio_context); | ||
581 | |||
582 | QLIST_FOREACH_SAFE(other_job, &txn->jobs, txn_list, next) { | ||
583 | - inner_ctx = other_job->aio_context; | ||
584 | - aio_context_acquire(inner_ctx); | ||
585 | rc = fn(other_job); | ||
586 | - aio_context_release(inner_ctx); | ||
587 | if (rc) { | ||
588 | break; | ||
589 | } | ||
590 | } | ||
591 | |||
592 | - /* | ||
593 | - * Note that job->aio_context might have been changed by calling fn, so we | ||
594 | - * can't use a local variable to cache it. | ||
595 | - */ | ||
596 | - aio_context_acquire(job->aio_context); | ||
597 | job_unref_locked(job); | ||
598 | return rc; | ||
599 | } | ||
600 | @@ -XXX,XX +XXX,XX @@ void job_unref_locked(Job *job) | ||
601 | assert(!job->txn); | ||
602 | |||
603 | if (job->driver->free) { | ||
604 | + AioContext *aio_context = job->aio_context; | ||
605 | job_unlock(); | ||
606 | + /* FIXME: aiocontext lock is required because cb calls blk_unref */ | ||
607 | + aio_context_acquire(aio_context); | ||
608 | job->driver->free(job); | ||
609 | + aio_context_release(aio_context); | ||
610 | job_lock(); | ||
611 | } | ||
612 | |||
613 | @@ -XXX,XX +XXX,XX @@ void job_enter_cond_locked(Job *job, bool(*fn)(Job *job)) | ||
614 | return; | ||
615 | } | ||
616 | |||
617 | - real_job_lock(); | ||
618 | if (job->busy) { | ||
619 | - real_job_unlock(); | ||
620 | return; | ||
621 | } | ||
622 | |||
623 | if (fn && !fn(job)) { | ||
624 | - real_job_unlock(); | ||
625 | return; | ||
626 | } | ||
627 | |||
628 | assert(!job->deferred_to_main_loop); | ||
629 | timer_del(&job->sleep_timer); | ||
630 | job->busy = true; | ||
631 | - real_job_unlock(); | ||
632 | job_unlock(); | ||
633 | aio_co_wake(job->co); | ||
634 | job_lock(); | ||
635 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn job_do_yield_locked(Job *job, uint64_t ns) | ||
636 | { | ||
637 | AioContext *next_aio_context; | ||
638 | |||
639 | - real_job_lock(); | ||
640 | if (ns != -1) { | ||
641 | timer_mod(&job->sleep_timer, ns); | ||
642 | } | ||
643 | job->busy = false; | ||
644 | job_event_idle_locked(job); | ||
645 | - real_job_unlock(); | ||
646 | job_unlock(); | ||
647 | qemu_coroutine_yield(); | ||
648 | job_lock(); | ||
649 | @@ -XXX,XX +XXX,XX @@ static void job_clean(Job *job) | ||
650 | } | ||
651 | } | ||
652 | |||
653 | -/* Called with job_mutex held, but releases it temporarily */ | ||
654 | +/* | ||
655 | + * Called with job_mutex held, but releases it temporarily. | ||
656 | + * Takes AioContext lock internally to invoke a job->driver callback. | ||
657 | + */ | ||
658 | static int job_finalize_single_locked(Job *job) | ||
659 | { | ||
660 | int job_ret; | ||
661 | + AioContext *ctx = job->aio_context; | ||
662 | |||
663 | assert(job_is_completed_locked(job)); | ||
664 | |||
665 | @@ -XXX,XX +XXX,XX @@ static int job_finalize_single_locked(Job *job) | ||
666 | |||
667 | job_ret = job->ret; | ||
668 | job_unlock(); | ||
669 | + aio_context_acquire(ctx); | ||
670 | |||
671 | if (!job_ret) { | ||
672 | job_commit(job); | ||
673 | @@ -XXX,XX +XXX,XX @@ static int job_finalize_single_locked(Job *job) | ||
674 | } | ||
675 | job_clean(job); | ||
676 | |||
677 | - job_lock(); | ||
678 | - | ||
679 | if (job->cb) { | ||
680 | - job_ret = job->ret; | ||
681 | - job_unlock(); | ||
682 | job->cb(job->opaque, job_ret); | ||
683 | - job_lock(); | ||
684 | } | ||
685 | |||
686 | + aio_context_release(ctx); | ||
687 | + job_lock(); | ||
27 | + | 688 | + |
28 | top_bs = bdrv_lookup_bs(s->top_id, s->top_id, NULL); | 689 | /* Emit events only if we actually started */ |
29 | if (!top_bs) { | 690 | if (job_started_locked(job)) { |
30 | return; | 691 | if (job_is_cancelled_locked(job)) { |
692 | @@ -XXX,XX +XXX,XX @@ static int job_finalize_single_locked(Job *job) | ||
693 | return 0; | ||
694 | } | ||
695 | |||
696 | -/* Called with job_mutex held, but releases it temporarily */ | ||
697 | +/* | ||
698 | + * Called with job_mutex held, but releases it temporarily. | ||
699 | + * Takes AioContext lock internally to invoke a job->driver callback. | ||
700 | + */ | ||
701 | static void job_cancel_async_locked(Job *job, bool force) | ||
702 | { | ||
703 | + AioContext *ctx = job->aio_context; | ||
704 | GLOBAL_STATE_CODE(); | ||
705 | if (job->driver->cancel) { | ||
706 | job_unlock(); | ||
707 | + aio_context_acquire(ctx); | ||
708 | force = job->driver->cancel(job, force); | ||
709 | + aio_context_release(ctx); | ||
710 | job_lock(); | ||
711 | } else { | ||
712 | /* No .cancel() means the job will behave as if force-cancelled */ | ||
713 | @@ -XXX,XX +XXX,XX @@ static void job_cancel_async_locked(Job *job, bool force) | ||
714 | } | ||
715 | } | ||
716 | |||
717 | -/* Called with job_mutex held, but releases it temporarily. */ | ||
718 | +/* | ||
719 | + * Called with job_mutex held, but releases it temporarily. | ||
720 | + * Takes AioContext lock internally to invoke a job->driver callback. | ||
721 | + */ | ||
722 | static void job_completed_txn_abort_locked(Job *job) | ||
723 | { | ||
724 | - AioContext *ctx; | ||
725 | JobTxn *txn = job->txn; | ||
726 | Job *other_job; | ||
727 | |||
728 | @@ -XXX,XX +XXX,XX @@ static void job_completed_txn_abort_locked(Job *job) | ||
729 | txn->aborting = true; | ||
730 | job_txn_ref_locked(txn); | ||
731 | |||
732 | - /* | ||
733 | - * We can only hold the single job's AioContext lock while calling | ||
734 | - * job_finalize_single() because the finalization callbacks can involve | ||
735 | - * calls of AIO_WAIT_WHILE(), which could deadlock otherwise. | ||
736 | - * Note that the job's AioContext may change when it is finalized. | ||
737 | - */ | ||
738 | job_ref_locked(job); | ||
739 | - aio_context_release(job->aio_context); | ||
740 | |||
741 | /* Other jobs are effectively cancelled by us, set the status for | ||
742 | * them; this job, however, may or may not be cancelled, depending | ||
743 | * on the caller, so leave it. */ | ||
744 | QLIST_FOREACH(other_job, &txn->jobs, txn_list) { | ||
745 | if (other_job != job) { | ||
746 | - ctx = other_job->aio_context; | ||
747 | - aio_context_acquire(ctx); | ||
748 | /* | ||
749 | * This is a transaction: If one job failed, no result will matter. | ||
750 | * Therefore, pass force=true to terminate all other jobs as quickly | ||
751 | * as possible. | ||
752 | */ | ||
753 | job_cancel_async_locked(other_job, true); | ||
754 | - aio_context_release(ctx); | ||
755 | } | ||
756 | } | ||
757 | while (!QLIST_EMPTY(&txn->jobs)) { | ||
758 | other_job = QLIST_FIRST(&txn->jobs); | ||
759 | - /* | ||
760 | - * The job's AioContext may change, so store it in @ctx so we | ||
761 | - * release the same context that we have acquired before. | ||
762 | - */ | ||
763 | - ctx = other_job->aio_context; | ||
764 | - aio_context_acquire(ctx); | ||
765 | if (!job_is_completed_locked(other_job)) { | ||
766 | assert(job_cancel_requested_locked(other_job)); | ||
767 | job_finish_sync_locked(other_job, NULL, NULL); | ||
768 | } | ||
769 | job_finalize_single_locked(other_job); | ||
770 | - aio_context_release(ctx); | ||
771 | } | ||
772 | |||
773 | - /* | ||
774 | - * Use job_ref()/job_unref() so we can read the AioContext here | ||
775 | - * even if the job went away during job_finalize_single(). | ||
776 | - */ | ||
777 | - aio_context_acquire(job->aio_context); | ||
778 | job_unref_locked(job); | ||
779 | - | ||
780 | job_txn_unref_locked(txn); | ||
781 | } | ||
782 | |||
783 | @@ -XXX,XX +XXX,XX @@ static void job_completed_txn_abort_locked(Job *job) | ||
784 | static int job_prepare_locked(Job *job) | ||
785 | { | ||
786 | int ret; | ||
787 | + AioContext *ctx = job->aio_context; | ||
788 | |||
789 | GLOBAL_STATE_CODE(); | ||
790 | + | ||
791 | if (job->ret == 0 && job->driver->prepare) { | ||
792 | job_unlock(); | ||
793 | + aio_context_acquire(ctx); | ||
794 | ret = job->driver->prepare(job); | ||
795 | + aio_context_release(ctx); | ||
796 | job_lock(); | ||
797 | job->ret = ret; | ||
798 | job_update_rc_locked(job); | ||
799 | } | ||
800 | + | ||
801 | return job->ret; | ||
802 | } | ||
803 | |||
804 | @@ -XXX,XX +XXX,XX @@ static void job_completed_locked(Job *job) | ||
805 | static void job_exit(void *opaque) | ||
806 | { | ||
807 | Job *job = (Job *)opaque; | ||
808 | - AioContext *ctx; | ||
809 | JOB_LOCK_GUARD(); | ||
810 | - | ||
811 | job_ref_locked(job); | ||
812 | - aio_context_acquire(job->aio_context); | ||
813 | |||
814 | /* This is a lie, we're not quiescent, but still doing the completion | ||
815 | * callbacks. However, completion callbacks tend to involve operations that | ||
816 | @@ -XXX,XX +XXX,XX @@ static void job_exit(void *opaque) | ||
817 | job_event_idle_locked(job); | ||
818 | |||
819 | job_completed_locked(job); | ||
820 | - | ||
821 | - /* | ||
822 | - * Note that calling job_completed can move the job to a different | ||
823 | - * aio_context, so we cannot cache from above. job_txn_apply takes care of | ||
824 | - * acquiring the new lock, and we ref/unref to avoid job_completed freeing | ||
825 | - * the job underneath us. | ||
826 | - */ | ||
827 | - ctx = job->aio_context; | ||
828 | job_unref_locked(job); | ||
829 | - aio_context_release(ctx); | ||
830 | } | ||
831 | |||
832 | /** | ||
833 | @@ -XXX,XX +XXX,XX @@ int job_cancel_sync(Job *job, bool force) | ||
834 | void job_cancel_sync_all(void) | ||
835 | { | ||
836 | Job *job; | ||
837 | - AioContext *aio_context; | ||
838 | JOB_LOCK_GUARD(); | ||
839 | |||
840 | while ((job = job_next_locked(NULL))) { | ||
841 | - aio_context = job->aio_context; | ||
842 | - aio_context_acquire(aio_context); | ||
843 | job_cancel_sync_locked(job, true); | ||
844 | - aio_context_release(aio_context); | ||
845 | } | ||
846 | } | ||
847 | |||
848 | @@ -XXX,XX +XXX,XX @@ int job_finish_sync_locked(Job *job, | ||
849 | } | ||
850 | |||
851 | job_unlock(); | ||
852 | - AIO_WAIT_WHILE(job->aio_context, | ||
853 | - (job_enter(job), !job_is_completed(job))); | ||
854 | + AIO_WAIT_WHILE_UNLOCKED(job->aio_context, | ||
855 | + (job_enter(job), !job_is_completed(job))); | ||
856 | job_lock(); | ||
857 | |||
858 | ret = (job_is_cancelled_locked(job) && job->ret == 0) | ||
859 | diff --git a/qemu-img.c b/qemu-img.c | ||
860 | index XXXXXXX..XXXXXXX 100644 | ||
861 | --- a/qemu-img.c | ||
862 | +++ b/qemu-img.c | ||
863 | @@ -XXX,XX +XXX,XX @@ static void run_block_job(BlockJob *job, Error **errp) | ||
864 | AioContext *aio_context = block_job_get_aio_context(job); | ||
865 | int ret = 0; | ||
866 | |||
867 | - aio_context_acquire(aio_context); | ||
868 | job_lock(); | ||
869 | job_ref_locked(&job->job); | ||
870 | do { | ||
871 | @@ -XXX,XX +XXX,XX @@ static void run_block_job(BlockJob *job, Error **errp) | ||
872 | } | ||
873 | job_unref_locked(&job->job); | ||
874 | job_unlock(); | ||
875 | - aio_context_release(aio_context); | ||
876 | |||
877 | /* publish completion progress only when success */ | ||
878 | if (!ret) { | ||
879 | diff --git a/tests/unit/test-bdrv-drain.c b/tests/unit/test-bdrv-drain.c | ||
880 | index XXXXXXX..XXXXXXX 100644 | ||
881 | --- a/tests/unit/test-bdrv-drain.c | ||
882 | +++ b/tests/unit/test-bdrv-drain.c | ||
883 | @@ -XXX,XX +XXX,XX @@ static void test_blockjob_common_drain_node(enum drain_type drain_type, | ||
884 | tjob->prepare_ret = -EIO; | ||
885 | break; | ||
886 | } | ||
887 | + aio_context_release(ctx); | ||
888 | |||
889 | job_start(&job->job); | ||
890 | - aio_context_release(ctx); | ||
891 | |||
892 | if (use_iothread) { | ||
893 | /* job_co_entry() is run in the I/O thread, wait for the actual job | ||
894 | @@ -XXX,XX +XXX,XX @@ static void test_blockjob_common_drain_node(enum drain_type drain_type, | ||
895 | g_assert_true(job->job.busy); /* We're in qemu_co_sleep_ns() */ | ||
896 | } | ||
897 | |||
898 | - aio_context_acquire(ctx); | ||
899 | WITH_JOB_LOCK_GUARD() { | ||
900 | ret = job_complete_sync_locked(&job->job, &error_abort); | ||
901 | } | ||
902 | g_assert_cmpint(ret, ==, (result == TEST_JOB_SUCCESS ? 0 : -EIO)); | ||
903 | |||
904 | + aio_context_acquire(ctx); | ||
905 | if (use_iothread) { | ||
906 | blk_set_aio_context(blk_src, qemu_get_aio_context(), &error_abort); | ||
907 | assert(blk_get_aio_context(blk_target) == qemu_get_aio_context()); | ||
908 | diff --git a/tests/unit/test-block-iothread.c b/tests/unit/test-block-iothread.c | ||
909 | index XXXXXXX..XXXXXXX 100644 | ||
910 | --- a/tests/unit/test-block-iothread.c | ||
911 | +++ b/tests/unit/test-block-iothread.c | ||
912 | @@ -XXX,XX +XXX,XX @@ static void test_attach_blockjob(void) | ||
913 | aio_poll(qemu_get_aio_context(), false); | ||
914 | } | ||
915 | |||
916 | - aio_context_acquire(ctx); | ||
917 | WITH_JOB_LOCK_GUARD() { | ||
918 | job_complete_sync_locked(&tjob->common.job, &error_abort); | ||
919 | } | ||
920 | + aio_context_acquire(ctx); | ||
921 | blk_set_aio_context(blk, qemu_get_aio_context(), &error_abort); | ||
922 | aio_context_release(ctx); | ||
923 | |||
924 | diff --git a/tests/unit/test-blockjob.c b/tests/unit/test-blockjob.c | ||
925 | index XXXXXXX..XXXXXXX 100644 | ||
926 | --- a/tests/unit/test-blockjob.c | ||
927 | +++ b/tests/unit/test-blockjob.c | ||
928 | @@ -XXX,XX +XXX,XX @@ static void cancel_common(CancelJob *s) | ||
929 | BlockJob *job = &s->common; | ||
930 | BlockBackend *blk = s->blk; | ||
931 | JobStatus sts = job->job.status; | ||
932 | - AioContext *ctx; | ||
933 | - | ||
934 | - ctx = job->job.aio_context; | ||
935 | - aio_context_acquire(ctx); | ||
936 | + AioContext *ctx = job->job.aio_context; | ||
937 | |||
938 | job_cancel_sync(&job->job, true); | ||
939 | WITH_JOB_LOCK_GUARD() { | ||
940 | @@ -XXX,XX +XXX,XX @@ static void cancel_common(CancelJob *s) | ||
941 | assert(job->job.status == JOB_STATUS_NULL); | ||
942 | job_unref_locked(&job->job); | ||
943 | } | ||
944 | - destroy_blk(blk); | ||
945 | |||
946 | + aio_context_acquire(ctx); | ||
947 | + destroy_blk(blk); | ||
948 | aio_context_release(ctx); | ||
949 | + | ||
950 | } | ||
951 | |||
952 | static void test_cancel_created(void) | ||
953 | @@ -XXX,XX +XXX,XX @@ static void test_cancel_concluded(void) | ||
954 | aio_poll(qemu_get_aio_context(), true); | ||
955 | assert_job_status_is(job, JOB_STATUS_PENDING); | ||
956 | |||
957 | - aio_context_acquire(job->aio_context); | ||
958 | WITH_JOB_LOCK_GUARD() { | ||
959 | job_finalize_locked(job, &error_abort); | ||
960 | + assert(job->status == JOB_STATUS_CONCLUDED); | ||
961 | } | ||
962 | - aio_context_release(job->aio_context); | ||
963 | - assert_job_status_is(job, JOB_STATUS_CONCLUDED); | ||
964 | |||
965 | cancel_common(s); | ||
966 | } | ||
967 | @@ -XXX,XX +XXX,XX @@ static void test_complete_in_standby(void) | ||
968 | |||
969 | /* Wait for the job to become READY */ | ||
970 | job_start(job); | ||
971 | - aio_context_acquire(ctx); | ||
972 | /* | ||
973 | * Here we are waiting for the status to change, so don't bother | ||
974 | * protecting the read every time. | ||
975 | */ | ||
976 | - AIO_WAIT_WHILE(ctx, job->status != JOB_STATUS_READY); | ||
977 | - aio_context_release(ctx); | ||
978 | + AIO_WAIT_WHILE_UNLOCKED(ctx, job->status != JOB_STATUS_READY); | ||
979 | |||
980 | /* Begin the drained section, pausing the job */ | ||
981 | bdrv_drain_all_begin(); | ||
982 | @@ -XXX,XX +XXX,XX @@ static void test_complete_in_standby(void) | ||
983 | aio_context_acquire(ctx); | ||
984 | /* This will schedule the job to resume it */ | ||
985 | bdrv_drain_all_end(); | ||
986 | + aio_context_release(ctx); | ||
987 | |||
988 | WITH_JOB_LOCK_GUARD() { | ||
989 | /* But the job cannot run, so it will remain on standby */ | ||
990 | @@ -XXX,XX +XXX,XX @@ static void test_complete_in_standby(void) | ||
991 | job_dismiss_locked(&job, &error_abort); | ||
992 | } | ||
993 | |||
994 | + aio_context_acquire(ctx); | ||
995 | destroy_blk(blk); | ||
996 | aio_context_release(ctx); | ||
997 | iothread_join(iothread); | ||
31 | -- | 998 | -- |
32 | 2.25.4 | 999 | 2.37.3 |
33 | |||
34 | diff view generated by jsdifflib |
1 | We made sure that iotests.py passes pylint. It would be a shame if we | 1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
---|---|---|---|
2 | allowed new patches in that break this again, so let's just add a | ||
3 | meta-test case that runs pylint on it. | ||
4 | 2 | ||
5 | While we don't pass mypy --strict yet, we can already run it with a few | 3 | Not sure what the atomic here was supposed to do, since job.busy |
6 | options that would be part of --strict to make sure that we won't | 4 | is protected by the job lock. Since the whole function |
7 | regress on these aspects at least until we can enable the full thing. | 5 | is called under job_mutex, just remove the atomic. |
8 | 6 | ||
9 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 7 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
10 | Message-Id: <20200511163529.349329-3-kwolf@redhat.com> | 8 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> |
11 | Reviewed-by: Max Reitz <mreitz@redhat.com> | 9 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> |
12 | Reviewed-by: John Snow <jsnow@redhat.com> | 10 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> |
11 | Message-Id: <20220926093214.506243-20-eesposit@redhat.com> | ||
13 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
14 | --- | 13 | --- |
15 | tests/qemu-iotests/297 | 44 ++++++++++++++++++++++++++++++++++++++ | 14 | blockjob.c | 2 +- |
16 | tests/qemu-iotests/297.out | 3 +++ | 15 | 1 file changed, 1 insertion(+), 1 deletion(-) |
17 | tests/qemu-iotests/group | 1 + | ||
18 | 3 files changed, 48 insertions(+) | ||
19 | create mode 100755 tests/qemu-iotests/297 | ||
20 | create mode 100644 tests/qemu-iotests/297.out | ||
21 | 16 | ||
22 | diff --git a/tests/qemu-iotests/297 b/tests/qemu-iotests/297 | 17 | diff --git a/blockjob.c b/blockjob.c |
23 | new file mode 100755 | ||
24 | index XXXXXXX..XXXXXXX | ||
25 | --- /dev/null | ||
26 | +++ b/tests/qemu-iotests/297 | ||
27 | @@ -XXX,XX +XXX,XX @@ | ||
28 | +#!/usr/bin/env bash | ||
29 | +# | ||
30 | +# Copyright (C) 2020 Red Hat, Inc. | ||
31 | +# | ||
32 | +# This program is free software; you can redistribute it and/or modify | ||
33 | +# it under the terms of the GNU General Public License as published by | ||
34 | +# the Free Software Foundation; either version 2 of the License, or | ||
35 | +# (at your option) any later version. | ||
36 | +# | ||
37 | +# This program is distributed in the hope that it will be useful, | ||
38 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
39 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
40 | +# GNU General Public License for more details. | ||
41 | +# | ||
42 | +# You should have received a copy of the GNU General Public License | ||
43 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
44 | + | ||
45 | +seq=$(basename $0) | ||
46 | +echo "QA output created by $seq" | ||
47 | + | ||
48 | +status=1 # failure is the default! | ||
49 | + | ||
50 | +# get standard environment | ||
51 | +. ./common.rc | ||
52 | + | ||
53 | +if ! type -p "pylint-3" > /dev/null; then | ||
54 | + _notrun "pylint-3 not found" | ||
55 | +fi | ||
56 | +if ! type -p "mypy" > /dev/null; then | ||
57 | + _notrun "mypy not found" | ||
58 | +fi | ||
59 | + | ||
60 | +pylint-3 --score=n iotests.py | ||
61 | + | ||
62 | +MYPYPATH=../../python/ mypy --warn-unused-configs --disallow-subclassing-any \ | ||
63 | + --disallow-any-generics --disallow-incomplete-defs \ | ||
64 | + --disallow-untyped-decorators --no-implicit-optional \ | ||
65 | + --warn-redundant-casts --warn-unused-ignores \ | ||
66 | + --no-implicit-reexport iotests.py | ||
67 | + | ||
68 | +# success, all done | ||
69 | +echo "*** done" | ||
70 | +rm -f $seq.full | ||
71 | +status=0 | ||
72 | diff --git a/tests/qemu-iotests/297.out b/tests/qemu-iotests/297.out | ||
73 | new file mode 100644 | ||
74 | index XXXXXXX..XXXXXXX | ||
75 | --- /dev/null | ||
76 | +++ b/tests/qemu-iotests/297.out | ||
77 | @@ -XXX,XX +XXX,XX @@ | ||
78 | +QA output created by 297 | ||
79 | +Success: no issues found in 1 source file | ||
80 | +*** done | ||
81 | diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group | ||
82 | index XXXXXXX..XXXXXXX 100644 | 18 | index XXXXXXX..XXXXXXX 100644 |
83 | --- a/tests/qemu-iotests/group | 19 | --- a/blockjob.c |
84 | +++ b/tests/qemu-iotests/group | 20 | +++ b/blockjob.c |
85 | @@ -XXX,XX +XXX,XX @@ | 21 | @@ -XXX,XX +XXX,XX @@ BlockJobInfo *block_job_query_locked(BlockJob *job, Error **errp) |
86 | 289 rw quick | 22 | info = g_new0(BlockJobInfo, 1); |
87 | 290 rw auto quick | 23 | info->type = g_strdup(job_type_str(&job->job)); |
88 | 292 rw auto quick | 24 | info->device = g_strdup(job->job.id); |
89 | +297 meta | 25 | - info->busy = qatomic_read(&job->job.busy); |
26 | + info->busy = job->job.busy; | ||
27 | info->paused = job->job.pause_count > 0; | ||
28 | info->offset = progress_current; | ||
29 | info->len = progress_total; | ||
90 | -- | 30 | -- |
91 | 2.25.4 | 31 | 2.37.3 |
92 | |||
93 | diff view generated by jsdifflib |
1 | From: Max Reitz <mreitz@redhat.com> | 1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 3 | These public functions are not used anywhere, thus can be dropped. |
4 | Message-Id: <20200513110544.176672-25-mreitz@redhat.com> | 4 | |
5 | Reviewed-by: Eric Blake <eblake@redhat.com> | 5 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
6 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
7 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
8 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> | ||
9 | Message-Id: <20220926093214.506243-21-eesposit@redhat.com> | ||
6 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
7 | --- | 11 | --- |
8 | include/block/block_int.h | 1 - | 12 | include/block/blockjob.h | 31 ++++++++++++------------------- |
9 | block.c | 60 ++------------------------------------- | 13 | blockjob.c | 16 ++-------------- |
10 | 2 files changed, 3 insertions(+), 58 deletions(-) | 14 | 2 files changed, 14 insertions(+), 33 deletions(-) |
11 | 15 | ||
12 | diff --git a/include/block/block_int.h b/include/block/block_int.h | 16 | diff --git a/include/block/blockjob.h b/include/block/blockjob.h |
13 | index XXXXXXX..XXXXXXX 100644 | 17 | index XXXXXXX..XXXXXXX 100644 |
14 | --- a/include/block/block_int.h | 18 | --- a/include/block/blockjob.h |
15 | +++ b/include/block/block_int.h | 19 | +++ b/include/block/blockjob.h |
16 | @@ -XXX,XX +XXX,XX @@ struct BdrvChildClass { | 20 | @@ -XXX,XX +XXX,XX @@ typedef struct BlockJob { |
17 | 21 | */ | |
18 | extern const BdrvChildClass child_of_bds; | 22 | |
19 | extern const BdrvChildClass child_file; | 23 | /** |
20 | -extern const BdrvChildClass child_backing; | 24 | - * block_job_next: |
21 | 25 | + * block_job_next_locked: | |
22 | struct BdrvChild { | 26 | * @job: A block job, or %NULL. |
23 | BlockDriverState *bs; | 27 | * |
24 | diff --git a/block.c b/block.c | 28 | * Get the next element from the list of block jobs after @job, or the |
29 | * first one if @job is %NULL. | ||
30 | * | ||
31 | * Returns the requested job, or %NULL if there are no more jobs left. | ||
32 | + * Called with job lock held. | ||
33 | */ | ||
34 | -BlockJob *block_job_next(BlockJob *job); | ||
35 | - | ||
36 | -/* Same as block_job_next(), but called with job lock held. */ | ||
37 | BlockJob *block_job_next_locked(BlockJob *job); | ||
38 | |||
39 | /** | ||
40 | @@ -XXX,XX +XXX,XX @@ BlockJob *block_job_next_locked(BlockJob *job); | ||
41 | * Get the block job identified by @id (which must not be %NULL). | ||
42 | * | ||
43 | * Returns the requested job, or %NULL if it doesn't exist. | ||
44 | + * Called with job lock *not* held. | ||
45 | */ | ||
46 | BlockJob *block_job_get(const char *id); | ||
47 | |||
48 | @@ -XXX,XX +XXX,XX @@ void block_job_remove_all_bdrv(BlockJob *job); | ||
49 | bool block_job_has_bdrv(BlockJob *job, BlockDriverState *bs); | ||
50 | |||
51 | /** | ||
52 | - * block_job_set_speed: | ||
53 | + * block_job_set_speed_locked: | ||
54 | * @job: The job to set the speed for. | ||
55 | * @speed: The new value | ||
56 | * @errp: Error object. | ||
57 | * | ||
58 | * Set a rate-limiting parameter for the job; the actual meaning may | ||
59 | * vary depending on the job type. | ||
60 | - */ | ||
61 | -bool block_job_set_speed(BlockJob *job, int64_t speed, Error **errp); | ||
62 | - | ||
63 | -/* | ||
64 | - * Same as block_job_set_speed(), but called with job lock held. | ||
65 | - * Might release the lock temporarily. | ||
66 | + * | ||
67 | + * Called with job lock held, but might release it temporarily. | ||
68 | */ | ||
69 | bool block_job_set_speed_locked(BlockJob *job, int64_t speed, Error **errp); | ||
70 | |||
71 | /** | ||
72 | - * block_job_query: | ||
73 | + * block_job_query_locked: | ||
74 | * @job: The job to get information about. | ||
75 | * | ||
76 | * Return information about a job. | ||
77 | + * | ||
78 | + * Called with job lock held. | ||
79 | */ | ||
80 | -BlockJobInfo *block_job_query(BlockJob *job, Error **errp); | ||
81 | - | ||
82 | -/* Same as block_job_query(), but called with job lock held. */ | ||
83 | BlockJobInfo *block_job_query_locked(BlockJob *job, Error **errp); | ||
84 | |||
85 | /** | ||
86 | - * block_job_iostatus_reset: | ||
87 | + * block_job_iostatus_reset_locked: | ||
88 | * @job: The job whose I/O status should be reset. | ||
89 | * | ||
90 | * Reset I/O status on @job and on BlockDriverState objects it uses, | ||
91 | * other than job->blk. | ||
92 | + * | ||
93 | + * Called with job lock held. | ||
94 | */ | ||
95 | -void block_job_iostatus_reset(BlockJob *job); | ||
96 | - | ||
97 | -/* Same as block_job_iostatus_reset(), but called with job lock held. */ | ||
98 | void block_job_iostatus_reset_locked(BlockJob *job); | ||
99 | |||
100 | /* | ||
101 | diff --git a/blockjob.c b/blockjob.c | ||
25 | index XXXXXXX..XXXXXXX 100644 | 102 | index XXXXXXX..XXXXXXX 100644 |
26 | --- a/block.c | 103 | --- a/blockjob.c |
27 | +++ b/block.c | 104 | +++ b/blockjob.c |
28 | @@ -XXX,XX +XXX,XX @@ static void bdrv_backing_attach(BdrvChild *c) | 105 | @@ -XXX,XX +XXX,XX @@ BlockJob *block_job_next_locked(BlockJob *bjob) |
29 | parent->backing_blocker); | 106 | return job ? container_of(job, BlockJob, job) : NULL; |
30 | } | 107 | } |
31 | 108 | ||
32 | -/* XXX: Will be removed along with child_backing */ | 109 | -BlockJob *block_job_next(BlockJob *bjob) |
33 | -static void bdrv_child_cb_attach_backing(BdrvChild *c) | ||
34 | -{ | 110 | -{ |
35 | - if (!(c->role & BDRV_CHILD_COW)) { | 111 | - JOB_LOCK_GUARD(); |
36 | - bdrv_backing_attach(c); | 112 | - return block_job_next_locked(bjob); |
37 | - } | ||
38 | - bdrv_child_cb_attach(c); | ||
39 | -} | 113 | -} |
40 | - | 114 | - |
41 | static void bdrv_backing_detach(BdrvChild *c) | 115 | BlockJob *block_job_get_locked(const char *id) |
42 | { | 116 | { |
43 | BlockDriverState *parent = c->opaque; | 117 | Job *job = job_get_locked(id); |
44 | @@ -XXX,XX +XXX,XX @@ static void bdrv_backing_detach(BdrvChild *c) | 118 | @@ -XXX,XX +XXX,XX @@ bool block_job_set_speed_locked(BlockJob *job, int64_t speed, Error **errp) |
45 | parent->backing_blocker = NULL; | 119 | return true; |
46 | } | 120 | } |
47 | 121 | ||
48 | -/* XXX: Will be removed along with child_backing */ | 122 | -bool block_job_set_speed(BlockJob *job, int64_t speed, Error **errp) |
49 | -static void bdrv_child_cb_detach_backing(BdrvChild *c) | 123 | +static bool block_job_set_speed(BlockJob *job, int64_t speed, Error **errp) |
124 | { | ||
125 | JOB_LOCK_GUARD(); | ||
126 | return block_job_set_speed_locked(job, speed, errp); | ||
127 | @@ -XXX,XX +XXX,XX @@ BlockJobInfo *block_job_query_locked(BlockJob *job, Error **errp) | ||
128 | return info; | ||
129 | } | ||
130 | |||
131 | -BlockJobInfo *block_job_query(BlockJob *job, Error **errp) | ||
50 | -{ | 132 | -{ |
51 | - if (!(c->role & BDRV_CHILD_COW)) { | 133 | - JOB_LOCK_GUARD(); |
52 | - bdrv_backing_detach(c); | 134 | - return block_job_query_locked(job, errp); |
53 | - } | ||
54 | - bdrv_child_cb_detach(c); | ||
55 | -} | 135 | -} |
56 | - | 136 | - |
57 | -/* | 137 | /* Called with job lock held */ |
58 | - * Returns the options and flags that bs->backing should get, based on the | 138 | static void block_job_iostatus_set_err_locked(BlockJob *job, int error) |
59 | - * given options and flags for the parent BDS | ||
60 | - */ | ||
61 | -static void bdrv_backing_options(BdrvChildRole role, bool parent_is_format, | ||
62 | - int *child_flags, QDict *child_options, | ||
63 | - int parent_flags, QDict *parent_options) | ||
64 | -{ | ||
65 | - bdrv_inherited_options(BDRV_CHILD_COW, true, | ||
66 | - child_flags, child_options, | ||
67 | - parent_flags, parent_options); | ||
68 | -} | ||
69 | - | ||
70 | static int bdrv_backing_update_filename(BdrvChild *c, BlockDriverState *base, | ||
71 | const char *filename, Error **errp) | ||
72 | { | 139 | { |
73 | @@ -XXX,XX +XXX,XX @@ static int bdrv_backing_update_filename(BdrvChild *c, BlockDriverState *base, | 140 | @@ -XXX,XX +XXX,XX @@ void block_job_iostatus_reset_locked(BlockJob *job) |
74 | return ret; | 141 | job->iostatus = BLOCK_DEVICE_IO_STATUS_OK; |
75 | } | 142 | } |
76 | 143 | ||
77 | -const BdrvChildClass child_backing = { | 144 | -void block_job_iostatus_reset(BlockJob *job) |
78 | - .parent_is_bds = true, | 145 | +static void block_job_iostatus_reset(BlockJob *job) |
79 | - .get_parent_desc = bdrv_child_get_parent_desc, | ||
80 | - .attach = bdrv_child_cb_attach_backing, | ||
81 | - .detach = bdrv_child_cb_detach_backing, | ||
82 | - .inherit_options = bdrv_backing_options, | ||
83 | - .drained_begin = bdrv_child_cb_drained_begin, | ||
84 | - .drained_poll = bdrv_child_cb_drained_poll, | ||
85 | - .drained_end = bdrv_child_cb_drained_end, | ||
86 | - .inactivate = bdrv_child_cb_inactivate, | ||
87 | - .update_filename = bdrv_backing_update_filename, | ||
88 | - .can_set_aio_ctx = bdrv_child_cb_can_set_aio_ctx, | ||
89 | - .set_aio_ctx = bdrv_child_cb_set_aio_ctx, | ||
90 | -}; | ||
91 | - | ||
92 | /* | ||
93 | * Returns the options and flags that a generic child of a BDS should | ||
94 | * get, based on the given options and flags for the parent BDS. | ||
95 | @@ -XXX,XX +XXX,XX @@ static void bdrv_default_perms_for_cow(BlockDriverState *bs, BdrvChild *c, | ||
96 | uint64_t perm, uint64_t shared, | ||
97 | uint64_t *nperm, uint64_t *nshared) | ||
98 | { | 146 | { |
99 | - assert(child_class == &child_backing || | 147 | JOB_LOCK_GUARD(); |
100 | - (child_class == &child_of_bds && (role & BDRV_CHILD_COW))); | 148 | block_job_iostatus_reset_locked(job); |
101 | + assert(child_class == &child_of_bds && (role & BDRV_CHILD_COW)); | ||
102 | |||
103 | /* | ||
104 | * We want consistent read from backing files if the parent needs it. | ||
105 | @@ -XXX,XX +XXX,XX @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c, | ||
106 | uint64_t perm, uint64_t shared, | ||
107 | uint64_t *nperm, uint64_t *nshared) | ||
108 | { | ||
109 | - bool backing = (child_class == &child_backing); | ||
110 | - | ||
111 | if (child_class == &child_of_bds) { | ||
112 | bdrv_default_perms(bs, c, child_class, role, reopen_queue, | ||
113 | perm, shared, nperm, nshared); | ||
114 | return; | ||
115 | } | ||
116 | |||
117 | - assert(child_class == &child_backing || child_class == &child_file); | ||
118 | + assert(child_class == &child_file); | ||
119 | |||
120 | - if (!backing) { | ||
121 | - bdrv_default_perms_for_storage(bs, c, child_class, role, reopen_queue, | ||
122 | - perm, shared, nperm, nshared); | ||
123 | - } else { | ||
124 | - bdrv_default_perms_for_cow(bs, c, child_class, role, reopen_queue, | ||
125 | + bdrv_default_perms_for_storage(bs, c, child_class, role, reopen_queue, | ||
126 | perm, shared, nperm, nshared); | ||
127 | - } | ||
128 | } | ||
129 | |||
130 | void bdrv_default_perms(BlockDriverState *bs, BdrvChild *c, | ||
131 | -- | 149 | -- |
132 | 2.25.4 | 150 | 2.37.3 |
133 | |||
134 | diff view generated by jsdifflib |
1 | From: Max Reitz <mreitz@redhat.com> | 1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | For now, all callers (effectively) pass 0 and no callee evaluates thie | 3 | These public functions are not used anywhere, thus can be dropped. |
4 | value. Later patches will change both. | 4 | Also, since this is the final job API that doesn't use AioContext |
5 | lock and replaces it with job_lock, adjust all remaining function | ||
6 | documentation to clearly specify if the job lock is taken or not. | ||
5 | 7 | ||
6 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 8 | Also document the locking requirements for a few functions |
7 | Reviewed-by: Eric Blake <eblake@redhat.com> | 9 | where the second version is not removed. |
8 | Message-Id: <20200513110544.176672-8-mreitz@redhat.com> | 10 | |
11 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
12 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
13 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
14 | Message-Id: <20220926093214.506243-22-eesposit@redhat.com> | ||
15 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> | ||
9 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 16 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
10 | --- | 17 | --- |
11 | include/block/block_int.h | 3 ++- | 18 | include/qemu/job.h | 110 +++++++++++++------------------------ |
12 | block.c | 40 +++++++++++++++++++++++---------------- | 19 | job.c | 107 ++---------------------------------- |
13 | block/block-backend.c | 3 ++- | 20 | tests/unit/test-blockjob.c | 4 +- |
14 | block/vvfat.c | 3 ++- | 21 | 3 files changed, 46 insertions(+), 175 deletions(-) |
15 | 4 files changed, 30 insertions(+), 19 deletions(-) | ||
16 | 22 | ||
17 | diff --git a/include/block/block_int.h b/include/block/block_int.h | 23 | diff --git a/include/qemu/job.h b/include/qemu/job.h |
18 | index XXXXXXX..XXXXXXX 100644 | 24 | index XXXXXXX..XXXXXXX 100644 |
19 | --- a/include/block/block_int.h | 25 | --- a/include/qemu/job.h |
20 | +++ b/include/block/block_int.h | 26 | +++ b/include/qemu/job.h |
21 | @@ -XXX,XX +XXX,XX @@ struct BdrvChildClass { | 27 | @@ -XXX,XX +XXX,XX @@ JobTxn *job_txn_new(void); |
22 | * non-BDS parents. */ | 28 | /** |
23 | bool parent_is_bds; | 29 | * Release a reference that was previously acquired with job_txn_add_job or |
24 | 30 | * job_txn_new. If it's the last reference to the object, it will be freed. | |
25 | - void (*inherit_options)(int *child_flags, QDict *child_options, | 31 | + * |
26 | + void (*inherit_options)(BdrvChildRole role, | 32 | + * Called with job lock *not* held. |
27 | + int *child_flags, QDict *child_options, | 33 | */ |
28 | int parent_flags, QDict *parent_options); | 34 | void job_txn_unref(JobTxn *txn); |
29 | 35 | ||
30 | void (*change_media)(BdrvChild *child, bool load); | 36 | @@ -XXX,XX +XXX,XX @@ void *job_create(const char *job_id, const JobDriver *driver, JobTxn *txn, |
31 | diff --git a/block.c b/block.c | 37 | /** |
38 | * Add a reference to Job refcnt, it will be decreased with job_unref, and then | ||
39 | * be freed if it comes to be the last reference. | ||
40 | + * | ||
41 | + * Called with job lock held. | ||
42 | */ | ||
43 | -void job_ref(Job *job); | ||
44 | - | ||
45 | -/* Same as job_ref(), but called with job lock held. */ | ||
46 | void job_ref_locked(Job *job); | ||
47 | |||
48 | /** | ||
49 | - * Release a reference that was previously acquired with job_ref() or | ||
50 | + * Release a reference that was previously acquired with job_ref_locked() or | ||
51 | * job_create(). If it's the last reference to the object, it will be freed. | ||
52 | * | ||
53 | * Takes AioContext lock internally to invoke a job->driver callback. | ||
54 | + * Called with job lock held. | ||
55 | */ | ||
56 | -void job_unref(Job *job); | ||
57 | - | ||
58 | -/* Same as job_unref(), but called with job lock held. */ | ||
59 | void job_unref_locked(Job *job); | ||
60 | |||
61 | /** | ||
62 | @@ -XXX,XX +XXX,XX @@ void job_progress_increase_remaining(Job *job, uint64_t delta); | ||
63 | * Conditionally enter the job coroutine if the job is ready to run, not | ||
64 | * already busy and fn() returns true. fn() is called while under the job_lock | ||
65 | * critical section. | ||
66 | - */ | ||
67 | -void job_enter_cond(Job *job, bool(*fn)(Job *job)); | ||
68 | - | ||
69 | -/* | ||
70 | - * Same as job_enter_cond(), but called with job lock held. | ||
71 | - * Might release the lock temporarily. | ||
72 | + * | ||
73 | + * Called with job lock held, but might release it temporarily. | ||
74 | */ | ||
75 | void job_enter_cond_locked(Job *job, bool(*fn)(Job *job)); | ||
76 | |||
77 | @@ -XXX,XX +XXX,XX @@ bool job_cancel_requested(Job *job); | ||
78 | |||
79 | /** | ||
80 | * Returns whether the job is in a completed state. | ||
81 | - * Called with job_mutex *not* held. | ||
82 | + * Called with job lock held. | ||
83 | */ | ||
84 | -bool job_is_completed(Job *job); | ||
85 | - | ||
86 | -/* Same as job_is_completed(), but called with job lock held. */ | ||
87 | bool job_is_completed_locked(Job *job); | ||
88 | |||
89 | /** | ||
90 | @@ -XXX,XX +XXX,XX @@ bool job_is_ready_locked(Job *job); | ||
91 | /** | ||
92 | * Request @job to pause at the next pause point. Must be paired with | ||
93 | * job_resume(). If the job is supposed to be resumed by user action, call | ||
94 | - * job_user_pause() instead. | ||
95 | + * job_user_pause_locked() instead. | ||
96 | + * | ||
97 | + * Called with job lock *not* held. | ||
98 | */ | ||
99 | void job_pause(Job *job); | ||
100 | |||
101 | /* Same as job_pause(), but called with job lock held. */ | ||
102 | void job_pause_locked(Job *job); | ||
103 | |||
104 | -/** Resumes a @job paused with job_pause. */ | ||
105 | +/** Resumes a @job paused with job_pause. Called with job lock *not* held. */ | ||
106 | void job_resume(Job *job); | ||
107 | |||
108 | /* | ||
109 | @@ -XXX,XX +XXX,XX @@ void job_resume_locked(Job *job); | ||
110 | /** | ||
111 | * Asynchronously pause the specified @job. | ||
112 | * Do not allow a resume until a matching call to job_user_resume. | ||
113 | + * Called with job lock held. | ||
114 | */ | ||
115 | -void job_user_pause(Job *job, Error **errp); | ||
116 | - | ||
117 | -/* Same as job_user_pause(), but called with job lock held. */ | ||
118 | void job_user_pause_locked(Job *job, Error **errp); | ||
119 | |||
120 | -/** Returns true if the job is user-paused. */ | ||
121 | -bool job_user_paused(Job *job); | ||
122 | - | ||
123 | -/* Same as job_user_paused(), but called with job lock held. */ | ||
124 | +/** | ||
125 | + * Returns true if the job is user-paused. | ||
126 | + * Called with job lock held. | ||
127 | + */ | ||
128 | bool job_user_paused_locked(Job *job); | ||
129 | |||
130 | /** | ||
131 | * Resume the specified @job. | ||
132 | - * Must be paired with a preceding job_user_pause. | ||
133 | - */ | ||
134 | -void job_user_resume(Job *job, Error **errp); | ||
135 | - | ||
136 | -/* | ||
137 | - * Same as job_user_resume(), but called with job lock held. | ||
138 | - * Might release the lock temporarily. | ||
139 | + * Must be paired with a preceding job_user_pause_locked. | ||
140 | + * Called with job lock held, but might release it temporarily. | ||
141 | */ | ||
142 | void job_user_resume_locked(Job *job, Error **errp); | ||
143 | |||
144 | @@ -XXX,XX +XXX,XX @@ void job_user_resume_locked(Job *job, Error **errp); | ||
145 | * first one if @job is %NULL. | ||
146 | * | ||
147 | * Returns the requested job, or %NULL if there are no more jobs left. | ||
148 | + * Called with job lock *not* held. | ||
149 | */ | ||
150 | Job *job_next(Job *job); | ||
151 | |||
152 | @@ -XXX,XX +XXX,XX @@ Job *job_next_locked(Job *job); | ||
153 | * Get the job identified by @id (which must not be %NULL). | ||
154 | * | ||
155 | * Returns the requested job, or %NULL if it doesn't exist. | ||
156 | + * Called with job lock held. | ||
157 | */ | ||
158 | -Job *job_get(const char *id); | ||
159 | - | ||
160 | -/* Same as job_get(), but called with job lock held. */ | ||
161 | Job *job_get_locked(const char *id); | ||
162 | |||
163 | /** | ||
164 | * Check whether the verb @verb can be applied to @job in its current state. | ||
165 | * Returns 0 if the verb can be applied; otherwise errp is set and -EPERM | ||
166 | * returned. | ||
167 | + * | ||
168 | + * Called with job lock held. | ||
169 | */ | ||
170 | -int job_apply_verb(Job *job, JobVerb verb, Error **errp); | ||
171 | - | ||
172 | -/* Same as job_apply_verb, but called with job lock held. */ | ||
173 | int job_apply_verb_locked(Job *job, JobVerb verb, Error **errp); | ||
174 | |||
175 | /** | ||
176 | @@ -XXX,XX +XXX,XX @@ void job_early_fail(Job *job); | ||
177 | */ | ||
178 | void job_transition_to_ready(Job *job); | ||
179 | |||
180 | -/** Asynchronously complete the specified @job. */ | ||
181 | -void job_complete(Job *job, Error **errp); | ||
182 | - | ||
183 | -/* | ||
184 | - * Same as job_complete(), but called with job lock held. | ||
185 | - * Might release the lock temporarily. | ||
186 | +/** | ||
187 | + * Asynchronously complete the specified @job. | ||
188 | + * Called with job lock held, but might release it temporarily. | ||
189 | */ | ||
190 | void job_complete_locked(Job *job, Error **errp); | ||
191 | |||
192 | /** | ||
193 | * Asynchronously cancel the specified @job. If @force is true, the job should | ||
194 | * be cancelled immediately without waiting for a consistent state. | ||
195 | + * Called with job lock held. | ||
196 | */ | ||
197 | -void job_cancel(Job *job, bool force); | ||
198 | - | ||
199 | -/* Same as job_cancel(), but called with job lock held. */ | ||
200 | void job_cancel_locked(Job *job, bool force); | ||
201 | |||
202 | /** | ||
203 | - * Cancels the specified job like job_cancel(), but may refuse to do so if the | ||
204 | - * operation isn't meaningful in the current state of the job. | ||
205 | + * Cancels the specified job like job_cancel_locked(), but may refuse | ||
206 | + * to do so if the operation isn't meaningful in the current state of the job. | ||
207 | + * Called with job lock held. | ||
208 | */ | ||
209 | -void job_user_cancel(Job *job, bool force, Error **errp); | ||
210 | - | ||
211 | -/* Same as job_user_cancel(), but called with job lock held. */ | ||
212 | void job_user_cancel_locked(Job *job, bool force, Error **errp); | ||
213 | |||
214 | /** | ||
215 | @@ -XXX,XX +XXX,XX @@ void job_cancel_sync_all(void); | ||
216 | |||
217 | /** | ||
218 | * @job: The job to be completed. | ||
219 | - * @errp: Error object which may be set by job_complete(); this is not | ||
220 | + * @errp: Error object which may be set by job_complete_locked(); this is not | ||
221 | * necessarily set on every error, the job return value has to be | ||
222 | * checked as well. | ||
223 | * | ||
224 | @@ -XXX,XX +XXX,XX @@ void job_cancel_sync_all(void); | ||
225 | * function). | ||
226 | * | ||
227 | * Returns the return value from the job. | ||
228 | - * Called with job_lock *not* held. | ||
229 | + * Called with job_lock held. | ||
230 | */ | ||
231 | -int job_complete_sync(Job *job, Error **errp); | ||
232 | - | ||
233 | -/* Same as job_complete_sync, but called with job lock held. */ | ||
234 | int job_complete_sync_locked(Job *job, Error **errp); | ||
235 | |||
236 | /** | ||
237 | @@ -XXX,XX +XXX,XX @@ int job_complete_sync_locked(Job *job, Error **errp); | ||
238 | * FIXME: Make the below statement universally true: | ||
239 | * For jobs that support the manual workflow mode, all graph changes that occur | ||
240 | * as a result will occur after this command and before a successful reply. | ||
241 | + * | ||
242 | + * Called with job lock held. | ||
243 | */ | ||
244 | -void job_finalize(Job *job, Error **errp); | ||
245 | - | ||
246 | -/* Same as job_finalize(), but called with job lock held. */ | ||
247 | void job_finalize_locked(Job *job, Error **errp); | ||
248 | |||
249 | /** | ||
250 | * Remove the concluded @job from the query list and resets the passed pointer | ||
251 | * to %NULL. Returns an error if the job is not actually concluded. | ||
252 | + * | ||
253 | + * Called with job lock held. | ||
254 | */ | ||
255 | -void job_dismiss(Job **job, Error **errp); | ||
256 | - | ||
257 | -/* Same as job_dismiss(), but called with job lock held. */ | ||
258 | void job_dismiss_locked(Job **job, Error **errp); | ||
259 | |||
260 | /** | ||
261 | @@ -XXX,XX +XXX,XX @@ void job_dismiss_locked(Job **job, Error **errp); | ||
262 | * Returns 0 if the job is successfully completed, -ECANCELED if the job was | ||
263 | * cancelled before completing, and -errno in other error cases. | ||
264 | * | ||
265 | - * Called with job_lock *not* held. | ||
266 | - */ | ||
267 | -int job_finish_sync(Job *job, void (*finish)(Job *, Error **errp), | ||
268 | - Error **errp); | ||
269 | - | ||
270 | -/* | ||
271 | - * Same as job_finish_sync(), but called with job lock held. | ||
272 | - * Might release the lock temporarily. | ||
273 | + * Called with job_lock held, but might release it temporarily. | ||
274 | */ | ||
275 | int job_finish_sync_locked(Job *job, void (*finish)(Job *, Error **errp), | ||
276 | Error **errp); | ||
277 | diff --git a/job.c b/job.c | ||
32 | index XXXXXXX..XXXXXXX 100644 | 278 | index XXXXXXX..XXXXXXX 100644 |
33 | --- a/block.c | 279 | --- a/job.c |
34 | +++ b/block.c | 280 | +++ b/job.c |
35 | @@ -XXX,XX +XXX,XX @@ static BlockDriverState *bdrv_open_inherit(const char *filename, | 281 | @@ -XXX,XX +XXX,XX @@ int job_apply_verb_locked(Job *job, JobVerb verb, Error **errp) |
36 | QDict *options, int flags, | 282 | return -EPERM; |
37 | BlockDriverState *parent, | 283 | } |
38 | const BdrvChildClass *child_class, | 284 | |
39 | + BdrvChildRole child_role, | 285 | -int job_apply_verb(Job *job, JobVerb verb, Error **errp) |
40 | Error **errp); | 286 | -{ |
41 | 287 | - JOB_LOCK_GUARD(); | |
42 | /* If non-zero, use only whitelisted block drivers */ | 288 | - return job_apply_verb_locked(job, verb, errp); |
43 | @@ -XXX,XX +XXX,XX @@ static void bdrv_temp_snapshot_options(int *child_flags, QDict *child_options, | 289 | -} |
44 | * Returns the options and flags that bs->file should get if a protocol driver | 290 | - |
45 | * is expected, based on the given options and flags for the parent BDS | 291 | JobType job_type(const Job *job) |
46 | */ | 292 | { |
47 | -static void bdrv_inherited_options(int *child_flags, QDict *child_options, | 293 | return job->driver->job_type; |
48 | +static void bdrv_inherited_options(BdrvChildRole role, | 294 | @@ -XXX,XX +XXX,XX @@ bool job_is_completed_locked(Job *job) |
49 | + int *child_flags, QDict *child_options, | 295 | return false; |
50 | int parent_flags, QDict *parent_options) | 296 | } |
51 | { | 297 | |
52 | int flags = parent_flags; | 298 | -bool job_is_completed(Job *job) |
53 | @@ -XXX,XX +XXX,XX @@ const BdrvChildClass child_file = { | 299 | +static bool job_is_completed(Job *job) |
54 | * (and not only protocols) is permitted for it, based on the given options and | 300 | { |
55 | * flags for the parent BDS | 301 | JOB_LOCK_GUARD(); |
56 | */ | 302 | return job_is_completed_locked(job); |
57 | -static void bdrv_inherited_fmt_options(int *child_flags, QDict *child_options, | 303 | @@ -XXX,XX +XXX,XX @@ Job *job_get_locked(const char *id) |
58 | +static void bdrv_inherited_fmt_options(BdrvChildRole role, | 304 | return NULL; |
59 | + int *child_flags, QDict *child_options, | 305 | } |
60 | int parent_flags, QDict *parent_options) | 306 | |
61 | { | 307 | -Job *job_get(const char *id) |
62 | - child_file.inherit_options(child_flags, child_options, | 308 | -{ |
63 | + child_file.inherit_options(role, child_flags, child_options, | 309 | - JOB_LOCK_GUARD(); |
64 | parent_flags, parent_options); | 310 | - return job_get_locked(id); |
65 | 311 | -} | |
66 | *child_flags &= ~(BDRV_O_PROTOCOL | BDRV_O_NO_IO); | 312 | - |
67 | @@ -XXX,XX +XXX,XX @@ static void bdrv_backing_detach(BdrvChild *c) | 313 | void job_set_aio_context(Job *job, AioContext *ctx) |
68 | * Returns the options and flags that bs->backing should get, based on the | 314 | { |
69 | * given options and flags for the parent BDS | 315 | /* protect against read in job_finish_sync_locked and job_start */ |
70 | */ | 316 | @@ -XXX,XX +XXX,XX @@ void job_ref_locked(Job *job) |
71 | -static void bdrv_backing_options(int *child_flags, QDict *child_options, | 317 | ++job->refcnt; |
72 | +static void bdrv_backing_options(BdrvChildRole role, | 318 | } |
73 | + int *child_flags, QDict *child_options, | 319 | |
74 | int parent_flags, QDict *parent_options) | 320 | -void job_ref(Job *job) |
75 | { | 321 | -{ |
76 | int flags = parent_flags; | 322 | - JOB_LOCK_GUARD(); |
77 | @@ -XXX,XX +XXX,XX @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options, | 323 | - job_ref_locked(job); |
324 | -} | ||
325 | - | ||
326 | void job_unref_locked(Job *job) | ||
327 | { | ||
328 | GLOBAL_STATE_CODE(); | ||
329 | @@ -XXX,XX +XXX,XX @@ void job_unref_locked(Job *job) | ||
78 | } | 330 | } |
79 | 331 | } | |
80 | backing_hd = bdrv_open_inherit(backing_filename, reference, options, 0, bs, | 332 | |
81 | - &child_backing, errp); | 333 | -void job_unref(Job *job) |
82 | + &child_backing, 0, errp); | 334 | -{ |
83 | if (!backing_hd) { | 335 | - JOB_LOCK_GUARD(); |
84 | bs->open_flags |= BDRV_O_NO_BACKING; | 336 | - job_unref_locked(job); |
85 | error_prepend(errp, "Could not open backing file: "); | 337 | -} |
86 | @@ -XXX,XX +XXX,XX @@ free_exit: | 338 | - |
87 | static BlockDriverState * | 339 | void job_progress_update(Job *job, uint64_t done) |
88 | bdrv_open_child_bs(const char *filename, QDict *options, const char *bdref_key, | 340 | { |
89 | BlockDriverState *parent, const BdrvChildClass *child_class, | 341 | progress_work_done(&job->progress, done); |
90 | - bool allow_none, Error **errp) | 342 | @@ -XXX,XX +XXX,XX @@ void job_enter_cond_locked(Job *job, bool(*fn)(Job *job)) |
91 | + BdrvChildRole child_role, bool allow_none, Error **errp) | 343 | job_lock(); |
92 | { | 344 | } |
93 | BlockDriverState *bs = NULL; | 345 | |
94 | QDict *image_options; | 346 | -void job_enter_cond(Job *job, bool(*fn)(Job *job)) |
95 | @@ -XXX,XX +XXX,XX @@ bdrv_open_child_bs(const char *filename, QDict *options, const char *bdref_key, | 347 | -{ |
348 | - JOB_LOCK_GUARD(); | ||
349 | - job_enter_cond_locked(job, fn); | ||
350 | -} | ||
351 | - | ||
352 | void job_enter(Job *job) | ||
353 | { | ||
354 | JOB_LOCK_GUARD(); | ||
355 | @@ -XXX,XX +XXX,XX @@ void coroutine_fn job_pause_point(Job *job) | ||
356 | job_pause_point_locked(job); | ||
357 | } | ||
358 | |||
359 | -static void coroutine_fn job_yield_locked(Job *job) | ||
360 | +void coroutine_fn job_yield(Job *job) | ||
361 | { | ||
362 | + JOB_LOCK_GUARD(); | ||
363 | assert(job->busy); | ||
364 | |||
365 | /* Check cancellation *before* setting busy = false, too! */ | ||
366 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn job_yield_locked(Job *job) | ||
367 | job_pause_point_locked(job); | ||
368 | } | ||
369 | |||
370 | -void coroutine_fn job_yield(Job *job) | ||
371 | -{ | ||
372 | - JOB_LOCK_GUARD(); | ||
373 | - job_yield_locked(job); | ||
374 | -} | ||
375 | - | ||
376 | void coroutine_fn job_sleep_ns(Job *job, int64_t ns) | ||
377 | { | ||
378 | JOB_LOCK_GUARD(); | ||
379 | @@ -XXX,XX +XXX,XX @@ void job_user_pause_locked(Job *job, Error **errp) | ||
380 | job_pause_locked(job); | ||
381 | } | ||
382 | |||
383 | -void job_user_pause(Job *job, Error **errp) | ||
384 | -{ | ||
385 | - JOB_LOCK_GUARD(); | ||
386 | - job_user_pause_locked(job, errp); | ||
387 | -} | ||
388 | - | ||
389 | bool job_user_paused_locked(Job *job) | ||
390 | { | ||
391 | return job->user_paused; | ||
392 | } | ||
393 | |||
394 | -bool job_user_paused(Job *job) | ||
395 | -{ | ||
396 | - JOB_LOCK_GUARD(); | ||
397 | - return job_user_paused_locked(job); | ||
398 | -} | ||
399 | - | ||
400 | void job_user_resume_locked(Job *job, Error **errp) | ||
401 | { | ||
402 | assert(job); | ||
403 | @@ -XXX,XX +XXX,XX @@ void job_user_resume_locked(Job *job, Error **errp) | ||
404 | job_resume_locked(job); | ||
405 | } | ||
406 | |||
407 | -void job_user_resume(Job *job, Error **errp) | ||
408 | -{ | ||
409 | - JOB_LOCK_GUARD(); | ||
410 | - job_user_resume_locked(job, errp); | ||
411 | -} | ||
412 | - | ||
413 | /* Called with job_mutex held, but releases it temporarily. */ | ||
414 | static void job_do_dismiss_locked(Job *job) | ||
415 | { | ||
416 | @@ -XXX,XX +XXX,XX @@ void job_dismiss_locked(Job **jobptr, Error **errp) | ||
417 | *jobptr = NULL; | ||
418 | } | ||
419 | |||
420 | -void job_dismiss(Job **jobptr, Error **errp) | ||
421 | -{ | ||
422 | - JOB_LOCK_GUARD(); | ||
423 | - job_dismiss_locked(jobptr, errp); | ||
424 | -} | ||
425 | - | ||
426 | void job_early_fail(Job *job) | ||
427 | { | ||
428 | JOB_LOCK_GUARD(); | ||
429 | @@ -XXX,XX +XXX,XX @@ void job_finalize_locked(Job *job, Error **errp) | ||
430 | job_do_finalize_locked(job); | ||
431 | } | ||
432 | |||
433 | -void job_finalize(Job *job, Error **errp) | ||
434 | -{ | ||
435 | - JOB_LOCK_GUARD(); | ||
436 | - job_finalize_locked(job, errp); | ||
437 | -} | ||
438 | - | ||
439 | /* Called with job_mutex held. */ | ||
440 | static int job_transition_to_pending_locked(Job *job) | ||
441 | { | ||
442 | @@ -XXX,XX +XXX,XX @@ void job_cancel_locked(Job *job, bool force) | ||
96 | } | 443 | } |
97 | 444 | } | |
98 | bs = bdrv_open_inherit(filename, reference, image_options, 0, | 445 | |
99 | - parent, child_class, errp); | 446 | -void job_cancel(Job *job, bool force) |
100 | + parent, child_class, child_role, errp); | 447 | -{ |
101 | if (!bs) { | 448 | - JOB_LOCK_GUARD(); |
102 | goto done; | 449 | - job_cancel_locked(job, force); |
103 | } | 450 | -} |
104 | @@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_open_child(const char *filename, | 451 | - |
105 | BlockDriverState *bs; | 452 | void job_user_cancel_locked(Job *job, bool force, Error **errp) |
106 | 453 | { | |
107 | bs = bdrv_open_child_bs(filename, options, bdref_key, parent, child_class, | 454 | if (job_apply_verb_locked(job, JOB_VERB_CANCEL, errp)) { |
108 | - allow_none, errp); | 455 | @@ -XXX,XX +XXX,XX @@ void job_user_cancel_locked(Job *job, bool force, Error **errp) |
109 | + child_role, allow_none, errp); | 456 | job_cancel_locked(job, force); |
110 | if (bs == NULL) { | 457 | } |
111 | return NULL; | 458 | |
112 | } | 459 | -void job_user_cancel(Job *job, bool force, Error **errp) |
113 | @@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_open_blockdev_ref(BlockdevRef *ref, Error **errp) | 460 | -{ |
114 | 461 | - JOB_LOCK_GUARD(); | |
115 | } | 462 | - job_user_cancel_locked(job, force, errp); |
116 | 463 | -} | |
117 | - bs = bdrv_open_inherit(NULL, reference, qdict, 0, NULL, NULL, errp); | 464 | - |
118 | + bs = bdrv_open_inherit(NULL, reference, qdict, 0, NULL, NULL, 0, errp); | 465 | -/* A wrapper around job_cancel() taking an Error ** parameter so it may be |
119 | obj = NULL; | 466 | - * used with job_finish_sync() without the need for (rather nasty) function |
120 | qobject_unref(obj); | 467 | - * pointer casts there. |
121 | visit_free(v); | 468 | +/* A wrapper around job_cancel_locked() taking an Error ** parameter so it may |
122 | @@ -XXX,XX +XXX,XX @@ static BlockDriverState *bdrv_open_inherit(const char *filename, | 469 | + * be used with job_finish_sync_locked() without the need for (rather nasty) |
123 | QDict *options, int flags, | 470 | + * function pointer casts there. |
124 | BlockDriverState *parent, | 471 | * |
125 | const BdrvChildClass *child_class, | 472 | * Called with job_mutex held. |
126 | + BdrvChildRole child_role, | 473 | */ |
127 | Error **errp) | 474 | @@ -XXX,XX +XXX,XX @@ int job_complete_sync_locked(Job *job, Error **errp) |
128 | { | 475 | return job_finish_sync_locked(job, job_complete_locked, errp); |
129 | int ret; | 476 | } |
130 | @@ -XXX,XX +XXX,XX @@ static BlockDriverState *bdrv_open_inherit(const char *filename, | 477 | |
131 | 478 | -int job_complete_sync(Job *job, Error **errp) | |
132 | if (child_class) { | 479 | -{ |
133 | bs->inherits_from = parent; | 480 | - JOB_LOCK_GUARD(); |
134 | - child_class->inherit_options(&flags, options, | 481 | - return job_complete_sync_locked(job, errp); |
135 | + child_class->inherit_options(child_role, &flags, options, | 482 | -} |
136 | parent->open_flags, parent->options); | 483 | - |
137 | } | 484 | void job_complete_locked(Job *job, Error **errp) |
138 | 485 | { | |
139 | @@ -XXX,XX +XXX,XX @@ static BlockDriverState *bdrv_open_inherit(const char *filename, | 486 | /* Should not be reachable via external interface for internal jobs */ |
140 | flags, options); | 487 | @@ -XXX,XX +XXX,XX @@ void job_complete_locked(Job *job, Error **errp) |
141 | /* Let bdrv_backing_options() override "read-only" */ | 488 | job_lock(); |
142 | qdict_del(options, BDRV_OPT_READ_ONLY); | 489 | } |
143 | - bdrv_backing_options(&flags, options, flags, options); | 490 | |
144 | + bdrv_backing_options(0, &flags, options, flags, options); | 491 | -void job_complete(Job *job, Error **errp) |
145 | } | 492 | -{ |
146 | 493 | - JOB_LOCK_GUARD(); | |
147 | bs->open_flags = flags; | 494 | - job_complete_locked(job, errp); |
148 | @@ -XXX,XX +XXX,XX @@ static BlockDriverState *bdrv_open_inherit(const char *filename, | 495 | -} |
149 | BlockDriverState *file_bs; | 496 | - |
150 | 497 | int job_finish_sync_locked(Job *job, | |
151 | file_bs = bdrv_open_child_bs(filename, options, "file", bs, | 498 | void (*finish)(Job *, Error **errp), |
152 | - &child_file, true, &local_err); | 499 | Error **errp) |
153 | + &child_file, 0, true, &local_err); | 500 | @@ -XXX,XX +XXX,XX @@ int job_finish_sync_locked(Job *job, |
154 | if (local_err) { | 501 | job_unref_locked(job); |
155 | goto fail; | 502 | return ret; |
156 | } | 503 | } |
157 | @@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_open(const char *filename, const char *reference, | 504 | - |
158 | QDict *options, int flags, Error **errp) | 505 | -int job_finish_sync(Job *job, void (*finish)(Job *, Error **errp), Error **errp) |
159 | { | 506 | -{ |
160 | return bdrv_open_inherit(filename, reference, options, flags, NULL, | 507 | - JOB_LOCK_GUARD(); |
161 | - NULL, errp); | 508 | - return job_finish_sync_locked(job, finish, errp); |
162 | + NULL, 0, errp); | 509 | -} |
163 | } | 510 | diff --git a/tests/unit/test-blockjob.c b/tests/unit/test-blockjob.c |
164 | |||
165 | /* Return true if the NULL-terminated @list contains @str */ | ||
166 | @@ -XXX,XX +XXX,XX @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue, | ||
167 | BlockDriverState *bs, | ||
168 | QDict *options, | ||
169 | const BdrvChildClass *klass, | ||
170 | + BdrvChildRole role, | ||
171 | QDict *parent_options, | ||
172 | int parent_flags, | ||
173 | bool keep_old_opts) | ||
174 | @@ -XXX,XX +XXX,XX @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue, | ||
175 | /* Inherit from parent node */ | ||
176 | if (parent_options) { | ||
177 | flags = 0; | ||
178 | - klass->inherit_options(&flags, options, parent_flags, parent_options); | ||
179 | + klass->inherit_options(role, &flags, options, | ||
180 | + parent_flags, parent_options); | ||
181 | } else { | ||
182 | flags = bdrv_get_flags(bs); | ||
183 | } | ||
184 | @@ -XXX,XX +XXX,XX @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue, | ||
185 | } | ||
186 | |||
187 | bdrv_reopen_queue_child(bs_queue, child->bs, new_child_options, | ||
188 | - child->klass, options, flags, child_keep_old); | ||
189 | + child->klass, child->role, options, flags, | ||
190 | + child_keep_old); | ||
191 | } | ||
192 | |||
193 | return bs_queue; | ||
194 | @@ -XXX,XX +XXX,XX @@ BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue, | ||
195 | BlockDriverState *bs, | ||
196 | QDict *options, bool keep_old_opts) | ||
197 | { | ||
198 | - return bdrv_reopen_queue_child(bs_queue, bs, options, NULL, NULL, 0, | ||
199 | + return bdrv_reopen_queue_child(bs_queue, bs, options, NULL, 0, NULL, 0, | ||
200 | keep_old_opts); | ||
201 | } | ||
202 | |||
203 | diff --git a/block/block-backend.c b/block/block-backend.c | ||
204 | index XXXXXXX..XXXXXXX 100644 | 511 | index XXXXXXX..XXXXXXX 100644 |
205 | --- a/block/block-backend.c | 512 | --- a/tests/unit/test-blockjob.c |
206 | +++ b/block/block-backend.c | 513 | +++ b/tests/unit/test-blockjob.c |
207 | @@ -XXX,XX +XXX,XX @@ static QTAILQ_HEAD(, BlockBackend) block_backends = | 514 | @@ -XXX,XX +XXX,XX @@ static const BlockJobDriver test_yielding_driver = { |
208 | static QTAILQ_HEAD(, BlockBackend) monitor_block_backends = | ||
209 | QTAILQ_HEAD_INITIALIZER(monitor_block_backends); | ||
210 | |||
211 | -static void blk_root_inherit_options(int *child_flags, QDict *child_options, | ||
212 | +static void blk_root_inherit_options(BdrvChildRole role, | ||
213 | + int *child_flags, QDict *child_options, | ||
214 | int parent_flags, QDict *parent_options) | ||
215 | { | ||
216 | /* We're not supposed to call this function for root nodes */ | ||
217 | diff --git a/block/vvfat.c b/block/vvfat.c | ||
218 | index XXXXXXX..XXXXXXX 100644 | ||
219 | --- a/block/vvfat.c | ||
220 | +++ b/block/vvfat.c | ||
221 | @@ -XXX,XX +XXX,XX @@ static BlockDriver vvfat_write_target = { | ||
222 | .bdrv_co_pwritev = write_target_commit, | ||
223 | }; | 515 | }; |
224 | 516 | ||
225 | -static void vvfat_qcow_options(int *child_flags, QDict *child_options, | 517 | /* |
226 | +static void vvfat_qcow_options(BdrvChildRole role, | 518 | - * Test that job_complete() works even on jobs that are in a paused |
227 | + int *child_flags, QDict *child_options, | 519 | + * Test that job_complete_locked() works even on jobs that are in a paused |
228 | int parent_flags, QDict *parent_options) | 520 | * state (i.e., STANDBY). |
229 | { | 521 | * |
230 | qdict_set_default_str(child_options, BDRV_OPT_READ_ONLY, "off"); | 522 | * To do this, run YieldingJob in an IO thread, get it into the READY |
523 | @@ -XXX,XX +XXX,XX @@ static const BlockJobDriver test_yielding_driver = { | ||
524 | * acquire the context so the job will not be entered and will thus | ||
525 | * remain on STANDBY. | ||
526 | * | ||
527 | - * job_complete() should still work without error. | ||
528 | + * job_complete_locked() should still work without error. | ||
529 | * | ||
530 | * Note that on the QMP interface, it is impossible to lock an IO | ||
531 | * thread before a drained section ends. In practice, the | ||
231 | -- | 532 | -- |
232 | 2.25.4 | 533 | 2.37.3 |
233 | |||
234 | diff view generated by jsdifflib |
1 | This tests that the mirror job catches situations where the target node | 1 | The field is unused (only ever set, but never read) since commit |
---|---|---|---|
2 | has a different size than the source node. It must also forbid resize | 2 | ac9185603. Additionally, the commit message of commit 34fa110e already |
3 | operations when the job is already running. | 3 | explained earlier why it's unreliable. Remove it. |
4 | 4 | ||
5 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 5 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
6 | Reviewed-by: Eric Blake <eblake@redhat.com> | 6 | Message-Id: <20220923142838.91043-1-kwolf@redhat.com> |
7 | Message-Id: <20200511135825.219437-5-kwolf@redhat.com> | ||
8 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
9 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 7 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
11 | --- | 8 | --- |
12 | tests/qemu-iotests/041 | 45 ++++++++++++++++++++++++++++++++++++++ | 9 | block/file-posix.c | 9 --------- |
13 | tests/qemu-iotests/041.out | 4 ++-- | 10 | 1 file changed, 9 deletions(-) |
14 | 2 files changed, 47 insertions(+), 2 deletions(-) | ||
15 | 11 | ||
16 | diff --git a/tests/qemu-iotests/041 b/tests/qemu-iotests/041 | 12 | diff --git a/block/file-posix.c b/block/file-posix.c |
17 | index XXXXXXX..XXXXXXX 100755 | ||
18 | --- a/tests/qemu-iotests/041 | ||
19 | +++ b/tests/qemu-iotests/041 | ||
20 | @@ -XXX,XX +XXX,XX @@ class TestSingleBlockdev(TestSingleDrive): | ||
21 | target=self.qmp_target) | ||
22 | self.assert_qmp(result, 'error/class', 'GenericError') | ||
23 | |||
24 | + def do_test_resize(self, device, node): | ||
25 | + def pre_finalize(): | ||
26 | + if device: | ||
27 | + result = self.vm.qmp('block_resize', device=device, size=65536) | ||
28 | + self.assert_qmp(result, 'error/class', 'GenericError') | ||
29 | + | ||
30 | + result = self.vm.qmp('block_resize', node_name=node, size=65536) | ||
31 | + self.assert_qmp(result, 'error/class', 'GenericError') | ||
32 | + | ||
33 | + result = self.vm.qmp(self.qmp_cmd, job_id='job0', device='drive0', | ||
34 | + sync='full', target=self.qmp_target, | ||
35 | + auto_finalize=False, auto_dismiss=False) | ||
36 | + self.assert_qmp(result, 'return', {}) | ||
37 | + | ||
38 | + result = self.vm.run_job('job0', auto_finalize=False, | ||
39 | + pre_finalize=pre_finalize) | ||
40 | + self.assertEqual(result, None) | ||
41 | + | ||
42 | + def test_source_resize(self): | ||
43 | + self.do_test_resize('drive0', 'top') | ||
44 | + | ||
45 | + def test_target_resize(self): | ||
46 | + self.do_test_resize(None, self.qmp_target) | ||
47 | + | ||
48 | + def do_test_target_size(self, size): | ||
49 | + result = self.vm.qmp('block_resize', node_name=self.qmp_target, | ||
50 | + size=size) | ||
51 | + self.assert_qmp(result, 'return', {}) | ||
52 | + | ||
53 | + result = self.vm.qmp(self.qmp_cmd, job_id='job0', | ||
54 | + device='drive0', sync='full', auto_dismiss=False, | ||
55 | + target=self.qmp_target) | ||
56 | + self.assert_qmp(result, 'return', {}) | ||
57 | + | ||
58 | + result = self.vm.run_job('job0') | ||
59 | + self.assertEqual(result, 'Source and target image have different sizes') | ||
60 | + | ||
61 | + def test_small_target(self): | ||
62 | + self.do_test_target_size(self.image_len // 2) | ||
63 | + | ||
64 | + def test_large_target(self): | ||
65 | + self.do_test_target_size(self.image_len * 2) | ||
66 | + | ||
67 | test_large_cluster = None | ||
68 | test_image_not_found = None | ||
69 | test_small_buffer2 = None | ||
70 | @@ -XXX,XX +XXX,XX @@ class TestSingleDriveZeroLength(TestSingleDrive): | ||
71 | |||
72 | class TestSingleBlockdevZeroLength(TestSingleBlockdev): | ||
73 | image_len = 0 | ||
74 | + test_small_target = None | ||
75 | + test_large_target = None | ||
76 | |||
77 | class TestSingleDriveUnalignedLength(TestSingleDrive): | ||
78 | image_len = 1025 * 1024 | ||
79 | diff --git a/tests/qemu-iotests/041.out b/tests/qemu-iotests/041.out | ||
80 | index XXXXXXX..XXXXXXX 100644 | 13 | index XXXXXXX..XXXXXXX 100644 |
81 | --- a/tests/qemu-iotests/041.out | 14 | --- a/block/file-posix.c |
82 | +++ b/tests/qemu-iotests/041.out | 15 | +++ b/block/file-posix.c |
83 | @@ -XXX,XX +XXX,XX @@ | 16 | @@ -XXX,XX +XXX,XX @@ typedef struct BDRVRawState { |
84 | -.............................................................................................. | 17 | |
85 | +........................................................................................................ | 18 | bool has_discard:1; |
86 | ---------------------------------------------------------------------- | 19 | bool has_write_zeroes:1; |
87 | -Ran 94 tests | 20 | - bool discard_zeroes:1; |
88 | +Ran 104 tests | 21 | bool use_linux_aio:1; |
89 | 22 | bool use_linux_io_uring:1; | |
90 | OK | 23 | int page_cache_inconsistent; /* errno from fdatasync failure */ |
24 | @@ -XXX,XX +XXX,XX @@ static int raw_open_common(BlockDriverState *bs, QDict *options, | ||
25 | ret = -EINVAL; | ||
26 | goto fail; | ||
27 | } else { | ||
28 | - s->discard_zeroes = true; | ||
29 | s->has_fallocate = true; | ||
30 | } | ||
31 | } else { | ||
32 | @@ -XXX,XX +XXX,XX @@ static int raw_open_common(BlockDriverState *bs, QDict *options, | ||
33 | } | ||
34 | |||
35 | if (S_ISBLK(st.st_mode)) { | ||
36 | -#ifdef BLKDISCARDZEROES | ||
37 | - unsigned int arg; | ||
38 | - if (ioctl(s->fd, BLKDISCARDZEROES, &arg) == 0 && arg) { | ||
39 | - s->discard_zeroes = true; | ||
40 | - } | ||
41 | -#endif | ||
42 | #ifdef __linux__ | ||
43 | /* On Linux 3.10, BLKDISCARD leaves stale data in the page cache. Do | ||
44 | * not rely on the contents of discarded blocks unless using O_DIRECT. | ||
45 | * Same for BLKZEROOUT. | ||
46 | */ | ||
47 | if (!(bs->open_flags & BDRV_O_NOCACHE)) { | ||
48 | - s->discard_zeroes = false; | ||
49 | s->has_write_zeroes = false; | ||
50 | } | ||
51 | #endif | ||
91 | -- | 52 | -- |
92 | 2.25.4 | 53 | 2.37.3 |
93 | |||
94 | diff view generated by jsdifflib |