1 | The following changes since commit ec397e90d21269037280633b6058d1f280e27667: | 1 | The following changes since commit c1eb2ddf0f8075faddc5f7c3d39feae3e8e9d6b4: |
---|---|---|---|
2 | 2 | ||
3 | Merge remote-tracking branch 'remotes/alistair/tags/pull-riscv-to-apply-20210901-2' into staging (2021-09-01 08:33:02 +0100) | 3 | Update version for v8.0.0 release (2023-04-19 17:27:13 +0100) |
4 | 4 | ||
5 | are available in the Git repository at: | 5 | are available in the Git repository at: |
6 | 6 | ||
7 | https://github.com/XanClic/qemu.git tags/pull-block-2021-09-01 | 7 | https://gitlab.com/stefanha/qemu.git tags/block-pull-request |
8 | 8 | ||
9 | for you to fetch changes up to ebd979c74e2b8a7275090475df36dde4ab858320: | 9 | for you to fetch changes up to 36e5e9b22abe56aa00ca067851555ad8127a7966: |
10 | 10 | ||
11 | block/file-win32: add reopen handlers (2021-09-01 14:38:08 +0200) | 11 | tracing: install trace events file only if necessary (2023-04-20 07:39:43 -0400) |
12 | |||
13 | ---------------------------------------------------------------- | ||
14 | Pull request | ||
15 | |||
16 | Sam Li's zoned storage work and fixes I collected during the 8.0 freeze. | ||
17 | |||
18 | ---------------------------------------------------------------- | ||
19 | |||
20 | Carlos Santos (1): | ||
21 | tracing: install trace events file only if necessary | ||
22 | |||
23 | Philippe Mathieu-Daudé (1): | ||
24 | block/dmg: Declare a type definition for DMG uncompress function | ||
25 | |||
26 | Sam Li (17): | ||
27 | block/block-common: add zoned device structs | ||
28 | block/file-posix: introduce helper functions for sysfs attributes | ||
29 | block/block-backend: add block layer APIs resembling Linux | ||
30 | ZonedBlockDevice ioctls | ||
31 | block/raw-format: add zone operations to pass through requests | ||
32 | block: add zoned BlockDriver check to block layer | ||
33 | iotests: test new zone operations | ||
34 | block: add some trace events for new block layer APIs | ||
35 | docs/zoned-storage: add zoned device documentation | ||
36 | file-posix: add tracking of the zone write pointers | ||
37 | block: introduce zone append write for zoned devices | ||
38 | qemu-iotests: test zone append operation | ||
39 | block: add some trace events for zone append | ||
40 | include: update virtio_blk headers to v6.3-rc1 | ||
41 | virtio-blk: add zoned storage emulation for zoned devices | ||
42 | block: add accounting for zone append operation | ||
43 | virtio-blk: add some trace events for zoned emulation | ||
44 | docs/zoned-storage:add zoned emulation use case | ||
45 | |||
46 | Thomas De Schampheleire (1): | ||
47 | tracetool: use relative paths for '#line' preprocessor directives | ||
48 | |||
49 | docs/devel/index-api.rst | 1 + | ||
50 | docs/devel/zoned-storage.rst | 62 ++ | ||
51 | qapi/block-core.json | 68 +- | ||
52 | qapi/block.json | 4 + | ||
53 | meson.build | 4 + | ||
54 | block/dmg.h | 8 +- | ||
55 | include/block/accounting.h | 1 + | ||
56 | include/block/block-common.h | 57 ++ | ||
57 | include/block/block-io.h | 13 + | ||
58 | include/block/block_int-common.h | 37 + | ||
59 | include/block/raw-aio.h | 8 +- | ||
60 | include/standard-headers/drm/drm_fourcc.h | 12 + | ||
61 | include/standard-headers/linux/ethtool.h | 48 +- | ||
62 | include/standard-headers/linux/fuse.h | 45 +- | ||
63 | include/standard-headers/linux/pci_regs.h | 1 + | ||
64 | include/standard-headers/linux/vhost_types.h | 2 + | ||
65 | include/standard-headers/linux/virtio_blk.h | 105 +++ | ||
66 | include/sysemu/block-backend-io.h | 27 + | ||
67 | linux-headers/asm-arm64/kvm.h | 1 + | ||
68 | linux-headers/asm-x86/kvm.h | 34 +- | ||
69 | linux-headers/linux/kvm.h | 9 + | ||
70 | linux-headers/linux/vfio.h | 15 +- | ||
71 | linux-headers/linux/vhost.h | 8 + | ||
72 | block.c | 19 + | ||
73 | block/block-backend.c | 193 ++++++ | ||
74 | block/dmg.c | 7 +- | ||
75 | block/file-posix.c | 677 +++++++++++++++++-- | ||
76 | block/io.c | 68 ++ | ||
77 | block/io_uring.c | 4 + | ||
78 | block/linux-aio.c | 3 + | ||
79 | block/qapi-sysemu.c | 11 + | ||
80 | block/qapi.c | 18 + | ||
81 | block/raw-format.c | 26 + | ||
82 | hw/block/virtio-blk-common.c | 2 + | ||
83 | hw/block/virtio-blk.c | 405 +++++++++++ | ||
84 | hw/virtio/virtio-qmp.c | 2 + | ||
85 | qemu-io-cmds.c | 224 ++++++ | ||
86 | block/trace-events | 4 + | ||
87 | docs/system/qemu-block-drivers.rst.inc | 6 + | ||
88 | hw/block/trace-events | 7 + | ||
89 | scripts/tracetool/backend/ftrace.py | 4 +- | ||
90 | scripts/tracetool/backend/log.py | 4 +- | ||
91 | scripts/tracetool/backend/syslog.py | 4 +- | ||
92 | tests/qemu-iotests/tests/zoned | 105 +++ | ||
93 | tests/qemu-iotests/tests/zoned.out | 69 ++ | ||
94 | trace/meson.build | 2 +- | ||
95 | 46 files changed, 2353 insertions(+), 81 deletions(-) | ||
96 | create mode 100644 docs/devel/zoned-storage.rst | ||
97 | create mode 100755 tests/qemu-iotests/tests/zoned | ||
98 | create mode 100644 tests/qemu-iotests/tests/zoned.out | ||
99 | |||
100 | -- | ||
101 | 2.39.2 | ||
12 | 102 | ||
13 | 103 | ||
14 | **Note:** I’ve signed the pull request tag with my new GPG key, which I | ||
15 | have uploaded here: | ||
16 | |||
17 | https://xanclic.moe/A1FA40D098019CDF | ||
18 | |||
19 | Included in that key should be the signature I made with my old key | ||
20 | (F407DB0061D5CF40), and I hope that’s sufficient to establish a | ||
21 | reasonable level of trust. | ||
22 | |||
23 | (I’ve also tried uploading this key to several keyservers, but it | ||
24 | appears to me that keyservers are kind of a thing of the past now, | ||
25 | especially when it comes to uploading keys with signatures on them...) | ||
26 | |||
27 | ---------------------------------------------------------------- | ||
28 | Block patches: | ||
29 | - Make the backup-top filter driver available for user-created block | ||
30 | nodes (i.e. via blockdev-add) | ||
31 | - Allow running iotests with gdb or valgrind being attached to qemu | ||
32 | instances | ||
33 | - Fix the raw format driver's permissions: There is no metadata, so we | ||
34 | only need WRITE or RESIZE when the parent needs it | ||
35 | - Basic reopen implementation for win32 files (file-win32.c) so that | ||
36 | qemu-img commit can work | ||
37 | - uclibc/musl build fix for the FUSE export code | ||
38 | - Some iotests delinting | ||
39 | - block-hmp-cmds.c refactoring | ||
40 | |||
41 | ---------------------------------------------------------------- | ||
42 | Emanuele Giuseppe Esposito (15): | ||
43 | python: qemu: add timer parameter for qmp.accept socket | ||
44 | python: qemu: pass the wrapper field from QEMUQtestmachine to | ||
45 | QEMUMachine | ||
46 | docs/devel/testing: add debug section to the QEMU iotests chapter | ||
47 | qemu-iotests: add option to attach gdbserver | ||
48 | qemu-iotests: delay QMP socket timers | ||
49 | qemu_iotests: insert gdbserver command line as wrapper for qemu binary | ||
50 | qemu-iotests: add gdbserver option to script tests too | ||
51 | docs/devel/testing: add -gdb option to the debugging section of QEMU | ||
52 | iotests | ||
53 | qemu-iotests: extend the check script to prepare supporting valgrind | ||
54 | for python tests | ||
55 | qemu-iotests: extend QMP socket timeout when using valgrind | ||
56 | qemu-iotests: allow valgrind to read/delete the generated log file | ||
57 | qemu-iotests: insert valgrind command line as wrapper for qemu binary | ||
58 | docs/devel/testing: add -valgrind option to the debug section of QEMU | ||
59 | iotests | ||
60 | qemu-iotests: add option to show qemu binary logs on stdout | ||
61 | docs/devel/testing: add -p option to the debug section of QEMU iotests | ||
62 | |||
63 | Fabrice Fontaine (1): | ||
64 | block/export/fuse.c: fix fuse-lseek on uclibc or musl | ||
65 | |||
66 | John Snow (3): | ||
67 | python: Reduce strictness of pylint's duplicate-code check | ||
68 | iotests: use with-statement for open() calls | ||
69 | iotests: use subprocess.DEVNULL instead of open("/dev/null") | ||
70 | |||
71 | Mao Zhongyi (1): | ||
72 | block/monitor: Consolidate hmp_handle_error calls to reduce redundant | ||
73 | code | ||
74 | |||
75 | Stefan Hajnoczi (1): | ||
76 | raw-format: drop WRITE and RESIZE child perms when possible | ||
77 | |||
78 | Viktor Prutyanov (1): | ||
79 | block/file-win32: add reopen handlers | ||
80 | |||
81 | Vladimir Sementsov-Ogievskiy (34): | ||
82 | block: introduce bdrv_replace_child_bs() | ||
83 | block: introduce blk_replace_bs | ||
84 | qdev-properties: PropertyInfo: add realized_set_allowed field | ||
85 | qdev: allow setting drive property for realized device | ||
86 | block: rename backup-top to copy-before-write | ||
87 | block-copy: move detecting fleecing scheme to block-copy | ||
88 | block/block-copy: introduce block_copy_set_copy_opts() | ||
89 | block/backup: set copy_range and compress after filter insertion | ||
90 | block/backup: move cluster size calculation to block-copy | ||
91 | block/copy-before-write: relax permission requirements when no parents | ||
92 | block/copy-before-write: drop extra bdrv_unref on failure path | ||
93 | block/copy-before-write: use file child instead of backing | ||
94 | block/copy-before-write: bdrv_cbw_append(): replace child at last | ||
95 | block/copy-before-write: introduce cbw_init() | ||
96 | block/copy-before-write: cbw_init(): rename variables | ||
97 | block/copy-before-write: cbw_init(): use file child after attaching | ||
98 | block/copy-before-write: bdrv_cbw_append(): drop unused compress arg | ||
99 | block/copy-before-write: cbw_init(): use options | ||
100 | block/copy-before-write: initialize block-copy bitmap | ||
101 | block/block-copy: make setting progress optional | ||
102 | block/copy-before-write: make public block driver | ||
103 | qapi: publish copy-before-write filter | ||
104 | python/qemu/machine.py: refactor _qemu_args() | ||
105 | python/qemu/machine: QEMUMachine: improve qmp() method | ||
106 | python:QEMUMachine: template typing for self returning methods | ||
107 | iotests/222: fix pylint and mypy complains | ||
108 | iotests/222: constantly use single quotes for strings | ||
109 | iotests: move 222 to tests/image-fleecing | ||
110 | iotests.py: hmp_qemu_io: support qdev | ||
111 | iotests/image-fleecing: proper source device | ||
112 | iotests/image-fleecing: rename tgt_node | ||
113 | iotests/image-fleecing: prepare for adding new test-case | ||
114 | iotests/image-fleecing: add test-case for copy-before-write filter | ||
115 | block/block-copy: block_copy_state_new(): drop extra arguments | ||
116 | |||
117 | docs/devel/testing.rst | 29 +++ | ||
118 | qapi/block-core.json | 25 +- | ||
119 | block/{backup-top.h => copy-before-write.h} | 25 +- | ||
120 | include/block/block-copy.h | 6 +- | ||
121 | include/block/block.h | 2 + | ||
122 | include/hw/qdev-properties.h | 1 + | ||
123 | include/sysemu/block-backend.h | 1 + | ||
124 | block.c | 31 +++ | ||
125 | block/backup-top.c | 253 ------------------- | ||
126 | block/backup.c | 116 ++------- | ||
127 | block/block-backend.c | 8 + | ||
128 | block/block-copy.c | 136 ++++++++--- | ||
129 | block/copy-before-write.c | 256 ++++++++++++++++++++ | ||
130 | block/export/fuse.c | 3 + | ||
131 | block/file-win32.c | 101 +++++++- | ||
132 | block/monitor/block-hmp-cmds.c | 12 +- | ||
133 | block/raw-format.c | 21 +- | ||
134 | hw/core/qdev-properties-system.c | 43 +++- | ||
135 | hw/core/qdev-properties.c | 6 +- | ||
136 | .gitlab-ci.d/buildtest.yml | 6 +- | ||
137 | MAINTAINERS | 4 +- | ||
138 | block/meson.build | 2 +- | ||
139 | python/qemu/machine/machine.py | 56 +++-- | ||
140 | python/qemu/machine/qtest.py | 9 +- | ||
141 | python/setup.cfg | 5 + | ||
142 | tests/qemu-iotests/222 | 159 ------------ | ||
143 | tests/qemu-iotests/222.out | 67 ----- | ||
144 | tests/qemu-iotests/283 | 35 ++- | ||
145 | tests/qemu-iotests/283.out | 4 +- | ||
146 | tests/qemu-iotests/297 | 2 +- | ||
147 | tests/qemu-iotests/check | 15 +- | ||
148 | tests/qemu-iotests/common.qemu | 7 +- | ||
149 | tests/qemu-iotests/common.rc | 8 +- | ||
150 | tests/qemu-iotests/iotests.py | 75 ++++-- | ||
151 | tests/qemu-iotests/testenv.py | 23 +- | ||
152 | tests/qemu-iotests/tests/image-fleecing | 192 +++++++++++++++ | ||
153 | tests/qemu-iotests/tests/image-fleecing.out | 139 +++++++++++ | ||
154 | 37 files changed, 1172 insertions(+), 711 deletions(-) | ||
155 | rename block/{backup-top.h => copy-before-write.h} (56%) | ||
156 | delete mode 100644 block/backup-top.c | ||
157 | create mode 100644 block/copy-before-write.c | ||
158 | delete mode 100755 tests/qemu-iotests/222 | ||
159 | delete mode 100644 tests/qemu-iotests/222.out | ||
160 | create mode 100755 tests/qemu-iotests/tests/image-fleecing | ||
161 | create mode 100644 tests/qemu-iotests/tests/image-fleecing.out | ||
162 | |||
163 | -- | ||
164 | 2.31.1 | ||
165 | |||
166 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
2 | 1 | ||
3 | Also add a new _qmp_timer field to the QEMUMachine class. | ||
4 | |||
5 | Let's change the default socket timeout to None, so that if | ||
6 | a subclass needs to add a timer, it can be done by modifying | ||
7 | this private field. | ||
8 | |||
9 | At the same time, restore the timer to be 15 seconds in iotests.py, to | ||
10 | give an upper bound to the QMP monitor test command execution. | ||
11 | |||
12 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
13 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
14 | Reviewed-by: John Snow <jsnow@redhat.com> | ||
15 | Acked-by: John Snow <jsnow@redhat.com> | ||
16 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
17 | Message-Id: <20210809090114.64834-2-eesposit@redhat.com> | ||
18 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
19 | --- | ||
20 | python/qemu/machine/machine.py | 7 +++++-- | ||
21 | python/qemu/machine/qtest.py | 5 +++-- | ||
22 | tests/qemu-iotests/iotests.py | 3 ++- | ||
23 | 3 files changed, 10 insertions(+), 5 deletions(-) | ||
24 | |||
25 | diff --git a/python/qemu/machine/machine.py b/python/qemu/machine/machine.py | ||
26 | index XXXXXXX..XXXXXXX 100644 | ||
27 | --- a/python/qemu/machine/machine.py | ||
28 | +++ b/python/qemu/machine/machine.py | ||
29 | @@ -XXX,XX +XXX,XX @@ def __init__(self, | ||
30 | sock_dir: Optional[str] = None, | ||
31 | drain_console: bool = False, | ||
32 | console_log: Optional[str] = None, | ||
33 | - log_dir: Optional[str] = None): | ||
34 | + log_dir: Optional[str] = None, | ||
35 | + qmp_timer: Optional[float] = None): | ||
36 | ''' | ||
37 | Initialize a QEMUMachine | ||
38 | |||
39 | @@ -XXX,XX +XXX,XX @@ def __init__(self, | ||
40 | @param drain_console: (optional) True to drain console socket to buffer | ||
41 | @param console_log: (optional) path to console log file | ||
42 | @param log_dir: where to create and keep log files | ||
43 | + @param qmp_timer: (optional) default QMP socket timeout | ||
44 | @note: Qemu process is not started until launch() is used. | ||
45 | ''' | ||
46 | # pylint: disable=too-many-arguments | ||
47 | @@ -XXX,XX +XXX,XX @@ def __init__(self, | ||
48 | self._binary = binary | ||
49 | self._args = list(args) | ||
50 | self._wrapper = wrapper | ||
51 | + self._qmp_timer = qmp_timer | ||
52 | |||
53 | self._name = name or "qemu-%d" % os.getpid() | ||
54 | self._base_temp_dir = base_temp_dir | ||
55 | @@ -XXX,XX +XXX,XX @@ def _pre_launch(self) -> None: | ||
56 | |||
57 | def _post_launch(self) -> None: | ||
58 | if self._qmp_connection: | ||
59 | - self._qmp.accept() | ||
60 | + self._qmp.accept(self._qmp_timer) | ||
61 | |||
62 | def _post_shutdown(self) -> None: | ||
63 | """ | ||
64 | diff --git a/python/qemu/machine/qtest.py b/python/qemu/machine/qtest.py | ||
65 | index XXXXXXX..XXXXXXX 100644 | ||
66 | --- a/python/qemu/machine/qtest.py | ||
67 | +++ b/python/qemu/machine/qtest.py | ||
68 | @@ -XXX,XX +XXX,XX @@ def __init__(self, | ||
69 | name: Optional[str] = None, | ||
70 | base_temp_dir: str = "/var/tmp", | ||
71 | socket_scm_helper: Optional[str] = None, | ||
72 | - sock_dir: Optional[str] = None): | ||
73 | + sock_dir: Optional[str] = None, | ||
74 | + qmp_timer: Optional[float] = None): | ||
75 | # pylint: disable=too-many-arguments | ||
76 | |||
77 | if name is None: | ||
78 | @@ -XXX,XX +XXX,XX @@ def __init__(self, | ||
79 | sock_dir = base_temp_dir | ||
80 | super().__init__(binary, args, name=name, base_temp_dir=base_temp_dir, | ||
81 | socket_scm_helper=socket_scm_helper, | ||
82 | - sock_dir=sock_dir) | ||
83 | + sock_dir=sock_dir, qmp_timer=qmp_timer) | ||
84 | self._qtest: Optional[QEMUQtestProtocol] = None | ||
85 | self._qtest_path = os.path.join(sock_dir, name + "-qtest.sock") | ||
86 | |||
87 | diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py | ||
88 | index XXXXXXX..XXXXXXX 100644 | ||
89 | --- a/tests/qemu-iotests/iotests.py | ||
90 | +++ b/tests/qemu-iotests/iotests.py | ||
91 | @@ -XXX,XX +XXX,XX @@ class VM(qtest.QEMUQtestMachine): | ||
92 | |||
93 | def __init__(self, path_suffix=''): | ||
94 | name = "qemu%s-%d" % (path_suffix, os.getpid()) | ||
95 | + timer = 15.0 | ||
96 | super().__init__(qemu_prog, qemu_opts, name=name, | ||
97 | base_temp_dir=test_dir, | ||
98 | socket_scm_helper=socket_scm_helper, | ||
99 | - sock_dir=sock_dir) | ||
100 | + sock_dir=sock_dir, qmp_timer=timer) | ||
101 | self._num_drives = 0 | ||
102 | |||
103 | def add_object(self, opts): | ||
104 | -- | ||
105 | 2.31.1 | ||
106 | |||
107 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: John Snow <jsnow@redhat.com> | ||
2 | 1 | ||
3 | Pylint prior to 2.8.3 (We pin at >= 2.8.0) includes function and method | ||
4 | signatures as part of its duplicate checking algorithm. This check does | ||
5 | not listen to pragmas, so the only way to disable it is to turn it off | ||
6 | completely or increase the minimum duplicate lines so that it doesn't | ||
7 | trigger for functions with long, multi-line signatures. | ||
8 | |||
9 | When we decide to upgrade to pylint 2.8.3 or greater, we will be able to | ||
10 | use 'ignore-signatures = true' to the config instead. | ||
11 | |||
12 | I'd prefer not to keep us on the very bleeding edge of pylint if I can | ||
13 | help it -- 2.8.3 came out only three days ago at time of writing. | ||
14 | |||
15 | See: https://github.com/PyCQA/pylint/pull/4474 | ||
16 | Signed-off-by: John Snow <jsnow@redhat.com> | ||
17 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
18 | Acked-by: John Snow <jsnow@redhat.com> | ||
19 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
20 | Message-Id: <20210809090114.64834-3-eesposit@redhat.com> | ||
21 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
22 | --- | ||
23 | python/setup.cfg | 5 +++++ | ||
24 | 1 file changed, 5 insertions(+) | ||
25 | |||
26 | diff --git a/python/setup.cfg b/python/setup.cfg | ||
27 | index XXXXXXX..XXXXXXX 100644 | ||
28 | --- a/python/setup.cfg | ||
29 | +++ b/python/setup.cfg | ||
30 | @@ -XXX,XX +XXX,XX @@ good-names=i, | ||
31 | # Ignore imports when computing similarities. | ||
32 | ignore-imports=yes | ||
33 | |||
34 | +# Minimum lines number of a similarity. | ||
35 | +# TODO: Remove after we opt in to Pylint 2.8.3. See commit msg. | ||
36 | +min-similarity-lines=6 | ||
37 | + | ||
38 | + | ||
39 | [isort] | ||
40 | force_grid_wrap=4 | ||
41 | force_sort_within_sections=True | ||
42 | -- | ||
43 | 2.31.1 | ||
44 | |||
45 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
2 | 1 | ||
3 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
4 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
5 | Reviewed-by: John Snow <jsnow@redhat.com> | ||
6 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
7 | Acked-by: John Snow <jsnow@redhat.com> | ||
8 | Message-Id: <20210809090114.64834-4-eesposit@redhat.com> | ||
9 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
10 | --- | ||
11 | python/qemu/machine/qtest.py | 4 +++- | ||
12 | 1 file changed, 3 insertions(+), 1 deletion(-) | ||
13 | |||
14 | diff --git a/python/qemu/machine/qtest.py b/python/qemu/machine/qtest.py | ||
15 | index XXXXXXX..XXXXXXX 100644 | ||
16 | --- a/python/qemu/machine/qtest.py | ||
17 | +++ b/python/qemu/machine/qtest.py | ||
18 | @@ -XXX,XX +XXX,XX @@ class QEMUQtestMachine(QEMUMachine): | ||
19 | def __init__(self, | ||
20 | binary: str, | ||
21 | args: Sequence[str] = (), | ||
22 | + wrapper: Sequence[str] = (), | ||
23 | name: Optional[str] = None, | ||
24 | base_temp_dir: str = "/var/tmp", | ||
25 | socket_scm_helper: Optional[str] = None, | ||
26 | @@ -XXX,XX +XXX,XX @@ def __init__(self, | ||
27 | name = "qemu-%d" % os.getpid() | ||
28 | if sock_dir is None: | ||
29 | sock_dir = base_temp_dir | ||
30 | - super().__init__(binary, args, name=name, base_temp_dir=base_temp_dir, | ||
31 | + super().__init__(binary, args, wrapper=wrapper, name=name, | ||
32 | + base_temp_dir=base_temp_dir, | ||
33 | socket_scm_helper=socket_scm_helper, | ||
34 | sock_dir=sock_dir, qmp_timer=qmp_timer) | ||
35 | self._qtest: Optional[QEMUQtestProtocol] = None | ||
36 | -- | ||
37 | 2.31.1 | ||
38 | |||
39 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
2 | 1 | ||
3 | Introduce the "Debugging a test case" section, in preparation | ||
4 | to the additional flags that will be added in the next patches. | ||
5 | |||
6 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
7 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
8 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
9 | Message-Id: <20210809090114.64834-5-eesposit@redhat.com> | ||
10 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
11 | --- | ||
12 | docs/devel/testing.rst | 8 ++++++++ | ||
13 | 1 file changed, 8 insertions(+) | ||
14 | |||
15 | diff --git a/docs/devel/testing.rst b/docs/devel/testing.rst | ||
16 | index XXXXXXX..XXXXXXX 100644 | ||
17 | --- a/docs/devel/testing.rst | ||
18 | +++ b/docs/devel/testing.rst | ||
19 | @@ -XXX,XX +XXX,XX @@ another application on the host may have locked the file, possibly leading to a | ||
20 | test failure. If using such devices are explicitly desired, consider adding | ||
21 | ``locking=off`` option to disable image locking. | ||
22 | |||
23 | +Debugging a test case | ||
24 | +----------------------- | ||
25 | +The following options to the ``check`` script can be useful when debugging | ||
26 | +a failing test: | ||
27 | + | ||
28 | +* ``-d`` (debug) just increases the logging verbosity, showing | ||
29 | + for example the QMP commands and answers. | ||
30 | + | ||
31 | Test case groups | ||
32 | ---------------- | ||
33 | |||
34 | -- | ||
35 | 2.31.1 | ||
36 | |||
37 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
2 | 1 | ||
3 | Define -gdb flag and GDB_OPTIONS environment variable | ||
4 | to python tests to attach a gdbserver to each qemu instance. | ||
5 | This patch only adds and parses this flag, it does not yet add | ||
6 | the implementation for it. | ||
7 | |||
8 | if -gdb is not provided but $GDB_OPTIONS is set, ignore the | ||
9 | environment variable. | ||
10 | |||
11 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
12 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
13 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
14 | Message-Id: <20210809090114.64834-6-eesposit@redhat.com> | ||
15 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
16 | --- | ||
17 | tests/qemu-iotests/check | 6 +++++- | ||
18 | tests/qemu-iotests/iotests.py | 5 +++++ | ||
19 | tests/qemu-iotests/testenv.py | 17 +++++++++++++++-- | ||
20 | 3 files changed, 25 insertions(+), 3 deletions(-) | ||
21 | |||
22 | diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check | ||
23 | index XXXXXXX..XXXXXXX 100755 | ||
24 | --- a/tests/qemu-iotests/check | ||
25 | +++ b/tests/qemu-iotests/check | ||
26 | @@ -XXX,XX +XXX,XX @@ def make_argparser() -> argparse.ArgumentParser: | ||
27 | help='pretty print output for make check') | ||
28 | |||
29 | p.add_argument('-d', dest='debug', action='store_true', help='debug') | ||
30 | + p.add_argument('-gdb', action='store_true', | ||
31 | + help="start gdbserver with $GDB_OPTIONS options \ | ||
32 | + ('localhost:12345' if $GDB_OPTIONS is empty)") | ||
33 | p.add_argument('-misalign', action='store_true', | ||
34 | help='misalign memory allocations') | ||
35 | p.add_argument('--color', choices=['on', 'off', 'auto'], | ||
36 | @@ -XXX,XX +XXX,XX @@ if __name__ == '__main__': | ||
37 | env = TestEnv(imgfmt=args.imgfmt, imgproto=args.imgproto, | ||
38 | aiomode=args.aiomode, cachemode=args.cachemode, | ||
39 | imgopts=args.imgopts, misalign=args.misalign, | ||
40 | - debug=args.debug, valgrind=args.valgrind) | ||
41 | + debug=args.debug, valgrind=args.valgrind, | ||
42 | + gdb=args.gdb) | ||
43 | |||
44 | if len(sys.argv) > 1 and sys.argv[-len(args.tests)-1] == '--': | ||
45 | if not args.tests: | ||
46 | diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py | ||
47 | index XXXXXXX..XXXXXXX 100644 | ||
48 | --- a/tests/qemu-iotests/iotests.py | ||
49 | +++ b/tests/qemu-iotests/iotests.py | ||
50 | @@ -XXX,XX +XXX,XX @@ | ||
51 | qemu_prog = os.environ.get('QEMU_PROG', 'qemu') | ||
52 | qemu_opts = os.environ.get('QEMU_OPTIONS', '').strip().split(' ') | ||
53 | |||
54 | +gdb_qemu_env = os.environ.get('GDB_OPTIONS') | ||
55 | +qemu_gdb = [] | ||
56 | +if gdb_qemu_env: | ||
57 | + qemu_gdb = ['gdbserver'] + gdb_qemu_env.strip().split(' ') | ||
58 | + | ||
59 | imgfmt = os.environ.get('IMGFMT', 'raw') | ||
60 | imgproto = os.environ.get('IMGPROTO', 'file') | ||
61 | output_dir = os.environ.get('OUTPUT_DIR', '.') | ||
62 | diff --git a/tests/qemu-iotests/testenv.py b/tests/qemu-iotests/testenv.py | ||
63 | index XXXXXXX..XXXXXXX 100644 | ||
64 | --- a/tests/qemu-iotests/testenv.py | ||
65 | +++ b/tests/qemu-iotests/testenv.py | ||
66 | @@ -XXX,XX +XXX,XX @@ | ||
67 | import glob | ||
68 | from typing import List, Dict, Any, Optional, ContextManager | ||
69 | |||
70 | +DEF_GDB_OPTIONS = 'localhost:12345' | ||
71 | |||
72 | def isxfile(path: str) -> bool: | ||
73 | return os.path.isfile(path) and os.access(path, os.X_OK) | ||
74 | @@ -XXX,XX +XXX,XX @@ class TestEnv(ContextManager['TestEnv']): | ||
75 | 'QEMU_NBD_OPTIONS', 'IMGOPTS', 'IMGFMT', 'IMGPROTO', | ||
76 | 'AIOMODE', 'CACHEMODE', 'VALGRIND_QEMU', | ||
77 | 'CACHEMODE_IS_DEFAULT', 'IMGFMT_GENERIC', 'IMGOPTSSYNTAX', | ||
78 | - 'IMGKEYSECRET', 'QEMU_DEFAULT_MACHINE', 'MALLOC_PERTURB_'] | ||
79 | + 'IMGKEYSECRET', 'QEMU_DEFAULT_MACHINE', 'MALLOC_PERTURB_', | ||
80 | + 'GDB_OPTIONS'] | ||
81 | |||
82 | def prepare_subprocess(self, args: List[str]) -> Dict[str, str]: | ||
83 | if self.debug: | ||
84 | @@ -XXX,XX +XXX,XX @@ def __init__(self, imgfmt: str, imgproto: str, aiomode: str, | ||
85 | imgopts: Optional[str] = None, | ||
86 | misalign: bool = False, | ||
87 | debug: bool = False, | ||
88 | - valgrind: bool = False) -> None: | ||
89 | + valgrind: bool = False, | ||
90 | + gdb: bool = False) -> None: | ||
91 | self.imgfmt = imgfmt | ||
92 | self.imgproto = imgproto | ||
93 | self.aiomode = aiomode | ||
94 | @@ -XXX,XX +XXX,XX @@ def __init__(self, imgfmt: str, imgproto: str, aiomode: str, | ||
95 | self.misalign = misalign | ||
96 | self.debug = debug | ||
97 | |||
98 | + if gdb: | ||
99 | + self.gdb_options = os.getenv('GDB_OPTIONS', DEF_GDB_OPTIONS) | ||
100 | + if not self.gdb_options: | ||
101 | + # cover the case 'export GDB_OPTIONS=' | ||
102 | + self.gdb_options = DEF_GDB_OPTIONS | ||
103 | + elif 'GDB_OPTIONS' in os.environ: | ||
104 | + # to not propagate it in prepare_subprocess() | ||
105 | + del os.environ['GDB_OPTIONS'] | ||
106 | + | ||
107 | if valgrind: | ||
108 | self.valgrind_qemu = 'y' | ||
109 | |||
110 | @@ -XXX,XX +XXX,XX @@ def print_env(self) -> None: | ||
111 | TEST_DIR -- {TEST_DIR} | ||
112 | SOCK_DIR -- {SOCK_DIR} | ||
113 | SOCKET_SCM_HELPER -- {SOCKET_SCM_HELPER} | ||
114 | +GDB_OPTIONS -- {GDB_OPTIONS} | ||
115 | """ | ||
116 | |||
117 | args = collections.defaultdict(str, self.get_env()) | ||
118 | -- | ||
119 | 2.31.1 | ||
120 | |||
121 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
2 | 1 | ||
3 | Attaching gdbserver implies that the qmp socket | ||
4 | should wait indefinitely for an answer from QEMU. | ||
5 | |||
6 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
7 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
8 | Message-Id: <20210809090114.64834-7-eesposit@redhat.com> | ||
9 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
10 | --- | ||
11 | tests/qemu-iotests/iotests.py | 6 +++++- | ||
12 | 1 file changed, 5 insertions(+), 1 deletion(-) | ||
13 | |||
14 | diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py | ||
15 | index XXXXXXX..XXXXXXX 100644 | ||
16 | --- a/tests/qemu-iotests/iotests.py | ||
17 | +++ b/tests/qemu-iotests/iotests.py | ||
18 | @@ -XXX,XX +XXX,XX @@ def __init__(self, seconds, errmsg="Timeout"): | ||
19 | self.seconds = seconds | ||
20 | self.errmsg = errmsg | ||
21 | def __enter__(self): | ||
22 | + if qemu_gdb: | ||
23 | + return self | ||
24 | signal.signal(signal.SIGALRM, self.timeout) | ||
25 | signal.setitimer(signal.ITIMER_REAL, self.seconds) | ||
26 | return self | ||
27 | def __exit__(self, exc_type, value, traceback): | ||
28 | + if qemu_gdb: | ||
29 | + return False | ||
30 | signal.setitimer(signal.ITIMER_REAL, 0) | ||
31 | return False | ||
32 | def timeout(self, signum, frame): | ||
33 | @@ -XXX,XX +XXX,XX @@ class VM(qtest.QEMUQtestMachine): | ||
34 | |||
35 | def __init__(self, path_suffix=''): | ||
36 | name = "qemu%s-%d" % (path_suffix, os.getpid()) | ||
37 | - timer = 15.0 | ||
38 | + timer = 15.0 if not qemu_gdb else None | ||
39 | super().__init__(qemu_prog, qemu_opts, name=name, | ||
40 | base_temp_dir=test_dir, | ||
41 | socket_scm_helper=socket_scm_helper, | ||
42 | -- | ||
43 | 2.31.1 | ||
44 | |||
45 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
2 | 1 | ||
3 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
4 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
5 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
6 | Message-Id: <20210809090114.64834-8-eesposit@redhat.com> | ||
7 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
8 | --- | ||
9 | tests/qemu-iotests/iotests.py | 3 ++- | ||
10 | 1 file changed, 2 insertions(+), 1 deletion(-) | ||
11 | |||
12 | diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py | ||
13 | index XXXXXXX..XXXXXXX 100644 | ||
14 | --- a/tests/qemu-iotests/iotests.py | ||
15 | +++ b/tests/qemu-iotests/iotests.py | ||
16 | @@ -XXX,XX +XXX,XX @@ class VM(qtest.QEMUQtestMachine): | ||
17 | def __init__(self, path_suffix=''): | ||
18 | name = "qemu%s-%d" % (path_suffix, os.getpid()) | ||
19 | timer = 15.0 if not qemu_gdb else None | ||
20 | - super().__init__(qemu_prog, qemu_opts, name=name, | ||
21 | + super().__init__(qemu_prog, qemu_opts, wrapper=qemu_gdb, | ||
22 | + name=name, | ||
23 | base_temp_dir=test_dir, | ||
24 | socket_scm_helper=socket_scm_helper, | ||
25 | sock_dir=sock_dir, qmp_timer=timer) | ||
26 | -- | ||
27 | 2.31.1 | ||
28 | |||
29 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
2 | 1 | ||
3 | Remove read timer in test script when GDB_OPTIONS are set, | ||
4 | so that the bash tests won't timeout while running gdb. | ||
5 | |||
6 | The only limitation here is that running a script with gdbserver | ||
7 | will make the test output mismatch with the expected | ||
8 | results, making the test fail. | ||
9 | |||
10 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
11 | Message-Id: <20210809090114.64834-9-eesposit@redhat.com> | ||
12 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
13 | --- | ||
14 | tests/qemu-iotests/common.qemu | 7 ++++++- | ||
15 | tests/qemu-iotests/common.rc | 8 +++++++- | ||
16 | 2 files changed, 13 insertions(+), 2 deletions(-) | ||
17 | |||
18 | diff --git a/tests/qemu-iotests/common.qemu b/tests/qemu-iotests/common.qemu | ||
19 | index XXXXXXX..XXXXXXX 100644 | ||
20 | --- a/tests/qemu-iotests/common.qemu | ||
21 | +++ b/tests/qemu-iotests/common.qemu | ||
22 | @@ -XXX,XX +XXX,XX @@ _timed_wait_for() | ||
23 | timeout=yes | ||
24 | |||
25 | QEMU_STATUS[$h]=0 | ||
26 | - while IFS= read -t ${QEMU_COMM_TIMEOUT} resp <&${QEMU_OUT[$h]} | ||
27 | + read_timeout="-t ${QEMU_COMM_TIMEOUT}" | ||
28 | + if [ -n "${GDB_OPTIONS}" ]; then | ||
29 | + read_timeout= | ||
30 | + fi | ||
31 | + | ||
32 | + while IFS= read ${read_timeout} resp <&${QEMU_OUT[$h]} | ||
33 | do | ||
34 | if [ -n "$capture_events" ]; then | ||
35 | capture=0 | ||
36 | diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc | ||
37 | index XXXXXXX..XXXXXXX 100644 | ||
38 | --- a/tests/qemu-iotests/common.rc | ||
39 | +++ b/tests/qemu-iotests/common.rc | ||
40 | @@ -XXX,XX +XXX,XX @@ _qemu_wrapper() | ||
41 | if [ -n "${QEMU_NEED_PID}" ]; then | ||
42 | echo $BASHPID > "${QEMU_TEST_DIR}/qemu-${_QEMU_HANDLE}.pid" | ||
43 | fi | ||
44 | + | ||
45 | + GDB="" | ||
46 | + if [ -n "${GDB_OPTIONS}" ]; then | ||
47 | + GDB="gdbserver ${GDB_OPTIONS}" | ||
48 | + fi | ||
49 | + | ||
50 | VALGRIND_QEMU="${VALGRIND_QEMU_VM}" _qemu_proc_exec "${VALGRIND_LOGFILE}" \ | ||
51 | - "$QEMU_PROG" $QEMU_OPTIONS "$@" | ||
52 | + $GDB "$QEMU_PROG" $QEMU_OPTIONS "$@" | ||
53 | ) | ||
54 | RETVAL=$? | ||
55 | _qemu_proc_valgrind_log "${VALGRIND_LOGFILE}" $RETVAL | ||
56 | -- | ||
57 | 2.31.1 | ||
58 | |||
59 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
2 | 1 | ||
3 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
4 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
5 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
6 | Message-Id: <20210809090114.64834-10-eesposit@redhat.com> | ||
7 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
8 | --- | ||
9 | docs/devel/testing.rst | 11 +++++++++++ | ||
10 | 1 file changed, 11 insertions(+) | ||
11 | |||
12 | diff --git a/docs/devel/testing.rst b/docs/devel/testing.rst | ||
13 | index XXXXXXX..XXXXXXX 100644 | ||
14 | --- a/docs/devel/testing.rst | ||
15 | +++ b/docs/devel/testing.rst | ||
16 | @@ -XXX,XX +XXX,XX @@ Debugging a test case | ||
17 | The following options to the ``check`` script can be useful when debugging | ||
18 | a failing test: | ||
19 | |||
20 | +* ``-gdb`` wraps every QEMU invocation in a ``gdbserver``, which waits for a | ||
21 | + connection from a gdb client. The options given to ``gdbserver`` (e.g. the | ||
22 | + address on which to listen for connections) are taken from the ``$GDB_OPTIONS`` | ||
23 | + environment variable. By default (if ``$GDB_OPTIONS`` is empty), it listens on | ||
24 | + ``localhost:12345``. | ||
25 | + It is possible to connect to it for example with | ||
26 | + ``gdb -iex "target remote $addr"``, where ``$addr`` is the address | ||
27 | + ``gdbserver`` listens on. | ||
28 | + If the ``-gdb`` option is not used, ``$GDB_OPTIONS`` is ignored, | ||
29 | + regardless of whether it is set or not. | ||
30 | + | ||
31 | * ``-d`` (debug) just increases the logging verbosity, showing | ||
32 | for example the QMP commands and answers. | ||
33 | |||
34 | -- | ||
35 | 2.31.1 | ||
36 | |||
37 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
2 | 1 | ||
3 | Currently, the check script only parses the option and sets the | ||
4 | VALGRIND_QEMU environmental variable to "y". | ||
5 | Add another local python variable that prepares the command line, | ||
6 | identical to the one provided in the test scripts. | ||
7 | |||
8 | Because the python script does not know in advance the valgrind | ||
9 | PID to assign to the log file name, use the "%p" flag in valgrind | ||
10 | log file name that automatically puts the process PID at runtime. | ||
11 | |||
12 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
13 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
14 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
15 | Message-Id: <20210809090114.64834-11-eesposit@redhat.com> | ||
16 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
17 | --- | ||
18 | tests/qemu-iotests/check | 7 ++++--- | ||
19 | tests/qemu-iotests/iotests.py | 11 +++++++++++ | ||
20 | tests/qemu-iotests/testenv.py | 1 + | ||
21 | 3 files changed, 16 insertions(+), 3 deletions(-) | ||
22 | |||
23 | diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check | ||
24 | index XXXXXXX..XXXXXXX 100755 | ||
25 | --- a/tests/qemu-iotests/check | ||
26 | +++ b/tests/qemu-iotests/check | ||
27 | @@ -XXX,XX +XXX,XX @@ def make_argparser() -> argparse.ArgumentParser: | ||
28 | p.add_argument('-gdb', action='store_true', | ||
29 | help="start gdbserver with $GDB_OPTIONS options \ | ||
30 | ('localhost:12345' if $GDB_OPTIONS is empty)") | ||
31 | + p.add_argument('-valgrind', action='store_true', | ||
32 | + help='use valgrind, sets VALGRIND_QEMU environment ' | ||
33 | + 'variable') | ||
34 | + | ||
35 | p.add_argument('-misalign', action='store_true', | ||
36 | help='misalign memory allocations') | ||
37 | p.add_argument('--color', choices=['on', 'off', 'auto'], | ||
38 | @@ -XXX,XX +XXX,XX @@ def make_argparser() -> argparse.ArgumentParser: | ||
39 | g_bash.add_argument('-o', dest='imgopts', | ||
40 | help='options to pass to qemu-img create/convert, ' | ||
41 | 'sets IMGOPTS environment variable') | ||
42 | - g_bash.add_argument('-valgrind', action='store_true', | ||
43 | - help='use valgrind, sets VALGRIND_QEMU environment ' | ||
44 | - 'variable') | ||
45 | |||
46 | g_sel = p.add_argument_group('test selecting options', | ||
47 | 'The following options specify test set ' | ||
48 | diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py | ||
49 | index XXXXXXX..XXXXXXX 100644 | ||
50 | --- a/tests/qemu-iotests/iotests.py | ||
51 | +++ b/tests/qemu-iotests/iotests.py | ||
52 | @@ -XXX,XX +XXX,XX @@ | ||
53 | sys.stderr.write('Please run this test via the "check" script\n') | ||
54 | sys.exit(os.EX_USAGE) | ||
55 | |||
56 | +qemu_valgrind = [] | ||
57 | +if os.environ.get('VALGRIND_QEMU') == "y" and \ | ||
58 | + os.environ.get('NO_VALGRIND') != "y": | ||
59 | + valgrind_logfile = "--log-file=" + test_dir | ||
60 | + # %p allows to put the valgrind process PID, since | ||
61 | + # we don't know it a priori (subprocess.Popen is | ||
62 | + # not yet invoked) | ||
63 | + valgrind_logfile += "/%p.valgrind" | ||
64 | + | ||
65 | + qemu_valgrind = ['valgrind', valgrind_logfile, '--error-exitcode=99'] | ||
66 | + | ||
67 | socket_scm_helper = os.environ.get('SOCKET_SCM_HELPER', 'socket_scm_helper') | ||
68 | |||
69 | luks_default_secret_object = 'secret,id=keysec0,data=' + \ | ||
70 | diff --git a/tests/qemu-iotests/testenv.py b/tests/qemu-iotests/testenv.py | ||
71 | index XXXXXXX..XXXXXXX 100644 | ||
72 | --- a/tests/qemu-iotests/testenv.py | ||
73 | +++ b/tests/qemu-iotests/testenv.py | ||
74 | @@ -XXX,XX +XXX,XX @@ def print_env(self) -> None: | ||
75 | SOCK_DIR -- {SOCK_DIR} | ||
76 | SOCKET_SCM_HELPER -- {SOCKET_SCM_HELPER} | ||
77 | GDB_OPTIONS -- {GDB_OPTIONS} | ||
78 | +VALGRIND_QEMU -- {VALGRIND_QEMU} | ||
79 | """ | ||
80 | |||
81 | args = collections.defaultdict(str, self.get_env()) | ||
82 | -- | ||
83 | 2.31.1 | ||
84 | |||
85 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
2 | 1 | ||
3 | As with gdbserver, valgrind delays the test execution, so | ||
4 | the default QMP socket timeout and the generic class | ||
5 | Timeout in iotests.py timeouts too soon. | ||
6 | |||
7 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
8 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
9 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
10 | Message-Id: <20210809090114.64834-12-eesposit@redhat.com> | ||
11 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
12 | --- | ||
13 | tests/qemu-iotests/iotests.py | 6 +++--- | ||
14 | 1 file changed, 3 insertions(+), 3 deletions(-) | ||
15 | |||
16 | diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py | ||
17 | index XXXXXXX..XXXXXXX 100644 | ||
18 | --- a/tests/qemu-iotests/iotests.py | ||
19 | +++ b/tests/qemu-iotests/iotests.py | ||
20 | @@ -XXX,XX +XXX,XX @@ def __init__(self, seconds, errmsg="Timeout"): | ||
21 | self.seconds = seconds | ||
22 | self.errmsg = errmsg | ||
23 | def __enter__(self): | ||
24 | - if qemu_gdb: | ||
25 | + if qemu_gdb or qemu_valgrind: | ||
26 | return self | ||
27 | signal.signal(signal.SIGALRM, self.timeout) | ||
28 | signal.setitimer(signal.ITIMER_REAL, self.seconds) | ||
29 | return self | ||
30 | def __exit__(self, exc_type, value, traceback): | ||
31 | - if qemu_gdb: | ||
32 | + if qemu_gdb or qemu_valgrind: | ||
33 | return False | ||
34 | signal.setitimer(signal.ITIMER_REAL, 0) | ||
35 | return False | ||
36 | @@ -XXX,XX +XXX,XX @@ class VM(qtest.QEMUQtestMachine): | ||
37 | |||
38 | def __init__(self, path_suffix=''): | ||
39 | name = "qemu%s-%d" % (path_suffix, os.getpid()) | ||
40 | - timer = 15.0 if not qemu_gdb else None | ||
41 | + timer = 15.0 if not (qemu_gdb or qemu_valgrind) else None | ||
42 | super().__init__(qemu_prog, qemu_opts, wrapper=qemu_gdb, | ||
43 | name=name, | ||
44 | base_temp_dir=test_dir, | ||
45 | -- | ||
46 | 2.31.1 | ||
47 | |||
48 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
2 | 1 | ||
3 | When using -valgrind on the script tests, it generates a log file | ||
4 | in $TEST_DIR that is either read (if valgrind finds problems) or | ||
5 | otherwise deleted. Provide the same exact behavior when using | ||
6 | -valgrind on the python tests. | ||
7 | |||
8 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
9 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
10 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
11 | Message-Id: <20210809090114.64834-13-eesposit@redhat.com> | ||
12 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
13 | --- | ||
14 | tests/qemu-iotests/iotests.py | 11 +++++++++++ | ||
15 | 1 file changed, 11 insertions(+) | ||
16 | |||
17 | diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py | ||
18 | index XXXXXXX..XXXXXXX 100644 | ||
19 | --- a/tests/qemu-iotests/iotests.py | ||
20 | +++ b/tests/qemu-iotests/iotests.py | ||
21 | @@ -XXX,XX +XXX,XX @@ def __init__(self, path_suffix=''): | ||
22 | sock_dir=sock_dir, qmp_timer=timer) | ||
23 | self._num_drives = 0 | ||
24 | |||
25 | + def _post_shutdown(self) -> None: | ||
26 | + super()._post_shutdown() | ||
27 | + if not qemu_valgrind or not self._popen: | ||
28 | + return | ||
29 | + valgrind_filename = f"{test_dir}/{self._popen.pid}.valgrind" | ||
30 | + if self.exitcode() == 99: | ||
31 | + with open(valgrind_filename) as f: | ||
32 | + print(f.read()) | ||
33 | + else: | ||
34 | + os.remove(valgrind_filename) | ||
35 | + | ||
36 | def add_object(self, opts): | ||
37 | self._args.append('-object') | ||
38 | self._args.append(opts) | ||
39 | -- | ||
40 | 2.31.1 | ||
41 | |||
42 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
2 | 1 | ||
3 | If -gdb and -valgrind are both defined, return an error. | ||
4 | |||
5 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
6 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
7 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
8 | Message-Id: <20210809090114.64834-14-eesposit@redhat.com> | ||
9 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
10 | --- | ||
11 | tests/qemu-iotests/iotests.py | 6 +++++- | ||
12 | 1 file changed, 5 insertions(+), 1 deletion(-) | ||
13 | |||
14 | diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py | ||
15 | index XXXXXXX..XXXXXXX 100644 | ||
16 | --- a/tests/qemu-iotests/iotests.py | ||
17 | +++ b/tests/qemu-iotests/iotests.py | ||
18 | @@ -XXX,XX +XXX,XX @@ class VM(qtest.QEMUQtestMachine): | ||
19 | def __init__(self, path_suffix=''): | ||
20 | name = "qemu%s-%d" % (path_suffix, os.getpid()) | ||
21 | timer = 15.0 if not (qemu_gdb or qemu_valgrind) else None | ||
22 | - super().__init__(qemu_prog, qemu_opts, wrapper=qemu_gdb, | ||
23 | + if qemu_gdb and qemu_valgrind: | ||
24 | + sys.stderr.write('gdb and valgrind are mutually exclusive\n') | ||
25 | + sys.exit(1) | ||
26 | + wrapper = qemu_gdb if qemu_gdb else qemu_valgrind | ||
27 | + super().__init__(qemu_prog, qemu_opts, wrapper=wrapper, | ||
28 | name=name, | ||
29 | base_temp_dir=test_dir, | ||
30 | socket_scm_helper=socket_scm_helper, | ||
31 | -- | ||
32 | 2.31.1 | ||
33 | |||
34 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
2 | 1 | ||
3 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
4 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
5 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
6 | Message-Id: <20210809090114.64834-15-eesposit@redhat.com> | ||
7 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
8 | --- | ||
9 | docs/devel/testing.rst | 6 ++++++ | ||
10 | 1 file changed, 6 insertions(+) | ||
11 | |||
12 | diff --git a/docs/devel/testing.rst b/docs/devel/testing.rst | ||
13 | index XXXXXXX..XXXXXXX 100644 | ||
14 | --- a/docs/devel/testing.rst | ||
15 | +++ b/docs/devel/testing.rst | ||
16 | @@ -XXX,XX +XXX,XX @@ a failing test: | ||
17 | If the ``-gdb`` option is not used, ``$GDB_OPTIONS`` is ignored, | ||
18 | regardless of whether it is set or not. | ||
19 | |||
20 | +* ``-valgrind`` attaches a valgrind instance to QEMU. If it detects | ||
21 | + warnings, it will print and save the log in | ||
22 | + ``$TEST_DIR/<valgrind_pid>.valgrind``. | ||
23 | + The final command line will be ``valgrind --log-file=$TEST_DIR/ | ||
24 | + <valgrind_pid>.valgrind --error-exitcode=99 $QEMU ...`` | ||
25 | + | ||
26 | * ``-d`` (debug) just increases the logging verbosity, showing | ||
27 | for example the QMP commands and answers. | ||
28 | |||
29 | -- | ||
30 | 2.31.1 | ||
31 | |||
32 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
2 | 1 | ||
3 | Using the flag -p, allow the qemu binary to print to stdout. | ||
4 | |||
5 | Also create the common function _close_qemu_log_file() to | ||
6 | avoid accessing machine.py private fields directly and have | ||
7 | duplicate code. | ||
8 | |||
9 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
10 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
11 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
12 | Message-Id: <20210809090114.64834-16-eesposit@redhat.com> | ||
13 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
14 | --- | ||
15 | python/qemu/machine/machine.py | 9 ++++++--- | ||
16 | tests/qemu-iotests/check | 4 +++- | ||
17 | tests/qemu-iotests/iotests.py | 8 ++++++++ | ||
18 | tests/qemu-iotests/testenv.py | 9 +++++++-- | ||
19 | 4 files changed, 24 insertions(+), 6 deletions(-) | ||
20 | |||
21 | diff --git a/python/qemu/machine/machine.py b/python/qemu/machine/machine.py | ||
22 | index XXXXXXX..XXXXXXX 100644 | ||
23 | --- a/python/qemu/machine/machine.py | ||
24 | +++ b/python/qemu/machine/machine.py | ||
25 | @@ -XXX,XX +XXX,XX @@ def _post_launch(self) -> None: | ||
26 | if self._qmp_connection: | ||
27 | self._qmp.accept(self._qmp_timer) | ||
28 | |||
29 | + def _close_qemu_log_file(self) -> None: | ||
30 | + if self._qemu_log_file is not None: | ||
31 | + self._qemu_log_file.close() | ||
32 | + self._qemu_log_file = None | ||
33 | + | ||
34 | def _post_shutdown(self) -> None: | ||
35 | """ | ||
36 | Called to cleanup the VM instance after the process has exited. | ||
37 | @@ -XXX,XX +XXX,XX @@ def _post_shutdown(self) -> None: | ||
38 | self._qmp.close() | ||
39 | self._qmp_connection = None | ||
40 | |||
41 | - if self._qemu_log_file is not None: | ||
42 | - self._qemu_log_file.close() | ||
43 | - self._qemu_log_file = None | ||
44 | + self._close_qemu_log_file() | ||
45 | |||
46 | self._load_io_log() | ||
47 | |||
48 | diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check | ||
49 | index XXXXXXX..XXXXXXX 100755 | ||
50 | --- a/tests/qemu-iotests/check | ||
51 | +++ b/tests/qemu-iotests/check | ||
52 | @@ -XXX,XX +XXX,XX @@ def make_argparser() -> argparse.ArgumentParser: | ||
53 | help='pretty print output for make check') | ||
54 | |||
55 | p.add_argument('-d', dest='debug', action='store_true', help='debug') | ||
56 | + p.add_argument('-p', dest='print', action='store_true', | ||
57 | + help='redirects qemu\'s stdout and stderr to the test output') | ||
58 | p.add_argument('-gdb', action='store_true', | ||
59 | help="start gdbserver with $GDB_OPTIONS options \ | ||
60 | ('localhost:12345' if $GDB_OPTIONS is empty)") | ||
61 | @@ -XXX,XX +XXX,XX @@ if __name__ == '__main__': | ||
62 | aiomode=args.aiomode, cachemode=args.cachemode, | ||
63 | imgopts=args.imgopts, misalign=args.misalign, | ||
64 | debug=args.debug, valgrind=args.valgrind, | ||
65 | - gdb=args.gdb) | ||
66 | + gdb=args.gdb, qprint=args.print) | ||
67 | |||
68 | if len(sys.argv) > 1 and sys.argv[-len(args.tests)-1] == '--': | ||
69 | if not args.tests: | ||
70 | diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py | ||
71 | index XXXXXXX..XXXXXXX 100644 | ||
72 | --- a/tests/qemu-iotests/iotests.py | ||
73 | +++ b/tests/qemu-iotests/iotests.py | ||
74 | @@ -XXX,XX +XXX,XX @@ | ||
75 | if gdb_qemu_env: | ||
76 | qemu_gdb = ['gdbserver'] + gdb_qemu_env.strip().split(' ') | ||
77 | |||
78 | +qemu_print = os.environ.get('PRINT_QEMU', False) | ||
79 | + | ||
80 | imgfmt = os.environ.get('IMGFMT', 'raw') | ||
81 | imgproto = os.environ.get('IMGPROTO', 'file') | ||
82 | output_dir = os.environ.get('OUTPUT_DIR', '.') | ||
83 | @@ -XXX,XX +XXX,XX @@ def _post_shutdown(self) -> None: | ||
84 | else: | ||
85 | os.remove(valgrind_filename) | ||
86 | |||
87 | + def _pre_launch(self) -> None: | ||
88 | + super()._pre_launch() | ||
89 | + if qemu_print: | ||
90 | + # set QEMU binary output to stdout | ||
91 | + self._close_qemu_log_file() | ||
92 | + | ||
93 | def add_object(self, opts): | ||
94 | self._args.append('-object') | ||
95 | self._args.append(opts) | ||
96 | diff --git a/tests/qemu-iotests/testenv.py b/tests/qemu-iotests/testenv.py | ||
97 | index XXXXXXX..XXXXXXX 100644 | ||
98 | --- a/tests/qemu-iotests/testenv.py | ||
99 | +++ b/tests/qemu-iotests/testenv.py | ||
100 | @@ -XXX,XX +XXX,XX @@ class TestEnv(ContextManager['TestEnv']): | ||
101 | 'AIOMODE', 'CACHEMODE', 'VALGRIND_QEMU', | ||
102 | 'CACHEMODE_IS_DEFAULT', 'IMGFMT_GENERIC', 'IMGOPTSSYNTAX', | ||
103 | 'IMGKEYSECRET', 'QEMU_DEFAULT_MACHINE', 'MALLOC_PERTURB_', | ||
104 | - 'GDB_OPTIONS'] | ||
105 | + 'GDB_OPTIONS', 'PRINT_QEMU'] | ||
106 | |||
107 | def prepare_subprocess(self, args: List[str]) -> Dict[str, str]: | ||
108 | if self.debug: | ||
109 | @@ -XXX,XX +XXX,XX @@ def __init__(self, imgfmt: str, imgproto: str, aiomode: str, | ||
110 | misalign: bool = False, | ||
111 | debug: bool = False, | ||
112 | valgrind: bool = False, | ||
113 | - gdb: bool = False) -> None: | ||
114 | + gdb: bool = False, | ||
115 | + qprint: bool = False) -> None: | ||
116 | self.imgfmt = imgfmt | ||
117 | self.imgproto = imgproto | ||
118 | self.aiomode = aiomode | ||
119 | @@ -XXX,XX +XXX,XX @@ def __init__(self, imgfmt: str, imgproto: str, aiomode: str, | ||
120 | self.misalign = misalign | ||
121 | self.debug = debug | ||
122 | |||
123 | + if qprint: | ||
124 | + self.print_qemu = 'y' | ||
125 | + | ||
126 | if gdb: | ||
127 | self.gdb_options = os.getenv('GDB_OPTIONS', DEF_GDB_OPTIONS) | ||
128 | if not self.gdb_options: | ||
129 | @@ -XXX,XX +XXX,XX @@ def print_env(self) -> None: | ||
130 | SOCKET_SCM_HELPER -- {SOCKET_SCM_HELPER} | ||
131 | GDB_OPTIONS -- {GDB_OPTIONS} | ||
132 | VALGRIND_QEMU -- {VALGRIND_QEMU} | ||
133 | +PRINT_QEMU_OUTPUT -- {PRINT_QEMU} | ||
134 | """ | ||
135 | |||
136 | args = collections.defaultdict(str, self.get_env()) | ||
137 | -- | ||
138 | 2.31.1 | ||
139 | |||
140 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
2 | 1 | ||
3 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
4 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
5 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
6 | Message-Id: <20210809090114.64834-17-eesposit@redhat.com> | ||
7 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
8 | --- | ||
9 | docs/devel/testing.rst | 4 ++++ | ||
10 | 1 file changed, 4 insertions(+) | ||
11 | |||
12 | diff --git a/docs/devel/testing.rst b/docs/devel/testing.rst | ||
13 | index XXXXXXX..XXXXXXX 100644 | ||
14 | --- a/docs/devel/testing.rst | ||
15 | +++ b/docs/devel/testing.rst | ||
16 | @@ -XXX,XX +XXX,XX @@ a failing test: | ||
17 | * ``-d`` (debug) just increases the logging verbosity, showing | ||
18 | for example the QMP commands and answers. | ||
19 | |||
20 | +* ``-p`` (print) redirects QEMU’s stdout and stderr to the test output, | ||
21 | + instead of saving it into a log file in | ||
22 | + ``$TEST_DIR/qemu-machine-<random_string>``. | ||
23 | + | ||
24 | Test case groups | ||
25 | ---------------- | ||
26 | |||
27 | -- | ||
28 | 2.31.1 | ||
29 | |||
30 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Mao Zhongyi <maozhongyi@cmss.chinamobile.com> | ||
2 | 1 | ||
3 | Signed-off-by: Mao Zhongyi <maozhongyi@cmss.chinamobile.com> | ||
4 | Message-Id: <20210802062507.347555-1-maozhongyi@cmss.chinamobile.com> | ||
5 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
6 | --- | ||
7 | block/monitor/block-hmp-cmds.c | 12 ++++++------ | ||
8 | 1 file changed, 6 insertions(+), 6 deletions(-) | ||
9 | |||
10 | diff --git a/block/monitor/block-hmp-cmds.c b/block/monitor/block-hmp-cmds.c | ||
11 | index XXXXXXX..XXXXXXX 100644 | ||
12 | --- a/block/monitor/block-hmp-cmds.c | ||
13 | +++ b/block/monitor/block-hmp-cmds.c | ||
14 | @@ -XXX,XX +XXX,XX @@ void hmp_drive_mirror(Monitor *mon, const QDict *qdict) | ||
15 | |||
16 | if (!filename) { | ||
17 | error_setg(&err, QERR_MISSING_PARAMETER, "target"); | ||
18 | - hmp_handle_error(mon, err); | ||
19 | - return; | ||
20 | + goto end; | ||
21 | } | ||
22 | qmp_drive_mirror(&mirror, &err); | ||
23 | +end: | ||
24 | hmp_handle_error(mon, err); | ||
25 | } | ||
26 | |||
27 | @@ -XXX,XX +XXX,XX @@ void hmp_drive_backup(Monitor *mon, const QDict *qdict) | ||
28 | |||
29 | if (!filename) { | ||
30 | error_setg(&err, QERR_MISSING_PARAMETER, "target"); | ||
31 | - hmp_handle_error(mon, err); | ||
32 | - return; | ||
33 | + goto end; | ||
34 | } | ||
35 | |||
36 | qmp_drive_backup(&backup, &err); | ||
37 | +end: | ||
38 | hmp_handle_error(mon, err); | ||
39 | } | ||
40 | |||
41 | @@ -XXX,XX +XXX,XX @@ void hmp_snapshot_blkdev(Monitor *mon, const QDict *qdict) | ||
42 | * will be taken internally. Today it's actually required. | ||
43 | */ | ||
44 | error_setg(&err, QERR_MISSING_PARAMETER, "snapshot-file"); | ||
45 | - hmp_handle_error(mon, err); | ||
46 | - return; | ||
47 | + goto end; | ||
48 | } | ||
49 | |||
50 | mode = reuse ? NEW_IMAGE_MODE_EXISTING : NEW_IMAGE_MODE_ABSOLUTE_PATHS; | ||
51 | @@ -XXX,XX +XXX,XX @@ void hmp_snapshot_blkdev(Monitor *mon, const QDict *qdict) | ||
52 | filename, false, NULL, | ||
53 | !!format, format, | ||
54 | true, mode, &err); | ||
55 | +end: | ||
56 | hmp_handle_error(mon, err); | ||
57 | } | ||
58 | |||
59 | -- | ||
60 | 2.31.1 | ||
61 | |||
62 | diff view generated by jsdifflib |
1 | From: Fabrice Fontaine <fontaine.fabrice@gmail.com> | 1 | From: Sam Li <faithilikerun@gmail.com> |
---|---|---|---|
2 | 2 | ||
3 | Include linux/fs.h to avoid the following build failure on uclibc or | 3 | Signed-off-by: Sam Li <faithilikerun@gmail.com> |
4 | musl raised since version 6.0.0: | 4 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> |
5 | Reviewed-by: Damien Le Moal <damien.lemoal@opensource.wdc.com> | ||
6 | Reviewed-by: Hannes Reinecke <hare@suse.de> | ||
7 | Reviewed-by: Dmitry Fomichev <dmitry.fomichev@wdc.com> | ||
8 | Acked-by: Kevin Wolf <kwolf@redhat.com> | ||
9 | Message-id: 20230324090605.28361-2-faithilikerun@gmail.com | ||
10 | [Adjust commit message prefix as suggested by Philippe Mathieu-Daudé | ||
11 | <philmd@linaro.org>. | ||
12 | --Stefan] | ||
13 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
14 | --- | ||
15 | include/block/block-common.h | 43 ++++++++++++++++++++++++++++++++++++ | ||
16 | 1 file changed, 43 insertions(+) | ||
5 | 17 | ||
6 | ../block/export/fuse.c: In function 'fuse_lseek': | 18 | diff --git a/include/block/block-common.h b/include/block/block-common.h |
7 | ../block/export/fuse.c:641:19: error: 'SEEK_HOLE' undeclared (first use in this function) | ||
8 | 641 | if (whence != SEEK_HOLE && whence != SEEK_DATA) { | ||
9 | | ^~~~~~~~~ | ||
10 | ../block/export/fuse.c:641:19: note: each undeclared identifier is reported only once for each function it appears in | ||
11 | ../block/export/fuse.c:641:42: error: 'SEEK_DATA' undeclared (first use in this function); did you mean 'SEEK_SET'? | ||
12 | 641 | if (whence != SEEK_HOLE && whence != SEEK_DATA) { | ||
13 | | ^~~~~~~~~ | ||
14 | | SEEK_SET | ||
15 | |||
16 | Fixes: | ||
17 | - http://autobuild.buildroot.org/results/33c90ebf04997f4d3557cfa66abc9cf9a3076137 | ||
18 | |||
19 | Signed-off-by: Fabrice Fontaine <fontaine.fabrice@gmail.com> | ||
20 | Message-Id: <20210827220301.272887-1-fontaine.fabrice@gmail.com> | ||
21 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
22 | --- | ||
23 | block/export/fuse.c | 3 +++ | ||
24 | 1 file changed, 3 insertions(+) | ||
25 | |||
26 | diff --git a/block/export/fuse.c b/block/export/fuse.c | ||
27 | index XXXXXXX..XXXXXXX 100644 | 19 | index XXXXXXX..XXXXXXX 100644 |
28 | --- a/block/export/fuse.c | 20 | --- a/include/block/block-common.h |
29 | +++ b/block/export/fuse.c | 21 | +++ b/include/block/block-common.h |
30 | @@ -XXX,XX +XXX,XX @@ | 22 | @@ -XXX,XX +XXX,XX @@ typedef struct BlockDriver BlockDriver; |
31 | #include <fuse.h> | 23 | typedef struct BdrvChild BdrvChild; |
32 | #include <fuse_lowlevel.h> | 24 | typedef struct BdrvChildClass BdrvChildClass; |
33 | 25 | ||
34 | +#ifdef __linux__ | 26 | +typedef enum BlockZoneOp { |
35 | +#include <linux/fs.h> | 27 | + BLK_ZO_OPEN, |
36 | +#endif | 28 | + BLK_ZO_CLOSE, |
37 | 29 | + BLK_ZO_FINISH, | |
38 | /* Prevent overly long bounce buffer allocations */ | 30 | + BLK_ZO_RESET, |
39 | #define FUSE_MAX_BOUNCE_BYTES (MIN(BDRV_REQUEST_MAX_BYTES, 64 * 1024 * 1024)) | 31 | +} BlockZoneOp; |
32 | + | ||
33 | +typedef enum BlockZoneModel { | ||
34 | + BLK_Z_NONE = 0x0, /* Regular block device */ | ||
35 | + BLK_Z_HM = 0x1, /* Host-managed zoned block device */ | ||
36 | + BLK_Z_HA = 0x2, /* Host-aware zoned block device */ | ||
37 | +} BlockZoneModel; | ||
38 | + | ||
39 | +typedef enum BlockZoneState { | ||
40 | + BLK_ZS_NOT_WP = 0x0, | ||
41 | + BLK_ZS_EMPTY = 0x1, | ||
42 | + BLK_ZS_IOPEN = 0x2, | ||
43 | + BLK_ZS_EOPEN = 0x3, | ||
44 | + BLK_ZS_CLOSED = 0x4, | ||
45 | + BLK_ZS_RDONLY = 0xD, | ||
46 | + BLK_ZS_FULL = 0xE, | ||
47 | + BLK_ZS_OFFLINE = 0xF, | ||
48 | +} BlockZoneState; | ||
49 | + | ||
50 | +typedef enum BlockZoneType { | ||
51 | + BLK_ZT_CONV = 0x1, /* Conventional random writes supported */ | ||
52 | + BLK_ZT_SWR = 0x2, /* Sequential writes required */ | ||
53 | + BLK_ZT_SWP = 0x3, /* Sequential writes preferred */ | ||
54 | +} BlockZoneType; | ||
55 | + | ||
56 | +/* | ||
57 | + * Zone descriptor data structure. | ||
58 | + * Provides information on a zone with all position and size values in bytes. | ||
59 | + */ | ||
60 | +typedef struct BlockZoneDescriptor { | ||
61 | + uint64_t start; | ||
62 | + uint64_t length; | ||
63 | + uint64_t cap; | ||
64 | + uint64_t wp; | ||
65 | + BlockZoneType type; | ||
66 | + BlockZoneState state; | ||
67 | +} BlockZoneDescriptor; | ||
68 | + | ||
69 | typedef struct BlockDriverInfo { | ||
70 | /* in bytes, 0 if irrelevant */ | ||
71 | int cluster_size; | ||
40 | -- | 72 | -- |
41 | 2.31.1 | 73 | 2.39.2 |
42 | 74 | ||
43 | 75 | diff view generated by jsdifflib |
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 1 | From: Sam Li <faithilikerun@gmail.com> |
---|---|---|---|
2 | 2 | ||
3 | Move part of bdrv_cbw_append() to new function cbw_open(). It's an | 3 | Use get_sysfs_str_val() to get the string value of device |
4 | intermediate step for adding normal .bdrv_open() handler to the | 4 | zoned model. Then get_sysfs_zoned_model() can convert it to |
5 | filter. With this commit no logic is changed, but we have a function | 5 | BlockZoneModel type of QEMU. |
6 | which will be turned into .bdrv_open() handler in future commit. | 6 | |
7 | 7 | Use get_sysfs_long_val() to get the long value of zoned device | |
8 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 8 | information. |
9 | Reviewed-by: Max Reitz <mreitz@redhat.com> | 9 | |
10 | Message-Id: <20210824083856.17408-15-vsementsov@virtuozzo.com> | 10 | Signed-off-by: Sam Li <faithilikerun@gmail.com> |
11 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | 11 | Reviewed-by: Hannes Reinecke <hare@suse.de> |
12 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
13 | Reviewed-by: Damien Le Moal <damien.lemoal@opensource.wdc.com> | ||
14 | Reviewed-by: Dmitry Fomichev <dmitry.fomichev@wdc.com> | ||
15 | Acked-by: Kevin Wolf <kwolf@redhat.com> | ||
16 | Message-id: 20230324090605.28361-3-faithilikerun@gmail.com | ||
17 | [Adjust commit message prefix as suggested by Philippe Mathieu-Daudé | ||
18 | <philmd@linaro.org>. | ||
19 | --Stefan] | ||
20 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
12 | --- | 21 | --- |
13 | block/copy-before-write.c | 69 +++++++++++++++++++++++---------------- | 22 | include/block/block_int-common.h | 3 + |
14 | 1 file changed, 41 insertions(+), 28 deletions(-) | 23 | block/file-posix.c | 130 ++++++++++++++++++++++--------- |
15 | 24 | 2 files changed, 95 insertions(+), 38 deletions(-) | |
16 | diff --git a/block/copy-before-write.c b/block/copy-before-write.c | 25 | |
26 | diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h | ||
17 | index XXXXXXX..XXXXXXX 100644 | 27 | index XXXXXXX..XXXXXXX 100644 |
18 | --- a/block/copy-before-write.c | 28 | --- a/include/block/block_int-common.h |
19 | +++ b/block/copy-before-write.c | 29 | +++ b/include/block/block_int-common.h |
20 | @@ -XXX,XX +XXX,XX @@ static void cbw_child_perm(BlockDriverState *bs, BdrvChild *c, | 30 | @@ -XXX,XX +XXX,XX @@ typedef struct BlockLimits { |
21 | } | 31 | * an explicit monitor command to load the disk inside the guest). |
32 | */ | ||
33 | bool has_variable_length; | ||
34 | + | ||
35 | + /* device zone model */ | ||
36 | + BlockZoneModel zoned; | ||
37 | } BlockLimits; | ||
38 | |||
39 | typedef struct BdrvOpBlocker BdrvOpBlocker; | ||
40 | diff --git a/block/file-posix.c b/block/file-posix.c | ||
41 | index XXXXXXX..XXXXXXX 100644 | ||
42 | --- a/block/file-posix.c | ||
43 | +++ b/block/file-posix.c | ||
44 | @@ -XXX,XX +XXX,XX @@ static int hdev_get_max_hw_transfer(int fd, struct stat *st) | ||
45 | #endif | ||
22 | } | 46 | } |
23 | 47 | ||
24 | +static int cbw_init(BlockDriverState *top, BlockDriverState *source, | 48 | -static int hdev_get_max_segments(int fd, struct stat *st) |
25 | + BlockDriverState *target, bool compress, Error **errp) | 49 | +/* |
50 | + * Get a sysfs attribute value as character string. | ||
51 | + */ | ||
52 | +static int get_sysfs_str_val(struct stat *st, const char *attribute, | ||
53 | + char **val) { | ||
54 | +#ifdef CONFIG_LINUX | ||
55 | + g_autofree char *sysfspath = NULL; | ||
56 | + int ret; | ||
57 | + size_t len; | ||
58 | + | ||
59 | + if (!S_ISBLK(st->st_mode)) { | ||
60 | + return -ENOTSUP; | ||
61 | + } | ||
62 | + | ||
63 | + sysfspath = g_strdup_printf("/sys/dev/block/%u:%u/queue/%s", | ||
64 | + major(st->st_rdev), minor(st->st_rdev), | ||
65 | + attribute); | ||
66 | + ret = g_file_get_contents(sysfspath, val, &len, NULL); | ||
67 | + if (ret == -1) { | ||
68 | + return -ENOENT; | ||
69 | + } | ||
70 | + | ||
71 | + /* The file is ended with '\n' */ | ||
72 | + char *p; | ||
73 | + p = *val; | ||
74 | + if (*(p + len - 1) == '\n') { | ||
75 | + *(p + len - 1) = '\0'; | ||
76 | + } | ||
77 | + return ret; | ||
78 | +#else | ||
79 | + return -ENOTSUP; | ||
80 | +#endif | ||
81 | +} | ||
82 | + | ||
83 | +static int get_sysfs_zoned_model(struct stat *st, BlockZoneModel *zoned) | ||
26 | +{ | 84 | +{ |
27 | + BDRVCopyBeforeWriteState *state = top->opaque; | 85 | + g_autofree char *val = NULL; |
28 | + | 86 | + int ret; |
29 | + top->total_sectors = source->total_sectors; | 87 | + |
30 | + top->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED | | 88 | + ret = get_sysfs_str_val(st, "zoned", &val); |
31 | + (BDRV_REQ_FUA & source->supported_write_flags); | 89 | + if (ret < 0) { |
32 | + top->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED | | 90 | + return ret; |
33 | + ((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK) & | 91 | + } |
34 | + source->supported_zero_flags); | 92 | + |
35 | + | 93 | + if (strcmp(val, "host-managed") == 0) { |
36 | + bdrv_ref(target); | 94 | + *zoned = BLK_Z_HM; |
37 | + state->target = bdrv_attach_child(top, target, "target", &child_of_bds, | 95 | + } else if (strcmp(val, "host-aware") == 0) { |
38 | + BDRV_CHILD_DATA, errp); | 96 | + *zoned = BLK_Z_HA; |
39 | + if (!state->target) { | 97 | + } else if (strcmp(val, "none") == 0) { |
40 | + error_prepend(errp, "Cannot attach target child: "); | 98 | + *zoned = BLK_Z_NONE; |
41 | + return -EINVAL; | 99 | + } else { |
42 | + } | 100 | + return -ENOTSUP; |
43 | + | 101 | + } |
44 | + bdrv_ref(source); | ||
45 | + top->file = bdrv_attach_child(top, source, "file", &child_of_bds, | ||
46 | + BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, | ||
47 | + errp); | ||
48 | + if (!top->file) { | ||
49 | + error_prepend(errp, "Cannot attach file child: "); | ||
50 | + return -EINVAL; | ||
51 | + } | ||
52 | + | ||
53 | + state->bcs = block_copy_state_new(top->file, state->target, false, compress, | ||
54 | + errp); | ||
55 | + if (!state->bcs) { | ||
56 | + error_prepend(errp, "Cannot create block-copy-state: "); | ||
57 | + return -EINVAL; | ||
58 | + } | ||
59 | + | ||
60 | + return 0; | 102 | + return 0; |
61 | +} | 103 | +} |
62 | + | 104 | + |
63 | BlockDriver bdrv_cbw_filter = { | 105 | +/* |
64 | .format_name = "copy-before-write", | 106 | + * Get a sysfs attribute value as a long integer. |
65 | .instance_size = sizeof(BDRVCopyBeforeWriteState), | 107 | + */ |
66 | @@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_cbw_append(BlockDriverState *source, | 108 | +static long get_sysfs_long_val(struct stat *st, const char *attribute) |
67 | error_prepend(errp, "Cannot open driver: "); | 109 | { |
68 | return NULL; | 110 | #ifdef CONFIG_LINUX |
111 | - char buf[32]; | ||
112 | + g_autofree char *str = NULL; | ||
113 | const char *end; | ||
114 | - char *sysfspath = NULL; | ||
115 | + long val; | ||
116 | + int ret; | ||
117 | + | ||
118 | + ret = get_sysfs_str_val(st, attribute, &str); | ||
119 | + if (ret < 0) { | ||
120 | + return ret; | ||
121 | + } | ||
122 | + | ||
123 | + /* The file is ended with '\n', pass 'end' to accept that. */ | ||
124 | + ret = qemu_strtol(str, &end, 10, &val); | ||
125 | + if (ret == 0 && end && *end == '\0') { | ||
126 | + ret = val; | ||
127 | + } | ||
128 | + return ret; | ||
129 | +#else | ||
130 | + return -ENOTSUP; | ||
131 | +#endif | ||
132 | +} | ||
133 | + | ||
134 | +static int hdev_get_max_segments(int fd, struct stat *st) | ||
135 | +{ | ||
136 | +#ifdef CONFIG_LINUX | ||
137 | int ret; | ||
138 | - int sysfd = -1; | ||
139 | - long max_segments; | ||
140 | |||
141 | if (S_ISCHR(st->st_mode)) { | ||
142 | if (ioctl(fd, SG_GET_SG_TABLESIZE, &ret) == 0) { | ||
143 | @@ -XXX,XX +XXX,XX @@ static int hdev_get_max_segments(int fd, struct stat *st) | ||
144 | } | ||
145 | return -ENOTSUP; | ||
69 | } | 146 | } |
70 | - | 147 | - |
71 | state = top->opaque; | 148 | - if (!S_ISBLK(st->st_mode)) { |
72 | - top->total_sectors = source->total_sectors; | 149 | - return -ENOTSUP; |
73 | - top->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED | | 150 | - } |
74 | - (BDRV_REQ_FUA & source->supported_write_flags); | ||
75 | - top->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED | | ||
76 | - ((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK) & | ||
77 | - source->supported_zero_flags); | ||
78 | - | 151 | - |
79 | - bdrv_ref(target); | 152 | - sysfspath = g_strdup_printf("/sys/dev/block/%u:%u/queue/max_segments", |
80 | - state->target = bdrv_attach_child(top, target, "target", &child_of_bds, | 153 | - major(st->st_rdev), minor(st->st_rdev)); |
81 | - BDRV_CHILD_DATA, errp); | 154 | - sysfd = open(sysfspath, O_RDONLY); |
82 | - if (!state->target) { | 155 | - if (sysfd == -1) { |
83 | - error_prepend(errp, "Cannot attach target child: "); | 156 | - ret = -errno; |
84 | - goto fail; | 157 | - goto out; |
85 | - } | 158 | - } |
86 | 159 | - ret = RETRY_ON_EINTR(read(sysfd, buf, sizeof(buf) - 1)); | |
87 | - bdrv_ref(source); | 160 | - if (ret < 0) { |
88 | - top->file = bdrv_attach_child(top, source, "file", &child_of_bds, | 161 | - ret = -errno; |
89 | - BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, | 162 | - goto out; |
90 | - errp); | 163 | - } else if (ret == 0) { |
91 | - if (!top->file) { | 164 | - ret = -EIO; |
92 | - error_prepend(errp, "Cannot attach file child: "); | 165 | - goto out; |
93 | - goto fail; | 166 | - } |
167 | - buf[ret] = 0; | ||
168 | - /* The file is ended with '\n', pass 'end' to accept that. */ | ||
169 | - ret = qemu_strtol(buf, &end, 10, &max_segments); | ||
170 | - if (ret == 0 && end && *end == '\n') { | ||
171 | - ret = max_segments; | ||
94 | - } | 172 | - } |
95 | - | 173 | - |
96 | - state->bcs = block_copy_state_new(top->file, state->target, false, compress, | 174 | -out: |
97 | - errp); | 175 | - if (sysfd != -1) { |
98 | - if (!state->bcs) { | 176 | - close(sysfd); |
99 | - error_prepend(errp, "Cannot create block-copy-state: "); | 177 | - } |
100 | + ret = cbw_init(top, source, target, compress, errp); | 178 | - g_free(sysfspath); |
179 | - return ret; | ||
180 | + return get_sysfs_long_val(st, "max_segments"); | ||
181 | #else | ||
182 | return -ENOTSUP; | ||
183 | #endif | ||
184 | @@ -XXX,XX +XXX,XX @@ static void raw_refresh_limits(BlockDriverState *bs, Error **errp) | ||
185 | { | ||
186 | BDRVRawState *s = bs->opaque; | ||
187 | struct stat st; | ||
188 | + int ret; | ||
189 | + BlockZoneModel zoned; | ||
190 | |||
191 | s->needs_alignment = raw_needs_alignment(bs); | ||
192 | raw_probe_alignment(bs, s->fd, errp); | ||
193 | @@ -XXX,XX +XXX,XX @@ static void raw_refresh_limits(BlockDriverState *bs, Error **errp) | ||
194 | bs->bl.max_hw_iov = ret; | ||
195 | } | ||
196 | } | ||
197 | + | ||
198 | + ret = get_sysfs_zoned_model(&st, &zoned); | ||
101 | + if (ret < 0) { | 199 | + if (ret < 0) { |
102 | goto fail; | 200 | + zoned = BLK_Z_NONE; |
103 | } | 201 | + } |
104 | 202 | + bs->bl.zoned = zoned; | |
203 | } | ||
204 | |||
205 | static int check_for_dasd(int fd) | ||
105 | -- | 206 | -- |
106 | 2.31.1 | 207 | 2.39.2 |
107 | 208 | ||
108 | 209 | diff view generated by jsdifflib |
1 | From: Viktor Prutyanov <viktor.prutyanov@phystech.edu> | 1 | From: Sam Li <faithilikerun@gmail.com> |
---|---|---|---|
2 | 2 | ||
3 | Make 'qemu-img commit' work on Windows. | 3 | Add zoned device option to host_device BlockDriver. It will be presented only |
4 | for zoned host block devices. By adding zone management operations to the | ||
5 | host_block_device BlockDriver, users can use the new block layer APIs | ||
6 | including Report Zone and four zone management operations | ||
7 | (open, close, finish, reset, reset_all). | ||
4 | 8 | ||
5 | Command 'commit' requires reopening backing file in RW mode. So, | 9 | Qemu-io uses the new APIs to perform zoned storage commands of the device: |
6 | add reopen prepare/commit/abort handlers and change dwShareMode | 10 | zone_report(zrp), zone_open(zo), zone_close(zc), zone_reset(zrs), |
7 | for CreateFile call in order to allow further read/write reopening. | 11 | zone_finish(zf). |
8 | 12 | ||
9 | Resolves: https://gitlab.com/qemu-project/qemu/-/issues/418 | 13 | For example, to test zone_report, use following command: |
14 | $ ./build/qemu-io --image-opts -n driver=host_device, filename=/dev/nullb0 | ||
15 | -c "zrp offset nr_zones" | ||
10 | 16 | ||
11 | Suggested-by: Hanna Reitz <hreitz@redhat.com> | 17 | Signed-off-by: Sam Li <faithilikerun@gmail.com> |
12 | Signed-off-by: Viktor Prutyanov <viktor.prutyanov@phystech.edu> | 18 | Reviewed-by: Hannes Reinecke <hare@suse.de> |
13 | Tested-by: Helge Konetzka <hk@zapateado.de> | 19 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> |
14 | Message-Id: <20210825173625.19415-1-viktor.prutyanov@phystech.edu> | 20 | Reviewed-by: Dmitry Fomichev <dmitry.fomichev@wdc.com> |
15 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | 21 | Acked-by: Kevin Wolf <kwolf@redhat.com> |
22 | Message-id: 20230324090605.28361-4-faithilikerun@gmail.com | ||
23 | [Adjust commit message prefix as suggested by Philippe Mathieu-Daudé | ||
24 | <philmd@linaro.org> and remove spurious ret = -errno in | ||
25 | raw_co_zone_mgmt(). | ||
26 | --Stefan] | ||
27 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
16 | --- | 28 | --- |
17 | block/file-win32.c | 101 ++++++++++++++++++++++++++++++++++++++++++++- | 29 | meson.build | 4 + |
18 | 1 file changed, 100 insertions(+), 1 deletion(-) | 30 | include/block/block-io.h | 9 + |
31 | include/block/block_int-common.h | 21 ++ | ||
32 | include/block/raw-aio.h | 6 +- | ||
33 | include/sysemu/block-backend-io.h | 18 ++ | ||
34 | block/block-backend.c | 133 +++++++++++++ | ||
35 | block/file-posix.c | 306 +++++++++++++++++++++++++++++- | ||
36 | block/io.c | 41 ++++ | ||
37 | qemu-io-cmds.c | 149 +++++++++++++++ | ||
38 | 9 files changed, 684 insertions(+), 3 deletions(-) | ||
19 | 39 | ||
20 | diff --git a/block/file-win32.c b/block/file-win32.c | 40 | diff --git a/meson.build b/meson.build |
21 | index XXXXXXX..XXXXXXX 100644 | 41 | index XXXXXXX..XXXXXXX 100644 |
22 | --- a/block/file-win32.c | 42 | --- a/meson.build |
23 | +++ b/block/file-win32.c | 43 | +++ b/meson.build |
24 | @@ -XXX,XX +XXX,XX @@ typedef struct BDRVRawState { | 44 | @@ -XXX,XX +XXX,XX @@ config_host_data.set('CONFIG_REPLICATION', get_option('replication').allowed()) |
25 | QEMUWin32AIOState *aio; | 45 | # has_header |
26 | } BDRVRawState; | 46 | config_host_data.set('CONFIG_EPOLL', cc.has_header('sys/epoll.h')) |
27 | 47 | config_host_data.set('CONFIG_LINUX_MAGIC_H', cc.has_header('linux/magic.h')) | |
28 | +typedef struct BDRVRawReopenState { | 48 | +config_host_data.set('CONFIG_BLKZONED', cc.has_header('linux/blkzoned.h')) |
29 | + HANDLE hfile; | 49 | config_host_data.set('CONFIG_VALGRIND_H', cc.has_header('valgrind/valgrind.h')) |
30 | +} BDRVRawReopenState; | 50 | config_host_data.set('HAVE_BTRFS_H', cc.has_header('linux/btrfs.h')) |
31 | + | 51 | config_host_data.set('HAVE_DRM_H', cc.has_header('libdrm/drm.h')) |
32 | /* | 52 | @@ -XXX,XX +XXX,XX @@ config_host_data.set('HAVE_SIGEV_NOTIFY_THREAD_ID', |
33 | * Read/writes the data to/from a given linear buffer. | 53 | config_host_data.set('HAVE_STRUCT_STAT_ST_ATIM', |
34 | * | 54 | cc.has_member('struct stat', 'st_atim', |
35 | @@ -XXX,XX +XXX,XX @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags, | 55 | prefix: '#include <sys/stat.h>')) |
56 | +config_host_data.set('HAVE_BLK_ZONE_REP_CAPACITY', | ||
57 | + cc.has_member('struct blk_zone', 'capacity', | ||
58 | + prefix: '#include <linux/blkzoned.h>')) | ||
59 | |||
60 | # has_type | ||
61 | config_host_data.set('CONFIG_IOVEC', | ||
62 | diff --git a/include/block/block-io.h b/include/block/block-io.h | ||
63 | index XXXXXXX..XXXXXXX 100644 | ||
64 | --- a/include/block/block-io.h | ||
65 | +++ b/include/block/block-io.h | ||
66 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn GRAPH_RDLOCK bdrv_co_flush(BlockDriverState *bs); | ||
67 | int coroutine_fn GRAPH_RDLOCK bdrv_co_pdiscard(BdrvChild *child, int64_t offset, | ||
68 | int64_t bytes); | ||
69 | |||
70 | +/* Report zone information of zone block device. */ | ||
71 | +int coroutine_fn GRAPH_RDLOCK bdrv_co_zone_report(BlockDriverState *bs, | ||
72 | + int64_t offset, | ||
73 | + unsigned int *nr_zones, | ||
74 | + BlockZoneDescriptor *zones); | ||
75 | +int coroutine_fn GRAPH_RDLOCK bdrv_co_zone_mgmt(BlockDriverState *bs, | ||
76 | + BlockZoneOp op, | ||
77 | + int64_t offset, int64_t len); | ||
78 | + | ||
79 | bool bdrv_can_write_zeroes_with_unmap(BlockDriverState *bs); | ||
80 | int bdrv_block_status(BlockDriverState *bs, int64_t offset, | ||
81 | int64_t bytes, int64_t *pnum, int64_t *map, | ||
82 | diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h | ||
83 | index XXXXXXX..XXXXXXX 100644 | ||
84 | --- a/include/block/block_int-common.h | ||
85 | +++ b/include/block/block_int-common.h | ||
86 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { | ||
87 | int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_load_vmstate)( | ||
88 | BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos); | ||
89 | |||
90 | + int coroutine_fn (*bdrv_co_zone_report)(BlockDriverState *bs, | ||
91 | + int64_t offset, unsigned int *nr_zones, | ||
92 | + BlockZoneDescriptor *zones); | ||
93 | + int coroutine_fn (*bdrv_co_zone_mgmt)(BlockDriverState *bs, BlockZoneOp op, | ||
94 | + int64_t offset, int64_t len); | ||
95 | + | ||
96 | /* removable device specific */ | ||
97 | bool coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_is_inserted)( | ||
98 | BlockDriverState *bs); | ||
99 | @@ -XXX,XX +XXX,XX @@ typedef struct BlockLimits { | ||
100 | |||
101 | /* device zone model */ | ||
102 | BlockZoneModel zoned; | ||
103 | + | ||
104 | + /* zone size expressed in bytes */ | ||
105 | + uint32_t zone_size; | ||
106 | + | ||
107 | + /* total number of zones */ | ||
108 | + uint32_t nr_zones; | ||
109 | + | ||
110 | + /* maximum sectors of a zone append write operation */ | ||
111 | + int64_t max_append_sectors; | ||
112 | + | ||
113 | + /* maximum number of open zones */ | ||
114 | + int64_t max_open_zones; | ||
115 | + | ||
116 | + /* maximum number of active zones */ | ||
117 | + int64_t max_active_zones; | ||
118 | } BlockLimits; | ||
119 | |||
120 | typedef struct BdrvOpBlocker BdrvOpBlocker; | ||
121 | diff --git a/include/block/raw-aio.h b/include/block/raw-aio.h | ||
122 | index XXXXXXX..XXXXXXX 100644 | ||
123 | --- a/include/block/raw-aio.h | ||
124 | +++ b/include/block/raw-aio.h | ||
125 | @@ -XXX,XX +XXX,XX @@ | ||
126 | #define QEMU_AIO_WRITE_ZEROES 0x0020 | ||
127 | #define QEMU_AIO_COPY_RANGE 0x0040 | ||
128 | #define QEMU_AIO_TRUNCATE 0x0080 | ||
129 | +#define QEMU_AIO_ZONE_REPORT 0x0100 | ||
130 | +#define QEMU_AIO_ZONE_MGMT 0x0200 | ||
131 | #define QEMU_AIO_TYPE_MASK \ | ||
132 | (QEMU_AIO_READ | \ | ||
133 | QEMU_AIO_WRITE | \ | ||
134 | @@ -XXX,XX +XXX,XX @@ | ||
135 | QEMU_AIO_DISCARD | \ | ||
136 | QEMU_AIO_WRITE_ZEROES | \ | ||
137 | QEMU_AIO_COPY_RANGE | \ | ||
138 | - QEMU_AIO_TRUNCATE) | ||
139 | + QEMU_AIO_TRUNCATE | \ | ||
140 | + QEMU_AIO_ZONE_REPORT | \ | ||
141 | + QEMU_AIO_ZONE_MGMT) | ||
142 | |||
143 | /* AIO flags */ | ||
144 | #define QEMU_AIO_MISALIGNED 0x1000 | ||
145 | diff --git a/include/sysemu/block-backend-io.h b/include/sysemu/block-backend-io.h | ||
146 | index XXXXXXX..XXXXXXX 100644 | ||
147 | --- a/include/sysemu/block-backend-io.h | ||
148 | +++ b/include/sysemu/block-backend-io.h | ||
149 | @@ -XXX,XX +XXX,XX @@ BlockAIOCB *blk_aio_pwritev(BlockBackend *blk, int64_t offset, | ||
150 | BlockCompletionFunc *cb, void *opaque); | ||
151 | BlockAIOCB *blk_aio_flush(BlockBackend *blk, | ||
152 | BlockCompletionFunc *cb, void *opaque); | ||
153 | +BlockAIOCB *blk_aio_zone_report(BlockBackend *blk, int64_t offset, | ||
154 | + unsigned int *nr_zones, | ||
155 | + BlockZoneDescriptor *zones, | ||
156 | + BlockCompletionFunc *cb, void *opaque); | ||
157 | +BlockAIOCB *blk_aio_zone_mgmt(BlockBackend *blk, BlockZoneOp op, | ||
158 | + int64_t offset, int64_t len, | ||
159 | + BlockCompletionFunc *cb, void *opaque); | ||
160 | BlockAIOCB *blk_aio_pdiscard(BlockBackend *blk, int64_t offset, int64_t bytes, | ||
161 | BlockCompletionFunc *cb, void *opaque); | ||
162 | void blk_aio_cancel_async(BlockAIOCB *acb); | ||
163 | @@ -XXX,XX +XXX,XX @@ int co_wrapper_mixed blk_pwrite_zeroes(BlockBackend *blk, int64_t offset, | ||
164 | int coroutine_fn blk_co_pwrite_zeroes(BlockBackend *blk, int64_t offset, | ||
165 | int64_t bytes, BdrvRequestFlags flags); | ||
166 | |||
167 | +int coroutine_fn blk_co_zone_report(BlockBackend *blk, int64_t offset, | ||
168 | + unsigned int *nr_zones, | ||
169 | + BlockZoneDescriptor *zones); | ||
170 | +int co_wrapper_mixed blk_zone_report(BlockBackend *blk, int64_t offset, | ||
171 | + unsigned int *nr_zones, | ||
172 | + BlockZoneDescriptor *zones); | ||
173 | +int coroutine_fn blk_co_zone_mgmt(BlockBackend *blk, BlockZoneOp op, | ||
174 | + int64_t offset, int64_t len); | ||
175 | +int co_wrapper_mixed blk_zone_mgmt(BlockBackend *blk, BlockZoneOp op, | ||
176 | + int64_t offset, int64_t len); | ||
177 | + | ||
178 | int co_wrapper_mixed blk_pdiscard(BlockBackend *blk, int64_t offset, | ||
179 | int64_t bytes); | ||
180 | int coroutine_fn blk_co_pdiscard(BlockBackend *blk, int64_t offset, | ||
181 | diff --git a/block/block-backend.c b/block/block-backend.c | ||
182 | index XXXXXXX..XXXXXXX 100644 | ||
183 | --- a/block/block-backend.c | ||
184 | +++ b/block/block-backend.c | ||
185 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn blk_co_flush(BlockBackend *blk) | ||
186 | return ret; | ||
187 | } | ||
188 | |||
189 | +static void coroutine_fn blk_aio_zone_report_entry(void *opaque) | ||
190 | +{ | ||
191 | + BlkAioEmAIOCB *acb = opaque; | ||
192 | + BlkRwCo *rwco = &acb->rwco; | ||
193 | + | ||
194 | + rwco->ret = blk_co_zone_report(rwco->blk, rwco->offset, | ||
195 | + (unsigned int*)acb->bytes,rwco->iobuf); | ||
196 | + blk_aio_complete(acb); | ||
197 | +} | ||
198 | + | ||
199 | +BlockAIOCB *blk_aio_zone_report(BlockBackend *blk, int64_t offset, | ||
200 | + unsigned int *nr_zones, | ||
201 | + BlockZoneDescriptor *zones, | ||
202 | + BlockCompletionFunc *cb, void *opaque) | ||
203 | +{ | ||
204 | + BlkAioEmAIOCB *acb; | ||
205 | + Coroutine *co; | ||
206 | + IO_CODE(); | ||
207 | + | ||
208 | + blk_inc_in_flight(blk); | ||
209 | + acb = blk_aio_get(&blk_aio_em_aiocb_info, blk, cb, opaque); | ||
210 | + acb->rwco = (BlkRwCo) { | ||
211 | + .blk = blk, | ||
212 | + .offset = offset, | ||
213 | + .iobuf = zones, | ||
214 | + .ret = NOT_DONE, | ||
215 | + }; | ||
216 | + acb->bytes = (int64_t)nr_zones, | ||
217 | + acb->has_returned = false; | ||
218 | + | ||
219 | + co = qemu_coroutine_create(blk_aio_zone_report_entry, acb); | ||
220 | + aio_co_enter(blk_get_aio_context(blk), co); | ||
221 | + | ||
222 | + acb->has_returned = true; | ||
223 | + if (acb->rwco.ret != NOT_DONE) { | ||
224 | + replay_bh_schedule_oneshot_event(blk_get_aio_context(blk), | ||
225 | + blk_aio_complete_bh, acb); | ||
226 | + } | ||
227 | + | ||
228 | + return &acb->common; | ||
229 | +} | ||
230 | + | ||
231 | +static void coroutine_fn blk_aio_zone_mgmt_entry(void *opaque) | ||
232 | +{ | ||
233 | + BlkAioEmAIOCB *acb = opaque; | ||
234 | + BlkRwCo *rwco = &acb->rwco; | ||
235 | + | ||
236 | + rwco->ret = blk_co_zone_mgmt(rwco->blk, (BlockZoneOp)rwco->iobuf, | ||
237 | + rwco->offset, acb->bytes); | ||
238 | + blk_aio_complete(acb); | ||
239 | +} | ||
240 | + | ||
241 | +BlockAIOCB *blk_aio_zone_mgmt(BlockBackend *blk, BlockZoneOp op, | ||
242 | + int64_t offset, int64_t len, | ||
243 | + BlockCompletionFunc *cb, void *opaque) { | ||
244 | + BlkAioEmAIOCB *acb; | ||
245 | + Coroutine *co; | ||
246 | + IO_CODE(); | ||
247 | + | ||
248 | + blk_inc_in_flight(blk); | ||
249 | + acb = blk_aio_get(&blk_aio_em_aiocb_info, blk, cb, opaque); | ||
250 | + acb->rwco = (BlkRwCo) { | ||
251 | + .blk = blk, | ||
252 | + .offset = offset, | ||
253 | + .iobuf = (void *)op, | ||
254 | + .ret = NOT_DONE, | ||
255 | + }; | ||
256 | + acb->bytes = len; | ||
257 | + acb->has_returned = false; | ||
258 | + | ||
259 | + co = qemu_coroutine_create(blk_aio_zone_mgmt_entry, acb); | ||
260 | + aio_co_enter(blk_get_aio_context(blk), co); | ||
261 | + | ||
262 | + acb->has_returned = true; | ||
263 | + if (acb->rwco.ret != NOT_DONE) { | ||
264 | + replay_bh_schedule_oneshot_event(blk_get_aio_context(blk), | ||
265 | + blk_aio_complete_bh, acb); | ||
266 | + } | ||
267 | + | ||
268 | + return &acb->common; | ||
269 | +} | ||
270 | + | ||
271 | +/* | ||
272 | + * Send a zone_report command. | ||
273 | + * offset is a byte offset from the start of the device. No alignment | ||
274 | + * required for offset. | ||
275 | + * nr_zones represents IN maximum and OUT actual. | ||
276 | + */ | ||
277 | +int coroutine_fn blk_co_zone_report(BlockBackend *blk, int64_t offset, | ||
278 | + unsigned int *nr_zones, | ||
279 | + BlockZoneDescriptor *zones) | ||
280 | +{ | ||
281 | + int ret; | ||
282 | + IO_CODE(); | ||
283 | + | ||
284 | + blk_inc_in_flight(blk); /* increase before waiting */ | ||
285 | + blk_wait_while_drained(blk); | ||
286 | + if (!blk_is_available(blk)) { | ||
287 | + blk_dec_in_flight(blk); | ||
288 | + return -ENOMEDIUM; | ||
289 | + } | ||
290 | + ret = bdrv_co_zone_report(blk_bs(blk), offset, nr_zones, zones); | ||
291 | + blk_dec_in_flight(blk); | ||
292 | + return ret; | ||
293 | +} | ||
294 | + | ||
295 | +/* | ||
296 | + * Send a zone_management command. | ||
297 | + * op is the zone operation; | ||
298 | + * offset is the byte offset from the start of the zoned device; | ||
299 | + * len is the maximum number of bytes the command should operate on. It | ||
300 | + * should be aligned with the device zone size. | ||
301 | + */ | ||
302 | +int coroutine_fn blk_co_zone_mgmt(BlockBackend *blk, BlockZoneOp op, | ||
303 | + int64_t offset, int64_t len) | ||
304 | +{ | ||
305 | + int ret; | ||
306 | + IO_CODE(); | ||
307 | + | ||
308 | + blk_inc_in_flight(blk); | ||
309 | + blk_wait_while_drained(blk); | ||
310 | + | ||
311 | + ret = blk_check_byte_request(blk, offset, len); | ||
312 | + if (ret < 0) { | ||
313 | + blk_dec_in_flight(blk); | ||
314 | + return ret; | ||
315 | + } | ||
316 | + | ||
317 | + ret = bdrv_co_zone_mgmt(blk_bs(blk), op, offset, len); | ||
318 | + blk_dec_in_flight(blk); | ||
319 | + return ret; | ||
320 | +} | ||
321 | + | ||
322 | void blk_drain(BlockBackend *blk) | ||
323 | { | ||
324 | BlockDriverState *bs = blk_bs(blk); | ||
325 | diff --git a/block/file-posix.c b/block/file-posix.c | ||
326 | index XXXXXXX..XXXXXXX 100644 | ||
327 | --- a/block/file-posix.c | ||
328 | +++ b/block/file-posix.c | ||
329 | @@ -XXX,XX +XXX,XX @@ | ||
330 | #include <sys/param.h> | ||
331 | #include <sys/syscall.h> | ||
332 | #include <sys/vfs.h> | ||
333 | +#if defined(CONFIG_BLKZONED) | ||
334 | +#include <linux/blkzoned.h> | ||
335 | +#endif | ||
336 | #include <linux/cdrom.h> | ||
337 | #include <linux/fd.h> | ||
338 | #include <linux/fs.h> | ||
339 | @@ -XXX,XX +XXX,XX @@ typedef struct RawPosixAIOData { | ||
340 | PreallocMode prealloc; | ||
341 | Error **errp; | ||
342 | } truncate; | ||
343 | + struct { | ||
344 | + unsigned int *nr_zones; | ||
345 | + BlockZoneDescriptor *zones; | ||
346 | + } zone_report; | ||
347 | + struct { | ||
348 | + unsigned long op; | ||
349 | + } zone_mgmt; | ||
350 | }; | ||
351 | } RawPosixAIOData; | ||
352 | |||
353 | @@ -XXX,XX +XXX,XX @@ static void raw_refresh_limits(BlockDriverState *bs, Error **errp) | ||
354 | zoned = BLK_Z_NONE; | ||
36 | } | 355 | } |
37 | 356 | bs->bl.zoned = zoned; | |
38 | s->hfile = CreateFile(filename, access_flags, | 357 | + if (zoned != BLK_Z_NONE) { |
39 | - FILE_SHARE_READ, NULL, | 358 | + /* |
40 | + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, | 359 | + * The zoned device must at least have zone size and nr_zones fields. |
41 | OPEN_EXISTING, overlapped, NULL); | 360 | + */ |
42 | if (s->hfile == INVALID_HANDLE_VALUE) { | 361 | + ret = get_sysfs_long_val(&st, "chunk_sectors"); |
43 | int err = GetLastError(); | 362 | + if (ret < 0) { |
44 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_create_opts(BlockDriver *drv, | 363 | + error_setg_errno(errp, -ret, "Unable to read chunk_sectors " |
45 | return raw_co_create(&options, errp); | 364 | + "sysfs attribute"); |
365 | + goto out; | ||
366 | + } else if (!ret) { | ||
367 | + error_setg(errp, "Read 0 from chunk_sectors sysfs attribute"); | ||
368 | + goto out; | ||
369 | + } | ||
370 | + bs->bl.zone_size = ret << BDRV_SECTOR_BITS; | ||
371 | + | ||
372 | + ret = get_sysfs_long_val(&st, "nr_zones"); | ||
373 | + if (ret < 0) { | ||
374 | + error_setg_errno(errp, -ret, "Unable to read nr_zones " | ||
375 | + "sysfs attribute"); | ||
376 | + goto out; | ||
377 | + } else if (!ret) { | ||
378 | + error_setg(errp, "Read 0 from nr_zones sysfs attribute"); | ||
379 | + goto out; | ||
380 | + } | ||
381 | + bs->bl.nr_zones = ret; | ||
382 | + | ||
383 | + ret = get_sysfs_long_val(&st, "zone_append_max_bytes"); | ||
384 | + if (ret > 0) { | ||
385 | + bs->bl.max_append_sectors = ret >> BDRV_SECTOR_BITS; | ||
386 | + } | ||
387 | + | ||
388 | + ret = get_sysfs_long_val(&st, "max_open_zones"); | ||
389 | + if (ret >= 0) { | ||
390 | + bs->bl.max_open_zones = ret; | ||
391 | + } | ||
392 | + | ||
393 | + ret = get_sysfs_long_val(&st, "max_active_zones"); | ||
394 | + if (ret >= 0) { | ||
395 | + bs->bl.max_active_zones = ret; | ||
396 | + } | ||
397 | + return; | ||
398 | + } | ||
399 | +out: | ||
400 | + bs->bl.zoned = BLK_Z_NONE; | ||
46 | } | 401 | } |
47 | 402 | ||
48 | +static int raw_reopen_prepare(BDRVReopenState *state, | 403 | static int check_for_dasd(int fd) |
49 | + BlockReopenQueue *queue, Error **errp) | 404 | @@ -XXX,XX +XXX,XX @@ static int hdev_probe_blocksizes(BlockDriverState *bs, BlockSizes *bsz) |
50 | +{ | 405 | BDRVRawState *s = bs->opaque; |
51 | + BDRVRawState *s = state->bs->opaque; | 406 | int ret; |
52 | + BDRVRawReopenState *rs; | 407 | |
53 | + int access_flags; | 408 | - /* If DASD, get blocksizes */ |
54 | + DWORD overlapped; | 409 | + /* If DASD or zoned devices, get blocksizes */ |
55 | + int ret = 0; | 410 | if (check_for_dasd(s->fd) < 0) { |
56 | + | 411 | - return -ENOTSUP; |
57 | + if (s->type != FTYPE_FILE) { | 412 | + /* zoned devices are not DASD */ |
58 | + error_setg(errp, "Can only reopen files"); | 413 | + if (bs->bl.zoned == BLK_Z_NONE) { |
414 | + return -ENOTSUP; | ||
415 | + } | ||
416 | } | ||
417 | ret = probe_logical_blocksize(s->fd, &bsz->log); | ||
418 | if (ret < 0) { | ||
419 | @@ -XXX,XX +XXX,XX @@ static off_t copy_file_range(int in_fd, off_t *in_off, int out_fd, | ||
420 | } | ||
421 | #endif | ||
422 | |||
423 | +/* | ||
424 | + * parse_zone - Fill a zone descriptor | ||
425 | + */ | ||
426 | +#if defined(CONFIG_BLKZONED) | ||
427 | +static inline int parse_zone(struct BlockZoneDescriptor *zone, | ||
428 | + const struct blk_zone *blkz) { | ||
429 | + zone->start = blkz->start << BDRV_SECTOR_BITS; | ||
430 | + zone->length = blkz->len << BDRV_SECTOR_BITS; | ||
431 | + zone->wp = blkz->wp << BDRV_SECTOR_BITS; | ||
432 | + | ||
433 | +#ifdef HAVE_BLK_ZONE_REP_CAPACITY | ||
434 | + zone->cap = blkz->capacity << BDRV_SECTOR_BITS; | ||
435 | +#else | ||
436 | + zone->cap = blkz->len << BDRV_SECTOR_BITS; | ||
437 | +#endif | ||
438 | + | ||
439 | + switch (blkz->type) { | ||
440 | + case BLK_ZONE_TYPE_SEQWRITE_REQ: | ||
441 | + zone->type = BLK_ZT_SWR; | ||
442 | + break; | ||
443 | + case BLK_ZONE_TYPE_SEQWRITE_PREF: | ||
444 | + zone->type = BLK_ZT_SWP; | ||
445 | + break; | ||
446 | + case BLK_ZONE_TYPE_CONVENTIONAL: | ||
447 | + zone->type = BLK_ZT_CONV; | ||
448 | + break; | ||
449 | + default: | ||
450 | + error_report("Unsupported zone type: 0x%x", blkz->type); | ||
451 | + return -ENOTSUP; | ||
452 | + } | ||
453 | + | ||
454 | + switch (blkz->cond) { | ||
455 | + case BLK_ZONE_COND_NOT_WP: | ||
456 | + zone->state = BLK_ZS_NOT_WP; | ||
457 | + break; | ||
458 | + case BLK_ZONE_COND_EMPTY: | ||
459 | + zone->state = BLK_ZS_EMPTY; | ||
460 | + break; | ||
461 | + case BLK_ZONE_COND_IMP_OPEN: | ||
462 | + zone->state = BLK_ZS_IOPEN; | ||
463 | + break; | ||
464 | + case BLK_ZONE_COND_EXP_OPEN: | ||
465 | + zone->state = BLK_ZS_EOPEN; | ||
466 | + break; | ||
467 | + case BLK_ZONE_COND_CLOSED: | ||
468 | + zone->state = BLK_ZS_CLOSED; | ||
469 | + break; | ||
470 | + case BLK_ZONE_COND_READONLY: | ||
471 | + zone->state = BLK_ZS_RDONLY; | ||
472 | + break; | ||
473 | + case BLK_ZONE_COND_FULL: | ||
474 | + zone->state = BLK_ZS_FULL; | ||
475 | + break; | ||
476 | + case BLK_ZONE_COND_OFFLINE: | ||
477 | + zone->state = BLK_ZS_OFFLINE; | ||
478 | + break; | ||
479 | + default: | ||
480 | + error_report("Unsupported zone state: 0x%x", blkz->cond); | ||
481 | + return -ENOTSUP; | ||
482 | + } | ||
483 | + return 0; | ||
484 | +} | ||
485 | +#endif | ||
486 | + | ||
487 | +#if defined(CONFIG_BLKZONED) | ||
488 | +static int handle_aiocb_zone_report(void *opaque) | ||
489 | +{ | ||
490 | + RawPosixAIOData *aiocb = opaque; | ||
491 | + int fd = aiocb->aio_fildes; | ||
492 | + unsigned int *nr_zones = aiocb->zone_report.nr_zones; | ||
493 | + BlockZoneDescriptor *zones = aiocb->zone_report.zones; | ||
494 | + /* zoned block devices use 512-byte sectors */ | ||
495 | + uint64_t sector = aiocb->aio_offset / 512; | ||
496 | + | ||
497 | + struct blk_zone *blkz; | ||
498 | + size_t rep_size; | ||
499 | + unsigned int nrz; | ||
500 | + int ret, n = 0, i = 0; | ||
501 | + | ||
502 | + nrz = *nr_zones; | ||
503 | + rep_size = sizeof(struct blk_zone_report) + nrz * sizeof(struct blk_zone); | ||
504 | + g_autofree struct blk_zone_report *rep = NULL; | ||
505 | + rep = g_malloc(rep_size); | ||
506 | + | ||
507 | + blkz = (struct blk_zone *)(rep + 1); | ||
508 | + while (n < nrz) { | ||
509 | + memset(rep, 0, rep_size); | ||
510 | + rep->sector = sector; | ||
511 | + rep->nr_zones = nrz - n; | ||
512 | + | ||
513 | + do { | ||
514 | + ret = ioctl(fd, BLKREPORTZONE, rep); | ||
515 | + } while (ret != 0 && errno == EINTR); | ||
516 | + if (ret != 0) { | ||
517 | + error_report("%d: ioctl BLKREPORTZONE at %" PRId64 " failed %d", | ||
518 | + fd, sector, errno); | ||
519 | + return -errno; | ||
520 | + } | ||
521 | + | ||
522 | + if (!rep->nr_zones) { | ||
523 | + break; | ||
524 | + } | ||
525 | + | ||
526 | + for (i = 0; i < rep->nr_zones; i++, n++) { | ||
527 | + ret = parse_zone(&zones[n], &blkz[i]); | ||
528 | + if (ret != 0) { | ||
529 | + return ret; | ||
530 | + } | ||
531 | + | ||
532 | + /* The next report should start after the last zone reported */ | ||
533 | + sector = blkz[i].start + blkz[i].len; | ||
534 | + } | ||
535 | + } | ||
536 | + | ||
537 | + *nr_zones = n; | ||
538 | + return 0; | ||
539 | +} | ||
540 | +#endif | ||
541 | + | ||
542 | +#if defined(CONFIG_BLKZONED) | ||
543 | +static int handle_aiocb_zone_mgmt(void *opaque) | ||
544 | +{ | ||
545 | + RawPosixAIOData *aiocb = opaque; | ||
546 | + int fd = aiocb->aio_fildes; | ||
547 | + uint64_t sector = aiocb->aio_offset / 512; | ||
548 | + int64_t nr_sectors = aiocb->aio_nbytes / 512; | ||
549 | + struct blk_zone_range range; | ||
550 | + int ret; | ||
551 | + | ||
552 | + /* Execute the operation */ | ||
553 | + range.sector = sector; | ||
554 | + range.nr_sectors = nr_sectors; | ||
555 | + do { | ||
556 | + ret = ioctl(fd, aiocb->zone_mgmt.op, &range); | ||
557 | + } while (ret != 0 && errno == EINTR); | ||
558 | + | ||
559 | + return ret; | ||
560 | +} | ||
561 | +#endif | ||
562 | + | ||
563 | static int handle_aiocb_copy_range(void *opaque) | ||
564 | { | ||
565 | RawPosixAIOData *aiocb = opaque; | ||
566 | @@ -XXX,XX +XXX,XX @@ static void raw_account_discard(BDRVRawState *s, uint64_t nbytes, int ret) | ||
567 | } | ||
568 | } | ||
569 | |||
570 | +/* | ||
571 | + * zone report - Get a zone block device's information in the form | ||
572 | + * of an array of zone descriptors. | ||
573 | + * zones is an array of zone descriptors to hold zone information on reply; | ||
574 | + * offset can be any byte within the entire size of the device; | ||
575 | + * nr_zones is the maxium number of sectors the command should operate on. | ||
576 | + */ | ||
577 | +#if defined(CONFIG_BLKZONED) | ||
578 | +static int coroutine_fn raw_co_zone_report(BlockDriverState *bs, int64_t offset, | ||
579 | + unsigned int *nr_zones, | ||
580 | + BlockZoneDescriptor *zones) { | ||
581 | + BDRVRawState *s = bs->opaque; | ||
582 | + RawPosixAIOData acb = (RawPosixAIOData) { | ||
583 | + .bs = bs, | ||
584 | + .aio_fildes = s->fd, | ||
585 | + .aio_type = QEMU_AIO_ZONE_REPORT, | ||
586 | + .aio_offset = offset, | ||
587 | + .zone_report = { | ||
588 | + .nr_zones = nr_zones, | ||
589 | + .zones = zones, | ||
590 | + }, | ||
591 | + }; | ||
592 | + | ||
593 | + return raw_thread_pool_submit(bs, handle_aiocb_zone_report, &acb); | ||
594 | +} | ||
595 | +#endif | ||
596 | + | ||
597 | +/* | ||
598 | + * zone management operations - Execute an operation on a zone | ||
599 | + */ | ||
600 | +#if defined(CONFIG_BLKZONED) | ||
601 | +static int coroutine_fn raw_co_zone_mgmt(BlockDriverState *bs, BlockZoneOp op, | ||
602 | + int64_t offset, int64_t len) { | ||
603 | + BDRVRawState *s = bs->opaque; | ||
604 | + RawPosixAIOData acb; | ||
605 | + int64_t zone_size, zone_size_mask; | ||
606 | + const char *op_name; | ||
607 | + unsigned long zo; | ||
608 | + int ret; | ||
609 | + int64_t capacity = bs->total_sectors << BDRV_SECTOR_BITS; | ||
610 | + | ||
611 | + zone_size = bs->bl.zone_size; | ||
612 | + zone_size_mask = zone_size - 1; | ||
613 | + if (offset & zone_size_mask) { | ||
614 | + error_report("sector offset %" PRId64 " is not aligned to zone size " | ||
615 | + "%" PRId64 "", offset / 512, zone_size / 512); | ||
59 | + return -EINVAL; | 616 | + return -EINVAL; |
60 | + } | 617 | + } |
61 | + | 618 | + |
62 | + rs = g_new0(BDRVRawReopenState, 1); | 619 | + if (((offset + len) < capacity && len & zone_size_mask) || |
63 | + | 620 | + offset + len > capacity) { |
64 | + /* | 621 | + error_report("number of sectors %" PRId64 " is not aligned to zone size" |
65 | + * We do not support changing any options (only flags). By leaving | 622 | + " %" PRId64 "", len / 512, zone_size / 512); |
66 | + * all options in state->options, we tell the generic reopen code | 623 | + return -EINVAL; |
67 | + * that we do not support changing any of them, so it will verify | 624 | + } |
68 | + * that their values did not change. | 625 | + |
69 | + */ | 626 | + switch (op) { |
70 | + | 627 | + case BLK_ZO_OPEN: |
71 | + raw_parse_flags(state->flags, s->aio != NULL, &access_flags, &overlapped); | 628 | + op_name = "BLKOPENZONE"; |
72 | + rs->hfile = CreateFile(state->bs->filename, access_flags, | 629 | + zo = BLKOPENZONE; |
73 | + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, | 630 | + break; |
74 | + OPEN_EXISTING, overlapped, NULL); | 631 | + case BLK_ZO_CLOSE: |
75 | + | 632 | + op_name = "BLKCLOSEZONE"; |
76 | + if (rs->hfile == INVALID_HANDLE_VALUE) { | 633 | + zo = BLKCLOSEZONE; |
77 | + int err = GetLastError(); | 634 | + break; |
78 | + | 635 | + case BLK_ZO_FINISH: |
79 | + error_setg_win32(errp, err, "Could not reopen '%s'", | 636 | + op_name = "BLKFINISHZONE"; |
80 | + state->bs->filename); | 637 | + zo = BLKFINISHZONE; |
81 | + if (err == ERROR_ACCESS_DENIED) { | 638 | + break; |
82 | + ret = -EACCES; | 639 | + case BLK_ZO_RESET: |
83 | + } else { | 640 | + op_name = "BLKRESETZONE"; |
84 | + ret = -EINVAL; | 641 | + zo = BLKRESETZONE; |
642 | + break; | ||
643 | + default: | ||
644 | + error_report("Unsupported zone op: 0x%x", op); | ||
645 | + return -ENOTSUP; | ||
646 | + } | ||
647 | + | ||
648 | + acb = (RawPosixAIOData) { | ||
649 | + .bs = bs, | ||
650 | + .aio_fildes = s->fd, | ||
651 | + .aio_type = QEMU_AIO_ZONE_MGMT, | ||
652 | + .aio_offset = offset, | ||
653 | + .aio_nbytes = len, | ||
654 | + .zone_mgmt = { | ||
655 | + .op = zo, | ||
656 | + }, | ||
657 | + }; | ||
658 | + | ||
659 | + ret = raw_thread_pool_submit(bs, handle_aiocb_zone_mgmt, &acb); | ||
660 | + if (ret != 0) { | ||
661 | + error_report("ioctl %s failed %d", op_name, ret); | ||
662 | + } | ||
663 | + | ||
664 | + return ret; | ||
665 | +} | ||
666 | +#endif | ||
667 | + | ||
668 | static coroutine_fn int | ||
669 | raw_do_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
670 | bool blkdev) | ||
671 | @@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_host_device = { | ||
672 | #ifdef __linux__ | ||
673 | .bdrv_co_ioctl = hdev_co_ioctl, | ||
674 | #endif | ||
675 | + | ||
676 | + /* zoned device */ | ||
677 | +#if defined(CONFIG_BLKZONED) | ||
678 | + /* zone management operations */ | ||
679 | + .bdrv_co_zone_report = raw_co_zone_report, | ||
680 | + .bdrv_co_zone_mgmt = raw_co_zone_mgmt, | ||
681 | +#endif | ||
682 | }; | ||
683 | |||
684 | #if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) | ||
685 | diff --git a/block/io.c b/block/io.c | ||
686 | index XXXXXXX..XXXXXXX 100644 | ||
687 | --- a/block/io.c | ||
688 | +++ b/block/io.c | ||
689 | @@ -XXX,XX +XXX,XX @@ out: | ||
690 | return co.ret; | ||
691 | } | ||
692 | |||
693 | +int coroutine_fn bdrv_co_zone_report(BlockDriverState *bs, int64_t offset, | ||
694 | + unsigned int *nr_zones, | ||
695 | + BlockZoneDescriptor *zones) | ||
696 | +{ | ||
697 | + BlockDriver *drv = bs->drv; | ||
698 | + CoroutineIOCompletion co = { | ||
699 | + .coroutine = qemu_coroutine_self(), | ||
700 | + }; | ||
701 | + IO_CODE(); | ||
702 | + | ||
703 | + bdrv_inc_in_flight(bs); | ||
704 | + if (!drv || !drv->bdrv_co_zone_report || bs->bl.zoned == BLK_Z_NONE) { | ||
705 | + co.ret = -ENOTSUP; | ||
706 | + goto out; | ||
707 | + } | ||
708 | + co.ret = drv->bdrv_co_zone_report(bs, offset, nr_zones, zones); | ||
709 | +out: | ||
710 | + bdrv_dec_in_flight(bs); | ||
711 | + return co.ret; | ||
712 | +} | ||
713 | + | ||
714 | +int coroutine_fn bdrv_co_zone_mgmt(BlockDriverState *bs, BlockZoneOp op, | ||
715 | + int64_t offset, int64_t len) | ||
716 | +{ | ||
717 | + BlockDriver *drv = bs->drv; | ||
718 | + CoroutineIOCompletion co = { | ||
719 | + .coroutine = qemu_coroutine_self(), | ||
720 | + }; | ||
721 | + IO_CODE(); | ||
722 | + | ||
723 | + bdrv_inc_in_flight(bs); | ||
724 | + if (!drv || !drv->bdrv_co_zone_mgmt || bs->bl.zoned == BLK_Z_NONE) { | ||
725 | + co.ret = -ENOTSUP; | ||
726 | + goto out; | ||
727 | + } | ||
728 | + co.ret = drv->bdrv_co_zone_mgmt(bs, op, offset, len); | ||
729 | +out: | ||
730 | + bdrv_dec_in_flight(bs); | ||
731 | + return co.ret; | ||
732 | +} | ||
733 | + | ||
734 | void *qemu_blockalign(BlockDriverState *bs, size_t size) | ||
735 | { | ||
736 | IO_CODE(); | ||
737 | diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c | ||
738 | index XXXXXXX..XXXXXXX 100644 | ||
739 | --- a/qemu-io-cmds.c | ||
740 | +++ b/qemu-io-cmds.c | ||
741 | @@ -XXX,XX +XXX,XX @@ static const cmdinfo_t flush_cmd = { | ||
742 | .oneline = "flush all in-core file state to disk", | ||
743 | }; | ||
744 | |||
745 | +static inline int64_t tosector(int64_t bytes) | ||
746 | +{ | ||
747 | + return bytes >> BDRV_SECTOR_BITS; | ||
748 | +} | ||
749 | + | ||
750 | +static int zone_report_f(BlockBackend *blk, int argc, char **argv) | ||
751 | +{ | ||
752 | + int ret; | ||
753 | + int64_t offset; | ||
754 | + unsigned int nr_zones; | ||
755 | + | ||
756 | + ++optind; | ||
757 | + offset = cvtnum(argv[optind]); | ||
758 | + ++optind; | ||
759 | + nr_zones = cvtnum(argv[optind]); | ||
760 | + | ||
761 | + g_autofree BlockZoneDescriptor *zones = NULL; | ||
762 | + zones = g_new(BlockZoneDescriptor, nr_zones); | ||
763 | + ret = blk_zone_report(blk, offset, &nr_zones, zones); | ||
764 | + if (ret < 0) { | ||
765 | + printf("zone report failed: %s\n", strerror(-ret)); | ||
766 | + } else { | ||
767 | + for (int i = 0; i < nr_zones; ++i) { | ||
768 | + printf("start: 0x%" PRIx64 ", len 0x%" PRIx64 ", " | ||
769 | + "cap"" 0x%" PRIx64 ", wptr 0x%" PRIx64 ", " | ||
770 | + "zcond:%u, [type: %u]\n", | ||
771 | + tosector(zones[i].start), tosector(zones[i].length), | ||
772 | + tosector(zones[i].cap), tosector(zones[i].wp), | ||
773 | + zones[i].state, zones[i].type); | ||
85 | + } | 774 | + } |
86 | + goto fail; | 775 | + } |
87 | + } | ||
88 | + | ||
89 | + if (s->aio) { | ||
90 | + ret = win32_aio_attach(s->aio, rs->hfile); | ||
91 | + if (ret < 0) { | ||
92 | + error_setg_errno(errp, -ret, "Could not enable AIO"); | ||
93 | + CloseHandle(rs->hfile); | ||
94 | + goto fail; | ||
95 | + } | ||
96 | + } | ||
97 | + | ||
98 | + state->opaque = rs; | ||
99 | + | ||
100 | + return 0; | ||
101 | + | ||
102 | +fail: | ||
103 | + g_free(rs); | ||
104 | + state->opaque = NULL; | ||
105 | + | ||
106 | + return ret; | 776 | + return ret; |
107 | +} | 777 | +} |
108 | + | 778 | + |
109 | +static void raw_reopen_commit(BDRVReopenState *state) | 779 | +static const cmdinfo_t zone_report_cmd = { |
110 | +{ | 780 | + .name = "zone_report", |
111 | + BDRVRawState *s = state->bs->opaque; | 781 | + .altname = "zrp", |
112 | + BDRVRawReopenState *rs = state->opaque; | 782 | + .cfunc = zone_report_f, |
113 | + | 783 | + .argmin = 2, |
114 | + assert(rs != NULL); | 784 | + .argmax = 2, |
115 | + | 785 | + .args = "offset number", |
116 | + CloseHandle(s->hfile); | 786 | + .oneline = "report zone information", |
117 | + s->hfile = rs->hfile; | 787 | +}; |
118 | + | 788 | + |
119 | + g_free(rs); | 789 | +static int zone_open_f(BlockBackend *blk, int argc, char **argv) |
120 | + state->opaque = NULL; | 790 | +{ |
121 | +} | 791 | + int ret; |
122 | + | 792 | + int64_t offset, len; |
123 | +static void raw_reopen_abort(BDRVReopenState *state) | 793 | + ++optind; |
124 | +{ | 794 | + offset = cvtnum(argv[optind]); |
125 | + BDRVRawReopenState *rs = state->opaque; | 795 | + ++optind; |
126 | + | 796 | + len = cvtnum(argv[optind]); |
127 | + if (!rs) { | 797 | + ret = blk_zone_mgmt(blk, BLK_ZO_OPEN, offset, len); |
128 | + return; | 798 | + if (ret < 0) { |
129 | + } | 799 | + printf("zone open failed: %s\n", strerror(-ret)); |
130 | + | 800 | + } |
131 | + if (rs->hfile != INVALID_HANDLE_VALUE) { | 801 | + return ret; |
132 | + CloseHandle(rs->hfile); | 802 | +} |
133 | + } | 803 | + |
134 | + | 804 | +static const cmdinfo_t zone_open_cmd = { |
135 | + g_free(rs); | 805 | + .name = "zone_open", |
136 | + state->opaque = NULL; | 806 | + .altname = "zo", |
137 | +} | 807 | + .cfunc = zone_open_f, |
138 | + | 808 | + .argmin = 2, |
139 | static QemuOptsList raw_create_opts = { | 809 | + .argmax = 2, |
140 | .name = "raw-create-opts", | 810 | + .args = "offset len", |
141 | .head = QTAILQ_HEAD_INITIALIZER(raw_create_opts.head), | 811 | + .oneline = "explicit open a range of zones in zone block device", |
142 | @@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_file = { | 812 | +}; |
143 | .bdrv_co_create_opts = raw_co_create_opts, | 813 | + |
144 | .bdrv_has_zero_init = bdrv_has_zero_init_1, | 814 | +static int zone_close_f(BlockBackend *blk, int argc, char **argv) |
145 | 815 | +{ | |
146 | + .bdrv_reopen_prepare = raw_reopen_prepare, | 816 | + int ret; |
147 | + .bdrv_reopen_commit = raw_reopen_commit, | 817 | + int64_t offset, len; |
148 | + .bdrv_reopen_abort = raw_reopen_abort, | 818 | + ++optind; |
149 | + | 819 | + offset = cvtnum(argv[optind]); |
150 | .bdrv_aio_preadv = raw_aio_preadv, | 820 | + ++optind; |
151 | .bdrv_aio_pwritev = raw_aio_pwritev, | 821 | + len = cvtnum(argv[optind]); |
152 | .bdrv_aio_flush = raw_aio_flush, | 822 | + ret = blk_zone_mgmt(blk, BLK_ZO_CLOSE, offset, len); |
823 | + if (ret < 0) { | ||
824 | + printf("zone close failed: %s\n", strerror(-ret)); | ||
825 | + } | ||
826 | + return ret; | ||
827 | +} | ||
828 | + | ||
829 | +static const cmdinfo_t zone_close_cmd = { | ||
830 | + .name = "zone_close", | ||
831 | + .altname = "zc", | ||
832 | + .cfunc = zone_close_f, | ||
833 | + .argmin = 2, | ||
834 | + .argmax = 2, | ||
835 | + .args = "offset len", | ||
836 | + .oneline = "close a range of zones in zone block device", | ||
837 | +}; | ||
838 | + | ||
839 | +static int zone_finish_f(BlockBackend *blk, int argc, char **argv) | ||
840 | +{ | ||
841 | + int ret; | ||
842 | + int64_t offset, len; | ||
843 | + ++optind; | ||
844 | + offset = cvtnum(argv[optind]); | ||
845 | + ++optind; | ||
846 | + len = cvtnum(argv[optind]); | ||
847 | + ret = blk_zone_mgmt(blk, BLK_ZO_FINISH, offset, len); | ||
848 | + if (ret < 0) { | ||
849 | + printf("zone finish failed: %s\n", strerror(-ret)); | ||
850 | + } | ||
851 | + return ret; | ||
852 | +} | ||
853 | + | ||
854 | +static const cmdinfo_t zone_finish_cmd = { | ||
855 | + .name = "zone_finish", | ||
856 | + .altname = "zf", | ||
857 | + .cfunc = zone_finish_f, | ||
858 | + .argmin = 2, | ||
859 | + .argmax = 2, | ||
860 | + .args = "offset len", | ||
861 | + .oneline = "finish a range of zones in zone block device", | ||
862 | +}; | ||
863 | + | ||
864 | +static int zone_reset_f(BlockBackend *blk, int argc, char **argv) | ||
865 | +{ | ||
866 | + int ret; | ||
867 | + int64_t offset, len; | ||
868 | + ++optind; | ||
869 | + offset = cvtnum(argv[optind]); | ||
870 | + ++optind; | ||
871 | + len = cvtnum(argv[optind]); | ||
872 | + ret = blk_zone_mgmt(blk, BLK_ZO_RESET, offset, len); | ||
873 | + if (ret < 0) { | ||
874 | + printf("zone reset failed: %s\n", strerror(-ret)); | ||
875 | + } | ||
876 | + return ret; | ||
877 | +} | ||
878 | + | ||
879 | +static const cmdinfo_t zone_reset_cmd = { | ||
880 | + .name = "zone_reset", | ||
881 | + .altname = "zrs", | ||
882 | + .cfunc = zone_reset_f, | ||
883 | + .argmin = 2, | ||
884 | + .argmax = 2, | ||
885 | + .args = "offset len", | ||
886 | + .oneline = "reset a zone write pointer in zone block device", | ||
887 | +}; | ||
888 | + | ||
889 | static int truncate_f(BlockBackend *blk, int argc, char **argv); | ||
890 | static const cmdinfo_t truncate_cmd = { | ||
891 | .name = "truncate", | ||
892 | @@ -XXX,XX +XXX,XX @@ static void __attribute((constructor)) init_qemuio_commands(void) | ||
893 | qemuio_add_command(&aio_write_cmd); | ||
894 | qemuio_add_command(&aio_flush_cmd); | ||
895 | qemuio_add_command(&flush_cmd); | ||
896 | + qemuio_add_command(&zone_report_cmd); | ||
897 | + qemuio_add_command(&zone_open_cmd); | ||
898 | + qemuio_add_command(&zone_close_cmd); | ||
899 | + qemuio_add_command(&zone_finish_cmd); | ||
900 | + qemuio_add_command(&zone_reset_cmd); | ||
901 | qemuio_add_command(&truncate_cmd); | ||
902 | qemuio_add_command(&length_cmd); | ||
903 | qemuio_add_command(&info_cmd); | ||
153 | -- | 904 | -- |
154 | 2.31.1 | 905 | 2.39.2 |
155 | 906 | ||
156 | 907 | diff view generated by jsdifflib |
1 | From: Stefan Hajnoczi <stefanha@redhat.com> | 1 | From: Sam Li <faithilikerun@gmail.com> |
---|---|---|---|
2 | 2 | ||
3 | The following command-line fails due to a permissions conflict: | 3 | raw-format driver usually sits on top of file-posix driver. It needs to |
4 | pass through requests of zone commands. | ||
4 | 5 | ||
5 | $ qemu-storage-daemon \ | 6 | Signed-off-by: Sam Li <faithilikerun@gmail.com> |
6 | --blockdev driver=nvme,node-name=nvme0,device=0000:08:00.0,namespace=1 \ | 7 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> |
7 | --blockdev driver=raw,node-name=l1-1,file=nvme0,offset=0,size=1073741824 \ | 8 | Reviewed-by: Damien Le Moal <damien.lemoal@opensource.wdc.com> |
8 | --blockdev driver=raw,node-name=l1-2,file=nvme0,offset=1073741824,size=1073741824 \ | 9 | Reviewed-by: Hannes Reinecke <hare@suse.de> |
9 | --nbd-server addr.type=unix,addr.path=/tmp/nbd.sock,max-connections=2 \ | 10 | Reviewed-by: Dmitry Fomichev <dmitry.fomichev@wdc.com> |
10 | --export type=nbd,id=nbd-l1-1,node-name=l1-1,name=l1-1,writable=on \ | 11 | Acked-by: Kevin Wolf <kwolf@redhat.com> |
11 | --export type=nbd,id=nbd-l1-2,node-name=l1-2,name=l1-2,writable=on | 12 | Message-id: 20230324090605.28361-5-faithilikerun@gmail.com |
12 | 13 | [Adjust commit message prefix as suggested by Philippe Mathieu-Daudé | |
13 | qemu-storage-daemon: --export type=nbd,id=nbd-l1-1,node-name=l1-1,name=l1-1,writable=on: Permission conflict on node 'nvme0': permissions 'resize' are both required by node 'l1-1' (uses node 'nvme0' as 'file' child) and unshared by node 'l1-2' (uses node 'nvme0' as 'file' child). | 14 | <philmd@linaro.org>. |
14 | 15 | --Stefan] | |
15 | The problem is that block/raw-format.c relies on bdrv_default_perms() to | ||
16 | set permissions on the nvme node. The default permissions add RESIZE in | ||
17 | anticipation of a format driver like qcow2 that needs to grow the image | ||
18 | file. This fails because RESIZE is unshared, so we cannot get the RESIZE | ||
19 | permission. | ||
20 | |||
21 | Max Reitz pointed out that block/crypto.c already handles this case by | ||
22 | implementing a custom ->bdrv_child_perm() function that adjusts the | ||
23 | result of bdrv_default_perms(). | ||
24 | |||
25 | This patch takes the same approach in block/raw-format.c so that RESIZE | ||
26 | is only required if it's actually necessary (e.g. the parent is qcow2). | ||
27 | |||
28 | Cc: Max Reitz <mreitz@redhat.com> | ||
29 | Cc: Kevin Wolf <kwolf@redhat.com> | ||
30 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> | 16 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> |
31 | Message-Id: <20210726122839.822900-1-stefanha@redhat.com> | ||
32 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
33 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
34 | --- | 17 | --- |
35 | block/raw-format.c | 21 ++++++++++++++++++++- | 18 | block/raw-format.c | 17 +++++++++++++++++ |
36 | 1 file changed, 20 insertions(+), 1 deletion(-) | 19 | 1 file changed, 17 insertions(+) |
37 | 20 | ||
38 | diff --git a/block/raw-format.c b/block/raw-format.c | 21 | diff --git a/block/raw-format.c b/block/raw-format.c |
39 | index XXXXXXX..XXXXXXX 100644 | 22 | index XXXXXXX..XXXXXXX 100644 |
40 | --- a/block/raw-format.c | 23 | --- a/block/raw-format.c |
41 | +++ b/block/raw-format.c | 24 | +++ b/block/raw-format.c |
42 | @@ -XXX,XX +XXX,XX @@ static void raw_cancel_in_flight(BlockDriverState *bs) | 25 | @@ -XXX,XX +XXX,XX @@ raw_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes) |
43 | bdrv_cancel_in_flight(bs->file->bs); | 26 | return bdrv_co_pdiscard(bs->file, offset, bytes); |
44 | } | 27 | } |
45 | 28 | ||
46 | +static void raw_child_perm(BlockDriverState *bs, BdrvChild *c, | 29 | +static int coroutine_fn GRAPH_RDLOCK |
47 | + BdrvChildRole role, | 30 | +raw_co_zone_report(BlockDriverState *bs, int64_t offset, |
48 | + BlockReopenQueue *reopen_queue, | 31 | + unsigned int *nr_zones, |
49 | + uint64_t parent_perm, uint64_t parent_shared, | 32 | + BlockZoneDescriptor *zones) |
50 | + uint64_t *nperm, uint64_t *nshared) | ||
51 | +{ | 33 | +{ |
52 | + bdrv_default_perms(bs, c, role, reopen_queue, parent_perm, | 34 | + return bdrv_co_zone_report(bs->file->bs, offset, nr_zones, zones); |
53 | + parent_shared, nperm, nshared); | ||
54 | + | ||
55 | + /* | ||
56 | + * bdrv_default_perms() may add WRITE and/or RESIZE (see comment in | ||
57 | + * bdrv_default_perms_for_storage() for an explanation) but we only need | ||
58 | + * them if they are in parent_perm. Drop WRITE and RESIZE whenever possible | ||
59 | + * to avoid permission conflicts. | ||
60 | + */ | ||
61 | + *nperm &= ~(BLK_PERM_WRITE | BLK_PERM_RESIZE); | ||
62 | + *nperm |= parent_perm & (BLK_PERM_WRITE | BLK_PERM_RESIZE); | ||
63 | +} | 35 | +} |
64 | + | 36 | + |
65 | BlockDriver bdrv_raw = { | 37 | +static int coroutine_fn GRAPH_RDLOCK |
66 | .format_name = "raw", | 38 | +raw_co_zone_mgmt(BlockDriverState *bs, BlockZoneOp op, |
67 | .instance_size = sizeof(BDRVRawState), | 39 | + int64_t offset, int64_t len) |
40 | +{ | ||
41 | + return bdrv_co_zone_mgmt(bs->file->bs, op, offset, len); | ||
42 | +} | ||
43 | + | ||
44 | static int64_t coroutine_fn GRAPH_RDLOCK | ||
45 | raw_co_getlength(BlockDriverState *bs) | ||
46 | { | ||
68 | @@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_raw = { | 47 | @@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_raw = { |
69 | .bdrv_reopen_commit = &raw_reopen_commit, | ||
70 | .bdrv_reopen_abort = &raw_reopen_abort, | ||
71 | .bdrv_open = &raw_open, | ||
72 | - .bdrv_child_perm = bdrv_default_perms, | ||
73 | + .bdrv_child_perm = raw_child_perm, | ||
74 | .bdrv_co_create_opts = &raw_co_create_opts, | ||
75 | .bdrv_co_preadv = &raw_co_preadv, | ||
76 | .bdrv_co_pwritev = &raw_co_pwritev, | 48 | .bdrv_co_pwritev = &raw_co_pwritev, |
49 | .bdrv_co_pwrite_zeroes = &raw_co_pwrite_zeroes, | ||
50 | .bdrv_co_pdiscard = &raw_co_pdiscard, | ||
51 | + .bdrv_co_zone_report = &raw_co_zone_report, | ||
52 | + .bdrv_co_zone_mgmt = &raw_co_zone_mgmt, | ||
53 | .bdrv_co_block_status = &raw_co_block_status, | ||
54 | .bdrv_co_copy_range_from = &raw_co_copy_range_from, | ||
55 | .bdrv_co_copy_range_to = &raw_co_copy_range_to, | ||
77 | -- | 56 | -- |
78 | 2.31.1 | 57 | 2.39.2 |
79 | 58 | ||
80 | 59 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: John Snow <jsnow@redhat.com> | ||
2 | 1 | ||
3 | Silences a new pylint warning. The dangers of *not* doing this are | ||
4 | somewhat unclear; I believe the file object gets garbage collected | ||
5 | eventually, but possibly the way in which it happens is | ||
6 | non-deterministic. Maybe this is a valid warning, but if there are | ||
7 | consequences of not doing it, I am not aware of them at present. | ||
8 | |||
9 | Signed-off-by: John Snow <jsnow@redhat.com> | ||
10 | Message-Id: <20210720173336.1876937-2-jsnow@redhat.com> | ||
11 | Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> | ||
12 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
13 | --- | ||
14 | tests/qemu-iotests/iotests.py | 7 ++++--- | ||
15 | 1 file changed, 4 insertions(+), 3 deletions(-) | ||
16 | |||
17 | diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py | ||
18 | index XXXXXXX..XXXXXXX 100644 | ||
19 | --- a/tests/qemu-iotests/iotests.py | ||
20 | +++ b/tests/qemu-iotests/iotests.py | ||
21 | @@ -XXX,XX +XXX,XX @@ def notrun(reason): | ||
22 | # Each test in qemu-iotests has a number ("seq") | ||
23 | seq = os.path.basename(sys.argv[0]) | ||
24 | |||
25 | - open('%s/%s.notrun' % (output_dir, seq), 'w').write(reason + '\n') | ||
26 | + with open('%s/%s.notrun' % (output_dir, seq), 'w') as outfile: | ||
27 | + outfile.write(reason + '\n') | ||
28 | logger.warning("%s not run: %s", seq, reason) | ||
29 | sys.exit(0) | ||
30 | |||
31 | @@ -XXX,XX +XXX,XX @@ def case_notrun(reason): | ||
32 | # Each test in qemu-iotests has a number ("seq") | ||
33 | seq = os.path.basename(sys.argv[0]) | ||
34 | |||
35 | - open('%s/%s.casenotrun' % (output_dir, seq), 'a').write( | ||
36 | - ' [case not run] ' + reason + '\n') | ||
37 | + with open('%s/%s.casenotrun' % (output_dir, seq), 'a') as outfile: | ||
38 | + outfile.write(' [case not run] ' + reason + '\n') | ||
39 | |||
40 | def _verify_image_format(supported_fmts: Sequence[str] = (), | ||
41 | unsupported_fmts: Sequence[str] = ()) -> None: | ||
42 | -- | ||
43 | 2.31.1 | ||
44 | |||
45 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: John Snow <jsnow@redhat.com> | ||
2 | 1 | ||
3 | Avoids a warning from pylint not to use open() outside of a | ||
4 | with-statement, and is ... probably more portable anyway. Not that I | ||
5 | think we care too much about running tests *on* Windows, but... eh. | ||
6 | |||
7 | Signed-off-by: John Snow <jsnow@redhat.com> | ||
8 | Message-Id: <20210720173336.1876937-3-jsnow@redhat.com> | ||
9 | Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> | ||
10 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
11 | --- | ||
12 | tests/qemu-iotests/iotests.py | 14 +++++++------- | ||
13 | 1 file changed, 7 insertions(+), 7 deletions(-) | ||
14 | |||
15 | diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py | ||
16 | index XXXXXXX..XXXXXXX 100644 | ||
17 | --- a/tests/qemu-iotests/iotests.py | ||
18 | +++ b/tests/qemu-iotests/iotests.py | ||
19 | @@ -XXX,XX +XXX,XX @@ def qemu_io_silent(*args): | ||
20 | default_args = qemu_io_args | ||
21 | |||
22 | args = default_args + list(args) | ||
23 | - exitcode = subprocess.call(args, stdout=open('/dev/null', 'w')) | ||
24 | - if exitcode < 0: | ||
25 | + result = subprocess.run(args, stdout=subprocess.DEVNULL, check=False) | ||
26 | + if result.returncode < 0: | ||
27 | sys.stderr.write('qemu-io received signal %i: %s\n' % | ||
28 | - (-exitcode, ' '.join(args))) | ||
29 | - return exitcode | ||
30 | + (-result.returncode, ' '.join(args))) | ||
31 | + return result.returncode | ||
32 | |||
33 | def qemu_io_silent_check(*args): | ||
34 | '''Run qemu-io and return the true if subprocess returned 0''' | ||
35 | args = qemu_io_args + list(args) | ||
36 | - exitcode = subprocess.call(args, stdout=open('/dev/null', 'w'), | ||
37 | - stderr=subprocess.STDOUT) | ||
38 | - return exitcode == 0 | ||
39 | + result = subprocess.run(args, stdout=subprocess.DEVNULL, | ||
40 | + stderr=subprocess.STDOUT, check=False) | ||
41 | + return result.returncode == 0 | ||
42 | |||
43 | class QemuIoInteractive: | ||
44 | def __init__(self, *args): | ||
45 | -- | ||
46 | 2.31.1 | ||
47 | |||
48 | diff view generated by jsdifflib |
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 1 | From: Sam Li <faithilikerun@gmail.com> |
---|---|---|---|
2 | 2 | ||
3 | We need an ability to insert filters above top block node, attached to | 3 | Putting zoned/non-zoned BlockDrivers on top of each other is not |
4 | block device. It can't be achieved with blockdev-reopen command. So, we | 4 | allowed. |
5 | want do it with help of qom-set. | ||
6 | 5 | ||
7 | Intended usage: | 6 | Signed-off-by: Sam Li <faithilikerun@gmail.com> |
7 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
8 | Reviewed-by: Hannes Reinecke <hare@suse.de> | ||
9 | Reviewed-by: Dmitry Fomichev <dmitry.fomichev@wdc.com> | ||
10 | Acked-by: Kevin Wolf <kwolf@redhat.com> | ||
11 | Message-id: 20230324090605.28361-6-faithilikerun@gmail.com | ||
12 | [Adjust commit message prefix as suggested by Philippe Mathieu-Daudé | ||
13 | <philmd@linaro.org> and clarify that the check is about zoned | ||
14 | BlockDrivers. | ||
15 | --Stefan] | ||
16 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
17 | --- | ||
18 | include/block/block_int-common.h | 5 +++++ | ||
19 | block.c | 19 +++++++++++++++++++ | ||
20 | block/file-posix.c | 12 ++++++++++++ | ||
21 | block/raw-format.c | 1 + | ||
22 | 4 files changed, 37 insertions(+) | ||
8 | 23 | ||
9 | Assume there is a node A that is attached to some guest device. | 24 | diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h |
10 | |||
11 | 1. blockdev-add to create a filter node B that has A as its child. | ||
12 | |||
13 | 2. qom-set to change the node attached to the guest device’s | ||
14 | BlockBackend from A to B. | ||
15 | |||
16 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
17 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
18 | Message-Id: <20210824083856.17408-5-vsementsov@virtuozzo.com> | ||
19 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
20 | --- | ||
21 | hw/core/qdev-properties-system.c | 43 +++++++++++++++++++++++--------- | ||
22 | 1 file changed, 31 insertions(+), 12 deletions(-) | ||
23 | |||
24 | diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c | ||
25 | index XXXXXXX..XXXXXXX 100644 | 25 | index XXXXXXX..XXXXXXX 100644 |
26 | --- a/hw/core/qdev-properties-system.c | 26 | --- a/include/block/block_int-common.h |
27 | +++ b/hw/core/qdev-properties-system.c | 27 | +++ b/include/block/block_int-common.h |
28 | @@ -XXX,XX +XXX,XX @@ | 28 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { |
29 | 29 | */ | |
30 | static bool check_prop_still_unset(Object *obj, const char *name, | 30 | bool is_format; |
31 | const void *old_val, const char *new_val, | 31 | |
32 | - Error **errp) | 32 | + /* |
33 | + bool allow_override, Error **errp) | 33 | + * Set to true if the BlockDriver supports zoned children. |
34 | { | 34 | + */ |
35 | const GlobalProperty *prop = qdev_find_global_prop(obj, name); | 35 | + bool supports_zoned_children; |
36 | 36 | + | |
37 | - if (!old_val) { | 37 | /* |
38 | + if (!old_val || (!prop && allow_override)) { | 38 | * Drivers not implementing bdrv_parse_filename nor bdrv_open should have |
39 | return true; | 39 | * this field set to true, except ones that are defined only by their |
40 | } | 40 | diff --git a/block.c b/block.c |
41 | 41 | index XXXXXXX..XXXXXXX 100644 | |
42 | @@ -XXX,XX +XXX,XX @@ static void set_drive_helper(Object *obj, Visitor *v, const char *name, | 42 | --- a/block.c |
43 | BlockBackend *blk; | 43 | +++ b/block.c |
44 | bool blk_created = false; | 44 | @@ -XXX,XX +XXX,XX @@ void bdrv_add_child(BlockDriverState *parent_bs, BlockDriverState *child_bs, |
45 | int ret; | ||
46 | + BlockDriverState *bs; | ||
47 | + AioContext *ctx; | ||
48 | |||
49 | if (!visit_type_str(v, name, &str, errp)) { | ||
50 | return; | 45 | return; |
51 | } | 46 | } |
52 | 47 | ||
53 | - /* | 48 | + /* |
54 | - * TODO Should this really be an error? If no, the old value | 49 | + * Non-zoned block drivers do not follow zoned storage constraints |
55 | - * needs to be released before we store the new one. | 50 | + * (i.e. sequential writes to zones). Refuse mixing zoned and non-zoned |
56 | - */ | 51 | + * drivers in a graph. |
57 | - if (!check_prop_still_unset(obj, name, *ptr, str, errp)) { | 52 | + */ |
58 | + if (!check_prop_still_unset(obj, name, *ptr, str, true, errp)) { | 53 | + if (!parent_bs->drv->supports_zoned_children && |
54 | + child_bs->bl.zoned == BLK_Z_HM) { | ||
55 | + /* | ||
56 | + * The host-aware model allows zoned storage constraints and random | ||
57 | + * write. Allow mixing host-aware and non-zoned drivers. Using | ||
58 | + * host-aware device as a regular device. | ||
59 | + */ | ||
60 | + error_setg(errp, "Cannot add a %s child to a %s parent", | ||
61 | + child_bs->bl.zoned == BLK_Z_HM ? "zoned" : "non-zoned", | ||
62 | + parent_bs->drv->supports_zoned_children ? | ||
63 | + "support zoned children" : "not support zoned children"); | ||
59 | + return; | 64 | + return; |
60 | + } | 65 | + } |
61 | + | 66 | + |
62 | + if (*ptr) { | 67 | if (!QLIST_EMPTY(&child_bs->parents)) { |
63 | + /* BlockBackend alread exists. So, we want to change attached node */ | 68 | error_setg(errp, "The node %s already has a parent", |
64 | + blk = *ptr; | 69 | child_bs->node_name); |
65 | + ctx = blk_get_aio_context(blk); | 70 | diff --git a/block/file-posix.c b/block/file-posix.c |
66 | + bs = bdrv_lookup_bs(NULL, str, errp); | 71 | index XXXXXXX..XXXXXXX 100644 |
67 | + if (!bs) { | 72 | --- a/block/file-posix.c |
68 | + return; | 73 | +++ b/block/file-posix.c |
69 | + } | 74 | @@ -XXX,XX +XXX,XX @@ static int raw_open_common(BlockDriverState *bs, QDict *options, |
70 | + | 75 | goto fail; |
71 | + if (ctx != bdrv_get_aio_context(bs)) { | 76 | } |
72 | + error_setg(errp, "Different aio context is not supported for new " | ||
73 | + "node"); | ||
74 | + } | ||
75 | + | ||
76 | + aio_context_acquire(ctx); | ||
77 | + blk_replace_bs(blk, bs, errp); | ||
78 | + aio_context_release(ctx); | ||
79 | return; | ||
80 | } | 77 | } |
81 | 78 | +#ifdef CONFIG_BLKZONED | |
82 | @@ -XXX,XX +XXX,XX @@ static void set_drive_helper(Object *obj, Visitor *v, const char *name, | 79 | + /* |
83 | 80 | + * The kernel page cache does not reliably work for writes to SWR zones | |
84 | blk = blk_by_name(str); | 81 | + * of zoned block device because it can not guarantee the order of writes. |
85 | if (!blk) { | 82 | + */ |
86 | - BlockDriverState *bs = bdrv_lookup_bs(NULL, str, NULL); | 83 | + if ((bs->bl.zoned != BLK_Z_NONE) && |
87 | + bs = bdrv_lookup_bs(NULL, str, NULL); | 84 | + (!(s->open_flags & O_DIRECT))) { |
88 | if (bs) { | 85 | + error_setg(errp, "The driver supports zoned devices, and it requires " |
89 | /* | 86 | + "cache.direct=on, which was not specified."); |
90 | * If the device supports iothreads, it will make sure to move the | 87 | + return -EINVAL; /* No host kernel page cache */ |
91 | @@ -XXX,XX +XXX,XX @@ static void set_drive_helper(Object *obj, Visitor *v, const char *name, | 88 | + } |
92 | * aware of iothreads require their BlockBackends to be in the main | 89 | +#endif |
93 | * AioContext. | 90 | |
94 | */ | 91 | if (S_ISBLK(st.st_mode)) { |
95 | - AioContext *ctx = iothread ? bdrv_get_aio_context(bs) : | 92 | #ifdef __linux__ |
96 | - qemu_get_aio_context(); | 93 | diff --git a/block/raw-format.c b/block/raw-format.c |
97 | + ctx = iothread ? bdrv_get_aio_context(bs) : qemu_get_aio_context(); | 94 | index XXXXXXX..XXXXXXX 100644 |
98 | blk = blk_new(ctx, 0, BLK_PERM_ALL); | 95 | --- a/block/raw-format.c |
99 | blk_created = true; | 96 | +++ b/block/raw-format.c |
100 | 97 | @@ -XXX,XX +XXX,XX @@ static void raw_child_perm(BlockDriverState *bs, BdrvChild *c, | |
101 | @@ -XXX,XX +XXX,XX @@ static void release_drive(Object *obj, const char *name, void *opaque) | 98 | BlockDriver bdrv_raw = { |
102 | const PropertyInfo qdev_prop_drive = { | 99 | .format_name = "raw", |
103 | .name = "str", | 100 | .instance_size = sizeof(BDRVRawState), |
104 | .description = "Node name or ID of a block device to use as a backend", | 101 | + .supports_zoned_children = true, |
105 | + .realized_set_allowed = true, | 102 | .bdrv_probe = &raw_probe, |
106 | .get = get_drive, | 103 | .bdrv_reopen_prepare = &raw_reopen_prepare, |
107 | .set = set_drive, | 104 | .bdrv_reopen_commit = &raw_reopen_commit, |
108 | .release = release_drive, | ||
109 | @@ -XXX,XX +XXX,XX @@ const PropertyInfo qdev_prop_drive = { | ||
110 | const PropertyInfo qdev_prop_drive_iothread = { | ||
111 | .name = "str", | ||
112 | .description = "Node name or ID of a block device to use as a backend", | ||
113 | + .realized_set_allowed = true, | ||
114 | .get = get_drive, | ||
115 | .set = set_drive_iothread, | ||
116 | .release = release_drive, | ||
117 | @@ -XXX,XX +XXX,XX @@ static void set_chr(Object *obj, Visitor *v, const char *name, void *opaque, | ||
118 | * TODO Should this really be an error? If no, the old value | ||
119 | * needs to be released before we store the new one. | ||
120 | */ | ||
121 | - if (!check_prop_still_unset(obj, name, be->chr, str, errp)) { | ||
122 | + if (!check_prop_still_unset(obj, name, be->chr, str, false, errp)) { | ||
123 | return; | ||
124 | } | ||
125 | |||
126 | @@ -XXX,XX +XXX,XX @@ static void set_netdev(Object *obj, Visitor *v, const char *name, | ||
127 | * TODO Should this really be an error? If no, the old value | ||
128 | * needs to be released before we store the new one. | ||
129 | */ | ||
130 | - if (!check_prop_still_unset(obj, name, ncs[i], str, errp)) { | ||
131 | + if (!check_prop_still_unset(obj, name, ncs[i], str, false, errp)) { | ||
132 | goto out; | ||
133 | } | ||
134 | |||
135 | -- | 105 | -- |
136 | 2.31.1 | 106 | 2.39.2 |
137 | 107 | ||
138 | 108 | diff view generated by jsdifflib |
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 1 | From: Sam Li <faithilikerun@gmail.com> |
---|---|---|---|
2 | 2 | ||
3 | We are going to add a test-case with some behavior modifications. So, | 3 | The new block layer APIs of zoned block devices can be tested by: |
4 | let's prepare a function to be reused. | 4 | $ tests/qemu-iotests/check zoned |
5 | Run each zone operation on a newly created null_blk device | ||
6 | and see whether it outputs the same zone information. | ||
5 | 7 | ||
6 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 8 | Signed-off-by: Sam Li <faithilikerun@gmail.com> |
7 | Reviewed-by: Max Reitz <mreitz@redhat.com> | 9 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> |
8 | Message-Id: <20210824083856.17408-33-vsementsov@virtuozzo.com> | 10 | Acked-by: Kevin Wolf <kwolf@redhat.com> |
9 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | 11 | Message-id: 20230324090605.28361-7-faithilikerun@gmail.com |
12 | [Adjust commit message prefix as suggested by Philippe Mathieu-Daudé | ||
13 | <philmd@linaro.org>. | ||
14 | --Stefan] | ||
15 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
10 | --- | 16 | --- |
11 | tests/qemu-iotests/tests/image-fleecing | 19 +++++++++++++------ | 17 | tests/qemu-iotests/tests/zoned | 89 ++++++++++++++++++++++++++++++ |
12 | 1 file changed, 13 insertions(+), 6 deletions(-) | 18 | tests/qemu-iotests/tests/zoned.out | 53 ++++++++++++++++++ |
19 | 2 files changed, 142 insertions(+) | ||
20 | create mode 100755 tests/qemu-iotests/tests/zoned | ||
21 | create mode 100644 tests/qemu-iotests/tests/zoned.out | ||
13 | 22 | ||
14 | diff --git a/tests/qemu-iotests/tests/image-fleecing b/tests/qemu-iotests/tests/image-fleecing | 23 | diff --git a/tests/qemu-iotests/tests/zoned b/tests/qemu-iotests/tests/zoned |
15 | index XXXXXXX..XXXXXXX 100755 | 24 | new file mode 100755 |
16 | --- a/tests/qemu-iotests/tests/image-fleecing | 25 | index XXXXXXX..XXXXXXX |
17 | +++ b/tests/qemu-iotests/tests/image-fleecing | 26 | --- /dev/null |
18 | @@ -XXX,XX +XXX,XX @@ remainder = [('0xd5', '0x108000', '32k'), # Right-end of partial-left [1] | 27 | +++ b/tests/qemu-iotests/tests/zoned |
19 | ('0xdc', '32M', '32k'), # Left-end of partial-right [2] | 28 | @@ -XXX,XX +XXX,XX @@ |
20 | ('0xcd', '0x3ff0000', '64k')] # patterns[3] | 29 | +#!/usr/bin/env bash |
21 | 30 | +# | |
22 | -with iotests.FilePath('base.img') as base_img_path, \ | 31 | +# Test zone management operations. |
23 | - iotests.FilePath('fleece.img') as fleece_img_path, \ | 32 | +# |
24 | - iotests.FilePath('nbd.sock', | 33 | + |
25 | - base_dir=iotests.sock_dir) as nbd_sock_path, \ | 34 | +seq="$(basename $0)" |
26 | - iotests.VM() as vm: | 35 | +echo "QA output created by $seq" |
27 | - | 36 | +status=1 # failure is the default! |
28 | +def do_test(base_img_path, fleece_img_path, nbd_sock_path, vm): | 37 | + |
29 | log('--- Setting up images ---') | 38 | +_cleanup() |
30 | log('') | 39 | +{ |
31 | 40 | + _cleanup_test_img | |
32 | @@ -XXX,XX +XXX,XX @@ with iotests.FilePath('base.img') as base_img_path, \ | 41 | + sudo -n rmmod null_blk |
33 | 42 | +} | |
34 | log('') | 43 | +trap "_cleanup; exit \$status" 0 1 2 3 15 |
35 | log('Done') | 44 | + |
45 | +# get standard environment, filters and checks | ||
46 | +. ../common.rc | ||
47 | +. ../common.filter | ||
48 | +. ../common.qemu | ||
49 | + | ||
50 | +# This test only runs on Linux hosts with raw image files. | ||
51 | +_supported_fmt raw | ||
52 | +_supported_proto file | ||
53 | +_supported_os Linux | ||
54 | + | ||
55 | +sudo -n true || \ | ||
56 | + _notrun 'Password-less sudo required' | ||
57 | + | ||
58 | +IMG="--image-opts -n driver=host_device,filename=/dev/nullb0" | ||
59 | +QEMU_IO_OPTIONS=$QEMU_IO_OPTIONS_NO_FMT | ||
60 | + | ||
61 | +echo "Testing a null_blk device:" | ||
62 | +echo "case 1: if the operations work" | ||
63 | +sudo -n modprobe null_blk nr_devices=1 zoned=1 | ||
64 | +sudo -n chmod 0666 /dev/nullb0 | ||
65 | + | ||
66 | +echo "(1) report the first zone:" | ||
67 | +$QEMU_IO $IMG -c "zrp 0 1" | ||
68 | +echo | ||
69 | +echo "report the first 10 zones" | ||
70 | +$QEMU_IO $IMG -c "zrp 0 10" | ||
71 | +echo | ||
72 | +echo "report the last zone:" | ||
73 | +$QEMU_IO $IMG -c "zrp 0x3e70000000 2" # 0x3e70000000 / 512 = 0x1f380000 | ||
74 | +echo | ||
75 | +echo | ||
76 | +echo "(2) opening the first zone" | ||
77 | +$QEMU_IO $IMG -c "zo 0 268435456" # 268435456 / 512 = 524288 | ||
78 | +echo "report after:" | ||
79 | +$QEMU_IO $IMG -c "zrp 0 1" | ||
80 | +echo | ||
81 | +echo "opening the second zone" | ||
82 | +$QEMU_IO $IMG -c "zo 268435456 268435456" # | ||
83 | +echo "report after:" | ||
84 | +$QEMU_IO $IMG -c "zrp 268435456 1" | ||
85 | +echo | ||
86 | +echo "opening the last zone" | ||
87 | +$QEMU_IO $IMG -c "zo 0x3e70000000 268435456" | ||
88 | +echo "report after:" | ||
89 | +$QEMU_IO $IMG -c "zrp 0x3e70000000 2" | ||
90 | +echo | ||
91 | +echo | ||
92 | +echo "(3) closing the first zone" | ||
93 | +$QEMU_IO $IMG -c "zc 0 268435456" | ||
94 | +echo "report after:" | ||
95 | +$QEMU_IO $IMG -c "zrp 0 1" | ||
96 | +echo | ||
97 | +echo "closing the last zone" | ||
98 | +$QEMU_IO $IMG -c "zc 0x3e70000000 268435456" | ||
99 | +echo "report after:" | ||
100 | +$QEMU_IO $IMG -c "zrp 0x3e70000000 2" | ||
101 | +echo | ||
102 | +echo | ||
103 | +echo "(4) finishing the second zone" | ||
104 | +$QEMU_IO $IMG -c "zf 268435456 268435456" | ||
105 | +echo "After finishing a zone:" | ||
106 | +$QEMU_IO $IMG -c "zrp 268435456 1" | ||
107 | +echo | ||
108 | +echo | ||
109 | +echo "(5) resetting the second zone" | ||
110 | +$QEMU_IO $IMG -c "zrs 268435456 268435456" | ||
111 | +echo "After resetting a zone:" | ||
112 | +$QEMU_IO $IMG -c "zrp 268435456 1" | ||
113 | + | ||
114 | +# success, all done | ||
115 | +echo "*** done" | ||
116 | +rm -f $seq.full | ||
117 | +status=0 | ||
118 | diff --git a/tests/qemu-iotests/tests/zoned.out b/tests/qemu-iotests/tests/zoned.out | ||
119 | new file mode 100644 | ||
120 | index XXXXXXX..XXXXXXX | ||
121 | --- /dev/null | ||
122 | +++ b/tests/qemu-iotests/tests/zoned.out | ||
123 | @@ -XXX,XX +XXX,XX @@ | ||
124 | +QA output created by zoned | ||
125 | +Testing a null_blk device: | ||
126 | +case 1: if the operations work | ||
127 | +(1) report the first zone: | ||
128 | +start: 0x0, len 0x80000, cap 0x80000, wptr 0x0, zcond:1, [type: 2] | ||
129 | + | ||
130 | +report the first 10 zones | ||
131 | +start: 0x0, len 0x80000, cap 0x80000, wptr 0x0, zcond:1, [type: 2] | ||
132 | +start: 0x80000, len 0x80000, cap 0x80000, wptr 0x80000, zcond:1, [type: 2] | ||
133 | +start: 0x100000, len 0x80000, cap 0x80000, wptr 0x100000, zcond:1, [type: 2] | ||
134 | +start: 0x180000, len 0x80000, cap 0x80000, wptr 0x180000, zcond:1, [type: 2] | ||
135 | +start: 0x200000, len 0x80000, cap 0x80000, wptr 0x200000, zcond:1, [type: 2] | ||
136 | +start: 0x280000, len 0x80000, cap 0x80000, wptr 0x280000, zcond:1, [type: 2] | ||
137 | +start: 0x300000, len 0x80000, cap 0x80000, wptr 0x300000, zcond:1, [type: 2] | ||
138 | +start: 0x380000, len 0x80000, cap 0x80000, wptr 0x380000, zcond:1, [type: 2] | ||
139 | +start: 0x400000, len 0x80000, cap 0x80000, wptr 0x400000, zcond:1, [type: 2] | ||
140 | +start: 0x480000, len 0x80000, cap 0x80000, wptr 0x480000, zcond:1, [type: 2] | ||
141 | + | ||
142 | +report the last zone: | ||
143 | +start: 0x1f380000, len 0x80000, cap 0x80000, wptr 0x1f380000, zcond:1, [type: 2] | ||
36 | + | 144 | + |
37 | + | 145 | + |
38 | +def test(): | 146 | +(2) opening the first zone |
39 | + with iotests.FilePath('base.img') as base_img_path, \ | 147 | +report after: |
40 | + iotests.FilePath('fleece.img') as fleece_img_path, \ | 148 | +start: 0x0, len 0x80000, cap 0x80000, wptr 0x0, zcond:3, [type: 2] |
41 | + iotests.FilePath('nbd.sock', | 149 | + |
42 | + base_dir=iotests.sock_dir) as nbd_sock_path, \ | 150 | +opening the second zone |
43 | + iotests.VM() as vm: | 151 | +report after: |
44 | + do_test(base_img_path, fleece_img_path, nbd_sock_path, vm) | 152 | +start: 0x80000, len 0x80000, cap 0x80000, wptr 0x80000, zcond:3, [type: 2] |
153 | + | ||
154 | +opening the last zone | ||
155 | +report after: | ||
156 | +start: 0x1f380000, len 0x80000, cap 0x80000, wptr 0x1f380000, zcond:3, [type: 2] | ||
45 | + | 157 | + |
46 | + | 158 | + |
47 | +test() | 159 | +(3) closing the first zone |
160 | +report after: | ||
161 | +start: 0x0, len 0x80000, cap 0x80000, wptr 0x0, zcond:1, [type: 2] | ||
162 | + | ||
163 | +closing the last zone | ||
164 | +report after: | ||
165 | +start: 0x1f380000, len 0x80000, cap 0x80000, wptr 0x1f380000, zcond:1, [type: 2] | ||
166 | + | ||
167 | + | ||
168 | +(4) finishing the second zone | ||
169 | +After finishing a zone: | ||
170 | +start: 0x80000, len 0x80000, cap 0x80000, wptr 0x100000, zcond:14, [type: 2] | ||
171 | + | ||
172 | + | ||
173 | +(5) resetting the second zone | ||
174 | +After resetting a zone: | ||
175 | +start: 0x80000, len 0x80000, cap 0x80000, wptr 0x80000, zcond:1, [type: 2] | ||
176 | +*** done | ||
48 | -- | 177 | -- |
49 | 2.31.1 | 178 | 2.39.2 |
50 | 179 | ||
51 | 180 | diff view generated by jsdifflib |
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 1 | From: Sam Li <faithilikerun@gmail.com> |
---|---|---|---|
2 | 2 | ||
3 | The only caller pass copy_range and compress both false. Let's just | 3 | Signed-off-by: Sam Li <faithilikerun@gmail.com> |
4 | drop these arguments. | 4 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> |
5 | Reviewed-by: Dmitry Fomichev <dmitry.fomichev@wdc.com> | ||
6 | Acked-by: Kevin Wolf <kwolf@redhat.com> | ||
7 | Message-id: 20230324090605.28361-8-faithilikerun@gmail.com | ||
8 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
9 | --- | ||
10 | block/file-posix.c | 3 +++ | ||
11 | block/trace-events | 2 ++ | ||
12 | 2 files changed, 5 insertions(+) | ||
5 | 13 | ||
6 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 14 | diff --git a/block/file-posix.c b/block/file-posix.c |
7 | Message-Id: <20210824083856.17408-35-vsementsov@virtuozzo.com> | ||
8 | Reviewed-by: Hanna Reitz <hreitz@redhat.com> | ||
9 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
10 | --- | ||
11 | include/block/block-copy.h | 1 - | ||
12 | block/block-copy.c | 5 ++--- | ||
13 | block/copy-before-write.c | 2 +- | ||
14 | 3 files changed, 3 insertions(+), 5 deletions(-) | ||
15 | |||
16 | diff --git a/include/block/block-copy.h b/include/block/block-copy.h | ||
17 | index XXXXXXX..XXXXXXX 100644 | 15 | index XXXXXXX..XXXXXXX 100644 |
18 | --- a/include/block/block-copy.h | 16 | --- a/block/file-posix.c |
19 | +++ b/include/block/block-copy.h | 17 | +++ b/block/file-posix.c |
20 | @@ -XXX,XX +XXX,XX @@ typedef struct BlockCopyState BlockCopyState; | 18 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_zone_report(BlockDriverState *bs, int64_t offset, |
21 | typedef struct BlockCopyCallState BlockCopyCallState; | 19 | }, |
22 | 20 | }; | |
23 | BlockCopyState *block_copy_state_new(BdrvChild *source, BdrvChild *target, | 21 | |
24 | - bool use_copy_range, bool compress, | 22 | + trace_zbd_zone_report(bs, *nr_zones, offset >> BDRV_SECTOR_BITS); |
25 | Error **errp); | 23 | return raw_thread_pool_submit(bs, handle_aiocb_zone_report, &acb); |
26 | 24 | } | |
27 | /* Function should be called prior any actual copy request */ | 25 | #endif |
28 | diff --git a/block/block-copy.c b/block/block-copy.c | 26 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_zone_mgmt(BlockDriverState *bs, BlockZoneOp op, |
27 | }, | ||
28 | }; | ||
29 | |||
30 | + trace_zbd_zone_mgmt(bs, op_name, offset >> BDRV_SECTOR_BITS, | ||
31 | + len >> BDRV_SECTOR_BITS); | ||
32 | ret = raw_thread_pool_submit(bs, handle_aiocb_zone_mgmt, &acb); | ||
33 | if (ret != 0) { | ||
34 | error_report("ioctl %s failed %d", op_name, ret); | ||
35 | diff --git a/block/trace-events b/block/trace-events | ||
29 | index XXXXXXX..XXXXXXX 100644 | 36 | index XXXXXXX..XXXXXXX 100644 |
30 | --- a/block/block-copy.c | 37 | --- a/block/trace-events |
31 | +++ b/block/block-copy.c | 38 | +++ b/block/trace-events |
32 | @@ -XXX,XX +XXX,XX @@ static int64_t block_copy_calculate_cluster_size(BlockDriverState *target, | 39 | @@ -XXX,XX +XXX,XX @@ file_FindEjectableOpticalMedia(const char *media) "Matching using %s" |
33 | } | 40 | file_setup_cdrom(const char *partition) "Using %s as optical disc" |
34 | 41 | file_hdev_is_sg(int type, int version) "SG device found: type=%d, version=%d" | |
35 | BlockCopyState *block_copy_state_new(BdrvChild *source, BdrvChild *target, | 42 | file_flush_fdatasync_failed(int err) "errno %d" |
36 | - bool use_copy_range, | 43 | +zbd_zone_report(void *bs, unsigned int nr_zones, int64_t sector) "bs %p report %d zones starting at sector offset 0x%" PRIx64 "" |
37 | - bool compress, Error **errp) | 44 | +zbd_zone_mgmt(void *bs, const char *op_name, int64_t sector, int64_t len) "bs %p %s starts at sector offset 0x%" PRIx64 " over a range of 0x%" PRIx64 " sectors" |
38 | + Error **errp) | 45 | |
39 | { | 46 | # ssh.c |
40 | BlockCopyState *s; | 47 | sftp_error(const char *op, const char *ssh_err, int ssh_err_code, int sftp_err_code) "%s failed: %s (libssh error code: %d, sftp error code: %d)" |
41 | int64_t cluster_size; | ||
42 | @@ -XXX,XX +XXX,XX @@ BlockCopyState *block_copy_state_new(BdrvChild *source, BdrvChild *target, | ||
43 | cluster_size), | ||
44 | }; | ||
45 | |||
46 | - block_copy_set_copy_opts(s, use_copy_range, compress); | ||
47 | + block_copy_set_copy_opts(s, false, false); | ||
48 | |||
49 | ratelimit_init(&s->rate_limit); | ||
50 | qemu_co_mutex_init(&s->lock); | ||
51 | diff --git a/block/copy-before-write.c b/block/copy-before-write.c | ||
52 | index XXXXXXX..XXXXXXX 100644 | ||
53 | --- a/block/copy-before-write.c | ||
54 | +++ b/block/copy-before-write.c | ||
55 | @@ -XXX,XX +XXX,XX @@ static int cbw_open(BlockDriverState *bs, QDict *options, int flags, | ||
56 | ((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK) & | ||
57 | bs->file->bs->supported_zero_flags); | ||
58 | |||
59 | - s->bcs = block_copy_state_new(bs->file, s->target, false, false, errp); | ||
60 | + s->bcs = block_copy_state_new(bs->file, s->target, errp); | ||
61 | if (!s->bcs) { | ||
62 | error_prepend(errp, "Cannot create block-copy-state: "); | ||
63 | return -EINVAL; | ||
64 | -- | 48 | -- |
65 | 2.31.1 | 49 | 2.39.2 |
66 | |||
67 | diff view generated by jsdifflib |
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 1 | From: Sam Li <faithilikerun@gmail.com> |
---|---|---|---|
2 | 2 | ||
3 | Define scsi device to operate with it by qom-set in further patch. | 3 | Add the documentation about the zoned device support to virtio-blk |
4 | emulation. | ||
4 | 5 | ||
5 | Give a new node-name to source block node, to not look like device | 6 | Signed-off-by: Sam Li <faithilikerun@gmail.com> |
6 | name. | 7 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> |
8 | Reviewed-by: Damien Le Moal <damien.lemoal@opensource.wdc.com> | ||
9 | Reviewed-by: Dmitry Fomichev <dmitry.fomichev@wdc.com> | ||
10 | Acked-by: Kevin Wolf <kwolf@redhat.com> | ||
11 | Message-id: 20230324090605.28361-9-faithilikerun@gmail.com | ||
12 | [Add index-api.rst to fix "zoned-storage.rst:document isn't included in | ||
13 | any toctree" error. | ||
14 | --Stefan] | ||
15 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
16 | --- | ||
17 | docs/devel/index-api.rst | 1 + | ||
18 | docs/devel/zoned-storage.rst | 43 ++++++++++++++++++++++++++ | ||
19 | docs/system/qemu-block-drivers.rst.inc | 6 ++++ | ||
20 | 3 files changed, 50 insertions(+) | ||
21 | create mode 100644 docs/devel/zoned-storage.rst | ||
7 | 22 | ||
8 | Job now don't want to work without giving explicit id, so, let's call | 23 | diff --git a/docs/devel/index-api.rst b/docs/devel/index-api.rst |
9 | it "fleecing". | ||
10 | |||
11 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
12 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
13 | Message-Id: <20210824083856.17408-31-vsementsov@virtuozzo.com> | ||
14 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
15 | --- | ||
16 | tests/qemu-iotests/tests/image-fleecing | 12 ++++++++---- | ||
17 | tests/qemu-iotests/tests/image-fleecing.out | 2 +- | ||
18 | 2 files changed, 9 insertions(+), 5 deletions(-) | ||
19 | |||
20 | diff --git a/tests/qemu-iotests/tests/image-fleecing b/tests/qemu-iotests/tests/image-fleecing | ||
21 | index XXXXXXX..XXXXXXX 100755 | ||
22 | --- a/tests/qemu-iotests/tests/image-fleecing | ||
23 | +++ b/tests/qemu-iotests/tests/image-fleecing | ||
24 | @@ -XXX,XX +XXX,XX @@ with iotests.FilePath('base.img') as base_img_path, \ | ||
25 | log('--- Launching VM ---') | ||
26 | log('') | ||
27 | |||
28 | - vm.add_drive(base_img_path) | ||
29 | + src_node = 'source' | ||
30 | + vm.add_blockdev(f'driver={iotests.imgfmt},file.driver=file,' | ||
31 | + f'file.filename={base_img_path},node-name={src_node}') | ||
32 | + vm.add_device('virtio-scsi') | ||
33 | + vm.add_device(f'scsi-hd,id=sda,drive={src_node}') | ||
34 | vm.launch() | ||
35 | log('Done') | ||
36 | |||
37 | @@ -XXX,XX +XXX,XX @@ with iotests.FilePath('base.img') as base_img_path, \ | ||
38 | log('--- Setting up Fleecing Graph ---') | ||
39 | log('') | ||
40 | |||
41 | - src_node = 'drive0' | ||
42 | tgt_node = 'fleeceNode' | ||
43 | |||
44 | # create tgt_node backed by src_node | ||
45 | @@ -XXX,XX +XXX,XX @@ with iotests.FilePath('base.img') as base_img_path, \ | ||
46 | |||
47 | # Establish COW from source to fleecing node | ||
48 | log(vm.qmp('blockdev-backup', | ||
49 | + job_id='fleecing', | ||
50 | device=src_node, | ||
51 | target=tgt_node, | ||
52 | sync='none')) | ||
53 | @@ -XXX,XX +XXX,XX @@ with iotests.FilePath('base.img') as base_img_path, \ | ||
54 | for p in overwrite: | ||
55 | cmd = 'write -P%s %s %s' % p | ||
56 | log(cmd) | ||
57 | - log(vm.hmp_qemu_io(src_node, cmd)) | ||
58 | + log(vm.hmp_qemu_io('/machine/peripheral/sda', cmd, qdev=True)) | ||
59 | |||
60 | log('') | ||
61 | log('--- Verifying Data ---') | ||
62 | @@ -XXX,XX +XXX,XX @@ with iotests.FilePath('base.img') as base_img_path, \ | ||
63 | log('--- Cleanup ---') | ||
64 | log('') | ||
65 | |||
66 | - log(vm.qmp('block-job-cancel', device=src_node)) | ||
67 | + log(vm.qmp('block-job-cancel', device='fleecing')) | ||
68 | e = vm.event_wait('BLOCK_JOB_CANCELLED') | ||
69 | assert e is not None | ||
70 | log(e, filters=[iotests.filter_qmp_event]) | ||
71 | diff --git a/tests/qemu-iotests/tests/image-fleecing.out b/tests/qemu-iotests/tests/image-fleecing.out | ||
72 | index XXXXXXX..XXXXXXX 100644 | 24 | index XXXXXXX..XXXXXXX 100644 |
73 | --- a/tests/qemu-iotests/tests/image-fleecing.out | 25 | --- a/docs/devel/index-api.rst |
74 | +++ b/tests/qemu-iotests/tests/image-fleecing.out | 26 | +++ b/docs/devel/index-api.rst |
75 | @@ -XXX,XX +XXX,XX @@ read -P0 0x3fe0000 64k | 27 | @@ -XXX,XX +XXX,XX @@ generated from in-code annotations to function prototypes. |
76 | --- Cleanup --- | 28 | memory |
77 | 29 | modules | |
78 | {"return": {}} | 30 | ui |
79 | -{"data": {"device": "drive0", "len": 67108864, "offset": 393216, "speed": 0, "type": "backup"}, "event": "BLOCK_JOB_CANCELLED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} | 31 | + zoned-storage |
80 | +{"data": {"device": "fleecing", "len": 67108864, "offset": 393216, "speed": 0, "type": "backup"}, "event": "BLOCK_JOB_CANCELLED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} | 32 | diff --git a/docs/devel/zoned-storage.rst b/docs/devel/zoned-storage.rst |
81 | {"return": {}} | 33 | new file mode 100644 |
82 | {"return": {}} | 34 | index XXXXXXX..XXXXXXX |
35 | --- /dev/null | ||
36 | +++ b/docs/devel/zoned-storage.rst | ||
37 | @@ -XXX,XX +XXX,XX @@ | ||
38 | +============= | ||
39 | +zoned-storage | ||
40 | +============= | ||
41 | + | ||
42 | +Zoned Block Devices (ZBDs) divide the LBA space into block regions called zones | ||
43 | +that are larger than the LBA size. They can only allow sequential writes, which | ||
44 | +can reduce write amplification in SSDs, and potentially lead to higher | ||
45 | +throughput and increased capacity. More details about ZBDs can be found at: | ||
46 | + | ||
47 | +https://zonedstorage.io/docs/introduction/zoned-storage | ||
48 | + | ||
49 | +1. Block layer APIs for zoned storage | ||
50 | +------------------------------------- | ||
51 | +QEMU block layer supports three zoned storage models: | ||
52 | +- BLK_Z_HM: The host-managed zoned model only allows sequential writes access | ||
53 | +to zones. It supports ZBD-specific I/O commands that can be used by a host to | ||
54 | +manage the zones of a device. | ||
55 | +- BLK_Z_HA: The host-aware zoned model allows random write operations in | ||
56 | +zones, making it backward compatible with regular block devices. | ||
57 | +- BLK_Z_NONE: The non-zoned model has no zones support. It includes both | ||
58 | +regular and drive-managed ZBD devices. ZBD-specific I/O commands are not | ||
59 | +supported. | ||
60 | + | ||
61 | +The block device information resides inside BlockDriverState. QEMU uses | ||
62 | +BlockLimits struct(BlockDriverState::bl) that is continuously accessed by the | ||
63 | +block layer while processing I/O requests. A BlockBackend has a root pointer to | ||
64 | +a BlockDriverState graph(for example, raw format on top of file-posix). The | ||
65 | +zoned storage information can be propagated from the leaf BlockDriverState all | ||
66 | +the way up to the BlockBackend. If the zoned storage model in file-posix is | ||
67 | +set to BLK_Z_HM, then block drivers will declare support for zoned host device. | ||
68 | + | ||
69 | +The block layer APIs support commands needed for zoned storage devices, | ||
70 | +including report zones, four zone operations, and zone append. | ||
71 | + | ||
72 | +2. Emulating zoned storage controllers | ||
73 | +-------------------------------------- | ||
74 | +When the BlockBackend's BlockLimits model reports a zoned storage device, users | ||
75 | +like the virtio-blk emulation or the qemu-io-cmds.c utility can use block layer | ||
76 | +APIs for zoned storage emulation or testing. | ||
77 | + | ||
78 | +For example, to test zone_report on a null_blk device using qemu-io is: | ||
79 | +$ path/to/qemu-io --image-opts -n driver=host_device,filename=/dev/nullb0 | ||
80 | +-c "zrp offset nr_zones" | ||
81 | diff --git a/docs/system/qemu-block-drivers.rst.inc b/docs/system/qemu-block-drivers.rst.inc | ||
82 | index XXXXXXX..XXXXXXX 100644 | ||
83 | --- a/docs/system/qemu-block-drivers.rst.inc | ||
84 | +++ b/docs/system/qemu-block-drivers.rst.inc | ||
85 | @@ -XXX,XX +XXX,XX @@ Hard disks | ||
86 | you may corrupt your host data (use the ``-snapshot`` command | ||
87 | line option or modify the device permissions accordingly). | ||
88 | |||
89 | +Zoned block devices | ||
90 | + Zoned block devices can be passed through to the guest if the emulated storage | ||
91 | + controller supports zoned storage. Use ``--blockdev host_device, | ||
92 | + node-name=drive0,filename=/dev/nullb0,cache.direct=on`` to pass through | ||
93 | + ``/dev/nullb0`` as ``drive0``. | ||
94 | + | ||
95 | Windows | ||
96 | ^^^^^^^ | ||
83 | 97 | ||
84 | -- | 98 | -- |
85 | 2.31.1 | 99 | 2.39.2 |
86 | |||
87 | diff view generated by jsdifflib |
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 1 | From: Philippe Mathieu-Daudé <philmd@linaro.org> |
---|---|---|---|
2 | 2 | ||
3 | New fleecing method becomes available: copy-before-write filter. | 3 | Introduce the BdrvDmgUncompressFunc type defintion. To emphasis |
4 | dmg_uncompress_bz2 and dmg_uncompress_lzfse are pointer to functions, | ||
5 | declare them using this new typedef. | ||
4 | 6 | ||
5 | Actually we don't need backup job to setup image fleecing. Add test | 7 | Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> |
6 | for new recommended way of image fleecing. | 8 | Message-id: 20230320152610.32052-1-philmd@linaro.org |
9 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
10 | --- | ||
11 | block/dmg.h | 8 ++++---- | ||
12 | block/dmg.c | 7 ++----- | ||
13 | 2 files changed, 6 insertions(+), 9 deletions(-) | ||
7 | 14 | ||
8 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 15 | diff --git a/block/dmg.h b/block/dmg.h |
9 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
10 | Message-Id: <20210824083856.17408-34-vsementsov@virtuozzo.com> | ||
11 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
12 | --- | ||
13 | tests/qemu-iotests/tests/image-fleecing | 50 +++++++++----- | ||
14 | tests/qemu-iotests/tests/image-fleecing.out | 72 +++++++++++++++++++++ | ||
15 | 2 files changed, 107 insertions(+), 15 deletions(-) | ||
16 | |||
17 | diff --git a/tests/qemu-iotests/tests/image-fleecing b/tests/qemu-iotests/tests/image-fleecing | ||
18 | index XXXXXXX..XXXXXXX 100755 | ||
19 | --- a/tests/qemu-iotests/tests/image-fleecing | ||
20 | +++ b/tests/qemu-iotests/tests/image-fleecing | ||
21 | @@ -XXX,XX +XXX,XX @@ remainder = [('0xd5', '0x108000', '32k'), # Right-end of partial-left [1] | ||
22 | ('0xdc', '32M', '32k'), # Left-end of partial-right [2] | ||
23 | ('0xcd', '0x3ff0000', '64k')] # patterns[3] | ||
24 | |||
25 | -def do_test(base_img_path, fleece_img_path, nbd_sock_path, vm): | ||
26 | +def do_test(use_cbw, base_img_path, fleece_img_path, nbd_sock_path, vm): | ||
27 | log('--- Setting up images ---') | ||
28 | log('') | ||
29 | |||
30 | @@ -XXX,XX +XXX,XX @@ def do_test(base_img_path, fleece_img_path, nbd_sock_path, vm): | ||
31 | |||
32 | src_node = 'source' | ||
33 | tmp_node = 'temp' | ||
34 | + qom_path = '/machine/peripheral/sda' | ||
35 | vm.add_blockdev(f'driver={iotests.imgfmt},file.driver=file,' | ||
36 | f'file.filename={base_img_path},node-name={src_node}') | ||
37 | vm.add_device('virtio-scsi') | ||
38 | @@ -XXX,XX +XXX,XX @@ def do_test(base_img_path, fleece_img_path, nbd_sock_path, vm): | ||
39 | 'backing': src_node, | ||
40 | })) | ||
41 | |||
42 | - # Establish COW from source to fleecing node | ||
43 | - log(vm.qmp('blockdev-backup', | ||
44 | - job_id='fleecing', | ||
45 | - device=src_node, | ||
46 | - target=tmp_node, | ||
47 | - sync='none')) | ||
48 | + # Establish CBW from source to fleecing node | ||
49 | + if use_cbw: | ||
50 | + log(vm.qmp('blockdev-add', { | ||
51 | + 'driver': 'copy-before-write', | ||
52 | + 'node-name': 'fl-cbw', | ||
53 | + 'file': src_node, | ||
54 | + 'target': tmp_node | ||
55 | + })) | ||
56 | + | ||
57 | + log(vm.qmp('qom-set', path=qom_path, property='drive', value='fl-cbw')) | ||
58 | + else: | ||
59 | + log(vm.qmp('blockdev-backup', | ||
60 | + job_id='fleecing', | ||
61 | + device=src_node, | ||
62 | + target=tmp_node, | ||
63 | + sync='none')) | ||
64 | |||
65 | log('') | ||
66 | log('--- Setting up NBD Export ---') | ||
67 | @@ -XXX,XX +XXX,XX @@ def do_test(base_img_path, fleece_img_path, nbd_sock_path, vm): | ||
68 | for p in overwrite: | ||
69 | cmd = 'write -P%s %s %s' % p | ||
70 | log(cmd) | ||
71 | - log(vm.hmp_qemu_io('/machine/peripheral/sda', cmd, qdev=True)) | ||
72 | + log(vm.hmp_qemu_io(qom_path, cmd, qdev=True)) | ||
73 | |||
74 | log('') | ||
75 | log('--- Verifying Data ---') | ||
76 | @@ -XXX,XX +XXX,XX @@ def do_test(base_img_path, fleece_img_path, nbd_sock_path, vm): | ||
77 | log('--- Cleanup ---') | ||
78 | log('') | ||
79 | |||
80 | - log(vm.qmp('block-job-cancel', device='fleecing')) | ||
81 | - e = vm.event_wait('BLOCK_JOB_CANCELLED') | ||
82 | - assert e is not None | ||
83 | - log(e, filters=[iotests.filter_qmp_event]) | ||
84 | + if use_cbw: | ||
85 | + log(vm.qmp('qom-set', path=qom_path, property='drive', value=src_node)) | ||
86 | + log(vm.qmp('blockdev-del', node_name='fl-cbw')) | ||
87 | + else: | ||
88 | + log(vm.qmp('block-job-cancel', device='fleecing')) | ||
89 | + e = vm.event_wait('BLOCK_JOB_CANCELLED') | ||
90 | + assert e is not None | ||
91 | + log(e, filters=[iotests.filter_qmp_event]) | ||
92 | + | ||
93 | log(vm.qmp('nbd-server-stop')) | ||
94 | log(vm.qmp('blockdev-del', node_name=tmp_node)) | ||
95 | vm.shutdown() | ||
96 | @@ -XXX,XX +XXX,XX @@ def do_test(base_img_path, fleece_img_path, nbd_sock_path, vm): | ||
97 | log('Done') | ||
98 | |||
99 | |||
100 | -def test(): | ||
101 | +def test(use_cbw): | ||
102 | with iotests.FilePath('base.img') as base_img_path, \ | ||
103 | iotests.FilePath('fleece.img') as fleece_img_path, \ | ||
104 | iotests.FilePath('nbd.sock', | ||
105 | base_dir=iotests.sock_dir) as nbd_sock_path, \ | ||
106 | iotests.VM() as vm: | ||
107 | - do_test(base_img_path, fleece_img_path, nbd_sock_path, vm) | ||
108 | + do_test(use_cbw, base_img_path, fleece_img_path, nbd_sock_path, vm) | ||
109 | + | ||
110 | |||
111 | +log('=== Test backup(sync=none) based fleecing ===\n') | ||
112 | +test(False) | ||
113 | |||
114 | -test() | ||
115 | +log('=== Test filter based fleecing ===\n') | ||
116 | +test(True) | ||
117 | diff --git a/tests/qemu-iotests/tests/image-fleecing.out b/tests/qemu-iotests/tests/image-fleecing.out | ||
118 | index XXXXXXX..XXXXXXX 100644 | 16 | index XXXXXXX..XXXXXXX 100644 |
119 | --- a/tests/qemu-iotests/tests/image-fleecing.out | 17 | --- a/block/dmg.h |
120 | +++ b/tests/qemu-iotests/tests/image-fleecing.out | 18 | +++ b/block/dmg.h |
19 | @@ -XXX,XX +XXX,XX @@ typedef struct BDRVDMGState { | ||
20 | z_stream zstream; | ||
21 | } BDRVDMGState; | ||
22 | |||
23 | -extern int (*dmg_uncompress_bz2)(char *next_in, unsigned int avail_in, | ||
24 | - char *next_out, unsigned int avail_out); | ||
25 | +typedef int BdrvDmgUncompressFunc(char *next_in, unsigned int avail_in, | ||
26 | + char *next_out, unsigned int avail_out); | ||
27 | |||
28 | -extern int (*dmg_uncompress_lzfse)(char *next_in, unsigned int avail_in, | ||
29 | - char *next_out, unsigned int avail_out); | ||
30 | +extern BdrvDmgUncompressFunc *dmg_uncompress_bz2; | ||
31 | +extern BdrvDmgUncompressFunc *dmg_uncompress_lzfse; | ||
32 | |||
33 | #endif | ||
34 | diff --git a/block/dmg.c b/block/dmg.c | ||
35 | index XXXXXXX..XXXXXXX 100644 | ||
36 | --- a/block/dmg.c | ||
37 | +++ b/block/dmg.c | ||
121 | @@ -XXX,XX +XXX,XX @@ | 38 | @@ -XXX,XX +XXX,XX @@ |
122 | +=== Test backup(sync=none) based fleecing === | 39 | #include "qemu/memalign.h" |
123 | + | 40 | #include "dmg.h" |
124 | --- Setting up images --- | 41 | |
125 | 42 | -int (*dmg_uncompress_bz2)(char *next_in, unsigned int avail_in, | |
126 | Done | 43 | - char *next_out, unsigned int avail_out); |
127 | @@ -XXX,XX +XXX,XX @@ read -P0xdc 32M 32k | 44 | - |
128 | read -P0xcd 0x3ff0000 64k | 45 | -int (*dmg_uncompress_lzfse)(char *next_in, unsigned int avail_in, |
129 | 46 | - char *next_out, unsigned int avail_out); | |
130 | Done | 47 | +BdrvDmgUncompressFunc *dmg_uncompress_bz2; |
131 | +=== Test filter based fleecing === | 48 | +BdrvDmgUncompressFunc *dmg_uncompress_lzfse; |
132 | + | 49 | |
133 | +--- Setting up images --- | 50 | enum { |
134 | + | 51 | /* Limit chunk sizes to prevent unreasonable amounts of memory being used |
135 | +Done | ||
136 | + | ||
137 | +--- Launching VM --- | ||
138 | + | ||
139 | +Done | ||
140 | + | ||
141 | +--- Setting up Fleecing Graph --- | ||
142 | + | ||
143 | +{"return": {}} | ||
144 | +{"return": {}} | ||
145 | +{"return": {}} | ||
146 | + | ||
147 | +--- Setting up NBD Export --- | ||
148 | + | ||
149 | +{"return": {}} | ||
150 | +{"return": {}} | ||
151 | + | ||
152 | +--- Sanity Check --- | ||
153 | + | ||
154 | +read -P0x5d 0 64k | ||
155 | +read -P0xd5 1M 64k | ||
156 | +read -P0xdc 32M 64k | ||
157 | +read -P0xcd 0x3ff0000 64k | ||
158 | +read -P0 0x00f8000 32k | ||
159 | +read -P0 0x2010000 32k | ||
160 | +read -P0 0x3fe0000 64k | ||
161 | + | ||
162 | +--- Testing COW --- | ||
163 | + | ||
164 | +write -P0xab 0 64k | ||
165 | +{"return": ""} | ||
166 | +write -P0xad 0x00f8000 64k | ||
167 | +{"return": ""} | ||
168 | +write -P0x1d 0x2008000 64k | ||
169 | +{"return": ""} | ||
170 | +write -P0xea 0x3fe0000 64k | ||
171 | +{"return": ""} | ||
172 | + | ||
173 | +--- Verifying Data --- | ||
174 | + | ||
175 | +read -P0x5d 0 64k | ||
176 | +read -P0xd5 1M 64k | ||
177 | +read -P0xdc 32M 64k | ||
178 | +read -P0xcd 0x3ff0000 64k | ||
179 | +read -P0 0x00f8000 32k | ||
180 | +read -P0 0x2010000 32k | ||
181 | +read -P0 0x3fe0000 64k | ||
182 | + | ||
183 | +--- Cleanup --- | ||
184 | + | ||
185 | +{"return": {}} | ||
186 | +{"return": {}} | ||
187 | +{"return": {}} | ||
188 | +{"return": {}} | ||
189 | + | ||
190 | +--- Confirming writes --- | ||
191 | + | ||
192 | +read -P0xab 0 64k | ||
193 | +read -P0xad 0x00f8000 64k | ||
194 | +read -P0x1d 0x2008000 64k | ||
195 | +read -P0xea 0x3fe0000 64k | ||
196 | +read -P0xd5 0x108000 32k | ||
197 | +read -P0xdc 32M 32k | ||
198 | +read -P0xcd 0x3ff0000 64k | ||
199 | + | ||
200 | +Done | ||
201 | -- | 52 | -- |
202 | 2.31.1 | 53 | 2.39.2 |
203 | 54 | ||
204 | 55 | diff view generated by jsdifflib |
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 1 | From: Thomas De Schampheleire <thomas.de_schampheleire@nokia.com> |
---|---|---|---|
2 | 2 | ||
3 | Actually target of backup(sync=None) is not a final backup target: | 3 | The event filename is an absolute path. Convert it to a relative path when |
4 | image fleecing is intended to be used with external tool, which will | 4 | writing '#line' directives, to preserve reproducibility of the generated |
5 | copy data from fleecing node to some real backup target. | 5 | output when different base paths are used. |
6 | 6 | ||
7 | Also, we are going to add a test case for "push backup with fleecing", | 7 | Signed-off-by: Thomas De Schampheleire <thomas.de_schampheleire@nokia.com> |
8 | where instead of exporting fleecing node by NBD, we'll start a backup | 8 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> |
9 | job from fleecing node to real backup target. | 9 | Message-Id: <20230406080045.21696-1-thomas.de_schampheleire@nokia.com> |
10 | --- | ||
11 | scripts/tracetool/backend/ftrace.py | 4 +++- | ||
12 | scripts/tracetool/backend/log.py | 4 +++- | ||
13 | scripts/tracetool/backend/syslog.py | 4 +++- | ||
14 | 3 files changed, 9 insertions(+), 3 deletions(-) | ||
10 | 15 | ||
11 | To avoid confusion, let's rename temporary fleecing node now. | 16 | diff --git a/scripts/tracetool/backend/ftrace.py b/scripts/tracetool/backend/ftrace.py |
12 | 17 | index XXXXXXX..XXXXXXX 100644 | |
13 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 18 | --- a/scripts/tracetool/backend/ftrace.py |
14 | Reviewed-by: Max Reitz <mreitz@redhat.com> | 19 | +++ b/scripts/tracetool/backend/ftrace.py |
15 | Message-Id: <20210824083856.17408-32-vsementsov@virtuozzo.com> | 20 | @@ -XXX,XX +XXX,XX @@ |
16 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | 21 | __email__ = "stefanha@redhat.com" |
17 | --- | 22 | |
18 | tests/qemu-iotests/tests/image-fleecing | 14 +++++++------- | 23 | |
19 | 1 file changed, 7 insertions(+), 7 deletions(-) | 24 | +import os.path |
20 | 25 | + | |
21 | diff --git a/tests/qemu-iotests/tests/image-fleecing b/tests/qemu-iotests/tests/image-fleecing | 26 | from tracetool import out |
22 | index XXXXXXX..XXXXXXX 100755 | 27 | |
23 | --- a/tests/qemu-iotests/tests/image-fleecing | 28 | |
24 | +++ b/tests/qemu-iotests/tests/image-fleecing | 29 | @@ -XXX,XX +XXX,XX @@ def generate_h(event, group): |
25 | @@ -XXX,XX +XXX,XX @@ with iotests.FilePath('base.img') as base_img_path, \ | 30 | args=event.args, |
26 | log('') | 31 | event_id="TRACE_" + event.name.upper(), |
27 | 32 | event_lineno=event.lineno, | |
28 | src_node = 'source' | 33 | - event_filename=event.filename, |
29 | + tmp_node = 'temp' | 34 | + event_filename=os.path.relpath(event.filename), |
30 | vm.add_blockdev(f'driver={iotests.imgfmt},file.driver=file,' | 35 | fmt=event.fmt.rstrip("\n"), |
31 | f'file.filename={base_img_path},node-name={src_node}') | 36 | argnames=argnames) |
32 | vm.add_device('virtio-scsi') | 37 | |
33 | @@ -XXX,XX +XXX,XX @@ with iotests.FilePath('base.img') as base_img_path, \ | 38 | diff --git a/scripts/tracetool/backend/log.py b/scripts/tracetool/backend/log.py |
34 | log('--- Setting up Fleecing Graph ---') | 39 | index XXXXXXX..XXXXXXX 100644 |
35 | log('') | 40 | --- a/scripts/tracetool/backend/log.py |
36 | 41 | +++ b/scripts/tracetool/backend/log.py | |
37 | - tgt_node = 'fleeceNode' | 42 | @@ -XXX,XX +XXX,XX @@ |
38 | 43 | __email__ = "stefanha@redhat.com" | |
39 | - # create tgt_node backed by src_node | 44 | |
40 | + # create tmp_node backed by src_node | 45 | |
41 | log(vm.qmp('blockdev-add', { | 46 | +import os.path |
42 | 'driver': 'qcow2', | 47 | + |
43 | - 'node-name': tgt_node, | 48 | from tracetool import out |
44 | + 'node-name': tmp_node, | 49 | |
45 | 'file': { | 50 | |
46 | 'driver': 'file', | 51 | @@ -XXX,XX +XXX,XX @@ def generate_h(event, group): |
47 | 'filename': fleece_img_path, | 52 | ' }', |
48 | @@ -XXX,XX +XXX,XX @@ with iotests.FilePath('base.img') as base_img_path, \ | 53 | cond=cond, |
49 | log(vm.qmp('blockdev-backup', | 54 | event_lineno=event.lineno, |
50 | job_id='fleecing', | 55 | - event_filename=event.filename, |
51 | device=src_node, | 56 | + event_filename=os.path.relpath(event.filename), |
52 | - target=tgt_node, | 57 | name=event.name, |
53 | + target=tmp_node, | 58 | fmt=event.fmt.rstrip("\n"), |
54 | sync='none')) | 59 | argnames=argnames) |
55 | 60 | diff --git a/scripts/tracetool/backend/syslog.py b/scripts/tracetool/backend/syslog.py | |
56 | log('') | 61 | index XXXXXXX..XXXXXXX 100644 |
57 | log('--- Setting up NBD Export ---') | 62 | --- a/scripts/tracetool/backend/syslog.py |
58 | log('') | 63 | +++ b/scripts/tracetool/backend/syslog.py |
59 | 64 | @@ -XXX,XX +XXX,XX @@ | |
60 | - nbd_uri = 'nbd+unix:///%s?socket=%s' % (tgt_node, nbd_sock_path) | 65 | __email__ = "stefanha@redhat.com" |
61 | + nbd_uri = 'nbd+unix:///%s?socket=%s' % (tmp_node, nbd_sock_path) | 66 | |
62 | log(vm.qmp('nbd-server-start', | 67 | |
63 | {'addr': { 'type': 'unix', | 68 | +import os.path |
64 | 'data': { 'path': nbd_sock_path } } })) | 69 | + |
65 | 70 | from tracetool import out | |
66 | - log(vm.qmp('nbd-server-add', device=tgt_node)) | 71 | |
67 | + log(vm.qmp('nbd-server-add', device=tmp_node)) | 72 | |
68 | 73 | @@ -XXX,XX +XXX,XX @@ def generate_h(event, group): | |
69 | log('') | 74 | ' }', |
70 | log('--- Sanity Check ---') | 75 | cond=cond, |
71 | @@ -XXX,XX +XXX,XX @@ with iotests.FilePath('base.img') as base_img_path, \ | 76 | event_lineno=event.lineno, |
72 | assert e is not None | 77 | - event_filename=event.filename, |
73 | log(e, filters=[iotests.filter_qmp_event]) | 78 | + event_filename=os.path.relpath(event.filename), |
74 | log(vm.qmp('nbd-server-stop')) | 79 | name=event.name, |
75 | - log(vm.qmp('blockdev-del', node_name=tgt_node)) | 80 | fmt=event.fmt.rstrip("\n"), |
76 | + log(vm.qmp('blockdev-del', node_name=tmp_node)) | 81 | argnames=argnames) |
77 | vm.shutdown() | ||
78 | |||
79 | log('') | ||
80 | -- | 82 | -- |
81 | 2.31.1 | 83 | 2.39.2 |
82 | |||
83 | diff view generated by jsdifflib |
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 1 | From: Sam Li <faithilikerun@gmail.com> |
---|---|---|---|
2 | 2 | ||
3 | One more step closer to .bdrv_open(): use options instead of plain | 3 | Since Linux doesn't have a user API to issue zone append operations to |
4 | arguments. Move to bdrv_open_child() calls, native for drive open | 4 | zoned devices from user space, the file-posix driver is modified to add |
5 | handlers. | 5 | zone append emulation using regular writes. To do this, the file-posix |
6 | driver tracks the wp location of all zones of the device. It uses an | ||
7 | array of uint64_t. The most significant bit of each wp location indicates | ||
8 | if the zone type is conventional zones. | ||
6 | 9 | ||
7 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 10 | The zones wp can be changed due to the following operations issued: |
8 | Reviewed-by: Hanna Reitz <hreitz@redhat.com> | 11 | - zone reset: change the wp to the start offset of that zone |
9 | Message-Id: <20210824083856.17408-19-vsementsov@virtuozzo.com> | 12 | - zone finish: change to the end location of that zone |
10 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | 13 | - write to a zone |
14 | - zone append | ||
15 | |||
16 | Signed-off-by: Sam Li <faithilikerun@gmail.com> | ||
17 | Message-id: 20230407081657.17947-2-faithilikerun@gmail.com | ||
18 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
11 | --- | 19 | --- |
12 | block/copy-before-write.c | 29 +++++++++++++++-------------- | 20 | include/block/block-common.h | 14 +++ |
13 | 1 file changed, 15 insertions(+), 14 deletions(-) | 21 | include/block/block_int-common.h | 5 + |
22 | block/file-posix.c | 173 ++++++++++++++++++++++++++++++- | ||
23 | 3 files changed, 189 insertions(+), 3 deletions(-) | ||
14 | 24 | ||
15 | diff --git a/block/copy-before-write.c b/block/copy-before-write.c | 25 | diff --git a/include/block/block-common.h b/include/block/block-common.h |
16 | index XXXXXXX..XXXXXXX 100644 | 26 | index XXXXXXX..XXXXXXX 100644 |
17 | --- a/block/copy-before-write.c | 27 | --- a/include/block/block-common.h |
18 | +++ b/block/copy-before-write.c | 28 | +++ b/include/block/block-common.h |
19 | @@ -XXX,XX +XXX,XX @@ static void cbw_child_perm(BlockDriverState *bs, BdrvChild *c, | 29 | @@ -XXX,XX +XXX,XX @@ typedef struct BlockZoneDescriptor { |
20 | } | 30 | BlockZoneState state; |
31 | } BlockZoneDescriptor; | ||
32 | |||
33 | +/* | ||
34 | + * Track write pointers of a zone in bytes. | ||
35 | + */ | ||
36 | +typedef struct BlockZoneWps { | ||
37 | + CoMutex colock; | ||
38 | + uint64_t wp[]; | ||
39 | +} BlockZoneWps; | ||
40 | + | ||
41 | typedef struct BlockDriverInfo { | ||
42 | /* in bytes, 0 if irrelevant */ | ||
43 | int cluster_size; | ||
44 | @@ -XXX,XX +XXX,XX @@ typedef enum { | ||
45 | #define BDRV_SECTOR_BITS 9 | ||
46 | #define BDRV_SECTOR_SIZE (1ULL << BDRV_SECTOR_BITS) | ||
47 | |||
48 | +/* | ||
49 | + * Get the first most significant bit of wp. If it is zero, then | ||
50 | + * the zone type is SWR. | ||
51 | + */ | ||
52 | +#define BDRV_ZT_IS_CONV(wp) (wp & (1ULL << 63)) | ||
53 | + | ||
54 | #define BDRV_REQUEST_MAX_SECTORS MIN_CONST(SIZE_MAX >> BDRV_SECTOR_BITS, \ | ||
55 | INT_MAX >> BDRV_SECTOR_BITS) | ||
56 | #define BDRV_REQUEST_MAX_BYTES (BDRV_REQUEST_MAX_SECTORS << BDRV_SECTOR_BITS) | ||
57 | diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h | ||
58 | index XXXXXXX..XXXXXXX 100644 | ||
59 | --- a/include/block/block_int-common.h | ||
60 | +++ b/include/block/block_int-common.h | ||
61 | @@ -XXX,XX +XXX,XX @@ typedef struct BlockLimits { | ||
62 | |||
63 | /* maximum number of active zones */ | ||
64 | int64_t max_active_zones; | ||
65 | + | ||
66 | + int64_t write_granularity; | ||
67 | } BlockLimits; | ||
68 | |||
69 | typedef struct BdrvOpBlocker BdrvOpBlocker; | ||
70 | @@ -XXX,XX +XXX,XX @@ struct BlockDriverState { | ||
71 | CoMutex bsc_modify_lock; | ||
72 | /* Always non-NULL, but must only be dereferenced under an RCU read guard */ | ||
73 | BdrvBlockStatusCache *block_status_cache; | ||
74 | + | ||
75 | + /* array of write pointers' location of each zone in the zoned device. */ | ||
76 | + BlockZoneWps *wps; | ||
77 | }; | ||
78 | |||
79 | struct BlockBackendRootState { | ||
80 | diff --git a/block/file-posix.c b/block/file-posix.c | ||
81 | index XXXXXXX..XXXXXXX 100644 | ||
82 | --- a/block/file-posix.c | ||
83 | +++ b/block/file-posix.c | ||
84 | @@ -XXX,XX +XXX,XX @@ static int hdev_get_max_segments(int fd, struct stat *st) | ||
85 | #endif | ||
21 | } | 86 | } |
22 | 87 | ||
23 | -static int cbw_init(BlockDriverState *bs, BlockDriverState *source, | 88 | +#if defined(CONFIG_BLKZONED) |
24 | - BlockDriverState *target, Error **errp) | 89 | +/* |
25 | +static int cbw_init(BlockDriverState *bs, QDict *options, Error **errp) | 90 | + * If the reset_all flag is true, then the wps of zone whose state is |
91 | + * not readonly or offline should be all reset to the start sector. | ||
92 | + * Else, take the real wp of the device. | ||
93 | + */ | ||
94 | +static int get_zones_wp(BlockDriverState *bs, int fd, int64_t offset, | ||
95 | + unsigned int nrz, bool reset_all) | ||
96 | +{ | ||
97 | + struct blk_zone *blkz; | ||
98 | + size_t rep_size; | ||
99 | + uint64_t sector = offset >> BDRV_SECTOR_BITS; | ||
100 | + BlockZoneWps *wps = bs->wps; | ||
101 | + int j = offset / bs->bl.zone_size; | ||
102 | + int ret, n = 0, i = 0; | ||
103 | + rep_size = sizeof(struct blk_zone_report) + nrz * sizeof(struct blk_zone); | ||
104 | + g_autofree struct blk_zone_report *rep = NULL; | ||
105 | + | ||
106 | + rep = g_malloc(rep_size); | ||
107 | + blkz = (struct blk_zone *)(rep + 1); | ||
108 | + while (n < nrz) { | ||
109 | + memset(rep, 0, rep_size); | ||
110 | + rep->sector = sector; | ||
111 | + rep->nr_zones = nrz - n; | ||
112 | + | ||
113 | + do { | ||
114 | + ret = ioctl(fd, BLKREPORTZONE, rep); | ||
115 | + } while (ret != 0 && errno == EINTR); | ||
116 | + if (ret != 0) { | ||
117 | + error_report("%d: ioctl BLKREPORTZONE at %" PRId64 " failed %d", | ||
118 | + fd, offset, errno); | ||
119 | + return -errno; | ||
120 | + } | ||
121 | + | ||
122 | + if (!rep->nr_zones) { | ||
123 | + break; | ||
124 | + } | ||
125 | + | ||
126 | + for (i = 0; i < rep->nr_zones; ++i, ++n, ++j) { | ||
127 | + /* | ||
128 | + * The wp tracking cares only about sequential writes required and | ||
129 | + * sequential write preferred zones so that the wp can advance to | ||
130 | + * the right location. | ||
131 | + * Use the most significant bit of the wp location to indicate the | ||
132 | + * zone type: 0 for SWR/SWP zones and 1 for conventional zones. | ||
133 | + */ | ||
134 | + if (blkz[i].type == BLK_ZONE_TYPE_CONVENTIONAL) { | ||
135 | + wps->wp[j] |= 1ULL << 63; | ||
136 | + } else { | ||
137 | + switch(blkz[i].cond) { | ||
138 | + case BLK_ZONE_COND_FULL: | ||
139 | + case BLK_ZONE_COND_READONLY: | ||
140 | + /* Zone not writable */ | ||
141 | + wps->wp[j] = (blkz[i].start + blkz[i].len) << BDRV_SECTOR_BITS; | ||
142 | + break; | ||
143 | + case BLK_ZONE_COND_OFFLINE: | ||
144 | + /* Zone not writable nor readable */ | ||
145 | + wps->wp[j] = (blkz[i].start) << BDRV_SECTOR_BITS; | ||
146 | + break; | ||
147 | + default: | ||
148 | + if (reset_all) { | ||
149 | + wps->wp[j] = blkz[i].start << BDRV_SECTOR_BITS; | ||
150 | + } else { | ||
151 | + wps->wp[j] = blkz[i].wp << BDRV_SECTOR_BITS; | ||
152 | + } | ||
153 | + break; | ||
154 | + } | ||
155 | + } | ||
156 | + } | ||
157 | + sector = blkz[i - 1].start + blkz[i - 1].len; | ||
158 | + } | ||
159 | + | ||
160 | + return 0; | ||
161 | +} | ||
162 | + | ||
163 | +static void update_zones_wp(BlockDriverState *bs, int fd, int64_t offset, | ||
164 | + unsigned int nrz) | ||
165 | +{ | ||
166 | + if (get_zones_wp(bs, fd, offset, nrz, 0) < 0) { | ||
167 | + error_report("update zone wp failed"); | ||
168 | + } | ||
169 | +} | ||
170 | +#endif | ||
171 | + | ||
172 | static void raw_refresh_limits(BlockDriverState *bs, Error **errp) | ||
26 | { | 173 | { |
27 | BDRVCopyBeforeWriteState *s = bs->opaque; | 174 | BDRVRawState *s = bs->opaque; |
28 | 175 | @@ -XXX,XX +XXX,XX @@ static void raw_refresh_limits(BlockDriverState *bs, Error **errp) | |
29 | - bdrv_ref(target); | 176 | if (ret >= 0) { |
30 | - s->target = bdrv_attach_child(bs, target, "target", &child_of_bds, | 177 | bs->bl.max_active_zones = ret; |
31 | - BDRV_CHILD_DATA, errp); | 178 | } |
32 | - if (!s->target) { | 179 | + |
33 | - error_prepend(errp, "Cannot attach target child: "); | 180 | + ret = get_sysfs_long_val(&st, "physical_block_size"); |
34 | + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, | 181 | + if (ret >= 0) { |
35 | + BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, | 182 | + bs->bl.write_granularity = ret; |
36 | + false, errp); | 183 | + } |
37 | + if (!bs->file) { | 184 | + |
185 | + /* The refresh_limits() function can be called multiple times. */ | ||
186 | + g_free(bs->wps); | ||
187 | + bs->wps = g_malloc(sizeof(BlockZoneWps) + | ||
188 | + sizeof(int64_t) * bs->bl.nr_zones); | ||
189 | + ret = get_zones_wp(bs, s->fd, 0, bs->bl.nr_zones, 0); | ||
190 | + if (ret < 0) { | ||
191 | + error_setg_errno(errp, -ret, "report wps failed"); | ||
192 | + bs->wps = NULL; | ||
193 | + return; | ||
194 | + } | ||
195 | + qemu_co_mutex_init(&bs->wps->colock); | ||
196 | return; | ||
197 | } | ||
198 | out: | ||
199 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_prw(BlockDriverState *bs, uint64_t offset, | ||
200 | { | ||
201 | BDRVRawState *s = bs->opaque; | ||
202 | RawPosixAIOData acb; | ||
203 | + int ret; | ||
204 | |||
205 | if (fd_open(bs) < 0) | ||
206 | return -EIO; | ||
207 | +#if defined(CONFIG_BLKZONED) | ||
208 | + if (type & QEMU_AIO_WRITE && bs->wps) { | ||
209 | + qemu_co_mutex_lock(&bs->wps->colock); | ||
210 | + } | ||
211 | +#endif | ||
212 | |||
213 | /* | ||
214 | * When using O_DIRECT, the request must be aligned to be able to use | ||
215 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_prw(BlockDriverState *bs, uint64_t offset, | ||
216 | } else if (s->use_linux_io_uring) { | ||
217 | LuringState *aio = aio_get_linux_io_uring(bdrv_get_aio_context(bs)); | ||
218 | assert(qiov->size == bytes); | ||
219 | - return luring_co_submit(bs, aio, s->fd, offset, qiov, type); | ||
220 | + ret = luring_co_submit(bs, aio, s->fd, offset, qiov, type); | ||
221 | + goto out; | ||
222 | #endif | ||
223 | #ifdef CONFIG_LINUX_AIO | ||
224 | } else if (s->use_linux_aio) { | ||
225 | LinuxAioState *aio = aio_get_linux_aio(bdrv_get_aio_context(bs)); | ||
226 | assert(qiov->size == bytes); | ||
227 | - return laio_co_submit(bs, aio, s->fd, offset, qiov, type, | ||
228 | + ret = laio_co_submit(bs, aio, s->fd, offset, qiov, type, | ||
229 | s->aio_max_batch); | ||
230 | + goto out; | ||
231 | #endif | ||
232 | } | ||
233 | |||
234 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_prw(BlockDriverState *bs, uint64_t offset, | ||
235 | }; | ||
236 | |||
237 | assert(qiov->size == bytes); | ||
238 | - return raw_thread_pool_submit(bs, handle_aiocb_rw, &acb); | ||
239 | + ret = raw_thread_pool_submit(bs, handle_aiocb_rw, &acb); | ||
240 | + | ||
241 | +out: | ||
242 | +#if defined(CONFIG_BLKZONED) | ||
243 | + BlockZoneWps *wps = bs->wps; | ||
244 | + if (ret == 0) { | ||
245 | + if (type & QEMU_AIO_WRITE && wps && bs->bl.zone_size) { | ||
246 | + uint64_t *wp = &wps->wp[offset / bs->bl.zone_size]; | ||
247 | + if (!BDRV_ZT_IS_CONV(*wp)) { | ||
248 | + /* Advance the wp if needed */ | ||
249 | + if (offset + bytes > *wp) { | ||
250 | + *wp = offset + bytes; | ||
251 | + } | ||
252 | + } | ||
253 | + } | ||
254 | + } else { | ||
255 | + if (type & QEMU_AIO_WRITE) { | ||
256 | + update_zones_wp(bs, s->fd, 0, 1); | ||
257 | + } | ||
258 | + } | ||
259 | + | ||
260 | + if (type & QEMU_AIO_WRITE && wps) { | ||
261 | + qemu_co_mutex_unlock(&wps->colock); | ||
262 | + } | ||
263 | +#endif | ||
264 | + return ret; | ||
265 | } | ||
266 | |||
267 | static int coroutine_fn raw_co_preadv(BlockDriverState *bs, int64_t offset, | ||
268 | @@ -XXX,XX +XXX,XX @@ static void raw_close(BlockDriverState *bs) | ||
269 | BDRVRawState *s = bs->opaque; | ||
270 | |||
271 | if (s->fd >= 0) { | ||
272 | +#if defined(CONFIG_BLKZONED) | ||
273 | + g_free(bs->wps); | ||
274 | +#endif | ||
275 | qemu_close(s->fd); | ||
276 | s->fd = -1; | ||
277 | } | ||
278 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_zone_mgmt(BlockDriverState *bs, BlockZoneOp op, | ||
279 | const char *op_name; | ||
280 | unsigned long zo; | ||
281 | int ret; | ||
282 | + BlockZoneWps *wps = bs->wps; | ||
283 | int64_t capacity = bs->total_sectors << BDRV_SECTOR_BITS; | ||
284 | |||
285 | zone_size = bs->bl.zone_size; | ||
286 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_zone_mgmt(BlockDriverState *bs, BlockZoneOp op, | ||
38 | return -EINVAL; | 287 | return -EINVAL; |
39 | } | 288 | } |
40 | 289 | ||
41 | - bdrv_ref(source); | 290 | + QEMU_LOCK_GUARD(&wps->colock); |
42 | - bs->file = bdrv_attach_child(bs, source, "file", &child_of_bds, | 291 | + uint32_t i = offset / bs->bl.zone_size; |
43 | - BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, | 292 | + uint32_t nrz = len / bs->bl.zone_size; |
44 | - errp); | 293 | + uint64_t *wp = &wps->wp[i]; |
45 | - if (!bs->file) { | 294 | + if (BDRV_ZT_IS_CONV(*wp) && len != capacity) { |
46 | - error_prepend(errp, "Cannot attach file child: "); | 295 | + error_report("zone mgmt operations are not allowed for conventional zones"); |
47 | + s->target = bdrv_open_child(NULL, options, "target", bs, &child_of_bds, | 296 | + return -EIO; |
48 | + BDRV_CHILD_DATA, false, errp); | 297 | + } |
49 | + if (!s->target) { | 298 | + |
50 | return -EINVAL; | 299 | switch (op) { |
51 | } | 300 | case BLK_ZO_OPEN: |
52 | 301 | op_name = "BLKOPENZONE"; | |
53 | @@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_cbw_append(BlockDriverState *source, | 302 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_zone_mgmt(BlockDriverState *bs, BlockZoneOp op, |
54 | int ret; | 303 | len >> BDRV_SECTOR_BITS); |
55 | BDRVCopyBeforeWriteState *state; | 304 | ret = raw_thread_pool_submit(bs, handle_aiocb_zone_mgmt, &acb); |
56 | BlockDriverState *top; | 305 | if (ret != 0) { |
57 | + QDict *opts; | 306 | + update_zones_wp(bs, s->fd, offset, i); |
58 | 307 | error_report("ioctl %s failed %d", op_name, ret); | |
59 | assert(source->total_sectors == target->total_sectors); | 308 | + return ret; |
60 | 309 | + } | |
61 | @@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_cbw_append(BlockDriverState *source, | 310 | + |
62 | } | 311 | + if (zo == BLKRESETZONE && len == capacity) { |
63 | state = top->opaque; | 312 | + ret = get_zones_wp(bs, s->fd, 0, bs->bl.nr_zones, 1); |
64 | 313 | + if (ret < 0) { | |
65 | - ret = cbw_init(top, source, target, errp); | 314 | + error_report("reporting single wp failed"); |
66 | + opts = qdict_new(); | 315 | + return ret; |
67 | + qdict_put_str(opts, "file", bdrv_get_node_name(source)); | 316 | + } |
68 | + qdict_put_str(opts, "target", bdrv_get_node_name(target)); | 317 | + } else if (zo == BLKRESETZONE) { |
69 | + | 318 | + for (int j = 0; j < nrz; ++j) { |
70 | + ret = cbw_init(top, opts, errp); | 319 | + wp[j] = offset + j * zone_size; |
71 | + qobject_unref(opts); | 320 | + } |
72 | if (ret < 0) { | 321 | + } else if (zo == BLKFINISHZONE) { |
73 | goto fail; | 322 | + for (int j = 0; j < nrz; ++j) { |
74 | } | 323 | + /* The zoned device allows the last zone smaller that the |
324 | + * zone size. */ | ||
325 | + wp[j] = MIN(offset + (j + 1) * zone_size, offset + len); | ||
326 | + } | ||
327 | } | ||
328 | |||
329 | return ret; | ||
75 | -- | 330 | -- |
76 | 2.31.1 | 331 | 2.39.2 |
77 | |||
78 | diff view generated by jsdifflib |
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 1 | From: Sam Li <faithilikerun@gmail.com> |
---|---|---|---|
2 | 2 | ||
3 | Add function to transactionally replace bs inside BdrvChild. | 3 | A zone append command is a write operation that specifies the first |
4 | logical block of a zone as the write position. When writing to a zoned | ||
5 | block device using zone append, the byte offset of the call may point at | ||
6 | any position within the zone to which the data is being appended. Upon | ||
7 | completion the device will respond with the position where the data has | ||
8 | been written in the zone. | ||
4 | 9 | ||
5 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 10 | Signed-off-by: Sam Li <faithilikerun@gmail.com> |
6 | Reviewed-by: Max Reitz <mreitz@redhat.com> | 11 | Reviewed-by: Dmitry Fomichev <dmitry.fomichev@wdc.com> |
7 | Message-Id: <20210824083856.17408-2-vsementsov@virtuozzo.com> | 12 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> |
8 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | 13 | Message-id: 20230407081657.17947-3-faithilikerun@gmail.com |
14 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
9 | --- | 15 | --- |
10 | include/block/block.h | 2 ++ | 16 | include/block/block-io.h | 4 +++ |
11 | block.c | 31 +++++++++++++++++++++++++++++++ | 17 | include/block/block_int-common.h | 3 ++ |
12 | 2 files changed, 33 insertions(+) | 18 | include/block/raw-aio.h | 4 ++- |
19 | include/sysemu/block-backend-io.h | 9 +++++ | ||
20 | block/block-backend.c | 60 +++++++++++++++++++++++++++++++ | ||
21 | block/file-posix.c | 58 ++++++++++++++++++++++++++---- | ||
22 | block/io.c | 27 ++++++++++++++ | ||
23 | block/io_uring.c | 4 +++ | ||
24 | block/linux-aio.c | 3 ++ | ||
25 | block/raw-format.c | 8 +++++ | ||
26 | 10 files changed, 172 insertions(+), 8 deletions(-) | ||
13 | 27 | ||
14 | diff --git a/include/block/block.h b/include/block/block.h | 28 | diff --git a/include/block/block-io.h b/include/block/block-io.h |
15 | index XXXXXXX..XXXXXXX 100644 | 29 | index XXXXXXX..XXXXXXX 100644 |
16 | --- a/include/block/block.h | 30 | --- a/include/block/block-io.h |
17 | +++ b/include/block/block.h | 31 | +++ b/include/block/block-io.h |
18 | @@ -XXX,XX +XXX,XX @@ int bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top, | 32 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn GRAPH_RDLOCK bdrv_co_zone_report(BlockDriverState *bs, |
19 | Error **errp); | 33 | int coroutine_fn GRAPH_RDLOCK bdrv_co_zone_mgmt(BlockDriverState *bs, |
20 | int bdrv_replace_node(BlockDriverState *from, BlockDriverState *to, | 34 | BlockZoneOp op, |
21 | Error **errp); | 35 | int64_t offset, int64_t len); |
22 | +int bdrv_replace_child_bs(BdrvChild *child, BlockDriverState *new_bs, | 36 | +int coroutine_fn GRAPH_RDLOCK bdrv_co_zone_append(BlockDriverState *bs, |
23 | + Error **errp); | 37 | + int64_t *offset, |
24 | BlockDriverState *bdrv_insert_node(BlockDriverState *bs, QDict *node_options, | 38 | + QEMUIOVector *qiov, |
25 | int flags, Error **errp); | 39 | + BdrvRequestFlags flags); |
26 | int bdrv_drop_filter(BlockDriverState *bs, Error **errp); | 40 | |
27 | diff --git a/block.c b/block.c | 41 | bool bdrv_can_write_zeroes_with_unmap(BlockDriverState *bs); |
28 | index XXXXXXX..XXXXXXX 100644 | 42 | int bdrv_block_status(BlockDriverState *bs, int64_t offset, |
29 | --- a/block.c | 43 | diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h |
30 | +++ b/block.c | 44 | index XXXXXXX..XXXXXXX 100644 |
31 | @@ -XXX,XX +XXX,XX @@ out: | 45 | --- a/include/block/block_int-common.h |
46 | +++ b/include/block/block_int-common.h | ||
47 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { | ||
48 | BlockZoneDescriptor *zones); | ||
49 | int coroutine_fn (*bdrv_co_zone_mgmt)(BlockDriverState *bs, BlockZoneOp op, | ||
50 | int64_t offset, int64_t len); | ||
51 | + int coroutine_fn (*bdrv_co_zone_append)(BlockDriverState *bs, | ||
52 | + int64_t *offset, QEMUIOVector *qiov, | ||
53 | + BdrvRequestFlags flags); | ||
54 | |||
55 | /* removable device specific */ | ||
56 | bool coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_is_inserted)( | ||
57 | diff --git a/include/block/raw-aio.h b/include/block/raw-aio.h | ||
58 | index XXXXXXX..XXXXXXX 100644 | ||
59 | --- a/include/block/raw-aio.h | ||
60 | +++ b/include/block/raw-aio.h | ||
61 | @@ -XXX,XX +XXX,XX @@ | ||
62 | #define QEMU_AIO_TRUNCATE 0x0080 | ||
63 | #define QEMU_AIO_ZONE_REPORT 0x0100 | ||
64 | #define QEMU_AIO_ZONE_MGMT 0x0200 | ||
65 | +#define QEMU_AIO_ZONE_APPEND 0x0400 | ||
66 | #define QEMU_AIO_TYPE_MASK \ | ||
67 | (QEMU_AIO_READ | \ | ||
68 | QEMU_AIO_WRITE | \ | ||
69 | @@ -XXX,XX +XXX,XX @@ | ||
70 | QEMU_AIO_COPY_RANGE | \ | ||
71 | QEMU_AIO_TRUNCATE | \ | ||
72 | QEMU_AIO_ZONE_REPORT | \ | ||
73 | - QEMU_AIO_ZONE_MGMT) | ||
74 | + QEMU_AIO_ZONE_MGMT | \ | ||
75 | + QEMU_AIO_ZONE_APPEND) | ||
76 | |||
77 | /* AIO flags */ | ||
78 | #define QEMU_AIO_MISALIGNED 0x1000 | ||
79 | diff --git a/include/sysemu/block-backend-io.h b/include/sysemu/block-backend-io.h | ||
80 | index XXXXXXX..XXXXXXX 100644 | ||
81 | --- a/include/sysemu/block-backend-io.h | ||
82 | +++ b/include/sysemu/block-backend-io.h | ||
83 | @@ -XXX,XX +XXX,XX @@ BlockAIOCB *blk_aio_zone_report(BlockBackend *blk, int64_t offset, | ||
84 | BlockAIOCB *blk_aio_zone_mgmt(BlockBackend *blk, BlockZoneOp op, | ||
85 | int64_t offset, int64_t len, | ||
86 | BlockCompletionFunc *cb, void *opaque); | ||
87 | +BlockAIOCB *blk_aio_zone_append(BlockBackend *blk, int64_t *offset, | ||
88 | + QEMUIOVector *qiov, BdrvRequestFlags flags, | ||
89 | + BlockCompletionFunc *cb, void *opaque); | ||
90 | BlockAIOCB *blk_aio_pdiscard(BlockBackend *blk, int64_t offset, int64_t bytes, | ||
91 | BlockCompletionFunc *cb, void *opaque); | ||
92 | void blk_aio_cancel_async(BlockAIOCB *acb); | ||
93 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn blk_co_zone_mgmt(BlockBackend *blk, BlockZoneOp op, | ||
94 | int64_t offset, int64_t len); | ||
95 | int co_wrapper_mixed blk_zone_mgmt(BlockBackend *blk, BlockZoneOp op, | ||
96 | int64_t offset, int64_t len); | ||
97 | +int coroutine_fn blk_co_zone_append(BlockBackend *blk, int64_t *offset, | ||
98 | + QEMUIOVector *qiov, | ||
99 | + BdrvRequestFlags flags); | ||
100 | +int co_wrapper_mixed blk_zone_append(BlockBackend *blk, int64_t *offset, | ||
101 | + QEMUIOVector *qiov, | ||
102 | + BdrvRequestFlags flags); | ||
103 | |||
104 | int co_wrapper_mixed blk_pdiscard(BlockBackend *blk, int64_t offset, | ||
105 | int64_t bytes); | ||
106 | diff --git a/block/block-backend.c b/block/block-backend.c | ||
107 | index XXXXXXX..XXXXXXX 100644 | ||
108 | --- a/block/block-backend.c | ||
109 | +++ b/block/block-backend.c | ||
110 | @@ -XXX,XX +XXX,XX @@ BlockAIOCB *blk_aio_zone_mgmt(BlockBackend *blk, BlockZoneOp op, | ||
111 | return &acb->common; | ||
112 | } | ||
113 | |||
114 | +static void coroutine_fn blk_aio_zone_append_entry(void *opaque) | ||
115 | +{ | ||
116 | + BlkAioEmAIOCB *acb = opaque; | ||
117 | + BlkRwCo *rwco = &acb->rwco; | ||
118 | + | ||
119 | + rwco->ret = blk_co_zone_append(rwco->blk, (int64_t *)acb->bytes, | ||
120 | + rwco->iobuf, rwco->flags); | ||
121 | + blk_aio_complete(acb); | ||
122 | +} | ||
123 | + | ||
124 | +BlockAIOCB *blk_aio_zone_append(BlockBackend *blk, int64_t *offset, | ||
125 | + QEMUIOVector *qiov, BdrvRequestFlags flags, | ||
126 | + BlockCompletionFunc *cb, void *opaque) { | ||
127 | + BlkAioEmAIOCB *acb; | ||
128 | + Coroutine *co; | ||
129 | + IO_CODE(); | ||
130 | + | ||
131 | + blk_inc_in_flight(blk); | ||
132 | + acb = blk_aio_get(&blk_aio_em_aiocb_info, blk, cb, opaque); | ||
133 | + acb->rwco = (BlkRwCo) { | ||
134 | + .blk = blk, | ||
135 | + .ret = NOT_DONE, | ||
136 | + .flags = flags, | ||
137 | + .iobuf = qiov, | ||
138 | + }; | ||
139 | + acb->bytes = (int64_t)offset; | ||
140 | + acb->has_returned = false; | ||
141 | + | ||
142 | + co = qemu_coroutine_create(blk_aio_zone_append_entry, acb); | ||
143 | + aio_co_enter(blk_get_aio_context(blk), co); | ||
144 | + acb->has_returned = true; | ||
145 | + if (acb->rwco.ret != NOT_DONE) { | ||
146 | + replay_bh_schedule_oneshot_event(blk_get_aio_context(blk), | ||
147 | + blk_aio_complete_bh, acb); | ||
148 | + } | ||
149 | + | ||
150 | + return &acb->common; | ||
151 | +} | ||
152 | + | ||
153 | /* | ||
154 | * Send a zone_report command. | ||
155 | * offset is a byte offset from the start of the device. No alignment | ||
156 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn blk_co_zone_mgmt(BlockBackend *blk, BlockZoneOp op, | ||
32 | return ret; | 157 | return ret; |
33 | } | 158 | } |
34 | 159 | ||
35 | +/* Not for empty child */ | 160 | +/* |
36 | +int bdrv_replace_child_bs(BdrvChild *child, BlockDriverState *new_bs, | 161 | + * Send a zone_append command. |
37 | + Error **errp) | 162 | + */ |
163 | +int coroutine_fn blk_co_zone_append(BlockBackend *blk, int64_t *offset, | ||
164 | + QEMUIOVector *qiov, BdrvRequestFlags flags) | ||
38 | +{ | 165 | +{ |
39 | + int ret; | 166 | + int ret; |
40 | + Transaction *tran = tran_new(); | 167 | + IO_CODE(); |
41 | + g_autoptr(GHashTable) found = NULL; | 168 | + |
42 | + g_autoptr(GSList) refresh_list = NULL; | 169 | + blk_inc_in_flight(blk); |
43 | + BlockDriverState *old_bs = child->bs; | 170 | + blk_wait_while_drained(blk); |
44 | + | 171 | + if (!blk_is_available(blk)) { |
45 | + bdrv_ref(old_bs); | 172 | + blk_dec_in_flight(blk); |
46 | + bdrv_drained_begin(old_bs); | 173 | + return -ENOMEDIUM; |
47 | + bdrv_drained_begin(new_bs); | 174 | + } |
48 | + | 175 | + |
49 | + bdrv_replace_child_tran(child, new_bs, tran); | 176 | + ret = bdrv_co_zone_append(blk_bs(blk), offset, qiov, flags); |
50 | + | 177 | + blk_dec_in_flight(blk); |
51 | + found = g_hash_table_new(NULL, NULL); | ||
52 | + refresh_list = bdrv_topological_dfs(refresh_list, found, old_bs); | ||
53 | + refresh_list = bdrv_topological_dfs(refresh_list, found, new_bs); | ||
54 | + | ||
55 | + ret = bdrv_list_refresh_perms(refresh_list, NULL, tran, errp); | ||
56 | + | ||
57 | + tran_finalize(tran, ret); | ||
58 | + | ||
59 | + bdrv_drained_end(old_bs); | ||
60 | + bdrv_drained_end(new_bs); | ||
61 | + bdrv_unref(old_bs); | ||
62 | + | ||
63 | + return ret; | 178 | + return ret; |
64 | +} | 179 | +} |
65 | + | 180 | + |
66 | static void bdrv_delete(BlockDriverState *bs) | 181 | void blk_drain(BlockBackend *blk) |
67 | { | 182 | { |
68 | assert(bdrv_op_blocker_is_empty(bs)); | 183 | BlockDriverState *bs = blk_bs(blk); |
184 | diff --git a/block/file-posix.c b/block/file-posix.c | ||
185 | index XXXXXXX..XXXXXXX 100644 | ||
186 | --- a/block/file-posix.c | ||
187 | +++ b/block/file-posix.c | ||
188 | @@ -XXX,XX +XXX,XX @@ typedef struct BDRVRawState { | ||
189 | bool has_write_zeroes:1; | ||
190 | bool use_linux_aio:1; | ||
191 | bool use_linux_io_uring:1; | ||
192 | + int64_t *offset; /* offset of zone append operation */ | ||
193 | int page_cache_inconsistent; /* errno from fdatasync failure */ | ||
194 | bool has_fallocate; | ||
195 | bool needs_alignment; | ||
196 | @@ -XXX,XX +XXX,XX @@ static ssize_t handle_aiocb_rw_vector(RawPosixAIOData *aiocb) | ||
197 | ssize_t len; | ||
198 | |||
199 | len = RETRY_ON_EINTR( | ||
200 | - (aiocb->aio_type & QEMU_AIO_WRITE) ? | ||
201 | + (aiocb->aio_type & (QEMU_AIO_WRITE | QEMU_AIO_ZONE_APPEND)) ? | ||
202 | qemu_pwritev(aiocb->aio_fildes, | ||
203 | aiocb->io.iov, | ||
204 | aiocb->io.niov, | ||
205 | @@ -XXX,XX +XXX,XX @@ static ssize_t handle_aiocb_rw_linear(RawPosixAIOData *aiocb, char *buf) | ||
206 | ssize_t len; | ||
207 | |||
208 | while (offset < aiocb->aio_nbytes) { | ||
209 | - if (aiocb->aio_type & QEMU_AIO_WRITE) { | ||
210 | + if (aiocb->aio_type & (QEMU_AIO_WRITE | QEMU_AIO_ZONE_APPEND)) { | ||
211 | len = pwrite(aiocb->aio_fildes, | ||
212 | (const char *)buf + offset, | ||
213 | aiocb->aio_nbytes - offset, | ||
214 | @@ -XXX,XX +XXX,XX @@ static int handle_aiocb_rw(void *opaque) | ||
215 | } | ||
216 | |||
217 | nbytes = handle_aiocb_rw_linear(aiocb, buf); | ||
218 | - if (!(aiocb->aio_type & QEMU_AIO_WRITE)) { | ||
219 | + if (!(aiocb->aio_type & (QEMU_AIO_WRITE | QEMU_AIO_ZONE_APPEND))) { | ||
220 | char *p = buf; | ||
221 | size_t count = aiocb->aio_nbytes, copy; | ||
222 | int i; | ||
223 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_prw(BlockDriverState *bs, uint64_t offset, | ||
224 | if (fd_open(bs) < 0) | ||
225 | return -EIO; | ||
226 | #if defined(CONFIG_BLKZONED) | ||
227 | - if (type & QEMU_AIO_WRITE && bs->wps) { | ||
228 | + if ((type & (QEMU_AIO_WRITE | QEMU_AIO_ZONE_APPEND)) && bs->wps) { | ||
229 | qemu_co_mutex_lock(&bs->wps->colock); | ||
230 | + if (type & QEMU_AIO_ZONE_APPEND && bs->bl.zone_size) { | ||
231 | + int index = offset / bs->bl.zone_size; | ||
232 | + offset = bs->wps->wp[index]; | ||
233 | + } | ||
234 | } | ||
235 | #endif | ||
236 | |||
237 | @@ -XXX,XX +XXX,XX @@ out: | ||
238 | #if defined(CONFIG_BLKZONED) | ||
239 | BlockZoneWps *wps = bs->wps; | ||
240 | if (ret == 0) { | ||
241 | - if (type & QEMU_AIO_WRITE && wps && bs->bl.zone_size) { | ||
242 | + if ((type & (QEMU_AIO_WRITE | QEMU_AIO_ZONE_APPEND)) | ||
243 | + && wps && bs->bl.zone_size) { | ||
244 | uint64_t *wp = &wps->wp[offset / bs->bl.zone_size]; | ||
245 | if (!BDRV_ZT_IS_CONV(*wp)) { | ||
246 | + if (type & QEMU_AIO_ZONE_APPEND) { | ||
247 | + *s->offset = *wp; | ||
248 | + } | ||
249 | /* Advance the wp if needed */ | ||
250 | if (offset + bytes > *wp) { | ||
251 | *wp = offset + bytes; | ||
252 | @@ -XXX,XX +XXX,XX @@ out: | ||
253 | } | ||
254 | } | ||
255 | } else { | ||
256 | - if (type & QEMU_AIO_WRITE) { | ||
257 | + if (type & (QEMU_AIO_WRITE | QEMU_AIO_ZONE_APPEND)) { | ||
258 | update_zones_wp(bs, s->fd, 0, 1); | ||
259 | } | ||
260 | } | ||
261 | |||
262 | - if (type & QEMU_AIO_WRITE && wps) { | ||
263 | + if ((type & (QEMU_AIO_WRITE | QEMU_AIO_ZONE_APPEND)) && wps) { | ||
264 | qemu_co_mutex_unlock(&wps->colock); | ||
265 | } | ||
266 | #endif | ||
267 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_zone_mgmt(BlockDriverState *bs, BlockZoneOp op, | ||
268 | } | ||
269 | #endif | ||
270 | |||
271 | +#if defined(CONFIG_BLKZONED) | ||
272 | +static int coroutine_fn raw_co_zone_append(BlockDriverState *bs, | ||
273 | + int64_t *offset, | ||
274 | + QEMUIOVector *qiov, | ||
275 | + BdrvRequestFlags flags) { | ||
276 | + assert(flags == 0); | ||
277 | + int64_t zone_size_mask = bs->bl.zone_size - 1; | ||
278 | + int64_t iov_len = 0; | ||
279 | + int64_t len = 0; | ||
280 | + BDRVRawState *s = bs->opaque; | ||
281 | + s->offset = offset; | ||
282 | + | ||
283 | + if (*offset & zone_size_mask) { | ||
284 | + error_report("sector offset %" PRId64 " is not aligned to zone size " | ||
285 | + "%" PRId32 "", *offset / 512, bs->bl.zone_size / 512); | ||
286 | + return -EINVAL; | ||
287 | + } | ||
288 | + | ||
289 | + int64_t wg = bs->bl.write_granularity; | ||
290 | + int64_t wg_mask = wg - 1; | ||
291 | + for (int i = 0; i < qiov->niov; i++) { | ||
292 | + iov_len = qiov->iov[i].iov_len; | ||
293 | + if (iov_len & wg_mask) { | ||
294 | + error_report("len of IOVector[%d] %" PRId64 " is not aligned to " | ||
295 | + "block size %" PRId64 "", i, iov_len, wg); | ||
296 | + return -EINVAL; | ||
297 | + } | ||
298 | + len += iov_len; | ||
299 | + } | ||
300 | + | ||
301 | + return raw_co_prw(bs, *offset, len, qiov, QEMU_AIO_ZONE_APPEND); | ||
302 | +} | ||
303 | +#endif | ||
304 | + | ||
305 | static coroutine_fn int | ||
306 | raw_do_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
307 | bool blkdev) | ||
308 | @@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_host_device = { | ||
309 | /* zone management operations */ | ||
310 | .bdrv_co_zone_report = raw_co_zone_report, | ||
311 | .bdrv_co_zone_mgmt = raw_co_zone_mgmt, | ||
312 | + .bdrv_co_zone_append = raw_co_zone_append, | ||
313 | #endif | ||
314 | }; | ||
315 | |||
316 | diff --git a/block/io.c b/block/io.c | ||
317 | index XXXXXXX..XXXXXXX 100644 | ||
318 | --- a/block/io.c | ||
319 | +++ b/block/io.c | ||
320 | @@ -XXX,XX +XXX,XX @@ out: | ||
321 | return co.ret; | ||
322 | } | ||
323 | |||
324 | +int coroutine_fn bdrv_co_zone_append(BlockDriverState *bs, int64_t *offset, | ||
325 | + QEMUIOVector *qiov, | ||
326 | + BdrvRequestFlags flags) | ||
327 | +{ | ||
328 | + int ret; | ||
329 | + BlockDriver *drv = bs->drv; | ||
330 | + CoroutineIOCompletion co = { | ||
331 | + .coroutine = qemu_coroutine_self(), | ||
332 | + }; | ||
333 | + IO_CODE(); | ||
334 | + | ||
335 | + ret = bdrv_check_qiov_request(*offset, qiov->size, qiov, 0, NULL); | ||
336 | + if (ret < 0) { | ||
337 | + return ret; | ||
338 | + } | ||
339 | + | ||
340 | + bdrv_inc_in_flight(bs); | ||
341 | + if (!drv || !drv->bdrv_co_zone_append || bs->bl.zoned == BLK_Z_NONE) { | ||
342 | + co.ret = -ENOTSUP; | ||
343 | + goto out; | ||
344 | + } | ||
345 | + co.ret = drv->bdrv_co_zone_append(bs, offset, qiov, flags); | ||
346 | +out: | ||
347 | + bdrv_dec_in_flight(bs); | ||
348 | + return co.ret; | ||
349 | +} | ||
350 | + | ||
351 | void *qemu_blockalign(BlockDriverState *bs, size_t size) | ||
352 | { | ||
353 | IO_CODE(); | ||
354 | diff --git a/block/io_uring.c b/block/io_uring.c | ||
355 | index XXXXXXX..XXXXXXX 100644 | ||
356 | --- a/block/io_uring.c | ||
357 | +++ b/block/io_uring.c | ||
358 | @@ -XXX,XX +XXX,XX @@ static int luring_do_submit(int fd, LuringAIOCB *luringcb, LuringState *s, | ||
359 | io_uring_prep_writev(sqes, fd, luringcb->qiov->iov, | ||
360 | luringcb->qiov->niov, offset); | ||
361 | break; | ||
362 | + case QEMU_AIO_ZONE_APPEND: | ||
363 | + io_uring_prep_writev(sqes, fd, luringcb->qiov->iov, | ||
364 | + luringcb->qiov->niov, offset); | ||
365 | + break; | ||
366 | case QEMU_AIO_READ: | ||
367 | io_uring_prep_readv(sqes, fd, luringcb->qiov->iov, | ||
368 | luringcb->qiov->niov, offset); | ||
369 | diff --git a/block/linux-aio.c b/block/linux-aio.c | ||
370 | index XXXXXXX..XXXXXXX 100644 | ||
371 | --- a/block/linux-aio.c | ||
372 | +++ b/block/linux-aio.c | ||
373 | @@ -XXX,XX +XXX,XX @@ static int laio_do_submit(int fd, struct qemu_laiocb *laiocb, off_t offset, | ||
374 | case QEMU_AIO_WRITE: | ||
375 | io_prep_pwritev(iocbs, fd, qiov->iov, qiov->niov, offset); | ||
376 | break; | ||
377 | + case QEMU_AIO_ZONE_APPEND: | ||
378 | + io_prep_pwritev(iocbs, fd, qiov->iov, qiov->niov, offset); | ||
379 | + break; | ||
380 | case QEMU_AIO_READ: | ||
381 | io_prep_preadv(iocbs, fd, qiov->iov, qiov->niov, offset); | ||
382 | break; | ||
383 | diff --git a/block/raw-format.c b/block/raw-format.c | ||
384 | index XXXXXXX..XXXXXXX 100644 | ||
385 | --- a/block/raw-format.c | ||
386 | +++ b/block/raw-format.c | ||
387 | @@ -XXX,XX +XXX,XX @@ raw_co_zone_mgmt(BlockDriverState *bs, BlockZoneOp op, | ||
388 | return bdrv_co_zone_mgmt(bs->file->bs, op, offset, len); | ||
389 | } | ||
390 | |||
391 | +static int coroutine_fn GRAPH_RDLOCK | ||
392 | +raw_co_zone_append(BlockDriverState *bs,int64_t *offset, QEMUIOVector *qiov, | ||
393 | + BdrvRequestFlags flags) | ||
394 | +{ | ||
395 | + return bdrv_co_zone_append(bs->file->bs, offset, qiov, flags); | ||
396 | +} | ||
397 | + | ||
398 | static int64_t coroutine_fn GRAPH_RDLOCK | ||
399 | raw_co_getlength(BlockDriverState *bs) | ||
400 | { | ||
401 | @@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_raw = { | ||
402 | .bdrv_co_pdiscard = &raw_co_pdiscard, | ||
403 | .bdrv_co_zone_report = &raw_co_zone_report, | ||
404 | .bdrv_co_zone_mgmt = &raw_co_zone_mgmt, | ||
405 | + .bdrv_co_zone_append = &raw_co_zone_append, | ||
406 | .bdrv_co_block_status = &raw_co_block_status, | ||
407 | .bdrv_co_copy_range_from = &raw_co_copy_range_from, | ||
408 | .bdrv_co_copy_range_to = &raw_co_copy_range_to, | ||
69 | -- | 409 | -- |
70 | 2.31.1 | 410 | 2.39.2 |
71 | |||
72 | diff view generated by jsdifflib |
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 1 | From: Sam Li <faithilikerun@gmail.com> |
---|---|---|---|
2 | 2 | ||
3 | The main consumer of cluster-size is block-copy. Let's calculate it | 3 | The patch tests zone append writes by reporting the zone wp after |
4 | here instead of passing through backup-top. | 4 | the completion of the call. "zap -p" option can print the sector |
5 | offset value after completion, which should be the start sector | ||
6 | where the append write begins. | ||
5 | 7 | ||
6 | We are going to publish copy-before-write filter soon, so it will be | 8 | Signed-off-by: Sam Li <faithilikerun@gmail.com> |
7 | created through options. But we don't want for now to make explicit | 9 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> |
8 | option for cluster-size, let's continue to calculate it automatically. | 10 | Message-id: 20230407081657.17947-4-faithilikerun@gmail.com |
9 | So, now is the time to get rid of cluster_size argument for | 11 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> |
10 | bdrv_cbw_append(). | 12 | --- |
13 | qemu-io-cmds.c | 75 ++++++++++++++++++++++++++++++ | ||
14 | tests/qemu-iotests/tests/zoned | 16 +++++++ | ||
15 | tests/qemu-iotests/tests/zoned.out | 16 +++++++ | ||
16 | 3 files changed, 107 insertions(+) | ||
11 | 17 | ||
12 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 18 | diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c |
13 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
14 | Message-Id: <20210824083856.17408-10-vsementsov@virtuozzo.com> | ||
15 | [hreitz: Add qemu/error-report.h include to block/block-copy.c] | ||
16 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
17 | --- | ||
18 | block/copy-before-write.h | 1 - | ||
19 | include/block/block-copy.h | 5 +-- | ||
20 | block/backup.c | 62 ++++++-------------------------------- | ||
21 | block/block-copy.c | 52 +++++++++++++++++++++++++++++++- | ||
22 | block/copy-before-write.c | 10 +++--- | ||
23 | 5 files changed, 67 insertions(+), 63 deletions(-) | ||
24 | |||
25 | diff --git a/block/copy-before-write.h b/block/copy-before-write.h | ||
26 | index XXXXXXX..XXXXXXX 100644 | 19 | index XXXXXXX..XXXXXXX 100644 |
27 | --- a/block/copy-before-write.h | 20 | --- a/qemu-io-cmds.c |
28 | +++ b/block/copy-before-write.h | 21 | +++ b/qemu-io-cmds.c |
29 | @@ -XXX,XX +XXX,XX @@ | 22 | @@ -XXX,XX +XXX,XX @@ static const cmdinfo_t zone_reset_cmd = { |
30 | BlockDriverState *bdrv_cbw_append(BlockDriverState *source, | 23 | .oneline = "reset a zone write pointer in zone block device", |
31 | BlockDriverState *target, | ||
32 | const char *filter_node_name, | ||
33 | - uint64_t cluster_size, | ||
34 | bool compress, | ||
35 | BlockCopyState **bcs, | ||
36 | Error **errp); | ||
37 | diff --git a/include/block/block-copy.h b/include/block/block-copy.h | ||
38 | index XXXXXXX..XXXXXXX 100644 | ||
39 | --- a/include/block/block-copy.h | ||
40 | +++ b/include/block/block-copy.h | ||
41 | @@ -XXX,XX +XXX,XX @@ typedef struct BlockCopyState BlockCopyState; | ||
42 | typedef struct BlockCopyCallState BlockCopyCallState; | ||
43 | |||
44 | BlockCopyState *block_copy_state_new(BdrvChild *source, BdrvChild *target, | ||
45 | - int64_t cluster_size, bool use_copy_range, | ||
46 | - bool compress, Error **errp); | ||
47 | + bool use_copy_range, bool compress, | ||
48 | + Error **errp); | ||
49 | |||
50 | /* Function should be called prior any actual copy request */ | ||
51 | void block_copy_set_copy_opts(BlockCopyState *s, bool use_copy_range, | ||
52 | @@ -XXX,XX +XXX,XX @@ void block_copy_kick(BlockCopyCallState *call_state); | ||
53 | void block_copy_call_cancel(BlockCopyCallState *call_state); | ||
54 | |||
55 | BdrvDirtyBitmap *block_copy_dirty_bitmap(BlockCopyState *s); | ||
56 | +int64_t block_copy_cluster_size(BlockCopyState *s); | ||
57 | void block_copy_set_skip_unallocated(BlockCopyState *s, bool skip); | ||
58 | |||
59 | #endif /* BLOCK_COPY_H */ | ||
60 | diff --git a/block/backup.c b/block/backup.c | ||
61 | index XXXXXXX..XXXXXXX 100644 | ||
62 | --- a/block/backup.c | ||
63 | +++ b/block/backup.c | ||
64 | @@ -XXX,XX +XXX,XX @@ | ||
65 | |||
66 | #include "block/copy-before-write.h" | ||
67 | |||
68 | -#define BACKUP_CLUSTER_SIZE_DEFAULT (1 << 16) | ||
69 | - | ||
70 | typedef struct BackupBlockJob { | ||
71 | BlockJob common; | ||
72 | BlockDriverState *cbw; | ||
73 | @@ -XXX,XX +XXX,XX @@ static const BlockJobDriver backup_job_driver = { | ||
74 | .set_speed = backup_set_speed, | ||
75 | }; | 24 | }; |
76 | 25 | ||
77 | -static int64_t backup_calculate_cluster_size(BlockDriverState *target, | 26 | +static int do_aio_zone_append(BlockBackend *blk, QEMUIOVector *qiov, |
78 | - Error **errp) | 27 | + int64_t *offset, int flags, int *total) |
79 | -{ | 28 | +{ |
80 | - int ret; | 29 | + int async_ret = NOT_DONE; |
81 | - BlockDriverInfo bdi; | ||
82 | - bool target_does_cow = bdrv_backing_chain_next(target); | ||
83 | - | ||
84 | - /* | ||
85 | - * If there is no backing file on the target, we cannot rely on COW if our | ||
86 | - * backup cluster size is smaller than the target cluster size. Even for | ||
87 | - * targets with a backing file, try to avoid COW if possible. | ||
88 | - */ | ||
89 | - ret = bdrv_get_info(target, &bdi); | ||
90 | - if (ret == -ENOTSUP && !target_does_cow) { | ||
91 | - /* Cluster size is not defined */ | ||
92 | - warn_report("The target block device doesn't provide " | ||
93 | - "information about the block size and it doesn't have a " | ||
94 | - "backing file. The default block size of %u bytes is " | ||
95 | - "used. If the actual block size of the target exceeds " | ||
96 | - "this default, the backup may be unusable", | ||
97 | - BACKUP_CLUSTER_SIZE_DEFAULT); | ||
98 | - return BACKUP_CLUSTER_SIZE_DEFAULT; | ||
99 | - } else if (ret < 0 && !target_does_cow) { | ||
100 | - error_setg_errno(errp, -ret, | ||
101 | - "Couldn't determine the cluster size of the target image, " | ||
102 | - "which has no backing file"); | ||
103 | - error_append_hint(errp, | ||
104 | - "Aborting, since this may create an unusable destination image\n"); | ||
105 | - return ret; | ||
106 | - } else if (ret < 0 && target_does_cow) { | ||
107 | - /* Not fatal; just trudge on ahead. */ | ||
108 | - return BACKUP_CLUSTER_SIZE_DEFAULT; | ||
109 | - } | ||
110 | - | ||
111 | - return MAX(BACKUP_CLUSTER_SIZE_DEFAULT, bdi.cluster_size); | ||
112 | -} | ||
113 | - | ||
114 | BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, | ||
115 | BlockDriverState *target, int64_t speed, | ||
116 | MirrorSyncMode sync_mode, BdrvDirtyBitmap *sync_bitmap, | ||
117 | @@ -XXX,XX +XXX,XX @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, | ||
118 | return NULL; | ||
119 | } | ||
120 | |||
121 | - cluster_size = backup_calculate_cluster_size(target, errp); | ||
122 | - if (cluster_size < 0) { | ||
123 | - goto error; | ||
124 | - } | ||
125 | - | ||
126 | if (perf->max_workers < 1) { | ||
127 | error_setg(errp, "max-workers must be greater than zero"); | ||
128 | return NULL; | ||
129 | @@ -XXX,XX +XXX,XX @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, | ||
130 | return NULL; | ||
131 | } | ||
132 | |||
133 | - if (perf->max_chunk && perf->max_chunk < cluster_size) { | ||
134 | - error_setg(errp, "Required max-chunk (%" PRIi64 ") is less than backup " | ||
135 | - "cluster size (%" PRIi64 ")", perf->max_chunk, cluster_size); | ||
136 | - return NULL; | ||
137 | - } | ||
138 | - | ||
139 | - | ||
140 | if (sync_bitmap) { | ||
141 | /* If we need to write to this bitmap, check that we can: */ | ||
142 | if (bitmap_mode != BITMAP_SYNC_MODE_NEVER && | ||
143 | @@ -XXX,XX +XXX,XX @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, | ||
144 | goto error; | ||
145 | } | ||
146 | |||
147 | - cbw = bdrv_cbw_append(bs, target, filter_node_name, | ||
148 | - cluster_size, false, &bcs, errp); | ||
149 | + cbw = bdrv_cbw_append(bs, target, filter_node_name, false, &bcs, errp); | ||
150 | if (!cbw) { | ||
151 | goto error; | ||
152 | } | ||
153 | |||
154 | + cluster_size = block_copy_cluster_size(bcs); | ||
155 | + | 30 | + |
156 | + if (perf->max_chunk && perf->max_chunk < cluster_size) { | 31 | + blk_aio_zone_append(blk, offset, qiov, flags, aio_rw_done, &async_ret); |
157 | + error_setg(errp, "Required max-chunk (%" PRIi64 ") is less than backup " | 32 | + while (async_ret == NOT_DONE) { |
158 | + "cluster size (%" PRIi64 ")", perf->max_chunk, cluster_size); | 33 | + main_loop_wait(false); |
159 | + goto error; | ||
160 | + } | 34 | + } |
161 | + | 35 | + |
162 | /* job->len is fixed, so we can't allow resize */ | 36 | + *total = qiov->size; |
163 | job = block_job_create(job_id, &backup_job_driver, txn, cbw, | 37 | + return async_ret < 0 ? async_ret : 1; |
164 | 0, BLK_PERM_ALL, | 38 | +} |
165 | diff --git a/block/block-copy.c b/block/block-copy.c | 39 | + |
166 | index XXXXXXX..XXXXXXX 100644 | 40 | +static int zone_append_f(BlockBackend *blk, int argc, char **argv) |
167 | --- a/block/block-copy.c | ||
168 | +++ b/block/block-copy.c | ||
169 | @@ -XXX,XX +XXX,XX @@ | ||
170 | #include "qemu/units.h" | ||
171 | #include "qemu/coroutine.h" | ||
172 | #include "block/aio_task.h" | ||
173 | +#include "qemu/error-report.h" | ||
174 | |||
175 | #define BLOCK_COPY_MAX_COPY_RANGE (16 * MiB) | ||
176 | #define BLOCK_COPY_MAX_BUFFER (1 * MiB) | ||
177 | #define BLOCK_COPY_MAX_MEM (128 * MiB) | ||
178 | #define BLOCK_COPY_MAX_WORKERS 64 | ||
179 | #define BLOCK_COPY_SLICE_TIME 100000000ULL /* ns */ | ||
180 | +#define BLOCK_COPY_CLUSTER_SIZE_DEFAULT (1 << 16) | ||
181 | |||
182 | typedef enum { | ||
183 | COPY_READ_WRITE_CLUSTER, | ||
184 | @@ -XXX,XX +XXX,XX @@ void block_copy_set_copy_opts(BlockCopyState *s, bool use_copy_range, | ||
185 | } | ||
186 | } | ||
187 | |||
188 | +static int64_t block_copy_calculate_cluster_size(BlockDriverState *target, | ||
189 | + Error **errp) | ||
190 | +{ | 41 | +{ |
191 | + int ret; | 42 | + int ret; |
192 | + BlockDriverInfo bdi; | 43 | + bool pflag = false; |
193 | + bool target_does_cow = bdrv_backing_chain_next(target); | 44 | + int flags = 0; |
45 | + int total = 0; | ||
46 | + int64_t offset; | ||
47 | + char *buf; | ||
48 | + int c, nr_iov; | ||
49 | + int pattern = 0xcd; | ||
50 | + QEMUIOVector qiov; | ||
194 | + | 51 | + |
195 | + /* | 52 | + if (optind > argc - 3) { |
196 | + * If there is no backing file on the target, we cannot rely on COW if our | 53 | + return -EINVAL; |
197 | + * backup cluster size is smaller than the target cluster size. Even for | ||
198 | + * targets with a backing file, try to avoid COW if possible. | ||
199 | + */ | ||
200 | + ret = bdrv_get_info(target, &bdi); | ||
201 | + if (ret == -ENOTSUP && !target_does_cow) { | ||
202 | + /* Cluster size is not defined */ | ||
203 | + warn_report("The target block device doesn't provide " | ||
204 | + "information about the block size and it doesn't have a " | ||
205 | + "backing file. The default block size of %u bytes is " | ||
206 | + "used. If the actual block size of the target exceeds " | ||
207 | + "this default, the backup may be unusable", | ||
208 | + BLOCK_COPY_CLUSTER_SIZE_DEFAULT); | ||
209 | + return BLOCK_COPY_CLUSTER_SIZE_DEFAULT; | ||
210 | + } else if (ret < 0 && !target_does_cow) { | ||
211 | + error_setg_errno(errp, -ret, | ||
212 | + "Couldn't determine the cluster size of the target image, " | ||
213 | + "which has no backing file"); | ||
214 | + error_append_hint(errp, | ||
215 | + "Aborting, since this may create an unusable destination image\n"); | ||
216 | + return ret; | ||
217 | + } else if (ret < 0 && target_does_cow) { | ||
218 | + /* Not fatal; just trudge on ahead. */ | ||
219 | + return BLOCK_COPY_CLUSTER_SIZE_DEFAULT; | ||
220 | + } | 54 | + } |
221 | + | 55 | + |
222 | + return MAX(BLOCK_COPY_CLUSTER_SIZE_DEFAULT, bdi.cluster_size); | 56 | + if ((c = getopt(argc, argv, "p")) != -1) { |
57 | + pflag = true; | ||
58 | + } | ||
59 | + | ||
60 | + offset = cvtnum(argv[optind]); | ||
61 | + if (offset < 0) { | ||
62 | + print_cvtnum_err(offset, argv[optind]); | ||
63 | + return offset; | ||
64 | + } | ||
65 | + optind++; | ||
66 | + nr_iov = argc - optind; | ||
67 | + buf = create_iovec(blk, &qiov, &argv[optind], nr_iov, pattern, | ||
68 | + flags & BDRV_REQ_REGISTERED_BUF); | ||
69 | + if (buf == NULL) { | ||
70 | + return -EINVAL; | ||
71 | + } | ||
72 | + ret = do_aio_zone_append(blk, &qiov, &offset, flags, &total); | ||
73 | + if (ret < 0) { | ||
74 | + printf("zone append failed: %s\n", strerror(-ret)); | ||
75 | + goto out; | ||
76 | + } | ||
77 | + | ||
78 | + if (pflag) { | ||
79 | + printf("After zap done, the append sector is 0x%" PRIx64 "\n", | ||
80 | + tosector(offset)); | ||
81 | + } | ||
82 | + | ||
83 | +out: | ||
84 | + qemu_io_free(blk, buf, qiov.size, | ||
85 | + flags & BDRV_REQ_REGISTERED_BUF); | ||
86 | + qemu_iovec_destroy(&qiov); | ||
87 | + return ret; | ||
223 | +} | 88 | +} |
224 | + | 89 | + |
225 | BlockCopyState *block_copy_state_new(BdrvChild *source, BdrvChild *target, | 90 | +static const cmdinfo_t zone_append_cmd = { |
226 | - int64_t cluster_size, bool use_copy_range, | 91 | + .name = "zone_append", |
227 | + bool use_copy_range, | 92 | + .altname = "zap", |
228 | bool compress, Error **errp) | 93 | + .cfunc = zone_append_f, |
229 | { | 94 | + .argmin = 3, |
230 | BlockCopyState *s; | 95 | + .argmax = 4, |
231 | + int64_t cluster_size; | 96 | + .args = "offset len [len..]", |
232 | BdrvDirtyBitmap *copy_bitmap; | 97 | + .oneline = "append write a number of bytes at a specified offset", |
233 | bool is_fleecing; | 98 | +}; |
234 | |||
235 | + cluster_size = block_copy_calculate_cluster_size(target->bs, errp); | ||
236 | + if (cluster_size < 0) { | ||
237 | + return NULL; | ||
238 | + } | ||
239 | + | 99 | + |
240 | copy_bitmap = bdrv_create_dirty_bitmap(source->bs, cluster_size, NULL, | 100 | static int truncate_f(BlockBackend *blk, int argc, char **argv); |
241 | errp); | 101 | static const cmdinfo_t truncate_cmd = { |
242 | if (!copy_bitmap) { | 102 | .name = "truncate", |
243 | @@ -XXX,XX +XXX,XX @@ BdrvDirtyBitmap *block_copy_dirty_bitmap(BlockCopyState *s) | 103 | @@ -XXX,XX +XXX,XX @@ static void __attribute((constructor)) init_qemuio_commands(void) |
244 | return s->copy_bitmap; | 104 | qemuio_add_command(&zone_close_cmd); |
245 | } | 105 | qemuio_add_command(&zone_finish_cmd); |
246 | 106 | qemuio_add_command(&zone_reset_cmd); | |
247 | +int64_t block_copy_cluster_size(BlockCopyState *s) | 107 | + qemuio_add_command(&zone_append_cmd); |
248 | +{ | 108 | qemuio_add_command(&truncate_cmd); |
249 | + return s->cluster_size; | 109 | qemuio_add_command(&length_cmd); |
250 | +} | 110 | qemuio_add_command(&info_cmd); |
111 | diff --git a/tests/qemu-iotests/tests/zoned b/tests/qemu-iotests/tests/zoned | ||
112 | index XXXXXXX..XXXXXXX 100755 | ||
113 | --- a/tests/qemu-iotests/tests/zoned | ||
114 | +++ b/tests/qemu-iotests/tests/zoned | ||
115 | @@ -XXX,XX +XXX,XX @@ echo "(5) resetting the second zone" | ||
116 | $QEMU_IO $IMG -c "zrs 268435456 268435456" | ||
117 | echo "After resetting a zone:" | ||
118 | $QEMU_IO $IMG -c "zrp 268435456 1" | ||
119 | +echo | ||
120 | +echo | ||
121 | +echo "(6) append write" # the physical block size of the device is 4096 | ||
122 | +$QEMU_IO $IMG -c "zrp 0 1" | ||
123 | +$QEMU_IO $IMG -c "zap -p 0 0x1000 0x2000" | ||
124 | +echo "After appending the first zone firstly:" | ||
125 | +$QEMU_IO $IMG -c "zrp 0 1" | ||
126 | +$QEMU_IO $IMG -c "zap -p 0 0x1000 0x2000" | ||
127 | +echo "After appending the first zone secondly:" | ||
128 | +$QEMU_IO $IMG -c "zrp 0 1" | ||
129 | +$QEMU_IO $IMG -c "zap -p 268435456 0x1000 0x2000" | ||
130 | +echo "After appending the second zone firstly:" | ||
131 | +$QEMU_IO $IMG -c "zrp 268435456 1" | ||
132 | +$QEMU_IO $IMG -c "zap -p 268435456 0x1000 0x2000" | ||
133 | +echo "After appending the second zone secondly:" | ||
134 | +$QEMU_IO $IMG -c "zrp 268435456 1" | ||
135 | |||
136 | # success, all done | ||
137 | echo "*** done" | ||
138 | diff --git a/tests/qemu-iotests/tests/zoned.out b/tests/qemu-iotests/tests/zoned.out | ||
139 | index XXXXXXX..XXXXXXX 100644 | ||
140 | --- a/tests/qemu-iotests/tests/zoned.out | ||
141 | +++ b/tests/qemu-iotests/tests/zoned.out | ||
142 | @@ -XXX,XX +XXX,XX @@ start: 0x80000, len 0x80000, cap 0x80000, wptr 0x100000, zcond:14, [type: 2] | ||
143 | (5) resetting the second zone | ||
144 | After resetting a zone: | ||
145 | start: 0x80000, len 0x80000, cap 0x80000, wptr 0x80000, zcond:1, [type: 2] | ||
251 | + | 146 | + |
252 | void block_copy_set_skip_unallocated(BlockCopyState *s, bool skip) | 147 | + |
253 | { | 148 | +(6) append write |
254 | qatomic_set(&s->skip_unallocated, skip); | 149 | +start: 0x0, len 0x80000, cap 0x80000, wptr 0x0, zcond:1, [type: 2] |
255 | diff --git a/block/copy-before-write.c b/block/copy-before-write.c | 150 | +After zap done, the append sector is 0x0 |
256 | index XXXXXXX..XXXXXXX 100644 | 151 | +After appending the first zone firstly: |
257 | --- a/block/copy-before-write.c | 152 | +start: 0x0, len 0x80000, cap 0x80000, wptr 0x18, zcond:2, [type: 2] |
258 | +++ b/block/copy-before-write.c | 153 | +After zap done, the append sector is 0x18 |
259 | @@ -XXX,XX +XXX,XX @@ | 154 | +After appending the first zone secondly: |
260 | typedef struct BDRVCopyBeforeWriteState { | 155 | +start: 0x0, len 0x80000, cap 0x80000, wptr 0x30, zcond:2, [type: 2] |
261 | BlockCopyState *bcs; | 156 | +After zap done, the append sector is 0x80000 |
262 | BdrvChild *target; | 157 | +After appending the second zone firstly: |
263 | - int64_t cluster_size; | 158 | +start: 0x80000, len 0x80000, cap 0x80000, wptr 0x80018, zcond:2, [type: 2] |
264 | } BDRVCopyBeforeWriteState; | 159 | +After zap done, the append sector is 0x80018 |
265 | 160 | +After appending the second zone secondly: | |
266 | static coroutine_fn int cbw_co_preadv( | 161 | +start: 0x80000, len 0x80000, cap 0x80000, wptr 0x80030, zcond:2, [type: 2] |
267 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int cbw_do_copy_before_write(BlockDriverState *bs, | 162 | *** done |
268 | { | ||
269 | BDRVCopyBeforeWriteState *s = bs->opaque; | ||
270 | uint64_t off, end; | ||
271 | + int64_t cluster_size = block_copy_cluster_size(s->bcs); | ||
272 | |||
273 | if (flags & BDRV_REQ_WRITE_UNCHANGED) { | ||
274 | return 0; | ||
275 | } | ||
276 | |||
277 | - off = QEMU_ALIGN_DOWN(offset, s->cluster_size); | ||
278 | - end = QEMU_ALIGN_UP(offset + bytes, s->cluster_size); | ||
279 | + off = QEMU_ALIGN_DOWN(offset, cluster_size); | ||
280 | + end = QEMU_ALIGN_UP(offset + bytes, cluster_size); | ||
281 | |||
282 | return block_copy(s->bcs, off, end - off, true); | ||
283 | } | ||
284 | @@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_cbw_filter = { | ||
285 | BlockDriverState *bdrv_cbw_append(BlockDriverState *source, | ||
286 | BlockDriverState *target, | ||
287 | const char *filter_node_name, | ||
288 | - uint64_t cluster_size, | ||
289 | bool compress, | ||
290 | BlockCopyState **bcs, | ||
291 | Error **errp) | ||
292 | @@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_cbw_append(BlockDriverState *source, | ||
293 | } | ||
294 | appended = true; | ||
295 | |||
296 | - state->cluster_size = cluster_size; | ||
297 | state->bcs = block_copy_state_new(top->backing, state->target, | ||
298 | - cluster_size, false, compress, errp); | ||
299 | + false, compress, errp); | ||
300 | if (!state->bcs) { | ||
301 | error_prepend(errp, "Cannot create block-copy-state: "); | ||
302 | goto fail; | ||
303 | -- | 163 | -- |
304 | 2.31.1 | 164 | 2.39.2 |
305 | |||
306 | diff view generated by jsdifflib |
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 1 | From: Sam Li <faithilikerun@gmail.com> |
---|---|---|---|
2 | 2 | ||
3 | We are going to publish copy-before-write filter to be used in separate | 3 | Signed-off-by: Sam Li <faithilikerun@gmail.com> |
4 | of backup. Future step would support bitmap for the filter. But let's | 4 | Reviewed-by: Dmitry Fomichev <dmitry.fomichev@wdc.com> |
5 | start from full set bitmap. | 5 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> |
6 | Message-id: 20230407081657.17947-5-faithilikerun@gmail.com | ||
7 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
8 | --- | ||
9 | block/file-posix.c | 3 +++ | ||
10 | block/trace-events | 2 ++ | ||
11 | 2 files changed, 5 insertions(+) | ||
6 | 12 | ||
7 | We have to modify backup, as bitmap is first initialized by | 13 | diff --git a/block/file-posix.c b/block/file-posix.c |
8 | copy-before-write filter, and then backup modifies it. | ||
9 | |||
10 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
11 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
12 | Message-Id: <20210824083856.17408-20-vsementsov@virtuozzo.com> | ||
13 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
14 | --- | ||
15 | block/backup.c | 16 +++++++--------- | ||
16 | block/copy-before-write.c | 4 ++++ | ||
17 | 2 files changed, 11 insertions(+), 9 deletions(-) | ||
18 | |||
19 | diff --git a/block/backup.c b/block/backup.c | ||
20 | index XXXXXXX..XXXXXXX 100644 | 14 | index XXXXXXX..XXXXXXX 100644 |
21 | --- a/block/backup.c | 15 | --- a/block/file-posix.c |
22 | +++ b/block/backup.c | 16 | +++ b/block/file-posix.c |
23 | @@ -XXX,XX +XXX,XX @@ static void backup_init_bcs_bitmap(BackupBlockJob *job) | 17 | @@ -XXX,XX +XXX,XX @@ out: |
24 | BdrvDirtyBitmap *bcs_bitmap = block_copy_dirty_bitmap(job->bcs); | 18 | if (!BDRV_ZT_IS_CONV(*wp)) { |
25 | 19 | if (type & QEMU_AIO_ZONE_APPEND) { | |
26 | if (job->sync_mode == MIRROR_SYNC_MODE_BITMAP) { | 20 | *s->offset = *wp; |
27 | + bdrv_clear_dirty_bitmap(bcs_bitmap, NULL); | 21 | + trace_zbd_zone_append_complete(bs, *s->offset |
28 | ret = bdrv_dirty_bitmap_merge_internal(bcs_bitmap, job->sync_bitmap, | 22 | + >> BDRV_SECTOR_BITS); |
29 | NULL, true); | 23 | } |
30 | assert(ret); | 24 | /* Advance the wp if needed */ |
31 | - } else { | 25 | if (offset + bytes > *wp) { |
32 | - if (job->sync_mode == MIRROR_SYNC_MODE_TOP) { | 26 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_zone_append(BlockDriverState *bs, |
33 | - /* | 27 | len += iov_len; |
34 | - * We can't hog the coroutine to initialize this thoroughly. | ||
35 | - * Set a flag and resume work when we are able to yield safely. | ||
36 | - */ | ||
37 | - block_copy_set_skip_unallocated(job->bcs, true); | ||
38 | - } | ||
39 | - bdrv_set_dirty_bitmap(bcs_bitmap, 0, job->len); | ||
40 | + } else if (job->sync_mode == MIRROR_SYNC_MODE_TOP) { | ||
41 | + /* | ||
42 | + * We can't hog the coroutine to initialize this thoroughly. | ||
43 | + * Set a flag and resume work when we are able to yield safely. | ||
44 | + */ | ||
45 | + block_copy_set_skip_unallocated(job->bcs, true); | ||
46 | } | 28 | } |
47 | 29 | ||
48 | estimate = bdrv_get_dirty_count(bcs_bitmap); | 30 | + trace_zbd_zone_append(bs, *offset >> BDRV_SECTOR_BITS); |
49 | diff --git a/block/copy-before-write.c b/block/copy-before-write.c | 31 | return raw_co_prw(bs, *offset, len, qiov, QEMU_AIO_ZONE_APPEND); |
32 | } | ||
33 | #endif | ||
34 | diff --git a/block/trace-events b/block/trace-events | ||
50 | index XXXXXXX..XXXXXXX 100644 | 35 | index XXXXXXX..XXXXXXX 100644 |
51 | --- a/block/copy-before-write.c | 36 | --- a/block/trace-events |
52 | +++ b/block/copy-before-write.c | 37 | +++ b/block/trace-events |
53 | @@ -XXX,XX +XXX,XX @@ static void cbw_child_perm(BlockDriverState *bs, BdrvChild *c, | 38 | @@ -XXX,XX +XXX,XX @@ file_hdev_is_sg(int type, int version) "SG device found: type=%d, version=%d" |
54 | static int cbw_init(BlockDriverState *bs, QDict *options, Error **errp) | 39 | file_flush_fdatasync_failed(int err) "errno %d" |
55 | { | 40 | zbd_zone_report(void *bs, unsigned int nr_zones, int64_t sector) "bs %p report %d zones starting at sector offset 0x%" PRIx64 "" |
56 | BDRVCopyBeforeWriteState *s = bs->opaque; | 41 | zbd_zone_mgmt(void *bs, const char *op_name, int64_t sector, int64_t len) "bs %p %s starts at sector offset 0x%" PRIx64 " over a range of 0x%" PRIx64 " sectors" |
57 | + BdrvDirtyBitmap *copy_bitmap; | 42 | +zbd_zone_append(void *bs, int64_t sector) "bs %p append at sector offset 0x%" PRIx64 "" |
58 | 43 | +zbd_zone_append_complete(void *bs, int64_t sector) "bs %p returns append sector 0x%" PRIx64 "" | |
59 | bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, | 44 | |
60 | BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, | 45 | # ssh.c |
61 | @@ -XXX,XX +XXX,XX @@ static int cbw_init(BlockDriverState *bs, QDict *options, Error **errp) | 46 | sftp_error(const char *op, const char *ssh_err, int ssh_err_code, int sftp_err_code) "%s failed: %s (libssh error code: %d, sftp error code: %d)" |
62 | return -EINVAL; | ||
63 | } | ||
64 | |||
65 | + copy_bitmap = block_copy_dirty_bitmap(s->bcs); | ||
66 | + bdrv_set_dirty_bitmap(copy_bitmap, 0, bdrv_dirty_bitmap_size(copy_bitmap)); | ||
67 | + | ||
68 | return 0; | ||
69 | } | ||
70 | |||
71 | -- | 47 | -- |
72 | 2.31.1 | 48 | 2.39.2 |
73 | |||
74 | diff view generated by jsdifflib |
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 1 | From: Sam Li <faithilikerun@gmail.com> |
---|---|---|---|
2 | 2 | ||
3 | Add function to change bs inside blk. | 3 | Use scripts/update-linux-headers.sh to update headers to 6.3-rc1. |
4 | 4 | ||
5 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 5 | Signed-off-by: Sam Li <faithilikerun@gmail.com> |
6 | Reviewed-by: Max Reitz <mreitz@redhat.com> | 6 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> |
7 | Message-Id: <20210824083856.17408-3-vsementsov@virtuozzo.com> | 7 | Reviewed-by: Dmitry Fomichev <dmitry.fomichev@wdc.com> |
8 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | 8 | Message-id: 20230407082528.18841-2-faithilikerun@gmail.com |
9 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
9 | --- | 10 | --- |
10 | include/sysemu/block-backend.h | 1 + | 11 | include/standard-headers/drm/drm_fourcc.h | 12 +++ |
11 | block/block-backend.c | 8 ++++++++ | 12 | include/standard-headers/linux/ethtool.h | 48 ++++++++- |
12 | 2 files changed, 9 insertions(+) | 13 | include/standard-headers/linux/fuse.h | 45 +++++++- |
14 | include/standard-headers/linux/pci_regs.h | 1 + | ||
15 | include/standard-headers/linux/vhost_types.h | 2 + | ||
16 | include/standard-headers/linux/virtio_blk.h | 105 +++++++++++++++++++ | ||
17 | linux-headers/asm-arm64/kvm.h | 1 + | ||
18 | linux-headers/asm-x86/kvm.h | 34 +++++- | ||
19 | linux-headers/linux/kvm.h | 9 ++ | ||
20 | linux-headers/linux/vfio.h | 15 +-- | ||
21 | linux-headers/linux/vhost.h | 8 ++ | ||
22 | 11 files changed, 270 insertions(+), 10 deletions(-) | ||
13 | 23 | ||
14 | diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h | 24 | diff --git a/include/standard-headers/drm/drm_fourcc.h b/include/standard-headers/drm/drm_fourcc.h |
15 | index XXXXXXX..XXXXXXX 100644 | 25 | index XXXXXXX..XXXXXXX 100644 |
16 | --- a/include/sysemu/block-backend.h | 26 | --- a/include/standard-headers/drm/drm_fourcc.h |
17 | +++ b/include/sysemu/block-backend.h | 27 | +++ b/include/standard-headers/drm/drm_fourcc.h |
18 | @@ -XXX,XX +XXX,XX @@ BlockBackend *blk_by_public(BlockBackendPublic *public); | 28 | @@ -XXX,XX +XXX,XX @@ extern "C" { |
19 | BlockDriverState *blk_bs(BlockBackend *blk); | 29 | * |
20 | void blk_remove_bs(BlockBackend *blk); | 30 | * The authoritative list of format modifier codes is found in |
21 | int blk_insert_bs(BlockBackend *blk, BlockDriverState *bs, Error **errp); | 31 | * `include/uapi/drm/drm_fourcc.h` |
22 | +int blk_replace_bs(BlockBackend *blk, BlockDriverState *new_bs, Error **errp); | 32 | + * |
23 | bool bdrv_has_blk(BlockDriverState *bs); | 33 | + * Open Source User Waiver |
24 | bool bdrv_is_root_node(BlockDriverState *bs); | 34 | + * ----------------------- |
25 | int blk_set_perm(BlockBackend *blk, uint64_t perm, uint64_t shared_perm, | 35 | + * |
26 | diff --git a/block/block-backend.c b/block/block-backend.c | 36 | + * Because this is the authoritative source for pixel formats and modifiers |
27 | index XXXXXXX..XXXXXXX 100644 | 37 | + * referenced by GL, Vulkan extensions and other standards and hence used both |
28 | --- a/block/block-backend.c | 38 | + * by open source and closed source driver stacks, the usual requirement for an |
29 | +++ b/block/block-backend.c | 39 | + * upstream in-kernel or open source userspace user does not apply. |
30 | @@ -XXX,XX +XXX,XX @@ int blk_insert_bs(BlockBackend *blk, BlockDriverState *bs, Error **errp) | 40 | + * |
31 | return 0; | 41 | + * To ensure, as much as feasible, compatibility across stacks and avoid |
32 | } | 42 | + * confusion with incompatible enumerations stakeholders for all relevant driver |
43 | + * stacks should approve additions. | ||
44 | */ | ||
45 | |||
46 | #define fourcc_code(a, b, c, d) ((uint32_t)(a) | ((uint32_t)(b) << 8) | \ | ||
47 | diff --git a/include/standard-headers/linux/ethtool.h b/include/standard-headers/linux/ethtool.h | ||
48 | index XXXXXXX..XXXXXXX 100644 | ||
49 | --- a/include/standard-headers/linux/ethtool.h | ||
50 | +++ b/include/standard-headers/linux/ethtool.h | ||
51 | @@ -XXX,XX +XXX,XX @@ enum ethtool_stringset { | ||
52 | ETH_SS_COUNT | ||
53 | }; | ||
54 | |||
55 | +/** | ||
56 | + * enum ethtool_mac_stats_src - source of ethtool MAC statistics | ||
57 | + * @ETHTOOL_MAC_STATS_SRC_AGGREGATE: | ||
58 | + * if device supports a MAC merge layer, this retrieves the aggregate | ||
59 | + * statistics of the eMAC and pMAC. Otherwise, it retrieves just the | ||
60 | + * statistics of the single (express) MAC. | ||
61 | + * @ETHTOOL_MAC_STATS_SRC_EMAC: | ||
62 | + * if device supports a MM layer, this retrieves the eMAC statistics. | ||
63 | + * Otherwise, it retrieves the statistics of the single (express) MAC. | ||
64 | + * @ETHTOOL_MAC_STATS_SRC_PMAC: | ||
65 | + * if device supports a MM layer, this retrieves the pMAC statistics. | ||
66 | + */ | ||
67 | +enum ethtool_mac_stats_src { | ||
68 | + ETHTOOL_MAC_STATS_SRC_AGGREGATE, | ||
69 | + ETHTOOL_MAC_STATS_SRC_EMAC, | ||
70 | + ETHTOOL_MAC_STATS_SRC_PMAC, | ||
71 | +}; | ||
72 | + | ||
73 | /** | ||
74 | * enum ethtool_module_power_mode_policy - plug-in module power mode policy | ||
75 | * @ETHTOOL_MODULE_POWER_MODE_POLICY_HIGH: Module is always in high power mode. | ||
76 | @@ -XXX,XX +XXX,XX @@ enum ethtool_podl_pse_pw_d_status { | ||
77 | ETHTOOL_PODL_PSE_PW_D_STATUS_ERROR, | ||
78 | }; | ||
79 | |||
80 | +/** | ||
81 | + * enum ethtool_mm_verify_status - status of MAC Merge Verify function | ||
82 | + * @ETHTOOL_MM_VERIFY_STATUS_UNKNOWN: | ||
83 | + * verification status is unknown | ||
84 | + * @ETHTOOL_MM_VERIFY_STATUS_INITIAL: | ||
85 | + * the 802.3 Verify State diagram is in the state INIT_VERIFICATION | ||
86 | + * @ETHTOOL_MM_VERIFY_STATUS_VERIFYING: | ||
87 | + * the Verify State diagram is in the state VERIFICATION_IDLE, | ||
88 | + * SEND_VERIFY or WAIT_FOR_RESPONSE | ||
89 | + * @ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED: | ||
90 | + * indicates that the Verify State diagram is in the state VERIFIED | ||
91 | + * @ETHTOOL_MM_VERIFY_STATUS_FAILED: | ||
92 | + * the Verify State diagram is in the state VERIFY_FAIL | ||
93 | + * @ETHTOOL_MM_VERIFY_STATUS_DISABLED: | ||
94 | + * verification of preemption operation is disabled | ||
95 | + */ | ||
96 | +enum ethtool_mm_verify_status { | ||
97 | + ETHTOOL_MM_VERIFY_STATUS_UNKNOWN, | ||
98 | + ETHTOOL_MM_VERIFY_STATUS_INITIAL, | ||
99 | + ETHTOOL_MM_VERIFY_STATUS_VERIFYING, | ||
100 | + ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED, | ||
101 | + ETHTOOL_MM_VERIFY_STATUS_FAILED, | ||
102 | + ETHTOOL_MM_VERIFY_STATUS_DISABLED, | ||
103 | +}; | ||
104 | + | ||
105 | /** | ||
106 | * struct ethtool_gstrings - string set for data tagging | ||
107 | * @cmd: Command number = %ETHTOOL_GSTRINGS | ||
108 | @@ -XXX,XX +XXX,XX @@ struct ethtool_rxnfc { | ||
109 | uint32_t rule_cnt; | ||
110 | uint32_t rss_context; | ||
111 | }; | ||
112 | - uint32_t rule_locs[0]; | ||
113 | + uint32_t rule_locs[]; | ||
114 | }; | ||
115 | |||
116 | |||
117 | @@ -XXX,XX +XXX,XX @@ enum ethtool_link_mode_bit_indices { | ||
118 | ETHTOOL_LINK_MODE_800000baseDR8_2_Full_BIT = 96, | ||
119 | ETHTOOL_LINK_MODE_800000baseSR8_Full_BIT = 97, | ||
120 | ETHTOOL_LINK_MODE_800000baseVR8_Full_BIT = 98, | ||
121 | + ETHTOOL_LINK_MODE_10baseT1S_Full_BIT = 99, | ||
122 | + ETHTOOL_LINK_MODE_10baseT1S_Half_BIT = 100, | ||
123 | + ETHTOOL_LINK_MODE_10baseT1S_P2MP_Half_BIT = 101, | ||
124 | |||
125 | /* must be last entry */ | ||
126 | __ETHTOOL_LINK_MODE_MASK_NBITS | ||
127 | diff --git a/include/standard-headers/linux/fuse.h b/include/standard-headers/linux/fuse.h | ||
128 | index XXXXXXX..XXXXXXX 100644 | ||
129 | --- a/include/standard-headers/linux/fuse.h | ||
130 | +++ b/include/standard-headers/linux/fuse.h | ||
131 | @@ -XXX,XX +XXX,XX @@ | ||
132 | * 7.38 | ||
133 | * - add FUSE_EXPIRE_ONLY flag to fuse_notify_inval_entry | ||
134 | * - add FOPEN_PARALLEL_DIRECT_WRITES | ||
135 | + * - add total_extlen to fuse_in_header | ||
136 | + * - add FUSE_MAX_NR_SECCTX | ||
137 | + * - add extension header | ||
138 | + * - add FUSE_EXT_GROUPS | ||
139 | + * - add FUSE_CREATE_SUPP_GROUP | ||
140 | */ | ||
141 | |||
142 | #ifndef _LINUX_FUSE_H | ||
143 | @@ -XXX,XX +XXX,XX @@ struct fuse_file_lock { | ||
144 | * FUSE_SECURITY_CTX: add security context to create, mkdir, symlink, and | ||
145 | * mknod | ||
146 | * FUSE_HAS_INODE_DAX: use per inode DAX | ||
147 | + * FUSE_CREATE_SUPP_GROUP: add supplementary group info to create, mkdir, | ||
148 | + * symlink and mknod (single group that matches parent) | ||
149 | */ | ||
150 | #define FUSE_ASYNC_READ (1 << 0) | ||
151 | #define FUSE_POSIX_LOCKS (1 << 1) | ||
152 | @@ -XXX,XX +XXX,XX @@ struct fuse_file_lock { | ||
153 | /* bits 32..63 get shifted down 32 bits into the flags2 field */ | ||
154 | #define FUSE_SECURITY_CTX (1ULL << 32) | ||
155 | #define FUSE_HAS_INODE_DAX (1ULL << 33) | ||
156 | +#define FUSE_CREATE_SUPP_GROUP (1ULL << 34) | ||
157 | |||
158 | /** | ||
159 | * CUSE INIT request/reply flags | ||
160 | @@ -XXX,XX +XXX,XX @@ struct fuse_file_lock { | ||
161 | */ | ||
162 | #define FUSE_EXPIRE_ONLY (1 << 0) | ||
163 | |||
164 | +/** | ||
165 | + * extension type | ||
166 | + * FUSE_MAX_NR_SECCTX: maximum value of &fuse_secctx_header.nr_secctx | ||
167 | + * FUSE_EXT_GROUPS: &fuse_supp_groups extension | ||
168 | + */ | ||
169 | +enum fuse_ext_type { | ||
170 | + /* Types 0..31 are reserved for fuse_secctx_header */ | ||
171 | + FUSE_MAX_NR_SECCTX = 31, | ||
172 | + FUSE_EXT_GROUPS = 32, | ||
173 | +}; | ||
174 | + | ||
175 | enum fuse_opcode { | ||
176 | FUSE_LOOKUP = 1, | ||
177 | FUSE_FORGET = 2, /* no reply */ | ||
178 | @@ -XXX,XX +XXX,XX @@ struct fuse_in_header { | ||
179 | uint32_t uid; | ||
180 | uint32_t gid; | ||
181 | uint32_t pid; | ||
182 | - uint32_t padding; | ||
183 | + uint16_t total_extlen; /* length of extensions in 8byte units */ | ||
184 | + uint16_t padding; | ||
185 | }; | ||
186 | |||
187 | struct fuse_out_header { | ||
188 | @@ -XXX,XX +XXX,XX @@ struct fuse_secctx_header { | ||
189 | uint32_t nr_secctx; | ||
190 | }; | ||
191 | |||
192 | +/** | ||
193 | + * struct fuse_ext_header - extension header | ||
194 | + * @size: total size of this extension including this header | ||
195 | + * @type: type of extension | ||
196 | + * | ||
197 | + * This is made compatible with fuse_secctx_header by using type values > | ||
198 | + * FUSE_MAX_NR_SECCTX | ||
199 | + */ | ||
200 | +struct fuse_ext_header { | ||
201 | + uint32_t size; | ||
202 | + uint32_t type; | ||
203 | +}; | ||
204 | + | ||
205 | +/** | ||
206 | + * struct fuse_supp_groups - Supplementary group extension | ||
207 | + * @nr_groups: number of supplementary groups | ||
208 | + * @groups: flexible array of group IDs | ||
209 | + */ | ||
210 | +struct fuse_supp_groups { | ||
211 | + uint32_t nr_groups; | ||
212 | + uint32_t groups[]; | ||
213 | +}; | ||
214 | + | ||
215 | #endif /* _LINUX_FUSE_H */ | ||
216 | diff --git a/include/standard-headers/linux/pci_regs.h b/include/standard-headers/linux/pci_regs.h | ||
217 | index XXXXXXX..XXXXXXX 100644 | ||
218 | --- a/include/standard-headers/linux/pci_regs.h | ||
219 | +++ b/include/standard-headers/linux/pci_regs.h | ||
220 | @@ -XXX,XX +XXX,XX @@ | ||
221 | #define PCI_EXP_LNKCTL2_TX_MARGIN 0x0380 /* Transmit Margin */ | ||
222 | #define PCI_EXP_LNKCTL2_HASD 0x0020 /* HW Autonomous Speed Disable */ | ||
223 | #define PCI_EXP_LNKSTA2 0x32 /* Link Status 2 */ | ||
224 | +#define PCI_EXP_LNKSTA2_FLIT 0x0400 /* Flit Mode Status */ | ||
225 | #define PCI_CAP_EXP_ENDPOINT_SIZEOF_V2 0x32 /* end of v2 EPs w/ link */ | ||
226 | #define PCI_EXP_SLTCAP2 0x34 /* Slot Capabilities 2 */ | ||
227 | #define PCI_EXP_SLTCAP2_IBPD 0x00000001 /* In-band PD Disable Supported */ | ||
228 | diff --git a/include/standard-headers/linux/vhost_types.h b/include/standard-headers/linux/vhost_types.h | ||
229 | index XXXXXXX..XXXXXXX 100644 | ||
230 | --- a/include/standard-headers/linux/vhost_types.h | ||
231 | +++ b/include/standard-headers/linux/vhost_types.h | ||
232 | @@ -XXX,XX +XXX,XX @@ struct vhost_vdpa_iova_range { | ||
233 | #define VHOST_BACKEND_F_IOTLB_ASID 0x3 | ||
234 | /* Device can be suspended */ | ||
235 | #define VHOST_BACKEND_F_SUSPEND 0x4 | ||
236 | +/* Device can be resumed */ | ||
237 | +#define VHOST_BACKEND_F_RESUME 0x5 | ||
238 | |||
239 | #endif | ||
240 | diff --git a/include/standard-headers/linux/virtio_blk.h b/include/standard-headers/linux/virtio_blk.h | ||
241 | index XXXXXXX..XXXXXXX 100644 | ||
242 | --- a/include/standard-headers/linux/virtio_blk.h | ||
243 | +++ b/include/standard-headers/linux/virtio_blk.h | ||
244 | @@ -XXX,XX +XXX,XX @@ | ||
245 | #define VIRTIO_BLK_F_DISCARD 13 /* DISCARD is supported */ | ||
246 | #define VIRTIO_BLK_F_WRITE_ZEROES 14 /* WRITE ZEROES is supported */ | ||
247 | #define VIRTIO_BLK_F_SECURE_ERASE 16 /* Secure Erase is supported */ | ||
248 | +#define VIRTIO_BLK_F_ZONED 17 /* Zoned block device */ | ||
249 | |||
250 | /* Legacy feature bits */ | ||
251 | #ifndef VIRTIO_BLK_NO_LEGACY | ||
252 | @@ -XXX,XX +XXX,XX @@ struct virtio_blk_config { | ||
253 | /* Secure erase commands must be aligned to this number of sectors. */ | ||
254 | __virtio32 secure_erase_sector_alignment; | ||
255 | |||
256 | + /* Zoned block device characteristics (if VIRTIO_BLK_F_ZONED) */ | ||
257 | + struct virtio_blk_zoned_characteristics { | ||
258 | + uint32_t zone_sectors; | ||
259 | + uint32_t max_open_zones; | ||
260 | + uint32_t max_active_zones; | ||
261 | + uint32_t max_append_sectors; | ||
262 | + uint32_t write_granularity; | ||
263 | + uint8_t model; | ||
264 | + uint8_t unused2[3]; | ||
265 | + } zoned; | ||
266 | } QEMU_PACKED; | ||
267 | |||
268 | /* | ||
269 | @@ -XXX,XX +XXX,XX @@ struct virtio_blk_config { | ||
270 | /* Secure erase command */ | ||
271 | #define VIRTIO_BLK_T_SECURE_ERASE 14 | ||
272 | |||
273 | +/* Zone append command */ | ||
274 | +#define VIRTIO_BLK_T_ZONE_APPEND 15 | ||
275 | + | ||
276 | +/* Report zones command */ | ||
277 | +#define VIRTIO_BLK_T_ZONE_REPORT 16 | ||
278 | + | ||
279 | +/* Open zone command */ | ||
280 | +#define VIRTIO_BLK_T_ZONE_OPEN 18 | ||
281 | + | ||
282 | +/* Close zone command */ | ||
283 | +#define VIRTIO_BLK_T_ZONE_CLOSE 20 | ||
284 | + | ||
285 | +/* Finish zone command */ | ||
286 | +#define VIRTIO_BLK_T_ZONE_FINISH 22 | ||
287 | + | ||
288 | +/* Reset zone command */ | ||
289 | +#define VIRTIO_BLK_T_ZONE_RESET 24 | ||
290 | + | ||
291 | +/* Reset All zones command */ | ||
292 | +#define VIRTIO_BLK_T_ZONE_RESET_ALL 26 | ||
293 | + | ||
294 | #ifndef VIRTIO_BLK_NO_LEGACY | ||
295 | /* Barrier before this op. */ | ||
296 | #define VIRTIO_BLK_T_BARRIER 0x80000000 | ||
297 | @@ -XXX,XX +XXX,XX @@ struct virtio_blk_outhdr { | ||
298 | __virtio64 sector; | ||
299 | }; | ||
33 | 300 | ||
34 | +/* | 301 | +/* |
35 | + * Change BlockDriverState associated with @blk. | 302 | + * Supported zoned device models. |
36 | + */ | 303 | + */ |
37 | +int blk_replace_bs(BlockBackend *blk, BlockDriverState *new_bs, Error **errp) | 304 | + |
38 | +{ | 305 | +/* Regular block device */ |
39 | + return bdrv_replace_child_bs(blk->root, new_bs, errp); | 306 | +#define VIRTIO_BLK_Z_NONE 0 |
40 | +} | 307 | +/* Host-managed zoned device */ |
41 | + | 308 | +#define VIRTIO_BLK_Z_HM 1 |
309 | +/* Host-aware zoned device */ | ||
310 | +#define VIRTIO_BLK_Z_HA 2 | ||
311 | + | ||
312 | +/* | ||
313 | + * Zone descriptor. A part of VIRTIO_BLK_T_ZONE_REPORT command reply. | ||
314 | + */ | ||
315 | +struct virtio_blk_zone_descriptor { | ||
316 | + /* Zone capacity */ | ||
317 | + uint64_t z_cap; | ||
318 | + /* The starting sector of the zone */ | ||
319 | + uint64_t z_start; | ||
320 | + /* Zone write pointer position in sectors */ | ||
321 | + uint64_t z_wp; | ||
322 | + /* Zone type */ | ||
323 | + uint8_t z_type; | ||
324 | + /* Zone state */ | ||
325 | + uint8_t z_state; | ||
326 | + uint8_t reserved[38]; | ||
327 | +}; | ||
328 | + | ||
329 | +struct virtio_blk_zone_report { | ||
330 | + uint64_t nr_zones; | ||
331 | + uint8_t reserved[56]; | ||
332 | + struct virtio_blk_zone_descriptor zones[]; | ||
333 | +}; | ||
334 | + | ||
335 | +/* | ||
336 | + * Supported zone types. | ||
337 | + */ | ||
338 | + | ||
339 | +/* Conventional zone */ | ||
340 | +#define VIRTIO_BLK_ZT_CONV 1 | ||
341 | +/* Sequential Write Required zone */ | ||
342 | +#define VIRTIO_BLK_ZT_SWR 2 | ||
343 | +/* Sequential Write Preferred zone */ | ||
344 | +#define VIRTIO_BLK_ZT_SWP 3 | ||
345 | + | ||
346 | +/* | ||
347 | + * Zone states that are available for zones of all types. | ||
348 | + */ | ||
349 | + | ||
350 | +/* Not a write pointer (conventional zones only) */ | ||
351 | +#define VIRTIO_BLK_ZS_NOT_WP 0 | ||
352 | +/* Empty */ | ||
353 | +#define VIRTIO_BLK_ZS_EMPTY 1 | ||
354 | +/* Implicitly Open */ | ||
355 | +#define VIRTIO_BLK_ZS_IOPEN 2 | ||
356 | +/* Explicitly Open */ | ||
357 | +#define VIRTIO_BLK_ZS_EOPEN 3 | ||
358 | +/* Closed */ | ||
359 | +#define VIRTIO_BLK_ZS_CLOSED 4 | ||
360 | +/* Read-Only */ | ||
361 | +#define VIRTIO_BLK_ZS_RDONLY 13 | ||
362 | +/* Full */ | ||
363 | +#define VIRTIO_BLK_ZS_FULL 14 | ||
364 | +/* Offline */ | ||
365 | +#define VIRTIO_BLK_ZS_OFFLINE 15 | ||
366 | + | ||
367 | /* Unmap this range (only valid for write zeroes command) */ | ||
368 | #define VIRTIO_BLK_WRITE_ZEROES_FLAG_UNMAP 0x00000001 | ||
369 | |||
370 | @@ -XXX,XX +XXX,XX @@ struct virtio_scsi_inhdr { | ||
371 | #define VIRTIO_BLK_S_OK 0 | ||
372 | #define VIRTIO_BLK_S_IOERR 1 | ||
373 | #define VIRTIO_BLK_S_UNSUPP 2 | ||
374 | + | ||
375 | +/* Error codes that are specific to zoned block devices */ | ||
376 | +#define VIRTIO_BLK_S_ZONE_INVALID_CMD 3 | ||
377 | +#define VIRTIO_BLK_S_ZONE_UNALIGNED_WP 4 | ||
378 | +#define VIRTIO_BLK_S_ZONE_OPEN_RESOURCE 5 | ||
379 | +#define VIRTIO_BLK_S_ZONE_ACTIVE_RESOURCE 6 | ||
380 | + | ||
381 | #endif /* _LINUX_VIRTIO_BLK_H */ | ||
382 | diff --git a/linux-headers/asm-arm64/kvm.h b/linux-headers/asm-arm64/kvm.h | ||
383 | index XXXXXXX..XXXXXXX 100644 | ||
384 | --- a/linux-headers/asm-arm64/kvm.h | ||
385 | +++ b/linux-headers/asm-arm64/kvm.h | ||
386 | @@ -XXX,XX +XXX,XX @@ struct kvm_regs { | ||
387 | #define KVM_ARM_VCPU_SVE 4 /* enable SVE for this CPU */ | ||
388 | #define KVM_ARM_VCPU_PTRAUTH_ADDRESS 5 /* VCPU uses address authentication */ | ||
389 | #define KVM_ARM_VCPU_PTRAUTH_GENERIC 6 /* VCPU uses generic authentication */ | ||
390 | +#define KVM_ARM_VCPU_HAS_EL2 7 /* Support nested virtualization */ | ||
391 | |||
392 | struct kvm_vcpu_init { | ||
393 | __u32 target; | ||
394 | diff --git a/linux-headers/asm-x86/kvm.h b/linux-headers/asm-x86/kvm.h | ||
395 | index XXXXXXX..XXXXXXX 100644 | ||
396 | --- a/linux-headers/asm-x86/kvm.h | ||
397 | +++ b/linux-headers/asm-x86/kvm.h | ||
398 | @@ -XXX,XX +XXX,XX @@ | ||
399 | |||
400 | #include <linux/types.h> | ||
401 | #include <linux/ioctl.h> | ||
402 | +#include <linux/stddef.h> | ||
403 | |||
404 | #define KVM_PIO_PAGE_OFFSET 1 | ||
405 | #define KVM_COALESCED_MMIO_PAGE_OFFSET 2 | ||
406 | @@ -XXX,XX +XXX,XX @@ struct kvm_nested_state { | ||
407 | * KVM_{GET,PUT}_NESTED_STATE ioctl values. | ||
408 | */ | ||
409 | union { | ||
410 | - struct kvm_vmx_nested_state_data vmx[0]; | ||
411 | - struct kvm_svm_nested_state_data svm[0]; | ||
412 | + __DECLARE_FLEX_ARRAY(struct kvm_vmx_nested_state_data, vmx); | ||
413 | + __DECLARE_FLEX_ARRAY(struct kvm_svm_nested_state_data, svm); | ||
414 | } data; | ||
415 | }; | ||
416 | |||
417 | @@ -XXX,XX +XXX,XX @@ struct kvm_pmu_event_filter { | ||
418 | #define KVM_PMU_EVENT_ALLOW 0 | ||
419 | #define KVM_PMU_EVENT_DENY 1 | ||
420 | |||
421 | +#define KVM_PMU_EVENT_FLAG_MASKED_EVENTS BIT(0) | ||
422 | +#define KVM_PMU_EVENT_FLAGS_VALID_MASK (KVM_PMU_EVENT_FLAG_MASKED_EVENTS) | ||
423 | + | ||
424 | +/* | ||
425 | + * Masked event layout. | ||
426 | + * Bits Description | ||
427 | + * ---- ----------- | ||
428 | + * 7:0 event select (low bits) | ||
429 | + * 15:8 umask match | ||
430 | + * 31:16 unused | ||
431 | + * 35:32 event select (high bits) | ||
432 | + * 36:54 unused | ||
433 | + * 55 exclude bit | ||
434 | + * 63:56 umask mask | ||
435 | + */ | ||
436 | + | ||
437 | +#define KVM_PMU_ENCODE_MASKED_ENTRY(event_select, mask, match, exclude) \ | ||
438 | + (((event_select) & 0xFFULL) | (((event_select) & 0XF00ULL) << 24) | \ | ||
439 | + (((mask) & 0xFFULL) << 56) | \ | ||
440 | + (((match) & 0xFFULL) << 8) | \ | ||
441 | + ((__u64)(!!(exclude)) << 55)) | ||
442 | + | ||
443 | +#define KVM_PMU_MASKED_ENTRY_EVENT_SELECT \ | ||
444 | + (GENMASK_ULL(7, 0) | GENMASK_ULL(35, 32)) | ||
445 | +#define KVM_PMU_MASKED_ENTRY_UMASK_MASK (GENMASK_ULL(63, 56)) | ||
446 | +#define KVM_PMU_MASKED_ENTRY_UMASK_MATCH (GENMASK_ULL(15, 8)) | ||
447 | +#define KVM_PMU_MASKED_ENTRY_EXCLUDE (BIT_ULL(55)) | ||
448 | +#define KVM_PMU_MASKED_ENTRY_UMASK_MASK_SHIFT (56) | ||
449 | + | ||
450 | /* for KVM_{GET,SET,HAS}_DEVICE_ATTR */ | ||
451 | #define KVM_VCPU_TSC_CTRL 0 /* control group for the timestamp counter (TSC) */ | ||
452 | #define KVM_VCPU_TSC_OFFSET 0 /* attribute for the TSC offset */ | ||
453 | diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h | ||
454 | index XXXXXXX..XXXXXXX 100644 | ||
455 | --- a/linux-headers/linux/kvm.h | ||
456 | +++ b/linux-headers/linux/kvm.h | ||
457 | @@ -XXX,XX +XXX,XX @@ struct kvm_s390_mem_op { | ||
458 | struct { | ||
459 | __u8 ar; /* the access register number */ | ||
460 | __u8 key; /* access key, ignored if flag unset */ | ||
461 | + __u8 pad1[6]; /* ignored */ | ||
462 | + __u64 old_addr; /* ignored if cmpxchg flag unset */ | ||
463 | }; | ||
464 | __u32 sida_offset; /* offset into the sida */ | ||
465 | __u8 reserved[32]; /* ignored */ | ||
466 | @@ -XXX,XX +XXX,XX @@ struct kvm_s390_mem_op { | ||
467 | #define KVM_S390_MEMOP_SIDA_WRITE 3 | ||
468 | #define KVM_S390_MEMOP_ABSOLUTE_READ 4 | ||
469 | #define KVM_S390_MEMOP_ABSOLUTE_WRITE 5 | ||
470 | +#define KVM_S390_MEMOP_ABSOLUTE_CMPXCHG 6 | ||
471 | + | ||
472 | /* flags for kvm_s390_mem_op->flags */ | ||
473 | #define KVM_S390_MEMOP_F_CHECK_ONLY (1ULL << 0) | ||
474 | #define KVM_S390_MEMOP_F_INJECT_EXCEPTION (1ULL << 1) | ||
475 | #define KVM_S390_MEMOP_F_SKEY_PROTECTION (1ULL << 2) | ||
476 | |||
477 | +/* flags specifying extension support via KVM_CAP_S390_MEM_OP_EXTENSION */ | ||
478 | +#define KVM_S390_MEMOP_EXTENSION_CAP_BASE (1 << 0) | ||
479 | +#define KVM_S390_MEMOP_EXTENSION_CAP_CMPXCHG (1 << 1) | ||
480 | + | ||
481 | /* for KVM_INTERRUPT */ | ||
482 | struct kvm_interrupt { | ||
483 | /* in */ | ||
484 | @@ -XXX,XX +XXX,XX @@ struct kvm_ppc_resize_hpt { | ||
485 | #define KVM_CAP_DIRTY_LOG_RING_ACQ_REL 223 | ||
486 | #define KVM_CAP_S390_PROTECTED_ASYNC_DISABLE 224 | ||
487 | #define KVM_CAP_DIRTY_LOG_RING_WITH_BITMAP 225 | ||
488 | +#define KVM_CAP_PMU_EVENT_MASKED_EVENTS 226 | ||
489 | |||
490 | #ifdef KVM_CAP_IRQ_ROUTING | ||
491 | |||
492 | diff --git a/linux-headers/linux/vfio.h b/linux-headers/linux/vfio.h | ||
493 | index XXXXXXX..XXXXXXX 100644 | ||
494 | --- a/linux-headers/linux/vfio.h | ||
495 | +++ b/linux-headers/linux/vfio.h | ||
496 | @@ -XXX,XX +XXX,XX @@ | ||
497 | /* Supports VFIO_DMA_UNMAP_FLAG_ALL */ | ||
498 | #define VFIO_UNMAP_ALL 9 | ||
499 | |||
500 | -/* Supports the vaddr flag for DMA map and unmap */ | ||
501 | +/* | ||
502 | + * Supports the vaddr flag for DMA map and unmap. Not supported for mediated | ||
503 | + * devices, so this capability is subject to change as groups are added or | ||
504 | + * removed. | ||
505 | + */ | ||
506 | #define VFIO_UPDATE_VADDR 10 | ||
507 | |||
42 | /* | 508 | /* |
43 | * Sets the permission bitmasks that the user of the BlockBackend needs. | 509 | @@ -XXX,XX +XXX,XX @@ struct vfio_iommu_type1_info_dma_avail { |
510 | * Map process virtual addresses to IO virtual addresses using the | ||
511 | * provided struct vfio_dma_map. Caller sets argsz. READ &/ WRITE required. | ||
512 | * | ||
513 | - * If flags & VFIO_DMA_MAP_FLAG_VADDR, update the base vaddr for iova, and | ||
514 | - * unblock translation of host virtual addresses in the iova range. The vaddr | ||
515 | + * If flags & VFIO_DMA_MAP_FLAG_VADDR, update the base vaddr for iova. The vaddr | ||
516 | * must have previously been invalidated with VFIO_DMA_UNMAP_FLAG_VADDR. To | ||
517 | * maintain memory consistency within the user application, the updated vaddr | ||
518 | * must address the same memory object as originally mapped. Failure to do so | ||
519 | @@ -XXX,XX +XXX,XX @@ struct vfio_bitmap { | ||
520 | * must be 0. This cannot be combined with the get-dirty-bitmap flag. | ||
521 | * | ||
522 | * If flags & VFIO_DMA_UNMAP_FLAG_VADDR, do not unmap, but invalidate host | ||
523 | - * virtual addresses in the iova range. Tasks that attempt to translate an | ||
524 | - * iova's vaddr will block. DMA to already-mapped pages continues. This | ||
525 | - * cannot be combined with the get-dirty-bitmap flag. | ||
526 | + * virtual addresses in the iova range. DMA to already-mapped pages continues. | ||
527 | + * Groups may not be added to the container while any addresses are invalid. | ||
528 | + * This cannot be combined with the get-dirty-bitmap flag. | ||
44 | */ | 529 | */ |
530 | struct vfio_iommu_type1_dma_unmap { | ||
531 | __u32 argsz; | ||
532 | diff --git a/linux-headers/linux/vhost.h b/linux-headers/linux/vhost.h | ||
533 | index XXXXXXX..XXXXXXX 100644 | ||
534 | --- a/linux-headers/linux/vhost.h | ||
535 | +++ b/linux-headers/linux/vhost.h | ||
536 | @@ -XXX,XX +XXX,XX @@ | ||
537 | */ | ||
538 | #define VHOST_VDPA_SUSPEND _IO(VHOST_VIRTIO, 0x7D) | ||
539 | |||
540 | +/* Resume a device so it can resume processing virtqueue requests | ||
541 | + * | ||
542 | + * After the return of this ioctl the device will have restored all the | ||
543 | + * necessary states and it is fully operational to continue processing the | ||
544 | + * virtqueue descriptors. | ||
545 | + */ | ||
546 | +#define VHOST_VDPA_RESUME _IO(VHOST_VIRTIO, 0x7E) | ||
547 | + | ||
548 | #endif | ||
45 | -- | 549 | -- |
46 | 2.31.1 | 550 | 2.39.2 |
47 | |||
48 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
2 | 1 | ||
3 | Add field, so property can declare support for setting the property | ||
4 | when device is realized. To be used in the following commit. | ||
5 | |||
6 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
7 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
8 | Message-Id: <20210824083856.17408-4-vsementsov@virtuozzo.com> | ||
9 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
10 | --- | ||
11 | include/hw/qdev-properties.h | 1 + | ||
12 | hw/core/qdev-properties.c | 6 +++--- | ||
13 | 2 files changed, 4 insertions(+), 3 deletions(-) | ||
14 | |||
15 | diff --git a/include/hw/qdev-properties.h b/include/hw/qdev-properties.h | ||
16 | index XXXXXXX..XXXXXXX 100644 | ||
17 | --- a/include/hw/qdev-properties.h | ||
18 | +++ b/include/hw/qdev-properties.h | ||
19 | @@ -XXX,XX +XXX,XX @@ struct PropertyInfo { | ||
20 | const char *name; | ||
21 | const char *description; | ||
22 | const QEnumLookup *enum_table; | ||
23 | + bool realized_set_allowed; /* allow setting property on realized device */ | ||
24 | int (*print)(Object *obj, Property *prop, char *dest, size_t len); | ||
25 | void (*set_default_value)(ObjectProperty *op, const Property *prop); | ||
26 | ObjectProperty *(*create)(ObjectClass *oc, const char *name, | ||
27 | diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c | ||
28 | index XXXXXXX..XXXXXXX 100644 | ||
29 | --- a/hw/core/qdev-properties.c | ||
30 | +++ b/hw/core/qdev-properties.c | ||
31 | @@ -XXX,XX +XXX,XX @@ void qdev_prop_set_after_realize(DeviceState *dev, const char *name, | ||
32 | |||
33 | /* returns: true if property is allowed to be set, false otherwise */ | ||
34 | static bool qdev_prop_allow_set(Object *obj, const char *name, | ||
35 | - Error **errp) | ||
36 | + const PropertyInfo *info, Error **errp) | ||
37 | { | ||
38 | DeviceState *dev = DEVICE(obj); | ||
39 | |||
40 | - if (dev->realized) { | ||
41 | + if (dev->realized && !info->realized_set_allowed) { | ||
42 | qdev_prop_set_after_realize(dev, name, errp); | ||
43 | return false; | ||
44 | } | ||
45 | @@ -XXX,XX +XXX,XX @@ static void field_prop_set(Object *obj, Visitor *v, const char *name, | ||
46 | { | ||
47 | Property *prop = opaque; | ||
48 | |||
49 | - if (!qdev_prop_allow_set(obj, name, errp)) { | ||
50 | + if (!qdev_prop_allow_set(obj, name, prop->info, errp)) { | ||
51 | return; | ||
52 | } | ||
53 | |||
54 | -- | ||
55 | 2.31.1 | ||
56 | |||
57 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
2 | 1 | ||
3 | We are going to convert backup_top to full featured public filter, | ||
4 | which can be used in separate of backup job. Start from renaming from | ||
5 | "how it used" to "what it does". | ||
6 | |||
7 | While updating comments in 283 iotest, drop and rephrase also things | ||
8 | about ".active", as this field is now dropped, and filter doesn't have | ||
9 | "inactive" mode. | ||
10 | |||
11 | Note that this change may be considered as incompatible interface | ||
12 | change, as backup-top filter format name was visible through | ||
13 | query-block and query-named-block-nodes. | ||
14 | |||
15 | Still, consider the following reasoning: | ||
16 | |||
17 | 1. backup-top was never documented, so if someone depends on format | ||
18 | name (for driver that can't be used other than it is automatically | ||
19 | inserted on backup job start), it's a kind of "undocumented feature | ||
20 | use". So I think we are free to change it. | ||
21 | |||
22 | 2. There is a hope, that there is no such users: it's a lot more native | ||
23 | to give a good node-name to backup-top filter if need to operate | ||
24 | with it somehow, and don't touch format name. | ||
25 | |||
26 | 3. Another "incompatible" change in further commit would be moving | ||
27 | copy-before-write filter from using backing child to file child. And | ||
28 | this is even more reasonable than renaming: for now all public | ||
29 | filters are file-child based. | ||
30 | |||
31 | So, it's a risky change, but risk seems small and good interface worth | ||
32 | it. | ||
33 | |||
34 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
35 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
36 | Message-Id: <20210824083856.17408-6-vsementsov@virtuozzo.com> | ||
37 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
38 | --- | ||
39 | block/{backup-top.h => copy-before-write.h} | 28 +++--- | ||
40 | block/backup.c | 22 ++--- | ||
41 | block/{backup-top.c => copy-before-write.c} | 100 ++++++++++---------- | ||
42 | MAINTAINERS | 4 +- | ||
43 | block/meson.build | 2 +- | ||
44 | tests/qemu-iotests/283 | 35 +++---- | ||
45 | tests/qemu-iotests/283.out | 4 +- | ||
46 | 7 files changed, 95 insertions(+), 100 deletions(-) | ||
47 | rename block/{backup-top.h => copy-before-write.h} (56%) | ||
48 | rename block/{backup-top.c => copy-before-write.c} (62%) | ||
49 | |||
50 | diff --git a/block/backup-top.h b/block/copy-before-write.h | ||
51 | similarity index 56% | ||
52 | rename from block/backup-top.h | ||
53 | rename to block/copy-before-write.h | ||
54 | index XXXXXXX..XXXXXXX 100644 | ||
55 | --- a/block/backup-top.h | ||
56 | +++ b/block/copy-before-write.h | ||
57 | @@ -XXX,XX +XXX,XX @@ | ||
58 | /* | ||
59 | - * backup-top filter driver | ||
60 | + * copy-before-write filter driver | ||
61 | * | ||
62 | * The driver performs Copy-Before-Write (CBW) operation: it is injected above | ||
63 | * some node, and before each write it copies _old_ data to the target node. | ||
64 | * | ||
65 | - * Copyright (c) 2018-2019 Virtuozzo International GmbH. | ||
66 | + * Copyright (c) 2018-2021 Virtuozzo International GmbH. | ||
67 | * | ||
68 | * Author: | ||
69 | * Sementsov-Ogievskiy Vladimir <vsementsov@virtuozzo.com> | ||
70 | @@ -XXX,XX +XXX,XX @@ | ||
71 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
72 | */ | ||
73 | |||
74 | -#ifndef BACKUP_TOP_H | ||
75 | -#define BACKUP_TOP_H | ||
76 | +#ifndef COPY_BEFORE_WRITE_H | ||
77 | +#define COPY_BEFORE_WRITE_H | ||
78 | |||
79 | #include "block/block_int.h" | ||
80 | #include "block/block-copy.h" | ||
81 | |||
82 | -BlockDriverState *bdrv_backup_top_append(BlockDriverState *source, | ||
83 | - BlockDriverState *target, | ||
84 | - const char *filter_node_name, | ||
85 | - uint64_t cluster_size, | ||
86 | - BackupPerf *perf, | ||
87 | - BdrvRequestFlags write_flags, | ||
88 | - BlockCopyState **bcs, | ||
89 | - Error **errp); | ||
90 | -void bdrv_backup_top_drop(BlockDriverState *bs); | ||
91 | +BlockDriverState *bdrv_cbw_append(BlockDriverState *source, | ||
92 | + BlockDriverState *target, | ||
93 | + const char *filter_node_name, | ||
94 | + uint64_t cluster_size, | ||
95 | + BackupPerf *perf, | ||
96 | + BdrvRequestFlags write_flags, | ||
97 | + BlockCopyState **bcs, | ||
98 | + Error **errp); | ||
99 | +void bdrv_cbw_drop(BlockDriverState *bs); | ||
100 | |||
101 | -#endif /* BACKUP_TOP_H */ | ||
102 | +#endif /* COPY_BEFORE_WRITE_H */ | ||
103 | diff --git a/block/backup.c b/block/backup.c | ||
104 | index XXXXXXX..XXXXXXX 100644 | ||
105 | --- a/block/backup.c | ||
106 | +++ b/block/backup.c | ||
107 | @@ -XXX,XX +XXX,XX @@ | ||
108 | #include "qemu/bitmap.h" | ||
109 | #include "qemu/error-report.h" | ||
110 | |||
111 | -#include "block/backup-top.h" | ||
112 | +#include "block/copy-before-write.h" | ||
113 | |||
114 | #define BACKUP_CLUSTER_SIZE_DEFAULT (1 << 16) | ||
115 | |||
116 | typedef struct BackupBlockJob { | ||
117 | BlockJob common; | ||
118 | - BlockDriverState *backup_top; | ||
119 | + BlockDriverState *cbw; | ||
120 | BlockDriverState *source_bs; | ||
121 | BlockDriverState *target_bs; | ||
122 | |||
123 | @@ -XXX,XX +XXX,XX @@ static void backup_clean(Job *job) | ||
124 | { | ||
125 | BackupBlockJob *s = container_of(job, BackupBlockJob, common.job); | ||
126 | block_job_remove_all_bdrv(&s->common); | ||
127 | - bdrv_backup_top_drop(s->backup_top); | ||
128 | + bdrv_cbw_drop(s->cbw); | ||
129 | } | ||
130 | |||
131 | void backup_do_checkpoint(BlockJob *job, Error **errp) | ||
132 | @@ -XXX,XX +XXX,XX @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, | ||
133 | BackupBlockJob *job = NULL; | ||
134 | int64_t cluster_size; | ||
135 | BdrvRequestFlags write_flags; | ||
136 | - BlockDriverState *backup_top = NULL; | ||
137 | + BlockDriverState *cbw = NULL; | ||
138 | BlockCopyState *bcs = NULL; | ||
139 | |||
140 | assert(bs); | ||
141 | @@ -XXX,XX +XXX,XX @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, | ||
142 | write_flags = (bdrv_chain_contains(target, bs) ? BDRV_REQ_SERIALISING : 0) | | ||
143 | (compress ? BDRV_REQ_WRITE_COMPRESSED : 0), | ||
144 | |||
145 | - backup_top = bdrv_backup_top_append(bs, target, filter_node_name, | ||
146 | + cbw = bdrv_cbw_append(bs, target, filter_node_name, | ||
147 | cluster_size, perf, | ||
148 | write_flags, &bcs, errp); | ||
149 | - if (!backup_top) { | ||
150 | + if (!cbw) { | ||
151 | goto error; | ||
152 | } | ||
153 | |||
154 | /* job->len is fixed, so we can't allow resize */ | ||
155 | - job = block_job_create(job_id, &backup_job_driver, txn, backup_top, | ||
156 | + job = block_job_create(job_id, &backup_job_driver, txn, cbw, | ||
157 | 0, BLK_PERM_ALL, | ||
158 | speed, creation_flags, cb, opaque, errp); | ||
159 | if (!job) { | ||
160 | goto error; | ||
161 | } | ||
162 | |||
163 | - job->backup_top = backup_top; | ||
164 | + job->cbw = cbw; | ||
165 | job->source_bs = bs; | ||
166 | job->target_bs = target; | ||
167 | job->on_source_error = on_source_error; | ||
168 | @@ -XXX,XX +XXX,XX @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, | ||
169 | block_copy_set_progress_meter(bcs, &job->common.job.progress); | ||
170 | block_copy_set_speed(bcs, speed); | ||
171 | |||
172 | - /* Required permissions are already taken by backup-top target */ | ||
173 | + /* Required permissions are taken by copy-before-write filter target */ | ||
174 | block_job_add_bdrv(&job->common, "target", target, 0, BLK_PERM_ALL, | ||
175 | &error_abort); | ||
176 | |||
177 | @@ -XXX,XX +XXX,XX @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, | ||
178 | if (sync_bitmap) { | ||
179 | bdrv_reclaim_dirty_bitmap(sync_bitmap, NULL); | ||
180 | } | ||
181 | - if (backup_top) { | ||
182 | - bdrv_backup_top_drop(backup_top); | ||
183 | + if (cbw) { | ||
184 | + bdrv_cbw_drop(cbw); | ||
185 | } | ||
186 | |||
187 | return NULL; | ||
188 | diff --git a/block/backup-top.c b/block/copy-before-write.c | ||
189 | similarity index 62% | ||
190 | rename from block/backup-top.c | ||
191 | rename to block/copy-before-write.c | ||
192 | index XXXXXXX..XXXXXXX 100644 | ||
193 | --- a/block/backup-top.c | ||
194 | +++ b/block/copy-before-write.c | ||
195 | @@ -XXX,XX +XXX,XX @@ | ||
196 | /* | ||
197 | - * backup-top filter driver | ||
198 | + * copy-before-write filter driver | ||
199 | * | ||
200 | * The driver performs Copy-Before-Write (CBW) operation: it is injected above | ||
201 | * some node, and before each write it copies _old_ data to the target node. | ||
202 | * | ||
203 | - * Copyright (c) 2018-2019 Virtuozzo International GmbH. | ||
204 | + * Copyright (c) 2018-2021 Virtuozzo International GmbH. | ||
205 | * | ||
206 | * Author: | ||
207 | * Sementsov-Ogievskiy Vladimir <vsementsov@virtuozzo.com> | ||
208 | @@ -XXX,XX +XXX,XX @@ | ||
209 | #include "block/qdict.h" | ||
210 | #include "block/block-copy.h" | ||
211 | |||
212 | -#include "block/backup-top.h" | ||
213 | +#include "block/copy-before-write.h" | ||
214 | |||
215 | -typedef struct BDRVBackupTopState { | ||
216 | +typedef struct BDRVCopyBeforeWriteState { | ||
217 | BlockCopyState *bcs; | ||
218 | BdrvChild *target; | ||
219 | int64_t cluster_size; | ||
220 | -} BDRVBackupTopState; | ||
221 | +} BDRVCopyBeforeWriteState; | ||
222 | |||
223 | -static coroutine_fn int backup_top_co_preadv( | ||
224 | +static coroutine_fn int cbw_co_preadv( | ||
225 | BlockDriverState *bs, uint64_t offset, uint64_t bytes, | ||
226 | QEMUIOVector *qiov, int flags) | ||
227 | { | ||
228 | return bdrv_co_preadv(bs->backing, offset, bytes, qiov, flags); | ||
229 | } | ||
230 | |||
231 | -static coroutine_fn int backup_top_cbw(BlockDriverState *bs, uint64_t offset, | ||
232 | - uint64_t bytes, BdrvRequestFlags flags) | ||
233 | +static coroutine_fn int cbw_do_copy_before_write(BlockDriverState *bs, | ||
234 | + uint64_t offset, uint64_t bytes, BdrvRequestFlags flags) | ||
235 | { | ||
236 | - BDRVBackupTopState *s = bs->opaque; | ||
237 | + BDRVCopyBeforeWriteState *s = bs->opaque; | ||
238 | uint64_t off, end; | ||
239 | |||
240 | if (flags & BDRV_REQ_WRITE_UNCHANGED) { | ||
241 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int backup_top_cbw(BlockDriverState *bs, uint64_t offset, | ||
242 | return block_copy(s->bcs, off, end - off, true); | ||
243 | } | ||
244 | |||
245 | -static int coroutine_fn backup_top_co_pdiscard(BlockDriverState *bs, | ||
246 | - int64_t offset, int bytes) | ||
247 | +static int coroutine_fn cbw_co_pdiscard(BlockDriverState *bs, | ||
248 | + int64_t offset, int bytes) | ||
249 | { | ||
250 | - int ret = backup_top_cbw(bs, offset, bytes, 0); | ||
251 | + int ret = cbw_do_copy_before_write(bs, offset, bytes, 0); | ||
252 | if (ret < 0) { | ||
253 | return ret; | ||
254 | } | ||
255 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_top_co_pdiscard(BlockDriverState *bs, | ||
256 | return bdrv_co_pdiscard(bs->backing, offset, bytes); | ||
257 | } | ||
258 | |||
259 | -static int coroutine_fn backup_top_co_pwrite_zeroes(BlockDriverState *bs, | ||
260 | +static int coroutine_fn cbw_co_pwrite_zeroes(BlockDriverState *bs, | ||
261 | int64_t offset, int bytes, BdrvRequestFlags flags) | ||
262 | { | ||
263 | - int ret = backup_top_cbw(bs, offset, bytes, flags); | ||
264 | + int ret = cbw_do_copy_before_write(bs, offset, bytes, flags); | ||
265 | if (ret < 0) { | ||
266 | return ret; | ||
267 | } | ||
268 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_top_co_pwrite_zeroes(BlockDriverState *bs, | ||
269 | return bdrv_co_pwrite_zeroes(bs->backing, offset, bytes, flags); | ||
270 | } | ||
271 | |||
272 | -static coroutine_fn int backup_top_co_pwritev(BlockDriverState *bs, | ||
273 | - uint64_t offset, | ||
274 | - uint64_t bytes, | ||
275 | - QEMUIOVector *qiov, int flags) | ||
276 | +static coroutine_fn int cbw_co_pwritev(BlockDriverState *bs, | ||
277 | + uint64_t offset, | ||
278 | + uint64_t bytes, | ||
279 | + QEMUIOVector *qiov, int flags) | ||
280 | { | ||
281 | - int ret = backup_top_cbw(bs, offset, bytes, flags); | ||
282 | + int ret = cbw_do_copy_before_write(bs, offset, bytes, flags); | ||
283 | if (ret < 0) { | ||
284 | return ret; | ||
285 | } | ||
286 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int backup_top_co_pwritev(BlockDriverState *bs, | ||
287 | return bdrv_co_pwritev(bs->backing, offset, bytes, qiov, flags); | ||
288 | } | ||
289 | |||
290 | -static int coroutine_fn backup_top_co_flush(BlockDriverState *bs) | ||
291 | +static int coroutine_fn cbw_co_flush(BlockDriverState *bs) | ||
292 | { | ||
293 | if (!bs->backing) { | ||
294 | return 0; | ||
295 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_top_co_flush(BlockDriverState *bs) | ||
296 | return bdrv_co_flush(bs->backing->bs); | ||
297 | } | ||
298 | |||
299 | -static void backup_top_refresh_filename(BlockDriverState *bs) | ||
300 | +static void cbw_refresh_filename(BlockDriverState *bs) | ||
301 | { | ||
302 | if (bs->backing == NULL) { | ||
303 | /* | ||
304 | @@ -XXX,XX +XXX,XX @@ static void backup_top_refresh_filename(BlockDriverState *bs) | ||
305 | bs->backing->bs->filename); | ||
306 | } | ||
307 | |||
308 | -static void backup_top_child_perm(BlockDriverState *bs, BdrvChild *c, | ||
309 | - BdrvChildRole role, | ||
310 | - BlockReopenQueue *reopen_queue, | ||
311 | - uint64_t perm, uint64_t shared, | ||
312 | - uint64_t *nperm, uint64_t *nshared) | ||
313 | +static void cbw_child_perm(BlockDriverState *bs, BdrvChild *c, | ||
314 | + BdrvChildRole role, | ||
315 | + BlockReopenQueue *reopen_queue, | ||
316 | + uint64_t perm, uint64_t shared, | ||
317 | + uint64_t *nperm, uint64_t *nshared) | ||
318 | { | ||
319 | if (!(role & BDRV_CHILD_FILTERED)) { | ||
320 | /* | ||
321 | @@ -XXX,XX +XXX,XX @@ static void backup_top_child_perm(BlockDriverState *bs, BdrvChild *c, | ||
322 | } | ||
323 | } | ||
324 | |||
325 | -BlockDriver bdrv_backup_top_filter = { | ||
326 | - .format_name = "backup-top", | ||
327 | - .instance_size = sizeof(BDRVBackupTopState), | ||
328 | +BlockDriver bdrv_cbw_filter = { | ||
329 | + .format_name = "copy-before-write", | ||
330 | + .instance_size = sizeof(BDRVCopyBeforeWriteState), | ||
331 | |||
332 | - .bdrv_co_preadv = backup_top_co_preadv, | ||
333 | - .bdrv_co_pwritev = backup_top_co_pwritev, | ||
334 | - .bdrv_co_pwrite_zeroes = backup_top_co_pwrite_zeroes, | ||
335 | - .bdrv_co_pdiscard = backup_top_co_pdiscard, | ||
336 | - .bdrv_co_flush = backup_top_co_flush, | ||
337 | + .bdrv_co_preadv = cbw_co_preadv, | ||
338 | + .bdrv_co_pwritev = cbw_co_pwritev, | ||
339 | + .bdrv_co_pwrite_zeroes = cbw_co_pwrite_zeroes, | ||
340 | + .bdrv_co_pdiscard = cbw_co_pdiscard, | ||
341 | + .bdrv_co_flush = cbw_co_flush, | ||
342 | |||
343 | - .bdrv_refresh_filename = backup_top_refresh_filename, | ||
344 | + .bdrv_refresh_filename = cbw_refresh_filename, | ||
345 | |||
346 | - .bdrv_child_perm = backup_top_child_perm, | ||
347 | + .bdrv_child_perm = cbw_child_perm, | ||
348 | |||
349 | .is_filter = true, | ||
350 | }; | ||
351 | |||
352 | -BlockDriverState *bdrv_backup_top_append(BlockDriverState *source, | ||
353 | - BlockDriverState *target, | ||
354 | - const char *filter_node_name, | ||
355 | - uint64_t cluster_size, | ||
356 | - BackupPerf *perf, | ||
357 | - BdrvRequestFlags write_flags, | ||
358 | - BlockCopyState **bcs, | ||
359 | - Error **errp) | ||
360 | +BlockDriverState *bdrv_cbw_append(BlockDriverState *source, | ||
361 | + BlockDriverState *target, | ||
362 | + const char *filter_node_name, | ||
363 | + uint64_t cluster_size, | ||
364 | + BackupPerf *perf, | ||
365 | + BdrvRequestFlags write_flags, | ||
366 | + BlockCopyState **bcs, | ||
367 | + Error **errp) | ||
368 | { | ||
369 | ERRP_GUARD(); | ||
370 | int ret; | ||
371 | - BDRVBackupTopState *state; | ||
372 | + BDRVCopyBeforeWriteState *state; | ||
373 | BlockDriverState *top; | ||
374 | bool appended = false; | ||
375 | |||
376 | assert(source->total_sectors == target->total_sectors); | ||
377 | |||
378 | - top = bdrv_new_open_driver(&bdrv_backup_top_filter, filter_node_name, | ||
379 | + top = bdrv_new_open_driver(&bdrv_cbw_filter, filter_node_name, | ||
380 | BDRV_O_RDWR, errp); | ||
381 | if (!top) { | ||
382 | return NULL; | ||
383 | @@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_backup_top_append(BlockDriverState *source, | ||
384 | |||
385 | ret = bdrv_append(top, source, errp); | ||
386 | if (ret < 0) { | ||
387 | - error_prepend(errp, "Cannot append backup-top filter: "); | ||
388 | + error_prepend(errp, "Cannot append copy-before-write filter: "); | ||
389 | goto fail; | ||
390 | } | ||
391 | appended = true; | ||
392 | @@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_backup_top_append(BlockDriverState *source, | ||
393 | |||
394 | fail: | ||
395 | if (appended) { | ||
396 | - bdrv_backup_top_drop(top); | ||
397 | + bdrv_cbw_drop(top); | ||
398 | } else { | ||
399 | bdrv_unref(top); | ||
400 | } | ||
401 | @@ -XXX,XX +XXX,XX @@ fail: | ||
402 | return NULL; | ||
403 | } | ||
404 | |||
405 | -void bdrv_backup_top_drop(BlockDriverState *bs) | ||
406 | +void bdrv_cbw_drop(BlockDriverState *bs) | ||
407 | { | ||
408 | - BDRVBackupTopState *s = bs->opaque; | ||
409 | + BDRVCopyBeforeWriteState *s = bs->opaque; | ||
410 | |||
411 | bdrv_drop_filter(bs, &error_abort); | ||
412 | |||
413 | diff --git a/MAINTAINERS b/MAINTAINERS | ||
414 | index XXXXXXX..XXXXXXX 100644 | ||
415 | --- a/MAINTAINERS | ||
416 | +++ b/MAINTAINERS | ||
417 | @@ -XXX,XX +XXX,XX @@ F: block/mirror.c | ||
418 | F: qapi/job.json | ||
419 | F: block/block-copy.c | ||
420 | F: include/block/block-copy.c | ||
421 | -F: block/backup-top.h | ||
422 | -F: block/backup-top.c | ||
423 | +F: block/copy-before-write.h | ||
424 | +F: block/copy-before-write.c | ||
425 | F: include/block/aio_task.h | ||
426 | F: block/aio_task.c | ||
427 | F: util/qemu-co-shared-resource.c | ||
428 | diff --git a/block/meson.build b/block/meson.build | ||
429 | index XXXXXXX..XXXXXXX 100644 | ||
430 | --- a/block/meson.build | ||
431 | +++ b/block/meson.build | ||
432 | @@ -XXX,XX +XXX,XX @@ block_ss.add(files( | ||
433 | 'aio_task.c', | ||
434 | 'amend.c', | ||
435 | 'backup.c', | ||
436 | - 'backup-top.c', | ||
437 | + 'copy-before-write.c', | ||
438 | 'blkdebug.c', | ||
439 | 'blklogwrites.c', | ||
440 | 'blkverify.c', | ||
441 | diff --git a/tests/qemu-iotests/283 b/tests/qemu-iotests/283 | ||
442 | index XXXXXXX..XXXXXXX 100755 | ||
443 | --- a/tests/qemu-iotests/283 | ||
444 | +++ b/tests/qemu-iotests/283 | ||
445 | @@ -XXX,XX +XXX,XX @@ | ||
446 | #!/usr/bin/env python3 | ||
447 | # group: auto quick | ||
448 | # | ||
449 | -# Test for backup-top filter permission activation failure | ||
450 | +# Test for copy-before-write filter permission conflict | ||
451 | # | ||
452 | # Copyright (c) 2019 Virtuozzo International GmbH. | ||
453 | # | ||
454 | @@ -XXX,XX +XXX,XX @@ size = 1024 * 1024 | ||
455 | """ Test description | ||
456 | |||
457 | When performing a backup, all writes on the source subtree must go through the | ||
458 | -backup-top filter so it can copy all data to the target before it is changed. | ||
459 | -backup-top filter is appended above source node, to achieve this thing, so all | ||
460 | -parents of source node are handled. A configuration with side parents of source | ||
461 | -sub-tree with write permission is unsupported (we'd have append several | ||
462 | -backup-top filter like nodes to handle such parents). The test create an | ||
463 | -example of such configuration and checks that a backup is then not allowed | ||
464 | -(blockdev-backup command should fail). | ||
465 | +copy-before-write filter so it can copy all data to the target before it is | ||
466 | +changed. copy-before-write filter is appended above source node, to achieve | ||
467 | +this thing, so all parents of source node are handled. A configuration with | ||
468 | +side parents of source sub-tree with write permission is unsupported (we'd have | ||
469 | +append several copy-before-write filter like nodes to handle such parents). The | ||
470 | +test create an example of such configuration and checks that a backup is then | ||
471 | +not allowed (blockdev-backup command should fail). | ||
472 | |||
473 | The configuration: | ||
474 | |||
475 | @@ -XXX,XX +XXX,XX @@ The configuration: | ||
476 | │ base │ ◀──────────── │ other │ | ||
477 | └─────────────┘ └───────┘ | ||
478 | |||
479 | -On activation (see .active field of backup-top state in block/backup-top.c), | ||
480 | -backup-top is going to unshare write permission on its source child. Write | ||
481 | -unsharing will be propagated to the "source->base" link and will conflict with | ||
482 | -other node write permission. So permission update will fail and backup job will | ||
483 | -not be started. | ||
484 | +copy-before-write filter wants to unshare write permission on its source child. | ||
485 | +Write unsharing will be propagated to the "source->base" link and will conflict | ||
486 | +with other node write permission. So permission update will fail and backup job | ||
487 | +will not be started. | ||
488 | |||
489 | Note, that the only thing which prevents backup of running on such | ||
490 | configuration is default permission propagation scheme. It may be altered by | ||
491 | @@ -XXX,XX +XXX,XX @@ vm.qmp_log('blockdev-backup', sync='full', device='source', target='target') | ||
492 | vm.shutdown() | ||
493 | |||
494 | |||
495 | -print('\n=== backup-top should be gone after job-finalize ===\n') | ||
496 | +print('\n=== copy-before-write filter should be gone after job-finalize ===\n') | ||
497 | |||
498 | -# Check that the backup-top node is gone after job-finalize. | ||
499 | -# | ||
500 | -# During finalization, the node becomes inactive and can no longer | ||
501 | -# function. If it is still present, new parents might be attached, and | ||
502 | -# there would be no meaningful way to handle their I/O requests. | ||
503 | +# Check that the copy-before-write node is gone after job-finalize. | ||
504 | |||
505 | vm = iotests.VM() | ||
506 | vm.launch() | ||
507 | @@ -XXX,XX +XXX,XX @@ vm.qmp_log('blockdev-backup', | ||
508 | |||
509 | vm.event_wait('BLOCK_JOB_PENDING', 5.0) | ||
510 | |||
511 | -# The backup-top filter should still be present prior to finalization | ||
512 | +# The copy-before-write filter should still be present prior to finalization | ||
513 | assert vm.node_info('backup-filter') is not None | ||
514 | |||
515 | vm.qmp_log('job-finalize', id='backup') | ||
516 | diff --git a/tests/qemu-iotests/283.out b/tests/qemu-iotests/283.out | ||
517 | index XXXXXXX..XXXXXXX 100644 | ||
518 | --- a/tests/qemu-iotests/283.out | ||
519 | +++ b/tests/qemu-iotests/283.out | ||
520 | @@ -XXX,XX +XXX,XX @@ | ||
521 | {"execute": "blockdev-add", "arguments": {"driver": "blkdebug", "image": "base", "node-name": "other", "take-child-perms": ["write"]}} | ||
522 | {"return": {}} | ||
523 | {"execute": "blockdev-backup", "arguments": {"device": "source", "sync": "full", "target": "target"}} | ||
524 | -{"error": {"class": "GenericError", "desc": "Cannot append backup-top filter: Permission conflict on node 'base': permissions 'write' are both required by node 'other' (uses node 'base' as 'image' child) and unshared by node 'source' (uses node 'base' as 'image' child)."}} | ||
525 | +{"error": {"class": "GenericError", "desc": "Cannot append copy-before-write filter: Permission conflict on node 'base': permissions 'write' are both required by node 'other' (uses node 'base' as 'image' child) and unshared by node 'source' (uses node 'base' as 'image' child)."}} | ||
526 | |||
527 | -=== backup-top should be gone after job-finalize === | ||
528 | +=== copy-before-write filter should be gone after job-finalize === | ||
529 | |||
530 | {"execute": "blockdev-add", "arguments": {"driver": "null-co", "node-name": "source"}} | ||
531 | {"return": {}} | ||
532 | -- | ||
533 | 2.31.1 | ||
534 | |||
535 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
2 | 1 | ||
3 | We want to simplify initialization interface of copy-before-write | ||
4 | filter as we are going to make it public. So, let's detect fleecing | ||
5 | scheme exactly in block-copy code, to not pass this information through | ||
6 | extra levels. | ||
7 | |||
8 | Why not just set BDRV_REQ_SERIALISING unconditionally: because we are | ||
9 | going to implement new more efficient fleecing scheme which will not | ||
10 | rely on backing feature. | ||
11 | |||
12 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
13 | Reviewed-by: Hanna Reitz <hreitz@redhat.com> | ||
14 | Message-Id: <20210824083856.17408-7-vsementsov@virtuozzo.com> | ||
15 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
16 | --- | ||
17 | block/copy-before-write.h | 2 +- | ||
18 | include/block/block-copy.h | 3 +-- | ||
19 | block/backup.c | 21 +-------------------- | ||
20 | block/block-copy.c | 24 +++++++++++++++++++++--- | ||
21 | block/copy-before-write.c | 4 ++-- | ||
22 | 5 files changed, 26 insertions(+), 28 deletions(-) | ||
23 | |||
24 | diff --git a/block/copy-before-write.h b/block/copy-before-write.h | ||
25 | index XXXXXXX..XXXXXXX 100644 | ||
26 | --- a/block/copy-before-write.h | ||
27 | +++ b/block/copy-before-write.h | ||
28 | @@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_cbw_append(BlockDriverState *source, | ||
29 | const char *filter_node_name, | ||
30 | uint64_t cluster_size, | ||
31 | BackupPerf *perf, | ||
32 | - BdrvRequestFlags write_flags, | ||
33 | + bool compress, | ||
34 | BlockCopyState **bcs, | ||
35 | Error **errp); | ||
36 | void bdrv_cbw_drop(BlockDriverState *bs); | ||
37 | diff --git a/include/block/block-copy.h b/include/block/block-copy.h | ||
38 | index XXXXXXX..XXXXXXX 100644 | ||
39 | --- a/include/block/block-copy.h | ||
40 | +++ b/include/block/block-copy.h | ||
41 | @@ -XXX,XX +XXX,XX @@ typedef struct BlockCopyCallState BlockCopyCallState; | ||
42 | |||
43 | BlockCopyState *block_copy_state_new(BdrvChild *source, BdrvChild *target, | ||
44 | int64_t cluster_size, bool use_copy_range, | ||
45 | - BdrvRequestFlags write_flags, | ||
46 | - Error **errp); | ||
47 | + bool compress, Error **errp); | ||
48 | |||
49 | void block_copy_set_progress_meter(BlockCopyState *s, ProgressMeter *pm); | ||
50 | |||
51 | diff --git a/block/backup.c b/block/backup.c | ||
52 | index XXXXXXX..XXXXXXX 100644 | ||
53 | --- a/block/backup.c | ||
54 | +++ b/block/backup.c | ||
55 | @@ -XXX,XX +XXX,XX @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, | ||
56 | int64_t len, target_len; | ||
57 | BackupBlockJob *job = NULL; | ||
58 | int64_t cluster_size; | ||
59 | - BdrvRequestFlags write_flags; | ||
60 | BlockDriverState *cbw = NULL; | ||
61 | BlockCopyState *bcs = NULL; | ||
62 | |||
63 | @@ -XXX,XX +XXX,XX @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, | ||
64 | goto error; | ||
65 | } | ||
66 | |||
67 | - /* | ||
68 | - * If source is in backing chain of target assume that target is going to be | ||
69 | - * used for "image fleecing", i.e. it should represent a kind of snapshot of | ||
70 | - * source at backup-start point in time. And target is going to be read by | ||
71 | - * somebody (for example, used as NBD export) during backup job. | ||
72 | - * | ||
73 | - * In this case, we need to add BDRV_REQ_SERIALISING write flag to avoid | ||
74 | - * intersection of backup writes and third party reads from target, | ||
75 | - * otherwise reading from target we may occasionally read already updated by | ||
76 | - * guest data. | ||
77 | - * | ||
78 | - * For more information see commit f8d59dfb40bb and test | ||
79 | - * tests/qemu-iotests/222 | ||
80 | - */ | ||
81 | - write_flags = (bdrv_chain_contains(target, bs) ? BDRV_REQ_SERIALISING : 0) | | ||
82 | - (compress ? BDRV_REQ_WRITE_COMPRESSED : 0), | ||
83 | - | ||
84 | cbw = bdrv_cbw_append(bs, target, filter_node_name, | ||
85 | - cluster_size, perf, | ||
86 | - write_flags, &bcs, errp); | ||
87 | + cluster_size, perf, compress, &bcs, errp); | ||
88 | if (!cbw) { | ||
89 | goto error; | ||
90 | } | ||
91 | diff --git a/block/block-copy.c b/block/block-copy.c | ||
92 | index XXXXXXX..XXXXXXX 100644 | ||
93 | --- a/block/block-copy.c | ||
94 | +++ b/block/block-copy.c | ||
95 | @@ -XXX,XX +XXX,XX @@ static uint32_t block_copy_max_transfer(BdrvChild *source, BdrvChild *target) | ||
96 | |||
97 | BlockCopyState *block_copy_state_new(BdrvChild *source, BdrvChild *target, | ||
98 | int64_t cluster_size, bool use_copy_range, | ||
99 | - BdrvRequestFlags write_flags, Error **errp) | ||
100 | + bool compress, Error **errp) | ||
101 | { | ||
102 | BlockCopyState *s; | ||
103 | BdrvDirtyBitmap *copy_bitmap; | ||
104 | + bool is_fleecing; | ||
105 | |||
106 | copy_bitmap = bdrv_create_dirty_bitmap(source->bs, cluster_size, NULL, | ||
107 | errp); | ||
108 | @@ -XXX,XX +XXX,XX @@ BlockCopyState *block_copy_state_new(BdrvChild *source, BdrvChild *target, | ||
109 | } | ||
110 | bdrv_disable_dirty_bitmap(copy_bitmap); | ||
111 | |||
112 | + /* | ||
113 | + * If source is in backing chain of target assume that target is going to be | ||
114 | + * used for "image fleecing", i.e. it should represent a kind of snapshot of | ||
115 | + * source at backup-start point in time. And target is going to be read by | ||
116 | + * somebody (for example, used as NBD export) during backup job. | ||
117 | + * | ||
118 | + * In this case, we need to add BDRV_REQ_SERIALISING write flag to avoid | ||
119 | + * intersection of backup writes and third party reads from target, | ||
120 | + * otherwise reading from target we may occasionally read already updated by | ||
121 | + * guest data. | ||
122 | + * | ||
123 | + * For more information see commit f8d59dfb40bb and test | ||
124 | + * tests/qemu-iotests/222 | ||
125 | + */ | ||
126 | + is_fleecing = bdrv_chain_contains(target->bs, source->bs); | ||
127 | + | ||
128 | s = g_new(BlockCopyState, 1); | ||
129 | *s = (BlockCopyState) { | ||
130 | .source = source, | ||
131 | @@ -XXX,XX +XXX,XX @@ BlockCopyState *block_copy_state_new(BdrvChild *source, BdrvChild *target, | ||
132 | .copy_bitmap = copy_bitmap, | ||
133 | .cluster_size = cluster_size, | ||
134 | .len = bdrv_dirty_bitmap_size(copy_bitmap), | ||
135 | - .write_flags = write_flags, | ||
136 | + .write_flags = (is_fleecing ? BDRV_REQ_SERIALISING : 0) | | ||
137 | + (compress ? BDRV_REQ_WRITE_COMPRESSED : 0), | ||
138 | .mem = shres_create(BLOCK_COPY_MAX_MEM), | ||
139 | .max_transfer = QEMU_ALIGN_DOWN( | ||
140 | block_copy_max_transfer(source, target), | ||
141 | @@ -XXX,XX +XXX,XX @@ BlockCopyState *block_copy_state_new(BdrvChild *source, BdrvChild *target, | ||
142 | * behalf). | ||
143 | */ | ||
144 | s->method = COPY_READ_WRITE_CLUSTER; | ||
145 | - } else if (write_flags & BDRV_REQ_WRITE_COMPRESSED) { | ||
146 | + } else if (compress) { | ||
147 | /* Compression supports only cluster-size writes and no copy-range. */ | ||
148 | s->method = COPY_READ_WRITE_CLUSTER; | ||
149 | } else { | ||
150 | diff --git a/block/copy-before-write.c b/block/copy-before-write.c | ||
151 | index XXXXXXX..XXXXXXX 100644 | ||
152 | --- a/block/copy-before-write.c | ||
153 | +++ b/block/copy-before-write.c | ||
154 | @@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_cbw_append(BlockDriverState *source, | ||
155 | const char *filter_node_name, | ||
156 | uint64_t cluster_size, | ||
157 | BackupPerf *perf, | ||
158 | - BdrvRequestFlags write_flags, | ||
159 | + bool compress, | ||
160 | BlockCopyState **bcs, | ||
161 | Error **errp) | ||
162 | { | ||
163 | @@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_cbw_append(BlockDriverState *source, | ||
164 | state->cluster_size = cluster_size; | ||
165 | state->bcs = block_copy_state_new(top->backing, state->target, | ||
166 | cluster_size, perf->use_copy_range, | ||
167 | - write_flags, errp); | ||
168 | + compress, errp); | ||
169 | if (!state->bcs) { | ||
170 | error_prepend(errp, "Cannot create block-copy-state: "); | ||
171 | goto fail; | ||
172 | -- | ||
173 | 2.31.1 | ||
174 | |||
175 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
2 | 1 | ||
3 | We'll need a possibility to set compress and use_copy_range options | ||
4 | after initialization of the state. So make corresponding part of | ||
5 | block_copy_state_new() separate and public. | ||
6 | |||
7 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
8 | Message-Id: <20210824083856.17408-8-vsementsov@virtuozzo.com> | ||
9 | Reviewed-by: Hanna Reitz <hreitz@redhat.com> | ||
10 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
11 | --- | ||
12 | include/block/block-copy.h | 3 +++ | ||
13 | block/block-copy.c | 49 ++++++++++++++++++++++---------------- | ||
14 | 2 files changed, 32 insertions(+), 20 deletions(-) | ||
15 | |||
16 | diff --git a/include/block/block-copy.h b/include/block/block-copy.h | ||
17 | index XXXXXXX..XXXXXXX 100644 | ||
18 | --- a/include/block/block-copy.h | ||
19 | +++ b/include/block/block-copy.h | ||
20 | @@ -XXX,XX +XXX,XX @@ BlockCopyState *block_copy_state_new(BdrvChild *source, BdrvChild *target, | ||
21 | int64_t cluster_size, bool use_copy_range, | ||
22 | bool compress, Error **errp); | ||
23 | |||
24 | +/* Function should be called prior any actual copy request */ | ||
25 | +void block_copy_set_copy_opts(BlockCopyState *s, bool use_copy_range, | ||
26 | + bool compress); | ||
27 | void block_copy_set_progress_meter(BlockCopyState *s, ProgressMeter *pm); | ||
28 | |||
29 | void block_copy_state_free(BlockCopyState *s); | ||
30 | diff --git a/block/block-copy.c b/block/block-copy.c | ||
31 | index XXXXXXX..XXXXXXX 100644 | ||
32 | --- a/block/block-copy.c | ||
33 | +++ b/block/block-copy.c | ||
34 | @@ -XXX,XX +XXX,XX @@ static uint32_t block_copy_max_transfer(BdrvChild *source, BdrvChild *target) | ||
35 | target->bs->bl.max_transfer)); | ||
36 | } | ||
37 | |||
38 | +void block_copy_set_copy_opts(BlockCopyState *s, bool use_copy_range, | ||
39 | + bool compress) | ||
40 | +{ | ||
41 | + /* Keep BDRV_REQ_SERIALISING set (or not set) in block_copy_state_new() */ | ||
42 | + s->write_flags = (s->write_flags & BDRV_REQ_SERIALISING) | | ||
43 | + (compress ? BDRV_REQ_WRITE_COMPRESSED : 0); | ||
44 | + | ||
45 | + if (s->max_transfer < s->cluster_size) { | ||
46 | + /* | ||
47 | + * copy_range does not respect max_transfer. We don't want to bother | ||
48 | + * with requests smaller than block-copy cluster size, so fallback to | ||
49 | + * buffered copying (read and write respect max_transfer on their | ||
50 | + * behalf). | ||
51 | + */ | ||
52 | + s->method = COPY_READ_WRITE_CLUSTER; | ||
53 | + } else if (compress) { | ||
54 | + /* Compression supports only cluster-size writes and no copy-range. */ | ||
55 | + s->method = COPY_READ_WRITE_CLUSTER; | ||
56 | + } else { | ||
57 | + /* | ||
58 | + * If copy range enabled, start with COPY_RANGE_SMALL, until first | ||
59 | + * successful copy_range (look at block_copy_do_copy). | ||
60 | + */ | ||
61 | + s->method = use_copy_range ? COPY_RANGE_SMALL : COPY_READ_WRITE; | ||
62 | + } | ||
63 | +} | ||
64 | + | ||
65 | BlockCopyState *block_copy_state_new(BdrvChild *source, BdrvChild *target, | ||
66 | int64_t cluster_size, bool use_copy_range, | ||
67 | bool compress, Error **errp) | ||
68 | @@ -XXX,XX +XXX,XX @@ BlockCopyState *block_copy_state_new(BdrvChild *source, BdrvChild *target, | ||
69 | .copy_bitmap = copy_bitmap, | ||
70 | .cluster_size = cluster_size, | ||
71 | .len = bdrv_dirty_bitmap_size(copy_bitmap), | ||
72 | - .write_flags = (is_fleecing ? BDRV_REQ_SERIALISING : 0) | | ||
73 | - (compress ? BDRV_REQ_WRITE_COMPRESSED : 0), | ||
74 | + .write_flags = (is_fleecing ? BDRV_REQ_SERIALISING : 0), | ||
75 | .mem = shres_create(BLOCK_COPY_MAX_MEM), | ||
76 | .max_transfer = QEMU_ALIGN_DOWN( | ||
77 | block_copy_max_transfer(source, target), | ||
78 | cluster_size), | ||
79 | }; | ||
80 | |||
81 | - if (s->max_transfer < cluster_size) { | ||
82 | - /* | ||
83 | - * copy_range does not respect max_transfer. We don't want to bother | ||
84 | - * with requests smaller than block-copy cluster size, so fallback to | ||
85 | - * buffered copying (read and write respect max_transfer on their | ||
86 | - * behalf). | ||
87 | - */ | ||
88 | - s->method = COPY_READ_WRITE_CLUSTER; | ||
89 | - } else if (compress) { | ||
90 | - /* Compression supports only cluster-size writes and no copy-range. */ | ||
91 | - s->method = COPY_READ_WRITE_CLUSTER; | ||
92 | - } else { | ||
93 | - /* | ||
94 | - * If copy range enabled, start with COPY_RANGE_SMALL, until first | ||
95 | - * successful copy_range (look at block_copy_do_copy). | ||
96 | - */ | ||
97 | - s->method = use_copy_range ? COPY_RANGE_SMALL : COPY_READ_WRITE; | ||
98 | - } | ||
99 | + block_copy_set_copy_opts(s, use_copy_range, compress); | ||
100 | |||
101 | ratelimit_init(&s->rate_limit); | ||
102 | qemu_co_mutex_init(&s->lock); | ||
103 | -- | ||
104 | 2.31.1 | ||
105 | |||
106 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
2 | 1 | ||
3 | We are going to publish copy-before-write filter, so it would be | ||
4 | initialized through options. Still we don't want to publish compress | ||
5 | and copy-range options, as | ||
6 | |||
7 | 1. Modern way to enable compression is to use compress filter. | ||
8 | |||
9 | 2. For copy-range it's unclean how to make proper interface: | ||
10 | - it's has experimental prefix for backup job anyway | ||
11 | - the whole BackupPerf structure doesn't make sense for the filter | ||
12 | So, let's just add copy-range possibility to the filter later if | ||
13 | needed. | ||
14 | |||
15 | Still, we are going to continue support for compression and | ||
16 | experimental copy-range in backup job. So, set these options after | ||
17 | filter creation. | ||
18 | |||
19 | Note, that we can drop "compress" argument of bdrv_cbw_append() now, as | ||
20 | well as "perf". The only reason not doing so is that now, when I | ||
21 | prepare this patch the big series around it is already reviewed and I | ||
22 | want to avoid extra rebase conflicts to simplify review of the | ||
23 | following version. | ||
24 | |||
25 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
26 | Reviewed-by: Hanna Reitz <hreitz@redhat.com> | ||
27 | Message-Id: <20210824083856.17408-9-vsementsov@virtuozzo.com> | ||
28 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
29 | --- | ||
30 | block/copy-before-write.h | 1 - | ||
31 | block/backup.c | 3 ++- | ||
32 | block/copy-before-write.c | 4 +--- | ||
33 | 3 files changed, 3 insertions(+), 5 deletions(-) | ||
34 | |||
35 | diff --git a/block/copy-before-write.h b/block/copy-before-write.h | ||
36 | index XXXXXXX..XXXXXXX 100644 | ||
37 | --- a/block/copy-before-write.h | ||
38 | +++ b/block/copy-before-write.h | ||
39 | @@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_cbw_append(BlockDriverState *source, | ||
40 | BlockDriverState *target, | ||
41 | const char *filter_node_name, | ||
42 | uint64_t cluster_size, | ||
43 | - BackupPerf *perf, | ||
44 | bool compress, | ||
45 | BlockCopyState **bcs, | ||
46 | Error **errp); | ||
47 | diff --git a/block/backup.c b/block/backup.c | ||
48 | index XXXXXXX..XXXXXXX 100644 | ||
49 | --- a/block/backup.c | ||
50 | +++ b/block/backup.c | ||
51 | @@ -XXX,XX +XXX,XX @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, | ||
52 | } | ||
53 | |||
54 | cbw = bdrv_cbw_append(bs, target, filter_node_name, | ||
55 | - cluster_size, perf, compress, &bcs, errp); | ||
56 | + cluster_size, false, &bcs, errp); | ||
57 | if (!cbw) { | ||
58 | goto error; | ||
59 | } | ||
60 | @@ -XXX,XX +XXX,XX @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, | ||
61 | job->len = len; | ||
62 | job->perf = *perf; | ||
63 | |||
64 | + block_copy_set_copy_opts(bcs, perf->use_copy_range, compress); | ||
65 | block_copy_set_progress_meter(bcs, &job->common.job.progress); | ||
66 | block_copy_set_speed(bcs, speed); | ||
67 | |||
68 | diff --git a/block/copy-before-write.c b/block/copy-before-write.c | ||
69 | index XXXXXXX..XXXXXXX 100644 | ||
70 | --- a/block/copy-before-write.c | ||
71 | +++ b/block/copy-before-write.c | ||
72 | @@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_cbw_append(BlockDriverState *source, | ||
73 | BlockDriverState *target, | ||
74 | const char *filter_node_name, | ||
75 | uint64_t cluster_size, | ||
76 | - BackupPerf *perf, | ||
77 | bool compress, | ||
78 | BlockCopyState **bcs, | ||
79 | Error **errp) | ||
80 | @@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_cbw_append(BlockDriverState *source, | ||
81 | |||
82 | state->cluster_size = cluster_size; | ||
83 | state->bcs = block_copy_state_new(top->backing, state->target, | ||
84 | - cluster_size, perf->use_copy_range, | ||
85 | - compress, errp); | ||
86 | + cluster_size, false, compress, errp); | ||
87 | if (!state->bcs) { | ||
88 | error_prepend(errp, "Cannot create block-copy-state: "); | ||
89 | goto fail; | ||
90 | -- | ||
91 | 2.31.1 | ||
92 | |||
93 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
2 | 1 | ||
3 | We are going to publish copy-before-write filter. So, user should be | ||
4 | able to create it with blockdev-add first, specifying both filtered and | ||
5 | target children. And then do blockdev-reopen, to actually insert the | ||
6 | filter where needed. | ||
7 | |||
8 | Currently, filter unshares write permission unconditionally on source | ||
9 | node. It's good, but it will not allow to do blockdev-add. So, let's | ||
10 | relax restrictions when filter doesn't have any parent. | ||
11 | |||
12 | Test output is modified, as now permission conflict happens only when | ||
13 | job creates a blk parent for filter node. | ||
14 | |||
15 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
16 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
17 | Message-Id: <20210824083856.17408-11-vsementsov@virtuozzo.com> | ||
18 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
19 | --- | ||
20 | block/copy-before-write.c | 8 +++++--- | ||
21 | tests/qemu-iotests/283.out | 2 +- | ||
22 | 2 files changed, 6 insertions(+), 4 deletions(-) | ||
23 | |||
24 | diff --git a/block/copy-before-write.c b/block/copy-before-write.c | ||
25 | index XXXXXXX..XXXXXXX 100644 | ||
26 | --- a/block/copy-before-write.c | ||
27 | +++ b/block/copy-before-write.c | ||
28 | @@ -XXX,XX +XXX,XX @@ static void cbw_child_perm(BlockDriverState *bs, BdrvChild *c, | ||
29 | bdrv_default_perms(bs, c, role, reopen_queue, | ||
30 | perm, shared, nperm, nshared); | ||
31 | |||
32 | - if (perm & BLK_PERM_WRITE) { | ||
33 | - *nperm = *nperm | BLK_PERM_CONSISTENT_READ; | ||
34 | + if (!QLIST_EMPTY(&bs->parents)) { | ||
35 | + if (perm & BLK_PERM_WRITE) { | ||
36 | + *nperm = *nperm | BLK_PERM_CONSISTENT_READ; | ||
37 | + } | ||
38 | + *nshared &= ~(BLK_PERM_WRITE | BLK_PERM_RESIZE); | ||
39 | } | ||
40 | - *nshared &= ~(BLK_PERM_WRITE | BLK_PERM_RESIZE); | ||
41 | } | ||
42 | } | ||
43 | |||
44 | diff --git a/tests/qemu-iotests/283.out b/tests/qemu-iotests/283.out | ||
45 | index XXXXXXX..XXXXXXX 100644 | ||
46 | --- a/tests/qemu-iotests/283.out | ||
47 | +++ b/tests/qemu-iotests/283.out | ||
48 | @@ -XXX,XX +XXX,XX @@ | ||
49 | {"execute": "blockdev-add", "arguments": {"driver": "blkdebug", "image": "base", "node-name": "other", "take-child-perms": ["write"]}} | ||
50 | {"return": {}} | ||
51 | {"execute": "blockdev-backup", "arguments": {"device": "source", "sync": "full", "target": "target"}} | ||
52 | -{"error": {"class": "GenericError", "desc": "Cannot append copy-before-write filter: Permission conflict on node 'base': permissions 'write' are both required by node 'other' (uses node 'base' as 'image' child) and unshared by node 'source' (uses node 'base' as 'image' child)."}} | ||
53 | +{"error": {"class": "GenericError", "desc": "Permission conflict on node 'base': permissions 'write' are both required by node 'other' (uses node 'base' as 'image' child) and unshared by node 'source' (uses node 'base' as 'image' child)."}} | ||
54 | |||
55 | === copy-before-write filter should be gone after job-finalize === | ||
56 | |||
57 | -- | ||
58 | 2.31.1 | ||
59 | |||
60 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
2 | 1 | ||
3 | bdrv_attach_child() do bdrv_unref() on failure, so we shouldn't do it | ||
4 | by hand here. | ||
5 | |||
6 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
7 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
8 | Message-Id: <20210824083856.17408-12-vsementsov@virtuozzo.com> | ||
9 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
10 | --- | ||
11 | block/copy-before-write.c | 1 - | ||
12 | 1 file changed, 1 deletion(-) | ||
13 | |||
14 | diff --git a/block/copy-before-write.c b/block/copy-before-write.c | ||
15 | index XXXXXXX..XXXXXXX 100644 | ||
16 | --- a/block/copy-before-write.c | ||
17 | +++ b/block/copy-before-write.c | ||
18 | @@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_cbw_append(BlockDriverState *source, | ||
19 | state->target = bdrv_attach_child(top, target, "target", &child_of_bds, | ||
20 | BDRV_CHILD_DATA, errp); | ||
21 | if (!state->target) { | ||
22 | - bdrv_unref(target); | ||
23 | bdrv_unref(top); | ||
24 | return NULL; | ||
25 | } | ||
26 | -- | ||
27 | 2.31.1 | ||
28 | |||
29 | diff view generated by jsdifflib |
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 1 | From: Sam Li <faithilikerun@gmail.com> |
---|---|---|---|
2 | 2 | ||
3 | Finally, copy-before-write gets own .bdrv_open and .bdrv_close | 3 | This patch extends virtio-blk emulation to handle zoned device commands |
4 | handlers, block_init() call and becomes available through bdrv_open(). | 4 | by calling the new block layer APIs to perform zoned device I/O on |
5 | behalf of the guest. It supports Report Zone, four zone oparations (open, | ||
6 | close, finish, reset), and Append Zone. | ||
5 | 7 | ||
6 | To achieve this: | 8 | The VIRTIO_BLK_F_ZONED feature bit will only be set if the host does |
9 | support zoned block devices. Regular block devices(conventional zones) | ||
10 | will not be set. | ||
7 | 11 | ||
8 | - cbw_init gets unused flags argument and becomes cbw_open | 12 | The guest os can use blktests, fio to test those commands on zoned devices. |
9 | - block_copy_state_free() call moved to new cbw_close() | 13 | Furthermore, using zonefs to test zone append write is also supported. |
10 | - in bdrv_cbw_append: | ||
11 | - options are completed with driver and node-name, and we can simply | ||
12 | use bdrv_insert_node() to do both open and drained replacing | ||
13 | - in bdrv_cbw_drop: | ||
14 | - cbw_close() is now responsible for freeing s->bcs, so don't do it | ||
15 | here | ||
16 | 14 | ||
17 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 15 | Signed-off-by: Sam Li <faithilikerun@gmail.com> |
18 | Reviewed-by: Max Reitz <mreitz@redhat.com> | 16 | Message-id: 20230407082528.18841-3-faithilikerun@gmail.com |
19 | Message-Id: <20210824083856.17408-22-vsementsov@virtuozzo.com> | 17 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> |
20 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
21 | --- | 18 | --- |
22 | block/copy-before-write.c | 60 ++++++++++++++++++--------------------- | 19 | hw/block/virtio-blk-common.c | 2 + |
23 | 1 file changed, 28 insertions(+), 32 deletions(-) | 20 | hw/block/virtio-blk.c | 389 +++++++++++++++++++++++++++++++++++ |
21 | hw/virtio/virtio-qmp.c | 2 + | ||
22 | 3 files changed, 393 insertions(+) | ||
24 | 23 | ||
25 | diff --git a/block/copy-before-write.c b/block/copy-before-write.c | 24 | diff --git a/hw/block/virtio-blk-common.c b/hw/block/virtio-blk-common.c |
26 | index XXXXXXX..XXXXXXX 100644 | 25 | index XXXXXXX..XXXXXXX 100644 |
27 | --- a/block/copy-before-write.c | 26 | --- a/hw/block/virtio-blk-common.c |
28 | +++ b/block/copy-before-write.c | 27 | +++ b/hw/block/virtio-blk-common.c |
29 | @@ -XXX,XX +XXX,XX @@ static void cbw_child_perm(BlockDriverState *bs, BdrvChild *c, | 28 | @@ -XXX,XX +XXX,XX @@ static const VirtIOFeature feature_sizes[] = { |
29 | .end = endof(struct virtio_blk_config, discard_sector_alignment)}, | ||
30 | {.flags = 1ULL << VIRTIO_BLK_F_WRITE_ZEROES, | ||
31 | .end = endof(struct virtio_blk_config, write_zeroes_may_unmap)}, | ||
32 | + {.flags = 1ULL << VIRTIO_BLK_F_ZONED, | ||
33 | + .end = endof(struct virtio_blk_config, zoned)}, | ||
34 | {} | ||
35 | }; | ||
36 | |||
37 | diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c | ||
38 | index XXXXXXX..XXXXXXX 100644 | ||
39 | --- a/hw/block/virtio-blk.c | ||
40 | +++ b/hw/block/virtio-blk.c | ||
41 | @@ -XXX,XX +XXX,XX @@ | ||
42 | #include "qemu/module.h" | ||
43 | #include "qemu/error-report.h" | ||
44 | #include "qemu/main-loop.h" | ||
45 | +#include "block/block_int.h" | ||
46 | #include "trace.h" | ||
47 | #include "hw/block/block.h" | ||
48 | #include "hw/qdev-properties.h" | ||
49 | @@ -XXX,XX +XXX,XX @@ err: | ||
50 | return err_status; | ||
51 | } | ||
52 | |||
53 | +typedef struct ZoneCmdData { | ||
54 | + VirtIOBlockReq *req; | ||
55 | + struct iovec *in_iov; | ||
56 | + unsigned in_num; | ||
57 | + union { | ||
58 | + struct { | ||
59 | + unsigned int nr_zones; | ||
60 | + BlockZoneDescriptor *zones; | ||
61 | + } zone_report_data; | ||
62 | + struct { | ||
63 | + int64_t offset; | ||
64 | + } zone_append_data; | ||
65 | + }; | ||
66 | +} ZoneCmdData; | ||
67 | + | ||
68 | +/* | ||
69 | + * check zoned_request: error checking before issuing requests. If all checks | ||
70 | + * passed, return true. | ||
71 | + * append: true if only zone append requests issued. | ||
72 | + */ | ||
73 | +static bool check_zoned_request(VirtIOBlock *s, int64_t offset, int64_t len, | ||
74 | + bool append, uint8_t *status) { | ||
75 | + BlockDriverState *bs = blk_bs(s->blk); | ||
76 | + int index; | ||
77 | + | ||
78 | + if (!virtio_has_feature(s->host_features, VIRTIO_BLK_F_ZONED)) { | ||
79 | + *status = VIRTIO_BLK_S_UNSUPP; | ||
80 | + return false; | ||
81 | + } | ||
82 | + | ||
83 | + if (offset < 0 || len < 0 || len > (bs->total_sectors << BDRV_SECTOR_BITS) | ||
84 | + || offset > (bs->total_sectors << BDRV_SECTOR_BITS) - len) { | ||
85 | + *status = VIRTIO_BLK_S_ZONE_INVALID_CMD; | ||
86 | + return false; | ||
87 | + } | ||
88 | + | ||
89 | + if (append) { | ||
90 | + if (bs->bl.write_granularity) { | ||
91 | + if ((offset % bs->bl.write_granularity) != 0) { | ||
92 | + *status = VIRTIO_BLK_S_ZONE_UNALIGNED_WP; | ||
93 | + return false; | ||
94 | + } | ||
95 | + } | ||
96 | + | ||
97 | + index = offset / bs->bl.zone_size; | ||
98 | + if (BDRV_ZT_IS_CONV(bs->wps->wp[index])) { | ||
99 | + *status = VIRTIO_BLK_S_ZONE_INVALID_CMD; | ||
100 | + return false; | ||
101 | + } | ||
102 | + | ||
103 | + if (len / 512 > bs->bl.max_append_sectors) { | ||
104 | + if (bs->bl.max_append_sectors == 0) { | ||
105 | + *status = VIRTIO_BLK_S_UNSUPP; | ||
106 | + } else { | ||
107 | + *status = VIRTIO_BLK_S_ZONE_INVALID_CMD; | ||
108 | + } | ||
109 | + return false; | ||
110 | + } | ||
111 | + } | ||
112 | + return true; | ||
113 | +} | ||
114 | + | ||
115 | +static void virtio_blk_zone_report_complete(void *opaque, int ret) | ||
116 | +{ | ||
117 | + ZoneCmdData *data = opaque; | ||
118 | + VirtIOBlockReq *req = data->req; | ||
119 | + VirtIOBlock *s = req->dev; | ||
120 | + VirtIODevice *vdev = VIRTIO_DEVICE(req->dev); | ||
121 | + struct iovec *in_iov = data->in_iov; | ||
122 | + unsigned in_num = data->in_num; | ||
123 | + int64_t zrp_size, n, j = 0; | ||
124 | + int64_t nz = data->zone_report_data.nr_zones; | ||
125 | + int8_t err_status = VIRTIO_BLK_S_OK; | ||
126 | + | ||
127 | + if (ret) { | ||
128 | + err_status = VIRTIO_BLK_S_ZONE_INVALID_CMD; | ||
129 | + goto out; | ||
130 | + } | ||
131 | + | ||
132 | + struct virtio_blk_zone_report zrp_hdr = (struct virtio_blk_zone_report) { | ||
133 | + .nr_zones = cpu_to_le64(nz), | ||
134 | + }; | ||
135 | + zrp_size = sizeof(struct virtio_blk_zone_report) | ||
136 | + + sizeof(struct virtio_blk_zone_descriptor) * nz; | ||
137 | + n = iov_from_buf(in_iov, in_num, 0, &zrp_hdr, sizeof(zrp_hdr)); | ||
138 | + if (n != sizeof(zrp_hdr)) { | ||
139 | + virtio_error(vdev, "Driver provided input buffer that is too small!"); | ||
140 | + err_status = VIRTIO_BLK_S_ZONE_INVALID_CMD; | ||
141 | + goto out; | ||
142 | + } | ||
143 | + | ||
144 | + for (size_t i = sizeof(zrp_hdr); i < zrp_size; | ||
145 | + i += sizeof(struct virtio_blk_zone_descriptor), ++j) { | ||
146 | + struct virtio_blk_zone_descriptor desc = | ||
147 | + (struct virtio_blk_zone_descriptor) { | ||
148 | + .z_start = cpu_to_le64(data->zone_report_data.zones[j].start | ||
149 | + >> BDRV_SECTOR_BITS), | ||
150 | + .z_cap = cpu_to_le64(data->zone_report_data.zones[j].cap | ||
151 | + >> BDRV_SECTOR_BITS), | ||
152 | + .z_wp = cpu_to_le64(data->zone_report_data.zones[j].wp | ||
153 | + >> BDRV_SECTOR_BITS), | ||
154 | + }; | ||
155 | + | ||
156 | + switch (data->zone_report_data.zones[j].type) { | ||
157 | + case BLK_ZT_CONV: | ||
158 | + desc.z_type = VIRTIO_BLK_ZT_CONV; | ||
159 | + break; | ||
160 | + case BLK_ZT_SWR: | ||
161 | + desc.z_type = VIRTIO_BLK_ZT_SWR; | ||
162 | + break; | ||
163 | + case BLK_ZT_SWP: | ||
164 | + desc.z_type = VIRTIO_BLK_ZT_SWP; | ||
165 | + break; | ||
166 | + default: | ||
167 | + g_assert_not_reached(); | ||
168 | + } | ||
169 | + | ||
170 | + switch (data->zone_report_data.zones[j].state) { | ||
171 | + case BLK_ZS_RDONLY: | ||
172 | + desc.z_state = VIRTIO_BLK_ZS_RDONLY; | ||
173 | + break; | ||
174 | + case BLK_ZS_OFFLINE: | ||
175 | + desc.z_state = VIRTIO_BLK_ZS_OFFLINE; | ||
176 | + break; | ||
177 | + case BLK_ZS_EMPTY: | ||
178 | + desc.z_state = VIRTIO_BLK_ZS_EMPTY; | ||
179 | + break; | ||
180 | + case BLK_ZS_CLOSED: | ||
181 | + desc.z_state = VIRTIO_BLK_ZS_CLOSED; | ||
182 | + break; | ||
183 | + case BLK_ZS_FULL: | ||
184 | + desc.z_state = VIRTIO_BLK_ZS_FULL; | ||
185 | + break; | ||
186 | + case BLK_ZS_EOPEN: | ||
187 | + desc.z_state = VIRTIO_BLK_ZS_EOPEN; | ||
188 | + break; | ||
189 | + case BLK_ZS_IOPEN: | ||
190 | + desc.z_state = VIRTIO_BLK_ZS_IOPEN; | ||
191 | + break; | ||
192 | + case BLK_ZS_NOT_WP: | ||
193 | + desc.z_state = VIRTIO_BLK_ZS_NOT_WP; | ||
194 | + break; | ||
195 | + default: | ||
196 | + g_assert_not_reached(); | ||
197 | + } | ||
198 | + | ||
199 | + /* TODO: it takes O(n^2) time complexity. Optimizations required. */ | ||
200 | + n = iov_from_buf(in_iov, in_num, i, &desc, sizeof(desc)); | ||
201 | + if (n != sizeof(desc)) { | ||
202 | + virtio_error(vdev, "Driver provided input buffer " | ||
203 | + "for descriptors that is too small!"); | ||
204 | + err_status = VIRTIO_BLK_S_ZONE_INVALID_CMD; | ||
205 | + } | ||
206 | + } | ||
207 | + | ||
208 | +out: | ||
209 | + aio_context_acquire(blk_get_aio_context(s->conf.conf.blk)); | ||
210 | + virtio_blk_req_complete(req, err_status); | ||
211 | + virtio_blk_free_request(req); | ||
212 | + aio_context_release(blk_get_aio_context(s->conf.conf.blk)); | ||
213 | + g_free(data->zone_report_data.zones); | ||
214 | + g_free(data); | ||
215 | +} | ||
216 | + | ||
217 | +static void virtio_blk_handle_zone_report(VirtIOBlockReq *req, | ||
218 | + struct iovec *in_iov, | ||
219 | + unsigned in_num) | ||
220 | +{ | ||
221 | + VirtIOBlock *s = req->dev; | ||
222 | + VirtIODevice *vdev = VIRTIO_DEVICE(s); | ||
223 | + unsigned int nr_zones; | ||
224 | + ZoneCmdData *data; | ||
225 | + int64_t zone_size, offset; | ||
226 | + uint8_t err_status; | ||
227 | + | ||
228 | + if (req->in_len < sizeof(struct virtio_blk_inhdr) + | ||
229 | + sizeof(struct virtio_blk_zone_report) + | ||
230 | + sizeof(struct virtio_blk_zone_descriptor)) { | ||
231 | + virtio_error(vdev, "in buffer too small for zone report"); | ||
232 | + return; | ||
233 | + } | ||
234 | + | ||
235 | + /* start byte offset of the zone report */ | ||
236 | + offset = virtio_ldq_p(vdev, &req->out.sector) << BDRV_SECTOR_BITS; | ||
237 | + if (!check_zoned_request(s, offset, 0, false, &err_status)) { | ||
238 | + goto out; | ||
239 | + } | ||
240 | + nr_zones = (req->in_len - sizeof(struct virtio_blk_inhdr) - | ||
241 | + sizeof(struct virtio_blk_zone_report)) / | ||
242 | + sizeof(struct virtio_blk_zone_descriptor); | ||
243 | + | ||
244 | + zone_size = sizeof(BlockZoneDescriptor) * nr_zones; | ||
245 | + data = g_malloc(sizeof(ZoneCmdData)); | ||
246 | + data->req = req; | ||
247 | + data->in_iov = in_iov; | ||
248 | + data->in_num = in_num; | ||
249 | + data->zone_report_data.nr_zones = nr_zones; | ||
250 | + data->zone_report_data.zones = g_malloc(zone_size), | ||
251 | + | ||
252 | + blk_aio_zone_report(s->blk, offset, &data->zone_report_data.nr_zones, | ||
253 | + data->zone_report_data.zones, | ||
254 | + virtio_blk_zone_report_complete, data); | ||
255 | + return; | ||
256 | +out: | ||
257 | + virtio_blk_req_complete(req, err_status); | ||
258 | + virtio_blk_free_request(req); | ||
259 | +} | ||
260 | + | ||
261 | +static void virtio_blk_zone_mgmt_complete(void *opaque, int ret) | ||
262 | +{ | ||
263 | + VirtIOBlockReq *req = opaque; | ||
264 | + VirtIOBlock *s = req->dev; | ||
265 | + int8_t err_status = VIRTIO_BLK_S_OK; | ||
266 | + | ||
267 | + if (ret) { | ||
268 | + err_status = VIRTIO_BLK_S_ZONE_INVALID_CMD; | ||
269 | + } | ||
270 | + | ||
271 | + aio_context_acquire(blk_get_aio_context(s->conf.conf.blk)); | ||
272 | + virtio_blk_req_complete(req, err_status); | ||
273 | + virtio_blk_free_request(req); | ||
274 | + aio_context_release(blk_get_aio_context(s->conf.conf.blk)); | ||
275 | +} | ||
276 | + | ||
277 | +static int virtio_blk_handle_zone_mgmt(VirtIOBlockReq *req, BlockZoneOp op) | ||
278 | +{ | ||
279 | + VirtIOBlock *s = req->dev; | ||
280 | + VirtIODevice *vdev = VIRTIO_DEVICE(s); | ||
281 | + BlockDriverState *bs = blk_bs(s->blk); | ||
282 | + int64_t offset = virtio_ldq_p(vdev, &req->out.sector) << BDRV_SECTOR_BITS; | ||
283 | + uint64_t len; | ||
284 | + uint64_t capacity = bs->total_sectors << BDRV_SECTOR_BITS; | ||
285 | + uint8_t err_status = VIRTIO_BLK_S_OK; | ||
286 | + | ||
287 | + uint32_t type = virtio_ldl_p(vdev, &req->out.type); | ||
288 | + if (type == VIRTIO_BLK_T_ZONE_RESET_ALL) { | ||
289 | + /* Entire drive capacity */ | ||
290 | + offset = 0; | ||
291 | + len = capacity; | ||
292 | + } else { | ||
293 | + if (bs->bl.zone_size > capacity - offset) { | ||
294 | + /* The zoned device allows the last smaller zone. */ | ||
295 | + len = capacity - bs->bl.zone_size * (bs->bl.nr_zones - 1); | ||
296 | + } else { | ||
297 | + len = bs->bl.zone_size; | ||
298 | + } | ||
299 | + } | ||
300 | + | ||
301 | + if (!check_zoned_request(s, offset, len, false, &err_status)) { | ||
302 | + goto out; | ||
303 | + } | ||
304 | + | ||
305 | + blk_aio_zone_mgmt(s->blk, op, offset, len, | ||
306 | + virtio_blk_zone_mgmt_complete, req); | ||
307 | + | ||
308 | + return 0; | ||
309 | +out: | ||
310 | + virtio_blk_req_complete(req, err_status); | ||
311 | + virtio_blk_free_request(req); | ||
312 | + return err_status; | ||
313 | +} | ||
314 | + | ||
315 | +static void virtio_blk_zone_append_complete(void *opaque, int ret) | ||
316 | +{ | ||
317 | + ZoneCmdData *data = opaque; | ||
318 | + VirtIOBlockReq *req = data->req; | ||
319 | + VirtIOBlock *s = req->dev; | ||
320 | + VirtIODevice *vdev = VIRTIO_DEVICE(req->dev); | ||
321 | + int64_t append_sector, n; | ||
322 | + uint8_t err_status = VIRTIO_BLK_S_OK; | ||
323 | + | ||
324 | + if (ret) { | ||
325 | + err_status = VIRTIO_BLK_S_ZONE_INVALID_CMD; | ||
326 | + goto out; | ||
327 | + } | ||
328 | + | ||
329 | + virtio_stq_p(vdev, &append_sector, | ||
330 | + data->zone_append_data.offset >> BDRV_SECTOR_BITS); | ||
331 | + n = iov_from_buf(data->in_iov, data->in_num, 0, &append_sector, | ||
332 | + sizeof(append_sector)); | ||
333 | + if (n != sizeof(append_sector)) { | ||
334 | + virtio_error(vdev, "Driver provided input buffer less than size of " | ||
335 | + "append_sector"); | ||
336 | + err_status = VIRTIO_BLK_S_ZONE_INVALID_CMD; | ||
337 | + goto out; | ||
338 | + } | ||
339 | + | ||
340 | +out: | ||
341 | + aio_context_acquire(blk_get_aio_context(s->conf.conf.blk)); | ||
342 | + virtio_blk_req_complete(req, err_status); | ||
343 | + virtio_blk_free_request(req); | ||
344 | + aio_context_release(blk_get_aio_context(s->conf.conf.blk)); | ||
345 | + g_free(data); | ||
346 | +} | ||
347 | + | ||
348 | +static int virtio_blk_handle_zone_append(VirtIOBlockReq *req, | ||
349 | + struct iovec *out_iov, | ||
350 | + struct iovec *in_iov, | ||
351 | + uint64_t out_num, | ||
352 | + unsigned in_num) { | ||
353 | + VirtIOBlock *s = req->dev; | ||
354 | + VirtIODevice *vdev = VIRTIO_DEVICE(s); | ||
355 | + uint8_t err_status = VIRTIO_BLK_S_OK; | ||
356 | + | ||
357 | + int64_t offset = virtio_ldq_p(vdev, &req->out.sector) << BDRV_SECTOR_BITS; | ||
358 | + int64_t len = iov_size(out_iov, out_num); | ||
359 | + | ||
360 | + if (!check_zoned_request(s, offset, len, true, &err_status)) { | ||
361 | + goto out; | ||
362 | + } | ||
363 | + | ||
364 | + ZoneCmdData *data = g_malloc(sizeof(ZoneCmdData)); | ||
365 | + data->req = req; | ||
366 | + data->in_iov = in_iov; | ||
367 | + data->in_num = in_num; | ||
368 | + data->zone_append_data.offset = offset; | ||
369 | + qemu_iovec_init_external(&req->qiov, out_iov, out_num); | ||
370 | + blk_aio_zone_append(s->blk, &data->zone_append_data.offset, &req->qiov, 0, | ||
371 | + virtio_blk_zone_append_complete, data); | ||
372 | + return 0; | ||
373 | + | ||
374 | +out: | ||
375 | + aio_context_acquire(blk_get_aio_context(s->conf.conf.blk)); | ||
376 | + virtio_blk_req_complete(req, err_status); | ||
377 | + virtio_blk_free_request(req); | ||
378 | + aio_context_release(blk_get_aio_context(s->conf.conf.blk)); | ||
379 | + return err_status; | ||
380 | +} | ||
381 | + | ||
382 | static int virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb) | ||
383 | { | ||
384 | uint32_t type; | ||
385 | @@ -XXX,XX +XXX,XX @@ static int virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb) | ||
386 | case VIRTIO_BLK_T_FLUSH: | ||
387 | virtio_blk_handle_flush(req, mrb); | ||
388 | break; | ||
389 | + case VIRTIO_BLK_T_ZONE_REPORT: | ||
390 | + virtio_blk_handle_zone_report(req, in_iov, in_num); | ||
391 | + break; | ||
392 | + case VIRTIO_BLK_T_ZONE_OPEN: | ||
393 | + virtio_blk_handle_zone_mgmt(req, BLK_ZO_OPEN); | ||
394 | + break; | ||
395 | + case VIRTIO_BLK_T_ZONE_CLOSE: | ||
396 | + virtio_blk_handle_zone_mgmt(req, BLK_ZO_CLOSE); | ||
397 | + break; | ||
398 | + case VIRTIO_BLK_T_ZONE_FINISH: | ||
399 | + virtio_blk_handle_zone_mgmt(req, BLK_ZO_FINISH); | ||
400 | + break; | ||
401 | + case VIRTIO_BLK_T_ZONE_RESET: | ||
402 | + virtio_blk_handle_zone_mgmt(req, BLK_ZO_RESET); | ||
403 | + break; | ||
404 | + case VIRTIO_BLK_T_ZONE_RESET_ALL: | ||
405 | + virtio_blk_handle_zone_mgmt(req, BLK_ZO_RESET); | ||
406 | + break; | ||
407 | case VIRTIO_BLK_T_SCSI_CMD: | ||
408 | virtio_blk_handle_scsi(req); | ||
409 | break; | ||
410 | @@ -XXX,XX +XXX,XX @@ static int virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb) | ||
411 | virtio_blk_free_request(req); | ||
412 | break; | ||
30 | } | 413 | } |
414 | + case VIRTIO_BLK_T_ZONE_APPEND & ~VIRTIO_BLK_T_OUT: | ||
415 | + /* | ||
416 | + * Passing out_iov/out_num and in_iov/in_num is not safe | ||
417 | + * to access req->elem.out_sg directly because it may be | ||
418 | + * modified by virtio_blk_handle_request(). | ||
419 | + */ | ||
420 | + virtio_blk_handle_zone_append(req, out_iov, in_iov, out_num, in_num); | ||
421 | + break; | ||
422 | /* | ||
423 | * VIRTIO_BLK_T_DISCARD and VIRTIO_BLK_T_WRITE_ZEROES are defined with | ||
424 | * VIRTIO_BLK_T_OUT flag set. We masked this flag in the switch statement, | ||
425 | @@ -XXX,XX +XXX,XX @@ static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config) | ||
426 | { | ||
427 | VirtIOBlock *s = VIRTIO_BLK(vdev); | ||
428 | BlockConf *conf = &s->conf.conf; | ||
429 | + BlockDriverState *bs = blk_bs(s->blk); | ||
430 | struct virtio_blk_config blkcfg; | ||
431 | uint64_t capacity; | ||
432 | int64_t length; | ||
433 | @@ -XXX,XX +XXX,XX @@ static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config) | ||
434 | blkcfg.write_zeroes_may_unmap = 1; | ||
435 | virtio_stl_p(vdev, &blkcfg.max_write_zeroes_seg, 1); | ||
436 | } | ||
437 | + if (bs->bl.zoned != BLK_Z_NONE) { | ||
438 | + switch (bs->bl.zoned) { | ||
439 | + case BLK_Z_HM: | ||
440 | + blkcfg.zoned.model = VIRTIO_BLK_Z_HM; | ||
441 | + break; | ||
442 | + case BLK_Z_HA: | ||
443 | + blkcfg.zoned.model = VIRTIO_BLK_Z_HA; | ||
444 | + break; | ||
445 | + default: | ||
446 | + g_assert_not_reached(); | ||
447 | + } | ||
448 | + | ||
449 | + virtio_stl_p(vdev, &blkcfg.zoned.zone_sectors, | ||
450 | + bs->bl.zone_size / 512); | ||
451 | + virtio_stl_p(vdev, &blkcfg.zoned.max_active_zones, | ||
452 | + bs->bl.max_active_zones); | ||
453 | + virtio_stl_p(vdev, &blkcfg.zoned.max_open_zones, | ||
454 | + bs->bl.max_open_zones); | ||
455 | + virtio_stl_p(vdev, &blkcfg.zoned.write_granularity, blk_size); | ||
456 | + virtio_stl_p(vdev, &blkcfg.zoned.max_append_sectors, | ||
457 | + bs->bl.max_append_sectors); | ||
458 | + } else { | ||
459 | + blkcfg.zoned.model = VIRTIO_BLK_Z_NONE; | ||
460 | + } | ||
461 | memcpy(config, &blkcfg, s->config_size); | ||
31 | } | 462 | } |
32 | 463 | ||
33 | -static int cbw_init(BlockDriverState *bs, QDict *options, Error **errp) | 464 | @@ -XXX,XX +XXX,XX @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp) |
34 | +static int cbw_open(BlockDriverState *bs, QDict *options, int flags, | 465 | VirtIODevice *vdev = VIRTIO_DEVICE(dev); |
35 | + Error **errp) | 466 | VirtIOBlock *s = VIRTIO_BLK(dev); |
36 | { | 467 | VirtIOBlkConf *conf = &s->conf; |
37 | BDRVCopyBeforeWriteState *s = bs->opaque; | 468 | + BlockDriverState *bs = blk_bs(conf->conf.blk); |
38 | BdrvDirtyBitmap *copy_bitmap; | 469 | Error *err = NULL; |
39 | @@ -XXX,XX +XXX,XX @@ static int cbw_init(BlockDriverState *bs, QDict *options, Error **errp) | 470 | unsigned i; |
40 | return 0; | 471 | |
41 | } | 472 | @@ -XXX,XX +XXX,XX @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp) |
42 | 473 | return; | |
43 | +static void cbw_close(BlockDriverState *bs) | ||
44 | +{ | ||
45 | + BDRVCopyBeforeWriteState *s = bs->opaque; | ||
46 | + | ||
47 | + block_copy_state_free(s->bcs); | ||
48 | + s->bcs = NULL; | ||
49 | +} | ||
50 | + | ||
51 | BlockDriver bdrv_cbw_filter = { | ||
52 | .format_name = "copy-before-write", | ||
53 | .instance_size = sizeof(BDRVCopyBeforeWriteState), | ||
54 | |||
55 | + .bdrv_open = cbw_open, | ||
56 | + .bdrv_close = cbw_close, | ||
57 | + | ||
58 | .bdrv_co_preadv = cbw_co_preadv, | ||
59 | .bdrv_co_pwritev = cbw_co_pwritev, | ||
60 | .bdrv_co_pwrite_zeroes = cbw_co_pwrite_zeroes, | ||
61 | @@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_cbw_append(BlockDriverState *source, | ||
62 | Error **errp) | ||
63 | { | ||
64 | ERRP_GUARD(); | ||
65 | - int ret; | ||
66 | BDRVCopyBeforeWriteState *state; | ||
67 | BlockDriverState *top; | ||
68 | QDict *opts; | ||
69 | |||
70 | assert(source->total_sectors == target->total_sectors); | ||
71 | |||
72 | - top = bdrv_new_open_driver(&bdrv_cbw_filter, filter_node_name, | ||
73 | - BDRV_O_RDWR, errp); | ||
74 | - if (!top) { | ||
75 | - error_prepend(errp, "Cannot open driver: "); | ||
76 | - return NULL; | ||
77 | - } | ||
78 | - state = top->opaque; | ||
79 | - | ||
80 | opts = qdict_new(); | ||
81 | + qdict_put_str(opts, "driver", "copy-before-write"); | ||
82 | + if (filter_node_name) { | ||
83 | + qdict_put_str(opts, "node-name", filter_node_name); | ||
84 | + } | ||
85 | qdict_put_str(opts, "file", bdrv_get_node_name(source)); | ||
86 | qdict_put_str(opts, "target", bdrv_get_node_name(target)); | ||
87 | |||
88 | - ret = cbw_init(top, opts, errp); | ||
89 | - qobject_unref(opts); | ||
90 | - if (ret < 0) { | ||
91 | - goto fail; | ||
92 | - } | ||
93 | - | ||
94 | - bdrv_drained_begin(source); | ||
95 | - ret = bdrv_replace_node(source, top, errp); | ||
96 | - bdrv_drained_end(source); | ||
97 | - if (ret < 0) { | ||
98 | - error_prepend(errp, "Cannot append copy-before-write filter: "); | ||
99 | - goto fail; | ||
100 | + top = bdrv_insert_node(source, opts, BDRV_O_RDWR, errp); | ||
101 | + if (!top) { | ||
102 | + return NULL; | ||
103 | } | 474 | } |
104 | 475 | ||
105 | + state = top->opaque; | 476 | + if (bs->bl.zoned != BLK_Z_NONE) { |
106 | *bcs = state->bcs; | 477 | + virtio_add_feature(&s->host_features, VIRTIO_BLK_F_ZONED); |
107 | 478 | + if (bs->bl.zoned == BLK_Z_HM) { | |
108 | return top; | 479 | + virtio_clear_feature(&s->host_features, VIRTIO_BLK_F_DISCARD); |
109 | - | 480 | + } |
110 | -fail: | 481 | + } |
111 | - block_copy_state_free(state->bcs); | 482 | + |
112 | - bdrv_unref(top); | 483 | if (virtio_has_feature(s->host_features, VIRTIO_BLK_F_DISCARD) && |
113 | - return NULL; | 484 | (!conf->max_discard_sectors || |
114 | } | 485 | conf->max_discard_sectors > BDRV_REQUEST_MAX_SECTORS)) { |
115 | 486 | diff --git a/hw/virtio/virtio-qmp.c b/hw/virtio/virtio-qmp.c | |
116 | void bdrv_cbw_drop(BlockDriverState *bs) | 487 | index XXXXXXX..XXXXXXX 100644 |
117 | { | 488 | --- a/hw/virtio/virtio-qmp.c |
118 | - BDRVCopyBeforeWriteState *s = bs->opaque; | 489 | +++ b/hw/virtio/virtio-qmp.c |
119 | - | 490 | @@ -XXX,XX +XXX,XX @@ static const qmp_virtio_feature_map_t virtio_blk_feature_map[] = { |
120 | bdrv_drop_filter(bs, &error_abort); | 491 | "VIRTIO_BLK_F_DISCARD: Discard command supported"), |
121 | - | 492 | FEATURE_ENTRY(VIRTIO_BLK_F_WRITE_ZEROES, \ |
122 | - block_copy_state_free(s->bcs); | 493 | "VIRTIO_BLK_F_WRITE_ZEROES: Write zeroes command supported"), |
123 | - | 494 | + FEATURE_ENTRY(VIRTIO_BLK_F_ZONED, \ |
124 | bdrv_unref(bs); | 495 | + "VIRTIO_BLK_F_ZONED: Zoned block devices"), |
125 | } | 496 | #ifndef VIRTIO_BLK_NO_LEGACY |
126 | + | 497 | FEATURE_ENTRY(VIRTIO_BLK_F_BARRIER, \ |
127 | +static void cbw_init(void) | 498 | "VIRTIO_BLK_F_BARRIER: Request barriers supported"), |
128 | +{ | ||
129 | + bdrv_register(&bdrv_cbw_filter); | ||
130 | +} | ||
131 | + | ||
132 | +block_init(cbw_init); | ||
133 | -- | 499 | -- |
134 | 2.31.1 | 500 | 2.39.2 |
135 | |||
136 | diff view generated by jsdifflib |
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 1 | From: Sam Li <faithilikerun@gmail.com> |
---|---|---|---|
2 | 2 | ||
3 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 3 | Taking account of the new zone append write operation for zoned devices, |
4 | Reviewed-by: Max Reitz <mreitz@redhat.com> | 4 | BLOCK_ACCT_ZONE_APPEND enum is introduced as other I/O request type (read, |
5 | Acked-by: Markus Armbruster <armbru@redhat.com> | 5 | write, flush). |
6 | Message-Id: <20210824083856.17408-23-vsementsov@virtuozzo.com> | 6 | |
7 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | 7 | Signed-off-by: Sam Li <faithilikerun@gmail.com> |
8 | Message-id: 20230407082528.18841-4-faithilikerun@gmail.com | ||
9 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
8 | --- | 10 | --- |
9 | qapi/block-core.json | 25 +++++++++++++++++++++++-- | 11 | qapi/block-core.json | 68 ++++++++++++++++++++++++++++++++------ |
10 | 1 file changed, 23 insertions(+), 2 deletions(-) | 12 | qapi/block.json | 4 +++ |
13 | include/block/accounting.h | 1 + | ||
14 | block/qapi-sysemu.c | 11 ++++++ | ||
15 | block/qapi.c | 18 ++++++++++ | ||
16 | hw/block/virtio-blk.c | 4 +++ | ||
17 | 6 files changed, 95 insertions(+), 11 deletions(-) | ||
11 | 18 | ||
12 | diff --git a/qapi/block-core.json b/qapi/block-core.json | 19 | diff --git a/qapi/block-core.json b/qapi/block-core.json |
13 | index XXXXXXX..XXXXXXX 100644 | 20 | index XXXXXXX..XXXXXXX 100644 |
14 | --- a/qapi/block-core.json | 21 | --- a/qapi/block-core.json |
15 | +++ b/qapi/block-core.json | 22 | +++ b/qapi/block-core.json |
16 | @@ -XXX,XX +XXX,XX @@ | 23 | @@ -XXX,XX +XXX,XX @@ |
17 | # @blklogwrites: Since 3.0 | 24 | # @min_wr_latency_ns: Minimum latency of write operations in the |
18 | # @blkreplay: Since 4.2 | 25 | # defined interval, in nanoseconds. |
19 | # @compress: Since 5.0 | 26 | # |
20 | +# @copy-before-write: Since 6.2 | 27 | +# @min_zone_append_latency_ns: Minimum latency of zone append operations |
21 | # | 28 | +# in the defined interval, in nanoseconds |
22 | # Since: 2.9 | 29 | +# (since 8.1) |
30 | +# | ||
31 | # @min_flush_latency_ns: Minimum latency of flush operations in the | ||
32 | # defined interval, in nanoseconds. | ||
33 | # | ||
34 | @@ -XXX,XX +XXX,XX @@ | ||
35 | # @max_wr_latency_ns: Maximum latency of write operations in the | ||
36 | # defined interval, in nanoseconds. | ||
37 | # | ||
38 | +# @max_zone_append_latency_ns: Maximum latency of zone append operations | ||
39 | +# in the defined interval, in nanoseconds | ||
40 | +# (since 8.1) | ||
41 | +# | ||
42 | # @max_flush_latency_ns: Maximum latency of flush operations in the | ||
43 | # defined interval, in nanoseconds. | ||
44 | # | ||
45 | @@ -XXX,XX +XXX,XX @@ | ||
46 | # @avg_wr_latency_ns: Average latency of write operations in the | ||
47 | # defined interval, in nanoseconds. | ||
48 | # | ||
49 | +# @avg_zone_append_latency_ns: Average latency of zone append operations | ||
50 | +# in the defined interval, in nanoseconds | ||
51 | +# (since 8.1) | ||
52 | +# | ||
53 | # @avg_flush_latency_ns: Average latency of flush operations in the | ||
54 | # defined interval, in nanoseconds. | ||
55 | # | ||
56 | @@ -XXX,XX +XXX,XX @@ | ||
57 | # @avg_wr_queue_depth: Average number of pending write operations | ||
58 | # in the defined interval. | ||
59 | # | ||
60 | +# @avg_zone_append_queue_depth: Average number of pending zone append | ||
61 | +# operations in the defined interval | ||
62 | +# (since 8.1). | ||
63 | +# | ||
64 | # Since: 2.5 | ||
23 | ## | 65 | ## |
24 | { 'enum': 'BlockdevDriver', | 66 | { 'struct': 'BlockDeviceTimedStats', |
25 | 'data': [ 'blkdebug', 'blklogwrites', 'blkreplay', 'blkverify', 'bochs', | 67 | 'data': { 'interval_length': 'int', 'min_rd_latency_ns': 'int', |
26 | - 'cloop', 'compress', 'copy-on-read', 'dmg', 'file', 'ftp', 'ftps', | 68 | 'max_rd_latency_ns': 'int', 'avg_rd_latency_ns': 'int', |
27 | - 'gluster', | 69 | 'min_wr_latency_ns': 'int', 'max_wr_latency_ns': 'int', |
28 | + 'cloop', 'compress', 'copy-before-write', 'copy-on-read', 'dmg', | 70 | - 'avg_wr_latency_ns': 'int', 'min_flush_latency_ns': 'int', |
29 | + 'file', 'ftp', 'ftps', 'gluster', | 71 | - 'max_flush_latency_ns': 'int', 'avg_flush_latency_ns': 'int', |
30 | {'name': 'host_cdrom', 'if': 'HAVE_HOST_BLOCK_DEVICE' }, | 72 | - 'avg_rd_queue_depth': 'number', 'avg_wr_queue_depth': 'number' } } |
31 | {'name': 'host_device', 'if': 'HAVE_HOST_BLOCK_DEVICE' }, | 73 | + 'avg_wr_latency_ns': 'int', 'min_zone_append_latency_ns': 'int', |
32 | 'http', 'https', 'iscsi', | 74 | + 'max_zone_append_latency_ns': 'int', |
33 | @@ -XXX,XX +XXX,XX @@ | 75 | + 'avg_zone_append_latency_ns': 'int', |
34 | 'base': 'BlockdevOptionsGenericFormat', | 76 | + 'min_flush_latency_ns': 'int', 'max_flush_latency_ns': 'int', |
35 | 'data': { '*bottom': 'str' } } | 77 | + 'avg_flush_latency_ns': 'int', 'avg_rd_queue_depth': 'number', |
36 | 78 | + 'avg_wr_queue_depth': 'number', | |
37 | +## | 79 | + 'avg_zone_append_queue_depth': 'number' } } |
38 | +# @BlockdevOptionsCbw: | 80 | |
39 | +# | 81 | ## |
40 | +# Driver specific block device options for the copy-before-write driver, | 82 | # @BlockDeviceStats: |
41 | +# which does so called copy-before-write operations: when data is | 83 | @@ -XXX,XX +XXX,XX @@ |
42 | +# written to the filter, the filter first reads corresponding blocks | 84 | # |
43 | +# from its file child and copies them to @target child. After successfully | 85 | # @wr_bytes: The number of bytes written by the device. |
44 | +# copying, the write request is propagated to file child. If copying | 86 | # |
45 | +# fails, the original write request is failed too and no data is written | 87 | +# @zone_append_bytes: The number of bytes appended by the zoned devices |
46 | +# to file child. | 88 | +# (since 8.1) |
47 | +# | 89 | +# |
48 | +# @target: The target for copy-before-write operations. | 90 | # @unmap_bytes: The number of bytes unmapped by the device (Since 4.2) |
49 | +# | 91 | # |
50 | +# Since: 6.2 | 92 | # @rd_operations: The number of read operations performed by the device. |
51 | +## | 93 | # |
52 | +{ 'struct': 'BlockdevOptionsCbw', | 94 | # @wr_operations: The number of write operations performed by the device. |
53 | + 'base': 'BlockdevOptionsGenericFormat', | 95 | # |
54 | + 'data': { 'target': 'BlockdevRef' } } | 96 | +# @zone_append_operations: The number of zone append operations performed |
97 | +# by the zoned devices (since 8.1) | ||
98 | +# | ||
99 | # @flush_operations: The number of cache flush operations performed by the | ||
100 | # device (since 0.15) | ||
101 | # | ||
102 | @@ -XXX,XX +XXX,XX @@ | ||
103 | # | ||
104 | # @wr_total_time_ns: Total time spent on writes in nanoseconds (since 0.15). | ||
105 | # | ||
106 | +# @zone_append_total_time_ns: Total time spent on zone append writes | ||
107 | +# in nanoseconds (since 8.1) | ||
108 | +# | ||
109 | # @flush_total_time_ns: Total time spent on cache flushes in nanoseconds | ||
110 | # (since 0.15). | ||
111 | # | ||
112 | @@ -XXX,XX +XXX,XX @@ | ||
113 | # @wr_merged: Number of write requests that have been merged into another | ||
114 | # request (Since 2.3). | ||
115 | # | ||
116 | +# @zone_append_merged: Number of zone append requests that have been merged | ||
117 | +# into another request (since 8.1) | ||
118 | +# | ||
119 | # @unmap_merged: Number of unmap requests that have been merged into another | ||
120 | # request (Since 4.2) | ||
121 | # | ||
122 | @@ -XXX,XX +XXX,XX @@ | ||
123 | # @failed_wr_operations: The number of failed write operations | ||
124 | # performed by the device (Since 2.5) | ||
125 | # | ||
126 | +# @failed_zone_append_operations: The number of failed zone append write | ||
127 | +# operations performed by the zoned devices | ||
128 | +# (since 8.1) | ||
129 | +# | ||
130 | # @failed_flush_operations: The number of failed flush operations | ||
131 | # performed by the device (Since 2.5) | ||
132 | # | ||
133 | @@ -XXX,XX +XXX,XX @@ | ||
134 | # @invalid_wr_operations: The number of invalid write operations | ||
135 | # performed by the device (Since 2.5) | ||
136 | # | ||
137 | +# @invalid_zone_append_operations: The number of invalid zone append operations | ||
138 | +# performed by the zoned device (since 8.1) | ||
139 | +# | ||
140 | # @invalid_flush_operations: The number of invalid flush operations | ||
141 | # performed by the device (Since 2.5) | ||
142 | # | ||
143 | @@ -XXX,XX +XXX,XX @@ | ||
144 | # | ||
145 | # @wr_latency_histogram: @BlockLatencyHistogramInfo. (Since 4.0) | ||
146 | # | ||
147 | +# @zone_append_latency_histogram: @BlockLatencyHistogramInfo. (since 8.1) | ||
148 | +# | ||
149 | # @flush_latency_histogram: @BlockLatencyHistogramInfo. (Since 4.0) | ||
150 | # | ||
151 | # Since: 0.14 | ||
152 | ## | ||
153 | { 'struct': 'BlockDeviceStats', | ||
154 | - 'data': {'rd_bytes': 'int', 'wr_bytes': 'int', 'unmap_bytes' : 'int', | ||
155 | - 'rd_operations': 'int', 'wr_operations': 'int', | ||
156 | + 'data': {'rd_bytes': 'int', 'wr_bytes': 'int', 'zone_append_bytes': 'int', | ||
157 | + 'unmap_bytes' : 'int', 'rd_operations': 'int', | ||
158 | + 'wr_operations': 'int', 'zone_append_operations': 'int', | ||
159 | 'flush_operations': 'int', 'unmap_operations': 'int', | ||
160 | 'rd_total_time_ns': 'int', 'wr_total_time_ns': 'int', | ||
161 | - 'flush_total_time_ns': 'int', 'unmap_total_time_ns': 'int', | ||
162 | - 'wr_highest_offset': 'int', | ||
163 | - 'rd_merged': 'int', 'wr_merged': 'int', 'unmap_merged': 'int', | ||
164 | - '*idle_time_ns': 'int', | ||
165 | + 'zone_append_total_time_ns': 'int', 'flush_total_time_ns': 'int', | ||
166 | + 'unmap_total_time_ns': 'int', 'wr_highest_offset': 'int', | ||
167 | + 'rd_merged': 'int', 'wr_merged': 'int', 'zone_append_merged': 'int', | ||
168 | + 'unmap_merged': 'int', '*idle_time_ns': 'int', | ||
169 | 'failed_rd_operations': 'int', 'failed_wr_operations': 'int', | ||
170 | - 'failed_flush_operations': 'int', 'failed_unmap_operations': 'int', | ||
171 | - 'invalid_rd_operations': 'int', 'invalid_wr_operations': 'int', | ||
172 | + 'failed_zone_append_operations': 'int', | ||
173 | + 'failed_flush_operations': 'int', | ||
174 | + 'failed_unmap_operations': 'int', 'invalid_rd_operations': 'int', | ||
175 | + 'invalid_wr_operations': 'int', | ||
176 | + 'invalid_zone_append_operations': 'int', | ||
177 | 'invalid_flush_operations': 'int', 'invalid_unmap_operations': 'int', | ||
178 | 'account_invalid': 'bool', 'account_failed': 'bool', | ||
179 | 'timed_stats': ['BlockDeviceTimedStats'], | ||
180 | '*rd_latency_histogram': 'BlockLatencyHistogramInfo', | ||
181 | '*wr_latency_histogram': 'BlockLatencyHistogramInfo', | ||
182 | + '*zone_append_latency_histogram': 'BlockLatencyHistogramInfo', | ||
183 | '*flush_latency_histogram': 'BlockLatencyHistogramInfo' } } | ||
184 | |||
185 | ## | ||
186 | diff --git a/qapi/block.json b/qapi/block.json | ||
187 | index XXXXXXX..XXXXXXX 100644 | ||
188 | --- a/qapi/block.json | ||
189 | +++ b/qapi/block.json | ||
190 | @@ -XXX,XX +XXX,XX @@ | ||
191 | # @boundaries-write: list of interval boundary values for write latency | ||
192 | # histogram. | ||
193 | # | ||
194 | +# @boundaries-zap: list of interval boundary values for zone append write | ||
195 | +# latency histogram. | ||
196 | +# | ||
197 | # @boundaries-flush: list of interval boundary values for flush latency | ||
198 | # histogram. | ||
199 | # | ||
200 | @@ -XXX,XX +XXX,XX @@ | ||
201 | '*boundaries': ['uint64'], | ||
202 | '*boundaries-read': ['uint64'], | ||
203 | '*boundaries-write': ['uint64'], | ||
204 | + '*boundaries-zap': ['uint64'], | ||
205 | '*boundaries-flush': ['uint64'] }, | ||
206 | 'allow-preconfig': true } | ||
207 | diff --git a/include/block/accounting.h b/include/block/accounting.h | ||
208 | index XXXXXXX..XXXXXXX 100644 | ||
209 | --- a/include/block/accounting.h | ||
210 | +++ b/include/block/accounting.h | ||
211 | @@ -XXX,XX +XXX,XX @@ enum BlockAcctType { | ||
212 | BLOCK_ACCT_READ, | ||
213 | BLOCK_ACCT_WRITE, | ||
214 | BLOCK_ACCT_FLUSH, | ||
215 | + BLOCK_ACCT_ZONE_APPEND, | ||
216 | BLOCK_ACCT_UNMAP, | ||
217 | BLOCK_MAX_IOTYPE, | ||
218 | }; | ||
219 | diff --git a/block/qapi-sysemu.c b/block/qapi-sysemu.c | ||
220 | index XXXXXXX..XXXXXXX 100644 | ||
221 | --- a/block/qapi-sysemu.c | ||
222 | +++ b/block/qapi-sysemu.c | ||
223 | @@ -XXX,XX +XXX,XX @@ void qmp_block_latency_histogram_set( | ||
224 | bool has_boundaries, uint64List *boundaries, | ||
225 | bool has_boundaries_read, uint64List *boundaries_read, | ||
226 | bool has_boundaries_write, uint64List *boundaries_write, | ||
227 | + bool has_boundaries_append, uint64List *boundaries_append, | ||
228 | bool has_boundaries_flush, uint64List *boundaries_flush, | ||
229 | Error **errp) | ||
230 | { | ||
231 | @@ -XXX,XX +XXX,XX @@ void qmp_block_latency_histogram_set( | ||
232 | } | ||
233 | } | ||
234 | |||
235 | + if (has_boundaries || has_boundaries_append) { | ||
236 | + ret = block_latency_histogram_set( | ||
237 | + stats, BLOCK_ACCT_ZONE_APPEND, | ||
238 | + has_boundaries_append ? boundaries_append : boundaries); | ||
239 | + if (ret) { | ||
240 | + error_setg(errp, "Device '%s' set append write boundaries fail", id); | ||
241 | + return; | ||
242 | + } | ||
243 | + } | ||
55 | + | 244 | + |
56 | ## | 245 | if (has_boundaries || has_boundaries_flush) { |
57 | # @BlockdevOptions: | 246 | ret = block_latency_histogram_set( |
58 | # | 247 | stats, BLOCK_ACCT_FLUSH, |
59 | @@ -XXX,XX +XXX,XX @@ | 248 | diff --git a/block/qapi.c b/block/qapi.c |
60 | 'bochs': 'BlockdevOptionsGenericFormat', | 249 | index XXXXXXX..XXXXXXX 100644 |
61 | 'cloop': 'BlockdevOptionsGenericFormat', | 250 | --- a/block/qapi.c |
62 | 'compress': 'BlockdevOptionsGenericFormat', | 251 | +++ b/block/qapi.c |
63 | + 'copy-before-write':'BlockdevOptionsCbw', | 252 | @@ -XXX,XX +XXX,XX @@ static void bdrv_query_blk_stats(BlockDeviceStats *ds, BlockBackend *blk) |
64 | 'copy-on-read':'BlockdevOptionsCor', | 253 | |
65 | 'dmg': 'BlockdevOptionsGenericFormat', | 254 | ds->rd_bytes = stats->nr_bytes[BLOCK_ACCT_READ]; |
66 | 'file': 'BlockdevOptionsFile', | 255 | ds->wr_bytes = stats->nr_bytes[BLOCK_ACCT_WRITE]; |
256 | + ds->zone_append_bytes = stats->nr_bytes[BLOCK_ACCT_ZONE_APPEND]; | ||
257 | ds->unmap_bytes = stats->nr_bytes[BLOCK_ACCT_UNMAP]; | ||
258 | ds->rd_operations = stats->nr_ops[BLOCK_ACCT_READ]; | ||
259 | ds->wr_operations = stats->nr_ops[BLOCK_ACCT_WRITE]; | ||
260 | + ds->zone_append_operations = stats->nr_ops[BLOCK_ACCT_ZONE_APPEND]; | ||
261 | ds->unmap_operations = stats->nr_ops[BLOCK_ACCT_UNMAP]; | ||
262 | |||
263 | ds->failed_rd_operations = stats->failed_ops[BLOCK_ACCT_READ]; | ||
264 | ds->failed_wr_operations = stats->failed_ops[BLOCK_ACCT_WRITE]; | ||
265 | + ds->failed_zone_append_operations = | ||
266 | + stats->failed_ops[BLOCK_ACCT_ZONE_APPEND]; | ||
267 | ds->failed_flush_operations = stats->failed_ops[BLOCK_ACCT_FLUSH]; | ||
268 | ds->failed_unmap_operations = stats->failed_ops[BLOCK_ACCT_UNMAP]; | ||
269 | |||
270 | ds->invalid_rd_operations = stats->invalid_ops[BLOCK_ACCT_READ]; | ||
271 | ds->invalid_wr_operations = stats->invalid_ops[BLOCK_ACCT_WRITE]; | ||
272 | + ds->invalid_zone_append_operations = | ||
273 | + stats->invalid_ops[BLOCK_ACCT_ZONE_APPEND]; | ||
274 | ds->invalid_flush_operations = | ||
275 | stats->invalid_ops[BLOCK_ACCT_FLUSH]; | ||
276 | ds->invalid_unmap_operations = stats->invalid_ops[BLOCK_ACCT_UNMAP]; | ||
277 | |||
278 | ds->rd_merged = stats->merged[BLOCK_ACCT_READ]; | ||
279 | ds->wr_merged = stats->merged[BLOCK_ACCT_WRITE]; | ||
280 | + ds->zone_append_merged = stats->merged[BLOCK_ACCT_ZONE_APPEND]; | ||
281 | ds->unmap_merged = stats->merged[BLOCK_ACCT_UNMAP]; | ||
282 | ds->flush_operations = stats->nr_ops[BLOCK_ACCT_FLUSH]; | ||
283 | ds->wr_total_time_ns = stats->total_time_ns[BLOCK_ACCT_WRITE]; | ||
284 | + ds->zone_append_total_time_ns = | ||
285 | + stats->total_time_ns[BLOCK_ACCT_ZONE_APPEND]; | ||
286 | ds->rd_total_time_ns = stats->total_time_ns[BLOCK_ACCT_READ]; | ||
287 | ds->flush_total_time_ns = stats->total_time_ns[BLOCK_ACCT_FLUSH]; | ||
288 | ds->unmap_total_time_ns = stats->total_time_ns[BLOCK_ACCT_UNMAP]; | ||
289 | @@ -XXX,XX +XXX,XX @@ static void bdrv_query_blk_stats(BlockDeviceStats *ds, BlockBackend *blk) | ||
290 | |||
291 | TimedAverage *rd = &ts->latency[BLOCK_ACCT_READ]; | ||
292 | TimedAverage *wr = &ts->latency[BLOCK_ACCT_WRITE]; | ||
293 | + TimedAverage *zap = &ts->latency[BLOCK_ACCT_ZONE_APPEND]; | ||
294 | TimedAverage *fl = &ts->latency[BLOCK_ACCT_FLUSH]; | ||
295 | |||
296 | dev_stats->interval_length = ts->interval_length; | ||
297 | @@ -XXX,XX +XXX,XX @@ static void bdrv_query_blk_stats(BlockDeviceStats *ds, BlockBackend *blk) | ||
298 | dev_stats->max_wr_latency_ns = timed_average_max(wr); | ||
299 | dev_stats->avg_wr_latency_ns = timed_average_avg(wr); | ||
300 | |||
301 | + dev_stats->min_zone_append_latency_ns = timed_average_min(zap); | ||
302 | + dev_stats->max_zone_append_latency_ns = timed_average_max(zap); | ||
303 | + dev_stats->avg_zone_append_latency_ns = timed_average_avg(zap); | ||
304 | + | ||
305 | dev_stats->min_flush_latency_ns = timed_average_min(fl); | ||
306 | dev_stats->max_flush_latency_ns = timed_average_max(fl); | ||
307 | dev_stats->avg_flush_latency_ns = timed_average_avg(fl); | ||
308 | @@ -XXX,XX +XXX,XX @@ static void bdrv_query_blk_stats(BlockDeviceStats *ds, BlockBackend *blk) | ||
309 | block_acct_queue_depth(ts, BLOCK_ACCT_READ); | ||
310 | dev_stats->avg_wr_queue_depth = | ||
311 | block_acct_queue_depth(ts, BLOCK_ACCT_WRITE); | ||
312 | + dev_stats->avg_zone_append_queue_depth = | ||
313 | + block_acct_queue_depth(ts, BLOCK_ACCT_ZONE_APPEND); | ||
314 | |||
315 | QAPI_LIST_PREPEND(ds->timed_stats, dev_stats); | ||
316 | } | ||
317 | @@ -XXX,XX +XXX,XX @@ static void bdrv_query_blk_stats(BlockDeviceStats *ds, BlockBackend *blk) | ||
318 | = bdrv_latency_histogram_stats(&hgram[BLOCK_ACCT_READ]); | ||
319 | ds->wr_latency_histogram | ||
320 | = bdrv_latency_histogram_stats(&hgram[BLOCK_ACCT_WRITE]); | ||
321 | + ds->zone_append_latency_histogram | ||
322 | + = bdrv_latency_histogram_stats(&hgram[BLOCK_ACCT_ZONE_APPEND]); | ||
323 | ds->flush_latency_histogram | ||
324 | = bdrv_latency_histogram_stats(&hgram[BLOCK_ACCT_FLUSH]); | ||
325 | } | ||
326 | diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c | ||
327 | index XXXXXXX..XXXXXXX 100644 | ||
328 | --- a/hw/block/virtio-blk.c | ||
329 | +++ b/hw/block/virtio-blk.c | ||
330 | @@ -XXX,XX +XXX,XX @@ static int virtio_blk_handle_zone_append(VirtIOBlockReq *req, | ||
331 | data->in_num = in_num; | ||
332 | data->zone_append_data.offset = offset; | ||
333 | qemu_iovec_init_external(&req->qiov, out_iov, out_num); | ||
334 | + | ||
335 | + block_acct_start(blk_get_stats(s->blk), &req->acct, len, | ||
336 | + BLOCK_ACCT_ZONE_APPEND); | ||
337 | + | ||
338 | blk_aio_zone_append(s->blk, &data->zone_append_data.offset, &req->qiov, 0, | ||
339 | virtio_blk_zone_append_complete, data); | ||
340 | return 0; | ||
67 | -- | 341 | -- |
68 | 2.31.1 | 342 | 2.39.2 |
69 | |||
70 | diff view generated by jsdifflib |
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 1 | From: Sam Li <faithilikerun@gmail.com> |
---|---|---|---|
2 | 2 | ||
3 | We are going to publish copy-before-write filter, and there no public | 3 | Signed-off-by: Sam Li <faithilikerun@gmail.com> |
4 | backing-child-based filter in Qemu. No reason to create a precedent, so | 4 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> |
5 | let's refactor copy-before-write filter instead. | 5 | Message-id: 20230407082528.18841-5-faithilikerun@gmail.com |
6 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
7 | --- | ||
8 | hw/block/virtio-blk.c | 12 ++++++++++++ | ||
9 | hw/block/trace-events | 7 +++++++ | ||
10 | 2 files changed, 19 insertions(+) | ||
6 | 11 | ||
7 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 12 | diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c |
8 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
9 | Message-Id: <20210824083856.17408-13-vsementsov@virtuozzo.com> | ||
10 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
11 | --- | ||
12 | block/copy-before-write.c | 39 ++++++++++++++++++++++----------------- | ||
13 | 1 file changed, 22 insertions(+), 17 deletions(-) | ||
14 | |||
15 | diff --git a/block/copy-before-write.c b/block/copy-before-write.c | ||
16 | index XXXXXXX..XXXXXXX 100644 | 13 | index XXXXXXX..XXXXXXX 100644 |
17 | --- a/block/copy-before-write.c | 14 | --- a/hw/block/virtio-blk.c |
18 | +++ b/block/copy-before-write.c | 15 | +++ b/hw/block/virtio-blk.c |
19 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int cbw_co_preadv( | 16 | @@ -XXX,XX +XXX,XX @@ static void virtio_blk_zone_report_complete(void *opaque, int ret) |
20 | BlockDriverState *bs, uint64_t offset, uint64_t bytes, | 17 | int64_t nz = data->zone_report_data.nr_zones; |
21 | QEMUIOVector *qiov, int flags) | 18 | int8_t err_status = VIRTIO_BLK_S_OK; |
19 | |||
20 | + trace_virtio_blk_zone_report_complete(vdev, req, nz, ret); | ||
21 | if (ret) { | ||
22 | err_status = VIRTIO_BLK_S_ZONE_INVALID_CMD; | ||
23 | goto out; | ||
24 | @@ -XXX,XX +XXX,XX @@ static void virtio_blk_handle_zone_report(VirtIOBlockReq *req, | ||
25 | nr_zones = (req->in_len - sizeof(struct virtio_blk_inhdr) - | ||
26 | sizeof(struct virtio_blk_zone_report)) / | ||
27 | sizeof(struct virtio_blk_zone_descriptor); | ||
28 | + trace_virtio_blk_handle_zone_report(vdev, req, | ||
29 | + offset >> BDRV_SECTOR_BITS, nr_zones); | ||
30 | |||
31 | zone_size = sizeof(BlockZoneDescriptor) * nr_zones; | ||
32 | data = g_malloc(sizeof(ZoneCmdData)); | ||
33 | @@ -XXX,XX +XXX,XX @@ static void virtio_blk_zone_mgmt_complete(void *opaque, int ret) | ||
22 | { | 34 | { |
23 | - return bdrv_co_preadv(bs->backing, offset, bytes, qiov, flags); | 35 | VirtIOBlockReq *req = opaque; |
24 | + return bdrv_co_preadv(bs->file, offset, bytes, qiov, flags); | 36 | VirtIOBlock *s = req->dev; |
25 | } | 37 | + VirtIODevice *vdev = VIRTIO_DEVICE(s); |
26 | 38 | int8_t err_status = VIRTIO_BLK_S_OK; | |
27 | static coroutine_fn int cbw_do_copy_before_write(BlockDriverState *bs, | 39 | + trace_virtio_blk_zone_mgmt_complete(vdev, req,ret); |
28 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn cbw_co_pdiscard(BlockDriverState *bs, | 40 | |
29 | return ret; | 41 | if (ret) { |
42 | err_status = VIRTIO_BLK_S_ZONE_INVALID_CMD; | ||
43 | @@ -XXX,XX +XXX,XX @@ static int virtio_blk_handle_zone_mgmt(VirtIOBlockReq *req, BlockZoneOp op) | ||
44 | /* Entire drive capacity */ | ||
45 | offset = 0; | ||
46 | len = capacity; | ||
47 | + trace_virtio_blk_handle_zone_reset_all(vdev, req, 0, | ||
48 | + bs->total_sectors); | ||
49 | } else { | ||
50 | if (bs->bl.zone_size > capacity - offset) { | ||
51 | /* The zoned device allows the last smaller zone. */ | ||
52 | @@ -XXX,XX +XXX,XX @@ static int virtio_blk_handle_zone_mgmt(VirtIOBlockReq *req, BlockZoneOp op) | ||
53 | } else { | ||
54 | len = bs->bl.zone_size; | ||
55 | } | ||
56 | + trace_virtio_blk_handle_zone_mgmt(vdev, req, op, | ||
57 | + offset >> BDRV_SECTOR_BITS, | ||
58 | + len >> BDRV_SECTOR_BITS); | ||
30 | } | 59 | } |
31 | 60 | ||
32 | - return bdrv_co_pdiscard(bs->backing, offset, bytes); | 61 | if (!check_zoned_request(s, offset, len, false, &err_status)) { |
33 | + return bdrv_co_pdiscard(bs->file, offset, bytes); | 62 | @@ -XXX,XX +XXX,XX @@ static void virtio_blk_zone_append_complete(void *opaque, int ret) |
34 | } | 63 | err_status = VIRTIO_BLK_S_ZONE_INVALID_CMD; |
35 | 64 | goto out; | |
36 | static int coroutine_fn cbw_co_pwrite_zeroes(BlockDriverState *bs, | ||
37 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn cbw_co_pwrite_zeroes(BlockDriverState *bs, | ||
38 | return ret; | ||
39 | } | 65 | } |
40 | 66 | + trace_virtio_blk_zone_append_complete(vdev, req, append_sector, ret); | |
41 | - return bdrv_co_pwrite_zeroes(bs->backing, offset, bytes, flags); | 67 | |
42 | + return bdrv_co_pwrite_zeroes(bs->file, offset, bytes, flags); | 68 | out: |
43 | } | 69 | aio_context_acquire(blk_get_aio_context(s->conf.conf.blk)); |
44 | 70 | @@ -XXX,XX +XXX,XX @@ static int virtio_blk_handle_zone_append(VirtIOBlockReq *req, | |
45 | static coroutine_fn int cbw_co_pwritev(BlockDriverState *bs, | 71 | int64_t offset = virtio_ldq_p(vdev, &req->out.sector) << BDRV_SECTOR_BITS; |
46 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int cbw_co_pwritev(BlockDriverState *bs, | 72 | int64_t len = iov_size(out_iov, out_num); |
47 | return ret; | 73 | |
74 | + trace_virtio_blk_handle_zone_append(vdev, req, offset >> BDRV_SECTOR_BITS); | ||
75 | if (!check_zoned_request(s, offset, len, true, &err_status)) { | ||
76 | goto out; | ||
48 | } | 77 | } |
49 | 78 | diff --git a/hw/block/trace-events b/hw/block/trace-events | |
50 | - return bdrv_co_pwritev(bs->backing, offset, bytes, qiov, flags); | 79 | index XXXXXXX..XXXXXXX 100644 |
51 | + return bdrv_co_pwritev(bs->file, offset, bytes, qiov, flags); | 80 | --- a/hw/block/trace-events |
52 | } | 81 | +++ b/hw/block/trace-events |
53 | 82 | @@ -XXX,XX +XXX,XX @@ pflash_write_unknown(const char *name, uint8_t cmd) "%s: unknown command 0x%02x" | |
54 | static int coroutine_fn cbw_co_flush(BlockDriverState *bs) | 83 | # virtio-blk.c |
55 | { | 84 | virtio_blk_req_complete(void *vdev, void *req, int status) "vdev %p req %p status %d" |
56 | - if (!bs->backing) { | 85 | virtio_blk_rw_complete(void *vdev, void *req, int ret) "vdev %p req %p ret %d" |
57 | + if (!bs->file) { | 86 | +virtio_blk_zone_report_complete(void *vdev, void *req, unsigned int nr_zones, int ret) "vdev %p req %p nr_zones %u ret %d" |
58 | return 0; | 87 | +virtio_blk_zone_mgmt_complete(void *vdev, void *req, int ret) "vdev %p req %p ret %d" |
59 | } | 88 | +virtio_blk_zone_append_complete(void *vdev, void *req, int64_t sector, int ret) "vdev %p req %p, append sector 0x%" PRIx64 " ret %d" |
60 | 89 | virtio_blk_handle_write(void *vdev, void *req, uint64_t sector, size_t nsectors) "vdev %p req %p sector %"PRIu64" nsectors %zu" | |
61 | - return bdrv_co_flush(bs->backing->bs); | 90 | virtio_blk_handle_read(void *vdev, void *req, uint64_t sector, size_t nsectors) "vdev %p req %p sector %"PRIu64" nsectors %zu" |
62 | + return bdrv_co_flush(bs->file->bs); | 91 | virtio_blk_submit_multireq(void *vdev, void *mrb, int start, int num_reqs, uint64_t offset, size_t size, bool is_write) "vdev %p mrb %p start %d num_reqs %d offset %"PRIu64" size %zu is_write %d" |
63 | } | 92 | +virtio_blk_handle_zone_report(void *vdev, void *req, int64_t sector, unsigned int nr_zones) "vdev %p req %p sector 0x%" PRIx64 " nr_zones %u" |
64 | 93 | +virtio_blk_handle_zone_mgmt(void *vdev, void *req, uint8_t op, int64_t sector, int64_t len) "vdev %p req %p op 0x%x sector 0x%" PRIx64 " len 0x%" PRIx64 "" | |
65 | static void cbw_refresh_filename(BlockDriverState *bs) | 94 | +virtio_blk_handle_zone_reset_all(void *vdev, void *req, int64_t sector, int64_t len) "vdev %p req %p sector 0x%" PRIx64 " cap 0x%" PRIx64 "" |
66 | { | 95 | +virtio_blk_handle_zone_append(void *vdev, void *req, int64_t sector) "vdev %p req %p, append sector 0x%" PRIx64 "" |
67 | - if (bs->backing == NULL) { | 96 | |
68 | - /* | 97 | # hd-geometry.c |
69 | - * we can be here after failed bdrv_attach_child in | 98 | hd_geometry_lchs_guess(void *blk, int cyls, int heads, int secs) "blk %p LCHS %d %d %d" |
70 | - * bdrv_set_backing_hd | ||
71 | - */ | ||
72 | - return; | ||
73 | - } | ||
74 | pstrcpy(bs->exact_filename, sizeof(bs->exact_filename), | ||
75 | - bs->backing->bs->filename); | ||
76 | + bs->file->bs->filename); | ||
77 | } | ||
78 | |||
79 | static void cbw_child_perm(BlockDriverState *bs, BdrvChild *c, | ||
80 | @@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_cbw_append(BlockDriverState *source, | ||
81 | top = bdrv_new_open_driver(&bdrv_cbw_filter, filter_node_name, | ||
82 | BDRV_O_RDWR, errp); | ||
83 | if (!top) { | ||
84 | + error_prepend(errp, "Cannot open driver: "); | ||
85 | return NULL; | ||
86 | } | ||
87 | |||
88 | @@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_cbw_append(BlockDriverState *source, | ||
89 | state->target = bdrv_attach_child(top, target, "target", &child_of_bds, | ||
90 | BDRV_CHILD_DATA, errp); | ||
91 | if (!state->target) { | ||
92 | + error_prepend(errp, "Cannot attach target child: "); | ||
93 | + bdrv_unref(top); | ||
94 | + return NULL; | ||
95 | + } | ||
96 | + | ||
97 | + bdrv_ref(source); | ||
98 | + top->file = bdrv_attach_child(top, source, "file", &child_of_bds, | ||
99 | + BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, | ||
100 | + errp); | ||
101 | + if (!top->file) { | ||
102 | + error_prepend(errp, "Cannot attach file child: "); | ||
103 | bdrv_unref(top); | ||
104 | return NULL; | ||
105 | } | ||
106 | |||
107 | bdrv_drained_begin(source); | ||
108 | |||
109 | - ret = bdrv_append(top, source, errp); | ||
110 | + ret = bdrv_replace_node(source, top, errp); | ||
111 | if (ret < 0) { | ||
112 | error_prepend(errp, "Cannot append copy-before-write filter: "); | ||
113 | goto fail; | ||
114 | } | ||
115 | appended = true; | ||
116 | |||
117 | - state->bcs = block_copy_state_new(top->backing, state->target, | ||
118 | - false, compress, errp); | ||
119 | + state->bcs = block_copy_state_new(top->file, state->target, false, compress, | ||
120 | + errp); | ||
121 | if (!state->bcs) { | ||
122 | error_prepend(errp, "Cannot create block-copy-state: "); | ||
123 | goto fail; | ||
124 | -- | 99 | -- |
125 | 2.31.1 | 100 | 2.39.2 |
126 | |||
127 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
2 | 1 | ||
3 | Refactor the function to replace child at last. Thus we don't need to | ||
4 | revert it and code is simplified. | ||
5 | |||
6 | block-copy state initialization being done before replacing the child | ||
7 | doesn't need any drained section. | ||
8 | |||
9 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
10 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
11 | Message-Id: <20210824083856.17408-14-vsementsov@virtuozzo.com> | ||
12 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
13 | --- | ||
14 | block/copy-before-write.c | 33 +++++++++++---------------------- | ||
15 | 1 file changed, 11 insertions(+), 22 deletions(-) | ||
16 | |||
17 | diff --git a/block/copy-before-write.c b/block/copy-before-write.c | ||
18 | index XXXXXXX..XXXXXXX 100644 | ||
19 | --- a/block/copy-before-write.c | ||
20 | +++ b/block/copy-before-write.c | ||
21 | @@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_cbw_append(BlockDriverState *source, | ||
22 | int ret; | ||
23 | BDRVCopyBeforeWriteState *state; | ||
24 | BlockDriverState *top; | ||
25 | - bool appended = false; | ||
26 | |||
27 | assert(source->total_sectors == target->total_sectors); | ||
28 | |||
29 | @@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_cbw_append(BlockDriverState *source, | ||
30 | BDRV_CHILD_DATA, errp); | ||
31 | if (!state->target) { | ||
32 | error_prepend(errp, "Cannot attach target child: "); | ||
33 | - bdrv_unref(top); | ||
34 | - return NULL; | ||
35 | + goto fail; | ||
36 | } | ||
37 | |||
38 | bdrv_ref(source); | ||
39 | @@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_cbw_append(BlockDriverState *source, | ||
40 | errp); | ||
41 | if (!top->file) { | ||
42 | error_prepend(errp, "Cannot attach file child: "); | ||
43 | - bdrv_unref(top); | ||
44 | - return NULL; | ||
45 | - } | ||
46 | - | ||
47 | - bdrv_drained_begin(source); | ||
48 | - | ||
49 | - ret = bdrv_replace_node(source, top, errp); | ||
50 | - if (ret < 0) { | ||
51 | - error_prepend(errp, "Cannot append copy-before-write filter: "); | ||
52 | goto fail; | ||
53 | } | ||
54 | - appended = true; | ||
55 | |||
56 | state->bcs = block_copy_state_new(top->file, state->target, false, compress, | ||
57 | errp); | ||
58 | @@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_cbw_append(BlockDriverState *source, | ||
59 | error_prepend(errp, "Cannot create block-copy-state: "); | ||
60 | goto fail; | ||
61 | } | ||
62 | - *bcs = state->bcs; | ||
63 | |||
64 | + bdrv_drained_begin(source); | ||
65 | + ret = bdrv_replace_node(source, top, errp); | ||
66 | bdrv_drained_end(source); | ||
67 | + if (ret < 0) { | ||
68 | + error_prepend(errp, "Cannot append copy-before-write filter: "); | ||
69 | + goto fail; | ||
70 | + } | ||
71 | + | ||
72 | + *bcs = state->bcs; | ||
73 | |||
74 | return top; | ||
75 | |||
76 | fail: | ||
77 | - if (appended) { | ||
78 | - bdrv_cbw_drop(top); | ||
79 | - } else { | ||
80 | - bdrv_unref(top); | ||
81 | - } | ||
82 | - | ||
83 | - bdrv_drained_end(source); | ||
84 | - | ||
85 | + block_copy_state_free(state->bcs); | ||
86 | + bdrv_unref(top); | ||
87 | return NULL; | ||
88 | } | ||
89 | |||
90 | -- | ||
91 | 2.31.1 | ||
92 | |||
93 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
2 | 1 | ||
3 | One more step closer to real .bdrv_open() handler: use more usual names | ||
4 | for bs being initialized and its state. | ||
5 | |||
6 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
7 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
8 | Message-Id: <20210824083856.17408-16-vsementsov@virtuozzo.com> | ||
9 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
10 | --- | ||
11 | block/copy-before-write.c | 29 ++++++++++++++--------------- | ||
12 | 1 file changed, 14 insertions(+), 15 deletions(-) | ||
13 | |||
14 | diff --git a/block/copy-before-write.c b/block/copy-before-write.c | ||
15 | index XXXXXXX..XXXXXXX 100644 | ||
16 | --- a/block/copy-before-write.c | ||
17 | +++ b/block/copy-before-write.c | ||
18 | @@ -XXX,XX +XXX,XX @@ static void cbw_child_perm(BlockDriverState *bs, BdrvChild *c, | ||
19 | } | ||
20 | } | ||
21 | |||
22 | -static int cbw_init(BlockDriverState *top, BlockDriverState *source, | ||
23 | +static int cbw_init(BlockDriverState *bs, BlockDriverState *source, | ||
24 | BlockDriverState *target, bool compress, Error **errp) | ||
25 | { | ||
26 | - BDRVCopyBeforeWriteState *state = top->opaque; | ||
27 | + BDRVCopyBeforeWriteState *s = bs->opaque; | ||
28 | |||
29 | - top->total_sectors = source->total_sectors; | ||
30 | - top->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED | | ||
31 | + bs->total_sectors = source->total_sectors; | ||
32 | + bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED | | ||
33 | (BDRV_REQ_FUA & source->supported_write_flags); | ||
34 | - top->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED | | ||
35 | + bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED | | ||
36 | ((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK) & | ||
37 | source->supported_zero_flags); | ||
38 | |||
39 | bdrv_ref(target); | ||
40 | - state->target = bdrv_attach_child(top, target, "target", &child_of_bds, | ||
41 | - BDRV_CHILD_DATA, errp); | ||
42 | - if (!state->target) { | ||
43 | + s->target = bdrv_attach_child(bs, target, "target", &child_of_bds, | ||
44 | + BDRV_CHILD_DATA, errp); | ||
45 | + if (!s->target) { | ||
46 | error_prepend(errp, "Cannot attach target child: "); | ||
47 | return -EINVAL; | ||
48 | } | ||
49 | |||
50 | bdrv_ref(source); | ||
51 | - top->file = bdrv_attach_child(top, source, "file", &child_of_bds, | ||
52 | - BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, | ||
53 | - errp); | ||
54 | - if (!top->file) { | ||
55 | + bs->file = bdrv_attach_child(bs, source, "file", &child_of_bds, | ||
56 | + BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, | ||
57 | + errp); | ||
58 | + if (!bs->file) { | ||
59 | error_prepend(errp, "Cannot attach file child: "); | ||
60 | return -EINVAL; | ||
61 | } | ||
62 | |||
63 | - state->bcs = block_copy_state_new(top->file, state->target, false, compress, | ||
64 | - errp); | ||
65 | - if (!state->bcs) { | ||
66 | + s->bcs = block_copy_state_new(bs->file, s->target, false, compress, errp); | ||
67 | + if (!s->bcs) { | ||
68 | error_prepend(errp, "Cannot create block-copy-state: "); | ||
69 | return -EINVAL; | ||
70 | } | ||
71 | -- | ||
72 | 2.31.1 | ||
73 | |||
74 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
2 | 1 | ||
3 | In the next commit we'll get rid of source argument of cbw_init(). | ||
4 | Prepare to it now, to make next commit simpler: move the code block | ||
5 | that uses source below attaching the child and use bs->file->bs instead | ||
6 | of source variable. | ||
7 | |||
8 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
9 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
10 | Message-Id: <20210824083856.17408-17-vsementsov@virtuozzo.com> | ||
11 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
12 | --- | ||
13 | block/copy-before-write.c | 14 +++++++------- | ||
14 | 1 file changed, 7 insertions(+), 7 deletions(-) | ||
15 | |||
16 | diff --git a/block/copy-before-write.c b/block/copy-before-write.c | ||
17 | index XXXXXXX..XXXXXXX 100644 | ||
18 | --- a/block/copy-before-write.c | ||
19 | +++ b/block/copy-before-write.c | ||
20 | @@ -XXX,XX +XXX,XX @@ static int cbw_init(BlockDriverState *bs, BlockDriverState *source, | ||
21 | { | ||
22 | BDRVCopyBeforeWriteState *s = bs->opaque; | ||
23 | |||
24 | - bs->total_sectors = source->total_sectors; | ||
25 | - bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED | | ||
26 | - (BDRV_REQ_FUA & source->supported_write_flags); | ||
27 | - bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED | | ||
28 | - ((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK) & | ||
29 | - source->supported_zero_flags); | ||
30 | - | ||
31 | bdrv_ref(target); | ||
32 | s->target = bdrv_attach_child(bs, target, "target", &child_of_bds, | ||
33 | BDRV_CHILD_DATA, errp); | ||
34 | @@ -XXX,XX +XXX,XX @@ static int cbw_init(BlockDriverState *bs, BlockDriverState *source, | ||
35 | return -EINVAL; | ||
36 | } | ||
37 | |||
38 | + bs->total_sectors = bs->file->bs->total_sectors; | ||
39 | + bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED | | ||
40 | + (BDRV_REQ_FUA & bs->file->bs->supported_write_flags); | ||
41 | + bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED | | ||
42 | + ((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK) & | ||
43 | + bs->file->bs->supported_zero_flags); | ||
44 | + | ||
45 | s->bcs = block_copy_state_new(bs->file, s->target, false, compress, errp); | ||
46 | if (!s->bcs) { | ||
47 | error_prepend(errp, "Cannot create block-copy-state: "); | ||
48 | -- | ||
49 | 2.31.1 | ||
50 | |||
51 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
2 | 1 | ||
3 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
4 | Reviewed-by: Hanna Reitz <hreitz@redhat.com> | ||
5 | Message-Id: <20210824083856.17408-18-vsementsov@virtuozzo.com> | ||
6 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
7 | --- | ||
8 | block/copy-before-write.h | 1 - | ||
9 | block/backup.c | 2 +- | ||
10 | block/copy-before-write.c | 7 +++---- | ||
11 | 3 files changed, 4 insertions(+), 6 deletions(-) | ||
12 | |||
13 | diff --git a/block/copy-before-write.h b/block/copy-before-write.h | ||
14 | index XXXXXXX..XXXXXXX 100644 | ||
15 | --- a/block/copy-before-write.h | ||
16 | +++ b/block/copy-before-write.h | ||
17 | @@ -XXX,XX +XXX,XX @@ | ||
18 | BlockDriverState *bdrv_cbw_append(BlockDriverState *source, | ||
19 | BlockDriverState *target, | ||
20 | const char *filter_node_name, | ||
21 | - bool compress, | ||
22 | BlockCopyState **bcs, | ||
23 | Error **errp); | ||
24 | void bdrv_cbw_drop(BlockDriverState *bs); | ||
25 | diff --git a/block/backup.c b/block/backup.c | ||
26 | index XXXXXXX..XXXXXXX 100644 | ||
27 | --- a/block/backup.c | ||
28 | +++ b/block/backup.c | ||
29 | @@ -XXX,XX +XXX,XX @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, | ||
30 | goto error; | ||
31 | } | ||
32 | |||
33 | - cbw = bdrv_cbw_append(bs, target, filter_node_name, false, &bcs, errp); | ||
34 | + cbw = bdrv_cbw_append(bs, target, filter_node_name, &bcs, errp); | ||
35 | if (!cbw) { | ||
36 | goto error; | ||
37 | } | ||
38 | diff --git a/block/copy-before-write.c b/block/copy-before-write.c | ||
39 | index XXXXXXX..XXXXXXX 100644 | ||
40 | --- a/block/copy-before-write.c | ||
41 | +++ b/block/copy-before-write.c | ||
42 | @@ -XXX,XX +XXX,XX @@ static void cbw_child_perm(BlockDriverState *bs, BdrvChild *c, | ||
43 | } | ||
44 | |||
45 | static int cbw_init(BlockDriverState *bs, BlockDriverState *source, | ||
46 | - BlockDriverState *target, bool compress, Error **errp) | ||
47 | + BlockDriverState *target, Error **errp) | ||
48 | { | ||
49 | BDRVCopyBeforeWriteState *s = bs->opaque; | ||
50 | |||
51 | @@ -XXX,XX +XXX,XX @@ static int cbw_init(BlockDriverState *bs, BlockDriverState *source, | ||
52 | ((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK) & | ||
53 | bs->file->bs->supported_zero_flags); | ||
54 | |||
55 | - s->bcs = block_copy_state_new(bs->file, s->target, false, compress, errp); | ||
56 | + s->bcs = block_copy_state_new(bs->file, s->target, false, false, errp); | ||
57 | if (!s->bcs) { | ||
58 | error_prepend(errp, "Cannot create block-copy-state: "); | ||
59 | return -EINVAL; | ||
60 | @@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_cbw_filter = { | ||
61 | BlockDriverState *bdrv_cbw_append(BlockDriverState *source, | ||
62 | BlockDriverState *target, | ||
63 | const char *filter_node_name, | ||
64 | - bool compress, | ||
65 | BlockCopyState **bcs, | ||
66 | Error **errp) | ||
67 | { | ||
68 | @@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_cbw_append(BlockDriverState *source, | ||
69 | } | ||
70 | state = top->opaque; | ||
71 | |||
72 | - ret = cbw_init(top, source, target, compress, errp); | ||
73 | + ret = cbw_init(top, source, target, errp); | ||
74 | if (ret < 0) { | ||
75 | goto fail; | ||
76 | } | ||
77 | -- | ||
78 | 2.31.1 | ||
79 | |||
80 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
2 | 1 | ||
3 | Now block-copy will crash if user don't set progress meter by | ||
4 | block_copy_set_progress_meter(). copy-before-write filter will be used | ||
5 | in separate of backup job, and it doesn't want any progress meter (for | ||
6 | now). So, allow not setting it. | ||
7 | |||
8 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
9 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
10 | Message-Id: <20210824083856.17408-21-vsementsov@virtuozzo.com> | ||
11 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
12 | --- | ||
13 | block/block-copy.c | 18 +++++++++++------- | ||
14 | 1 file changed, 11 insertions(+), 7 deletions(-) | ||
15 | |||
16 | diff --git a/block/block-copy.c b/block/block-copy.c | ||
17 | index XXXXXXX..XXXXXXX 100644 | ||
18 | --- a/block/block-copy.c | ||
19 | +++ b/block/block-copy.c | ||
20 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn block_copy_task_end(BlockCopyTask *task, int ret) | ||
21 | bdrv_set_dirty_bitmap(task->s->copy_bitmap, task->offset, task->bytes); | ||
22 | } | ||
23 | QLIST_REMOVE(task, list); | ||
24 | - progress_set_remaining(task->s->progress, | ||
25 | - bdrv_get_dirty_count(task->s->copy_bitmap) + | ||
26 | - task->s->in_flight_bytes); | ||
27 | + if (task->s->progress) { | ||
28 | + progress_set_remaining(task->s->progress, | ||
29 | + bdrv_get_dirty_count(task->s->copy_bitmap) + | ||
30 | + task->s->in_flight_bytes); | ||
31 | + } | ||
32 | qemu_co_queue_restart_all(&task->wait_queue); | ||
33 | } | ||
34 | |||
35 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int block_copy_task_entry(AioTask *task) | ||
36 | t->call_state->ret = ret; | ||
37 | t->call_state->error_is_read = error_is_read; | ||
38 | } | ||
39 | - } else { | ||
40 | + } else if (s->progress) { | ||
41 | progress_work_done(s->progress, t->bytes); | ||
42 | } | ||
43 | } | ||
44 | @@ -XXX,XX +XXX,XX @@ int64_t block_copy_reset_unallocated(BlockCopyState *s, | ||
45 | if (!ret) { | ||
46 | qemu_co_mutex_lock(&s->lock); | ||
47 | bdrv_reset_dirty_bitmap(s->copy_bitmap, offset, bytes); | ||
48 | - progress_set_remaining(s->progress, | ||
49 | - bdrv_get_dirty_count(s->copy_bitmap) + | ||
50 | - s->in_flight_bytes); | ||
51 | + if (s->progress) { | ||
52 | + progress_set_remaining(s->progress, | ||
53 | + bdrv_get_dirty_count(s->copy_bitmap) + | ||
54 | + s->in_flight_bytes); | ||
55 | + } | ||
56 | qemu_co_mutex_unlock(&s->lock); | ||
57 | } | ||
58 | |||
59 | -- | ||
60 | 2.31.1 | ||
61 | |||
62 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
2 | 1 | ||
3 | - use shorter construction | ||
4 | - don't create new dict if not needed | ||
5 | - drop extra unpacking key-val arguments | ||
6 | - drop extra default values | ||
7 | |||
8 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
9 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
10 | Reviewed-by: John Snow <jsnow@redhat.com> | ||
11 | Message-Id: <20210824083856.17408-24-vsementsov@virtuozzo.com> | ||
12 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
13 | --- | ||
14 | python/qemu/machine/machine.py | 18 ++++++++---------- | ||
15 | 1 file changed, 8 insertions(+), 10 deletions(-) | ||
16 | |||
17 | diff --git a/python/qemu/machine/machine.py b/python/qemu/machine/machine.py | ||
18 | index XXXXXXX..XXXXXXX 100644 | ||
19 | --- a/python/qemu/machine/machine.py | ||
20 | +++ b/python/qemu/machine/machine.py | ||
21 | @@ -XXX,XX +XXX,XX @@ def _qmp(self) -> QEMUMonitorProtocol: | ||
22 | return self._qmp_connection | ||
23 | |||
24 | @classmethod | ||
25 | - def _qmp_args(cls, _conv_keys: bool = True, **args: Any) -> Dict[str, Any]: | ||
26 | - qmp_args = dict() | ||
27 | - for key, value in args.items(): | ||
28 | - if _conv_keys: | ||
29 | - qmp_args[key.replace('_', '-')] = value | ||
30 | - else: | ||
31 | - qmp_args[key] = value | ||
32 | - return qmp_args | ||
33 | + def _qmp_args(cls, conv_keys: bool, | ||
34 | + args: Dict[str, Any]) -> Dict[str, object]: | ||
35 | + if conv_keys: | ||
36 | + return {k.replace('_', '-'): v for k, v in args.items()} | ||
37 | + | ||
38 | + return args | ||
39 | |||
40 | def qmp(self, cmd: str, | ||
41 | conv_keys: bool = True, | ||
42 | @@ -XXX,XX +XXX,XX @@ def qmp(self, cmd: str, | ||
43 | """ | ||
44 | Invoke a QMP command and return the response dict | ||
45 | """ | ||
46 | - qmp_args = self._qmp_args(conv_keys, **args) | ||
47 | + qmp_args = self._qmp_args(conv_keys, args) | ||
48 | return self._qmp.cmd(cmd, args=qmp_args) | ||
49 | |||
50 | def command(self, cmd: str, | ||
51 | @@ -XXX,XX +XXX,XX @@ def command(self, cmd: str, | ||
52 | On success return the response dict. | ||
53 | On failure raise an exception. | ||
54 | """ | ||
55 | - qmp_args = self._qmp_args(conv_keys, **args) | ||
56 | + qmp_args = self._qmp_args(conv_keys, args) | ||
57 | return self._qmp.command(cmd, **qmp_args) | ||
58 | |||
59 | def get_qmp_event(self, wait: bool = False) -> Optional[QMPMessage]: | ||
60 | -- | ||
61 | 2.31.1 | ||
62 | |||
63 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
2 | 1 | ||
3 | We often call qmp() with unpacking dict, like qmp('foo', **{...}). | ||
4 | mypy don't really like it, it thinks that passed unpacked dict is a | ||
5 | positional argument and complains that it type should be bool (because | ||
6 | second argument of qmp() is conv_keys: bool). | ||
7 | |||
8 | Allow passing dict directly, simplifying interface, and giving a way to | ||
9 | satisfy mypy. | ||
10 | |||
11 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
12 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
13 | Reviewed-by: John Snow <jsnow@redhat.com> | ||
14 | Message-Id: <20210824083856.17408-25-vsementsov@virtuozzo.com> | ||
15 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
16 | --- | ||
17 | python/qemu/machine/machine.py | 12 +++++++++++- | ||
18 | 1 file changed, 11 insertions(+), 1 deletion(-) | ||
19 | |||
20 | diff --git a/python/qemu/machine/machine.py b/python/qemu/machine/machine.py | ||
21 | index XXXXXXX..XXXXXXX 100644 | ||
22 | --- a/python/qemu/machine/machine.py | ||
23 | +++ b/python/qemu/machine/machine.py | ||
24 | @@ -XXX,XX +XXX,XX @@ def _qmp_args(cls, conv_keys: bool, | ||
25 | return args | ||
26 | |||
27 | def qmp(self, cmd: str, | ||
28 | - conv_keys: bool = True, | ||
29 | + args_dict: Optional[Dict[str, object]] = None, | ||
30 | + conv_keys: Optional[bool] = None, | ||
31 | **args: Any) -> QMPMessage: | ||
32 | """ | ||
33 | Invoke a QMP command and return the response dict | ||
34 | """ | ||
35 | + if args_dict is not None: | ||
36 | + assert not args | ||
37 | + assert conv_keys is None | ||
38 | + args = args_dict | ||
39 | + conv_keys = False | ||
40 | + | ||
41 | + if conv_keys is None: | ||
42 | + conv_keys = True | ||
43 | + | ||
44 | qmp_args = self._qmp_args(conv_keys, args) | ||
45 | return self._qmp.cmd(cmd, args=qmp_args) | ||
46 | |||
47 | -- | ||
48 | 2.31.1 | ||
49 | |||
50 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
2 | 1 | ||
3 | mypy thinks that return value of these methods in subclusses is | ||
4 | QEMUMachine, which is wrong. So, make typing smarter. | ||
5 | |||
6 | Suggested-by: John Snow <jsnow@redhat.com> | ||
7 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
8 | Message-Id: <20210824083856.17408-26-vsementsov@virtuozzo.com> | ||
9 | Reviewed-by: Hanna Reitz <hreitz@redhat.com> | ||
10 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
11 | --- | ||
12 | python/qemu/machine/machine.py | 10 +++++++--- | ||
13 | 1 file changed, 7 insertions(+), 3 deletions(-) | ||
14 | |||
15 | diff --git a/python/qemu/machine/machine.py b/python/qemu/machine/machine.py | ||
16 | index XXXXXXX..XXXXXXX 100644 | ||
17 | --- a/python/qemu/machine/machine.py | ||
18 | +++ b/python/qemu/machine/machine.py | ||
19 | @@ -XXX,XX +XXX,XX @@ | ||
20 | Sequence, | ||
21 | Tuple, | ||
22 | Type, | ||
23 | + TypeVar, | ||
24 | ) | ||
25 | |||
26 | from qemu.qmp import ( # pylint: disable=import-error | ||
27 | @@ -XXX,XX +XXX,XX @@ class AbnormalShutdown(QEMUMachineError): | ||
28 | """ | ||
29 | |||
30 | |||
31 | +_T = TypeVar('_T', bound='QEMUMachine') | ||
32 | + | ||
33 | + | ||
34 | class QEMUMachine: | ||
35 | """ | ||
36 | A QEMU VM. | ||
37 | @@ -XXX,XX +XXX,XX @@ def __init__(self, | ||
38 | self._remove_files: List[str] = [] | ||
39 | self._user_killed = False | ||
40 | |||
41 | - def __enter__(self) -> 'QEMUMachine': | ||
42 | + def __enter__(self: _T) -> _T: | ||
43 | return self | ||
44 | |||
45 | def __exit__(self, | ||
46 | @@ -XXX,XX +XXX,XX @@ def add_monitor_null(self) -> None: | ||
47 | self._args.append('-monitor') | ||
48 | self._args.append('null') | ||
49 | |||
50 | - def add_fd(self, fd: int, fdset: int, | ||
51 | - opaque: str, opts: str = '') -> 'QEMUMachine': | ||
52 | + def add_fd(self: _T, fd: int, fdset: int, | ||
53 | + opaque: str, opts: str = '') -> _T: | ||
54 | """ | ||
55 | Pass a file descriptor to the VM | ||
56 | """ | ||
57 | -- | ||
58 | 2.31.1 | ||
59 | |||
60 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
2 | 1 | ||
3 | Here: | ||
4 | - long line | ||
5 | - move to new interface of vm.qmp() (direct passing dict), to avoid | ||
6 | mypy false-positive, as it thinks that unpacked dict is a positional | ||
7 | argument. | ||
8 | - extra parenthesis | ||
9 | - handle event_wait possible None value | ||
10 | |||
11 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
12 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
13 | Message-Id: <20210824083856.17408-27-vsementsov@virtuozzo.com> | ||
14 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
15 | --- | ||
16 | tests/qemu-iotests/222 | 20 +++++++++++--------- | ||
17 | tests/qemu-iotests/297 | 2 +- | ||
18 | 2 files changed, 12 insertions(+), 10 deletions(-) | ||
19 | |||
20 | diff --git a/tests/qemu-iotests/222 b/tests/qemu-iotests/222 | ||
21 | index XXXXXXX..XXXXXXX 100755 | ||
22 | --- a/tests/qemu-iotests/222 | ||
23 | +++ b/tests/qemu-iotests/222 | ||
24 | @@ -XXX,XX +XXX,XX @@ remainder = [("0xd5", "0x108000", "32k"), # Right-end of partial-left [1] | ||
25 | |||
26 | with iotests.FilePath('base.img') as base_img_path, \ | ||
27 | iotests.FilePath('fleece.img') as fleece_img_path, \ | ||
28 | - iotests.FilePath('nbd.sock', base_dir=iotests.sock_dir) as nbd_sock_path, \ | ||
29 | + iotests.FilePath('nbd.sock', | ||
30 | + base_dir=iotests.sock_dir) as nbd_sock_path, \ | ||
31 | iotests.VM() as vm: | ||
32 | |||
33 | log('--- Setting up images ---') | ||
34 | @@ -XXX,XX +XXX,XX @@ with iotests.FilePath('base.img') as base_img_path, \ | ||
35 | tgt_node = "fleeceNode" | ||
36 | |||
37 | # create tgt_node backed by src_node | ||
38 | - log(vm.qmp("blockdev-add", **{ | ||
39 | + log(vm.qmp("blockdev-add", { | ||
40 | "driver": "qcow2", | ||
41 | "node-name": tgt_node, | ||
42 | "file": { | ||
43 | @@ -XXX,XX +XXX,XX @@ with iotests.FilePath('base.img') as base_img_path, \ | ||
44 | |||
45 | nbd_uri = 'nbd+unix:///%s?socket=%s' % (tgt_node, nbd_sock_path) | ||
46 | log(vm.qmp("nbd-server-start", | ||
47 | - **{"addr": { "type": "unix", | ||
48 | - "data": { "path": nbd_sock_path } } })) | ||
49 | + {"addr": { "type": "unix", | ||
50 | + "data": { "path": nbd_sock_path } } })) | ||
51 | |||
52 | log(vm.qmp("nbd-server-add", device=tgt_node)) | ||
53 | |||
54 | @@ -XXX,XX +XXX,XX @@ with iotests.FilePath('base.img') as base_img_path, \ | ||
55 | log('--- Sanity Check ---') | ||
56 | log('') | ||
57 | |||
58 | - for p in (patterns + zeroes): | ||
59 | + for p in patterns + zeroes: | ||
60 | cmd = "read -P%s %s %s" % p | ||
61 | log(cmd) | ||
62 | assert qemu_io_silent('-r', '-f', 'raw', '-c', cmd, nbd_uri) == 0 | ||
63 | @@ -XXX,XX +XXX,XX @@ with iotests.FilePath('base.img') as base_img_path, \ | ||
64 | log('--- Verifying Data ---') | ||
65 | log('') | ||
66 | |||
67 | - for p in (patterns + zeroes): | ||
68 | + for p in patterns + zeroes: | ||
69 | cmd = "read -P%s %s %s" % p | ||
70 | log(cmd) | ||
71 | assert qemu_io_silent('-r', '-f', 'raw', '-c', cmd, nbd_uri) == 0 | ||
72 | @@ -XXX,XX +XXX,XX @@ with iotests.FilePath('base.img') as base_img_path, \ | ||
73 | log('') | ||
74 | |||
75 | log(vm.qmp('block-job-cancel', device=src_node)) | ||
76 | - log(vm.event_wait('BLOCK_JOB_CANCELLED'), | ||
77 | - filters=[iotests.filter_qmp_event]) | ||
78 | + e = vm.event_wait('BLOCK_JOB_CANCELLED') | ||
79 | + assert e is not None | ||
80 | + log(e, filters=[iotests.filter_qmp_event]) | ||
81 | log(vm.qmp('nbd-server-stop')) | ||
82 | log(vm.qmp('blockdev-del', node_name=tgt_node)) | ||
83 | vm.shutdown() | ||
84 | @@ -XXX,XX +XXX,XX @@ with iotests.FilePath('base.img') as base_img_path, \ | ||
85 | log('--- Confirming writes ---') | ||
86 | log('') | ||
87 | |||
88 | - for p in (overwrite + remainder): | ||
89 | + for p in overwrite + remainder: | ||
90 | cmd = "read -P%s %s %s" % p | ||
91 | log(cmd) | ||
92 | assert qemu_io_silent(base_img_path, '-c', cmd) == 0 | ||
93 | diff --git a/tests/qemu-iotests/297 b/tests/qemu-iotests/297 | ||
94 | index XXXXXXX..XXXXXXX 100755 | ||
95 | --- a/tests/qemu-iotests/297 | ||
96 | +++ b/tests/qemu-iotests/297 | ||
97 | @@ -XXX,XX +XXX,XX @@ SKIP_FILES = ( | ||
98 | '096', '118', '124', '132', '136', '139', '147', '148', '149', | ||
99 | '151', '152', '155', '163', '165', '169', '194', '196', '199', '202', | ||
100 | '203', '205', '206', '207', '208', '210', '211', '212', '213', '216', | ||
101 | - '218', '219', '222', '224', '228', '234', '235', '236', '237', '238', | ||
102 | + '218', '219', '224', '228', '234', '235', '236', '237', '238', | ||
103 | '240', '242', '245', '246', '248', '255', '256', '257', '258', '260', | ||
104 | '262', '264', '266', '274', '277', '280', '281', '295', '296', '298', | ||
105 | '299', '302', '303', '304', '307', | ||
106 | -- | ||
107 | 2.31.1 | ||
108 | |||
109 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
2 | 1 | ||
3 | The file use both single and double quotes for strings. Let's be | ||
4 | consistent. | ||
5 | |||
6 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
7 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
8 | Message-Id: <20210824083856.17408-28-vsementsov@virtuozzo.com> | ||
9 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
10 | --- | ||
11 | tests/qemu-iotests/222 | 68 +++++++++++++++++++++--------------------- | ||
12 | 1 file changed, 34 insertions(+), 34 deletions(-) | ||
13 | |||
14 | diff --git a/tests/qemu-iotests/222 b/tests/qemu-iotests/222 | ||
15 | index XXXXXXX..XXXXXXX 100755 | ||
16 | --- a/tests/qemu-iotests/222 | ||
17 | +++ b/tests/qemu-iotests/222 | ||
18 | @@ -XXX,XX +XXX,XX @@ iotests.script_initialize( | ||
19 | supported_platforms=['linux'], | ||
20 | ) | ||
21 | |||
22 | -patterns = [("0x5d", "0", "64k"), | ||
23 | - ("0xd5", "1M", "64k"), | ||
24 | - ("0xdc", "32M", "64k"), | ||
25 | - ("0xcd", "0x3ff0000", "64k")] # 64M - 64K | ||
26 | +patterns = [('0x5d', '0', '64k'), | ||
27 | + ('0xd5', '1M', '64k'), | ||
28 | + ('0xdc', '32M', '64k'), | ||
29 | + ('0xcd', '0x3ff0000', '64k')] # 64M - 64K | ||
30 | |||
31 | -overwrite = [("0xab", "0", "64k"), # Full overwrite | ||
32 | - ("0xad", "0x00f8000", "64k"), # Partial-left (1M-32K) | ||
33 | - ("0x1d", "0x2008000", "64k"), # Partial-right (32M+32K) | ||
34 | - ("0xea", "0x3fe0000", "64k")] # Adjacent-left (64M - 128K) | ||
35 | +overwrite = [('0xab', '0', '64k'), # Full overwrite | ||
36 | + ('0xad', '0x00f8000', '64k'), # Partial-left (1M-32K) | ||
37 | + ('0x1d', '0x2008000', '64k'), # Partial-right (32M+32K) | ||
38 | + ('0xea', '0x3fe0000', '64k')] # Adjacent-left (64M - 128K) | ||
39 | |||
40 | -zeroes = [("0", "0x00f8000", "32k"), # Left-end of partial-left (1M-32K) | ||
41 | - ("0", "0x2010000", "32k"), # Right-end of partial-right (32M+64K) | ||
42 | - ("0", "0x3fe0000", "64k")] # overwrite[3] | ||
43 | +zeroes = [('0', '0x00f8000', '32k'), # Left-end of partial-left (1M-32K) | ||
44 | + ('0', '0x2010000', '32k'), # Right-end of partial-right (32M+64K) | ||
45 | + ('0', '0x3fe0000', '64k')] # overwrite[3] | ||
46 | |||
47 | -remainder = [("0xd5", "0x108000", "32k"), # Right-end of partial-left [1] | ||
48 | - ("0xdc", "32M", "32k"), # Left-end of partial-right [2] | ||
49 | - ("0xcd", "0x3ff0000", "64k")] # patterns[3] | ||
50 | +remainder = [('0xd5', '0x108000', '32k'), # Right-end of partial-left [1] | ||
51 | + ('0xdc', '32M', '32k'), # Left-end of partial-right [2] | ||
52 | + ('0xcd', '0x3ff0000', '64k')] # patterns[3] | ||
53 | |||
54 | with iotests.FilePath('base.img') as base_img_path, \ | ||
55 | iotests.FilePath('fleece.img') as fleece_img_path, \ | ||
56 | @@ -XXX,XX +XXX,XX @@ with iotests.FilePath('base.img') as base_img_path, \ | ||
57 | log('') | ||
58 | |||
59 | assert qemu_img('create', '-f', iotests.imgfmt, base_img_path, '64M') == 0 | ||
60 | - assert qemu_img('create', '-f', "qcow2", fleece_img_path, '64M') == 0 | ||
61 | + assert qemu_img('create', '-f', 'qcow2', fleece_img_path, '64M') == 0 | ||
62 | |||
63 | for p in patterns: | ||
64 | qemu_io('-f', iotests.imgfmt, | ||
65 | @@ -XXX,XX +XXX,XX @@ with iotests.FilePath('base.img') as base_img_path, \ | ||
66 | log('--- Setting up Fleecing Graph ---') | ||
67 | log('') | ||
68 | |||
69 | - src_node = "drive0" | ||
70 | - tgt_node = "fleeceNode" | ||
71 | + src_node = 'drive0' | ||
72 | + tgt_node = 'fleeceNode' | ||
73 | |||
74 | # create tgt_node backed by src_node | ||
75 | - log(vm.qmp("blockdev-add", { | ||
76 | - "driver": "qcow2", | ||
77 | - "node-name": tgt_node, | ||
78 | - "file": { | ||
79 | - "driver": "file", | ||
80 | - "filename": fleece_img_path, | ||
81 | + log(vm.qmp('blockdev-add', { | ||
82 | + 'driver': 'qcow2', | ||
83 | + 'node-name': tgt_node, | ||
84 | + 'file': { | ||
85 | + 'driver': 'file', | ||
86 | + 'filename': fleece_img_path, | ||
87 | }, | ||
88 | - "backing": src_node, | ||
89 | + 'backing': src_node, | ||
90 | })) | ||
91 | |||
92 | # Establish COW from source to fleecing node | ||
93 | - log(vm.qmp("blockdev-backup", | ||
94 | + log(vm.qmp('blockdev-backup', | ||
95 | device=src_node, | ||
96 | target=tgt_node, | ||
97 | - sync="none")) | ||
98 | + sync='none')) | ||
99 | |||
100 | log('') | ||
101 | log('--- Setting up NBD Export ---') | ||
102 | log('') | ||
103 | |||
104 | nbd_uri = 'nbd+unix:///%s?socket=%s' % (tgt_node, nbd_sock_path) | ||
105 | - log(vm.qmp("nbd-server-start", | ||
106 | - {"addr": { "type": "unix", | ||
107 | - "data": { "path": nbd_sock_path } } })) | ||
108 | + log(vm.qmp('nbd-server-start', | ||
109 | + {'addr': { 'type': 'unix', | ||
110 | + 'data': { 'path': nbd_sock_path } } })) | ||
111 | |||
112 | - log(vm.qmp("nbd-server-add", device=tgt_node)) | ||
113 | + log(vm.qmp('nbd-server-add', device=tgt_node)) | ||
114 | |||
115 | log('') | ||
116 | log('--- Sanity Check ---') | ||
117 | log('') | ||
118 | |||
119 | for p in patterns + zeroes: | ||
120 | - cmd = "read -P%s %s %s" % p | ||
121 | + cmd = 'read -P%s %s %s' % p | ||
122 | log(cmd) | ||
123 | assert qemu_io_silent('-r', '-f', 'raw', '-c', cmd, nbd_uri) == 0 | ||
124 | |||
125 | @@ -XXX,XX +XXX,XX @@ with iotests.FilePath('base.img') as base_img_path, \ | ||
126 | log('') | ||
127 | |||
128 | for p in overwrite: | ||
129 | - cmd = "write -P%s %s %s" % p | ||
130 | + cmd = 'write -P%s %s %s' % p | ||
131 | log(cmd) | ||
132 | log(vm.hmp_qemu_io(src_node, cmd)) | ||
133 | |||
134 | @@ -XXX,XX +XXX,XX @@ with iotests.FilePath('base.img') as base_img_path, \ | ||
135 | log('') | ||
136 | |||
137 | for p in patterns + zeroes: | ||
138 | - cmd = "read -P%s %s %s" % p | ||
139 | + cmd = 'read -P%s %s %s' % p | ||
140 | log(cmd) | ||
141 | assert qemu_io_silent('-r', '-f', 'raw', '-c', cmd, nbd_uri) == 0 | ||
142 | |||
143 | @@ -XXX,XX +XXX,XX @@ with iotests.FilePath('base.img') as base_img_path, \ | ||
144 | log('') | ||
145 | |||
146 | for p in overwrite + remainder: | ||
147 | - cmd = "read -P%s %s %s" % p | ||
148 | + cmd = 'read -P%s %s %s' % p | ||
149 | log(cmd) | ||
150 | assert qemu_io_silent(base_img_path, '-c', cmd) == 0 | ||
151 | |||
152 | -- | ||
153 | 2.31.1 | ||
154 | |||
155 | diff view generated by jsdifflib |
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 1 | From: Sam Li <faithilikerun@gmail.com> |
---|---|---|---|
2 | 2 | ||
3 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 3 | Add the documentation about the example of using virtio-blk driver |
4 | Reviewed-by: Max Reitz <mreitz@redhat.com> | 4 | to pass the zoned block devices through to the guest. |
5 | Reviewed-by: John Snow <jsnow@redhat.com> | 5 | |
6 | Message-Id: <20210824083856.17408-30-vsementsov@virtuozzo.com> | 6 | Signed-off-by: Sam Li <faithilikerun@gmail.com> |
7 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | 7 | Message-id: 20230407082528.18841-6-faithilikerun@gmail.com |
8 | [Fix Sphinx indentation error by turning command-lines into | ||
9 | pre-formatted text. | ||
10 | --Stefan] | ||
11 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
8 | --- | 12 | --- |
9 | tests/qemu-iotests/iotests.py | 5 +++-- | 13 | docs/devel/zoned-storage.rst | 25 ++++++++++++++++++++++--- |
10 | 1 file changed, 3 insertions(+), 2 deletions(-) | 14 | 1 file changed, 22 insertions(+), 3 deletions(-) |
11 | 15 | ||
12 | diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py | 16 | diff --git a/docs/devel/zoned-storage.rst b/docs/devel/zoned-storage.rst |
13 | index XXXXXXX..XXXXXXX 100644 | 17 | index XXXXXXX..XXXXXXX 100644 |
14 | --- a/tests/qemu-iotests/iotests.py | 18 | --- a/docs/devel/zoned-storage.rst |
15 | +++ b/tests/qemu-iotests/iotests.py | 19 | +++ b/docs/devel/zoned-storage.rst |
16 | @@ -XXX,XX +XXX,XX @@ def resume_drive(self, drive: str) -> None: | 20 | @@ -XXX,XX +XXX,XX @@ When the BlockBackend's BlockLimits model reports a zoned storage device, users |
17 | self.hmp(f'qemu-io {drive} "remove_break bp_{drive}"') | 21 | like the virtio-blk emulation or the qemu-io-cmds.c utility can use block layer |
18 | 22 | APIs for zoned storage emulation or testing. | |
19 | def hmp_qemu_io(self, drive: str, cmd: str, | 23 | |
20 | - use_log: bool = False) -> QMPMessage: | 24 | -For example, to test zone_report on a null_blk device using qemu-io is: |
21 | + use_log: bool = False, qdev: bool = False) -> QMPMessage: | 25 | -$ path/to/qemu-io --image-opts -n driver=host_device,filename=/dev/nullb0 |
22 | """Write to a given drive using an HMP command""" | 26 | --c "zrp offset nr_zones" |
23 | - return self.hmp(f'qemu-io {drive} "{cmd}"', use_log=use_log) | 27 | +For example, to test zone_report on a null_blk device using qemu-io is:: |
24 | + d = '-d ' if qdev else '' | 28 | + |
25 | + return self.hmp(f'qemu-io {d}{drive} "{cmd}"', use_log=use_log) | 29 | + $ path/to/qemu-io --image-opts -n driver=host_device,filename=/dev/nullb0 -c "zrp offset nr_zones" |
26 | 30 | + | |
27 | def flatten_qmp_object(self, obj, output=None, basestr=''): | 31 | +To expose the host's zoned block device through virtio-blk, the command line |
28 | if output is None: | 32 | +can be (includes the -device parameter):: |
33 | + | ||
34 | + -blockdev node-name=drive0,driver=host_device,filename=/dev/nullb0,cache.direct=on \ | ||
35 | + -device virtio-blk-pci,drive=drive0 | ||
36 | + | ||
37 | +Or only use the -drive parameter:: | ||
38 | + | ||
39 | + -driver driver=host_device,file=/dev/nullb0,if=virtio,cache.direct=on | ||
40 | + | ||
41 | +Additionally, QEMU has several ways of supporting zoned storage, including: | ||
42 | +(1) Using virtio-scsi: --device scsi-block allows for the passing through of | ||
43 | +SCSI ZBC devices, enabling the attachment of ZBC or ZAC HDDs to QEMU. | ||
44 | +(2) PCI device pass-through: While NVMe ZNS emulation is available for testing | ||
45 | +purposes, it cannot yet pass through a zoned device from the host. To pass on | ||
46 | +the NVMe ZNS device to the guest, use VFIO PCI pass the entire NVMe PCI adapter | ||
47 | +through to the guest. Likewise, an HDD HBA can be passed on to QEMU all HDDs | ||
48 | +attached to the HBA. | ||
29 | -- | 49 | -- |
30 | 2.31.1 | 50 | 2.39.2 |
31 | |||
32 | diff view generated by jsdifflib |
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 1 | From: Carlos Santos <casantos@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Give a good name to test file. | 3 | It is not useful when configuring with --enable-trace-backends=nop. |
4 | 4 | ||
5 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 5 | Signed-off-by: Carlos Santos <casantos@redhat.com> |
6 | Reviewed-by: Max Reitz <mreitz@redhat.com> | 6 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> |
7 | Message-Id: <20210824083856.17408-29-vsementsov@virtuozzo.com> | 7 | Message-Id: <20230408010410.281263-1-casantos@redhat.com> |
8 | [hreitz: Adjust .gitlab-ci.d/buildtest.yml] | ||
9 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
10 | --- | 8 | --- |
11 | .gitlab-ci.d/buildtest.yml | 6 +++--- | 9 | trace/meson.build | 2 +- |
12 | tests/qemu-iotests/{222 => tests/image-fleecing} | 0 | 10 | 1 file changed, 1 insertion(+), 1 deletion(-) |
13 | tests/qemu-iotests/{222.out => tests/image-fleecing.out} | 0 | ||
14 | 3 files changed, 3 insertions(+), 3 deletions(-) | ||
15 | rename tests/qemu-iotests/{222 => tests/image-fleecing} (100%) | ||
16 | rename tests/qemu-iotests/{222.out => tests/image-fleecing.out} (100%) | ||
17 | 11 | ||
18 | diff --git a/.gitlab-ci.d/buildtest.yml b/.gitlab-ci.d/buildtest.yml | 12 | diff --git a/trace/meson.build b/trace/meson.build |
19 | index XXXXXXX..XXXXXXX 100644 | 13 | index XXXXXXX..XXXXXXX 100644 |
20 | --- a/.gitlab-ci.d/buildtest.yml | 14 | --- a/trace/meson.build |
21 | +++ b/.gitlab-ci.d/buildtest.yml | 15 | +++ b/trace/meson.build |
22 | @@ -XXX,XX +XXX,XX @@ build-tcg-disabled: | 16 | @@ -XXX,XX +XXX,XX @@ trace_events_all = custom_target('trace-events-all', |
23 | - cd tests/qemu-iotests/ | 17 | input: trace_events_files, |
24 | - ./check -raw 001 002 003 004 005 008 009 010 011 012 021 025 032 033 048 | 18 | command: [ 'cat', '@INPUT@' ], |
25 | 052 063 077 086 101 104 106 113 148 150 151 152 157 159 160 163 | 19 | capture: true, |
26 | - 170 171 183 184 192 194 208 221 222 226 227 236 253 277 | 20 | - install: true, |
27 | + 170 171 183 184 192 194 208 221 226 227 236 253 277 image-fleecing | 21 | + install: get_option('trace_backends') != [ 'nop' ], |
28 | - ./check -qcow2 028 051 056 057 058 065 068 082 085 091 095 096 102 122 | 22 | install_dir: qemu_datadir) |
29 | 124 132 139 142 144 145 151 152 155 157 165 194 196 200 202 | 23 | |
30 | - 208 209 216 218 222 227 234 246 247 248 250 254 255 257 258 | 24 | if 'ust' in get_option('trace_backends') |
31 | - 260 261 262 263 264 270 272 273 277 279 | ||
32 | + 208 209 216 218 227 234 246 247 248 250 254 255 257 258 | ||
33 | + 260 261 262 263 264 270 272 273 277 279 image-fleecing | ||
34 | |||
35 | build-user: | ||
36 | extends: .native_build_job_template | ||
37 | diff --git a/tests/qemu-iotests/222 b/tests/qemu-iotests/tests/image-fleecing | ||
38 | similarity index 100% | ||
39 | rename from tests/qemu-iotests/222 | ||
40 | rename to tests/qemu-iotests/tests/image-fleecing | ||
41 | diff --git a/tests/qemu-iotests/222.out b/tests/qemu-iotests/tests/image-fleecing.out | ||
42 | similarity index 100% | ||
43 | rename from tests/qemu-iotests/222.out | ||
44 | rename to tests/qemu-iotests/tests/image-fleecing.out | ||
45 | -- | 25 | -- |
46 | 2.31.1 | 26 | 2.39.2 |
47 | |||
48 | diff view generated by jsdifflib |