1 | The following changes since commit 527266f324def9f7f392fe3b0dd940cb8dc699d9: | 1 | The following changes since commit 67b6526cf042f22521feff5ea521a05d3dd2bf8f: |
---|---|---|---|
2 | 2 | ||
3 | Merge remote-tracking branch 'remotes/armbru/tags/pull-pflash-2019-03-26' into staging (2019-03-26 09:57:07 +0000) | 3 | Merge remote-tracking branch 'remotes/bonzini-gitlab/tags/for-upstream' into staging (2022-01-13 13:59:56 +0000) |
4 | 4 | ||
5 | are available in the Git repository at: | 5 | are available in the Git repository at: |
6 | 6 | ||
7 | git://repo.or.cz/qemu/kevin.git tags/for-upstream | 7 | git://repo.or.cz/qemu/kevin.git tags/for-upstream |
8 | 8 | ||
9 | for you to fetch changes up to c6e3f520c802c5cb2de80576aba7f9f1fe985d8b: | 9 | for you to fetch changes up to e5e748739562268ef4063ee77bf53ad7040b25c7: |
10 | 10 | ||
11 | qemu-io: Add write -n for BDRV_REQ_NO_FALLBACK (2019-03-26 11:37:51 +0100) | 11 | iotests/testrunner.py: refactor test_field_width (2022-01-14 12:03:16 +0100) |
12 | 12 | ||
13 | ---------------------------------------------------------------- | 13 | ---------------------------------------------------------------- |
14 | Block layer patches: | 14 | Block layer patches |
15 | 15 | ||
16 | - Fix slow pre-zeroing in qemu-img convert | 16 | - qemu-storage-daemon: Add vhost-user-blk help |
17 | - Test case for block job pausing on I/O errors | 17 | - block-backend: Fix use-after-free for BDS pointers after aio_poll() |
18 | - qemu-img: Fix sparseness of output image with unaligned ranges | ||
19 | - vvfat: Fix crashes in read-write mode | ||
20 | - Fix device deletion events with -device JSON syntax | ||
21 | - Code cleanups | ||
18 | 22 | ||
19 | ---------------------------------------------------------------- | 23 | ---------------------------------------------------------------- |
20 | Kevin Wolf (6): | 24 | Daniel P. Berrangé (1): |
21 | block: Remove error messages in bdrv_make_zero() | 25 | softmmu: fix device deletion events with -device JSON syntax |
22 | block: Add BDRV_REQ_NO_FALLBACK | ||
23 | block: Advertise BDRV_REQ_NO_FALLBACK in filter drivers | ||
24 | file-posix: Support BDRV_REQ_NO_FALLBACK for zero writes | ||
25 | qemu-img: Use BDRV_REQ_NO_FALLBACK for pre-zeroing | ||
26 | qemu-io: Add write -n for BDRV_REQ_NO_FALLBACK | ||
27 | 26 | ||
28 | Vladimir Sementsov-Ogievskiy (1): | 27 | Emanuele Giuseppe Esposito (3): |
29 | iotests: add 248: test resume mirror after auto pause on ENOSPC | 28 | block_int: make bdrv_backing_overridden static |
29 | include/sysemu/blockdev.h: remove drive_mark_claimed_by_board and inline drive_def | ||
30 | include/sysemu/blockdev.h: remove drive_get_max_devs | ||
30 | 31 | ||
31 | include/block/block.h | 7 ++++- | 32 | Hanna Reitz (2): |
32 | include/block/raw-aio.h | 1 + | 33 | iotests/stream-error-on-reset: New test |
33 | block/blkdebug.c | 2 +- | 34 | iotests/308: Fix for CAP_DAC_OVERRIDE |
34 | block/copy-on-read.c | 7 ++--- | ||
35 | block/file-posix.c | 24 ++++++++++------ | ||
36 | block/io.c | 16 +++++++---- | ||
37 | block/mirror.c | 3 +- | ||
38 | block/raw-format.c | 2 +- | ||
39 | qemu-img.c | 2 +- | ||
40 | qemu-io-cmds.c | 13 +++++++-- | ||
41 | tests/qemu-iotests/248 | 71 ++++++++++++++++++++++++++++++++++++++++++++++ | ||
42 | tests/qemu-iotests/248.out | 8 ++++++ | ||
43 | tests/qemu-iotests/group | 1 + | ||
44 | 13 files changed, 133 insertions(+), 24 deletions(-) | ||
45 | create mode 100755 tests/qemu-iotests/248 | ||
46 | create mode 100644 tests/qemu-iotests/248.out | ||
47 | 35 | ||
36 | Kevin Wolf (3): | ||
37 | vvfat: Fix size of temporary qcow file | ||
38 | vvfat: Fix vvfat_write() for writes before the root directory | ||
39 | iotests: Test qemu-img convert of zeroed data cluster | ||
40 | |||
41 | Philippe Mathieu-Daudé (3): | ||
42 | docs: Correct 'vhost-user-blk' spelling | ||
43 | qemu-storage-daemon: Add vhost-user-blk help | ||
44 | qapi/block: Restrict vhost-user-blk to CONFIG_VHOST_USER_BLK_SERVER | ||
45 | |||
46 | Stefan Hajnoczi (1): | ||
47 | block-backend: prevent dangling BDS pointers across aio_poll() | ||
48 | |||
49 | Vladimir Sementsov-Ogievskiy (3): | ||
50 | qemu-img: make is_allocated_sectors() more efficient | ||
51 | block: drop BLK_PERM_GRAPH_MOD | ||
52 | iotests/testrunner.py: refactor test_field_width | ||
53 | |||
54 | qapi/block-core.json | 7 +- | ||
55 | qapi/block-export.json | 6 +- | ||
56 | qapi/qdev.json | 5 +- | ||
57 | docs/tools/qemu-storage-daemon.rst | 2 +- | ||
58 | include/block/block.h | 9 +- | ||
59 | include/block/block_int.h | 3 - | ||
60 | include/sysemu/blockdev.h | 3 - | ||
61 | block.c | 11 +- | ||
62 | block/block-backend.c | 19 ++- | ||
63 | block/commit.c | 1 - | ||
64 | block/mirror.c | 15 +-- | ||
65 | block/monitor/block-hmp-cmds.c | 2 +- | ||
66 | block/vvfat.c | 37 ++++-- | ||
67 | blockdev.c | 24 +--- | ||
68 | hw/block/block.c | 3 +- | ||
69 | qemu-img.c | 23 +++- | ||
70 | softmmu/vl.c | 8 +- | ||
71 | storage-daemon/qemu-storage-daemon.c | 13 ++ | ||
72 | tests/qtest/device-plug-test.c | 19 +++ | ||
73 | scripts/render_block_graph.py | 1 - | ||
74 | tests/qemu-iotests/testrunner.py | 21 ++-- | ||
75 | tests/qemu-iotests/122 | 1 + | ||
76 | tests/qemu-iotests/122.out | 2 + | ||
77 | tests/qemu-iotests/273.out | 4 - | ||
78 | tests/qemu-iotests/308 | 25 +++- | ||
79 | tests/qemu-iotests/308.out | 2 +- | ||
80 | tests/qemu-iotests/tests/stream-error-on-reset | 140 +++++++++++++++++++++ | ||
81 | tests/qemu-iotests/tests/stream-error-on-reset.out | 5 + | ||
82 | 28 files changed, 307 insertions(+), 104 deletions(-) | ||
83 | create mode 100755 tests/qemu-iotests/tests/stream-error-on-reset | ||
84 | create mode 100644 tests/qemu-iotests/tests/stream-error-on-reset.out | ||
85 | |||
86 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
1 | 2 | ||
3 | bdrv_backing_overridden is only used in block.c, so there is | ||
4 | no need to leave it in block_int.h | ||
5 | |||
6 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
7 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
8 | Message-Id: <20211215121140.456939-2-eesposit@redhat.com> | ||
9 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
10 | --- | ||
11 | include/block/block_int.h | 3 --- | ||
12 | block.c | 4 +++- | ||
13 | 2 files changed, 3 insertions(+), 4 deletions(-) | ||
14 | |||
15 | diff --git a/include/block/block_int.h b/include/block/block_int.h | ||
16 | index XXXXXXX..XXXXXXX 100644 | ||
17 | --- a/include/block/block_int.h | ||
18 | +++ b/include/block/block_int.h | ||
19 | @@ -XXX,XX +XXX,XX @@ BlockDriver *bdrv_probe_all(const uint8_t *buf, int buf_size, | ||
20 | void bdrv_parse_filename_strip_prefix(const char *filename, const char *prefix, | ||
21 | QDict *options); | ||
22 | |||
23 | -bool bdrv_backing_overridden(BlockDriverState *bs); | ||
24 | - | ||
25 | - | ||
26 | /** | ||
27 | * bdrv_add_aio_context_notifier: | ||
28 | * | ||
29 | diff --git a/block.c b/block.c | ||
30 | index XXXXXXX..XXXXXXX 100644 | ||
31 | --- a/block.c | ||
32 | +++ b/block.c | ||
33 | @@ -XXX,XX +XXX,XX @@ static int bdrv_reopen_prepare(BDRVReopenState *reopen_state, | ||
34 | static void bdrv_reopen_commit(BDRVReopenState *reopen_state); | ||
35 | static void bdrv_reopen_abort(BDRVReopenState *reopen_state); | ||
36 | |||
37 | +static bool bdrv_backing_overridden(BlockDriverState *bs); | ||
38 | + | ||
39 | /* If non-zero, use only whitelisted block drivers */ | ||
40 | static int use_bdrv_whitelist; | ||
41 | |||
42 | @@ -XXX,XX +XXX,XX @@ static bool append_strong_runtime_options(QDict *d, BlockDriverState *bs) | ||
43 | /* Note: This function may return false positives; it may return true | ||
44 | * even if opening the backing file specified by bs's image header | ||
45 | * would result in exactly bs->backing. */ | ||
46 | -bool bdrv_backing_overridden(BlockDriverState *bs) | ||
47 | +static bool bdrv_backing_overridden(BlockDriverState *bs) | ||
48 | { | ||
49 | if (bs->backing) { | ||
50 | return strcmp(bs->auto_backing_file, | ||
51 | -- | ||
52 | 2.31.1 | ||
53 | |||
54 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
1 | 2 | ||
3 | drive_def is only a particular use case of | ||
4 | qemu_opts_parse_noisily, so it can be inlined. | ||
5 | |||
6 | Also remove drive_mark_claimed_by_board, as it is only defined | ||
7 | but not implemented (nor used) anywhere. | ||
8 | |||
9 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
10 | Message-Id: <20211215121140.456939-3-eesposit@redhat.com> | ||
11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
12 | --- | ||
13 | include/sysemu/blockdev.h | 2 -- | ||
14 | block/monitor/block-hmp-cmds.c | 2 +- | ||
15 | blockdev.c | 7 +------ | ||
16 | softmmu/vl.c | 4 +++- | ||
17 | 4 files changed, 5 insertions(+), 10 deletions(-) | ||
18 | |||
19 | diff --git a/include/sysemu/blockdev.h b/include/sysemu/blockdev.h | ||
20 | index XXXXXXX..XXXXXXX 100644 | ||
21 | --- a/include/sysemu/blockdev.h | ||
22 | +++ b/include/sysemu/blockdev.h | ||
23 | @@ -XXX,XX +XXX,XX @@ BlockBackend *blk_by_legacy_dinfo(DriveInfo *dinfo); | ||
24 | void override_max_devs(BlockInterfaceType type, int max_devs); | ||
25 | |||
26 | DriveInfo *drive_get(BlockInterfaceType type, int bus, int unit); | ||
27 | -void drive_mark_claimed_by_board(void); | ||
28 | void drive_check_orphaned(void); | ||
29 | DriveInfo *drive_get_by_index(BlockInterfaceType type, int index); | ||
30 | int drive_get_max_bus(BlockInterfaceType type); | ||
31 | int drive_get_max_devs(BlockInterfaceType type); | ||
32 | |||
33 | -QemuOpts *drive_def(const char *optstr); | ||
34 | QemuOpts *drive_add(BlockInterfaceType type, int index, const char *file, | ||
35 | const char *optstr); | ||
36 | DriveInfo *drive_new(QemuOpts *arg, BlockInterfaceType block_default_type, | ||
37 | diff --git a/block/monitor/block-hmp-cmds.c b/block/monitor/block-hmp-cmds.c | ||
38 | index XXXXXXX..XXXXXXX 100644 | ||
39 | --- a/block/monitor/block-hmp-cmds.c | ||
40 | +++ b/block/monitor/block-hmp-cmds.c | ||
41 | @@ -XXX,XX +XXX,XX @@ void hmp_drive_add(Monitor *mon, const QDict *qdict) | ||
42 | return; | ||
43 | } | ||
44 | |||
45 | - opts = drive_def(optstr); | ||
46 | + opts = qemu_opts_parse_noisily(qemu_find_opts("drive"), optstr, false); | ||
47 | if (!opts) | ||
48 | return; | ||
49 | |||
50 | diff --git a/blockdev.c b/blockdev.c | ||
51 | index XXXXXXX..XXXXXXX 100644 | ||
52 | --- a/blockdev.c | ||
53 | +++ b/blockdev.c | ||
54 | @@ -XXX,XX +XXX,XX @@ static int drive_index_to_unit_id(BlockInterfaceType type, int index) | ||
55 | return max_devs ? index % max_devs : index; | ||
56 | } | ||
57 | |||
58 | -QemuOpts *drive_def(const char *optstr) | ||
59 | -{ | ||
60 | - return qemu_opts_parse_noisily(qemu_find_opts("drive"), optstr, false); | ||
61 | -} | ||
62 | - | ||
63 | QemuOpts *drive_add(BlockInterfaceType type, int index, const char *file, | ||
64 | const char *optstr) | ||
65 | { | ||
66 | QemuOpts *opts; | ||
67 | |||
68 | - opts = drive_def(optstr); | ||
69 | + opts = qemu_opts_parse_noisily(qemu_find_opts("drive"), optstr, false); | ||
70 | if (!opts) { | ||
71 | return NULL; | ||
72 | } | ||
73 | diff --git a/softmmu/vl.c b/softmmu/vl.c | ||
74 | index XXXXXXX..XXXXXXX 100644 | ||
75 | --- a/softmmu/vl.c | ||
76 | +++ b/softmmu/vl.c | ||
77 | @@ -XXX,XX +XXX,XX @@ void qemu_init(int argc, char **argv, char **envp) | ||
78 | break; | ||
79 | } | ||
80 | case QEMU_OPTION_drive: | ||
81 | - if (drive_def(optarg) == NULL) { | ||
82 | + opts = qemu_opts_parse_noisily(qemu_find_opts("drive"), | ||
83 | + optarg, false); | ||
84 | + if (opts == NULL) { | ||
85 | exit(1); | ||
86 | } | ||
87 | break; | ||
88 | -- | ||
89 | 2.31.1 | ||
90 | |||
91 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
1 | 2 | ||
3 | Remove drive_get_max_devs, as it is not used by anyone. | ||
4 | |||
5 | Last use was removed in commit 8f2d75e81d5 | ||
6 | ("hw: Drop superfluous special checks for orphaned -drive"). | ||
7 | |||
8 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
9 | Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> | ||
10 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
11 | Message-Id: <20211215121140.456939-4-eesposit@redhat.com> | ||
12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
13 | --- | ||
14 | include/sysemu/blockdev.h | 1 - | ||
15 | blockdev.c | 17 ----------------- | ||
16 | 2 files changed, 18 deletions(-) | ||
17 | |||
18 | diff --git a/include/sysemu/blockdev.h b/include/sysemu/blockdev.h | ||
19 | index XXXXXXX..XXXXXXX 100644 | ||
20 | --- a/include/sysemu/blockdev.h | ||
21 | +++ b/include/sysemu/blockdev.h | ||
22 | @@ -XXX,XX +XXX,XX @@ DriveInfo *drive_get(BlockInterfaceType type, int bus, int unit); | ||
23 | void drive_check_orphaned(void); | ||
24 | DriveInfo *drive_get_by_index(BlockInterfaceType type, int index); | ||
25 | int drive_get_max_bus(BlockInterfaceType type); | ||
26 | -int drive_get_max_devs(BlockInterfaceType type); | ||
27 | |||
28 | QemuOpts *drive_add(BlockInterfaceType type, int index, const char *file, | ||
29 | const char *optstr); | ||
30 | diff --git a/blockdev.c b/blockdev.c | ||
31 | index XXXXXXX..XXXXXXX 100644 | ||
32 | --- a/blockdev.c | ||
33 | +++ b/blockdev.c | ||
34 | @@ -XXX,XX +XXX,XX @@ void blockdev_auto_del(BlockBackend *blk) | ||
35 | } | ||
36 | } | ||
37 | |||
38 | -/** | ||
39 | - * Returns the current mapping of how many units per bus | ||
40 | - * a particular interface can support. | ||
41 | - * | ||
42 | - * A positive integer indicates n units per bus. | ||
43 | - * 0 implies the mapping has not been established. | ||
44 | - * -1 indicates an invalid BlockInterfaceType was given. | ||
45 | - */ | ||
46 | -int drive_get_max_devs(BlockInterfaceType type) | ||
47 | -{ | ||
48 | - if (type >= IF_IDE && type < IF_COUNT) { | ||
49 | - return if_max_devs[type]; | ||
50 | - } | ||
51 | - | ||
52 | - return -1; | ||
53 | -} | ||
54 | - | ||
55 | static int drive_index_to_bus_id(BlockInterfaceType type, int index) | ||
56 | { | ||
57 | int max_devs = if_max_devs[type]; | ||
58 | -- | ||
59 | 2.31.1 | ||
60 | |||
61 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Daniel P. Berrangé <berrange@redhat.com> | ||
1 | 2 | ||
3 | The -device JSON syntax impl leaks a reference on the created | ||
4 | DeviceState instance. As a result when you hot-unplug the | ||
5 | device, the device_finalize method won't be called and thus | ||
6 | it will fail to emit the required DEVICE_DELETED event. | ||
7 | |||
8 | A 'json-cli' feature was previously added against the | ||
9 | 'device_add' QMP command QAPI schema to indicated to mgmt | ||
10 | apps that -device supported JSON syntax. Given the hotplug | ||
11 | bug that feature flag is not usable for its purpose, so | ||
12 | we add a new 'json-cli-hotplug' feature to indicate the | ||
13 | -device supports JSON without breaking hotplug. | ||
14 | |||
15 | Fixes: 5dacda5167560b3af8eadbce5814f60ba44b467e | ||
16 | Resolves: https://gitlab.com/qemu-project/qemu/-/issues/802 | ||
17 | Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> | ||
18 | Message-Id: <20220105123847.4047954-2-berrange@redhat.com> | ||
19 | Reviewed-by: Laurent Vivier <lvivier@redhat.com> | ||
20 | Tested-by: Ján Tomko <jtomko@redhat.com> | ||
21 | Reviewed-by: Thomas Huth <thuth@redhat.com> | ||
22 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
23 | --- | ||
24 | qapi/qdev.json | 5 ++++- | ||
25 | softmmu/vl.c | 4 +++- | ||
26 | tests/qtest/device-plug-test.c | 19 +++++++++++++++++++ | ||
27 | 3 files changed, 26 insertions(+), 2 deletions(-) | ||
28 | |||
29 | diff --git a/qapi/qdev.json b/qapi/qdev.json | ||
30 | index XXXXXXX..XXXXXXX 100644 | ||
31 | --- a/qapi/qdev.json | ||
32 | +++ b/qapi/qdev.json | ||
33 | @@ -XXX,XX +XXX,XX @@ | ||
34 | # @json-cli: If present, the "-device" command line option supports JSON | ||
35 | # syntax with a structure identical to the arguments of this | ||
36 | # command. | ||
37 | +# @json-cli-hotplug: If present, the "-device" command line option supports JSON | ||
38 | +# syntax without the reference counting leak that broke | ||
39 | +# hot-unplug | ||
40 | # | ||
41 | # Notes: | ||
42 | # | ||
43 | @@ -XXX,XX +XXX,XX @@ | ||
44 | { 'command': 'device_add', | ||
45 | 'data': {'driver': 'str', '*bus': 'str', '*id': 'str'}, | ||
46 | 'gen': false, # so we can get the additional arguments | ||
47 | - 'features': ['json-cli'] } | ||
48 | + 'features': ['json-cli', 'json-cli-hotplug'] } | ||
49 | |||
50 | ## | ||
51 | # @device_del: | ||
52 | diff --git a/softmmu/vl.c b/softmmu/vl.c | ||
53 | index XXXXXXX..XXXXXXX 100644 | ||
54 | --- a/softmmu/vl.c | ||
55 | +++ b/softmmu/vl.c | ||
56 | @@ -XXX,XX +XXX,XX @@ static void qemu_create_cli_devices(void) | ||
57 | qemu_opts_foreach(qemu_find_opts("device"), | ||
58 | device_init_func, NULL, &error_fatal); | ||
59 | QTAILQ_FOREACH(opt, &device_opts, next) { | ||
60 | + DeviceState *dev; | ||
61 | loc_push_restore(&opt->loc); | ||
62 | /* | ||
63 | * TODO Eventually we should call qmp_device_add() here to make sure it | ||
64 | @@ -XXX,XX +XXX,XX @@ static void qemu_create_cli_devices(void) | ||
65 | * from the start, so call qdev_device_add_from_qdict() directly for | ||
66 | * now. | ||
67 | */ | ||
68 | - qdev_device_add_from_qdict(opt->opts, true, &error_fatal); | ||
69 | + dev = qdev_device_add_from_qdict(opt->opts, true, &error_fatal); | ||
70 | + object_unref(OBJECT(dev)); | ||
71 | loc_pop(&opt->loc); | ||
72 | } | ||
73 | rom_reset_order_override(); | ||
74 | diff --git a/tests/qtest/device-plug-test.c b/tests/qtest/device-plug-test.c | ||
75 | index XXXXXXX..XXXXXXX 100644 | ||
76 | --- a/tests/qtest/device-plug-test.c | ||
77 | +++ b/tests/qtest/device-plug-test.c | ||
78 | @@ -XXX,XX +XXX,XX @@ static void test_pci_unplug_request(void) | ||
79 | qtest_quit(qtest); | ||
80 | } | ||
81 | |||
82 | +static void test_pci_unplug_json_request(void) | ||
83 | +{ | ||
84 | + QTestState *qtest = qtest_initf( | ||
85 | + "-device '{\"driver\": \"virtio-mouse-pci\", \"id\": \"dev0\"}'"); | ||
86 | + | ||
87 | + /* | ||
88 | + * Request device removal. As the guest is not running, the request won't | ||
89 | + * be processed. However during system reset, the removal will be | ||
90 | + * handled, removing the device. | ||
91 | + */ | ||
92 | + device_del(qtest, "dev0"); | ||
93 | + system_reset(qtest); | ||
94 | + wait_device_deleted_event(qtest, "dev0"); | ||
95 | + | ||
96 | + qtest_quit(qtest); | ||
97 | +} | ||
98 | + | ||
99 | static void test_ccw_unplug(void) | ||
100 | { | ||
101 | QTestState *qtest = qtest_initf("-device virtio-balloon-ccw,id=dev0"); | ||
102 | @@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv) | ||
103 | */ | ||
104 | qtest_add_func("/device-plug/pci-unplug-request", | ||
105 | test_pci_unplug_request); | ||
106 | + qtest_add_func("/device-plug/pci-unplug-json-request", | ||
107 | + test_pci_unplug_json_request); | ||
108 | |||
109 | if (!strcmp(arch, "s390x")) { | ||
110 | qtest_add_func("/device-plug/ccw-unplug", | ||
111 | -- | ||
112 | 2.31.1 | ||
113 | |||
114 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Philippe Mathieu-Daudé <f4bug@amsat.org> | ||
1 | 2 | ||
3 | Reported-by: Eric Blake <eblake@redhat.com> | ||
4 | Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org> | ||
5 | Message-Id: <20220107105420.395011-2-f4bug@amsat.org> | ||
6 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
7 | --- | ||
8 | docs/tools/qemu-storage-daemon.rst | 2 +- | ||
9 | 1 file changed, 1 insertion(+), 1 deletion(-) | ||
10 | |||
11 | diff --git a/docs/tools/qemu-storage-daemon.rst b/docs/tools/qemu-storage-daemon.rst | ||
12 | index XXXXXXX..XXXXXXX 100644 | ||
13 | --- a/docs/tools/qemu-storage-daemon.rst | ||
14 | +++ b/docs/tools/qemu-storage-daemon.rst | ||
15 | @@ -XXX,XX +XXX,XX @@ Export raw image file ``disk.img`` over NBD UNIX domain socket ``nbd.sock``:: | ||
16 | --nbd-server addr.type=unix,addr.path=nbd.sock \ | ||
17 | --export type=nbd,id=export,node-name=disk,writable=on | ||
18 | |||
19 | -Export a qcow2 image file ``disk.qcow2`` as a vhosts-user-blk device over UNIX | ||
20 | +Export a qcow2 image file ``disk.qcow2`` as a vhost-user-blk device over UNIX | ||
21 | domain socket ``vhost-user-blk.sock``:: | ||
22 | |||
23 | $ qemu-storage-daemon \ | ||
24 | -- | ||
25 | 2.31.1 | ||
26 | |||
27 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Philippe Mathieu-Daudé <philmd@redhat.com> | ||
1 | 2 | ||
3 | Add missing vhost-user-blk help: | ||
4 | |||
5 | $ qemu-storage-daemon -h | ||
6 | ... | ||
7 | --export [type=]vhost-user-blk,id=<id>,node-name=<node-name>, | ||
8 | addr.type=unix,addr.path=<socket-path>[,writable=on|off] | ||
9 | [,logical-block-size=<block-size>][,num-queues=<num-queues>] | ||
10 | export the specified block node as a | ||
11 | vhosts-user-blk device over UNIX domain socket | ||
12 | --export [type=]vhost-user-blk,id=<id>,node-name=<node-name>, | ||
13 | fd,addr.str=<fd>[,writable=on|off] | ||
14 | [,logical-block-size=<block-size>][,num-queues=<num-queues>] | ||
15 | export the specified block node as a | ||
16 | vhosts-user-blk device over file descriptor | ||
17 | ... | ||
18 | |||
19 | Fixes: 90fc91d50b7 ("convert vhost-user-blk server to block export API") | ||
20 | Reported-by: Qing Wang <qinwang@redhat.com> | ||
21 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
22 | Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com> | ||
23 | Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org> | ||
24 | Message-Id: <20220107105420.395011-3-f4bug@amsat.org> | ||
25 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
26 | --- | ||
27 | storage-daemon/qemu-storage-daemon.c | 13 +++++++++++++ | ||
28 | 1 file changed, 13 insertions(+) | ||
29 | |||
30 | diff --git a/storage-daemon/qemu-storage-daemon.c b/storage-daemon/qemu-storage-daemon.c | ||
31 | index XXXXXXX..XXXXXXX 100644 | ||
32 | --- a/storage-daemon/qemu-storage-daemon.c | ||
33 | +++ b/storage-daemon/qemu-storage-daemon.c | ||
34 | @@ -XXX,XX +XXX,XX @@ static void help(void) | ||
35 | " export the specified block node over FUSE\n" | ||
36 | "\n" | ||
37 | #endif /* CONFIG_FUSE */ | ||
38 | +#ifdef CONFIG_VHOST_USER_BLK_SERVER | ||
39 | +" --export [type=]vhost-user-blk,id=<id>,node-name=<node-name>,\n" | ||
40 | +" addr.type=unix,addr.path=<socket-path>[,writable=on|off]\n" | ||
41 | +" [,logical-block-size=<block-size>][,num-queues=<num-queues>]\n" | ||
42 | +" export the specified block node as a\n" | ||
43 | +" vhost-user-blk device over UNIX domain socket\n" | ||
44 | +" --export [type=]vhost-user-blk,id=<id>,node-name=<node-name>,\n" | ||
45 | +" fd,addr.str=<fd>[,writable=on|off]\n" | ||
46 | +" [,logical-block-size=<block-size>][,num-queues=<num-queues>]\n" | ||
47 | +" export the specified block node as a\n" | ||
48 | +" vhost-user-blk device over file descriptor\n" | ||
49 | +"\n" | ||
50 | +#endif /* CONFIG_VHOST_USER_BLK_SERVER */ | ||
51 | " --monitor [chardev=]name[,mode=control][,pretty[=on|off]]\n" | ||
52 | " configure a QMP monitor\n" | ||
53 | "\n" | ||
54 | -- | ||
55 | 2.31.1 | ||
56 | |||
57 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Philippe Mathieu-Daudé <philmd@redhat.com> | ||
1 | 2 | ||
3 | When building QEMU with --disable-vhost-user and using introspection, | ||
4 | query-qmp-schema lists vhost-user-blk even though it's not actually | ||
5 | available: | ||
6 | |||
7 | { "execute": "query-qmp-schema" } | ||
8 | { | ||
9 | "return": [ | ||
10 | ... | ||
11 | { | ||
12 | "name": "312", | ||
13 | "members": [ | ||
14 | { | ||
15 | "name": "nbd" | ||
16 | }, | ||
17 | { | ||
18 | "name": "vhost-user-blk" | ||
19 | } | ||
20 | ], | ||
21 | "meta-type": "enum", | ||
22 | "values": [ | ||
23 | "nbd", | ||
24 | "vhost-user-blk" | ||
25 | ] | ||
26 | }, | ||
27 | |||
28 | Restrict vhost-user-blk in BlockExportType when | ||
29 | CONFIG_VHOST_USER_BLK_SERVER is disabled, so it | ||
30 | doesn't end listed by query-qmp-schema. | ||
31 | |||
32 | Fixes: 90fc91d50b7 ("convert vhost-user-blk server to block export API") | ||
33 | Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com> | ||
34 | Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org> | ||
35 | Message-Id: <20220107105420.395011-4-f4bug@amsat.org> | ||
36 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
37 | --- | ||
38 | qapi/block-export.json | 6 ++++-- | ||
39 | 1 file changed, 4 insertions(+), 2 deletions(-) | ||
40 | |||
41 | diff --git a/qapi/block-export.json b/qapi/block-export.json | ||
42 | index XXXXXXX..XXXXXXX 100644 | ||
43 | --- a/qapi/block-export.json | ||
44 | +++ b/qapi/block-export.json | ||
45 | @@ -XXX,XX +XXX,XX @@ | ||
46 | # Since: 4.2 | ||
47 | ## | ||
48 | { 'enum': 'BlockExportType', | ||
49 | - 'data': [ 'nbd', 'vhost-user-blk', | ||
50 | + 'data': [ 'nbd', | ||
51 | + { 'name': 'vhost-user-blk', 'if': 'CONFIG_VHOST_USER_BLK_SERVER' }, | ||
52 | { 'name': 'fuse', 'if': 'CONFIG_FUSE' } ] } | ||
53 | |||
54 | ## | ||
55 | @@ -XXX,XX +XXX,XX @@ | ||
56 | 'discriminator': 'type', | ||
57 | 'data': { | ||
58 | 'nbd': 'BlockExportOptionsNbd', | ||
59 | - 'vhost-user-blk': 'BlockExportOptionsVhostUserBlk', | ||
60 | + 'vhost-user-blk': { 'type': 'BlockExportOptionsVhostUserBlk', | ||
61 | + 'if': 'CONFIG_VHOST_USER_BLK_SERVER' }, | ||
62 | 'fuse': { 'type': 'BlockExportOptionsFuse', | ||
63 | 'if': 'CONFIG_FUSE' } | ||
64 | } } | ||
65 | -- | ||
66 | 2.31.1 | ||
67 | |||
68 | diff view generated by jsdifflib |
1 | This makes the new BDRV_REQ_NO_FALLBACK flag available in the qemu-io | 1 | From: Stefan Hajnoczi <stefanha@redhat.com> |
---|---|---|---|
2 | write command. | ||
3 | 2 | ||
3 | The BlockBackend root child can change when aio_poll() is invoked. This | ||
4 | happens when a temporary filter node is removed upon blockjob | ||
5 | completion, for example. | ||
6 | |||
7 | Functions in block/block-backend.c must be aware of this when using a | ||
8 | blk_bs() pointer across aio_poll() because the BlockDriverState refcnt | ||
9 | may reach 0, resulting in a stale pointer. | ||
10 | |||
11 | One example is scsi_device_purge_requests(), which calls blk_drain() to | ||
12 | wait for in-flight requests to cancel. If the backup blockjob is active, | ||
13 | then the BlockBackend root child is a temporary filter BDS owned by the | ||
14 | blockjob. The blockjob can complete during bdrv_drained_begin() and the | ||
15 | last reference to the BDS is released when the temporary filter node is | ||
16 | removed. This results in a use-after-free when blk_drain() calls | ||
17 | bdrv_drained_end(bs) on the dangling pointer. | ||
18 | |||
19 | Explicitly hold a reference to bs across block APIs that invoke | ||
20 | aio_poll(). | ||
21 | |||
22 | Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=2021778 | ||
23 | Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=2036178 | ||
24 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
25 | Message-Id: <20220111153613.25453-2-stefanha@redhat.com> | ||
4 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 26 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
5 | Acked-by: Eric Blake <eblake@redhat.com> | ||
6 | --- | 27 | --- |
7 | qemu-io-cmds.c | 13 +++++++++++-- | 28 | block/block-backend.c | 19 +++++++++++++++++-- |
8 | 1 file changed, 11 insertions(+), 2 deletions(-) | 29 | 1 file changed, 17 insertions(+), 2 deletions(-) |
9 | 30 | ||
10 | diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c | 31 | diff --git a/block/block-backend.c b/block/block-backend.c |
11 | index XXXXXXX..XXXXXXX 100644 | 32 | index XXXXXXX..XXXXXXX 100644 |
12 | --- a/qemu-io-cmds.c | 33 | --- a/block/block-backend.c |
13 | +++ b/qemu-io-cmds.c | 34 | +++ b/block/block-backend.c |
14 | @@ -XXX,XX +XXX,XX @@ static void write_help(void) | 35 | @@ -XXX,XX +XXX,XX @@ BlockBackend *blk_by_public(BlockBackendPublic *public) |
15 | " -b, -- write to the VM state rather than the virtual disk\n" | 36 | void blk_remove_bs(BlockBackend *blk) |
16 | " -c, -- write compressed data with blk_write_compressed\n" | 37 | { |
17 | " -f, -- use Force Unit Access semantics\n" | 38 | ThrottleGroupMember *tgm = &blk->public.throttle_group_member; |
18 | +" -n, -- with -z, don't allow slow fallback\n" | 39 | - BlockDriverState *bs; |
19 | " -p, -- ignored for backwards compatibility\n" | 40 | BdrvChild *root; |
20 | " -P, -- use different pattern to fill file\n" | 41 | |
21 | " -C, -- report statistics in a machine parsable format\n" | 42 | notifier_list_notify(&blk->remove_bs_notifiers, blk); |
22 | @@ -XXX,XX +XXX,XX @@ static const cmdinfo_t write_cmd = { | 43 | if (tgm->throttle_state) { |
23 | .perm = BLK_PERM_WRITE, | 44 | - bs = blk_bs(blk); |
24 | .argmin = 2, | 45 | + BlockDriverState *bs = blk_bs(blk); |
25 | .argmax = -1, | 46 | + |
26 | - .args = "[-bcCfquz] [-P pattern] off len", | 47 | + /* |
27 | + .args = "[-bcCfnquz] [-P pattern] off len", | 48 | + * Take a ref in case blk_bs() changes across bdrv_drained_begin(), for |
28 | .oneline = "writes a number of bytes at a specified offset", | 49 | + * example, if a temporary filter node is removed by a blockjob. |
29 | .help = write_help, | 50 | + */ |
30 | }; | 51 | + bdrv_ref(bs); |
31 | @@ -XXX,XX +XXX,XX @@ static int write_f(BlockBackend *blk, int argc, char **argv) | 52 | bdrv_drained_begin(bs); |
32 | int64_t total = 0; | 53 | throttle_group_detach_aio_context(tgm); |
33 | int pattern = 0xcd; | 54 | throttle_group_attach_aio_context(tgm, qemu_get_aio_context()); |
34 | 55 | bdrv_drained_end(bs); | |
35 | - while ((c = getopt(argc, argv, "bcCfpP:quz")) != -1) { | 56 | + bdrv_unref(bs); |
36 | + while ((c = getopt(argc, argv, "bcCfnpP:quz")) != -1) { | ||
37 | switch (c) { | ||
38 | case 'b': | ||
39 | bflag = true; | ||
40 | @@ -XXX,XX +XXX,XX @@ static int write_f(BlockBackend *blk, int argc, char **argv) | ||
41 | case 'f': | ||
42 | flags |= BDRV_REQ_FUA; | ||
43 | break; | ||
44 | + case 'n': | ||
45 | + flags |= BDRV_REQ_NO_FALLBACK; | ||
46 | + break; | ||
47 | case 'p': | ||
48 | /* Ignored for backwards compatibility */ | ||
49 | break; | ||
50 | @@ -XXX,XX +XXX,XX @@ static int write_f(BlockBackend *blk, int argc, char **argv) | ||
51 | return -EINVAL; | ||
52 | } | 57 | } |
53 | 58 | ||
54 | + if ((flags & BDRV_REQ_NO_FALLBACK) && !zflag) { | 59 | blk_update_root_state(blk); |
55 | + printf("-n requires -z to be specified\n"); | 60 | @@ -XXX,XX +XXX,XX @@ void blk_drain(BlockBackend *blk) |
56 | + return -EINVAL; | 61 | BlockDriverState *bs = blk_bs(blk); |
57 | + } | 62 | |
63 | if (bs) { | ||
64 | + bdrv_ref(bs); | ||
65 | bdrv_drained_begin(bs); | ||
66 | } | ||
67 | |||
68 | @@ -XXX,XX +XXX,XX @@ void blk_drain(BlockBackend *blk) | ||
69 | |||
70 | if (bs) { | ||
71 | bdrv_drained_end(bs); | ||
72 | + bdrv_unref(bs); | ||
73 | } | ||
74 | } | ||
75 | |||
76 | @@ -XXX,XX +XXX,XX @@ static int blk_do_set_aio_context(BlockBackend *blk, AioContext *new_context, | ||
77 | int ret; | ||
78 | |||
79 | if (bs) { | ||
80 | + bdrv_ref(bs); | ||
58 | + | 81 | + |
59 | if ((flags & BDRV_REQ_MAY_UNMAP) && !zflag) { | 82 | if (update_root_node) { |
60 | printf("-u requires -z to be specified\n"); | 83 | ret = bdrv_child_try_set_aio_context(bs, new_context, blk->root, |
61 | return -EINVAL; | 84 | errp); |
85 | if (ret < 0) { | ||
86 | + bdrv_unref(bs); | ||
87 | return ret; | ||
88 | } | ||
89 | } | ||
90 | @@ -XXX,XX +XXX,XX @@ static int blk_do_set_aio_context(BlockBackend *blk, AioContext *new_context, | ||
91 | throttle_group_attach_aio_context(tgm, new_context); | ||
92 | bdrv_drained_end(bs); | ||
93 | } | ||
94 | + | ||
95 | + bdrv_unref(bs); | ||
96 | } | ||
97 | |||
98 | blk->ctx = new_context; | ||
99 | @@ -XXX,XX +XXX,XX @@ void blk_io_limits_disable(BlockBackend *blk) | ||
100 | ThrottleGroupMember *tgm = &blk->public.throttle_group_member; | ||
101 | assert(tgm->throttle_state); | ||
102 | if (bs) { | ||
103 | + bdrv_ref(bs); | ||
104 | bdrv_drained_begin(bs); | ||
105 | } | ||
106 | throttle_group_unregister_tgm(tgm); | ||
107 | if (bs) { | ||
108 | bdrv_drained_end(bs); | ||
109 | + bdrv_unref(bs); | ||
110 | } | ||
111 | } | ||
112 | |||
62 | -- | 113 | -- |
63 | 2.20.1 | 114 | 2.31.1 |
64 | 115 | ||
65 | 116 | diff view generated by jsdifflib |
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 1 | From: Hanna Reitz <hreitz@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Test that mirror job actually resume on resume command after being | 3 | Test the following scenario: |
4 | automatically paused on ENOSPC error. | 4 | - Simple stream block in two-layer backing chain (base and top) |
5 | - The job is drained via blk_drain(), then an error occurs while the job | ||
6 | settles the ongoing request | ||
7 | - And so the job completes while in blk_drain() | ||
5 | 8 | ||
6 | It's a follow-up test for 8d9648cbf3e | 9 | This was reported as a segfault, but is fixed by "block-backend: prevent |
7 | "blockjob: fix user pause in block_job_error_action" | 10 | dangling BDS pointers across aio_poll()". |
8 | 11 | ||
9 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 12 | Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=2036178 |
10 | Tested-by: John Snow <jsnow@redhat.com> | 13 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> |
11 | Reviewed-by: John Snow <jsnow@redhat.com> | 14 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> |
15 | Message-Id: <20220111153613.25453-3-stefanha@redhat.com> | ||
12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 16 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
13 | --- | 17 | --- |
14 | tests/qemu-iotests/248 | 71 ++++++++++++++++++++++++++++++++++++++ | 18 | .../qemu-iotests/tests/stream-error-on-reset | 140 ++++++++++++++++++ |
15 | tests/qemu-iotests/248.out | 8 +++++ | 19 | .../tests/stream-error-on-reset.out | 5 + |
16 | tests/qemu-iotests/group | 1 + | 20 | 2 files changed, 145 insertions(+) |
17 | 3 files changed, 80 insertions(+) | 21 | create mode 100755 tests/qemu-iotests/tests/stream-error-on-reset |
18 | create mode 100755 tests/qemu-iotests/248 | 22 | create mode 100644 tests/qemu-iotests/tests/stream-error-on-reset.out |
19 | create mode 100644 tests/qemu-iotests/248.out | ||
20 | 23 | ||
21 | diff --git a/tests/qemu-iotests/248 b/tests/qemu-iotests/248 | 24 | diff --git a/tests/qemu-iotests/tests/stream-error-on-reset b/tests/qemu-iotests/tests/stream-error-on-reset |
22 | new file mode 100755 | 25 | new file mode 100755 |
23 | index XXXXXXX..XXXXXXX | 26 | index XXXXXXX..XXXXXXX |
24 | --- /dev/null | 27 | --- /dev/null |
25 | +++ b/tests/qemu-iotests/248 | 28 | +++ b/tests/qemu-iotests/tests/stream-error-on-reset |
26 | @@ -XXX,XX +XXX,XX @@ | 29 | @@ -XXX,XX +XXX,XX @@ |
27 | +#!/usr/bin/env python | 30 | +#!/usr/bin/env python3 |
31 | +# group: rw quick | ||
28 | +# | 32 | +# |
29 | +# Test resume mirror after auto pause on ENOSPC | 33 | +# Test what happens when a stream job completes in a blk_drain(). |
30 | +# | 34 | +# |
31 | +# Copyright (c) 2019 Virtuozzo International GmbH. All rights reserved. | 35 | +# Copyright (C) 2022 Red Hat, Inc. |
32 | +# | 36 | +# |
33 | +# This program is free software; you can redistribute it and/or modify | 37 | +# This program is free software; you can redistribute it and/or modify |
34 | +# it under the terms of the GNU General Public License as published by | 38 | +# it under the terms of the GNU General Public License as published by |
35 | +# the Free Software Foundation; either version 2 of the License, or | 39 | +# the Free Software Foundation; either version 2 of the License, or |
36 | +# (at your option) any later version. | 40 | +# (at your option) any later version. |
... | ... | ||
42 | +# | 46 | +# |
43 | +# You should have received a copy of the GNU General Public License | 47 | +# You should have received a copy of the GNU General Public License |
44 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. | 48 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
45 | +# | 49 | +# |
46 | + | 50 | + |
51 | +import os | ||
47 | +import iotests | 52 | +import iotests |
48 | +from iotests import qemu_img_create, qemu_io, file_path, filter_qmp_testfiles | 53 | +from iotests import imgfmt, qemu_img_create, qemu_io_silent, QMPTestCase |
49 | + | 54 | + |
50 | +iotests.verify_image_format(supported_fmts=['qcow2']) | ||
51 | + | 55 | + |
52 | +source, target = file_path('source', 'target') | 56 | +image_size = 1 * 1024 * 1024 |
53 | +size = 5 * 1024 * 1024 | 57 | +data_size = 64 * 1024 |
54 | +limit = 2 * 1024 * 1024 | 58 | +base = os.path.join(iotests.test_dir, 'base.img') |
59 | +top = os.path.join(iotests.test_dir, 'top.img') | ||
55 | + | 60 | + |
56 | +qemu_img_create('-f', iotests.imgfmt, source, str(size)) | ||
57 | +qemu_img_create('-f', iotests.imgfmt, target, str(size)) | ||
58 | +qemu_io('-c', 'write 0 {}'.format(size), source) | ||
59 | + | 61 | + |
60 | +# raw format don't like empty files | 62 | +# We want to test completing a stream job in a blk_drain(). |
61 | +qemu_io('-c', 'write 0 {}'.format(size), target) | 63 | +# |
64 | +# The blk_drain() we are going to use is a virtio-scsi device resetting, | ||
65 | +# which we can trigger by resetting the system. | ||
66 | +# | ||
67 | +# In order to have the block job complete on drain, we (1) throttle its | ||
68 | +# base image so we can start the drain after it has begun, but before it | ||
69 | +# completes, and (2) make it encounter an I/O error on the ensuing write. | ||
70 | +# (If it completes regularly, the completion happens after the drain for | ||
71 | +# some reason.) | ||
62 | + | 72 | + |
63 | +vm = iotests.VM().add_drive(source) | 73 | +class TestStreamErrorOnReset(QMPTestCase): |
64 | +vm.launch() | 74 | + def setUp(self) -> None: |
75 | + """ | ||
76 | + Create two images: | ||
77 | + - base image {base} with {data_size} bytes allocated | ||
78 | + - top image {top} without any data allocated | ||
65 | + | 79 | + |
66 | +blockdev_opts = { | 80 | + And the following VM configuration: |
67 | + 'driver': iotests.imgfmt, | 81 | + - base image throttled to {data_size} |
68 | + 'node-name': 'target', | 82 | + - top image with a blkdebug configuration so the first write access |
69 | + 'file': { | 83 | + to it will result in an error |
70 | + 'driver': 'raw', | 84 | + - top image is attached to a virtio-scsi device |
71 | + 'size': limit, | 85 | + """ |
72 | + 'file': { | 86 | + assert qemu_img_create('-f', imgfmt, base, str(image_size)) == 0 |
73 | + 'driver': 'file', | 87 | + assert qemu_io_silent('-c', f'write 0 {data_size}', base) == 0 |
74 | + 'filename': target | 88 | + assert qemu_img_create('-f', imgfmt, top, str(image_size)) == 0 |
75 | + } | ||
76 | + } | ||
77 | +} | ||
78 | +vm.qmp_log('blockdev-add', filters=[filter_qmp_testfiles], **blockdev_opts) | ||
79 | + | 89 | + |
80 | +vm.qmp_log('blockdev-mirror', device='drive0', sync='full', target='target', | 90 | + self.vm = iotests.VM() |
81 | + on_target_error='enospc') | 91 | + self.vm.add_args('-accel', 'tcg') # Make throttling work properly |
92 | + self.vm.add_object(self.vm.qmp_to_opts({ | ||
93 | + 'qom-type': 'throttle-group', | ||
94 | + 'id': 'thrgr', | ||
95 | + 'x-bps-total': str(data_size) | ||
96 | + })) | ||
97 | + self.vm.add_blockdev(self.vm.qmp_to_opts({ | ||
98 | + 'driver': imgfmt, | ||
99 | + 'node-name': 'base', | ||
100 | + 'file': { | ||
101 | + 'driver': 'throttle', | ||
102 | + 'throttle-group': 'thrgr', | ||
103 | + 'file': { | ||
104 | + 'driver': 'file', | ||
105 | + 'filename': base | ||
106 | + } | ||
107 | + } | ||
108 | + })) | ||
109 | + self.vm.add_blockdev(self.vm.qmp_to_opts({ | ||
110 | + 'driver': imgfmt, | ||
111 | + 'node-name': 'top', | ||
112 | + 'file': { | ||
113 | + 'driver': 'blkdebug', | ||
114 | + 'node-name': 'top-blkdebug', | ||
115 | + 'inject-error': [{ | ||
116 | + 'event': 'pwritev', | ||
117 | + 'immediately': 'true', | ||
118 | + 'once': 'true' | ||
119 | + }], | ||
120 | + 'image': { | ||
121 | + 'driver': 'file', | ||
122 | + 'filename': top | ||
123 | + } | ||
124 | + }, | ||
125 | + 'backing': 'base' | ||
126 | + })) | ||
127 | + self.vm.add_device(self.vm.qmp_to_opts({ | ||
128 | + 'driver': 'virtio-scsi', | ||
129 | + 'id': 'vscsi' | ||
130 | + })) | ||
131 | + self.vm.add_device(self.vm.qmp_to_opts({ | ||
132 | + 'driver': 'scsi-hd', | ||
133 | + 'bus': 'vscsi.0', | ||
134 | + 'drive': 'top' | ||
135 | + })) | ||
136 | + self.vm.launch() | ||
82 | + | 137 | + |
83 | +vm.event_wait('JOB_STATUS_CHANGE', timeout=3.0, | 138 | + def tearDown(self) -> None: |
84 | + match={'data': {'status': 'paused'}}) | 139 | + self.vm.shutdown() |
140 | + os.remove(top) | ||
141 | + os.remove(base) | ||
85 | + | 142 | + |
86 | +# drop other cached events, to not interfere with further wait for 'running' | 143 | + def test_stream_error_on_reset(self) -> None: |
87 | +vm.get_qmp_events() | 144 | + # Launch a stream job, which will take at least a second to |
145 | + # complete, because the base image is throttled (so we can | ||
146 | + # get in between it having started and it having completed) | ||
147 | + res = self.vm.qmp('block-stream', job_id='stream', device='top') | ||
148 | + self.assert_qmp(res, 'return', {}) | ||
88 | + | 149 | + |
89 | +del blockdev_opts['file']['size'] | 150 | + while True: |
90 | +vm.qmp_log('x-blockdev-reopen', filters=[filter_qmp_testfiles], | 151 | + ev = self.vm.event_wait('JOB_STATUS_CHANGE') |
91 | + **blockdev_opts) | 152 | + if ev['data']['status'] == 'running': |
153 | + # Once the stream job is running, reset the system, which | ||
154 | + # forces the virtio-scsi device to be reset, thus draining | ||
155 | + # the stream job, and making it complete. Completing | ||
156 | + # inside of that drain should not result in a segfault. | ||
157 | + res = self.vm.qmp('system_reset') | ||
158 | + self.assert_qmp(res, 'return', {}) | ||
159 | + elif ev['data']['status'] == 'null': | ||
160 | + # The test is done once the job is gone | ||
161 | + break | ||
92 | + | 162 | + |
93 | +vm.qmp_log('block-job-resume', device='drive0') | ||
94 | +vm.event_wait('JOB_STATUS_CHANGE', timeout=1.0, | ||
95 | + match={'data': {'status': 'running'}}) | ||
96 | + | 163 | + |
97 | +vm.shutdown() | 164 | +if __name__ == '__main__': |
98 | diff --git a/tests/qemu-iotests/248.out b/tests/qemu-iotests/248.out | 165 | + # Passes with any format with backing file support, but qed and |
166 | + # qcow1 do not seem to exercise the used-to-be problematic code | ||
167 | + # path, so there is no point in having them in this list | ||
168 | + iotests.main(supported_fmts=['qcow2', 'vmdk'], | ||
169 | + supported_protocols=['file']) | ||
170 | diff --git a/tests/qemu-iotests/tests/stream-error-on-reset.out b/tests/qemu-iotests/tests/stream-error-on-reset.out | ||
99 | new file mode 100644 | 171 | new file mode 100644 |
100 | index XXXXXXX..XXXXXXX | 172 | index XXXXXXX..XXXXXXX |
101 | --- /dev/null | 173 | --- /dev/null |
102 | +++ b/tests/qemu-iotests/248.out | 174 | +++ b/tests/qemu-iotests/tests/stream-error-on-reset.out |
103 | @@ -XXX,XX +XXX,XX @@ | 175 | @@ -XXX,XX +XXX,XX @@ |
104 | +{"execute": "blockdev-add", "arguments": {"driver": "qcow2", "file": {"driver": "raw", "file": {"driver": "file", "filename": "TEST_DIR/PID-target"}, "size": 2097152}, "node-name": "target"}} | 176 | +. |
105 | +{"return": {}} | 177 | +---------------------------------------------------------------------- |
106 | +{"execute": "blockdev-mirror", "arguments": {"device": "drive0", "on-target-error": "enospc", "sync": "full", "target": "target"}} | 178 | +Ran 1 tests |
107 | +{"return": {}} | 179 | + |
108 | +{"execute": "x-blockdev-reopen", "arguments": {"driver": "qcow2", "file": {"driver": "raw", "file": {"driver": "file", "filename": "TEST_DIR/PID-target"}}, "node-name": "target"}} | 180 | +OK |
109 | +{"return": {}} | ||
110 | +{"execute": "block-job-resume", "arguments": {"device": "drive0"}} | ||
111 | +{"return": {}} | ||
112 | diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group | ||
113 | index XXXXXXX..XXXXXXX 100644 | ||
114 | --- a/tests/qemu-iotests/group | ||
115 | +++ b/tests/qemu-iotests/group | ||
116 | @@ -XXX,XX +XXX,XX @@ | ||
117 | 245 rw auto | ||
118 | 246 rw auto quick | ||
119 | 247 rw auto quick | ||
120 | +248 rw auto quick | ||
121 | -- | 181 | -- |
122 | 2.20.1 | 182 | 2.31.1 |
123 | 183 | ||
124 | 184 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Hanna Reitz <hreitz@redhat.com> | ||
1 | 2 | ||
3 | With CAP_DAC_OVERRIDE (which e.g. root generally has), permission checks | ||
4 | will be bypassed when opening files. | ||
5 | |||
6 | 308 in one instance tries to open a read-only file (FUSE export) with | ||
7 | qemu-io as read/write, and expects this to fail. However, when running | ||
8 | it as root, opening will succeed (thanks to CAP_DAC_OVERRIDE) and only | ||
9 | the actual write operation will fail. | ||
10 | |||
11 | Note this as "Case not run", but have the test pass in either case. | ||
12 | |||
13 | Reported-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
14 | Fixes: 2c7dd057aa7bd7a875e9b1a53975c220d6380bc4 | ||
15 | ("export/fuse: Pass default_permissions for mount") | ||
16 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
17 | Message-Id: <20220103120014.13061-1-hreitz@redhat.com> | ||
18 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
19 | --- | ||
20 | tests/qemu-iotests/308 | 25 +++++++++++++++++++++++-- | ||
21 | tests/qemu-iotests/308.out | 2 +- | ||
22 | 2 files changed, 24 insertions(+), 3 deletions(-) | ||
23 | |||
24 | diff --git a/tests/qemu-iotests/308 b/tests/qemu-iotests/308 | ||
25 | index XXXXXXX..XXXXXXX 100755 | ||
26 | --- a/tests/qemu-iotests/308 | ||
27 | +++ b/tests/qemu-iotests/308 | ||
28 | @@ -XXX,XX +XXX,XX @@ echo '=== Writable export ===' | ||
29 | fuse_export_add 'export-mp' "'mountpoint': '$EXT_MP', 'writable': true" | ||
30 | |||
31 | # Check that writing to the read-only export fails | ||
32 | -$QEMU_IO -f raw -c 'write -P 42 1M 64k' "$TEST_IMG" 2>&1 \ | ||
33 | - | _filter_qemu_io | _filter_testdir | _filter_imgfmt | ||
34 | +output=$($QEMU_IO -f raw -c 'write -P 42 1M 64k' "$TEST_IMG" 2>&1 \ | ||
35 | + | _filter_qemu_io | _filter_testdir | _filter_imgfmt) | ||
36 | + | ||
37 | +# Expected reference output: Opening the file fails because it has no | ||
38 | +# write permission | ||
39 | +reference="Could not open 'TEST_DIR/t.IMGFMT': Permission denied" | ||
40 | + | ||
41 | +if echo "$output" | grep -q "$reference"; then | ||
42 | + echo "Writing to read-only export failed: OK" | ||
43 | +elif echo "$output" | grep -q "write failed: Permission denied"; then | ||
44 | + # With CAP_DAC_OVERRIDE (e.g. when running this test as root), the export | ||
45 | + # can be opened regardless of its file permissions, but writing will then | ||
46 | + # fail. This is not the result for which we want to test, so count this as | ||
47 | + # a SKIP. | ||
48 | + _casenotrun "Opening RO export as R/W succeeded, perhaps because of" \ | ||
49 | + "CAP_DAC_OVERRIDE" | ||
50 | + | ||
51 | + # Still, write this to the reference output to make the test pass | ||
52 | + echo "Writing to read-only export failed: OK" | ||
53 | +else | ||
54 | + echo "Writing to read-only export failed: ERROR" | ||
55 | + echo "$output" | ||
56 | +fi | ||
57 | |||
58 | # But here it should work | ||
59 | $QEMU_IO -f raw -c 'write -P 42 1M 64k' "$EXT_MP" | _filter_qemu_io | ||
60 | diff --git a/tests/qemu-iotests/308.out b/tests/qemu-iotests/308.out | ||
61 | index XXXXXXX..XXXXXXX 100644 | ||
62 | --- a/tests/qemu-iotests/308.out | ||
63 | +++ b/tests/qemu-iotests/308.out | ||
64 | @@ -XXX,XX +XXX,XX @@ virtual size: 0 B (0 bytes) | ||
65 | 'mountpoint': 'TEST_DIR/t.IMGFMT.fuse', 'writable': true | ||
66 | } } | ||
67 | {"return": {}} | ||
68 | -qemu-io: can't open device TEST_DIR/t.IMGFMT: Could not open 'TEST_DIR/t.IMGFMT': Permission denied | ||
69 | +Writing to read-only export failed: OK | ||
70 | wrote 65536/65536 bytes at offset 1048576 | ||
71 | 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
72 | wrote 65536/65536 bytes at offset 1048576 | ||
73 | -- | ||
74 | 2.31.1 | ||
75 | |||
76 | diff view generated by jsdifflib |
1 | We know that the kernel implements a slow fallback code path for | 1 | The size of the qcow size was calculated so that only the FAT partition |
---|---|---|---|
2 | BLKZEROOUT, so if BDRV_REQ_NO_FALLBACK is given, we shouldn't call it. | 2 | would fit on it, but not the whole disk. However, offsets relative to |
3 | The other operations we call in the context of .bdrv_co_pwrite_zeroes | 3 | the whole disk are used to access it, so increase its size to be large |
4 | should usually be quick, so no modification should be needed for them. | 4 | enough for that. |
5 | If we ever notice that there are additional problematic cases, we can | ||
6 | still make these conditional as well. | ||
7 | 5 | ||
8 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 6 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
9 | Acked-by: Eric Blake <eblake@redhat.com> | 7 | Message-Id: <20211209151815.23495-1-kwolf@redhat.com> |
8 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
10 | --- | 9 | --- |
11 | include/block/raw-aio.h | 1 + | 10 | block/vvfat.c | 7 +++---- |
12 | block/file-posix.c | 24 ++++++++++++++++-------- | 11 | 1 file changed, 3 insertions(+), 4 deletions(-) |
13 | 2 files changed, 17 insertions(+), 8 deletions(-) | ||
14 | 12 | ||
15 | diff --git a/include/block/raw-aio.h b/include/block/raw-aio.h | 13 | diff --git a/block/vvfat.c b/block/vvfat.c |
16 | index XXXXXXX..XXXXXXX 100644 | 14 | index XXXXXXX..XXXXXXX 100644 |
17 | --- a/include/block/raw-aio.h | 15 | --- a/block/vvfat.c |
18 | +++ b/include/block/raw-aio.h | 16 | +++ b/block/vvfat.c |
19 | @@ -XXX,XX +XXX,XX @@ | 17 | @@ -XXX,XX +XXX,XX @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags, |
20 | /* AIO flags */ | 18 | dirname, cyls, heads, secs)); |
21 | #define QEMU_AIO_MISALIGNED 0x1000 | 19 | |
22 | #define QEMU_AIO_BLKDEV 0x2000 | 20 | s->sector_count = cyls * heads * secs - s->offset_to_bootsector; |
23 | +#define QEMU_AIO_NO_FALLBACK 0x4000 | 21 | + bs->total_sectors = cyls * heads * secs; |
24 | 22 | ||
25 | 23 | if (qemu_opt_get_bool(opts, "rw", false)) { | |
26 | /* linux-aio.c - Linux native implementation */ | 24 | if (!bdrv_is_read_only(bs)) { |
27 | diff --git a/block/file-posix.c b/block/file-posix.c | 25 | @@ -XXX,XX +XXX,XX @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags, |
28 | index XXXXXXX..XXXXXXX 100644 | 26 | } |
29 | --- a/block/file-posix.c | ||
30 | +++ b/block/file-posix.c | ||
31 | @@ -XXX,XX +XXX,XX @@ static int raw_open_common(BlockDriverState *bs, QDict *options, | ||
32 | } | 27 | } |
33 | #endif | 28 | |
34 | 29 | - bs->total_sectors = cyls * heads * secs; | |
35 | - bs->supported_zero_flags = BDRV_REQ_MAY_UNMAP; | 30 | - |
36 | + bs->supported_zero_flags = BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK; | 31 | if (init_directories(s, dirname, heads, secs, errp)) { |
37 | ret = 0; | 32 | ret = -EIO; |
38 | fail: | 33 | goto fail; |
39 | if (filename && (bdrv_flags & BDRV_O_TEMPORARY)) { | 34 | @@ -XXX,XX +XXX,XX @@ static int enable_write_target(BlockDriverState *bs, Error **errp) |
40 | @@ -XXX,XX +XXX,XX @@ static ssize_t handle_aiocb_write_zeroes_block(RawPosixAIOData *aiocb) | ||
41 | } | 35 | } |
42 | 36 | ||
43 | #ifdef BLKZEROOUT | 37 | opts = qemu_opts_create(bdrv_qcow->create_opts, NULL, 0, &error_abort); |
44 | - do { | 38 | - qemu_opt_set_number(opts, BLOCK_OPT_SIZE, s->sector_count * 512, |
45 | - uint64_t range[2] = { aiocb->aio_offset, aiocb->aio_nbytes }; | 39 | - &error_abort); |
46 | - if (ioctl(aiocb->aio_fildes, BLKZEROOUT, range) == 0) { | 40 | + qemu_opt_set_number(opts, BLOCK_OPT_SIZE, |
47 | - return 0; | 41 | + bs->total_sectors * BDRV_SECTOR_SIZE, &error_abort); |
48 | - } | 42 | qemu_opt_set(opts, BLOCK_OPT_BACKING_FILE, "fat:", &error_abort); |
49 | - } while (errno == EINTR); | 43 | |
50 | + /* The BLKZEROOUT implementation in the kernel doesn't set | 44 | ret = bdrv_create(bdrv_qcow, s->qcow_filename, opts, errp); |
51 | + * BLKDEV_ZERO_NOFALLBACK, so we can't call this if we have to avoid slow | ||
52 | + * fallbacks. */ | ||
53 | + if (!(aiocb->aio_type & QEMU_AIO_NO_FALLBACK)) { | ||
54 | + do { | ||
55 | + uint64_t range[2] = { aiocb->aio_offset, aiocb->aio_nbytes }; | ||
56 | + if (ioctl(aiocb->aio_fildes, BLKZEROOUT, range) == 0) { | ||
57 | + return 0; | ||
58 | + } | ||
59 | + } while (errno == EINTR); | ||
60 | |||
61 | - ret = translate_err(-errno); | ||
62 | + ret = translate_err(-errno); | ||
63 | + } | ||
64 | #endif | ||
65 | |||
66 | if (ret == -ENOTSUP) { | ||
67 | @@ -XXX,XX +XXX,XX @@ raw_do_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int bytes, | ||
68 | if (blkdev) { | ||
69 | acb.aio_type |= QEMU_AIO_BLKDEV; | ||
70 | } | ||
71 | + if (flags & BDRV_REQ_NO_FALLBACK) { | ||
72 | + acb.aio_type |= QEMU_AIO_NO_FALLBACK; | ||
73 | + } | ||
74 | |||
75 | if (flags & BDRV_REQ_MAY_UNMAP) { | ||
76 | acb.aio_type |= QEMU_AIO_DISCARD; | ||
77 | -- | 45 | -- |
78 | 2.20.1 | 46 | 2.31.1 |
79 | 47 | ||
80 | 48 | diff view generated by jsdifflib |
1 | Filter drivers that support .bdrv_co_pwrite_zeroes can safely advertise | 1 | The calculation in sector2cluster() is done relative to the offset of |
---|---|---|---|
2 | BDRV_REQ_NO_FALLBACK because they just forward the request flags to | 2 | the root directory. Any writes to blocks before the start of the root |
3 | their child node. | 3 | directory (in particular, writes to the FAT) result in negative values, |
4 | which are not handled correctly in vvfat_write(). | ||
5 | |||
6 | This changes sector2cluster() to return a signed value, and makes sure | ||
7 | that vvfat_write() doesn't try to find mappings for negative cluster | ||
8 | number. It clarifies the code in vvfat_write() to make it more obvious | ||
9 | that the cluster numbers can be negative. | ||
4 | 10 | ||
5 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
6 | Acked-by: Eric Blake <eblake@redhat.com> | 12 | Message-Id: <20211209152231.23756-1-kwolf@redhat.com> |
13 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
7 | --- | 14 | --- |
8 | block/blkdebug.c | 2 +- | 15 | block/vvfat.c | 30 ++++++++++++++++++++++-------- |
9 | block/copy-on-read.c | 7 +++---- | 16 | 1 file changed, 22 insertions(+), 8 deletions(-) |
10 | block/mirror.c | 3 ++- | ||
11 | block/raw-format.c | 2 +- | ||
12 | 4 files changed, 7 insertions(+), 7 deletions(-) | ||
13 | 17 | ||
14 | diff --git a/block/blkdebug.c b/block/blkdebug.c | 18 | diff --git a/block/vvfat.c b/block/vvfat.c |
15 | index XXXXXXX..XXXXXXX 100644 | 19 | index XXXXXXX..XXXXXXX 100644 |
16 | --- a/block/blkdebug.c | 20 | --- a/block/vvfat.c |
17 | +++ b/block/blkdebug.c | 21 | +++ b/block/vvfat.c |
18 | @@ -XXX,XX +XXX,XX @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags, | 22 | @@ -XXX,XX +XXX,XX @@ static int read_directory(BDRVVVFATState* s, int mapping_index) |
19 | bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED | | ||
20 | (BDRV_REQ_FUA & bs->file->bs->supported_write_flags); | ||
21 | bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED | | ||
22 | - ((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP) & | ||
23 | + ((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK) & | ||
24 | bs->file->bs->supported_zero_flags); | ||
25 | ret = -EINVAL; | ||
26 | |||
27 | diff --git a/block/copy-on-read.c b/block/copy-on-read.c | ||
28 | index XXXXXXX..XXXXXXX 100644 | ||
29 | --- a/block/copy-on-read.c | ||
30 | +++ b/block/copy-on-read.c | ||
31 | @@ -XXX,XX +XXX,XX @@ static int cor_open(BlockDriverState *bs, QDict *options, int flags, | ||
32 | } | ||
33 | |||
34 | bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED | | ||
35 | - (BDRV_REQ_FUA & | ||
36 | - bs->file->bs->supported_write_flags); | ||
37 | + (BDRV_REQ_FUA & bs->file->bs->supported_write_flags); | ||
38 | |||
39 | bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED | | ||
40 | - ((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP) & | ||
41 | - bs->file->bs->supported_zero_flags); | ||
42 | + ((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK) & | ||
43 | + bs->file->bs->supported_zero_flags); | ||
44 | |||
45 | return 0; | 23 | return 0; |
46 | } | 24 | } |
47 | diff --git a/block/mirror.c b/block/mirror.c | 25 | |
48 | index XXXXXXX..XXXXXXX 100644 | 26 | -static inline uint32_t sector2cluster(BDRVVVFATState* s,off_t sector_num) |
49 | --- a/block/mirror.c | 27 | +static inline int32_t sector2cluster(BDRVVVFATState* s,off_t sector_num) |
50 | +++ b/block/mirror.c | 28 | { |
51 | @@ -XXX,XX +XXX,XX @@ static void mirror_start_job(const char *job_id, BlockDriverState *bs, | 29 | return (sector_num - s->offset_to_root_dir) / s->sectors_per_cluster; |
30 | } | ||
31 | @@ -XXX,XX +XXX,XX @@ static int vvfat_write(BlockDriverState *bs, int64_t sector_num, | ||
32 | { | ||
33 | BDRVVVFATState *s = bs->opaque; | ||
34 | int i, ret; | ||
35 | + int first_cluster, last_cluster; | ||
36 | |||
37 | DLOG(checkpoint()); | ||
38 | |||
39 | @@ -XXX,XX +XXX,XX @@ DLOG(checkpoint()); | ||
40 | if (sector_num < s->offset_to_fat) | ||
41 | return -1; | ||
42 | |||
43 | - for (i = sector2cluster(s, sector_num); | ||
44 | - i <= sector2cluster(s, sector_num + nb_sectors - 1);) { | ||
45 | - mapping_t* mapping = find_mapping_for_cluster(s, i); | ||
46 | + /* | ||
47 | + * Values will be negative for writes to the FAT, which is located before | ||
48 | + * the root directory. | ||
49 | + */ | ||
50 | + first_cluster = sector2cluster(s, sector_num); | ||
51 | + last_cluster = sector2cluster(s, sector_num + nb_sectors - 1); | ||
52 | + | ||
53 | + for (i = first_cluster; i <= last_cluster;) { | ||
54 | + mapping_t *mapping = NULL; | ||
55 | + | ||
56 | + if (i >= 0) { | ||
57 | + mapping = find_mapping_for_cluster(s, i); | ||
58 | + } | ||
59 | + | ||
60 | if (mapping) { | ||
61 | if (mapping->read_only) { | ||
62 | fprintf(stderr, "Tried to write to write-protected file %s\n", | ||
63 | @@ -XXX,XX +XXX,XX @@ DLOG(checkpoint()); | ||
64 | } | ||
65 | } | ||
66 | i = mapping->end; | ||
67 | - } else | ||
68 | + } else { | ||
69 | i++; | ||
70 | + } | ||
52 | } | 71 | } |
53 | mirror_top_bs->total_sectors = bs->total_sectors; | 72 | |
54 | mirror_top_bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED; | 73 | /* |
55 | - mirror_top_bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED; | 74 | @@ -XXX,XX +XXX,XX @@ DLOG(fprintf(stderr, "Write to qcow backend: %d + %d\n", (int)sector_num, nb_sec |
56 | + mirror_top_bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED | | 75 | return ret; |
57 | + BDRV_REQ_NO_FALLBACK; | 76 | } |
58 | bs_opaque = g_new0(MirrorBDSOpaque, 1); | 77 | |
59 | mirror_top_bs->opaque = bs_opaque; | 78 | - for (i = sector2cluster(s, sector_num); |
60 | bdrv_set_aio_context(mirror_top_bs, bdrv_get_aio_context(bs)); | 79 | - i <= sector2cluster(s, sector_num + nb_sectors - 1); i++) |
61 | diff --git a/block/raw-format.c b/block/raw-format.c | 80 | - if (i >= 0) |
62 | index XXXXXXX..XXXXXXX 100644 | 81 | + for (i = first_cluster; i <= last_cluster; i++) { |
63 | --- a/block/raw-format.c | 82 | + if (i >= 0) { |
64 | +++ b/block/raw-format.c | 83 | s->used_clusters[i] |= USED_ALLOCATED; |
65 | @@ -XXX,XX +XXX,XX @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags, | 84 | + } |
66 | bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED | | 85 | + } |
67 | (BDRV_REQ_FUA & bs->file->bs->supported_write_flags); | 86 | |
68 | bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED | | 87 | DLOG(checkpoint()); |
69 | - ((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP) & | 88 | /* TODO: add timeout */ |
70 | + ((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK) & | ||
71 | bs->file->bs->supported_zero_flags); | ||
72 | |||
73 | if (bs->probed && !bdrv_is_read_only(bs)) { | ||
74 | -- | 89 | -- |
75 | 2.20.1 | 90 | 2.31.1 |
76 | 91 | ||
77 | 92 | diff view generated by jsdifflib |
1 | There is only a single caller of bdrv_make_zero(), which is qemu-img | 1 | This demonstrates what happens when the block status changes in |
---|---|---|---|
2 | convert. If the function fails, we just fall back to a different method | 2 | sub-min_sparse granularity, but all of the parts are zeroed out. The |
3 | of zeroing out blocks on the target image. There is no good reason to | 3 | alignment logic in is_allocated_sectors() prevents that the target image |
4 | print error messages on stderr when the higher level operation will | 4 | remains fully sparse as expected, but turns it into a data cluster of |
5 | actually succeed. | 5 | explicit zeros. |
6 | 6 | ||
7 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 7 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
8 | Acked-by: Eric Blake <eblake@redhat.com> | 8 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> |
9 | Message-Id: <20211217164654.1184218-2-vsementsov@virtuozzo.com> | ||
10 | Tested-by: Peter Lieven <pl@kamp.de> | ||
11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
9 | --- | 12 | --- |
10 | block/io.c | 4 ---- | 13 | tests/qemu-iotests/122 | 1 + |
11 | 1 file changed, 4 deletions(-) | 14 | tests/qemu-iotests/122.out | 10 ++++++++-- |
15 | 2 files changed, 9 insertions(+), 2 deletions(-) | ||
12 | 16 | ||
13 | diff --git a/block/io.c b/block/io.c | 17 | diff --git a/tests/qemu-iotests/122 b/tests/qemu-iotests/122 |
18 | index XXXXXXX..XXXXXXX 100755 | ||
19 | --- a/tests/qemu-iotests/122 | ||
20 | +++ b/tests/qemu-iotests/122 | ||
21 | @@ -XXX,XX +XXX,XX @@ $QEMU_IO -c "write -P 0 0 64k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_test | ||
22 | $QEMU_IO -c "write 0 1k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir | ||
23 | $QEMU_IO -c "write 8k 1k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir | ||
24 | $QEMU_IO -c "write 17k 1k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir | ||
25 | +$QEMU_IO -c "write -P 0 65k 1k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir | ||
26 | |||
27 | for min_sparse in 4k 8k; do | ||
28 | echo | ||
29 | diff --git a/tests/qemu-iotests/122.out b/tests/qemu-iotests/122.out | ||
14 | index XXXXXXX..XXXXXXX 100644 | 30 | index XXXXXXX..XXXXXXX 100644 |
15 | --- a/block/io.c | 31 | --- a/tests/qemu-iotests/122.out |
16 | +++ b/block/io.c | 32 | +++ b/tests/qemu-iotests/122.out |
17 | @@ -XXX,XX +XXX,XX @@ int bdrv_make_zero(BdrvChild *child, BdrvRequestFlags flags) | 33 | @@ -XXX,XX +XXX,XX @@ wrote 1024/1024 bytes at offset 8192 |
18 | } | 34 | 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) |
19 | ret = bdrv_block_status(bs, offset, bytes, &bytes, NULL, NULL); | 35 | wrote 1024/1024 bytes at offset 17408 |
20 | if (ret < 0) { | 36 | 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) |
21 | - error_report("error getting block status at offset %" PRId64 ": %s", | 37 | +wrote 1024/1024 bytes at offset 66560 |
22 | - offset, strerror(-ret)); | 38 | +1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) |
23 | return ret; | 39 | |
24 | } | 40 | convert -S 4k |
25 | if (ret & BDRV_BLOCK_ZERO) { | 41 | [{ "start": 0, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, |
26 | @@ -XXX,XX +XXX,XX @@ int bdrv_make_zero(BdrvChild *child, BdrvRequestFlags flags) | 42 | @@ -XXX,XX +XXX,XX @@ convert -S 4k |
27 | } | 43 | { "start": 8192, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, |
28 | ret = bdrv_pwrite_zeroes(child, offset, bytes, flags); | 44 | { "start": 12288, "length": 4096, "depth": 0, "present": false, "zero": true, "data": false}, |
29 | if (ret < 0) { | 45 | { "start": 16384, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, |
30 | - error_report("error writing zeroes at offset %" PRId64 ": %s", | 46 | -{ "start": 20480, "length": 67088384, "depth": 0, "present": false, "zero": true, "data": false}] |
31 | - offset, strerror(-ret)); | 47 | +{ "start": 20480, "length": 46080, "depth": 0, "present": false, "zero": true, "data": false}, |
32 | return ret; | 48 | +{ "start": 66560, "length": 1024, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, |
33 | } | 49 | +{ "start": 67584, "length": 67041280, "depth": 0, "present": false, "zero": true, "data": false}] |
34 | offset += bytes; | 50 | |
51 | convert -c -S 4k | ||
52 | [{ "start": 0, "length": 1024, "depth": 0, "present": true, "zero": false, "data": true}, | ||
53 | @@ -XXX,XX +XXX,XX @@ convert -c -S 4k | ||
54 | |||
55 | convert -S 8k | ||
56 | [{ "start": 0, "length": 24576, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
57 | -{ "start": 24576, "length": 67084288, "depth": 0, "present": false, "zero": true, "data": false}] | ||
58 | +{ "start": 24576, "length": 41984, "depth": 0, "present": false, "zero": true, "data": false}, | ||
59 | +{ "start": 66560, "length": 1024, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
60 | +{ "start": 67584, "length": 67041280, "depth": 0, "present": false, "zero": true, "data": false}] | ||
61 | |||
62 | convert -c -S 8k | ||
63 | [{ "start": 0, "length": 1024, "depth": 0, "present": true, "zero": false, "data": true}, | ||
35 | -- | 64 | -- |
36 | 2.20.1 | 65 | 2.31.1 |
37 | 66 | ||
38 | 67 | diff view generated by jsdifflib |
1 | If qemu-img convert sees that the target image isn't zero-initialised | 1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> |
---|---|---|---|
2 | yet, it tries to do an efficient zero write for the whole image first | ||
3 | to save the overhead of repeated explicit zero writes during the | ||
4 | conversion. Obviously, this provides only an advantage if the | ||
5 | pre-zeroing is actually efficient. Otherwise, we can end up writing | ||
6 | zeroes slowly while zeroing out the whole image, and then overwrite the | ||
7 | same blocks again with real data, potentially doubling the written data. | ||
8 | 2 | ||
9 | Pass BDRV_REQ_NO_FALLBACK to blk_make_zero() to avoid this case. If we | 3 | Consider the case when the whole buffer is zero and end is unaligned. |
10 | can't efficiently zero out, we'll instead write explicit zeroes only if | ||
11 | there is no data to be written to a block. | ||
12 | 4 | ||
5 | If i <= tail, we return 1 and do one unaligned WRITE, RMW happens. | ||
6 | |||
7 | If i > tail, we do on aligned WRITE_ZERO (or skip if target is zeroed) | ||
8 | and again one unaligned WRITE, RMW happens. | ||
9 | |||
10 | Let's do better: don't fragment the whole-zero buffer and report it as | ||
11 | ZERO: in case of zeroed target we just do nothing and avoid RMW. If | ||
12 | target is not zeroes, one unaligned WRITE_ZERO should not be much worse | ||
13 | than one unaligned WRITE. | ||
14 | |||
15 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
16 | Message-Id: <20211217164654.1184218-3-vsementsov@virtuozzo.com> | ||
17 | Tested-by: Peter Lieven <pl@kamp.de> | ||
13 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 18 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
14 | Acked-by: Eric Blake <eblake@redhat.com> | ||
15 | --- | 19 | --- |
16 | qemu-img.c | 2 +- | 20 | qemu-img.c | 23 +++++++++++++++++++---- |
17 | 1 file changed, 1 insertion(+), 1 deletion(-) | 21 | tests/qemu-iotests/122.out | 8 ++------ |
22 | 2 files changed, 21 insertions(+), 10 deletions(-) | ||
18 | 23 | ||
19 | diff --git a/qemu-img.c b/qemu-img.c | 24 | diff --git a/qemu-img.c b/qemu-img.c |
20 | index XXXXXXX..XXXXXXX 100644 | 25 | index XXXXXXX..XXXXXXX 100644 |
21 | --- a/qemu-img.c | 26 | --- a/qemu-img.c |
22 | +++ b/qemu-img.c | 27 | +++ b/qemu-img.c |
23 | @@ -XXX,XX +XXX,XX @@ static int convert_do_copy(ImgConvertState *s) | 28 | @@ -XXX,XX +XXX,XX @@ static int is_allocated_sectors(const uint8_t *buf, int n, int *pnum, |
24 | if (!s->has_zero_init && !s->target_has_backing && | ||
25 | bdrv_can_write_zeroes_with_unmap(blk_bs(s->target))) | ||
26 | { | ||
27 | - ret = blk_make_zero(s->target, BDRV_REQ_MAY_UNMAP); | ||
28 | + ret = blk_make_zero(s->target, BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK); | ||
29 | if (ret == 0) { | ||
30 | s->has_zero_init = true; | ||
31 | } | 29 | } |
30 | } | ||
31 | |||
32 | + if (i == n) { | ||
33 | + /* | ||
34 | + * The whole buf is the same. | ||
35 | + * No reason to split it into chunks, so return now. | ||
36 | + */ | ||
37 | + *pnum = i; | ||
38 | + return !is_zero; | ||
39 | + } | ||
40 | + | ||
41 | tail = (sector_num + i) & (alignment - 1); | ||
42 | if (tail) { | ||
43 | if (is_zero && i <= tail) { | ||
44 | - /* treat unallocated areas which only consist | ||
45 | - * of a small tail as allocated. */ | ||
46 | + /* | ||
47 | + * For sure next sector after i is data, and it will rewrite this | ||
48 | + * tail anyway due to RMW. So, let's just write data now. | ||
49 | + */ | ||
50 | is_zero = false; | ||
51 | } | ||
52 | if (!is_zero) { | ||
53 | - /* align up end offset of allocated areas. */ | ||
54 | + /* If possible, align up end offset of allocated areas. */ | ||
55 | i += alignment - tail; | ||
56 | i = MIN(i, n); | ||
57 | } else { | ||
58 | - /* align down end offset of zero areas. */ | ||
59 | + /* | ||
60 | + * For sure next sector after i is data, and it will rewrite this | ||
61 | + * tail anyway due to RMW. Better is avoid RMW and write zeroes up | ||
62 | + * to aligned bound. | ||
63 | + */ | ||
64 | i -= tail; | ||
65 | } | ||
66 | } | ||
67 | diff --git a/tests/qemu-iotests/122.out b/tests/qemu-iotests/122.out | ||
68 | index XXXXXXX..XXXXXXX 100644 | ||
69 | --- a/tests/qemu-iotests/122.out | ||
70 | +++ b/tests/qemu-iotests/122.out | ||
71 | @@ -XXX,XX +XXX,XX @@ convert -S 4k | ||
72 | { "start": 8192, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
73 | { "start": 12288, "length": 4096, "depth": 0, "present": false, "zero": true, "data": false}, | ||
74 | { "start": 16384, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
75 | -{ "start": 20480, "length": 46080, "depth": 0, "present": false, "zero": true, "data": false}, | ||
76 | -{ "start": 66560, "length": 1024, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
77 | -{ "start": 67584, "length": 67041280, "depth": 0, "present": false, "zero": true, "data": false}] | ||
78 | +{ "start": 20480, "length": 67088384, "depth": 0, "present": false, "zero": true, "data": false}] | ||
79 | |||
80 | convert -c -S 4k | ||
81 | [{ "start": 0, "length": 1024, "depth": 0, "present": true, "zero": false, "data": true}, | ||
82 | @@ -XXX,XX +XXX,XX @@ convert -c -S 4k | ||
83 | |||
84 | convert -S 8k | ||
85 | [{ "start": 0, "length": 24576, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
86 | -{ "start": 24576, "length": 41984, "depth": 0, "present": false, "zero": true, "data": false}, | ||
87 | -{ "start": 66560, "length": 1024, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
88 | -{ "start": 67584, "length": 67041280, "depth": 0, "present": false, "zero": true, "data": false}] | ||
89 | +{ "start": 24576, "length": 67084288, "depth": 0, "present": false, "zero": true, "data": false}] | ||
90 | |||
91 | convert -c -S 8k | ||
92 | [{ "start": 0, "length": 1024, "depth": 0, "present": true, "zero": false, "data": true}, | ||
32 | -- | 93 | -- |
33 | 2.20.1 | 94 | 2.31.1 |
34 | 95 | ||
35 | 96 | diff view generated by jsdifflib |
1 | For qemu-img convert, we want an operation that zeroes out the whole | 1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> |
---|---|---|---|
2 | image if this can be done efficiently, but that returns an error | 2 | |
3 | otherwise so we don't write explicit zeroes and immediately overwrite | 3 | First, this permission never protected a node from being changed, as |
4 | them with the real data, potentially doubling the amount of data to be | 4 | generic child-replacing functions don't check it. |
5 | written. | 5 | |
6 | 6 | Second, it's a strange thing: it presents a permission of parent node | |
7 | to change its child. But generally, children are replaced by different | ||
8 | mechanisms, like jobs or qmp commands, not by nodes. | ||
9 | |||
10 | Graph-mod permission is hard to understand. All other permissions | ||
11 | describe operations which done by parent node on its child: read, | ||
12 | write, resize. Graph modification operations are something completely | ||
13 | different. | ||
14 | |||
15 | The only place where BLK_PERM_GRAPH_MOD is used as "perm" (not shared | ||
16 | perm) is mirror_start_job, for s->target. Still modern code should use | ||
17 | bdrv_freeze_backing_chain() to protect from graph modification, if we | ||
18 | don't do it somewhere it may be considered as a bug. So, it's a bit | ||
19 | risky to drop GRAPH_MOD, and analyzing of possible loss of protection | ||
20 | is hard. But one day we should do it, let's do it now. | ||
21 | |||
22 | One more bit of information is that locking the corresponding byte in | ||
23 | file-posix doesn't make sense at all. | ||
24 | |||
25 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
26 | Message-Id: <20210902093754.2352-1-vsementsov@virtuozzo.com> | ||
7 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 27 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
8 | Acked-by: Eric Blake <eblake@redhat.com> | ||
9 | --- | 28 | --- |
10 | include/block/block.h | 7 ++++++- | 29 | qapi/block-core.json | 7 ++----- |
11 | block/io.c | 12 +++++++++++- | 30 | include/block/block.h | 9 +++++---- |
12 | 2 files changed, 17 insertions(+), 2 deletions(-) | 31 | block.c | 7 +------ |
13 | 32 | block/commit.c | 1 - | |
33 | block/mirror.c | 15 +++------------ | ||
34 | hw/block/block.c | 3 +-- | ||
35 | scripts/render_block_graph.py | 1 - | ||
36 | tests/qemu-iotests/273.out | 4 ---- | ||
37 | 8 files changed, 12 insertions(+), 35 deletions(-) | ||
38 | |||
39 | diff --git a/qapi/block-core.json b/qapi/block-core.json | ||
40 | index XXXXXXX..XXXXXXX 100644 | ||
41 | --- a/qapi/block-core.json | ||
42 | +++ b/qapi/block-core.json | ||
43 | @@ -XXX,XX +XXX,XX @@ | ||
44 | # | ||
45 | # @resize: This permission is required to change the size of a block node. | ||
46 | # | ||
47 | -# @graph-mod: This permission is required to change the node that this | ||
48 | -# BdrvChild points to. | ||
49 | -# | ||
50 | # Since: 4.0 | ||
51 | ## | ||
52 | { 'enum': 'BlockPermission', | ||
53 | - 'data': [ 'consistent-read', 'write', 'write-unchanged', 'resize', | ||
54 | - 'graph-mod' ] } | ||
55 | + 'data': [ 'consistent-read', 'write', 'write-unchanged', 'resize' ] } | ||
56 | + | ||
57 | ## | ||
58 | # @XDbgBlockGraphEdge: | ||
59 | # | ||
14 | diff --git a/include/block/block.h b/include/block/block.h | 60 | diff --git a/include/block/block.h b/include/block/block.h |
15 | index XXXXXXX..XXXXXXX 100644 | 61 | index XXXXXXX..XXXXXXX 100644 |
16 | --- a/include/block/block.h | 62 | --- a/include/block/block.h |
17 | +++ b/include/block/block.h | 63 | +++ b/include/block/block.h |
18 | @@ -XXX,XX +XXX,XX @@ typedef enum { | 64 | @@ -XXX,XX +XXX,XX @@ enum { |
65 | BLK_PERM_RESIZE = 0x08, | ||
66 | |||
67 | /** | ||
68 | - * This permission is required to change the node that this BdrvChild | ||
69 | - * points to. | ||
70 | + * There was a now-removed bit BLK_PERM_GRAPH_MOD, with value of 0x10. QEMU | ||
71 | + * 6.1 and earlier may still lock the corresponding byte in block/file-posix | ||
72 | + * locking. So, implementing some new permission should be very careful to | ||
73 | + * not interfere with this old unused thing. | ||
19 | */ | 74 | */ |
20 | BDRV_REQ_SERIALISING = 0x80, | 75 | - BLK_PERM_GRAPH_MOD = 0x10, |
21 | 76 | ||
22 | + /* Execute the request only if the operation can be offloaded or otherwise | 77 | - BLK_PERM_ALL = 0x1f, |
23 | + * be executed efficiently, but return an error instead of using a slow | 78 | + BLK_PERM_ALL = 0x0f, |
24 | + * fallback. */ | 79 | |
25 | + BDRV_REQ_NO_FALLBACK = 0x100, | 80 | DEFAULT_PERM_PASSTHROUGH = BLK_PERM_CONSISTENT_READ |
26 | + | 81 | | BLK_PERM_WRITE |
27 | /* Mask of valid flags */ | 82 | diff --git a/block.c b/block.c |
28 | - BDRV_REQ_MASK = 0xff, | 83 | index XXXXXXX..XXXXXXX 100644 |
29 | + BDRV_REQ_MASK = 0x1ff, | 84 | --- a/block.c |
30 | } BdrvRequestFlags; | 85 | +++ b/block.c |
31 | 86 | @@ -XXX,XX +XXX,XX @@ char *bdrv_perm_names(uint64_t perm) | |
32 | typedef struct BlockSizes { | 87 | { BLK_PERM_WRITE, "write" }, |
33 | diff --git a/block/io.c b/block/io.c | 88 | { BLK_PERM_WRITE_UNCHANGED, "write unchanged" }, |
34 | index XXXXXXX..XXXXXXX 100644 | 89 | { BLK_PERM_RESIZE, "resize" }, |
35 | --- a/block/io.c | 90 | - { BLK_PERM_GRAPH_MOD, "change children" }, |
36 | +++ b/block/io.c | 91 | { 0, NULL } |
37 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_driver_preadv(BlockDriverState *bs, | 92 | }; |
38 | unsigned int nb_sectors; | 93 | |
39 | 94 | @@ -XXX,XX +XXX,XX @@ static void bdrv_default_perms_for_cow(BlockDriverState *bs, BdrvChild *c, | |
40 | assert(!(flags & ~BDRV_REQ_MASK)); | 95 | shared = 0; |
41 | + assert(!(flags & BDRV_REQ_NO_FALLBACK)); | 96 | } |
42 | 97 | ||
43 | if (!drv) { | 98 | - shared |= BLK_PERM_CONSISTENT_READ | BLK_PERM_GRAPH_MOD | |
44 | return -ENOMEDIUM; | 99 | - BLK_PERM_WRITE_UNCHANGED; |
45 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_driver_pwritev(BlockDriverState *bs, | 100 | + shared |= BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED; |
46 | int ret; | 101 | |
47 | 102 | if (bs->open_flags & BDRV_O_INACTIVE) { | |
48 | assert(!(flags & ~BDRV_REQ_MASK)); | 103 | shared |= BLK_PERM_WRITE | BLK_PERM_RESIZE; |
49 | + assert(!(flags & BDRV_REQ_NO_FALLBACK)); | 104 | @@ -XXX,XX +XXX,XX @@ uint64_t bdrv_qapi_perm_to_blk_perm(BlockPermission qapi_perm) |
50 | 105 | [BLOCK_PERMISSION_WRITE] = BLK_PERM_WRITE, | |
51 | if (!drv) { | 106 | [BLOCK_PERMISSION_WRITE_UNCHANGED] = BLK_PERM_WRITE_UNCHANGED, |
52 | return -ENOMEDIUM; | 107 | [BLOCK_PERMISSION_RESIZE] = BLK_PERM_RESIZE, |
53 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs, | 108 | - [BLOCK_PERMISSION_GRAPH_MOD] = BLK_PERM_GRAPH_MOD, |
54 | return -ENOMEDIUM; | 109 | }; |
55 | } | 110 | |
56 | 111 | QEMU_BUILD_BUG_ON(ARRAY_SIZE(permissions) != BLOCK_PERMISSION__MAX); | |
57 | + if ((flags & ~bs->supported_zero_flags) & BDRV_REQ_NO_FALLBACK) { | 112 | @@ -XXX,XX +XXX,XX @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base, |
58 | + return -ENOTSUP; | 113 | update_inherits_from = bdrv_inherits_from_recursive(base, explicit_top); |
59 | + } | 114 | |
60 | + | 115 | /* success - we can delete the intermediate states, and link top->base */ |
61 | assert(alignment % bs->bl.request_alignment == 0); | 116 | - /* TODO Check graph modification op blockers (BLK_PERM_GRAPH_MOD) once |
62 | head = offset % alignment; | 117 | - * we've figured out how they should work. */ |
63 | tail = (offset + bytes) % alignment; | 118 | if (!backing_file_str) { |
64 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs, | 119 | bdrv_refresh_filename(base); |
65 | assert(!bs->supported_zero_flags); | 120 | backing_file_str = base->filename; |
121 | diff --git a/block/commit.c b/block/commit.c | ||
122 | index XXXXXXX..XXXXXXX 100644 | ||
123 | --- a/block/commit.c | ||
124 | +++ b/block/commit.c | ||
125 | @@ -XXX,XX +XXX,XX @@ void commit_start(const char *job_id, BlockDriverState *bs, | ||
126 | s->base = blk_new(s->common.job.aio_context, | ||
127 | base_perms, | ||
128 | BLK_PERM_CONSISTENT_READ | ||
129 | - | BLK_PERM_GRAPH_MOD | ||
130 | | BLK_PERM_WRITE_UNCHANGED); | ||
131 | ret = blk_insert_bs(s->base, base, errp); | ||
132 | if (ret < 0) { | ||
133 | diff --git a/block/mirror.c b/block/mirror.c | ||
134 | index XXXXXXX..XXXXXXX 100644 | ||
135 | --- a/block/mirror.c | ||
136 | +++ b/block/mirror.c | ||
137 | @@ -XXX,XX +XXX,XX @@ static void mirror_complete(Job *job, Error **errp) | ||
138 | replace_aio_context = bdrv_get_aio_context(s->to_replace); | ||
139 | aio_context_acquire(replace_aio_context); | ||
140 | |||
141 | - /* TODO Translate this into permission system. Current definition of | ||
142 | - * GRAPH_MOD would require to request it for the parents; they might | ||
143 | - * not even be BlockDriverStates, however, so a BdrvChild can't address | ||
144 | - * them. May need redefinition of GRAPH_MOD. */ | ||
145 | + /* TODO Translate this into child freeze system. */ | ||
146 | error_setg(&s->replace_blocker, | ||
147 | "block device is in use by block-job-complete"); | ||
148 | bdrv_op_block_all(s->to_replace, s->replace_blocker); | ||
149 | @@ -XXX,XX +XXX,XX @@ static BlockJob *mirror_start_job( | ||
150 | s = block_job_create(job_id, driver, NULL, mirror_top_bs, | ||
151 | BLK_PERM_CONSISTENT_READ, | ||
152 | BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED | | ||
153 | - BLK_PERM_WRITE | BLK_PERM_GRAPH_MOD, speed, | ||
154 | + BLK_PERM_WRITE, speed, | ||
155 | creation_flags, cb, opaque, errp); | ||
156 | if (!s) { | ||
157 | goto fail; | ||
158 | @@ -XXX,XX +XXX,XX @@ static BlockJob *mirror_start_job( | ||
159 | target_perms |= BLK_PERM_RESIZE; | ||
66 | } | 160 | } |
67 | 161 | ||
68 | - if (ret == -ENOTSUP) { | 162 | - target_shared_perms |= BLK_PERM_CONSISTENT_READ |
69 | + if (ret == -ENOTSUP && !(flags & BDRV_REQ_NO_FALLBACK)) { | 163 | - | BLK_PERM_WRITE |
70 | /* Fall back to bounce buffer if write zeroes is unsupported */ | 164 | - | BLK_PERM_GRAPH_MOD; |
71 | BdrvRequestFlags write_flags = flags & ~BDRV_REQ_ZERO_WRITE; | 165 | + target_shared_perms |= BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE; |
72 | 166 | } else if (bdrv_chain_contains(bs, bdrv_skip_filters(target))) { | |
73 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_copy_range_internal( | 167 | /* |
74 | BdrvTrackedRequest req; | 168 | * We may want to allow this in the future, but it would |
75 | int ret; | 169 | @@ -XXX,XX +XXX,XX @@ static BlockJob *mirror_start_job( |
76 | 170 | goto fail; | |
77 | + /* TODO We can support BDRV_REQ_NO_FALLBACK here */ | 171 | } |
78 | + assert(!(read_flags & BDRV_REQ_NO_FALLBACK)); | 172 | |
79 | + assert(!(write_flags & BDRV_REQ_NO_FALLBACK)); | 173 | - if (backing_mode != MIRROR_LEAVE_BACKING_CHAIN) { |
80 | + | 174 | - target_perms |= BLK_PERM_GRAPH_MOD; |
81 | if (!dst || !dst->bs) { | 175 | - } |
82 | return -ENOMEDIUM; | 176 | - |
83 | } | 177 | s->target = blk_new(s->common.job.aio_context, |
178 | target_perms, target_shared_perms); | ||
179 | ret = blk_insert_bs(s->target, target, errp); | ||
180 | diff --git a/hw/block/block.c b/hw/block/block.c | ||
181 | index XXXXXXX..XXXXXXX 100644 | ||
182 | --- a/hw/block/block.c | ||
183 | +++ b/hw/block/block.c | ||
184 | @@ -XXX,XX +XXX,XX @@ bool blkconf_apply_backend_options(BlockConf *conf, bool readonly, | ||
185 | perm |= BLK_PERM_WRITE; | ||
186 | } | ||
187 | |||
188 | - shared_perm = BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED | | ||
189 | - BLK_PERM_GRAPH_MOD; | ||
190 | + shared_perm = BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED; | ||
191 | if (resizable) { | ||
192 | shared_perm |= BLK_PERM_RESIZE; | ||
193 | } | ||
194 | diff --git a/scripts/render_block_graph.py b/scripts/render_block_graph.py | ||
195 | index XXXXXXX..XXXXXXX 100755 | ||
196 | --- a/scripts/render_block_graph.py | ||
197 | +++ b/scripts/render_block_graph.py | ||
198 | @@ -XXX,XX +XXX,XX @@ def perm(arr): | ||
199 | s = 'w' if 'write' in arr else '_' | ||
200 | s += 'r' if 'consistent-read' in arr else '_' | ||
201 | s += 'u' if 'write-unchanged' in arr else '_' | ||
202 | - s += 'g' if 'graph-mod' in arr else '_' | ||
203 | s += 's' if 'resize' in arr else '_' | ||
204 | return s | ||
205 | |||
206 | diff --git a/tests/qemu-iotests/273.out b/tests/qemu-iotests/273.out | ||
207 | index XXXXXXX..XXXXXXX 100644 | ||
208 | --- a/tests/qemu-iotests/273.out | ||
209 | +++ b/tests/qemu-iotests/273.out | ||
210 | @@ -XXX,XX +XXX,XX @@ Testing: -blockdev file,node-name=base,filename=TEST_DIR/t.IMGFMT.base -blockdev | ||
211 | "name": "file", | ||
212 | "parent": 5, | ||
213 | "shared-perm": [ | ||
214 | - "graph-mod", | ||
215 | "write-unchanged", | ||
216 | "consistent-read" | ||
217 | ], | ||
218 | @@ -XXX,XX +XXX,XX @@ Testing: -blockdev file,node-name=base,filename=TEST_DIR/t.IMGFMT.base -blockdev | ||
219 | "name": "backing", | ||
220 | "parent": 5, | ||
221 | "shared-perm": [ | ||
222 | - "graph-mod", | ||
223 | "resize", | ||
224 | "write-unchanged", | ||
225 | "write", | ||
226 | @@ -XXX,XX +XXX,XX @@ Testing: -blockdev file,node-name=base,filename=TEST_DIR/t.IMGFMT.base -blockdev | ||
227 | "name": "file", | ||
228 | "parent": 3, | ||
229 | "shared-perm": [ | ||
230 | - "graph-mod", | ||
231 | "write-unchanged", | ||
232 | "consistent-read" | ||
233 | ], | ||
234 | @@ -XXX,XX +XXX,XX @@ Testing: -blockdev file,node-name=base,filename=TEST_DIR/t.IMGFMT.base -blockdev | ||
235 | "name": "backing", | ||
236 | "parent": 3, | ||
237 | "shared-perm": [ | ||
238 | - "graph-mod", | ||
239 | "resize", | ||
240 | "write-unchanged", | ||
241 | "write", | ||
84 | -- | 242 | -- |
85 | 2.20.1 | 243 | 2.31.1 |
86 | 244 | ||
87 | 245 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
1 | 2 | ||
3 | A lot of Optional[] types doesn't make code beautiful. | ||
4 | test_field_width defaults to 8, but that is never used in the code. | ||
5 | |||
6 | More over, if we want some default behavior for single call of | ||
7 | test_run(), it should just print the whole test name, not limiting or | ||
8 | expanding its width, so 8 is bad default. | ||
9 | |||
10 | So, just drop the default as unused for now. | ||
11 | |||
12 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
13 | Message-Id: <20211210201450.101576-1-vsementsov@virtuozzo.com> | ||
14 | Reviewed-by: John Snow <jsnow@redhat.com> | ||
15 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
16 | --- | ||
17 | tests/qemu-iotests/testrunner.py | 21 ++++++++++----------- | ||
18 | 1 file changed, 10 insertions(+), 11 deletions(-) | ||
19 | |||
20 | diff --git a/tests/qemu-iotests/testrunner.py b/tests/qemu-iotests/testrunner.py | ||
21 | index XXXXXXX..XXXXXXX 100644 | ||
22 | --- a/tests/qemu-iotests/testrunner.py | ||
23 | +++ b/tests/qemu-iotests/testrunner.py | ||
24 | @@ -XXX,XX +XXX,XX @@ def __enter__(self) -> 'TestRunner': | ||
25 | def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any) -> None: | ||
26 | self._stack.close() | ||
27 | |||
28 | - def test_print_one_line(self, test: str, starttime: str, | ||
29 | + def test_print_one_line(self, test: str, | ||
30 | + test_field_width: int, | ||
31 | + starttime: str, | ||
32 | endtime: Optional[str] = None, status: str = '...', | ||
33 | lasttime: Optional[float] = None, | ||
34 | thistime: Optional[float] = None, | ||
35 | description: str = '', | ||
36 | - test_field_width: Optional[int] = None, | ||
37 | end: str = '\n') -> None: | ||
38 | """ Print short test info before/after test run """ | ||
39 | test = os.path.basename(test) | ||
40 | |||
41 | - if test_field_width is None: | ||
42 | - test_field_width = 8 | ||
43 | - | ||
44 | if self.makecheck and status != '...': | ||
45 | if status and status != 'pass': | ||
46 | status = f' [{status}]' | ||
47 | @@ -XXX,XX +XXX,XX @@ def do_run_test(self, test: str, mp: bool) -> TestResult: | ||
48 | casenotrun=casenotrun) | ||
49 | |||
50 | def run_test(self, test: str, | ||
51 | - test_field_width: Optional[int] = None, | ||
52 | + test_field_width: int, | ||
53 | mp: bool = False) -> TestResult: | ||
54 | """ | ||
55 | Run one test and print short status | ||
56 | @@ -XXX,XX +XXX,XX @@ def run_test(self, test: str, | ||
57 | |||
58 | if not self.makecheck: | ||
59 | self.test_print_one_line(test=test, | ||
60 | + test_field_width=test_field_width, | ||
61 | status = 'started' if mp else '...', | ||
62 | starttime=start, | ||
63 | lasttime=last_el, | ||
64 | - end = '\n' if mp else '\r', | ||
65 | - test_field_width=test_field_width) | ||
66 | + end = '\n' if mp else '\r') | ||
67 | |||
68 | res = self.do_run_test(test, mp) | ||
69 | |||
70 | end = datetime.datetime.now().strftime('%H:%M:%S') | ||
71 | - self.test_print_one_line(test=test, status=res.status, | ||
72 | + self.test_print_one_line(test=test, | ||
73 | + test_field_width=test_field_width, | ||
74 | + status=res.status, | ||
75 | starttime=start, endtime=end, | ||
76 | lasttime=last_el, thistime=res.elapsed, | ||
77 | - description=res.description, | ||
78 | - test_field_width=test_field_width) | ||
79 | + description=res.description) | ||
80 | |||
81 | if res.casenotrun: | ||
82 | print(res.casenotrun) | ||
83 | -- | ||
84 | 2.31.1 | ||
85 | |||
86 | diff view generated by jsdifflib |