1
The following changes since commit bae31bfa48b9caecee25da3d5333901a126a06b4:
1
The following changes since commit 813bac3d8d70d85cb7835f7945eb9eed84c2d8d0:
2
2
3
Merge remote-tracking branch 'remotes/kraxel/tags/audio-20200619-pull-request' into staging (2020-06-19 22:56:59 +0100)
3
Merge tag '2023q3-bsd-user-pull-request' of https://gitlab.com/bsdimp/qemu into staging (2023-08-29 08:58:00 -0400)
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-2020-06-22
7
https://gitlab.com/stefanha/qemu.git tags/block-pull-request
8
8
9
for you to fetch changes up to 74c55e4142a7bb835c38d3770c74210cbb1e4fab:
9
for you to fetch changes up to 3f5f2285bfcdd855508a55da7875fb92de1a6ed0:
10
10
11
iotests: don't test qcow2.py inside 291 (2020-06-22 16:05:23 +0200)
11
tests/qemu-iotests/197: add testcase for CoR with subclusters (2023-08-29 13:19:56 -0400)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
Block patches:
14
Pull request
15
- Support modifying a LUKS-encrypted image's keyslots
15
16
- iotest fixes
16
v2:
17
- Fix authorship information lost by the mailing list for Andrey Drobyshev
17
18
18
----------------------------------------------------------------
19
----------------------------------------------------------------
19
Max Reitz (1):
20
iotests: Make _filter_img_create more active
21
20
22
Maxim Levitsky (14):
21
Andrey Drobyshev (3):
23
iotests: filter few more luks specific create options
22
block: add subcluster_size field to BlockDriverInfo
24
qcrypto/core: add generic infrastructure for crypto options amendment
23
block/io: align requests to subcluster_size
25
qcrypto/luks: implement encryption key management
24
tests/qemu-iotests/197: add testcase for CoR with subclusters
26
block/amend: add 'force' option
27
block/amend: separate amend and create options for qemu-img
28
block/amend: refactor qcow2 amend options
29
block/crypto: rename two functions
30
block/crypto: implement the encryption key management
31
block/qcow2: extend qemu-img amend interface with crypto options
32
iotests: qemu-img tests for luks key management
33
block/core: add generic infrastructure for x-blockdev-amend qmp
34
command
35
block/crypto: implement blockdev-amend
36
block/qcow2: implement blockdev-amend
37
iotests: add tests for blockdev-amend
38
25
39
Philippe Mathieu-Daudé (1):
26
Fabiano Rosas (1):
40
iotests: Fix 051 output after qdev_init_nofail() removal
27
block-migration: Ensure we don't crash during migration cleanup
41
28
42
Vladimir Sementsov-Ogievskiy (2):
29
Jeuk Kim (4):
43
block/block-copy: block_copy_dirty_clusters: fix failure check
30
hw/ufs: Initial commit for emulated Universal-Flash-Storage
44
iotests: don't test qcow2.py inside 291
31
hw/ufs: Support for Query Transfer Requests
32
hw/ufs: Support for UFS logical unit
33
tests/qtest: Introduce tests for UFS
45
34
46
docs/tools/qemu-img.rst | 5 +-
35
MAINTAINERS | 7 +
47
qapi/block-core.json | 68 +++++
36
docs/specs/pci-ids.rst | 2 +
48
qapi/crypto.json | 73 +++++-
37
meson.build | 1 +
49
qapi/job.json | 4 +-
38
hw/ufs/trace.h | 1 +
50
block/crypto.h | 37 +++
39
hw/ufs/ufs.h | 131 +++
51
crypto/blockpriv.h | 8 +
40
include/block/block-common.h | 5 +
52
include/block/block.h | 1 +
41
include/block/block-io.h | 8 +-
53
include/block/block_int.h | 24 +-
42
include/block/ufs.h | 1090 +++++++++++++++++++++++++
54
include/crypto/block.h | 22 ++
43
include/hw/pci/pci.h | 1 +
55
block.c | 4 +-
44
include/hw/pci/pci_ids.h | 1 +
56
block/amend.c | 113 +++++++++
45
include/scsi/constants.h | 1 +
57
block/block-copy.c | 4 +-
46
block.c | 7 +
58
block/crypto.c | 206 +++++++++++++--
47
block/io.c | 50 +-
59
block/qcow2.c | 332 +++++++++++++-----------
48
block/mirror.c | 8 +-
60
crypto/block-luks.c | 416 ++++++++++++++++++++++++++++++-
49
block/qcow2.c | 1 +
61
crypto/block.c | 29 +++
50
hw/ufs/lu.c | 1445 ++++++++++++++++++++++++++++++++
62
qemu-img.c | 44 +++-
51
hw/ufs/ufs.c | 1494 ++++++++++++++++++++++++++++++++++
63
block/Makefile.objs | 2 +-
52
migration/block.c | 11 +-
64
qemu-img-cmds.hx | 4 +-
53
tests/qtest/ufs-test.c | 584 +++++++++++++
65
tests/qemu-iotests/049.out | 102 ++++----
54
hw/Kconfig | 1 +
66
tests/qemu-iotests/051.pc.out | 4 +-
55
hw/meson.build | 1 +
67
tests/qemu-iotests/061.out | 12 +-
56
hw/ufs/Kconfig | 4 +
68
tests/qemu-iotests/082.out | 185 ++++----------
57
hw/ufs/meson.build | 1 +
69
tests/qemu-iotests/085.out | 38 +--
58
hw/ufs/trace-events | 58 ++
70
tests/qemu-iotests/087.out | 6 +-
59
tests/qemu-iotests/197 | 29 +
71
tests/qemu-iotests/112.out | 2 +-
60
tests/qemu-iotests/197.out | 24 +
72
tests/qemu-iotests/134.out | 2 +-
61
tests/qtest/meson.build | 1 +
73
tests/qemu-iotests/141 | 2 +-
62
27 files changed, 4932 insertions(+), 35 deletions(-)
74
tests/qemu-iotests/144.out | 4 +-
63
create mode 100644 hw/ufs/trace.h
75
tests/qemu-iotests/153 | 9 +-
64
create mode 100644 hw/ufs/ufs.h
76
tests/qemu-iotests/158.out | 4 +-
65
create mode 100644 include/block/ufs.h
77
tests/qemu-iotests/182.out | 2 +-
66
create mode 100644 hw/ufs/lu.c
78
tests/qemu-iotests/185.out | 8 +-
67
create mode 100644 hw/ufs/ufs.c
79
tests/qemu-iotests/188.out | 2 +-
68
create mode 100644 tests/qtest/ufs-test.c
80
tests/qemu-iotests/189.out | 4 +-
69
create mode 100644 hw/ufs/Kconfig
81
tests/qemu-iotests/198.out | 4 +-
70
create mode 100644 hw/ufs/meson.build
82
tests/qemu-iotests/255.out | 8 +-
71
create mode 100644 hw/ufs/trace-events
83
tests/qemu-iotests/263.out | 4 +-
84
tests/qemu-iotests/274.out | 46 ++--
85
tests/qemu-iotests/280.out | 2 +-
86
tests/qemu-iotests/284.out | 6 +-
87
tests/qemu-iotests/291 | 4 -
88
tests/qemu-iotests/291.out | 33 ---
89
tests/qemu-iotests/293 | 207 +++++++++++++++
90
tests/qemu-iotests/293.out | 99 ++++++++
91
tests/qemu-iotests/294 | 90 +++++++
92
tests/qemu-iotests/294.out | 30 +++
93
tests/qemu-iotests/295 | 279 +++++++++++++++++++++
94
tests/qemu-iotests/295.out | 40 +++
95
tests/qemu-iotests/296 | 234 +++++++++++++++++
96
tests/qemu-iotests/296.out | 33 +++
97
tests/qemu-iotests/common.filter | 93 +++++--
98
tests/qemu-iotests/group | 4 +
99
53 files changed, 2482 insertions(+), 516 deletions(-)
100
create mode 100644 block/amend.c
101
create mode 100755 tests/qemu-iotests/293
102
create mode 100644 tests/qemu-iotests/293.out
103
create mode 100755 tests/qemu-iotests/294
104
create mode 100644 tests/qemu-iotests/294.out
105
create mode 100755 tests/qemu-iotests/295
106
create mode 100644 tests/qemu-iotests/295.out
107
create mode 100755 tests/qemu-iotests/296
108
create mode 100644 tests/qemu-iotests/296.out
109
72
110
--
73
--
111
2.26.2
74
2.41.0
112
113
diff view generated by jsdifflib
Deleted patch
1
Right now, _filter_img_create just filters out everything that looks
2
format-dependent, and applies some filename filters. That means that we
3
have to add another filter line every time some format gets a new
4
creation option. This can be avoided by instead discarding everything
5
and just keeping what we know is format-independent (format, size,
6
backing file, encryption information[1], preallocation) or just
7
interesting to have in the reference output (external data file path).
8
1
9
Furthermore, we probably want to sort these options. Format drivers are
10
not required to define them in any specific order, so the output is
11
effectively random (although this has never bothered us until now). We
12
need a specific order for our reference outputs, though. Unfortunately,
13
just using a plain "sort" would change a lot of existing reference
14
outputs, so we have to pre-filter the option keys to keep our existing
15
order (fmt, size, backing*, data, encryption info, preallocation).
16
17
Finally, this makes it difficult for _filter_img_create to automagically
18
work for QMP output. Thus, this patch adds a separate
19
_filter_img_create_for_qmp function that echos every line verbatim that
20
does not start with "Formatting", and pipes those "Formatting" lines to
21
_filter_img_create.
22
23
[1] Actually, the only thing that is really important is whether
24
encryption is enabled or not. A patch by Maxim thus removes all
25
other "encrypt.*" options from the output:
26
https://lists.nongnu.org/archive/html/qemu-block/2020-06/msg00339.html
27
But that patch needs to come later so we can get away with changing
28
as few reference outputs in this patch here as possible.
29
30
Signed-off-by: Max Reitz <mreitz@redhat.com>
31
Message-Id: <20200618150628.2169239-2-mreitz@redhat.com>
32
---
33
tests/qemu-iotests/112.out | 2 +-
34
tests/qemu-iotests/141 | 2 +-
35
tests/qemu-iotests/153 | 9 ++-
36
tests/qemu-iotests/common.filter | 96 ++++++++++++++++++++++++--------
37
4 files changed, 78 insertions(+), 31 deletions(-)
38
39
diff --git a/tests/qemu-iotests/112.out b/tests/qemu-iotests/112.out
40
index XXXXXXX..XXXXXXX 100644
41
--- a/tests/qemu-iotests/112.out
42
+++ b/tests/qemu-iotests/112.out
43
@@ -XXX,XX +XXX,XX @@ QA output created by 112
44
qemu-img: TEST_DIR/t.IMGFMT: Refcount width must be a power of two and may not exceed 64 bits
45
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
46
qemu-img: TEST_DIR/t.IMGFMT: Refcount width must be a power of two and may not exceed 64 bits
47
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 refcount_bits=-1
48
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
49
qemu-img: TEST_DIR/t.IMGFMT: Refcount width must be a power of two and may not exceed 64 bits
50
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
51
qemu-img: TEST_DIR/t.IMGFMT: Refcount width must be a power of two and may not exceed 64 bits
52
diff --git a/tests/qemu-iotests/141 b/tests/qemu-iotests/141
53
index XXXXXXX..XXXXXXX 100755
54
--- a/tests/qemu-iotests/141
55
+++ b/tests/qemu-iotests/141
56
@@ -XXX,XX +XXX,XX @@ test_blockjob()
57
_send_qemu_cmd $QEMU_HANDLE \
58
"$1" \
59
"$2" \
60
- | _filter_img_create | _filter_qmp_empty_return
61
+ | _filter_img_create_in_qmp | _filter_qmp_empty_return
62
63
# We want this to return an error because the block job is still running
64
_send_qemu_cmd $QEMU_HANDLE \
65
diff --git a/tests/qemu-iotests/153 b/tests/qemu-iotests/153
66
index XXXXXXX..XXXXXXX 100755
67
--- a/tests/qemu-iotests/153
68
+++ b/tests/qemu-iotests/153
69
@@ -XXX,XX +XXX,XX @@ done
70
71
echo
72
echo "== Creating ${TEST_IMG}.[abc] ==" | _filter_testdir
73
-(
74
- $QEMU_IMG create -f qcow2 "${TEST_IMG}.a" -b "${TEST_IMG}"
75
- $QEMU_IMG create -f qcow2 "${TEST_IMG}.b" -b "${TEST_IMG}"
76
- $QEMU_IMG create -f qcow2 "${TEST_IMG}.c" -b "${TEST_IMG}.b"
77
-) | _filter_img_create
78
+$QEMU_IMG create -f qcow2 "${TEST_IMG}.a" -b "${TEST_IMG}" | _filter_img_create
79
+$QEMU_IMG create -f qcow2 "${TEST_IMG}.b" -b "${TEST_IMG}" | _filter_img_create
80
+$QEMU_IMG create -f qcow2 "${TEST_IMG}.c" -b "${TEST_IMG}.b" \
81
+ | _filter_img_create
82
83
echo
84
echo "== Two devices sharing the same file in backing chain =="
85
diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter
86
index XXXXXXX..XXXXXXX 100644
87
--- a/tests/qemu-iotests/common.filter
88
+++ b/tests/qemu-iotests/common.filter
89
@@ -XXX,XX +XXX,XX @@ _filter_actual_image_size()
90
# replace driver-specific options in the "Formatting..." line
91
_filter_img_create()
92
{
93
- data_file_filter=()
94
- if data_file=$(_get_data_file "$TEST_IMG"); then
95
- data_file_filter=(-e "s# data_file=$data_file##")
96
+ # Split the line into the pre-options part ($filename_part, which
97
+ # precedes ", fmt=") and the options part ($options, which starts
98
+ # with "fmt=")
99
+ readarray -td '' formatting_line < <(sed -e 's/, fmt=/\x0/')
100
+
101
+ filename_part=${formatting_line[0]}
102
+ if [ -n "${formatting_line[1]}" ]; then
103
+ options="fmt=${formatting_line[1]}"
104
+ else
105
+ options=''
106
+ fi
107
+
108
+ # Set grep_data_file to '\|data_file' to keep it; make it empty
109
+ # to drop it.
110
+ # We want to drop it if it is part of the global $IMGOPTS, and we
111
+ # want to keep it otherwise (if the test specifically wants to
112
+ # test data files).
113
+ grep_data_file='\|data_file'
114
+ if _get_data_file "$TEST_IMG" > /dev/null; then
115
+ grep_data_file=''
116
fi
117
118
- $SED "${data_file_filter[@]}" \
119
+ filename_filters=(
120
-e "s#$REMOTE_TEST_DIR#TEST_DIR#g" \
121
-e "s#$IMGPROTO:$TEST_DIR#TEST_DIR#g" \
122
-e "s#$TEST_DIR#TEST_DIR#g" \
123
-e "s#$SOCK_DIR#SOCK_DIR#g" \
124
-e "s#$IMGFMT#IMGFMT#g" \
125
-e 's#nbd:127.0.0.1:[0-9]\\+#TEST_DIR/t.IMGFMT#g' \
126
- -e 's#nbd+unix:///\??socket=SOCK_DIR/nbd#TEST_DIR/t.IMGFMT#g' \
127
- -e "s# encryption=off##g" \
128
- -e "s# cluster_size=[0-9]\\+##g" \
129
- -e "s# table_size=[0-9]\\+##g" \
130
- -e "s# compat=[^ ]*##g" \
131
- -e "s# compat6=\\(on\\|off\\)##g" \
132
- -e "s# static=\\(on\\|off\\)##g" \
133
- -e "s# zeroed_grain=\\(on\\|off\\)##g" \
134
- -e "s# subformat=[^ ]*##g" \
135
- -e "s# adapter_type=[^ ]*##g" \
136
- -e "s# hwversion=[^ ]*##g" \
137
- -e "s# lazy_refcounts=\\(on\\|off\\)##g" \
138
- -e "s# block_size=[0-9]\\+##g" \
139
- -e "s# block_state_zero=\\(on\\|off\\)##g" \
140
- -e "s# log_size=[0-9]\\+##g" \
141
- -e "s# refcount_bits=[0-9]\\+##g" \
142
- -e "s# key-secret=[a-zA-Z0-9]\\+##g" \
143
- -e "s# iter-time=[0-9]\\+##g" \
144
- -e "s# force_size=\\(on\\|off\\)##g" \
145
- -e "s# compression_type=[a-zA-Z0-9]\\+##g"
146
+ -e 's#nbd+unix:///\??socket=SOCK_DIR/nbd#TEST_DIR/t.IMGFMT#g'
147
+ )
148
+
149
+ filename_part=$(echo "$filename_part" | $SED "${filename_filters[@]}")
150
+
151
+ # Break the option line before each option (preserving pre-existing
152
+ # line breaks by replacing them by \0 and restoring them at the end),
153
+ # then filter out the options we want to keep and sort them according
154
+ # to some order that all block drivers used at the time of writing
155
+ # this function.
156
+ options=$(
157
+ echo "$options" \
158
+ | tr '\n' '\0' \
159
+ | $SED -e 's/\x0$//' -e 's/ \([a-z0-9_.-]*\)=/\n\1=/g' \
160
+ | grep -ae "^\(fmt\\|size\\|backing\\|preallocation\\|encrypt$grep_data_file\\)" \
161
+ | $SED "${filename_filters[@]}" \
162
+ -e 's/^\(fmt\)/0-\1/' \
163
+ -e 's/^\(size\)/1-\1/' \
164
+ -e 's/^\(backing\)/2-\1/' \
165
+ -e 's/^\(data_file\)/3-\1/' \
166
+ -e 's/^\(encryption\)/4-\1/' \
167
+ -e 's/^\(encrypt\.format\)/5-\1/' \
168
+ -e 's/^\(encrypt\.key-secret\)/6-\1/' \
169
+ -e 's/^\(encrypt\.iter-time\)/7-\1/' \
170
+ -e 's/^\(preallocation\)/8-\1/' \
171
+ | sort \
172
+ | $SED -e 's/^[0-9]-//' \
173
+ | tr '\n\0' ' \n' \
174
+ | $SED -e 's/^ *$//' -e 's/ *$//'
175
+ )
176
+
177
+ if [ -n "$options" ]; then
178
+ echo "$filename_part, $options"
179
+ elif [ -n "$filename_part" ]; then
180
+ echo "$filename_part"
181
+ fi
182
+}
183
+
184
+# Filter the "Formatting..." line in QMP output (leaving the QMP output
185
+# untouched)
186
+# (In contrast to _filter_img_create(), this function does not support
187
+# multi-line Formatting output)
188
+_filter_img_create_in_qmp()
189
+{
190
+ while read -r line; do
191
+ if echo "$line" | grep -q '^Formatting'; then
192
+ echo "$line" | _filter_img_create
193
+ else
194
+ echo "$line"
195
+ fi
196
+ done
197
}
198
199
_filter_img_create_size()
200
--
201
2.26.2
202
203
diff view generated by jsdifflib
Deleted patch
1
From: Maxim Levitsky <mlevitsk@redhat.com>
2
1
3
This allows more tests to be able to have same output on both qcow2 luks encrypted images
4
and raw luks images
5
6
Signed-off-by: Maxim Levitsky <mlevitsk@redhat.com>
7
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
9
Message-Id: <20200618150628.2169239-3-mreitz@redhat.com>
10
---
11
tests/qemu-iotests/087.out | 6 +++---
12
tests/qemu-iotests/134.out | 2 +-
13
tests/qemu-iotests/158.out | 4 ++--
14
tests/qemu-iotests/188.out | 2 +-
15
tests/qemu-iotests/189.out | 4 ++--
16
tests/qemu-iotests/198.out | 4 ++--
17
tests/qemu-iotests/263.out | 4 ++--
18
tests/qemu-iotests/284.out | 6 +++---
19
tests/qemu-iotests/common.filter | 5 +----
20
9 files changed, 17 insertions(+), 20 deletions(-)
21
22
diff --git a/tests/qemu-iotests/087.out b/tests/qemu-iotests/087.out
23
index XXXXXXX..XXXXXXX 100644
24
--- a/tests/qemu-iotests/087.out
25
+++ b/tests/qemu-iotests/087.out
26
@@ -XXX,XX +XXX,XX @@ QMP_VERSION
27
28
=== Encrypted image QCow ===
29
30
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encryption=on encrypt.key-secret=sec0
31
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encryption=on
32
Testing:
33
QMP_VERSION
34
{"return": {}}
35
@@ -XXX,XX +XXX,XX @@ QMP_VERSION
36
37
=== Encrypted image LUKS ===
38
39
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encrypt.format=luks encrypt.key-secret=sec0
40
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
41
Testing:
42
QMP_VERSION
43
{"return": {}}
44
@@ -XXX,XX +XXX,XX @@ QMP_VERSION
45
46
=== Missing driver ===
47
48
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encryption=on encrypt.key-secret=sec0
49
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encryption=on
50
Testing: -S
51
QMP_VERSION
52
{"return": {}}
53
diff --git a/tests/qemu-iotests/134.out b/tests/qemu-iotests/134.out
54
index XXXXXXX..XXXXXXX 100644
55
--- a/tests/qemu-iotests/134.out
56
+++ b/tests/qemu-iotests/134.out
57
@@ -XXX,XX +XXX,XX @@
58
QA output created by 134
59
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encryption=on encrypt.key-secret=sec0
60
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encryption=on
61
62
== reading whole image ==
63
read 134217728/134217728 bytes at offset 0
64
diff --git a/tests/qemu-iotests/158.out b/tests/qemu-iotests/158.out
65
index XXXXXXX..XXXXXXX 100644
66
--- a/tests/qemu-iotests/158.out
67
+++ b/tests/qemu-iotests/158.out
68
@@ -XXX,XX +XXX,XX @@
69
QA output created by 158
70
== create base ==
71
-Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728 encryption=on encrypt.key-secret=sec0
72
+Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728 encryption=on
73
74
== writing whole image ==
75
wrote 134217728/134217728 bytes at offset 0
76
@@ -XXX,XX +XXX,XX @@ wrote 134217728/134217728 bytes at offset 0
77
read 134217728/134217728 bytes at offset 0
78
128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
79
== create overlay ==
80
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.base encryption=on encrypt.key-secret=sec0
81
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.base encryption=on
82
83
== writing part of a cluster ==
84
wrote 1024/1024 bytes at offset 0
85
diff --git a/tests/qemu-iotests/188.out b/tests/qemu-iotests/188.out
86
index XXXXXXX..XXXXXXX 100644
87
--- a/tests/qemu-iotests/188.out
88
+++ b/tests/qemu-iotests/188.out
89
@@ -XXX,XX +XXX,XX @@
90
QA output created by 188
91
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=16777216 encrypt.format=luks encrypt.key-secret=sec0 encrypt.iter-time=10
92
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=16777216
93
94
== reading whole image ==
95
read 16777216/16777216 bytes at offset 0
96
diff --git a/tests/qemu-iotests/189.out b/tests/qemu-iotests/189.out
97
index XXXXXXX..XXXXXXX 100644
98
--- a/tests/qemu-iotests/189.out
99
+++ b/tests/qemu-iotests/189.out
100
@@ -XXX,XX +XXX,XX @@
101
QA output created by 189
102
== create base ==
103
-Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=16777216 encrypt.format=luks encrypt.key-secret=sec0 encrypt.iter-time=10
104
+Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=16777216
105
106
== writing whole image ==
107
wrote 16777216/16777216 bytes at offset 0
108
@@ -XXX,XX +XXX,XX @@ wrote 16777216/16777216 bytes at offset 0
109
read 16777216/16777216 bytes at offset 0
110
16 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
111
== create overlay ==
112
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=16777216 backing_file=TEST_DIR/t.IMGFMT.base encrypt.format=luks encrypt.key-secret=sec1 encrypt.iter-time=10
113
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=16777216 backing_file=TEST_DIR/t.IMGFMT.base
114
115
== writing part of a cluster ==
116
wrote 1024/1024 bytes at offset 0
117
diff --git a/tests/qemu-iotests/198.out b/tests/qemu-iotests/198.out
118
index XXXXXXX..XXXXXXX 100644
119
--- a/tests/qemu-iotests/198.out
120
+++ b/tests/qemu-iotests/198.out
121
@@ -XXX,XX +XXX,XX @@
122
QA output created by 198
123
== create base ==
124
-Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=16777216 encrypt.format=luks encrypt.key-secret=sec0 encrypt.iter-time=10
125
+Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=16777216
126
127
== writing whole image base ==
128
wrote 16777216/16777216 bytes at offset 0
129
16 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
130
== create overlay ==
131
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=16777216 backing_file=TEST_DIR/t.IMGFMT.base encrypt.format=luks encrypt.key-secret=sec1 encrypt.iter-time=10
132
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=16777216 backing_file=TEST_DIR/t.IMGFMT.base
133
134
== writing whole image layer ==
135
wrote 16777216/16777216 bytes at offset 0
136
diff --git a/tests/qemu-iotests/263.out b/tests/qemu-iotests/263.out
137
index XXXXXXX..XXXXXXX 100644
138
--- a/tests/qemu-iotests/263.out
139
+++ b/tests/qemu-iotests/263.out
140
@@ -XXX,XX +XXX,XX @@ QA output created by 263
141
142
testing LUKS qcow2 encryption
143
144
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 encrypt.format=luks encrypt.key-secret=sec0 encrypt.iter-time=10
145
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576
146
== reading the whole image ==
147
read 1048576/1048576 bytes at offset 0
148
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
149
@@ -XXX,XX +XXX,XX @@ read 982528/982528 bytes at offset 66048
150
151
testing legacy AES qcow2 encryption
152
153
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 encrypt.format=aes encrypt.key-secret=sec0
154
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576
155
== reading the whole image ==
156
read 1048576/1048576 bytes at offset 0
157
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
158
diff --git a/tests/qemu-iotests/284.out b/tests/qemu-iotests/284.out
159
index XXXXXXX..XXXXXXX 100644
160
--- a/tests/qemu-iotests/284.out
161
+++ b/tests/qemu-iotests/284.out
162
@@ -XXX,XX +XXX,XX @@ QA output created by 284
163
164
testing LUKS qcow2 encryption
165
166
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 encrypt.format=luks encrypt.key-secret=sec0 encrypt.iter-time=10
167
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576
168
169
== cluster size 512
170
== checking image refcounts ==
171
@@ -XXX,XX +XXX,XX @@ wrote 1/1 bytes at offset 512
172
173
== rechecking image refcounts ==
174
No errors were found on the image.
175
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 encrypt.format=luks encrypt.key-secret=sec0 encrypt.iter-time=10
176
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576
177
178
== cluster size 2048
179
== checking image refcounts ==
180
@@ -XXX,XX +XXX,XX @@ wrote 1/1 bytes at offset 2048
181
182
== rechecking image refcounts ==
183
No errors were found on the image.
184
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 encrypt.format=luks encrypt.key-secret=sec0 encrypt.iter-time=10
185
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576
186
187
== cluster size 32768
188
== checking image refcounts ==
189
diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter
190
index XXXXXXX..XXXXXXX 100644
191
--- a/tests/qemu-iotests/common.filter
192
+++ b/tests/qemu-iotests/common.filter
193
@@ -XXX,XX +XXX,XX @@ _filter_img_create()
194
echo "$options" \
195
| tr '\n' '\0' \
196
| $SED -e 's/\x0$//' -e 's/ \([a-z0-9_.-]*\)=/\n\1=/g' \
197
- | grep -ae "^\(fmt\\|size\\|backing\\|preallocation\\|encrypt$grep_data_file\\)" \
198
+ | grep -ae "^\(fmt\\|size\\|backing\\|preallocation\\|encryption$grep_data_file\\)" \
199
| $SED "${filename_filters[@]}" \
200
-e 's/^\(fmt\)/0-\1/' \
201
-e 's/^\(size\)/1-\1/' \
202
-e 's/^\(backing\)/2-\1/' \
203
-e 's/^\(data_file\)/3-\1/' \
204
-e 's/^\(encryption\)/4-\1/' \
205
- -e 's/^\(encrypt\.format\)/5-\1/' \
206
- -e 's/^\(encrypt\.key-secret\)/6-\1/' \
207
- -e 's/^\(encrypt\.iter-time\)/7-\1/' \
208
-e 's/^\(preallocation\)/8-\1/' \
209
| sort \
210
| $SED -e 's/^[0-9]-//' \
211
--
212
2.26.2
213
214
diff view generated by jsdifflib
Deleted patch
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
1
3
ret may be > 0 on success path at this point. Fix assertion, which may
4
crash currently.
5
6
Fixes: 4ce5dd3e9b5ee0fac18625860eb3727399ee965e
7
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
8
Message-Id: <20200526181347.489557-1-vsementsov@virtuozzo.com>
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
---
11
block/block-copy.c | 4 +++-
12
1 file changed, 3 insertions(+), 1 deletion(-)
13
14
diff --git a/block/block-copy.c b/block/block-copy.c
15
index XXXXXXX..XXXXXXX 100644
16
--- a/block/block-copy.c
17
+++ b/block/block-copy.c
18
@@ -XXX,XX +XXX,XX @@ out:
19
* block_copy_task_run. If it fails, it means some task already failed
20
* for real reason, let's return first failure.
21
* Still, assert that we don't rewrite failure by success.
22
+ *
23
+ * Note: ret may be positive here because of block-status result.
24
*/
25
- assert(ret == 0 || aio_task_pool_status(aio) < 0);
26
+ assert(ret >= 0 || aio_task_pool_status(aio) < 0);
27
ret = aio_task_pool_status(aio);
28
29
aio_task_pool_free(aio);
30
--
31
2.26.2
32
33
diff view generated by jsdifflib
Deleted patch
1
From: Maxim Levitsky <mlevitsk@redhat.com>
2
1
3
This will be used first to implement luks keyslot management.
4
5
block_crypto_amend_opts_init will be used to convert
6
qemu-img cmdline to QCryptoBlockAmendOptions
7
8
Signed-off-by: Maxim Levitsky <mlevitsk@redhat.com>
9
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
10
Message-Id: <20200608094030.670121-2-mlevitsk@redhat.com>
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
12
---
13
qapi/crypto.json | 16 ++++++++++++++++
14
block/crypto.h | 3 +++
15
crypto/blockpriv.h | 8 ++++++++
16
include/crypto/block.h | 22 ++++++++++++++++++++++
17
block/crypto.c | 17 +++++++++++++++++
18
crypto/block.c | 29 +++++++++++++++++++++++++++++
19
6 files changed, 95 insertions(+)
20
21
diff --git a/qapi/crypto.json b/qapi/crypto.json
22
index XXXXXXX..XXXXXXX 100644
23
--- a/qapi/crypto.json
24
+++ b/qapi/crypto.json
25
@@ -XXX,XX +XXX,XX @@
26
'base': 'QCryptoBlockInfoBase',
27
'discriminator': 'format',
28
'data': { 'luks': 'QCryptoBlockInfoLUKS' } }
29
+
30
+
31
+
32
+##
33
+# @QCryptoBlockAmendOptions:
34
+#
35
+# The options that are available for all encryption formats
36
+# when amending encryption settings
37
+#
38
+# Since: 5.1
39
+##
40
+{ 'union': 'QCryptoBlockAmendOptions',
41
+ 'base': 'QCryptoBlockOptionsBase',
42
+ 'discriminator': 'format',
43
+ 'data': {
44
+ } }
45
diff --git a/block/crypto.h b/block/crypto.h
46
index XXXXXXX..XXXXXXX 100644
47
--- a/block/crypto.h
48
+++ b/block/crypto.h
49
@@ -XXX,XX +XXX,XX @@
50
QCryptoBlockCreateOptions *
51
block_crypto_create_opts_init(QDict *opts, Error **errp);
52
53
+QCryptoBlockAmendOptions *
54
+block_crypto_amend_opts_init(QDict *opts, Error **errp);
55
+
56
QCryptoBlockOpenOptions *
57
block_crypto_open_opts_init(QDict *opts, Error **errp);
58
59
diff --git a/crypto/blockpriv.h b/crypto/blockpriv.h
60
index XXXXXXX..XXXXXXX 100644
61
--- a/crypto/blockpriv.h
62
+++ b/crypto/blockpriv.h
63
@@ -XXX,XX +XXX,XX @@ struct QCryptoBlockDriver {
64
void *opaque,
65
Error **errp);
66
67
+ int (*amend)(QCryptoBlock *block,
68
+ QCryptoBlockReadFunc readfunc,
69
+ QCryptoBlockWriteFunc writefunc,
70
+ void *opaque,
71
+ QCryptoBlockAmendOptions *options,
72
+ bool force,
73
+ Error **errp);
74
+
75
int (*get_info)(QCryptoBlock *block,
76
QCryptoBlockInfo *info,
77
Error **errp);
78
diff --git a/include/crypto/block.h b/include/crypto/block.h
79
index XXXXXXX..XXXXXXX 100644
80
--- a/include/crypto/block.h
81
+++ b/include/crypto/block.h
82
@@ -XXX,XX +XXX,XX @@ QCryptoBlock *qcrypto_block_create(QCryptoBlockCreateOptions *options,
83
void *opaque,
84
Error **errp);
85
86
+/**
87
+ * qcrypto_block_amend_options:
88
+ * @block: the block encryption object
89
+ *
90
+ * @readfunc: callback for reading data from the volume header
91
+ * @writefunc: callback for writing data to the volume header
92
+ * @opaque: data to pass to @readfunc and @writefunc
93
+ * @options: the new/amended encryption options
94
+ * @force: hint for the driver to allow unsafe operation
95
+ * @errp: error pointer
96
+ *
97
+ * Changes the crypto options of the encryption format
98
+ *
99
+ */
100
+int qcrypto_block_amend_options(QCryptoBlock *block,
101
+ QCryptoBlockReadFunc readfunc,
102
+ QCryptoBlockWriteFunc writefunc,
103
+ void *opaque,
104
+ QCryptoBlockAmendOptions *options,
105
+ bool force,
106
+ Error **errp);
107
+
108
109
/**
110
* qcrypto_block_calculate_payload_offset:
111
diff --git a/block/crypto.c b/block/crypto.c
112
index XXXXXXX..XXXXXXX 100644
113
--- a/block/crypto.c
114
+++ b/block/crypto.c
115
@@ -XXX,XX +XXX,XX @@ block_crypto_create_opts_init(QDict *opts, Error **errp)
116
return ret;
117
}
118
119
+QCryptoBlockAmendOptions *
120
+block_crypto_amend_opts_init(QDict *opts, Error **errp)
121
+{
122
+ Visitor *v;
123
+ QCryptoBlockAmendOptions *ret;
124
+
125
+ v = qobject_input_visitor_new_flat_confused(opts, errp);
126
+ if (!v) {
127
+ return NULL;
128
+ }
129
+
130
+ visit_type_QCryptoBlockAmendOptions(v, NULL, &ret, errp);
131
+
132
+ visit_free(v);
133
+ return ret;
134
+}
135
+
136
137
static int block_crypto_open_generic(QCryptoBlockFormat format,
138
QemuOptsList *opts_spec,
139
diff --git a/crypto/block.c b/crypto/block.c
140
index XXXXXXX..XXXXXXX 100644
141
--- a/crypto/block.c
142
+++ b/crypto/block.c
143
@@ -XXX,XX +XXX,XX @@ qcrypto_block_calculate_payload_offset(QCryptoBlockCreateOptions *create_opts,
144
return crypto != NULL;
145
}
146
147
+int qcrypto_block_amend_options(QCryptoBlock *block,
148
+ QCryptoBlockReadFunc readfunc,
149
+ QCryptoBlockWriteFunc writefunc,
150
+ void *opaque,
151
+ QCryptoBlockAmendOptions *options,
152
+ bool force,
153
+ Error **errp)
154
+{
155
+ if (options->format != block->format) {
156
+ error_setg(errp,
157
+ "Cannot amend encryption format");
158
+ return -1;
159
+ }
160
+
161
+ if (!block->driver->amend) {
162
+ error_setg(errp,
163
+ "Crypto format %s doesn't support format options amendment",
164
+ QCryptoBlockFormat_str(block->format));
165
+ return -1;
166
+ }
167
+
168
+ return block->driver->amend(block,
169
+ readfunc,
170
+ writefunc,
171
+ opaque,
172
+ options,
173
+ force,
174
+ errp);
175
+}
176
177
QCryptoBlockInfo *qcrypto_block_get_info(QCryptoBlock *block,
178
Error **errp)
179
--
180
2.26.2
181
182
diff view generated by jsdifflib
1
From: Maxim Levitsky <mlevitsk@redhat.com>
1
From: Jeuk Kim <jeuk20.kim@gmail.com>
2
2
3
blockdev-amend will be used similiar to blockdev-create
3
Universal Flash Storage (UFS) is a high-performance mass storage device
4
to allow on the fly changes of the structure of the format based block devices.
4
with a serial interface. It is primarily used as a high-performance
5
data storage device for embedded applications.
5
6
6
Current plan is to first support encryption keyslot management for luks
7
This commit contains code for UFS device to be recognized
7
based formats (raw and embedded in qcow2)
8
as a UFS PCI device.
9
Patches to handle UFS logical unit and Transfer Request will follow.
8
10
9
Signed-off-by: Maxim Levitsky <mlevitsk@redhat.com>
11
Signed-off-by: Jeuk Kim <jeuk20.kim@samsung.com>
10
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
12
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
11
Message-Id: <20200608094030.670121-12-mlevitsk@redhat.com>
13
Message-id: 9f3db32fe1c708090a6bb764d456973b5abef55f.1691062912.git.jeuk20.kim@samsung.com
12
Signed-off-by: Max Reitz <mreitz@redhat.com>
14
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
13
---
15
---
14
qapi/block-core.json | 42 ++++++++++++++
16
MAINTAINERS | 6 +
15
qapi/job.json | 4 +-
17
docs/specs/pci-ids.rst | 2 +
16
include/block/block_int.h | 21 +++++--
18
meson.build | 1 +
17
block/amend.c | 113 ++++++++++++++++++++++++++++++++++++++
19
hw/ufs/trace.h | 1 +
18
block/Makefile.objs | 2 +-
20
hw/ufs/ufs.h | 42 ++
19
5 files changed, 174 insertions(+), 8 deletions(-)
21
include/block/ufs.h | 1090 ++++++++++++++++++++++++++++++++++++++
20
create mode 100644 block/amend.c
22
include/hw/pci/pci.h | 1 +
23
include/hw/pci/pci_ids.h | 1 +
24
hw/ufs/ufs.c | 278 ++++++++++
25
hw/Kconfig | 1 +
26
hw/meson.build | 1 +
27
hw/ufs/Kconfig | 4 +
28
hw/ufs/meson.build | 1 +
29
hw/ufs/trace-events | 32 ++
30
14 files changed, 1461 insertions(+)
31
create mode 100644 hw/ufs/trace.h
32
create mode 100644 hw/ufs/ufs.h
33
create mode 100644 include/block/ufs.h
34
create mode 100644 hw/ufs/ufs.c
35
create mode 100644 hw/ufs/Kconfig
36
create mode 100644 hw/ufs/meson.build
37
create mode 100644 hw/ufs/trace-events
21
38
22
diff --git a/qapi/block-core.json b/qapi/block-core.json
39
diff --git a/MAINTAINERS b/MAINTAINERS
23
index XXXXXXX..XXXXXXX 100644
40
index XXXXXXX..XXXXXXX 100644
24
--- a/qapi/block-core.json
41
--- a/MAINTAINERS
25
+++ b/qapi/block-core.json
42
+++ b/MAINTAINERS
26
@@ -XXX,XX +XXX,XX @@
43
@@ -XXX,XX +XXX,XX @@ F: tests/qtest/nvme-test.c
27
'data': { 'job-id': 'str',
44
F: docs/system/devices/nvme.rst
28
'options': 'BlockdevCreateOptions' } }
45
T: git git://git.infradead.org/qemu-nvme.git nvme-next
29
46
30
+##
47
+ufs
31
+# @BlockdevAmendOptions:
48
+M: Jeuk Kim <jeuk20.kim@samsung.com>
32
+#
49
+S: Supported
33
+# Options for amending an image format
50
+F: hw/ufs/*
34
+#
51
+F: include/block/ufs.h
35
+# @driver: Block driver of the node to amend.
52
+
36
+#
53
megasas
37
+# Since: 5.1
54
M: Hannes Reinecke <hare@suse.com>
38
+##
55
L: qemu-block@nongnu.org
39
+{ 'union': 'BlockdevAmendOptions',
56
diff --git a/docs/specs/pci-ids.rst b/docs/specs/pci-ids.rst
40
+ 'base': {
41
+ 'driver': 'BlockdevDriver' },
42
+ 'discriminator': 'driver',
43
+ 'data': {
44
+ } }
45
+
46
+##
47
+# @x-blockdev-amend:
48
+#
49
+# Starts a job to amend format specific options of an existing open block device
50
+# The job is automatically finalized, but a manual job-dismiss is required.
51
+#
52
+# @job-id: Identifier for the newly created job.
53
+#
54
+# @node-name: Name of the block node to work on
55
+#
56
+# @options: Options (driver specific)
57
+#
58
+# @force: Allow unsafe operations, format specific
59
+# For luks that allows erase of the last active keyslot
60
+# (permanent loss of data),
61
+# and replacement of an active keyslot
62
+# (possible loss of data if IO error happens)
63
+#
64
+# Since: 5.1
65
+##
66
+{ 'command': 'x-blockdev-amend',
67
+ 'data': { 'job-id': 'str',
68
+ 'node-name': 'str',
69
+ 'options': 'BlockdevAmendOptions',
70
+ '*force': 'bool' } }
71
+
72
##
73
# @BlockErrorAction:
74
#
75
diff --git a/qapi/job.json b/qapi/job.json
76
index XXXXXXX..XXXXXXX 100644
57
index XXXXXXX..XXXXXXX 100644
77
--- a/qapi/job.json
58
--- a/docs/specs/pci-ids.rst
78
+++ b/qapi/job.json
59
+++ b/docs/specs/pci-ids.rst
79
@@ -XXX,XX +XXX,XX @@
60
@@ -XXX,XX +XXX,XX @@ PCI devices (other than virtio):
80
#
61
PCI PVPanic device (``-device pvpanic-pci``)
81
# @create: image creation job type, see "blockdev-create" (since 3.0)
62
1b36:0012
82
#
63
PCI ACPI ERST device (``-device acpi-erst``)
83
+# @amend: image options amend job type, see "x-blockdev-amend" (since 5.1)
64
+1b36:0013
84
+#
65
+ PCI UFS device (``-device ufs``)
85
# Since: 1.7
66
86
##
67
All these devices are documented in :doc:`index`.
87
{ 'enum': 'JobType',
68
88
- 'data': ['commit', 'stream', 'mirror', 'backup', 'create'] }
69
diff --git a/meson.build b/meson.build
89
+ 'data': ['commit', 'stream', 'mirror', 'backup', 'create', 'amend'] }
90
91
##
92
# @JobStatus:
93
diff --git a/include/block/block_int.h b/include/block/block_int.h
94
index XXXXXXX..XXXXXXX 100644
70
index XXXXXXX..XXXXXXX 100644
95
--- a/include/block/block_int.h
71
--- a/meson.build
96
+++ b/include/block/block_int.h
72
+++ b/meson.build
97
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
73
@@ -XXX,XX +XXX,XX @@ if have_system
98
int (*bdrv_file_open)(BlockDriverState *bs, QDict *options, int flags,
74
'hw/ssi',
99
Error **errp);
75
'hw/timer',
100
void (*bdrv_close)(BlockDriverState *bs);
76
'hw/tpm',
101
+
77
+ 'hw/ufs',
102
+
78
'hw/usb',
103
int coroutine_fn (*bdrv_co_create)(BlockdevCreateOptions *opts,
79
'hw/vfio',
104
Error **errp);
80
'hw/virtio',
105
int coroutine_fn (*bdrv_co_create_opts)(BlockDriver *drv,
81
diff --git a/hw/ufs/trace.h b/hw/ufs/trace.h
106
const char *filename,
107
QemuOpts *opts,
108
Error **errp);
109
+
110
+ int coroutine_fn (*bdrv_co_amend)(BlockDriverState *bs,
111
+ BlockdevAmendOptions *opts,
112
+ bool force,
113
+ Error **errp);
114
+
115
+ int (*bdrv_amend_options)(BlockDriverState *bs,
116
+ QemuOpts *opts,
117
+ BlockDriverAmendStatusCB *status_cb,
118
+ void *cb_opaque,
119
+ bool force,
120
+ Error **errp);
121
+
122
int (*bdrv_make_empty)(BlockDriverState *bs);
123
124
/*
125
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
126
BdrvCheckResult *result,
127
BdrvCheckMode fix);
128
129
- int (*bdrv_amend_options)(BlockDriverState *bs, QemuOpts *opts,
130
- BlockDriverAmendStatusCB *status_cb,
131
- void *cb_opaque,
132
- bool force,
133
- Error **errp);
134
-
135
void (*bdrv_debug_event)(BlockDriverState *bs, BlkdebugEvent event);
136
137
/* TODO Better pass a option string/QDict/QemuOpts to add any rule? */
138
diff --git a/block/amend.c b/block/amend.c
139
new file mode 100644
82
new file mode 100644
140
index XXXXXXX..XXXXXXX
83
index XXXXXXX..XXXXXXX
141
--- /dev/null
84
--- /dev/null
142
+++ b/block/amend.c
85
+++ b/hw/ufs/trace.h
86
@@ -0,0 +1 @@
87
+#include "trace/trace-hw_ufs.h"
88
diff --git a/hw/ufs/ufs.h b/hw/ufs/ufs.h
89
new file mode 100644
90
index XXXXXXX..XXXXXXX
91
--- /dev/null
92
+++ b/hw/ufs/ufs.h
143
@@ -XXX,XX +XXX,XX @@
93
@@ -XXX,XX +XXX,XX @@
144
+/*
94
+/*
145
+ * Block layer code related to image options amend
95
+ * QEMU UFS
146
+ *
96
+ *
147
+ * Copyright (c) 2018 Kevin Wolf <kwolf@redhat.com>
97
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd. All rights reserved.
148
+ * Copyright (c) 2020 Red Hat. Inc
149
+ *
98
+ *
150
+ * Heavily based on create.c
99
+ * Written by Jeuk Kim <jeuk20.kim@samsung.com>
151
+ *
100
+ *
152
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
101
+ * SPDX-License-Identifier: GPL-2.0-or-later
153
+ * of this software and associated documentation files (the "Software"), to deal
102
+ */
154
+ * in the Software without restriction, including without limitation the rights
103
+
155
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
104
+#ifndef HW_UFS_UFS_H
156
+ * copies of the Software, and to permit persons to whom the Software is
105
+#define HW_UFS_UFS_H
157
+ * furnished to do so, subject to the following conditions:
106
+
107
+#include "hw/pci/pci_device.h"
108
+#include "hw/scsi/scsi.h"
109
+#include "block/ufs.h"
110
+
111
+#define UFS_MAX_LUS 32
112
+#define UFS_BLOCK_SIZE 4096
113
+
114
+typedef struct UfsParams {
115
+ char *serial;
116
+ uint8_t nutrs; /* Number of UTP Transfer Request Slots */
117
+ uint8_t nutmrs; /* Number of UTP Task Management Request Slots */
118
+} UfsParams;
119
+
120
+typedef struct UfsHc {
121
+ PCIDevice parent_obj;
122
+ MemoryRegion iomem;
123
+ UfsReg reg;
124
+ UfsParams params;
125
+ uint32_t reg_size;
126
+
127
+ qemu_irq irq;
128
+ QEMUBH *doorbell_bh;
129
+ QEMUBH *complete_bh;
130
+} UfsHc;
131
+
132
+#define TYPE_UFS "ufs"
133
+#define UFS(obj) OBJECT_CHECK(UfsHc, (obj), TYPE_UFS)
134
+
135
+#endif /* HW_UFS_UFS_H */
136
diff --git a/include/block/ufs.h b/include/block/ufs.h
137
new file mode 100644
138
index XXXXXXX..XXXXXXX
139
--- /dev/null
140
+++ b/include/block/ufs.h
141
@@ -XXX,XX +XXX,XX @@
142
+/* SPDX-License-Identifier: GPL-2.0-or-later */
143
+
144
+#ifndef BLOCK_UFS_H
145
+#define BLOCK_UFS_H
146
+
147
+#include "hw/registerfields.h"
148
+
149
+typedef struct QEMU_PACKED UfsReg {
150
+ uint32_t cap;
151
+ uint32_t rsvd0;
152
+ uint32_t ver;
153
+ uint32_t rsvd1;
154
+ uint32_t hcpid;
155
+ uint32_t hcmid;
156
+ uint32_t ahit;
157
+ uint32_t rsvd2;
158
+ uint32_t is;
159
+ uint32_t ie;
160
+ uint32_t rsvd3[2];
161
+ uint32_t hcs;
162
+ uint32_t hce;
163
+ uint32_t uecpa;
164
+ uint32_t uecdl;
165
+ uint32_t uecn;
166
+ uint32_t uect;
167
+ uint32_t uecdme;
168
+ uint32_t utriacr;
169
+ uint32_t utrlba;
170
+ uint32_t utrlbau;
171
+ uint32_t utrldbr;
172
+ uint32_t utrlclr;
173
+ uint32_t utrlrsr;
174
+ uint32_t utrlcnr;
175
+ uint32_t rsvd4[2];
176
+ uint32_t utmrlba;
177
+ uint32_t utmrlbau;
178
+ uint32_t utmrldbr;
179
+ uint32_t utmrlclr;
180
+ uint32_t utmrlrsr;
181
+ uint32_t rsvd5[3];
182
+ uint32_t uiccmd;
183
+ uint32_t ucmdarg1;
184
+ uint32_t ucmdarg2;
185
+ uint32_t ucmdarg3;
186
+ uint32_t rsvd6[4];
187
+ uint32_t rsvd7[4];
188
+ uint32_t rsvd8[16];
189
+ uint32_t ccap;
190
+} UfsReg;
191
+
192
+REG32(CAP, offsetof(UfsReg, cap))
193
+ FIELD(CAP, NUTRS, 0, 5)
194
+ FIELD(CAP, RTT, 8, 8)
195
+ FIELD(CAP, NUTMRS, 16, 3)
196
+ FIELD(CAP, AUTOH8, 23, 1)
197
+ FIELD(CAP, 64AS, 24, 1)
198
+ FIELD(CAP, OODDS, 25, 1)
199
+ FIELD(CAP, UICDMETMS, 26, 1)
200
+ FIELD(CAP, CS, 28, 1)
201
+REG32(VER, offsetof(UfsReg, ver))
202
+REG32(HCPID, offsetof(UfsReg, hcpid))
203
+REG32(HCMID, offsetof(UfsReg, hcmid))
204
+REG32(AHIT, offsetof(UfsReg, ahit))
205
+REG32(IS, offsetof(UfsReg, is))
206
+ FIELD(IS, UTRCS, 0, 1)
207
+ FIELD(IS, UDEPRI, 1, 1)
208
+ FIELD(IS, UE, 2, 1)
209
+ FIELD(IS, UTMS, 3, 1)
210
+ FIELD(IS, UPMS, 4, 1)
211
+ FIELD(IS, UHXS, 5, 1)
212
+ FIELD(IS, UHES, 6, 1)
213
+ FIELD(IS, ULLS, 7, 1)
214
+ FIELD(IS, ULSS, 8, 1)
215
+ FIELD(IS, UTMRCS, 9, 1)
216
+ FIELD(IS, UCCS, 10, 1)
217
+ FIELD(IS, DFES, 11, 1)
218
+ FIELD(IS, UTPES, 12, 1)
219
+ FIELD(IS, HCFES, 16, 1)
220
+ FIELD(IS, SBFES, 17, 1)
221
+ FIELD(IS, CEFES, 18, 1)
222
+REG32(IE, offsetof(UfsReg, ie))
223
+ FIELD(IE, UTRCE, 0, 1)
224
+ FIELD(IE, UDEPRIE, 1, 1)
225
+ FIELD(IE, UEE, 2, 1)
226
+ FIELD(IE, UTMSE, 3, 1)
227
+ FIELD(IE, UPMSE, 4, 1)
228
+ FIELD(IE, UHXSE, 5, 1)
229
+ FIELD(IE, UHESE, 6, 1)
230
+ FIELD(IE, ULLSE, 7, 1)
231
+ FIELD(IE, ULSSE, 8, 1)
232
+ FIELD(IE, UTMRCE, 9, 1)
233
+ FIELD(IE, UCCE, 10, 1)
234
+ FIELD(IE, DFEE, 11, 1)
235
+ FIELD(IE, UTPEE, 12, 1)
236
+ FIELD(IE, HCFEE, 16, 1)
237
+ FIELD(IE, SBFEE, 17, 1)
238
+ FIELD(IE, CEFEE, 18, 1)
239
+REG32(HCS, offsetof(UfsReg, hcs))
240
+ FIELD(HCS, DP, 0, 1)
241
+ FIELD(HCS, UTRLRDY, 1, 1)
242
+ FIELD(HCS, UTMRLRDY, 2, 1)
243
+ FIELD(HCS, UCRDY, 3, 1)
244
+ FIELD(HCS, UPMCRS, 8, 3)
245
+REG32(HCE, offsetof(UfsReg, hce))
246
+ FIELD(HCE, HCE, 0, 1)
247
+ FIELD(HCE, CGE, 1, 1)
248
+REG32(UECPA, offsetof(UfsReg, uecpa))
249
+REG32(UECDL, offsetof(UfsReg, uecdl))
250
+REG32(UECN, offsetof(UfsReg, uecn))
251
+REG32(UECT, offsetof(UfsReg, uect))
252
+REG32(UECDME, offsetof(UfsReg, uecdme))
253
+REG32(UTRIACR, offsetof(UfsReg, utriacr))
254
+REG32(UTRLBA, offsetof(UfsReg, utrlba))
255
+ FIELD(UTRLBA, UTRLBA, 9, 22)
256
+REG32(UTRLBAU, offsetof(UfsReg, utrlbau))
257
+REG32(UTRLDBR, offsetof(UfsReg, utrldbr))
258
+REG32(UTRLCLR, offsetof(UfsReg, utrlclr))
259
+REG32(UTRLRSR, offsetof(UfsReg, utrlrsr))
260
+REG32(UTRLCNR, offsetof(UfsReg, utrlcnr))
261
+REG32(UTMRLBA, offsetof(UfsReg, utmrlba))
262
+ FIELD(UTMRLBA, UTMRLBA, 9, 22)
263
+REG32(UTMRLBAU, offsetof(UfsReg, utmrlbau))
264
+REG32(UTMRLDBR, offsetof(UfsReg, utmrldbr))
265
+REG32(UTMRLCLR, offsetof(UfsReg, utmrlclr))
266
+REG32(UTMRLRSR, offsetof(UfsReg, utmrlrsr))
267
+REG32(UICCMD, offsetof(UfsReg, uiccmd))
268
+REG32(UCMDARG1, offsetof(UfsReg, ucmdarg1))
269
+REG32(UCMDARG2, offsetof(UfsReg, ucmdarg2))
270
+REG32(UCMDARG3, offsetof(UfsReg, ucmdarg3))
271
+REG32(CCAP, offsetof(UfsReg, ccap))
272
+
273
+#define UFS_INTR_MASK \
274
+ ((1 << R_IS_CEFES_SHIFT) | (1 << R_IS_SBFES_SHIFT) | \
275
+ (1 << R_IS_HCFES_SHIFT) | (1 << R_IS_UTPES_SHIFT) | \
276
+ (1 << R_IS_DFES_SHIFT) | (1 << R_IS_UCCS_SHIFT) | \
277
+ (1 << R_IS_UTMRCS_SHIFT) | (1 << R_IS_ULSS_SHIFT) | \
278
+ (1 << R_IS_ULLS_SHIFT) | (1 << R_IS_UHES_SHIFT) | \
279
+ (1 << R_IS_UHXS_SHIFT) | (1 << R_IS_UPMS_SHIFT) | \
280
+ (1 << R_IS_UTMS_SHIFT) | (1 << R_IS_UE_SHIFT) | \
281
+ (1 << R_IS_UDEPRI_SHIFT) | (1 << R_IS_UTRCS_SHIFT))
282
+
283
+#define UFS_UPIU_HEADER_TRANSACTION_TYPE_SHIFT 24
284
+#define UFS_UPIU_HEADER_TRANSACTION_TYPE_MASK 0xff
285
+#define UFS_UPIU_HEADER_TRANSACTION_TYPE(dword0) \
286
+ ((be32_to_cpu(dword0) >> UFS_UPIU_HEADER_TRANSACTION_TYPE_SHIFT) & \
287
+ UFS_UPIU_HEADER_TRANSACTION_TYPE_MASK)
288
+
289
+#define UFS_UPIU_HEADER_QUERY_FUNC_SHIFT 16
290
+#define UFS_UPIU_HEADER_QUERY_FUNC_MASK 0xff
291
+#define UFS_UPIU_HEADER_QUERY_FUNC(dword1) \
292
+ ((be32_to_cpu(dword1) >> UFS_UPIU_HEADER_QUERY_FUNC_SHIFT) & \
293
+ UFS_UPIU_HEADER_QUERY_FUNC_MASK)
294
+
295
+#define UFS_UPIU_HEADER_DATA_SEGMENT_LENGTH_SHIFT 0
296
+#define UFS_UPIU_HEADER_DATA_SEGMENT_LENGTH_MASK 0xffff
297
+#define UFS_UPIU_HEADER_DATA_SEGMENT_LENGTH(dword2) \
298
+ ((be32_to_cpu(dword2) >> UFS_UPIU_HEADER_DATA_SEGMENT_LENGTH_SHIFT) & \
299
+ UFS_UPIU_HEADER_DATA_SEGMENT_LENGTH_MASK)
300
+
301
+typedef struct QEMU_PACKED DeviceDescriptor {
302
+ uint8_t length;
303
+ uint8_t descriptor_idn;
304
+ uint8_t device;
305
+ uint8_t device_class;
306
+ uint8_t device_sub_class;
307
+ uint8_t protocol;
308
+ uint8_t number_lu;
309
+ uint8_t number_wlu;
310
+ uint8_t boot_enable;
311
+ uint8_t descr_access_en;
312
+ uint8_t init_power_mode;
313
+ uint8_t high_priority_lun;
314
+ uint8_t secure_removal_type;
315
+ uint8_t security_lu;
316
+ uint8_t background_ops_term_lat;
317
+ uint8_t init_active_icc_level;
318
+ uint16_t spec_version;
319
+ uint16_t manufacture_date;
320
+ uint8_t manufacturer_name;
321
+ uint8_t product_name;
322
+ uint8_t serial_number;
323
+ uint8_t oem_id;
324
+ uint16_t manufacturer_id;
325
+ uint8_t ud_0_base_offset;
326
+ uint8_t ud_config_p_length;
327
+ uint8_t device_rtt_cap;
328
+ uint16_t periodic_rtc_update;
329
+ uint8_t ufs_features_support;
330
+ uint8_t ffu_timeout;
331
+ uint8_t queue_depth;
332
+ uint16_t device_version;
333
+ uint8_t num_secure_wp_area;
334
+ uint32_t psa_max_data_size;
335
+ uint8_t psa_state_timeout;
336
+ uint8_t product_revision_level;
337
+ uint8_t reserved[36];
338
+ uint32_t extended_ufs_features_support;
339
+ uint8_t write_booster_buffer_preserve_user_space_en;
340
+ uint8_t write_booster_buffer_type;
341
+ uint32_t num_shared_write_booster_buffer_alloc_units;
342
+} DeviceDescriptor;
343
+
344
+typedef struct QEMU_PACKED GeometryDescriptor {
345
+ uint8_t length;
346
+ uint8_t descriptor_idn;
347
+ uint8_t media_technology;
348
+ uint8_t reserved;
349
+ uint64_t total_raw_device_capacity;
350
+ uint8_t max_number_lu;
351
+ uint32_t segment_size;
352
+ uint8_t allocation_unit_size;
353
+ uint8_t min_addr_block_size;
354
+ uint8_t optimal_read_block_size;
355
+ uint8_t optimal_write_block_size;
356
+ uint8_t max_in_buffer_size;
357
+ uint8_t max_out_buffer_size;
358
+ uint8_t rpmb_read_write_size;
359
+ uint8_t dynamic_capacity_resource_policy;
360
+ uint8_t data_ordering;
361
+ uint8_t max_context_id_number;
362
+ uint8_t sys_data_tag_unit_size;
363
+ uint8_t sys_data_tag_res_size;
364
+ uint8_t supported_sec_r_types;
365
+ uint16_t supported_memory_types;
366
+ uint32_t system_code_max_n_alloc_u;
367
+ uint16_t system_code_cap_adj_fac;
368
+ uint32_t non_persist_max_n_alloc_u;
369
+ uint16_t non_persist_cap_adj_fac;
370
+ uint32_t enhanced_1_max_n_alloc_u;
371
+ uint16_t enhanced_1_cap_adj_fac;
372
+ uint32_t enhanced_2_max_n_alloc_u;
373
+ uint16_t enhanced_2_cap_adj_fac;
374
+ uint32_t enhanced_3_max_n_alloc_u;
375
+ uint16_t enhanced_3_cap_adj_fac;
376
+ uint32_t enhanced_4_max_n_alloc_u;
377
+ uint16_t enhanced_4_cap_adj_fac;
378
+ uint32_t optimal_logical_block_size;
379
+ uint8_t reserved2[7];
380
+ uint32_t write_booster_buffer_max_n_alloc_units;
381
+ uint8_t device_max_write_booster_l_us;
382
+ uint8_t write_booster_buffer_cap_adj_fac;
383
+ uint8_t supported_write_booster_buffer_user_space_reduction_types;
384
+ uint8_t supported_write_booster_buffer_types;
385
+} GeometryDescriptor;
386
+
387
+#define UFS_GEOMETRY_CAPACITY_SHIFT 9
388
+
389
+typedef struct QEMU_PACKED UnitDescriptor {
390
+ uint8_t length;
391
+ uint8_t descriptor_idn;
392
+ uint8_t unit_index;
393
+ uint8_t lu_enable;
394
+ uint8_t boot_lun_id;
395
+ uint8_t lu_write_protect;
396
+ uint8_t lu_queue_depth;
397
+ uint8_t psa_sensitive;
398
+ uint8_t memory_type;
399
+ uint8_t data_reliability;
400
+ uint8_t logical_block_size;
401
+ uint64_t logical_block_count;
402
+ uint32_t erase_block_size;
403
+ uint8_t provisioning_type;
404
+ uint64_t phy_mem_resource_count;
405
+ uint16_t context_capabilities;
406
+ uint8_t large_unit_granularity_m1;
407
+ uint8_t reserved[6];
408
+ uint32_t lu_num_write_booster_buffer_alloc_units;
409
+} UnitDescriptor;
410
+
411
+typedef struct QEMU_PACKED RpmbUnitDescriptor {
412
+ uint8_t length;
413
+ uint8_t descriptor_idn;
414
+ uint8_t unit_index;
415
+ uint8_t lu_enable;
416
+ uint8_t boot_lun_id;
417
+ uint8_t lu_write_protect;
418
+ uint8_t lu_queue_depth;
419
+ uint8_t psa_sensitive;
420
+ uint8_t memory_type;
421
+ uint8_t reserved;
422
+ uint8_t logical_block_size;
423
+ uint64_t logical_block_count;
424
+ uint32_t erase_block_size;
425
+ uint8_t provisioning_type;
426
+ uint64_t phy_mem_resource_count;
427
+ uint8_t reserved2[3];
428
+} RpmbUnitDescriptor;
429
+
430
+typedef struct QEMU_PACKED PowerParametersDescriptor {
431
+ uint8_t length;
432
+ uint8_t descriptor_idn;
433
+ uint16_t active_icc_levels_vcc[16];
434
+ uint16_t active_icc_levels_vccq[16];
435
+ uint16_t active_icc_levels_vccq_2[16];
436
+} PowerParametersDescriptor;
437
+
438
+typedef struct QEMU_PACKED InterconnectDescriptor {
439
+ uint8_t length;
440
+ uint8_t descriptor_idn;
441
+ uint16_t bcd_unipro_version;
442
+ uint16_t bcd_mphy_version;
443
+} InterconnectDescriptor;
444
+
445
+typedef struct QEMU_PACKED StringDescriptor {
446
+ uint8_t length;
447
+ uint8_t descriptor_idn;
448
+ uint16_t UC[126];
449
+} StringDescriptor;
450
+
451
+typedef struct QEMU_PACKED DeviceHealthDescriptor {
452
+ uint8_t length;
453
+ uint8_t descriptor_idn;
454
+ uint8_t pre_eol_info;
455
+ uint8_t device_life_time_est_a;
456
+ uint8_t device_life_time_est_b;
457
+ uint8_t vendor_prop_info[32];
458
+ uint32_t refresh_total_count;
459
+ uint32_t refresh_progress;
460
+} DeviceHealthDescriptor;
461
+
462
+typedef struct QEMU_PACKED Flags {
463
+ uint8_t reserved;
464
+ uint8_t device_init;
465
+ uint8_t permanent_wp_en;
466
+ uint8_t power_on_wp_en;
467
+ uint8_t background_ops_en;
468
+ uint8_t device_life_span_mode_en;
469
+ uint8_t purge_enable;
470
+ uint8_t refresh_enable;
471
+ uint8_t phy_resource_removal;
472
+ uint8_t busy_rtc;
473
+ uint8_t reserved2;
474
+ uint8_t permanently_disable_fw_update;
475
+ uint8_t reserved3[2];
476
+ uint8_t wb_en;
477
+ uint8_t wb_buffer_flush_en;
478
+ uint8_t wb_buffer_flush_during_hibernate;
479
+ uint8_t reserved4[2];
480
+} Flags;
481
+
482
+typedef struct Attributes {
483
+ uint8_t boot_lun_en;
484
+ uint8_t reserved;
485
+ uint8_t current_power_mode;
486
+ uint8_t active_icc_level;
487
+ uint8_t out_of_order_data_en;
488
+ uint8_t background_op_status;
489
+ uint8_t purge_status;
490
+ uint8_t max_data_in_size;
491
+ uint8_t max_data_out_size;
492
+ uint32_t dyn_cap_needed;
493
+ uint8_t ref_clk_freq;
494
+ uint8_t config_descr_lock;
495
+ uint8_t max_num_of_rtt;
496
+ uint16_t exception_event_control;
497
+ uint16_t exception_event_status;
498
+ uint32_t seconds_passed;
499
+ uint16_t context_conf;
500
+ uint8_t device_ffu_status;
501
+ uint8_t psa_state;
502
+ uint32_t psa_data_size;
503
+ uint8_t ref_clk_gating_wait_time;
504
+ uint8_t device_case_rough_temperaure;
505
+ uint8_t device_too_high_temp_boundary;
506
+ uint8_t device_too_low_temp_boundary;
507
+ uint8_t throttling_status;
508
+ uint8_t wb_buffer_flush_status;
509
+ uint8_t available_wb_buffer_size;
510
+ uint8_t wb_buffer_life_time_est;
511
+ uint32_t current_wb_buffer_size;
512
+ uint8_t refresh_status;
513
+ uint8_t refresh_freq;
514
+ uint8_t refresh_unit;
515
+ uint8_t refresh_method;
516
+} Attributes;
517
+
518
+#define UFS_TRANSACTION_SPECIFIC_FIELD_SIZE 20
519
+#define UFS_MAX_QUERY_DATA_SIZE 256
520
+
521
+/* Command response result code */
522
+typedef enum CommandRespCode {
523
+ COMMAND_RESULT_SUCESS = 0x00,
524
+ COMMAND_RESULT_FAIL = 0x01,
525
+} CommandRespCode;
526
+
527
+enum {
528
+ UFS_UPIU_FLAG_UNDERFLOW = 0x20,
529
+ UFS_UPIU_FLAG_OVERFLOW = 0x40,
530
+};
531
+
532
+typedef struct QEMU_PACKED UtpUpiuHeader {
533
+ uint8_t trans_type;
534
+ uint8_t flags;
535
+ uint8_t lun;
536
+ uint8_t task_tag;
537
+ uint8_t iid_cmd_set_type;
538
+ uint8_t query_func;
539
+ uint8_t response;
540
+ uint8_t scsi_status;
541
+ uint8_t ehs_len;
542
+ uint8_t device_inf;
543
+ uint16_t data_segment_length;
544
+} UtpUpiuHeader;
545
+
546
+/*
547
+ * The code below is copied from the linux kernel
548
+ * ("include/uapi/scsi/scsi_bsg_ufs.h") and modified to fit the qemu style.
549
+ */
550
+
551
+typedef struct QEMU_PACKED UtpUpiuQuery {
552
+ uint8_t opcode;
553
+ uint8_t idn;
554
+ uint8_t index;
555
+ uint8_t selector;
556
+ uint16_t reserved_osf;
557
+ uint16_t length;
558
+ uint32_t value;
559
+ uint32_t reserved[2];
560
+ /* EHS length should be 0. We don't have to worry about EHS area. */
561
+ uint8_t data[UFS_MAX_QUERY_DATA_SIZE];
562
+} UtpUpiuQuery;
563
+
564
+#define UFS_CDB_SIZE 16
565
+
566
+/*
567
+ * struct UtpUpiuCmd - Command UPIU structure
568
+ * @data_transfer_len: Data Transfer Length DW-3
569
+ * @cdb: Command Descriptor Block CDB DW-4 to DW-7
570
+ */
571
+typedef struct QEMU_PACKED UtpUpiuCmd {
572
+ uint32_t exp_data_transfer_len;
573
+ uint8_t cdb[UFS_CDB_SIZE];
574
+} UtpUpiuCmd;
575
+
576
+/*
577
+ * struct UtpUpiuReq - general upiu request structure
578
+ * @header:UPIU header structure DW-0 to DW-2
579
+ * @sc: fields structure for scsi command DW-3 to DW-7
580
+ * @qr: fields structure for query request DW-3 to DW-7
581
+ * @uc: use utp_upiu_query to host the 4 dwords of uic command
582
+ */
583
+typedef struct QEMU_PACKED UtpUpiuReq {
584
+ UtpUpiuHeader header;
585
+ union {
586
+ UtpUpiuCmd sc;
587
+ UtpUpiuQuery qr;
588
+ };
589
+} UtpUpiuReq;
590
+
591
+/*
592
+ * The code below is copied from the linux kernel ("include/ufs/ufshci.h") and
593
+ * modified to fit the qemu style.
594
+ */
595
+
596
+enum {
597
+ PWR_OK = 0x0,
598
+ PWR_LOCAL = 0x01,
599
+ PWR_REMOTE = 0x02,
600
+ PWR_BUSY = 0x03,
601
+ PWR_ERROR_CAP = 0x04,
602
+ PWR_FATAL_ERROR = 0x05,
603
+};
604
+
605
+/* UIC Commands */
606
+enum uic_cmd_dme {
607
+ UIC_CMD_DME_GET = 0x01,
608
+ UIC_CMD_DME_SET = 0x02,
609
+ UIC_CMD_DME_PEER_GET = 0x03,
610
+ UIC_CMD_DME_PEER_SET = 0x04,
611
+ UIC_CMD_DME_POWERON = 0x10,
612
+ UIC_CMD_DME_POWEROFF = 0x11,
613
+ UIC_CMD_DME_ENABLE = 0x12,
614
+ UIC_CMD_DME_RESET = 0x14,
615
+ UIC_CMD_DME_END_PT_RST = 0x15,
616
+ UIC_CMD_DME_LINK_STARTUP = 0x16,
617
+ UIC_CMD_DME_HIBER_ENTER = 0x17,
618
+ UIC_CMD_DME_HIBER_EXIT = 0x18,
619
+ UIC_CMD_DME_TEST_MODE = 0x1A,
620
+};
621
+
622
+/* UIC Config result code / Generic error code */
623
+enum {
624
+ UIC_CMD_RESULT_SUCCESS = 0x00,
625
+ UIC_CMD_RESULT_INVALID_ATTR = 0x01,
626
+ UIC_CMD_RESULT_FAILURE = 0x01,
627
+ UIC_CMD_RESULT_INVALID_ATTR_VALUE = 0x02,
628
+ UIC_CMD_RESULT_READ_ONLY_ATTR = 0x03,
629
+ UIC_CMD_RESULT_WRITE_ONLY_ATTR = 0x04,
630
+ UIC_CMD_RESULT_BAD_INDEX = 0x05,
631
+ UIC_CMD_RESULT_LOCKED_ATTR = 0x06,
632
+ UIC_CMD_RESULT_BAD_TEST_FEATURE_INDEX = 0x07,
633
+ UIC_CMD_RESULT_PEER_COMM_FAILURE = 0x08,
634
+ UIC_CMD_RESULT_BUSY = 0x09,
635
+ UIC_CMD_RESULT_DME_FAILURE = 0x0A,
636
+};
637
+
638
+#define MASK_UIC_COMMAND_RESULT 0xFF
639
+
640
+/*
641
+ * Request Descriptor Definitions
642
+ */
643
+
644
+/* Transfer request command type */
645
+enum {
646
+ UTP_CMD_TYPE_SCSI = 0x0,
647
+ UTP_CMD_TYPE_UFS = 0x1,
648
+ UTP_CMD_TYPE_DEV_MANAGE = 0x2,
649
+};
650
+
651
+/* To accommodate UFS2.0 required Command type */
652
+enum {
653
+ UTP_CMD_TYPE_UFS_STORAGE = 0x1,
654
+};
655
+
656
+enum {
657
+ UTP_SCSI_COMMAND = 0x00000000,
658
+ UTP_NATIVE_UFS_COMMAND = 0x10000000,
659
+ UTP_DEVICE_MANAGEMENT_FUNCTION = 0x20000000,
660
+ UTP_REQ_DESC_INT_CMD = 0x01000000,
661
+ UTP_REQ_DESC_CRYPTO_ENABLE_CMD = 0x00800000,
662
+};
663
+
664
+/* UTP Transfer Request Data Direction (DD) */
665
+enum {
666
+ UTP_NO_DATA_TRANSFER = 0x00000000,
667
+ UTP_HOST_TO_DEVICE = 0x02000000,
668
+ UTP_DEVICE_TO_HOST = 0x04000000,
669
+};
670
+
671
+/* Overall command status values */
672
+enum UtpOcsCodes {
673
+ OCS_SUCCESS = 0x0,
674
+ OCS_INVALID_CMD_TABLE_ATTR = 0x1,
675
+ OCS_INVALID_PRDT_ATTR = 0x2,
676
+ OCS_MISMATCH_DATA_BUF_SIZE = 0x3,
677
+ OCS_MISMATCH_RESP_UPIU_SIZE = 0x4,
678
+ OCS_PEER_COMM_FAILURE = 0x5,
679
+ OCS_ABORTED = 0x6,
680
+ OCS_FATAL_ERROR = 0x7,
681
+ OCS_DEVICE_FATAL_ERROR = 0x8,
682
+ OCS_INVALID_CRYPTO_CONFIG = 0x9,
683
+ OCS_GENERAL_CRYPTO_ERROR = 0xa,
684
+ OCS_INVALID_COMMAND_STATUS = 0xf,
685
+};
686
+
687
+enum {
688
+ MASK_OCS = 0x0F,
689
+};
690
+
691
+/*
692
+ * struct UfshcdSgEntry - UFSHCI PRD Entry
693
+ * @addr: Physical address; DW-0 and DW-1.
694
+ * @reserved: Reserved for future use DW-2
695
+ * @size: size of physical segment DW-3
696
+ */
697
+typedef struct QEMU_PACKED UfshcdSgEntry {
698
+ uint64_t addr;
699
+ uint32_t reserved;
700
+ uint32_t size;
701
+ /*
702
+ * followed by variant-specific fields if
703
+ * CONFIG_SCSI_UFS_VARIABLE_SG_ENTRY_SIZE has been defined.
704
+ */
705
+} UfshcdSgEntry;
706
+
707
+/*
708
+ * struct RequestDescHeader - Descriptor Header common to both UTRD and UTMRD
709
+ * @dword0: Descriptor Header DW0
710
+ * @dword1: Descriptor Header DW1
711
+ * @dword2: Descriptor Header DW2
712
+ * @dword3: Descriptor Header DW3
713
+ */
714
+typedef struct QEMU_PACKED RequestDescHeader {
715
+ uint32_t dword_0;
716
+ uint32_t dword_1;
717
+ uint32_t dword_2;
718
+ uint32_t dword_3;
719
+} RequestDescHeader;
720
+
721
+/*
722
+ * struct UtpTransferReqDesc - UTP Transfer Request Descriptor (UTRD)
723
+ * @header: UTRD header DW-0 to DW-3
724
+ * @command_desc_base_addr_lo: UCD base address low DW-4
725
+ * @command_desc_base_addr_hi: UCD base address high DW-5
726
+ * @response_upiu_length: response UPIU length DW-6
727
+ * @response_upiu_offset: response UPIU offset DW-6
728
+ * @prd_table_length: Physical region descriptor length DW-7
729
+ * @prd_table_offset: Physical region descriptor offset DW-7
730
+ */
731
+typedef struct QEMU_PACKED UtpTransferReqDesc {
732
+ /* DW 0-3 */
733
+ RequestDescHeader header;
734
+
735
+ /* DW 4-5*/
736
+ uint32_t command_desc_base_addr_lo;
737
+ uint32_t command_desc_base_addr_hi;
738
+
739
+ /* DW 6 */
740
+ uint16_t response_upiu_length;
741
+ uint16_t response_upiu_offset;
742
+
743
+ /* DW 7 */
744
+ uint16_t prd_table_length;
745
+ uint16_t prd_table_offset;
746
+} UtpTransferReqDesc;
747
+
748
+/*
749
+ * UTMRD structure.
750
+ */
751
+typedef struct QEMU_PACKED UtpTaskReqDesc {
752
+ /* DW 0-3 */
753
+ RequestDescHeader header;
754
+
755
+ /* DW 4-11 - Task request UPIU structure */
756
+ struct {
757
+ UtpUpiuHeader req_header;
758
+ uint32_t input_param1;
759
+ uint32_t input_param2;
760
+ uint32_t input_param3;
761
+ uint32_t reserved1[2];
762
+ } upiu_req;
763
+
764
+ /* DW 12-19 - Task Management Response UPIU structure */
765
+ struct {
766
+ UtpUpiuHeader rsp_header;
767
+ uint32_t output_param1;
768
+ uint32_t output_param2;
769
+ uint32_t reserved2[3];
770
+ } upiu_rsp;
771
+} UtpTaskReqDesc;
772
+
773
+/*
774
+ * The code below is copied from the linux kernel ("include/ufs/ufs.h") and
775
+ * modified to fit the qemu style.
776
+ */
777
+
778
+#define GENERAL_UPIU_REQUEST_SIZE (sizeof(UtpUpiuReq))
779
+#define QUERY_DESC_MAX_SIZE 255
780
+#define QUERY_DESC_MIN_SIZE 2
781
+#define QUERY_DESC_HDR_SIZE 2
782
+#define QUERY_OSF_SIZE (GENERAL_UPIU_REQUEST_SIZE - (sizeof(UtpUpiuHeader)))
783
+#define UFS_SENSE_SIZE 18
784
+
785
+/*
786
+ * UFS device may have standard LUs and LUN id could be from 0x00 to
787
+ * 0x7F. Standard LUs use "Peripheral Device Addressing Format".
788
+ * UFS device may also have the Well Known LUs (also referred as W-LU)
789
+ * which again could be from 0x00 to 0x7F. For W-LUs, device only use
790
+ * the "Extended Addressing Format" which means the W-LUNs would be
791
+ * from 0xc100 (SCSI_W_LUN_BASE) onwards.
792
+ * This means max. LUN number reported from UFS device could be 0xC17F.
793
+ */
794
+#define UFS_UPIU_MAX_UNIT_NUM_ID 0x7F
795
+#define UFS_UPIU_WLUN_ID (1 << 7)
796
+
797
+/* WriteBooster buffer is available only for the logical unit from 0 to 7 */
798
+#define UFS_UPIU_MAX_WB_LUN_ID 8
799
+
800
+/*
801
+ * WriteBooster buffer lifetime has a limit setted by vendor.
802
+ * If it is over the limit, WriteBooster feature will be disabled.
803
+ */
804
+#define UFS_WB_EXCEED_LIFETIME 0x0B
805
+
806
+/*
807
+ * In UFS Spec, the Extra Header Segment (EHS) starts from byte 32 in UPIU
808
+ * request/response packet
809
+ */
810
+#define EHS_OFFSET_IN_RESPONSE 32
811
+
812
+/* Well known logical unit id in LUN field of UPIU */
813
+enum {
814
+ UFS_UPIU_REPORT_LUNS_WLUN = 0x81,
815
+ UFS_UPIU_UFS_DEVICE_WLUN = 0xD0,
816
+ UFS_UPIU_BOOT_WLUN = 0xB0,
817
+ UFS_UPIU_RPMB_WLUN = 0xC4,
818
+};
819
+
820
+/*
821
+ * UFS Protocol Information Unit related definitions
822
+ */
823
+
824
+/* Task management functions */
825
+enum {
826
+ UFS_ABORT_TASK = 0x01,
827
+ UFS_ABORT_TASK_SET = 0x02,
828
+ UFS_CLEAR_TASK_SET = 0x04,
829
+ UFS_LOGICAL_RESET = 0x08,
830
+ UFS_QUERY_TASK = 0x80,
831
+ UFS_QUERY_TASK_SET = 0x81,
832
+};
833
+
834
+/* UTP UPIU Transaction Codes Initiator to Target */
835
+enum {
836
+ UPIU_TRANSACTION_NOP_OUT = 0x00,
837
+ UPIU_TRANSACTION_COMMAND = 0x01,
838
+ UPIU_TRANSACTION_DATA_OUT = 0x02,
839
+ UPIU_TRANSACTION_TASK_REQ = 0x04,
840
+ UPIU_TRANSACTION_QUERY_REQ = 0x16,
841
+};
842
+
843
+/* UTP UPIU Transaction Codes Target to Initiator */
844
+enum {
845
+ UPIU_TRANSACTION_NOP_IN = 0x20,
846
+ UPIU_TRANSACTION_RESPONSE = 0x21,
847
+ UPIU_TRANSACTION_DATA_IN = 0x22,
848
+ UPIU_TRANSACTION_TASK_RSP = 0x24,
849
+ UPIU_TRANSACTION_READY_XFER = 0x31,
850
+ UPIU_TRANSACTION_QUERY_RSP = 0x36,
851
+ UPIU_TRANSACTION_REJECT_UPIU = 0x3F,
852
+};
853
+
854
+/* UPIU Read/Write flags */
855
+enum {
856
+ UPIU_CMD_FLAGS_NONE = 0x00,
857
+ UPIU_CMD_FLAGS_WRITE = 0x20,
858
+ UPIU_CMD_FLAGS_READ = 0x40,
859
+};
860
+
861
+/* UPIU Task Attributes */
862
+enum {
863
+ UPIU_TASK_ATTR_SIMPLE = 0x00,
864
+ UPIU_TASK_ATTR_ORDERED = 0x01,
865
+ UPIU_TASK_ATTR_HEADQ = 0x02,
866
+ UPIU_TASK_ATTR_ACA = 0x03,
867
+};
868
+
869
+/* UPIU Query request function */
870
+enum {
871
+ UPIU_QUERY_FUNC_STANDARD_READ_REQUEST = 0x01,
872
+ UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST = 0x81,
873
+};
874
+
875
+/* Flag idn for Query Requests*/
876
+enum flag_idn {
877
+ QUERY_FLAG_IDN_FDEVICEINIT = 0x01,
878
+ QUERY_FLAG_IDN_PERMANENT_WPE = 0x02,
879
+ QUERY_FLAG_IDN_PWR_ON_WPE = 0x03,
880
+ QUERY_FLAG_IDN_BKOPS_EN = 0x04,
881
+ QUERY_FLAG_IDN_LIFE_SPAN_MODE_ENABLE = 0x05,
882
+ QUERY_FLAG_IDN_PURGE_ENABLE = 0x06,
883
+ QUERY_FLAG_IDN_REFRESH_ENABLE = 0x07,
884
+ QUERY_FLAG_IDN_FPHYRESOURCEREMOVAL = 0x08,
885
+ QUERY_FLAG_IDN_BUSY_RTC = 0x09,
886
+ QUERY_FLAG_IDN_RESERVED3 = 0x0A,
887
+ QUERY_FLAG_IDN_PERMANENTLY_DISABLE_FW_UPDATE = 0x0B,
888
+ QUERY_FLAG_IDN_WB_EN = 0x0E,
889
+ QUERY_FLAG_IDN_WB_BUFF_FLUSH_EN = 0x0F,
890
+ QUERY_FLAG_IDN_WB_BUFF_FLUSH_DURING_HIBERN8 = 0x10,
891
+ QUERY_FLAG_IDN_HPB_RESET = 0x11,
892
+ QUERY_FLAG_IDN_HPB_EN = 0x12,
893
+ QUERY_FLAG_IDN_COUNT,
894
+};
895
+
896
+/* Attribute idn for Query requests */
897
+enum attr_idn {
898
+ QUERY_ATTR_IDN_BOOT_LU_EN = 0x00,
899
+ QUERY_ATTR_IDN_MAX_HPB_SINGLE_CMD = 0x01,
900
+ QUERY_ATTR_IDN_POWER_MODE = 0x02,
901
+ QUERY_ATTR_IDN_ACTIVE_ICC_LVL = 0x03,
902
+ QUERY_ATTR_IDN_OOO_DATA_EN = 0x04,
903
+ QUERY_ATTR_IDN_BKOPS_STATUS = 0x05,
904
+ QUERY_ATTR_IDN_PURGE_STATUS = 0x06,
905
+ QUERY_ATTR_IDN_MAX_DATA_IN = 0x07,
906
+ QUERY_ATTR_IDN_MAX_DATA_OUT = 0x08,
907
+ QUERY_ATTR_IDN_DYN_CAP_NEEDED = 0x09,
908
+ QUERY_ATTR_IDN_REF_CLK_FREQ = 0x0A,
909
+ QUERY_ATTR_IDN_CONF_DESC_LOCK = 0x0B,
910
+ QUERY_ATTR_IDN_MAX_NUM_OF_RTT = 0x0C,
911
+ QUERY_ATTR_IDN_EE_CONTROL = 0x0D,
912
+ QUERY_ATTR_IDN_EE_STATUS = 0x0E,
913
+ QUERY_ATTR_IDN_SECONDS_PASSED = 0x0F,
914
+ QUERY_ATTR_IDN_CNTX_CONF = 0x10,
915
+ QUERY_ATTR_IDN_CORR_PRG_BLK_NUM = 0x11,
916
+ QUERY_ATTR_IDN_RESERVED2 = 0x12,
917
+ QUERY_ATTR_IDN_RESERVED3 = 0x13,
918
+ QUERY_ATTR_IDN_FFU_STATUS = 0x14,
919
+ QUERY_ATTR_IDN_PSA_STATE = 0x15,
920
+ QUERY_ATTR_IDN_PSA_DATA_SIZE = 0x16,
921
+ QUERY_ATTR_IDN_REF_CLK_GATING_WAIT_TIME = 0x17,
922
+ QUERY_ATTR_IDN_CASE_ROUGH_TEMP = 0x18,
923
+ QUERY_ATTR_IDN_HIGH_TEMP_BOUND = 0x19,
924
+ QUERY_ATTR_IDN_LOW_TEMP_BOUND = 0x1A,
925
+ QUERY_ATTR_IDN_THROTTLING_STATUS = 0x1B,
926
+ QUERY_ATTR_IDN_WB_FLUSH_STATUS = 0x1C,
927
+ QUERY_ATTR_IDN_AVAIL_WB_BUFF_SIZE = 0x1D,
928
+ QUERY_ATTR_IDN_WB_BUFF_LIFE_TIME_EST = 0x1E,
929
+ QUERY_ATTR_IDN_CURR_WB_BUFF_SIZE = 0x1F,
930
+ QUERY_ATTR_IDN_REFRESH_STATUS = 0x2C,
931
+ QUERY_ATTR_IDN_REFRESH_FREQ = 0x2D,
932
+ QUERY_ATTR_IDN_REFRESH_UNIT = 0x2E,
933
+ QUERY_ATTR_IDN_COUNT,
934
+};
935
+
936
+/* Descriptor idn for Query requests */
937
+enum desc_idn {
938
+ QUERY_DESC_IDN_DEVICE = 0x0,
939
+ QUERY_DESC_IDN_CONFIGURATION = 0x1,
940
+ QUERY_DESC_IDN_UNIT = 0x2,
941
+ QUERY_DESC_IDN_RFU_0 = 0x3,
942
+ QUERY_DESC_IDN_INTERCONNECT = 0x4,
943
+ QUERY_DESC_IDN_STRING = 0x5,
944
+ QUERY_DESC_IDN_RFU_1 = 0x6,
945
+ QUERY_DESC_IDN_GEOMETRY = 0x7,
946
+ QUERY_DESC_IDN_POWER = 0x8,
947
+ QUERY_DESC_IDN_HEALTH = 0x9,
948
+ QUERY_DESC_IDN_MAX,
949
+};
950
+
951
+enum desc_header_offset {
952
+ QUERY_DESC_LENGTH_OFFSET = 0x00,
953
+ QUERY_DESC_DESC_TYPE_OFFSET = 0x01,
954
+};
955
+
956
+/* Unit descriptor parameters offsets in bytes*/
957
+enum unit_desc_param {
958
+ UNIT_DESC_PARAM_LEN = 0x0,
959
+ UNIT_DESC_PARAM_TYPE = 0x1,
960
+ UNIT_DESC_PARAM_UNIT_INDEX = 0x2,
961
+ UNIT_DESC_PARAM_LU_ENABLE = 0x3,
962
+ UNIT_DESC_PARAM_BOOT_LUN_ID = 0x4,
963
+ UNIT_DESC_PARAM_LU_WR_PROTECT = 0x5,
964
+ UNIT_DESC_PARAM_LU_Q_DEPTH = 0x6,
965
+ UNIT_DESC_PARAM_PSA_SENSITIVE = 0x7,
966
+ UNIT_DESC_PARAM_MEM_TYPE = 0x8,
967
+ UNIT_DESC_PARAM_DATA_RELIABILITY = 0x9,
968
+ UNIT_DESC_PARAM_LOGICAL_BLK_SIZE = 0xA,
969
+ UNIT_DESC_PARAM_LOGICAL_BLK_COUNT = 0xB,
970
+ UNIT_DESC_PARAM_ERASE_BLK_SIZE = 0x13,
971
+ UNIT_DESC_PARAM_PROVISIONING_TYPE = 0x17,
972
+ UNIT_DESC_PARAM_PHY_MEM_RSRC_CNT = 0x18,
973
+ UNIT_DESC_PARAM_CTX_CAPABILITIES = 0x20,
974
+ UNIT_DESC_PARAM_LARGE_UNIT_SIZE_M1 = 0x22,
975
+ UNIT_DESC_PARAM_HPB_LU_MAX_ACTIVE_RGNS = 0x23,
976
+ UNIT_DESC_PARAM_HPB_PIN_RGN_START_OFF = 0x25,
977
+ UNIT_DESC_PARAM_HPB_NUM_PIN_RGNS = 0x27,
978
+ UNIT_DESC_PARAM_WB_BUF_ALLOC_UNITS = 0x29,
979
+};
980
+
981
+/* RPMB Unit descriptor parameters offsets in bytes*/
982
+enum rpmb_unit_desc_param {
983
+ RPMB_UNIT_DESC_PARAM_LEN = 0x0,
984
+ RPMB_UNIT_DESC_PARAM_TYPE = 0x1,
985
+ RPMB_UNIT_DESC_PARAM_UNIT_INDEX = 0x2,
986
+ RPMB_UNIT_DESC_PARAM_LU_ENABLE = 0x3,
987
+ RPMB_UNIT_DESC_PARAM_BOOT_LUN_ID = 0x4,
988
+ RPMB_UNIT_DESC_PARAM_LU_WR_PROTECT = 0x5,
989
+ RPMB_UNIT_DESC_PARAM_LU_Q_DEPTH = 0x6,
990
+ RPMB_UNIT_DESC_PARAM_PSA_SENSITIVE = 0x7,
991
+ RPMB_UNIT_DESC_PARAM_MEM_TYPE = 0x8,
992
+ RPMB_UNIT_DESC_PARAM_REGION_EN = 0x9,
993
+ RPMB_UNIT_DESC_PARAM_LOGICAL_BLK_SIZE = 0xA,
994
+ RPMB_UNIT_DESC_PARAM_LOGICAL_BLK_COUNT = 0xB,
995
+ RPMB_UNIT_DESC_PARAM_REGION0_SIZE = 0x13,
996
+ RPMB_UNIT_DESC_PARAM_REGION1_SIZE = 0x14,
997
+ RPMB_UNIT_DESC_PARAM_REGION2_SIZE = 0x15,
998
+ RPMB_UNIT_DESC_PARAM_REGION3_SIZE = 0x16,
999
+ RPMB_UNIT_DESC_PARAM_PROVISIONING_TYPE = 0x17,
1000
+ RPMB_UNIT_DESC_PARAM_PHY_MEM_RSRC_CNT = 0x18,
1001
+};
1002
+
1003
+/* Device descriptor parameters offsets in bytes*/
1004
+enum device_desc_param {
1005
+ DEVICE_DESC_PARAM_LEN = 0x0,
1006
+ DEVICE_DESC_PARAM_TYPE = 0x1,
1007
+ DEVICE_DESC_PARAM_DEVICE_TYPE = 0x2,
1008
+ DEVICE_DESC_PARAM_DEVICE_CLASS = 0x3,
1009
+ DEVICE_DESC_PARAM_DEVICE_SUB_CLASS = 0x4,
1010
+ DEVICE_DESC_PARAM_PRTCL = 0x5,
1011
+ DEVICE_DESC_PARAM_NUM_LU = 0x6,
1012
+ DEVICE_DESC_PARAM_NUM_WLU = 0x7,
1013
+ DEVICE_DESC_PARAM_BOOT_ENBL = 0x8,
1014
+ DEVICE_DESC_PARAM_DESC_ACCSS_ENBL = 0x9,
1015
+ DEVICE_DESC_PARAM_INIT_PWR_MODE = 0xA,
1016
+ DEVICE_DESC_PARAM_HIGH_PR_LUN = 0xB,
1017
+ DEVICE_DESC_PARAM_SEC_RMV_TYPE = 0xC,
1018
+ DEVICE_DESC_PARAM_SEC_LU = 0xD,
1019
+ DEVICE_DESC_PARAM_BKOP_TERM_LT = 0xE,
1020
+ DEVICE_DESC_PARAM_ACTVE_ICC_LVL = 0xF,
1021
+ DEVICE_DESC_PARAM_SPEC_VER = 0x10,
1022
+ DEVICE_DESC_PARAM_MANF_DATE = 0x12,
1023
+ DEVICE_DESC_PARAM_MANF_NAME = 0x14,
1024
+ DEVICE_DESC_PARAM_PRDCT_NAME = 0x15,
1025
+ DEVICE_DESC_PARAM_SN = 0x16,
1026
+ DEVICE_DESC_PARAM_OEM_ID = 0x17,
1027
+ DEVICE_DESC_PARAM_MANF_ID = 0x18,
1028
+ DEVICE_DESC_PARAM_UD_OFFSET = 0x1A,
1029
+ DEVICE_DESC_PARAM_UD_LEN = 0x1B,
1030
+ DEVICE_DESC_PARAM_RTT_CAP = 0x1C,
1031
+ DEVICE_DESC_PARAM_FRQ_RTC = 0x1D,
1032
+ DEVICE_DESC_PARAM_UFS_FEAT = 0x1F,
1033
+ DEVICE_DESC_PARAM_FFU_TMT = 0x20,
1034
+ DEVICE_DESC_PARAM_Q_DPTH = 0x21,
1035
+ DEVICE_DESC_PARAM_DEV_VER = 0x22,
1036
+ DEVICE_DESC_PARAM_NUM_SEC_WPA = 0x24,
1037
+ DEVICE_DESC_PARAM_PSA_MAX_DATA = 0x25,
1038
+ DEVICE_DESC_PARAM_PSA_TMT = 0x29,
1039
+ DEVICE_DESC_PARAM_PRDCT_REV = 0x2A,
1040
+ DEVICE_DESC_PARAM_HPB_VER = 0x40,
1041
+ DEVICE_DESC_PARAM_HPB_CONTROL = 0x42,
1042
+ DEVICE_DESC_PARAM_EXT_UFS_FEATURE_SUP = 0x4F,
1043
+ DEVICE_DESC_PARAM_WB_PRESRV_USRSPC_EN = 0x53,
1044
+ DEVICE_DESC_PARAM_WB_TYPE = 0x54,
1045
+ DEVICE_DESC_PARAM_WB_SHARED_ALLOC_UNITS = 0x55,
1046
+};
1047
+
1048
+/* Interconnect descriptor parameters offsets in bytes*/
1049
+enum interconnect_desc_param {
1050
+ INTERCONNECT_DESC_PARAM_LEN = 0x0,
1051
+ INTERCONNECT_DESC_PARAM_TYPE = 0x1,
1052
+ INTERCONNECT_DESC_PARAM_UNIPRO_VER = 0x2,
1053
+ INTERCONNECT_DESC_PARAM_MPHY_VER = 0x4,
1054
+};
1055
+
1056
+/* Geometry descriptor parameters offsets in bytes*/
1057
+enum geometry_desc_param {
1058
+ GEOMETRY_DESC_PARAM_LEN = 0x0,
1059
+ GEOMETRY_DESC_PARAM_TYPE = 0x1,
1060
+ GEOMETRY_DESC_PARAM_DEV_CAP = 0x4,
1061
+ GEOMETRY_DESC_PARAM_MAX_NUM_LUN = 0xC,
1062
+ GEOMETRY_DESC_PARAM_SEG_SIZE = 0xD,
1063
+ GEOMETRY_DESC_PARAM_ALLOC_UNIT_SIZE = 0x11,
1064
+ GEOMETRY_DESC_PARAM_MIN_BLK_SIZE = 0x12,
1065
+ GEOMETRY_DESC_PARAM_OPT_RD_BLK_SIZE = 0x13,
1066
+ GEOMETRY_DESC_PARAM_OPT_WR_BLK_SIZE = 0x14,
1067
+ GEOMETRY_DESC_PARAM_MAX_IN_BUF_SIZE = 0x15,
1068
+ GEOMETRY_DESC_PARAM_MAX_OUT_BUF_SIZE = 0x16,
1069
+ GEOMETRY_DESC_PARAM_RPMB_RW_SIZE = 0x17,
1070
+ GEOMETRY_DESC_PARAM_DYN_CAP_RSRC_PLC = 0x18,
1071
+ GEOMETRY_DESC_PARAM_DATA_ORDER = 0x19,
1072
+ GEOMETRY_DESC_PARAM_MAX_NUM_CTX = 0x1A,
1073
+ GEOMETRY_DESC_PARAM_TAG_UNIT_SIZE = 0x1B,
1074
+ GEOMETRY_DESC_PARAM_TAG_RSRC_SIZE = 0x1C,
1075
+ GEOMETRY_DESC_PARAM_SEC_RM_TYPES = 0x1D,
1076
+ GEOMETRY_DESC_PARAM_MEM_TYPES = 0x1E,
1077
+ GEOMETRY_DESC_PARAM_SCM_MAX_NUM_UNITS = 0x20,
1078
+ GEOMETRY_DESC_PARAM_SCM_CAP_ADJ_FCTR = 0x24,
1079
+ GEOMETRY_DESC_PARAM_NPM_MAX_NUM_UNITS = 0x26,
1080
+ GEOMETRY_DESC_PARAM_NPM_CAP_ADJ_FCTR = 0x2A,
1081
+ GEOMETRY_DESC_PARAM_ENM1_MAX_NUM_UNITS = 0x2C,
1082
+ GEOMETRY_DESC_PARAM_ENM1_CAP_ADJ_FCTR = 0x30,
1083
+ GEOMETRY_DESC_PARAM_ENM2_MAX_NUM_UNITS = 0x32,
1084
+ GEOMETRY_DESC_PARAM_ENM2_CAP_ADJ_FCTR = 0x36,
1085
+ GEOMETRY_DESC_PARAM_ENM3_MAX_NUM_UNITS = 0x38,
1086
+ GEOMETRY_DESC_PARAM_ENM3_CAP_ADJ_FCTR = 0x3C,
1087
+ GEOMETRY_DESC_PARAM_ENM4_MAX_NUM_UNITS = 0x3E,
1088
+ GEOMETRY_DESC_PARAM_ENM4_CAP_ADJ_FCTR = 0x42,
1089
+ GEOMETRY_DESC_PARAM_OPT_LOG_BLK_SIZE = 0x44,
1090
+ GEOMETRY_DESC_PARAM_HPB_REGION_SIZE = 0x48,
1091
+ GEOMETRY_DESC_PARAM_HPB_NUMBER_LU = 0x49,
1092
+ GEOMETRY_DESC_PARAM_HPB_SUBREGION_SIZE = 0x4A,
1093
+ GEOMETRY_DESC_PARAM_HPB_MAX_ACTIVE_REGS = 0x4B,
1094
+ GEOMETRY_DESC_PARAM_WB_MAX_ALLOC_UNITS = 0x4F,
1095
+ GEOMETRY_DESC_PARAM_WB_MAX_WB_LUNS = 0x53,
1096
+ GEOMETRY_DESC_PARAM_WB_BUFF_CAP_ADJ = 0x54,
1097
+ GEOMETRY_DESC_PARAM_WB_SUP_RED_TYPE = 0x55,
1098
+ GEOMETRY_DESC_PARAM_WB_SUP_WB_TYPE = 0x56,
1099
+};
1100
+
1101
+/* Health descriptor parameters offsets in bytes*/
1102
+enum health_desc_param {
1103
+ HEALTH_DESC_PARAM_LEN = 0x0,
1104
+ HEALTH_DESC_PARAM_TYPE = 0x1,
1105
+ HEALTH_DESC_PARAM_EOL_INFO = 0x2,
1106
+ HEALTH_DESC_PARAM_LIFE_TIME_EST_A = 0x3,
1107
+ HEALTH_DESC_PARAM_LIFE_TIME_EST_B = 0x4,
1108
+};
1109
+
1110
+/* WriteBooster buffer mode */
1111
+enum {
1112
+ WB_BUF_MODE_LU_DEDICATED = 0x0,
1113
+ WB_BUF_MODE_SHARED = 0x1,
1114
+};
1115
+
1116
+/*
1117
+ * Logical Unit Write Protect
1118
+ * 00h: LU not write protected
1119
+ * 01h: LU write protected when fPowerOnWPEn =1
1120
+ * 02h: LU permanently write protected when fPermanentWPEn =1
1121
+ */
1122
+enum ufs_lu_wp_type {
1123
+ UFS_LU_NO_WP = 0x00,
1124
+ UFS_LU_POWER_ON_WP = 0x01,
1125
+ UFS_LU_PERM_WP = 0x02,
1126
+};
1127
+
1128
+/* UTP QUERY Transaction Specific Fields OpCode */
1129
+enum query_opcode {
1130
+ UPIU_QUERY_OPCODE_NOP = 0x0,
1131
+ UPIU_QUERY_OPCODE_READ_DESC = 0x1,
1132
+ UPIU_QUERY_OPCODE_WRITE_DESC = 0x2,
1133
+ UPIU_QUERY_OPCODE_READ_ATTR = 0x3,
1134
+ UPIU_QUERY_OPCODE_WRITE_ATTR = 0x4,
1135
+ UPIU_QUERY_OPCODE_READ_FLAG = 0x5,
1136
+ UPIU_QUERY_OPCODE_SET_FLAG = 0x6,
1137
+ UPIU_QUERY_OPCODE_CLEAR_FLAG = 0x7,
1138
+ UPIU_QUERY_OPCODE_TOGGLE_FLAG = 0x8,
1139
+};
1140
+
1141
+/* Query response result code */
1142
+typedef enum QueryRespCode {
1143
+ QUERY_RESULT_SUCCESS = 0x00,
1144
+ QUERY_RESULT_NOT_READABLE = 0xF6,
1145
+ QUERY_RESULT_NOT_WRITEABLE = 0xF7,
1146
+ QUERY_RESULT_ALREADY_WRITTEN = 0xF8,
1147
+ QUERY_RESULT_INVALID_LENGTH = 0xF9,
1148
+ QUERY_RESULT_INVALID_VALUE = 0xFA,
1149
+ QUERY_RESULT_INVALID_SELECTOR = 0xFB,
1150
+ QUERY_RESULT_INVALID_INDEX = 0xFC,
1151
+ QUERY_RESULT_INVALID_IDN = 0xFD,
1152
+ QUERY_RESULT_INVALID_OPCODE = 0xFE,
1153
+ QUERY_RESULT_GENERAL_FAILURE = 0xFF,
1154
+} QueryRespCode;
1155
+
1156
+/* UTP Transfer Request Command Type (CT) */
1157
+enum {
1158
+ UPIU_COMMAND_SET_TYPE_SCSI = 0x0,
1159
+ UPIU_COMMAND_SET_TYPE_UFS = 0x1,
1160
+ UPIU_COMMAND_SET_TYPE_QUERY = 0x2,
1161
+};
1162
+
1163
+/* Task management service response */
1164
+enum {
1165
+ UPIU_TASK_MANAGEMENT_FUNC_COMPL = 0x00,
1166
+ UPIU_TASK_MANAGEMENT_FUNC_NOT_SUPPORTED = 0x04,
1167
+ UPIU_TASK_MANAGEMENT_FUNC_SUCCEEDED = 0x08,
1168
+ UPIU_TASK_MANAGEMENT_FUNC_FAILED = 0x05,
1169
+ UPIU_INCORRECT_LOGICAL_UNIT_NO = 0x09,
1170
+};
1171
+
1172
+/* UFS device power modes */
1173
+enum ufs_dev_pwr_mode {
1174
+ UFS_ACTIVE_PWR_MODE = 1,
1175
+ UFS_SLEEP_PWR_MODE = 2,
1176
+ UFS_POWERDOWN_PWR_MODE = 3,
1177
+ UFS_DEEPSLEEP_PWR_MODE = 4,
1178
+};
1179
+
1180
+/*
1181
+ * struct UtpCmdRsp - Response UPIU structure
1182
+ * @residual_transfer_count: Residual transfer count DW-3
1183
+ * @reserved: Reserved double words DW-4 to DW-7
1184
+ * @sense_data_len: Sense data length DW-8 U16
1185
+ * @sense_data: Sense data field DW-8 to DW-12
1186
+ */
1187
+typedef struct QEMU_PACKED UtpCmdRsp {
1188
+ uint32_t residual_transfer_count;
1189
+ uint32_t reserved[4];
1190
+ uint16_t sense_data_len;
1191
+ uint8_t sense_data[UFS_SENSE_SIZE];
1192
+} UtpCmdRsp;
1193
+
1194
+/*
1195
+ * struct UtpUpiuRsp - general upiu response structure
1196
+ * @header: UPIU header structure DW-0 to DW-2
1197
+ * @sr: fields structure for scsi command DW-3 to DW-12
1198
+ * @qr: fields structure for query request DW-3 to DW-7
1199
+ */
1200
+typedef struct QEMU_PACKED UtpUpiuRsp {
1201
+ UtpUpiuHeader header;
1202
+ union {
1203
+ UtpCmdRsp sr;
1204
+ UtpUpiuQuery qr;
1205
+ };
1206
+} UtpUpiuRsp;
1207
+
1208
+static inline void _ufs_check_size(void)
1209
+{
1210
+ QEMU_BUILD_BUG_ON(sizeof(UfsReg) != 0x104);
1211
+ QEMU_BUILD_BUG_ON(sizeof(DeviceDescriptor) != 89);
1212
+ QEMU_BUILD_BUG_ON(sizeof(GeometryDescriptor) != 87);
1213
+ QEMU_BUILD_BUG_ON(sizeof(UnitDescriptor) != 45);
1214
+ QEMU_BUILD_BUG_ON(sizeof(RpmbUnitDescriptor) != 35);
1215
+ QEMU_BUILD_BUG_ON(sizeof(PowerParametersDescriptor) != 98);
1216
+ QEMU_BUILD_BUG_ON(sizeof(InterconnectDescriptor) != 6);
1217
+ QEMU_BUILD_BUG_ON(sizeof(StringDescriptor) != 254);
1218
+ QEMU_BUILD_BUG_ON(sizeof(DeviceHealthDescriptor) != 45);
1219
+ QEMU_BUILD_BUG_ON(sizeof(Flags) != 0x13);
1220
+ QEMU_BUILD_BUG_ON(sizeof(UtpUpiuHeader) != 12);
1221
+ QEMU_BUILD_BUG_ON(sizeof(UtpUpiuQuery) != 276);
1222
+ QEMU_BUILD_BUG_ON(sizeof(UtpUpiuCmd) != 20);
1223
+ QEMU_BUILD_BUG_ON(sizeof(UtpUpiuReq) != 288);
1224
+ QEMU_BUILD_BUG_ON(sizeof(UfshcdSgEntry) != 16);
1225
+ QEMU_BUILD_BUG_ON(sizeof(RequestDescHeader) != 16);
1226
+ QEMU_BUILD_BUG_ON(sizeof(UtpTransferReqDesc) != 32);
1227
+ QEMU_BUILD_BUG_ON(sizeof(UtpTaskReqDesc) != 80);
1228
+ QEMU_BUILD_BUG_ON(sizeof(UtpCmdRsp) != 40);
1229
+ QEMU_BUILD_BUG_ON(sizeof(UtpUpiuRsp) != 288);
1230
+}
1231
+#endif
1232
diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h
1233
index XXXXXXX..XXXXXXX 100644
1234
--- a/include/hw/pci/pci.h
1235
+++ b/include/hw/pci/pci.h
1236
@@ -XXX,XX +XXX,XX @@ extern bool pci_available;
1237
#define PCI_DEVICE_ID_REDHAT_NVME 0x0010
1238
#define PCI_DEVICE_ID_REDHAT_PVPANIC 0x0011
1239
#define PCI_DEVICE_ID_REDHAT_ACPI_ERST 0x0012
1240
+#define PCI_DEVICE_ID_REDHAT_UFS 0x0013
1241
#define PCI_DEVICE_ID_REDHAT_QXL 0x0100
1242
1243
#define FMT_PCIBUS PRIx64
1244
diff --git a/include/hw/pci/pci_ids.h b/include/hw/pci/pci_ids.h
1245
index XXXXXXX..XXXXXXX 100644
1246
--- a/include/hw/pci/pci_ids.h
1247
+++ b/include/hw/pci/pci_ids.h
1248
@@ -XXX,XX +XXX,XX @@
1249
#define PCI_CLASS_STORAGE_SATA 0x0106
1250
#define PCI_CLASS_STORAGE_SAS 0x0107
1251
#define PCI_CLASS_STORAGE_EXPRESS 0x0108
1252
+#define PCI_CLASS_STORAGE_UFS 0x0109
1253
#define PCI_CLASS_STORAGE_OTHER 0x0180
1254
1255
#define PCI_BASE_CLASS_NETWORK 0x02
1256
diff --git a/hw/ufs/ufs.c b/hw/ufs/ufs.c
1257
new file mode 100644
1258
index XXXXXXX..XXXXXXX
1259
--- /dev/null
1260
+++ b/hw/ufs/ufs.c
1261
@@ -XXX,XX +XXX,XX @@
1262
+/*
1263
+ * QEMU Universal Flash Storage (UFS) Controller
158
+ *
1264
+ *
159
+ * The above copyright notice and this permission notice shall be included in
1265
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd. All rights reserved.
160
+ * all copies or substantial portions of the Software.
161
+ *
1266
+ *
162
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1267
+ * Written by Jeuk Kim <jeuk20.kim@samsung.com>
163
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1268
+ *
164
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
1269
+ * SPDX-License-Identifier: GPL-2.0-or-later
165
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
166
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
167
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
168
+ * THE SOFTWARE.
169
+ */
1270
+ */
170
+
1271
+
171
+#include "qemu/osdep.h"
1272
+#include "qemu/osdep.h"
172
+#include "block/block_int.h"
173
+#include "qemu/job.h"
174
+#include "qemu/main-loop.h"
175
+#include "qapi/qapi-commands-block-core.h"
176
+#include "qapi/qapi-visit-block-core.h"
177
+#include "qapi/clone-visitor.h"
178
+#include "qapi/error.h"
1273
+#include "qapi/error.h"
179
+
1274
+#include "migration/vmstate.h"
180
+typedef struct BlockdevAmendJob {
1275
+#include "trace.h"
181
+ Job common;
1276
+#include "ufs.h"
182
+ BlockdevAmendOptions *opts;
1277
+
183
+ BlockDriverState *bs;
1278
+/* The QEMU-UFS device follows spec version 3.1 */
184
+ bool force;
1279
+#define UFS_SPEC_VER 0x00000310
185
+} BlockdevAmendJob;
1280
+#define UFS_MAX_NUTRS 32
186
+
1281
+#define UFS_MAX_NUTMRS 8
187
+static int coroutine_fn blockdev_amend_run(Job *job, Error **errp)
1282
+
1283
+static void ufs_irq_check(UfsHc *u)
188
+{
1284
+{
189
+ BlockdevAmendJob *s = container_of(job, BlockdevAmendJob, common);
1285
+ PCIDevice *pci = PCI_DEVICE(u);
190
+ int ret;
1286
+
191
+
1287
+ if ((u->reg.is & UFS_INTR_MASK) & u->reg.ie) {
192
+ job_progress_set_remaining(&s->common, 1);
1288
+ trace_ufs_irq_raise();
193
+ ret = s->bs->drv->bdrv_co_amend(s->bs, s->opts, s->force, errp);
1289
+ pci_irq_assert(pci);
194
+ job_progress_update(&s->common, 1);
1290
+ } else {
195
+ qapi_free_BlockdevAmendOptions(s->opts);
1291
+ trace_ufs_irq_lower();
196
+ return ret;
1292
+ pci_irq_deassert(pci);
1293
+ }
197
+}
1294
+}
198
+
1295
+
199
+static const JobDriver blockdev_amend_job_driver = {
1296
+static void ufs_process_uiccmd(UfsHc *u, uint32_t val)
200
+ .instance_size = sizeof(BlockdevAmendJob),
201
+ .job_type = JOB_TYPE_AMEND,
202
+ .run = blockdev_amend_run,
203
+};
204
+
205
+void qmp_x_blockdev_amend(const char *job_id,
206
+ const char *node_name,
207
+ BlockdevAmendOptions *options,
208
+ bool has_force,
209
+ bool force,
210
+ Error **errp)
211
+{
1297
+{
212
+ BlockdevAmendJob *s;
1298
+ trace_ufs_process_uiccmd(val, u->reg.ucmdarg1, u->reg.ucmdarg2,
213
+ const char *fmt = BlockdevDriver_str(options->driver);
1299
+ u->reg.ucmdarg3);
214
+ BlockDriver *drv = bdrv_find_format(fmt);
1300
+ /*
215
+ BlockDriverState *bs = bdrv_find_node(node_name);
1301
+ * Only the essential uic commands for running drivers on Linux and Windows
216
+
1302
+ * are implemented.
217
+
1303
+ */
218
+ if (!drv) {
1304
+ switch (val) {
219
+ error_setg(errp, "Block driver '%s' not found or not supported", fmt);
1305
+ case UIC_CMD_DME_LINK_STARTUP:
1306
+ u->reg.hcs = FIELD_DP32(u->reg.hcs, HCS, DP, 1);
1307
+ u->reg.hcs = FIELD_DP32(u->reg.hcs, HCS, UTRLRDY, 1);
1308
+ u->reg.hcs = FIELD_DP32(u->reg.hcs, HCS, UTMRLRDY, 1);
1309
+ u->reg.ucmdarg2 = UIC_CMD_RESULT_SUCCESS;
1310
+ break;
1311
+ /* TODO: Revisit it when Power Management is implemented */
1312
+ case UIC_CMD_DME_HIBER_ENTER:
1313
+ u->reg.is = FIELD_DP32(u->reg.is, IS, UHES, 1);
1314
+ u->reg.hcs = FIELD_DP32(u->reg.hcs, HCS, UPMCRS, PWR_LOCAL);
1315
+ u->reg.ucmdarg2 = UIC_CMD_RESULT_SUCCESS;
1316
+ break;
1317
+ case UIC_CMD_DME_HIBER_EXIT:
1318
+ u->reg.is = FIELD_DP32(u->reg.is, IS, UHXS, 1);
1319
+ u->reg.hcs = FIELD_DP32(u->reg.hcs, HCS, UPMCRS, PWR_LOCAL);
1320
+ u->reg.ucmdarg2 = UIC_CMD_RESULT_SUCCESS;
1321
+ break;
1322
+ default:
1323
+ u->reg.ucmdarg2 = UIC_CMD_RESULT_FAILURE;
1324
+ }
1325
+
1326
+ u->reg.is = FIELD_DP32(u->reg.is, IS, UCCS, 1);
1327
+
1328
+ ufs_irq_check(u);
1329
+}
1330
+
1331
+static void ufs_write_reg(UfsHc *u, hwaddr offset, uint32_t data, unsigned size)
1332
+{
1333
+ switch (offset) {
1334
+ case A_IS:
1335
+ u->reg.is &= ~data;
1336
+ ufs_irq_check(u);
1337
+ break;
1338
+ case A_IE:
1339
+ u->reg.ie = data;
1340
+ ufs_irq_check(u);
1341
+ break;
1342
+ case A_HCE:
1343
+ if (!FIELD_EX32(u->reg.hce, HCE, HCE) && FIELD_EX32(data, HCE, HCE)) {
1344
+ u->reg.hcs = FIELD_DP32(u->reg.hcs, HCS, UCRDY, 1);
1345
+ u->reg.hce = FIELD_DP32(u->reg.hce, HCE, HCE, 1);
1346
+ } else if (FIELD_EX32(u->reg.hce, HCE, HCE) &&
1347
+ !FIELD_EX32(data, HCE, HCE)) {
1348
+ u->reg.hcs = 0;
1349
+ u->reg.hce = FIELD_DP32(u->reg.hce, HCE, HCE, 0);
1350
+ }
1351
+ break;
1352
+ case A_UTRLBA:
1353
+ u->reg.utrlba = data & R_UTRLBA_UTRLBA_MASK;
1354
+ break;
1355
+ case A_UTRLBAU:
1356
+ u->reg.utrlbau = data;
1357
+ break;
1358
+ case A_UTRLDBR:
1359
+ /* Not yet supported */
1360
+ break;
1361
+ case A_UTRLRSR:
1362
+ u->reg.utrlrsr = data;
1363
+ break;
1364
+ case A_UTRLCNR:
1365
+ u->reg.utrlcnr &= ~data;
1366
+ break;
1367
+ case A_UTMRLBA:
1368
+ u->reg.utmrlba = data & R_UTMRLBA_UTMRLBA_MASK;
1369
+ break;
1370
+ case A_UTMRLBAU:
1371
+ u->reg.utmrlbau = data;
1372
+ break;
1373
+ case A_UICCMD:
1374
+ ufs_process_uiccmd(u, data);
1375
+ break;
1376
+ case A_UCMDARG1:
1377
+ u->reg.ucmdarg1 = data;
1378
+ break;
1379
+ case A_UCMDARG2:
1380
+ u->reg.ucmdarg2 = data;
1381
+ break;
1382
+ case A_UCMDARG3:
1383
+ u->reg.ucmdarg3 = data;
1384
+ break;
1385
+ case A_UTRLCLR:
1386
+ case A_UTMRLDBR:
1387
+ case A_UTMRLCLR:
1388
+ case A_UTMRLRSR:
1389
+ trace_ufs_err_unsupport_register_offset(offset);
1390
+ break;
1391
+ default:
1392
+ trace_ufs_err_invalid_register_offset(offset);
1393
+ break;
1394
+ }
1395
+}
1396
+
1397
+static uint64_t ufs_mmio_read(void *opaque, hwaddr addr, unsigned size)
1398
+{
1399
+ UfsHc *u = (UfsHc *)opaque;
1400
+ uint8_t *ptr = (uint8_t *)&u->reg;
1401
+ uint64_t value;
1402
+
1403
+ if (addr > sizeof(u->reg) - size) {
1404
+ trace_ufs_err_invalid_register_offset(addr);
1405
+ return 0;
1406
+ }
1407
+
1408
+ value = *(uint32_t *)(ptr + addr);
1409
+ trace_ufs_mmio_read(addr, value, size);
1410
+ return value;
1411
+}
1412
+
1413
+static void ufs_mmio_write(void *opaque, hwaddr addr, uint64_t data,
1414
+ unsigned size)
1415
+{
1416
+ UfsHc *u = (UfsHc *)opaque;
1417
+
1418
+ if (addr > sizeof(u->reg) - size) {
1419
+ trace_ufs_err_invalid_register_offset(addr);
220
+ return;
1420
+ return;
221
+ }
1421
+ }
222
+
1422
+
223
+ /*
1423
+ trace_ufs_mmio_write(addr, data, size);
224
+ * If the driver is in the schema, we know that it exists. But it may not
1424
+ ufs_write_reg(u, addr, data, size);
225
+ * be whitelisted.
1425
+}
226
+ */
1426
+
227
+ if (bdrv_uses_whitelist() && !bdrv_is_whitelisted(drv, false)) {
1427
+static const MemoryRegionOps ufs_mmio_ops = {
228
+ error_setg(errp, "Driver is not whitelisted");
1428
+ .read = ufs_mmio_read,
1429
+ .write = ufs_mmio_write,
1430
+ .endianness = DEVICE_LITTLE_ENDIAN,
1431
+ .impl = {
1432
+ .min_access_size = 4,
1433
+ .max_access_size = 4,
1434
+ },
1435
+};
1436
+
1437
+static bool ufs_check_constraints(UfsHc *u, Error **errp)
1438
+{
1439
+ if (u->params.nutrs > UFS_MAX_NUTRS) {
1440
+ error_setg(errp, "nutrs must be less than or equal to %d",
1441
+ UFS_MAX_NUTRS);
1442
+ return false;
1443
+ }
1444
+
1445
+ if (u->params.nutmrs > UFS_MAX_NUTMRS) {
1446
+ error_setg(errp, "nutmrs must be less than or equal to %d",
1447
+ UFS_MAX_NUTMRS);
1448
+ return false;
1449
+ }
1450
+
1451
+ return true;
1452
+}
1453
+
1454
+static void ufs_init_pci(UfsHc *u, PCIDevice *pci_dev)
1455
+{
1456
+ uint8_t *pci_conf = pci_dev->config;
1457
+
1458
+ pci_conf[PCI_INTERRUPT_PIN] = 1;
1459
+ pci_config_set_prog_interface(pci_conf, 0x1);
1460
+
1461
+ memory_region_init_io(&u->iomem, OBJECT(u), &ufs_mmio_ops, u, "ufs",
1462
+ u->reg_size);
1463
+ pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &u->iomem);
1464
+ u->irq = pci_allocate_irq(pci_dev);
1465
+}
1466
+
1467
+static void ufs_init_hc(UfsHc *u)
1468
+{
1469
+ uint32_t cap = 0;
1470
+
1471
+ u->reg_size = pow2ceil(sizeof(UfsReg));
1472
+
1473
+ memset(&u->reg, 0, sizeof(u->reg));
1474
+ cap = FIELD_DP32(cap, CAP, NUTRS, (u->params.nutrs - 1));
1475
+ cap = FIELD_DP32(cap, CAP, RTT, 2);
1476
+ cap = FIELD_DP32(cap, CAP, NUTMRS, (u->params.nutmrs - 1));
1477
+ cap = FIELD_DP32(cap, CAP, AUTOH8, 0);
1478
+ cap = FIELD_DP32(cap, CAP, 64AS, 1);
1479
+ cap = FIELD_DP32(cap, CAP, OODDS, 0);
1480
+ cap = FIELD_DP32(cap, CAP, UICDMETMS, 0);
1481
+ cap = FIELD_DP32(cap, CAP, CS, 0);
1482
+ u->reg.cap = cap;
1483
+ u->reg.ver = UFS_SPEC_VER;
1484
+}
1485
+
1486
+static void ufs_realize(PCIDevice *pci_dev, Error **errp)
1487
+{
1488
+ UfsHc *u = UFS(pci_dev);
1489
+
1490
+ if (!ufs_check_constraints(u, errp)) {
229
+ return;
1491
+ return;
230
+ }
1492
+ }
231
+
1493
+
232
+ if (bs->drv != drv) {
1494
+ ufs_init_hc(u);
233
+ error_setg(errp,
1495
+ ufs_init_pci(u, pci_dev);
234
+ "x-blockdev-amend doesn't support changing the block driver");
235
+ return;
236
+ }
237
+
238
+ /* Error out if the driver doesn't support .bdrv_co_amend */
239
+ if (!drv->bdrv_co_amend) {
240
+ error_setg(errp, "Driver does not support x-blockdev-amend");
241
+ return;
242
+ }
243
+
244
+ /* Create the block job */
245
+ s = job_create(job_id, &blockdev_amend_job_driver, NULL,
246
+ bdrv_get_aio_context(bs), JOB_DEFAULT | JOB_MANUAL_DISMISS,
247
+ NULL, NULL, errp);
248
+ if (!s) {
249
+ return;
250
+ }
251
+
252
+ s->bs = bs,
253
+ s->opts = QAPI_CLONE(BlockdevAmendOptions, options),
254
+ s->force = has_force ? force : false;
255
+ job_start(&s->common);
256
+}
1496
+}
257
diff --git a/block/Makefile.objs b/block/Makefile.objs
1497
+
1498
+static Property ufs_props[] = {
1499
+ DEFINE_PROP_STRING("serial", UfsHc, params.serial),
1500
+ DEFINE_PROP_UINT8("nutrs", UfsHc, params.nutrs, 32),
1501
+ DEFINE_PROP_UINT8("nutmrs", UfsHc, params.nutmrs, 8),
1502
+ DEFINE_PROP_END_OF_LIST(),
1503
+};
1504
+
1505
+static const VMStateDescription ufs_vmstate = {
1506
+ .name = "ufs",
1507
+ .unmigratable = 1,
1508
+};
1509
+
1510
+static void ufs_class_init(ObjectClass *oc, void *data)
1511
+{
1512
+ DeviceClass *dc = DEVICE_CLASS(oc);
1513
+ PCIDeviceClass *pc = PCI_DEVICE_CLASS(oc);
1514
+
1515
+ pc->realize = ufs_realize;
1516
+ pc->vendor_id = PCI_VENDOR_ID_REDHAT;
1517
+ pc->device_id = PCI_DEVICE_ID_REDHAT_UFS;
1518
+ pc->class_id = PCI_CLASS_STORAGE_UFS;
1519
+
1520
+ set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
1521
+ dc->desc = "Universal Flash Storage";
1522
+ device_class_set_props(dc, ufs_props);
1523
+ dc->vmsd = &ufs_vmstate;
1524
+}
1525
+
1526
+static const TypeInfo ufs_info = {
1527
+ .name = TYPE_UFS,
1528
+ .parent = TYPE_PCI_DEVICE,
1529
+ .class_init = ufs_class_init,
1530
+ .instance_size = sizeof(UfsHc),
1531
+ .interfaces = (InterfaceInfo[]){ { INTERFACE_PCIE_DEVICE }, {} },
1532
+};
1533
+
1534
+static void ufs_register_types(void)
1535
+{
1536
+ type_register_static(&ufs_info);
1537
+}
1538
+
1539
+type_init(ufs_register_types)
1540
diff --git a/hw/Kconfig b/hw/Kconfig
258
index XXXXXXX..XXXXXXX 100644
1541
index XXXXXXX..XXXXXXX 100644
259
--- a/block/Makefile.objs
1542
--- a/hw/Kconfig
260
+++ b/block/Makefile.objs
1543
+++ b/hw/Kconfig
261
@@ -XXX,XX +XXX,XX @@ block-obj-$(CONFIG_WIN32) += file-win32.o win32-aio.o
1544
@@ -XXX,XX +XXX,XX @@ source smbios/Kconfig
262
block-obj-$(CONFIG_POSIX) += file-posix.o
1545
source ssi/Kconfig
263
block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
1546
source timer/Kconfig
264
block-obj-$(CONFIG_LINUX_IO_URING) += io_uring.o
1547
source tpm/Kconfig
265
-block-obj-y += null.o mirror.o commit.o io.o create.o
1548
+source ufs/Kconfig
266
+block-obj-y += null.o mirror.o commit.o io.o create.o amend.o
1549
source usb/Kconfig
267
block-obj-y += throttle-groups.o
1550
source virtio/Kconfig
268
block-obj-$(CONFIG_LINUX) += nvme.o
1551
source vfio/Kconfig
269
1552
diff --git a/hw/meson.build b/hw/meson.build
1553
index XXXXXXX..XXXXXXX 100644
1554
--- a/hw/meson.build
1555
+++ b/hw/meson.build
1556
@@ -XXX,XX +XXX,XX @@ subdir('smbios')
1557
subdir('ssi')
1558
subdir('timer')
1559
subdir('tpm')
1560
+subdir('ufs')
1561
subdir('usb')
1562
subdir('vfio')
1563
subdir('virtio')
1564
diff --git a/hw/ufs/Kconfig b/hw/ufs/Kconfig
1565
new file mode 100644
1566
index XXXXXXX..XXXXXXX
1567
--- /dev/null
1568
+++ b/hw/ufs/Kconfig
1569
@@ -XXX,XX +XXX,XX @@
1570
+config UFS_PCI
1571
+ bool
1572
+ default y if PCI_DEVICES
1573
+ depends on PCI
1574
diff --git a/hw/ufs/meson.build b/hw/ufs/meson.build
1575
new file mode 100644
1576
index XXXXXXX..XXXXXXX
1577
--- /dev/null
1578
+++ b/hw/ufs/meson.build
1579
@@ -0,0 +1 @@
1580
+system_ss.add(when: 'CONFIG_UFS_PCI', if_true: files('ufs.c'))
1581
diff --git a/hw/ufs/trace-events b/hw/ufs/trace-events
1582
new file mode 100644
1583
index XXXXXXX..XXXXXXX
1584
--- /dev/null
1585
+++ b/hw/ufs/trace-events
1586
@@ -XXX,XX +XXX,XX @@
1587
+# ufs.c
1588
+ufs_irq_raise(void) "INTx"
1589
+ufs_irq_lower(void) "INTx"
1590
+ufs_mmio_read(uint64_t addr, uint64_t data, unsigned size) "addr 0x%"PRIx64" data 0x%"PRIx64" size %d"
1591
+ufs_mmio_write(uint64_t addr, uint64_t data, unsigned size) "addr 0x%"PRIx64" data 0x%"PRIx64" size %d"
1592
+ufs_process_db(uint32_t slot) "UTRLDBR slot %"PRIu32""
1593
+ufs_process_req(uint32_t slot) "UTRLDBR slot %"PRIu32""
1594
+ufs_complete_req(uint32_t slot) "UTRLDBR slot %"PRIu32""
1595
+ufs_sendback_req(uint32_t slot) "UTRLDBR slot %"PRIu32""
1596
+ufs_exec_nop_cmd(uint32_t slot) "UTRLDBR slot %"PRIu32""
1597
+ufs_exec_scsi_cmd(uint32_t slot, uint8_t lun, uint8_t opcode) "slot %"PRIu32", lun 0x%"PRIx8", opcode 0x%"PRIx8""
1598
+ufs_exec_query_cmd(uint32_t slot, uint8_t opcode) "slot %"PRIu32", opcode 0x%"PRIx8""
1599
+ufs_process_uiccmd(uint32_t uiccmd, uint32_t ucmdarg1, uint32_t ucmdarg2, uint32_t ucmdarg3) "uiccmd 0x%"PRIx32", ucmdarg1 0x%"PRIx32", ucmdarg2 0x%"PRIx32", ucmdarg3 0x%"PRIx32""
1600
+
1601
+# error condition
1602
+ufs_err_dma_read_utrd(uint32_t slot, uint64_t addr) "failed to read utrd. UTRLDBR slot %"PRIu32", UTRD dma addr %"PRIu64""
1603
+ufs_err_dma_read_req_upiu(uint32_t slot, uint64_t addr) "failed to read req upiu. UTRLDBR slot %"PRIu32", request upiu addr %"PRIu64""
1604
+ufs_err_dma_read_prdt(uint32_t slot, uint64_t addr) "failed to read prdt. UTRLDBR slot %"PRIu32", prdt addr %"PRIu64""
1605
+ufs_err_dma_write_utrd(uint32_t slot, uint64_t addr) "failed to write utrd. UTRLDBR slot %"PRIu32", UTRD dma addr %"PRIu64""
1606
+ufs_err_dma_write_rsp_upiu(uint32_t slot, uint64_t addr) "failed to write rsp upiu. UTRLDBR slot %"PRIu32", response upiu addr %"PRIu64""
1607
+ufs_err_utrl_slot_busy(uint32_t slot) "UTRLDBR slot %"PRIu32" is busy"
1608
+ufs_err_unsupport_register_offset(uint32_t offset) "Register offset 0x%"PRIx32" is not yet supported"
1609
+ufs_err_invalid_register_offset(uint32_t offset) "Register offset 0x%"PRIx32" is invalid"
1610
+ufs_err_scsi_cmd_invalid_lun(uint8_t lun) "scsi command has invalid lun: 0x%"PRIx8""
1611
+ufs_err_query_flag_not_readable(uint8_t idn) "query flag idn 0x%"PRIx8" is denied to read"
1612
+ufs_err_query_flag_not_writable(uint8_t idn) "query flag idn 0x%"PRIx8" is denied to write"
1613
+ufs_err_query_attr_not_readable(uint8_t idn) "query attribute idn 0x%"PRIx8" is denied to read"
1614
+ufs_err_query_attr_not_writable(uint8_t idn) "query attribute idn 0x%"PRIx8" is denied to write"
1615
+ufs_err_query_invalid_opcode(uint8_t opcode) "query request has invalid opcode. opcode: 0x%"PRIx8""
1616
+ufs_err_query_invalid_idn(uint8_t opcode, uint8_t idn) "query request has invalid idn. opcode: 0x%"PRIx8", idn 0x%"PRIx8""
1617
+ufs_err_query_invalid_index(uint8_t opcode, uint8_t index) "query request has invalid index. opcode: 0x%"PRIx8", index 0x%"PRIx8""
1618
+ufs_err_invalid_trans_code(uint32_t slot, uint8_t trans_code) "request upiu has invalid transaction code. slot: %"PRIu32", trans_code: 0x%"PRIx8""
270
--
1619
--
271
2.26.2
1620
2.41.0
272
273
diff view generated by jsdifflib
1
From: Maxim Levitsky <mlevitsk@redhat.com>
1
From: Jeuk Kim <jeuk20.kim@gmail.com>
2
2
3
This commit adds two tests that cover the
3
This commit makes the UFS device support query
4
new blockdev-amend functionality of luks and qcow2 driver
4
and nop out transfer requests.
5
5
6
Signed-off-by: Maxim Levitsky <mlevitsk@redhat.com>
6
The next patch would be support for UFS logical
7
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
7
unit and scsi command transfer request.
8
Message-Id: <20200608094030.670121-15-mlevitsk@redhat.com>
8
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
9
Signed-off-by: Jeuk Kim <jeuk20.kim@samsung.com>
10
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
11
Message-id: d06b440d660872092f70af1b8167bd5f4704c957.1691062912.git.jeuk20.kim@samsung.com
12
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
10
---
13
---
11
tests/qemu-iotests/295 | 279 +++++++++++++++++++++++++++++++++++++
14
hw/ufs/ufs.h | 46 +++
12
tests/qemu-iotests/295.out | 40 ++++++
15
hw/ufs/ufs.c | 980 +++++++++++++++++++++++++++++++++++++++++++-
13
tests/qemu-iotests/296 | 234 +++++++++++++++++++++++++++++++
16
hw/ufs/trace-events | 1 +
14
tests/qemu-iotests/296.out | 33 +++++
17
3 files changed, 1025 insertions(+), 2 deletions(-)
15
tests/qemu-iotests/group | 2 +
16
5 files changed, 588 insertions(+)
17
create mode 100755 tests/qemu-iotests/295
18
create mode 100644 tests/qemu-iotests/295.out
19
create mode 100755 tests/qemu-iotests/296
20
create mode 100644 tests/qemu-iotests/296.out
21
18
22
diff --git a/tests/qemu-iotests/295 b/tests/qemu-iotests/295
19
diff --git a/hw/ufs/ufs.h b/hw/ufs/ufs.h
23
new file mode 100755
20
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX
21
--- a/hw/ufs/ufs.h
25
--- /dev/null
22
+++ b/hw/ufs/ufs.h
26
+++ b/tests/qemu-iotests/295
27
@@ -XXX,XX +XXX,XX @@
23
@@ -XXX,XX +XXX,XX @@
28
+#!/usr/bin/env python3
24
#define UFS_MAX_LUS 32
29
+#
25
#define UFS_BLOCK_SIZE 4096
30
+# Test case QMP's encrypted key management
26
31
+#
27
+typedef enum UfsRequestState {
32
+# Copyright (C) 2019 Red Hat, Inc.
28
+ UFS_REQUEST_IDLE = 0,
33
+#
29
+ UFS_REQUEST_READY = 1,
34
+# This program is free software; you can redistribute it and/or modify
30
+ UFS_REQUEST_RUNNING = 2,
35
+# it under the terms of the GNU General Public License as published by
31
+ UFS_REQUEST_COMPLETE = 3,
36
+# the Free Software Foundation; either version 2 of the License, or
32
+ UFS_REQUEST_ERROR = 4,
37
+# (at your option) any later version.
33
+} UfsRequestState;
38
+#
34
+
39
+# This program is distributed in the hope that it will be useful,
35
+typedef enum UfsReqResult {
40
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
36
+ UFS_REQUEST_SUCCESS = 0,
41
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
37
+ UFS_REQUEST_FAIL = 1,
42
+# GNU General Public License for more details.
38
+} UfsReqResult;
43
+#
39
+
44
+# You should have received a copy of the GNU General Public License
40
+typedef struct UfsRequest {
45
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
41
+ struct UfsHc *hc;
46
+#
42
+ UfsRequestState state;
47
+
43
+ int slot;
48
+import iotests
44
+
49
+import os
45
+ UtpTransferReqDesc utrd;
50
+import time
46
+ UtpUpiuReq req_upiu;
51
+import json
47
+ UtpUpiuRsp rsp_upiu;
52
+
48
+
53
+test_img = os.path.join(iotests.test_dir, 'test.img')
49
+ /* for scsi command */
54
+
50
+ QEMUSGList *sg;
55
+class Secret:
51
+} UfsRequest;
56
+ def __init__(self, index):
52
+
57
+ self._id = "keysec" + str(index)
53
typedef struct UfsParams {
58
+ # you are not supposed to see the password...
54
char *serial;
59
+ self._secret = "hunter" + str(index)
55
uint8_t nutrs; /* Number of UTP Transfer Request Slots */
60
+
56
@@ -XXX,XX +XXX,XX @@ typedef struct UfsHc {
61
+ def id(self):
57
UfsReg reg;
62
+ return self._id
58
UfsParams params;
63
+
59
uint32_t reg_size;
64
+ def secret(self):
60
+ UfsRequest *req_list;
65
+ return self._secret
61
+
66
+
62
+ DeviceDescriptor device_desc;
67
+ def to_cmdline_object(self):
63
+ GeometryDescriptor geometry_desc;
68
+ return [ "secret,id=" + self._id + ",data=" + self._secret]
64
+ Attributes attributes;
69
+
65
+ Flags flags;
70
+ def to_qmp_object(self):
66
71
+ return { "qom_type" : "secret", "id": self.id(),
67
qemu_irq irq;
72
+ "props": { "data": self.secret() } }
68
QEMUBH *doorbell_bh;
73
+
69
@@ -XXX,XX +XXX,XX @@ typedef struct UfsHc {
74
+################################################################################
70
#define TYPE_UFS "ufs"
75
+class EncryptionSetupTestCase(iotests.QMPTestCase):
71
#define UFS(obj) OBJECT_CHECK(UfsHc, (obj), TYPE_UFS)
76
+
72
77
+ # test case startup
73
+typedef enum UfsQueryFlagPerm {
78
+ def setUp(self):
74
+ UFS_QUERY_FLAG_NONE = 0x0,
79
+ # start the VM
75
+ UFS_QUERY_FLAG_READ = 0x1,
80
+ self.vm = iotests.VM()
76
+ UFS_QUERY_FLAG_SET = 0x2,
81
+ self.vm.launch()
77
+ UFS_QUERY_FLAG_CLEAR = 0x4,
82
+
78
+ UFS_QUERY_FLAG_TOGGLE = 0x8,
83
+ # create the secrets and load 'em into the VM
79
+} UfsQueryFlagPerm;
84
+ self.secrets = [ Secret(i) for i in range(0, 6) ]
80
+
85
+ for secret in self.secrets:
81
+typedef enum UfsQueryAttrPerm {
86
+ result = self.vm.qmp("object-add", **secret.to_qmp_object())
82
+ UFS_QUERY_ATTR_NONE = 0x0,
87
+ self.assert_qmp(result, 'return', {})
83
+ UFS_QUERY_ATTR_READ = 0x1,
88
+
84
+ UFS_QUERY_ATTR_WRITE = 0x2,
89
+ if iotests.imgfmt == "qcow2":
85
+} UfsQueryAttrPerm;
90
+ self.pfx = "encrypt."
86
+
91
+ self.img_opts = [ '-o', "encrypt.format=luks" ]
87
#endif /* HW_UFS_UFS_H */
92
+ else:
88
diff --git a/hw/ufs/ufs.c b/hw/ufs/ufs.c
93
+ self.pfx = ""
89
index XXXXXXX..XXXXXXX 100644
94
+ self.img_opts = []
90
--- a/hw/ufs/ufs.c
95
+
91
+++ b/hw/ufs/ufs.c
96
+ # test case shutdown
92
@@ -XXX,XX +XXX,XX @@
97
+ def tearDown(self):
93
#include "ufs.h"
98
+ # stop the VM
94
99
+ self.vm.shutdown()
95
/* The QEMU-UFS device follows spec version 3.1 */
100
+
96
-#define UFS_SPEC_VER 0x00000310
101
+ ###########################################################################
97
+#define UFS_SPEC_VER 0x0310
102
+ # create the encrypted block device
98
#define UFS_MAX_NUTRS 32
103
+ def createImg(self, file, secret):
99
#define UFS_MAX_NUTMRS 8
104
+
100
105
+ iotests.qemu_img(
101
+static MemTxResult ufs_addr_read(UfsHc *u, hwaddr addr, void *buf, int size)
106
+ 'create',
102
+{
107
+ '--object', *secret.to_cmdline_object(),
103
+ hwaddr hi = addr + size - 1;
108
+ '-f', iotests.imgfmt,
104
+
109
+ '-o', self.pfx + 'key-secret=' + secret.id(),
105
+ if (hi < addr) {
110
+ '-o', self.pfx + 'iter-time=10',
106
+ return MEMTX_DECODE_ERROR;
111
+ *self.img_opts,
107
+ }
112
+ file,
108
+
113
+ '1M')
109
+ if (!FIELD_EX32(u->reg.cap, CAP, 64AS) && (hi >> 32)) {
114
+
110
+ return MEMTX_DECODE_ERROR;
115
+ ###########################################################################
111
+ }
116
+ # open an encrypted block device
112
+
117
+ def openImageQmp(self, id, file, secret, read_only = False):
113
+ return pci_dma_read(PCI_DEVICE(u), addr, buf, size);
118
+
114
+}
119
+ encrypt_options = {
115
+
120
+ 'key-secret' : secret.id()
116
+static MemTxResult ufs_addr_write(UfsHc *u, hwaddr addr, const void *buf,
117
+ int size)
118
+{
119
+ hwaddr hi = addr + size - 1;
120
+ if (hi < addr) {
121
+ return MEMTX_DECODE_ERROR;
122
+ }
123
+
124
+ if (!FIELD_EX32(u->reg.cap, CAP, 64AS) && (hi >> 32)) {
125
+ return MEMTX_DECODE_ERROR;
126
+ }
127
+
128
+ return pci_dma_write(PCI_DEVICE(u), addr, buf, size);
129
+}
130
+
131
+static void ufs_complete_req(UfsRequest *req, UfsReqResult req_result);
132
+
133
+static inline hwaddr ufs_get_utrd_addr(UfsHc *u, uint32_t slot)
134
+{
135
+ hwaddr utrl_base_addr = (((hwaddr)u->reg.utrlbau) << 32) + u->reg.utrlba;
136
+ hwaddr utrd_addr = utrl_base_addr + slot * sizeof(UtpTransferReqDesc);
137
+
138
+ return utrd_addr;
139
+}
140
+
141
+static inline hwaddr ufs_get_req_upiu_base_addr(const UtpTransferReqDesc *utrd)
142
+{
143
+ uint32_t cmd_desc_base_addr_lo =
144
+ le32_to_cpu(utrd->command_desc_base_addr_lo);
145
+ uint32_t cmd_desc_base_addr_hi =
146
+ le32_to_cpu(utrd->command_desc_base_addr_hi);
147
+
148
+ return (((hwaddr)cmd_desc_base_addr_hi) << 32) + cmd_desc_base_addr_lo;
149
+}
150
+
151
+static inline hwaddr ufs_get_rsp_upiu_base_addr(const UtpTransferReqDesc *utrd)
152
+{
153
+ hwaddr req_upiu_base_addr = ufs_get_req_upiu_base_addr(utrd);
154
+ uint32_t rsp_upiu_byte_off =
155
+ le16_to_cpu(utrd->response_upiu_offset) * sizeof(uint32_t);
156
+ return req_upiu_base_addr + rsp_upiu_byte_off;
157
+}
158
+
159
+static MemTxResult ufs_dma_read_utrd(UfsRequest *req)
160
+{
161
+ UfsHc *u = req->hc;
162
+ hwaddr utrd_addr = ufs_get_utrd_addr(u, req->slot);
163
+ MemTxResult ret;
164
+
165
+ ret = ufs_addr_read(u, utrd_addr, &req->utrd, sizeof(req->utrd));
166
+ if (ret) {
167
+ trace_ufs_err_dma_read_utrd(req->slot, utrd_addr);
168
+ }
169
+ return ret;
170
+}
171
+
172
+static MemTxResult ufs_dma_read_req_upiu(UfsRequest *req)
173
+{
174
+ UfsHc *u = req->hc;
175
+ hwaddr req_upiu_base_addr = ufs_get_req_upiu_base_addr(&req->utrd);
176
+ UtpUpiuReq *req_upiu = &req->req_upiu;
177
+ uint32_t copy_size;
178
+ uint16_t data_segment_length;
179
+ MemTxResult ret;
180
+
181
+ /*
182
+ * To know the size of the req_upiu, we need to read the
183
+ * data_segment_length in the header first.
184
+ */
185
+ ret = ufs_addr_read(u, req_upiu_base_addr, &req_upiu->header,
186
+ sizeof(UtpUpiuHeader));
187
+ if (ret) {
188
+ trace_ufs_err_dma_read_req_upiu(req->slot, req_upiu_base_addr);
189
+ return ret;
190
+ }
191
+ data_segment_length = be16_to_cpu(req_upiu->header.data_segment_length);
192
+
193
+ copy_size = sizeof(UtpUpiuHeader) + UFS_TRANSACTION_SPECIFIC_FIELD_SIZE +
194
+ data_segment_length;
195
+
196
+ ret = ufs_addr_read(u, req_upiu_base_addr, &req->req_upiu, copy_size);
197
+ if (ret) {
198
+ trace_ufs_err_dma_read_req_upiu(req->slot, req_upiu_base_addr);
199
+ }
200
+ return ret;
201
+}
202
+
203
+static MemTxResult ufs_dma_read_prdt(UfsRequest *req)
204
+{
205
+ UfsHc *u = req->hc;
206
+ uint16_t prdt_len = le16_to_cpu(req->utrd.prd_table_length);
207
+ uint16_t prdt_byte_off =
208
+ le16_to_cpu(req->utrd.prd_table_offset) * sizeof(uint32_t);
209
+ uint32_t prdt_size = prdt_len * sizeof(UfshcdSgEntry);
210
+ g_autofree UfshcdSgEntry *prd_entries = NULL;
211
+ hwaddr req_upiu_base_addr, prdt_base_addr;
212
+ int err;
213
+
214
+ assert(!req->sg);
215
+
216
+ if (prdt_size == 0) {
217
+ return MEMTX_OK;
218
+ }
219
+ prd_entries = g_new(UfshcdSgEntry, prdt_size);
220
+
221
+ req_upiu_base_addr = ufs_get_req_upiu_base_addr(&req->utrd);
222
+ prdt_base_addr = req_upiu_base_addr + prdt_byte_off;
223
+
224
+ err = ufs_addr_read(u, prdt_base_addr, prd_entries, prdt_size);
225
+ if (err) {
226
+ trace_ufs_err_dma_read_prdt(req->slot, prdt_base_addr);
227
+ return err;
228
+ }
229
+
230
+ req->sg = g_malloc0(sizeof(QEMUSGList));
231
+ pci_dma_sglist_init(req->sg, PCI_DEVICE(u), prdt_len);
232
+
233
+ for (uint16_t i = 0; i < prdt_len; ++i) {
234
+ hwaddr data_dma_addr = le64_to_cpu(prd_entries[i].addr);
235
+ uint32_t data_byte_count = le32_to_cpu(prd_entries[i].size) + 1;
236
+ qemu_sglist_add(req->sg, data_dma_addr, data_byte_count);
237
+ }
238
+ return MEMTX_OK;
239
+}
240
+
241
+static MemTxResult ufs_dma_read_upiu(UfsRequest *req)
242
+{
243
+ MemTxResult ret;
244
+
245
+ ret = ufs_dma_read_utrd(req);
246
+ if (ret) {
247
+ return ret;
248
+ }
249
+
250
+ ret = ufs_dma_read_req_upiu(req);
251
+ if (ret) {
252
+ return ret;
253
+ }
254
+
255
+ ret = ufs_dma_read_prdt(req);
256
+ if (ret) {
257
+ return ret;
258
+ }
259
+
260
+ return 0;
261
+}
262
+
263
+static MemTxResult ufs_dma_write_utrd(UfsRequest *req)
264
+{
265
+ UfsHc *u = req->hc;
266
+ hwaddr utrd_addr = ufs_get_utrd_addr(u, req->slot);
267
+ MemTxResult ret;
268
+
269
+ ret = ufs_addr_write(u, utrd_addr, &req->utrd, sizeof(req->utrd));
270
+ if (ret) {
271
+ trace_ufs_err_dma_write_utrd(req->slot, utrd_addr);
272
+ }
273
+ return ret;
274
+}
275
+
276
+static MemTxResult ufs_dma_write_rsp_upiu(UfsRequest *req)
277
+{
278
+ UfsHc *u = req->hc;
279
+ hwaddr rsp_upiu_base_addr = ufs_get_rsp_upiu_base_addr(&req->utrd);
280
+ uint32_t rsp_upiu_byte_len =
281
+ le16_to_cpu(req->utrd.response_upiu_length) * sizeof(uint32_t);
282
+ uint16_t data_segment_length =
283
+ be16_to_cpu(req->rsp_upiu.header.data_segment_length);
284
+ uint32_t copy_size = sizeof(UtpUpiuHeader) +
285
+ UFS_TRANSACTION_SPECIFIC_FIELD_SIZE +
286
+ data_segment_length;
287
+ MemTxResult ret;
288
+
289
+ if (copy_size > rsp_upiu_byte_len) {
290
+ copy_size = rsp_upiu_byte_len;
291
+ }
292
+
293
+ ret = ufs_addr_write(u, rsp_upiu_base_addr, &req->rsp_upiu, copy_size);
294
+ if (ret) {
295
+ trace_ufs_err_dma_write_rsp_upiu(req->slot, rsp_upiu_base_addr);
296
+ }
297
+ return ret;
298
+}
299
+
300
+static MemTxResult ufs_dma_write_upiu(UfsRequest *req)
301
+{
302
+ MemTxResult ret;
303
+
304
+ ret = ufs_dma_write_rsp_upiu(req);
305
+ if (ret) {
306
+ return ret;
307
+ }
308
+
309
+ return ufs_dma_write_utrd(req);
310
+}
311
+
312
static void ufs_irq_check(UfsHc *u)
313
{
314
PCIDevice *pci = PCI_DEVICE(u);
315
@@ -XXX,XX +XXX,XX @@ static void ufs_irq_check(UfsHc *u)
316
}
317
}
318
319
+static void ufs_process_db(UfsHc *u, uint32_t val)
320
+{
321
+ uint32_t slot;
322
+ uint32_t nutrs = u->params.nutrs;
323
+ UfsRequest *req;
324
+
325
+ val &= ~u->reg.utrldbr;
326
+ if (!val) {
327
+ return;
328
+ }
329
+
330
+ slot = find_first_bit((unsigned long *)&val, nutrs);
331
+
332
+ while (slot < nutrs) {
333
+ req = &u->req_list[slot];
334
+ if (req->state == UFS_REQUEST_ERROR) {
335
+ trace_ufs_err_utrl_slot_error(req->slot);
336
+ return;
121
+ }
337
+ }
122
+
338
+
123
+ if iotests.imgfmt == "qcow2":
339
+ if (req->state != UFS_REQUEST_IDLE) {
124
+ encrypt_options = {
340
+ trace_ufs_err_utrl_slot_busy(req->slot);
125
+ 'encrypt': {
341
+ return;
126
+ 'format':'luks',
127
+ **encrypt_options
128
+ }
129
+ }
130
+
131
+ result = self.vm.qmp('blockdev-add', **
132
+ {
133
+ 'driver': iotests.imgfmt,
134
+ 'node-name': id,
135
+ 'read-only': read_only,
136
+
137
+ **encrypt_options,
138
+
139
+ 'file': {
140
+ 'driver': 'file',
141
+ 'filename': test_img,
142
+ }
143
+ }
144
+ )
145
+ self.assert_qmp(result, 'return', {})
146
+
147
+ # close the encrypted block device
148
+ def closeImageQmp(self, id):
149
+ result = self.vm.qmp('blockdev-del', **{ 'node-name': id })
150
+ self.assert_qmp(result, 'return', {})
151
+
152
+ ###########################################################################
153
+ # add a key to an encrypted block device
154
+ def addKeyQmp(self, id, new_secret, secret = None,
155
+ slot = None, force = False):
156
+
157
+ crypt_options = {
158
+ 'state' : 'active',
159
+ 'new-secret' : new_secret.id(),
160
+ 'iter-time' : 10
161
+ }
342
+ }
162
+
343
+
163
+ if slot != None:
344
+ trace_ufs_process_db(slot);
164
+ crypt_options['keyslot'] = slot
345
+ req->state = UFS_REQUEST_READY;
165
+
346
+ slot = find_next_bit((unsigned long *)&val, nutrs, slot + 1);
166
+
347
+ }
167
+ if secret != None:
348
+
168
+ crypt_options['secret'] = secret.id()
349
+ qemu_bh_schedule(u->doorbell_bh);
169
+
350
+}
170
+ if iotests.imgfmt == "qcow2":
351
+
171
+ crypt_options['format'] = 'luks'
352
static void ufs_process_uiccmd(UfsHc *u, uint32_t val)
172
+ crypt_options = {
353
{
173
+ 'encrypt': crypt_options
354
trace_ufs_process_uiccmd(val, u->reg.ucmdarg1, u->reg.ucmdarg2,
174
+ }
355
@@ -XXX,XX +XXX,XX @@ static void ufs_write_reg(UfsHc *u, hwaddr offset, uint32_t data, unsigned size)
175
+
356
u->reg.utrlbau = data;
176
+ args = {
357
break;
177
+ 'node-name': id,
358
case A_UTRLDBR:
178
+ 'job-id' : 'job_add_key',
359
- /* Not yet supported */
179
+ 'options' : {
360
+ ufs_process_db(u, data);
180
+ 'driver' : iotests.imgfmt,
361
+ u->reg.utrldbr |= data;
181
+ **crypt_options
362
break;
182
+ },
363
case A_UTRLRSR:
364
u->reg.utrlrsr = data;
365
@@ -XXX,XX +XXX,XX @@ static const MemoryRegionOps ufs_mmio_ops = {
366
},
367
};
368
369
+static void ufs_build_upiu_header(UfsRequest *req, uint8_t trans_type,
370
+ uint8_t flags, uint8_t response,
371
+ uint8_t scsi_status,
372
+ uint16_t data_segment_length)
373
+{
374
+ memcpy(&req->rsp_upiu.header, &req->req_upiu.header, sizeof(UtpUpiuHeader));
375
+ req->rsp_upiu.header.trans_type = trans_type;
376
+ req->rsp_upiu.header.flags = flags;
377
+ req->rsp_upiu.header.response = response;
378
+ req->rsp_upiu.header.scsi_status = scsi_status;
379
+ req->rsp_upiu.header.data_segment_length = cpu_to_be16(data_segment_length);
380
+}
381
+
382
+static UfsReqResult ufs_exec_nop_cmd(UfsRequest *req)
383
+{
384
+ trace_ufs_exec_nop_cmd(req->slot);
385
+ ufs_build_upiu_header(req, UPIU_TRANSACTION_NOP_IN, 0, 0, 0, 0);
386
+ return UFS_REQUEST_SUCCESS;
387
+}
388
+
389
+/*
390
+ * This defines the permission of flags based on their IDN. There are some
391
+ * things that are declared read-only, which is inconsistent with the ufs spec,
392
+ * because we want to return an error for features that are not yet supported.
393
+ */
394
+static const int flag_permission[QUERY_FLAG_IDN_COUNT] = {
395
+ [QUERY_FLAG_IDN_FDEVICEINIT] = UFS_QUERY_FLAG_READ | UFS_QUERY_FLAG_SET,
396
+ /* Write protection is not supported */
397
+ [QUERY_FLAG_IDN_PERMANENT_WPE] = UFS_QUERY_FLAG_READ,
398
+ [QUERY_FLAG_IDN_PWR_ON_WPE] = UFS_QUERY_FLAG_READ,
399
+ [QUERY_FLAG_IDN_BKOPS_EN] = UFS_QUERY_FLAG_READ | UFS_QUERY_FLAG_SET |
400
+ UFS_QUERY_FLAG_CLEAR | UFS_QUERY_FLAG_TOGGLE,
401
+ [QUERY_FLAG_IDN_LIFE_SPAN_MODE_ENABLE] =
402
+ UFS_QUERY_FLAG_READ | UFS_QUERY_FLAG_SET | UFS_QUERY_FLAG_CLEAR |
403
+ UFS_QUERY_FLAG_TOGGLE,
404
+ /* Purge Operation is not supported */
405
+ [QUERY_FLAG_IDN_PURGE_ENABLE] = UFS_QUERY_FLAG_NONE,
406
+ /* Refresh Operation is not supported */
407
+ [QUERY_FLAG_IDN_REFRESH_ENABLE] = UFS_QUERY_FLAG_NONE,
408
+ /* Physical Resource Removal is not supported */
409
+ [QUERY_FLAG_IDN_FPHYRESOURCEREMOVAL] = UFS_QUERY_FLAG_READ,
410
+ [QUERY_FLAG_IDN_BUSY_RTC] = UFS_QUERY_FLAG_READ,
411
+ [QUERY_FLAG_IDN_PERMANENTLY_DISABLE_FW_UPDATE] = UFS_QUERY_FLAG_READ,
412
+ /* Write Booster is not supported */
413
+ [QUERY_FLAG_IDN_WB_EN] = UFS_QUERY_FLAG_READ,
414
+ [QUERY_FLAG_IDN_WB_BUFF_FLUSH_EN] = UFS_QUERY_FLAG_READ,
415
+ [QUERY_FLAG_IDN_WB_BUFF_FLUSH_DURING_HIBERN8] = UFS_QUERY_FLAG_READ,
416
+};
417
+
418
+static inline QueryRespCode ufs_flag_check_idn_valid(uint8_t idn, int op)
419
+{
420
+ if (idn >= QUERY_FLAG_IDN_COUNT) {
421
+ return QUERY_RESULT_INVALID_IDN;
422
+ }
423
+
424
+ if (!(flag_permission[idn] & op)) {
425
+ if (op == UFS_QUERY_FLAG_READ) {
426
+ trace_ufs_err_query_flag_not_readable(idn);
427
+ return QUERY_RESULT_NOT_READABLE;
183
+ }
428
+ }
184
+
429
+ trace_ufs_err_query_flag_not_writable(idn);
185
+ if force == True:
430
+ return QUERY_RESULT_NOT_WRITEABLE;
186
+ args['force'] = True
431
+ }
187
+
432
+
188
+ #TODO: check what jobs return
433
+ return QUERY_RESULT_SUCCESS;
189
+ result = self.vm.qmp('x-blockdev-amend', **args)
434
+}
190
+ assert result['return'] == {}
435
+
191
+ self.vm.run_job('job_add_key')
436
+static const int attr_permission[QUERY_ATTR_IDN_COUNT] = {
192
+
437
+ /* booting is not supported */
193
+ # erase a key from an encrypted block device
438
+ [QUERY_ATTR_IDN_BOOT_LU_EN] = UFS_QUERY_ATTR_READ,
194
+ def eraseKeyQmp(self, id, old_secret = None, slot = None, force = False):
439
+ [QUERY_ATTR_IDN_POWER_MODE] = UFS_QUERY_ATTR_READ,
195
+
440
+ [QUERY_ATTR_IDN_ACTIVE_ICC_LVL] =
196
+ crypt_options = {
441
+ UFS_QUERY_ATTR_READ | UFS_QUERY_ATTR_WRITE,
197
+ 'state' : 'inactive',
442
+ [QUERY_ATTR_IDN_OOO_DATA_EN] = UFS_QUERY_ATTR_READ,
443
+ [QUERY_ATTR_IDN_BKOPS_STATUS] = UFS_QUERY_ATTR_READ,
444
+ [QUERY_ATTR_IDN_PURGE_STATUS] = UFS_QUERY_ATTR_READ,
445
+ [QUERY_ATTR_IDN_MAX_DATA_IN] = UFS_QUERY_ATTR_READ | UFS_QUERY_ATTR_WRITE,
446
+ [QUERY_ATTR_IDN_MAX_DATA_OUT] = UFS_QUERY_ATTR_READ | UFS_QUERY_ATTR_WRITE,
447
+ [QUERY_ATTR_IDN_DYN_CAP_NEEDED] = UFS_QUERY_ATTR_READ,
448
+ [QUERY_ATTR_IDN_REF_CLK_FREQ] = UFS_QUERY_ATTR_READ | UFS_QUERY_ATTR_WRITE,
449
+ [QUERY_ATTR_IDN_CONF_DESC_LOCK] = UFS_QUERY_ATTR_READ,
450
+ [QUERY_ATTR_IDN_MAX_NUM_OF_RTT] =
451
+ UFS_QUERY_ATTR_READ | UFS_QUERY_ATTR_WRITE,
452
+ [QUERY_ATTR_IDN_EE_CONTROL] = UFS_QUERY_ATTR_READ | UFS_QUERY_ATTR_WRITE,
453
+ [QUERY_ATTR_IDN_EE_STATUS] = UFS_QUERY_ATTR_READ,
454
+ [QUERY_ATTR_IDN_SECONDS_PASSED] = UFS_QUERY_ATTR_WRITE,
455
+ [QUERY_ATTR_IDN_CNTX_CONF] = UFS_QUERY_ATTR_READ,
456
+ [QUERY_ATTR_IDN_FFU_STATUS] = UFS_QUERY_ATTR_READ,
457
+ [QUERY_ATTR_IDN_PSA_STATE] = UFS_QUERY_ATTR_READ | UFS_QUERY_ATTR_WRITE,
458
+ [QUERY_ATTR_IDN_PSA_DATA_SIZE] = UFS_QUERY_ATTR_READ | UFS_QUERY_ATTR_WRITE,
459
+ [QUERY_ATTR_IDN_REF_CLK_GATING_WAIT_TIME] = UFS_QUERY_ATTR_READ,
460
+ [QUERY_ATTR_IDN_CASE_ROUGH_TEMP] = UFS_QUERY_ATTR_READ,
461
+ [QUERY_ATTR_IDN_HIGH_TEMP_BOUND] = UFS_QUERY_ATTR_READ,
462
+ [QUERY_ATTR_IDN_LOW_TEMP_BOUND] = UFS_QUERY_ATTR_READ,
463
+ [QUERY_ATTR_IDN_THROTTLING_STATUS] = UFS_QUERY_ATTR_READ,
464
+ [QUERY_ATTR_IDN_WB_FLUSH_STATUS] = UFS_QUERY_ATTR_READ,
465
+ [QUERY_ATTR_IDN_AVAIL_WB_BUFF_SIZE] = UFS_QUERY_ATTR_READ,
466
+ [QUERY_ATTR_IDN_WB_BUFF_LIFE_TIME_EST] = UFS_QUERY_ATTR_READ,
467
+ [QUERY_ATTR_IDN_CURR_WB_BUFF_SIZE] = UFS_QUERY_ATTR_READ,
468
+ /* refresh operation is not supported */
469
+ [QUERY_ATTR_IDN_REFRESH_STATUS] = UFS_QUERY_ATTR_READ,
470
+ [QUERY_ATTR_IDN_REFRESH_FREQ] = UFS_QUERY_ATTR_READ,
471
+ [QUERY_ATTR_IDN_REFRESH_UNIT] = UFS_QUERY_ATTR_READ,
472
+};
473
+
474
+static inline QueryRespCode ufs_attr_check_idn_valid(uint8_t idn, int op)
475
+{
476
+ if (idn >= QUERY_ATTR_IDN_COUNT) {
477
+ return QUERY_RESULT_INVALID_IDN;
478
+ }
479
+
480
+ if (!(attr_permission[idn] & op)) {
481
+ if (op == UFS_QUERY_ATTR_READ) {
482
+ trace_ufs_err_query_attr_not_readable(idn);
483
+ return QUERY_RESULT_NOT_READABLE;
198
+ }
484
+ }
199
+
485
+ trace_ufs_err_query_attr_not_writable(idn);
200
+ if slot != None:
486
+ return QUERY_RESULT_NOT_WRITEABLE;
201
+ crypt_options['keyslot'] = slot
487
+ }
202
+ if old_secret != None:
488
+
203
+ crypt_options['old-secret'] = old_secret.id()
489
+ return QUERY_RESULT_SUCCESS;
204
+
490
+}
205
+ if iotests.imgfmt == "qcow2":
491
+
206
+ crypt_options['format'] = 'luks'
492
+static QueryRespCode ufs_exec_query_flag(UfsRequest *req, int op)
207
+ crypt_options = {
493
+{
208
+ 'encrypt': crypt_options
494
+ UfsHc *u = req->hc;
209
+ }
495
+ uint8_t idn = req->req_upiu.qr.idn;
210
+
496
+ uint32_t value;
211
+ args = {
497
+ QueryRespCode ret;
212
+ 'node-name': id,
498
+
213
+ 'job-id' : 'job_erase_key',
499
+ ret = ufs_flag_check_idn_valid(idn, op);
214
+ 'options' : {
500
+ if (ret) {
215
+ 'driver' : iotests.imgfmt,
501
+ return ret;
216
+ **crypt_options
502
+ }
217
+ },
503
+
504
+ if (idn == QUERY_FLAG_IDN_FDEVICEINIT) {
505
+ value = 0;
506
+ } else if (op == UFS_QUERY_FLAG_READ) {
507
+ value = *(((uint8_t *)&u->flags) + idn);
508
+ } else if (op == UFS_QUERY_FLAG_SET) {
509
+ value = 1;
510
+ } else if (op == UFS_QUERY_FLAG_CLEAR) {
511
+ value = 0;
512
+ } else if (op == UFS_QUERY_FLAG_TOGGLE) {
513
+ value = *(((uint8_t *)&u->flags) + idn);
514
+ value = !value;
515
+ } else {
516
+ trace_ufs_err_query_invalid_opcode(op);
517
+ return QUERY_RESULT_INVALID_OPCODE;
518
+ }
519
+
520
+ *(((uint8_t *)&u->flags) + idn) = value;
521
+ req->rsp_upiu.qr.value = cpu_to_be32(value);
522
+ return QUERY_RESULT_SUCCESS;
523
+}
524
+
525
+static uint32_t ufs_read_attr_value(UfsHc *u, uint8_t idn)
526
+{
527
+ switch (idn) {
528
+ case QUERY_ATTR_IDN_BOOT_LU_EN:
529
+ return u->attributes.boot_lun_en;
530
+ case QUERY_ATTR_IDN_POWER_MODE:
531
+ return u->attributes.current_power_mode;
532
+ case QUERY_ATTR_IDN_ACTIVE_ICC_LVL:
533
+ return u->attributes.active_icc_level;
534
+ case QUERY_ATTR_IDN_OOO_DATA_EN:
535
+ return u->attributes.out_of_order_data_en;
536
+ case QUERY_ATTR_IDN_BKOPS_STATUS:
537
+ return u->attributes.background_op_status;
538
+ case QUERY_ATTR_IDN_PURGE_STATUS:
539
+ return u->attributes.purge_status;
540
+ case QUERY_ATTR_IDN_MAX_DATA_IN:
541
+ return u->attributes.max_data_in_size;
542
+ case QUERY_ATTR_IDN_MAX_DATA_OUT:
543
+ return u->attributes.max_data_out_size;
544
+ case QUERY_ATTR_IDN_DYN_CAP_NEEDED:
545
+ return be32_to_cpu(u->attributes.dyn_cap_needed);
546
+ case QUERY_ATTR_IDN_REF_CLK_FREQ:
547
+ return u->attributes.ref_clk_freq;
548
+ case QUERY_ATTR_IDN_CONF_DESC_LOCK:
549
+ return u->attributes.config_descr_lock;
550
+ case QUERY_ATTR_IDN_MAX_NUM_OF_RTT:
551
+ return u->attributes.max_num_of_rtt;
552
+ case QUERY_ATTR_IDN_EE_CONTROL:
553
+ return be16_to_cpu(u->attributes.exception_event_control);
554
+ case QUERY_ATTR_IDN_EE_STATUS:
555
+ return be16_to_cpu(u->attributes.exception_event_status);
556
+ case QUERY_ATTR_IDN_SECONDS_PASSED:
557
+ return be32_to_cpu(u->attributes.seconds_passed);
558
+ case QUERY_ATTR_IDN_CNTX_CONF:
559
+ return be16_to_cpu(u->attributes.context_conf);
560
+ case QUERY_ATTR_IDN_FFU_STATUS:
561
+ return u->attributes.device_ffu_status;
562
+ case QUERY_ATTR_IDN_PSA_STATE:
563
+ return be32_to_cpu(u->attributes.psa_state);
564
+ case QUERY_ATTR_IDN_PSA_DATA_SIZE:
565
+ return be32_to_cpu(u->attributes.psa_data_size);
566
+ case QUERY_ATTR_IDN_REF_CLK_GATING_WAIT_TIME:
567
+ return u->attributes.ref_clk_gating_wait_time;
568
+ case QUERY_ATTR_IDN_CASE_ROUGH_TEMP:
569
+ return u->attributes.device_case_rough_temperaure;
570
+ case QUERY_ATTR_IDN_HIGH_TEMP_BOUND:
571
+ return u->attributes.device_too_high_temp_boundary;
572
+ case QUERY_ATTR_IDN_LOW_TEMP_BOUND:
573
+ return u->attributes.device_too_low_temp_boundary;
574
+ case QUERY_ATTR_IDN_THROTTLING_STATUS:
575
+ return u->attributes.throttling_status;
576
+ case QUERY_ATTR_IDN_WB_FLUSH_STATUS:
577
+ return u->attributes.wb_buffer_flush_status;
578
+ case QUERY_ATTR_IDN_AVAIL_WB_BUFF_SIZE:
579
+ return u->attributes.available_wb_buffer_size;
580
+ case QUERY_ATTR_IDN_WB_BUFF_LIFE_TIME_EST:
581
+ return u->attributes.wb_buffer_life_time_est;
582
+ case QUERY_ATTR_IDN_CURR_WB_BUFF_SIZE:
583
+ return be32_to_cpu(u->attributes.current_wb_buffer_size);
584
+ case QUERY_ATTR_IDN_REFRESH_STATUS:
585
+ return u->attributes.refresh_status;
586
+ case QUERY_ATTR_IDN_REFRESH_FREQ:
587
+ return u->attributes.refresh_freq;
588
+ case QUERY_ATTR_IDN_REFRESH_UNIT:
589
+ return u->attributes.refresh_unit;
590
+ }
591
+ return 0;
592
+}
593
+
594
+static void ufs_write_attr_value(UfsHc *u, uint8_t idn, uint32_t value)
595
+{
596
+ switch (idn) {
597
+ case QUERY_ATTR_IDN_ACTIVE_ICC_LVL:
598
+ u->attributes.active_icc_level = value;
599
+ break;
600
+ case QUERY_ATTR_IDN_MAX_DATA_IN:
601
+ u->attributes.max_data_in_size = value;
602
+ break;
603
+ case QUERY_ATTR_IDN_MAX_DATA_OUT:
604
+ u->attributes.max_data_out_size = value;
605
+ break;
606
+ case QUERY_ATTR_IDN_REF_CLK_FREQ:
607
+ u->attributes.ref_clk_freq = value;
608
+ break;
609
+ case QUERY_ATTR_IDN_MAX_NUM_OF_RTT:
610
+ u->attributes.max_num_of_rtt = value;
611
+ break;
612
+ case QUERY_ATTR_IDN_EE_CONTROL:
613
+ u->attributes.exception_event_control = cpu_to_be16(value);
614
+ break;
615
+ case QUERY_ATTR_IDN_SECONDS_PASSED:
616
+ u->attributes.seconds_passed = cpu_to_be32(value);
617
+ break;
618
+ case QUERY_ATTR_IDN_PSA_STATE:
619
+ u->attributes.psa_state = value;
620
+ break;
621
+ case QUERY_ATTR_IDN_PSA_DATA_SIZE:
622
+ u->attributes.psa_data_size = cpu_to_be32(value);
623
+ break;
624
+ }
625
+}
626
+
627
+static QueryRespCode ufs_exec_query_attr(UfsRequest *req, int op)
628
+{
629
+ UfsHc *u = req->hc;
630
+ uint8_t idn = req->req_upiu.qr.idn;
631
+ uint32_t value;
632
+ QueryRespCode ret;
633
+
634
+ ret = ufs_attr_check_idn_valid(idn, op);
635
+ if (ret) {
636
+ return ret;
637
+ }
638
+
639
+ if (op == UFS_QUERY_ATTR_READ) {
640
+ value = ufs_read_attr_value(u, idn);
641
+ } else {
642
+ value = be32_to_cpu(req->req_upiu.qr.value);
643
+ ufs_write_attr_value(u, idn, value);
644
+ }
645
+
646
+ req->rsp_upiu.qr.value = cpu_to_be32(value);
647
+ return QUERY_RESULT_SUCCESS;
648
+}
649
+
650
+static const RpmbUnitDescriptor rpmb_unit_desc = {
651
+ .length = sizeof(RpmbUnitDescriptor),
652
+ .descriptor_idn = 2,
653
+ .unit_index = UFS_UPIU_RPMB_WLUN,
654
+ .lu_enable = 0,
655
+};
656
+
657
+static QueryRespCode ufs_read_unit_desc(UfsRequest *req)
658
+{
659
+ uint8_t lun = req->req_upiu.qr.index;
660
+
661
+ if (lun != UFS_UPIU_RPMB_WLUN && lun > UFS_MAX_LUS) {
662
+ trace_ufs_err_query_invalid_index(req->req_upiu.qr.opcode, lun);
663
+ return QUERY_RESULT_INVALID_INDEX;
664
+ }
665
+
666
+ if (lun == UFS_UPIU_RPMB_WLUN) {
667
+ memcpy(&req->rsp_upiu.qr.data, &rpmb_unit_desc, rpmb_unit_desc.length);
668
+ } else {
669
+ /* unit descriptor is not yet supported */
670
+ return QUERY_RESULT_INVALID_INDEX;
671
+ }
672
+
673
+ return QUERY_RESULT_SUCCESS;
674
+}
675
+
676
+static inline StringDescriptor manufacturer_str_desc(void)
677
+{
678
+ StringDescriptor desc = {
679
+ .length = 0x12,
680
+ .descriptor_idn = QUERY_DESC_IDN_STRING,
681
+ };
682
+ desc.UC[0] = cpu_to_be16('R');
683
+ desc.UC[1] = cpu_to_be16('E');
684
+ desc.UC[2] = cpu_to_be16('D');
685
+ desc.UC[3] = cpu_to_be16('H');
686
+ desc.UC[4] = cpu_to_be16('A');
687
+ desc.UC[5] = cpu_to_be16('T');
688
+ return desc;
689
+}
690
+
691
+static inline StringDescriptor product_name_str_desc(void)
692
+{
693
+ StringDescriptor desc = {
694
+ .length = 0x22,
695
+ .descriptor_idn = QUERY_DESC_IDN_STRING,
696
+ };
697
+ desc.UC[0] = cpu_to_be16('Q');
698
+ desc.UC[1] = cpu_to_be16('E');
699
+ desc.UC[2] = cpu_to_be16('M');
700
+ desc.UC[3] = cpu_to_be16('U');
701
+ desc.UC[4] = cpu_to_be16(' ');
702
+ desc.UC[5] = cpu_to_be16('U');
703
+ desc.UC[6] = cpu_to_be16('F');
704
+ desc.UC[7] = cpu_to_be16('S');
705
+ return desc;
706
+}
707
+
708
+static inline StringDescriptor product_rev_level_str_desc(void)
709
+{
710
+ StringDescriptor desc = {
711
+ .length = 0x0a,
712
+ .descriptor_idn = QUERY_DESC_IDN_STRING,
713
+ };
714
+ desc.UC[0] = cpu_to_be16('0');
715
+ desc.UC[1] = cpu_to_be16('0');
716
+ desc.UC[2] = cpu_to_be16('0');
717
+ desc.UC[3] = cpu_to_be16('1');
718
+ return desc;
719
+}
720
+
721
+static const StringDescriptor null_str_desc = {
722
+ .length = 0x02,
723
+ .descriptor_idn = QUERY_DESC_IDN_STRING,
724
+};
725
+
726
+static QueryRespCode ufs_read_string_desc(UfsRequest *req)
727
+{
728
+ UfsHc *u = req->hc;
729
+ uint8_t index = req->req_upiu.qr.index;
730
+ StringDescriptor desc;
731
+
732
+ if (index == u->device_desc.manufacturer_name) {
733
+ desc = manufacturer_str_desc();
734
+ memcpy(&req->rsp_upiu.qr.data, &desc, desc.length);
735
+ } else if (index == u->device_desc.product_name) {
736
+ desc = product_name_str_desc();
737
+ memcpy(&req->rsp_upiu.qr.data, &desc, desc.length);
738
+ } else if (index == u->device_desc.serial_number) {
739
+ memcpy(&req->rsp_upiu.qr.data, &null_str_desc, null_str_desc.length);
740
+ } else if (index == u->device_desc.oem_id) {
741
+ memcpy(&req->rsp_upiu.qr.data, &null_str_desc, null_str_desc.length);
742
+ } else if (index == u->device_desc.product_revision_level) {
743
+ desc = product_rev_level_str_desc();
744
+ memcpy(&req->rsp_upiu.qr.data, &desc, desc.length);
745
+ } else {
746
+ trace_ufs_err_query_invalid_index(req->req_upiu.qr.opcode, index);
747
+ return QUERY_RESULT_INVALID_INDEX;
748
+ }
749
+ return QUERY_RESULT_SUCCESS;
750
+}
751
+
752
+static inline InterconnectDescriptor interconnect_desc(void)
753
+{
754
+ InterconnectDescriptor desc = {
755
+ .length = sizeof(InterconnectDescriptor),
756
+ .descriptor_idn = QUERY_DESC_IDN_INTERCONNECT,
757
+ };
758
+ desc.bcd_unipro_version = cpu_to_be16(0x180);
759
+ desc.bcd_mphy_version = cpu_to_be16(0x410);
760
+ return desc;
761
+}
762
+
763
+static QueryRespCode ufs_read_desc(UfsRequest *req)
764
+{
765
+ UfsHc *u = req->hc;
766
+ QueryRespCode status;
767
+ uint8_t idn = req->req_upiu.qr.idn;
768
+ uint16_t length = be16_to_cpu(req->req_upiu.qr.length);
769
+ InterconnectDescriptor desc;
770
+
771
+ switch (idn) {
772
+ case QUERY_DESC_IDN_DEVICE:
773
+ memcpy(&req->rsp_upiu.qr.data, &u->device_desc, sizeof(u->device_desc));
774
+ status = QUERY_RESULT_SUCCESS;
775
+ break;
776
+ case QUERY_DESC_IDN_UNIT:
777
+ status = ufs_read_unit_desc(req);
778
+ break;
779
+ case QUERY_DESC_IDN_GEOMETRY:
780
+ memcpy(&req->rsp_upiu.qr.data, &u->geometry_desc,
781
+ sizeof(u->geometry_desc));
782
+ status = QUERY_RESULT_SUCCESS;
783
+ break;
784
+ case QUERY_DESC_IDN_INTERCONNECT: {
785
+ desc = interconnect_desc();
786
+ memcpy(&req->rsp_upiu.qr.data, &desc, sizeof(InterconnectDescriptor));
787
+ status = QUERY_RESULT_SUCCESS;
788
+ break;
789
+ }
790
+ case QUERY_DESC_IDN_STRING:
791
+ status = ufs_read_string_desc(req);
792
+ break;
793
+ case QUERY_DESC_IDN_POWER:
794
+ /* mocking of power descriptor is not supported */
795
+ memset(&req->rsp_upiu.qr.data, 0, sizeof(PowerParametersDescriptor));
796
+ req->rsp_upiu.qr.data[0] = sizeof(PowerParametersDescriptor);
797
+ req->rsp_upiu.qr.data[1] = QUERY_DESC_IDN_POWER;
798
+ status = QUERY_RESULT_SUCCESS;
799
+ break;
800
+ case QUERY_DESC_IDN_HEALTH:
801
+ /* mocking of health descriptor is not supported */
802
+ memset(&req->rsp_upiu.qr.data, 0, sizeof(DeviceHealthDescriptor));
803
+ req->rsp_upiu.qr.data[0] = sizeof(DeviceHealthDescriptor);
804
+ req->rsp_upiu.qr.data[1] = QUERY_DESC_IDN_HEALTH;
805
+ status = QUERY_RESULT_SUCCESS;
806
+ break;
807
+ default:
808
+ length = 0;
809
+ trace_ufs_err_query_invalid_idn(req->req_upiu.qr.opcode, idn);
810
+ status = QUERY_RESULT_INVALID_IDN;
811
+ }
812
+
813
+ if (length > req->rsp_upiu.qr.data[0]) {
814
+ length = req->rsp_upiu.qr.data[0];
815
+ }
816
+ req->rsp_upiu.qr.opcode = req->req_upiu.qr.opcode;
817
+ req->rsp_upiu.qr.idn = req->req_upiu.qr.idn;
818
+ req->rsp_upiu.qr.index = req->req_upiu.qr.index;
819
+ req->rsp_upiu.qr.selector = req->req_upiu.qr.selector;
820
+ req->rsp_upiu.qr.length = cpu_to_be16(length);
821
+
822
+ return status;
823
+}
824
+
825
+static QueryRespCode ufs_exec_query_read(UfsRequest *req)
826
+{
827
+ QueryRespCode status;
828
+ switch (req->req_upiu.qr.opcode) {
829
+ case UPIU_QUERY_OPCODE_NOP:
830
+ status = QUERY_RESULT_SUCCESS;
831
+ break;
832
+ case UPIU_QUERY_OPCODE_READ_DESC:
833
+ status = ufs_read_desc(req);
834
+ break;
835
+ case UPIU_QUERY_OPCODE_READ_ATTR:
836
+ status = ufs_exec_query_attr(req, UFS_QUERY_ATTR_READ);
837
+ break;
838
+ case UPIU_QUERY_OPCODE_READ_FLAG:
839
+ status = ufs_exec_query_flag(req, UFS_QUERY_FLAG_READ);
840
+ break;
841
+ default:
842
+ trace_ufs_err_query_invalid_opcode(req->req_upiu.qr.opcode);
843
+ status = QUERY_RESULT_INVALID_OPCODE;
844
+ break;
845
+ }
846
+
847
+ return status;
848
+}
849
+
850
+static QueryRespCode ufs_exec_query_write(UfsRequest *req)
851
+{
852
+ QueryRespCode status;
853
+ switch (req->req_upiu.qr.opcode) {
854
+ case UPIU_QUERY_OPCODE_NOP:
855
+ status = QUERY_RESULT_SUCCESS;
856
+ break;
857
+ case UPIU_QUERY_OPCODE_WRITE_DESC:
858
+ /* write descriptor is not supported */
859
+ status = QUERY_RESULT_NOT_WRITEABLE;
860
+ break;
861
+ case UPIU_QUERY_OPCODE_WRITE_ATTR:
862
+ status = ufs_exec_query_attr(req, UFS_QUERY_ATTR_WRITE);
863
+ break;
864
+ case UPIU_QUERY_OPCODE_SET_FLAG:
865
+ status = ufs_exec_query_flag(req, UFS_QUERY_FLAG_SET);
866
+ break;
867
+ case UPIU_QUERY_OPCODE_CLEAR_FLAG:
868
+ status = ufs_exec_query_flag(req, UFS_QUERY_FLAG_CLEAR);
869
+ break;
870
+ case UPIU_QUERY_OPCODE_TOGGLE_FLAG:
871
+ status = ufs_exec_query_flag(req, UFS_QUERY_FLAG_TOGGLE);
872
+ break;
873
+ default:
874
+ trace_ufs_err_query_invalid_opcode(req->req_upiu.qr.opcode);
875
+ status = QUERY_RESULT_INVALID_OPCODE;
876
+ break;
877
+ }
878
+
879
+ return status;
880
+}
881
+
882
+static UfsReqResult ufs_exec_query_cmd(UfsRequest *req)
883
+{
884
+ uint8_t query_func = req->req_upiu.header.query_func;
885
+ uint16_t data_segment_length;
886
+ QueryRespCode status;
887
+
888
+ trace_ufs_exec_query_cmd(req->slot, req->req_upiu.qr.opcode);
889
+ if (query_func == UPIU_QUERY_FUNC_STANDARD_READ_REQUEST) {
890
+ status = ufs_exec_query_read(req);
891
+ } else if (query_func == UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST) {
892
+ status = ufs_exec_query_write(req);
893
+ } else {
894
+ status = QUERY_RESULT_GENERAL_FAILURE;
895
+ }
896
+
897
+ data_segment_length = be16_to_cpu(req->rsp_upiu.qr.length);
898
+ ufs_build_upiu_header(req, UPIU_TRANSACTION_QUERY_RSP, 0, status, 0,
899
+ data_segment_length);
900
+
901
+ if (status != QUERY_RESULT_SUCCESS) {
902
+ return UFS_REQUEST_FAIL;
903
+ }
904
+ return UFS_REQUEST_SUCCESS;
905
+}
906
+
907
+static void ufs_exec_req(UfsRequest *req)
908
+{
909
+ UfsReqResult req_result;
910
+
911
+ if (ufs_dma_read_upiu(req)) {
912
+ return;
913
+ }
914
+
915
+ switch (req->req_upiu.header.trans_type) {
916
+ case UPIU_TRANSACTION_NOP_OUT:
917
+ req_result = ufs_exec_nop_cmd(req);
918
+ break;
919
+ case UPIU_TRANSACTION_COMMAND:
920
+ /* Not yet implemented */
921
+ req_result = UFS_REQUEST_FAIL;
922
+ break;
923
+ case UPIU_TRANSACTION_QUERY_REQ:
924
+ req_result = ufs_exec_query_cmd(req);
925
+ break;
926
+ default:
927
+ trace_ufs_err_invalid_trans_code(req->slot,
928
+ req->req_upiu.header.trans_type);
929
+ req_result = UFS_REQUEST_FAIL;
930
+ }
931
+
932
+ ufs_complete_req(req, req_result);
933
+}
934
+
935
+static void ufs_process_req(void *opaque)
936
+{
937
+ UfsHc *u = opaque;
938
+ UfsRequest *req;
939
+ int slot;
940
+
941
+ for (slot = 0; slot < u->params.nutrs; slot++) {
942
+ req = &u->req_list[slot];
943
+
944
+ if (req->state != UFS_REQUEST_READY) {
945
+ continue;
218
+ }
946
+ }
219
+
947
+ trace_ufs_process_req(slot);
220
+ if force == True:
948
+ req->state = UFS_REQUEST_RUNNING;
221
+ args['force'] = True
949
+
222
+
950
+ ufs_exec_req(req);
223
+ result = self.vm.qmp('x-blockdev-amend', **args)
951
+ }
224
+ assert result['return'] == {}
952
+}
225
+ self.vm.run_job('job_erase_key')
953
+
226
+
954
+static void ufs_complete_req(UfsRequest *req, UfsReqResult req_result)
227
+ ###########################################################################
955
+{
228
+ # create image, and change its key
956
+ UfsHc *u = req->hc;
229
+ def testChangeKey(self):
957
+ assert(req->state == UFS_REQUEST_RUNNING);
230
+
958
+
231
+ # create the image with secret0 and open it
959
+ if (req_result == UFS_REQUEST_SUCCESS) {
232
+ self.createImg(test_img, self.secrets[0]);
960
+ req->utrd.header.dword_2 = cpu_to_le32(OCS_SUCCESS);
233
+ self.openImageQmp("testdev", test_img, self.secrets[0])
961
+ } else {
234
+
962
+ req->utrd.header.dword_2 = cpu_to_le32(OCS_INVALID_CMD_TABLE_ATTR);
235
+ # add key to slot 1
963
+ }
236
+ self.addKeyQmp("testdev", new_secret = self.secrets[1])
964
+
237
+
965
+ trace_ufs_complete_req(req->slot);
238
+ # add key to slot 5
966
+ req->state = UFS_REQUEST_COMPLETE;
239
+ self.addKeyQmp("testdev", new_secret = self.secrets[2], slot=5)
967
+ qemu_bh_schedule(u->complete_bh);
240
+
968
+}
241
+ # erase key from slot 0
969
+
242
+ self.eraseKeyQmp("testdev", old_secret = self.secrets[0])
970
+static void ufs_clear_req(UfsRequest *req)
243
+
971
+{
244
+ #reopen the image with secret1
972
+ if (req->sg != NULL) {
245
+ self.closeImageQmp("testdev")
973
+ qemu_sglist_destroy(req->sg);
246
+ self.openImageQmp("testdev", test_img, self.secrets[1])
974
+ g_free(req->sg);
247
+
975
+ req->sg = NULL;
248
+ # close and erase the image for good
976
+ }
249
+ self.closeImageQmp("testdev")
977
+
250
+ os.remove(test_img)
978
+ memset(&req->utrd, 0, sizeof(req->utrd));
251
+
979
+ memset(&req->req_upiu, 0, sizeof(req->req_upiu));
252
+ # test that if we erase the old password,
980
+ memset(&req->rsp_upiu, 0, sizeof(req->rsp_upiu));
253
+ # we can still change the encryption keys using 'old-secret'
981
+}
254
+ def testOldPassword(self):
982
+
255
+
983
+static void ufs_sendback_req(void *opaque)
256
+ # create the image with secret0 and open it
984
+{
257
+ self.createImg(test_img, self.secrets[0]);
985
+ UfsHc *u = opaque;
258
+ self.openImageQmp("testdev", test_img, self.secrets[0])
986
+ UfsRequest *req;
259
+
987
+ int slot;
260
+ # add key to slot 1
988
+
261
+ self.addKeyQmp("testdev", new_secret = self.secrets[1])
989
+ for (slot = 0; slot < u->params.nutrs; slot++) {
262
+
990
+ req = &u->req_list[slot];
263
+ # erase key from slot 0
991
+
264
+ self.eraseKeyQmp("testdev", old_secret = self.secrets[0])
992
+ if (req->state != UFS_REQUEST_COMPLETE) {
265
+
993
+ continue;
266
+ # this will fail as the old password is no longer valid
267
+ self.addKeyQmp("testdev", new_secret = self.secrets[2])
268
+
269
+ # this will work
270
+ self.addKeyQmp("testdev", new_secret = self.secrets[2], secret = self.secrets[1])
271
+
272
+ # close and erase the image for good
273
+ self.closeImageQmp("testdev")
274
+ os.remove(test_img)
275
+
276
+ def testUseForceLuke(self):
277
+
278
+ self.createImg(test_img, self.secrets[0]);
279
+ self.openImageQmp("testdev", test_img, self.secrets[0])
280
+
281
+ # Add bunch of secrets
282
+ self.addKeyQmp("testdev", new_secret = self.secrets[1], slot=4)
283
+ self.addKeyQmp("testdev", new_secret = self.secrets[4], slot=2)
284
+
285
+ # overwrite an active secret
286
+ self.addKeyQmp("testdev", new_secret = self.secrets[5], slot=2)
287
+ self.addKeyQmp("testdev", new_secret = self.secrets[5], slot=2, force=True)
288
+
289
+ self.addKeyQmp("testdev", new_secret = self.secrets[0])
290
+
291
+ # Now erase all the secrets
292
+ self.eraseKeyQmp("testdev", old_secret = self.secrets[5])
293
+ self.eraseKeyQmp("testdev", slot=4)
294
+
295
+ # erase last keyslot
296
+ self.eraseKeyQmp("testdev", old_secret = self.secrets[0])
297
+ self.eraseKeyQmp("testdev", old_secret = self.secrets[0], force=True)
298
+
299
+ self.closeImageQmp("testdev")
300
+ os.remove(test_img)
301
+
302
+
303
+if __name__ == '__main__':
304
+ # Encrypted formats support
305
+ iotests.activate_logging()
306
+ iotests.main(supported_fmts = ['qcow2', 'luks'])
307
diff --git a/tests/qemu-iotests/295.out b/tests/qemu-iotests/295.out
308
new file mode 100644
309
index XXXXXXX..XXXXXXX
310
--- /dev/null
311
+++ b/tests/qemu-iotests/295.out
312
@@ -XXX,XX +XXX,XX @@
313
+{"execute": "job-dismiss", "arguments": {"id": "job_add_key"}}
314
+{"return": {}}
315
+{"execute": "job-dismiss", "arguments": {"id": "job_add_key"}}
316
+{"return": {}}
317
+{"execute": "job-dismiss", "arguments": {"id": "job_erase_key"}}
318
+{"return": {}}
319
+{"execute": "job-dismiss", "arguments": {"id": "job_add_key"}}
320
+{"return": {}}
321
+{"execute": "job-dismiss", "arguments": {"id": "job_erase_key"}}
322
+{"return": {}}
323
+Job failed: Invalid password, cannot unlock any keyslot
324
+{"execute": "job-dismiss", "arguments": {"id": "job_add_key"}}
325
+{"return": {}}
326
+{"execute": "job-dismiss", "arguments": {"id": "job_add_key"}}
327
+{"return": {}}
328
+{"execute": "job-dismiss", "arguments": {"id": "job_add_key"}}
329
+{"return": {}}
330
+{"execute": "job-dismiss", "arguments": {"id": "job_add_key"}}
331
+{"return": {}}
332
+Job failed: Refusing to overwrite active keyslot 2 - please erase it first
333
+{"execute": "job-dismiss", "arguments": {"id": "job_add_key"}}
334
+{"return": {}}
335
+{"execute": "job-dismiss", "arguments": {"id": "job_add_key"}}
336
+{"return": {}}
337
+{"execute": "job-dismiss", "arguments": {"id": "job_add_key"}}
338
+{"return": {}}
339
+{"execute": "job-dismiss", "arguments": {"id": "job_erase_key"}}
340
+{"return": {}}
341
+{"execute": "job-dismiss", "arguments": {"id": "job_erase_key"}}
342
+{"return": {}}
343
+Job failed: All the active keyslots match the (old) password that was given and erasing them will erase all the data in the image irreversibly - refusing operation
344
+{"execute": "job-dismiss", "arguments": {"id": "job_erase_key"}}
345
+{"return": {}}
346
+{"execute": "job-dismiss", "arguments": {"id": "job_erase_key"}}
347
+{"return": {}}
348
+...
349
+----------------------------------------------------------------------
350
+Ran 3 tests
351
+
352
+OK
353
diff --git a/tests/qemu-iotests/296 b/tests/qemu-iotests/296
354
new file mode 100755
355
index XXXXXXX..XXXXXXX
356
--- /dev/null
357
+++ b/tests/qemu-iotests/296
358
@@ -XXX,XX +XXX,XX @@
359
+#!/usr/bin/env python3
360
+#
361
+# Test case for encryption key management versus image sharing
362
+#
363
+# Copyright (C) 2019 Red Hat, Inc.
364
+#
365
+# This program is free software; you can redistribute it and/or modify
366
+# it under the terms of the GNU General Public License as published by
367
+# the Free Software Foundation; either version 2 of the License, or
368
+# (at your option) any later version.
369
+#
370
+# This program is distributed in the hope that it will be useful,
371
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
372
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
373
+# GNU General Public License for more details.
374
+#
375
+# You should have received a copy of the GNU General Public License
376
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
377
+#
378
+
379
+import iotests
380
+import os
381
+import time
382
+import json
383
+
384
+test_img = os.path.join(iotests.test_dir, 'test.img')
385
+
386
+class Secret:
387
+ def __init__(self, index):
388
+ self._id = "keysec" + str(index)
389
+ # you are not supposed to see the password...
390
+ self._secret = "hunter" + str(index)
391
+
392
+ def id(self):
393
+ return self._id
394
+
395
+ def secret(self):
396
+ return self._secret
397
+
398
+ def to_cmdline_object(self):
399
+ return [ "secret,id=" + self._id + ",data=" + self._secret]
400
+
401
+ def to_qmp_object(self):
402
+ return { "qom_type" : "secret", "id": self.id(),
403
+ "props": { "data": self.secret() } }
404
+
405
+################################################################################
406
+
407
+class EncryptionSetupTestCase(iotests.QMPTestCase):
408
+
409
+ # test case startup
410
+ def setUp(self):
411
+
412
+ # start the VMs
413
+ self.vm1 = iotests.VM(path_suffix = 'VM1')
414
+ self.vm2 = iotests.VM(path_suffix = 'VM2')
415
+ self.vm1.launch()
416
+ self.vm2.launch()
417
+
418
+ # create the secrets and load 'em into the VMs
419
+ self.secrets = [ Secret(i) for i in range(0, 4) ]
420
+ for secret in self.secrets:
421
+ result = self.vm1.qmp("object-add", **secret.to_qmp_object())
422
+ self.assert_qmp(result, 'return', {})
423
+ result = self.vm2.qmp("object-add", **secret.to_qmp_object())
424
+ self.assert_qmp(result, 'return', {})
425
+
426
+ # test case shutdown
427
+ def tearDown(self):
428
+ # stop the VM
429
+ self.vm1.shutdown()
430
+ self.vm2.shutdown()
431
+
432
+ ###########################################################################
433
+ # create the encrypted block device using qemu-img
434
+ def createImg(self, file, secret):
435
+
436
+ output = iotests.qemu_img_pipe(
437
+ 'create',
438
+ '--object', *secret.to_cmdline_object(),
439
+ '-f', iotests.imgfmt,
440
+ '-o', 'key-secret=' + secret.id(),
441
+ '-o', 'iter-time=10',
442
+ file,
443
+ '1M')
444
+
445
+ iotests.log(output, filters=[iotests.filter_test_dir])
446
+
447
+ # attempts to add a key using qemu-img
448
+ def addKey(self, file, secret, new_secret):
449
+
450
+ image_options = {
451
+ 'key-secret' : secret.id(),
452
+ 'driver' : iotests.imgfmt,
453
+ 'file' : {
454
+ 'driver':'file',
455
+ 'filename': file,
456
+ }
457
+ }
458
+
459
+ output = iotests.qemu_img_pipe(
460
+ 'amend',
461
+ '--object', *secret.to_cmdline_object(),
462
+ '--object', *new_secret.to_cmdline_object(),
463
+
464
+ '-o', 'state=active',
465
+ '-o', 'new-secret=' + new_secret.id(),
466
+ '-o', 'iter-time=10',
467
+
468
+ "json:" + json.dumps(image_options)
469
+ )
470
+
471
+ iotests.log(output, filters=[iotests.filter_test_dir])
472
+
473
+ ###########################################################################
474
+ # open an encrypted block device
475
+ def openImageQmp(self, vm, id, file, secret,
476
+ readOnly = False, reOpen = False):
477
+
478
+ command = 'x-blockdev-reopen' if reOpen else 'blockdev-add'
479
+
480
+ result = vm.qmp(command, **
481
+ {
482
+ 'driver': iotests.imgfmt,
483
+ 'node-name': id,
484
+ 'read-only': readOnly,
485
+ 'key-secret' : secret.id(),
486
+ 'file': {
487
+ 'driver': 'file',
488
+ 'filename': test_img,
489
+ }
490
+ }
491
+ )
492
+ self.assert_qmp(result, 'return', {})
493
+
494
+ # close the encrypted block device
495
+ def closeImageQmp(self, vm, id):
496
+ result = vm.qmp('blockdev-del', **{ 'node-name': id })
497
+ self.assert_qmp(result, 'return', {})
498
+
499
+ ###########################################################################
500
+
501
+ # add a key to an encrypted block device
502
+ def addKeyQmp(self, vm, id, new_secret):
503
+
504
+ args = {
505
+ 'node-name': id,
506
+ 'job-id' : 'job0',
507
+ 'options' : {
508
+ 'state' : 'active',
509
+ 'driver' : iotests.imgfmt,
510
+ 'new-secret': new_secret.id(),
511
+ 'iter-time' : 10
512
+ },
513
+ }
994
+ }
514
+
995
+
515
+ result = vm.qmp('x-blockdev-amend', **args)
996
+ if (ufs_dma_write_upiu(req)) {
516
+ assert result['return'] == {}
997
+ req->state = UFS_REQUEST_ERROR;
517
+ vm.run_job('job0')
998
+ continue;
518
+
999
+ }
519
+ # test that when the image opened by two qemu processes,
1000
+
520
+ # neither of them can update the image
1001
+ /*
521
+ def test1(self):
1002
+ * TODO: UTP Transfer Request Interrupt Aggregation Control is not yet
522
+ self.createImg(test_img, self.secrets[0]);
1003
+ * supported
523
+
1004
+ */
524
+ # VM1 opens the image and adds a key
1005
+ if (le32_to_cpu(req->utrd.header.dword_2) != OCS_SUCCESS ||
525
+ self.openImageQmp(self.vm1, "testdev", test_img, self.secrets[0])
1006
+ le32_to_cpu(req->utrd.header.dword_0) & UTP_REQ_DESC_INT_CMD) {
526
+ self.addKeyQmp(self.vm1, "testdev", new_secret = self.secrets[1])
1007
+ u->reg.is = FIELD_DP32(u->reg.is, IS, UTRCS, 1);
527
+
1008
+ }
528
+
1009
+
529
+ # VM2 opens the image
1010
+ u->reg.utrldbr &= ~(1 << slot);
530
+ self.openImageQmp(self.vm2, "testdev", test_img, self.secrets[0])
1011
+ u->reg.utrlcnr |= (1 << slot);
531
+
1012
+
532
+
1013
+ trace_ufs_sendback_req(req->slot);
533
+ # neither VMs now should be able to add a key
1014
+
534
+ self.addKeyQmp(self.vm1, "testdev", new_secret = self.secrets[2])
1015
+ ufs_clear_req(req);
535
+ self.addKeyQmp(self.vm2, "testdev", new_secret = self.secrets[2])
1016
+ req->state = UFS_REQUEST_IDLE;
536
+
1017
+ }
537
+
1018
+
538
+ # VM 1 closes the image
1019
+ ufs_irq_check(u);
539
+ self.closeImageQmp(self.vm1, "testdev")
1020
+}
540
+
1021
+
541
+
1022
static bool ufs_check_constraints(UfsHc *u, Error **errp)
542
+ # now VM2 can add the key
1023
{
543
+ self.addKeyQmp(self.vm2, "testdev", new_secret = self.secrets[2])
1024
if (u->params.nutrs > UFS_MAX_NUTRS) {
544
+
1025
@@ -XXX,XX +XXX,XX @@ static void ufs_init_pci(UfsHc *u, PCIDevice *pci_dev)
545
+
1026
u->irq = pci_allocate_irq(pci_dev);
546
+ # qemu-img should also not be able to add a key
1027
}
547
+ self.addKey(test_img, self.secrets[0], self.secrets[2])
1028
548
+
1029
+static void ufs_init_state(UfsHc *u)
549
+ # cleanup
1030
+{
550
+ self.closeImageQmp(self.vm2, "testdev")
1031
+ u->req_list = g_new0(UfsRequest, u->params.nutrs);
551
+ os.remove(test_img)
1032
+
552
+
1033
+ for (int i = 0; i < u->params.nutrs; i++) {
553
+
1034
+ u->req_list[i].hc = u;
554
+ def test2(self):
1035
+ u->req_list[i].slot = i;
555
+ self.createImg(test_img, self.secrets[0]);
1036
+ u->req_list[i].sg = NULL;
556
+
1037
+ u->req_list[i].state = UFS_REQUEST_IDLE;
557
+ # VM1 opens the image readonly
1038
+ }
558
+ self.openImageQmp(self.vm1, "testdev", test_img, self.secrets[0],
1039
+
559
+ readOnly = True)
1040
+ u->doorbell_bh = qemu_bh_new_guarded(ufs_process_req, u,
560
+
1041
+ &DEVICE(u)->mem_reentrancy_guard);
561
+ # VM2 opens the image
1042
+ u->complete_bh = qemu_bh_new_guarded(ufs_sendback_req, u,
562
+ self.openImageQmp(self.vm2, "testdev", test_img, self.secrets[0])
1043
+ &DEVICE(u)->mem_reentrancy_guard);
563
+
1044
+}
564
+ # VM1 can't add a key since image is readonly
1045
+
565
+ self.addKeyQmp(self.vm1, "testdev", new_secret = self.secrets[2])
1046
static void ufs_init_hc(UfsHc *u)
566
+
1047
{
567
+ # VM2 can't add a key since VM is has the image opened
1048
uint32_t cap = 0;
568
+ self.addKeyQmp(self.vm2, "testdev", new_secret = self.secrets[2])
1049
@@ -XXX,XX +XXX,XX @@ static void ufs_init_hc(UfsHc *u)
569
+
1050
cap = FIELD_DP32(cap, CAP, CS, 0);
570
+
1051
u->reg.cap = cap;
571
+ #VM1 reopens the image read-write
1052
u->reg.ver = UFS_SPEC_VER;
572
+ self.openImageQmp(self.vm1, "testdev", test_img, self.secrets[0],
1053
+
573
+ reOpen = True, readOnly = False)
1054
+ memset(&u->device_desc, 0, sizeof(DeviceDescriptor));
574
+
1055
+ u->device_desc.length = sizeof(DeviceDescriptor);
575
+ # VM1 still can't add the key
1056
+ u->device_desc.descriptor_idn = QUERY_DESC_IDN_DEVICE;
576
+ self.addKeyQmp(self.vm1, "testdev", new_secret = self.secrets[2])
1057
+ u->device_desc.device_sub_class = 0x01;
577
+
1058
+ u->device_desc.number_lu = 0x00;
578
+ # VM2 gets away
1059
+ u->device_desc.number_wlu = 0x04;
579
+ self.closeImageQmp(self.vm2, "testdev")
1060
+ /* TODO: Revisit it when Power Management is implemented */
580
+
1061
+ u->device_desc.init_power_mode = 0x01; /* Active Mode */
581
+ # VM1 now can add the key
1062
+ u->device_desc.high_priority_lun = 0x7F; /* Same Priority */
582
+ self.addKeyQmp(self.vm1, "testdev", new_secret = self.secrets[2])
1063
+ u->device_desc.spec_version = cpu_to_be16(UFS_SPEC_VER);
583
+
1064
+ u->device_desc.manufacturer_name = 0x00;
584
+ self.closeImageQmp(self.vm1, "testdev")
1065
+ u->device_desc.product_name = 0x01;
585
+ os.remove(test_img)
1066
+ u->device_desc.serial_number = 0x02;
586
+
1067
+ u->device_desc.oem_id = 0x03;
587
+
1068
+ u->device_desc.ud_0_base_offset = 0x16;
588
+if __name__ == '__main__':
1069
+ u->device_desc.ud_config_p_length = 0x1A;
589
+ # support only raw luks since luks encrypted qcow2 is a proper
1070
+ u->device_desc.device_rtt_cap = 0x02;
590
+ # format driver which doesn't allow any sharing
1071
+ u->device_desc.queue_depth = u->params.nutrs;
591
+ iotests.activate_logging()
1072
+ u->device_desc.product_revision_level = 0x04;
592
+ iotests.main(supported_fmts = ['luks'])
1073
+
593
diff --git a/tests/qemu-iotests/296.out b/tests/qemu-iotests/296.out
1074
+ memset(&u->geometry_desc, 0, sizeof(GeometryDescriptor));
594
new file mode 100644
1075
+ u->geometry_desc.length = sizeof(GeometryDescriptor);
595
index XXXXXXX..XXXXXXX
1076
+ u->geometry_desc.descriptor_idn = QUERY_DESC_IDN_GEOMETRY;
596
--- /dev/null
1077
+ u->geometry_desc.max_number_lu = (UFS_MAX_LUS == 32) ? 0x1 : 0x0;
597
+++ b/tests/qemu-iotests/296.out
1078
+ u->geometry_desc.segment_size = cpu_to_be32(0x2000); /* 4KB */
598
@@ -XXX,XX +XXX,XX @@
1079
+ u->geometry_desc.allocation_unit_size = 0x1; /* 4KB */
599
+Formatting 'TEST_DIR/test.img', fmt=luks size=1048576 key-secret=keysec0 iter-time=10
1080
+ u->geometry_desc.min_addr_block_size = 0x8; /* 4KB */
600
+
1081
+ u->geometry_desc.max_in_buffer_size = 0x8;
601
+{"execute": "job-dismiss", "arguments": {"id": "job0"}}
1082
+ u->geometry_desc.max_out_buffer_size = 0x8;
602
+{"return": {}}
1083
+ u->geometry_desc.rpmb_read_write_size = 0x40;
603
+Job failed: Failed to get shared "consistent read" lock
1084
+ u->geometry_desc.data_ordering =
604
+{"execute": "job-dismiss", "arguments": {"id": "job0"}}
1085
+ 0x0; /* out-of-order data transfer is not supported */
605
+{"return": {}}
1086
+ u->geometry_desc.max_context_id_number = 0x5;
606
+Job failed: Failed to get shared "consistent read" lock
1087
+ u->geometry_desc.supported_memory_types = cpu_to_be16(0x8001);
607
+{"execute": "job-dismiss", "arguments": {"id": "job0"}}
1088
+
608
+{"return": {}}
1089
+ memset(&u->attributes, 0, sizeof(u->attributes));
609
+{"execute": "job-dismiss", "arguments": {"id": "job0"}}
1090
+ u->attributes.max_data_in_size = 0x08;
610
+{"return": {}}
1091
+ u->attributes.max_data_out_size = 0x08;
611
+qemu-img: Failed to get shared "consistent read" lock
1092
+ u->attributes.ref_clk_freq = 0x01; /* 26 MHz */
612
+Is another process using the image [TEST_DIR/test.img]?
1093
+ /* configure descriptor is not supported */
613
+
1094
+ u->attributes.config_descr_lock = 0x01;
614
+Formatting 'TEST_DIR/test.img', fmt=luks size=1048576 key-secret=keysec0 iter-time=10
1095
+ u->attributes.max_num_of_rtt = 0x02;
615
+
1096
+
616
+Job failed: Block node is read-only
1097
+ memset(&u->flags, 0, sizeof(u->flags));
617
+{"execute": "job-dismiss", "arguments": {"id": "job0"}}
1098
+ u->flags.permanently_disable_fw_update = 1;
618
+{"return": {}}
1099
}
619
+Job failed: Failed to get shared "consistent read" lock
1100
620
+{"execute": "job-dismiss", "arguments": {"id": "job0"}}
1101
static void ufs_realize(PCIDevice *pci_dev, Error **errp)
621
+{"return": {}}
1102
@@ -XXX,XX +XXX,XX @@ static void ufs_realize(PCIDevice *pci_dev, Error **errp)
622
+Job failed: Failed to get shared "consistent read" lock
1103
return;
623
+{"execute": "job-dismiss", "arguments": {"id": "job0"}}
1104
}
624
+{"return": {}}
1105
625
+{"execute": "job-dismiss", "arguments": {"id": "job0"}}
1106
+ ufs_init_state(u);
626
+{"return": {}}
1107
ufs_init_hc(u);
627
+..
1108
ufs_init_pci(u, pci_dev);
628
+----------------------------------------------------------------------
1109
}
629
+Ran 2 tests
1110
630
+
1111
+static void ufs_exit(PCIDevice *pci_dev)
631
+OK
1112
+{
632
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
1113
+ UfsHc *u = UFS(pci_dev);
1114
+
1115
+ qemu_bh_delete(u->doorbell_bh);
1116
+ qemu_bh_delete(u->complete_bh);
1117
+
1118
+ for (int i = 0; i < u->params.nutrs; i++) {
1119
+ ufs_clear_req(&u->req_list[i]);
1120
+ }
1121
+ g_free(u->req_list);
1122
+}
1123
+
1124
static Property ufs_props[] = {
1125
DEFINE_PROP_STRING("serial", UfsHc, params.serial),
1126
DEFINE_PROP_UINT8("nutrs", UfsHc, params.nutrs, 32),
1127
@@ -XXX,XX +XXX,XX @@ static void ufs_class_init(ObjectClass *oc, void *data)
1128
PCIDeviceClass *pc = PCI_DEVICE_CLASS(oc);
1129
1130
pc->realize = ufs_realize;
1131
+ pc->exit = ufs_exit;
1132
pc->vendor_id = PCI_VENDOR_ID_REDHAT;
1133
pc->device_id = PCI_DEVICE_ID_REDHAT_UFS;
1134
pc->class_id = PCI_CLASS_STORAGE_UFS;
1135
diff --git a/hw/ufs/trace-events b/hw/ufs/trace-events
633
index XXXXXXX..XXXXXXX 100644
1136
index XXXXXXX..XXXXXXX 100644
634
--- a/tests/qemu-iotests/group
1137
--- a/hw/ufs/trace-events
635
+++ b/tests/qemu-iotests/group
1138
+++ b/hw/ufs/trace-events
636
@@ -XXX,XX +XXX,XX @@
1139
@@ -XXX,XX +XXX,XX @@ ufs_err_dma_read_req_upiu(uint32_t slot, uint64_t addr) "failed to read req upiu
637
292 rw auto quick
1140
ufs_err_dma_read_prdt(uint32_t slot, uint64_t addr) "failed to read prdt. UTRLDBR slot %"PRIu32", prdt addr %"PRIu64""
638
293 rw auto
1141
ufs_err_dma_write_utrd(uint32_t slot, uint64_t addr) "failed to write utrd. UTRLDBR slot %"PRIu32", UTRD dma addr %"PRIu64""
639
294 rw auto quick
1142
ufs_err_dma_write_rsp_upiu(uint32_t slot, uint64_t addr) "failed to write rsp upiu. UTRLDBR slot %"PRIu32", response upiu addr %"PRIu64""
640
+295 rw auto
1143
+ufs_err_utrl_slot_error(uint32_t slot) "UTRLDBR slot %"PRIu32" is in error"
641
+296 rw auto
1144
ufs_err_utrl_slot_busy(uint32_t slot) "UTRLDBR slot %"PRIu32" is busy"
642
297 meta
1145
ufs_err_unsupport_register_offset(uint32_t offset) "Register offset 0x%"PRIx32" is not yet supported"
1146
ufs_err_invalid_register_offset(uint32_t offset) "Register offset 0x%"PRIx32" is invalid"
643
--
1147
--
644
2.26.2
1148
2.41.0
645
646
diff view generated by jsdifflib
1
From: Maxim Levitsky <mlevitsk@redhat.com>
1
From: Jeuk Kim <jeuk20.kim@gmail.com>
2
2
3
Next few patches will expose that functionality to the user.
3
This commit adds support for ufs logical unit.
4
The LU handles processing for the SCSI command,
5
unit descriptor query request.
4
6
5
Signed-off-by: Maxim Levitsky <mlevitsk@redhat.com>
7
This commit enables the UFS device to process
6
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
8
IO requests.
7
Message-Id: <20200608094030.670121-3-mlevitsk@redhat.com>
9
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
Signed-off-by: Jeuk Kim <jeuk20.kim@samsung.com>
11
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
12
Message-id: 898cea923e819dc21a99597bf045a12d7983be28.1691062912.git.jeuk20.kim@samsung.com
13
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
9
---
14
---
10
qapi/crypto.json | 59 ++++++-
15
hw/ufs/ufs.h | 43 ++
11
crypto/block-luks.c | 416 +++++++++++++++++++++++++++++++++++++++++++-
16
include/scsi/constants.h | 1 +
12
2 files changed, 469 insertions(+), 6 deletions(-)
17
hw/ufs/lu.c | 1445 ++++++++++++++++++++++++++++++++++++++
18
hw/ufs/ufs.c | 252 ++++++-
19
hw/ufs/meson.build | 2 +-
20
hw/ufs/trace-events | 25 +
21
6 files changed, 1761 insertions(+), 7 deletions(-)
22
create mode 100644 hw/ufs/lu.c
13
23
14
diff --git a/qapi/crypto.json b/qapi/crypto.json
24
diff --git a/hw/ufs/ufs.h b/hw/ufs/ufs.h
15
index XXXXXXX..XXXXXXX 100644
25
index XXXXXXX..XXXXXXX 100644
16
--- a/qapi/crypto.json
26
--- a/hw/ufs/ufs.h
17
+++ b/qapi/crypto.json
27
+++ b/hw/ufs/ufs.h
18
@@ -XXX,XX +XXX,XX @@
28
@@ -XXX,XX +XXX,XX @@
19
'uuid': 'str',
29
#define UFS_MAX_LUS 32
20
'slots': [ 'QCryptoBlockInfoLUKSSlot' ] }}
30
#define UFS_BLOCK_SIZE 4096
21
31
22
-
32
+typedef struct UfsBusClass {
23
##
33
+ BusClass parent_class;
24
# @QCryptoBlockInfo:
34
+ bool (*parent_check_address)(BusState *bus, DeviceState *dev, Error **errp);
25
#
35
+} UfsBusClass;
36
+
37
+typedef struct UfsBus {
38
+ SCSIBus parent_bus;
39
+} UfsBus;
40
+
41
+#define TYPE_UFS_BUS "ufs-bus"
42
+DECLARE_OBJ_CHECKERS(UfsBus, UfsBusClass, UFS_BUS, TYPE_UFS_BUS)
43
+
44
typedef enum UfsRequestState {
45
UFS_REQUEST_IDLE = 0,
46
UFS_REQUEST_READY = 1,
47
@@ -XXX,XX +XXX,XX @@ typedef enum UfsRequestState {
48
typedef enum UfsReqResult {
49
UFS_REQUEST_SUCCESS = 0,
50
UFS_REQUEST_FAIL = 1,
51
+ UFS_REQUEST_NO_COMPLETE = 2,
52
} UfsReqResult;
53
54
typedef struct UfsRequest {
55
@@ -XXX,XX +XXX,XX @@ typedef struct UfsRequest {
56
QEMUSGList *sg;
57
} UfsRequest;
58
59
+typedef struct UfsLu {
60
+ SCSIDevice qdev;
61
+ uint8_t lun;
62
+ UnitDescriptor unit_desc;
63
+} UfsLu;
64
+
65
+typedef struct UfsWLu {
66
+ SCSIDevice qdev;
67
+ uint8_t lun;
68
+} UfsWLu;
69
+
70
typedef struct UfsParams {
71
char *serial;
72
uint8_t nutrs; /* Number of UTP Transfer Request Slots */
73
@@ -XXX,XX +XXX,XX @@ typedef struct UfsParams {
74
75
typedef struct UfsHc {
76
PCIDevice parent_obj;
77
+ UfsBus bus;
78
MemoryRegion iomem;
79
UfsReg reg;
80
UfsParams params;
81
uint32_t reg_size;
82
UfsRequest *req_list;
83
84
+ UfsLu *lus[UFS_MAX_LUS];
85
+ UfsWLu *report_wlu;
86
+ UfsWLu *dev_wlu;
87
+ UfsWLu *boot_wlu;
88
+ UfsWLu *rpmb_wlu;
89
DeviceDescriptor device_desc;
90
GeometryDescriptor geometry_desc;
91
Attributes attributes;
92
@@ -XXX,XX +XXX,XX @@ typedef struct UfsHc {
93
#define TYPE_UFS "ufs"
94
#define UFS(obj) OBJECT_CHECK(UfsHc, (obj), TYPE_UFS)
95
96
+#define TYPE_UFS_LU "ufs-lu"
97
+#define UFSLU(obj) OBJECT_CHECK(UfsLu, (obj), TYPE_UFS_LU)
98
+
99
+#define TYPE_UFS_WLU "ufs-wlu"
100
+#define UFSWLU(obj) OBJECT_CHECK(UfsWLu, (obj), TYPE_UFS_WLU)
101
+
102
typedef enum UfsQueryFlagPerm {
103
UFS_QUERY_FLAG_NONE = 0x0,
104
UFS_QUERY_FLAG_READ = 0x1,
105
@@ -XXX,XX +XXX,XX @@ typedef enum UfsQueryAttrPerm {
106
UFS_QUERY_ATTR_WRITE = 0x2,
107
} UfsQueryAttrPerm;
108
109
+static inline bool is_wlun(uint8_t lun)
110
+{
111
+ return (lun == UFS_UPIU_REPORT_LUNS_WLUN ||
112
+ lun == UFS_UPIU_UFS_DEVICE_WLUN || lun == UFS_UPIU_BOOT_WLUN ||
113
+ lun == UFS_UPIU_RPMB_WLUN);
114
+}
115
+
116
#endif /* HW_UFS_UFS_H */
117
diff --git a/include/scsi/constants.h b/include/scsi/constants.h
118
index XXXXXXX..XXXXXXX 100644
119
--- a/include/scsi/constants.h
120
+++ b/include/scsi/constants.h
26
@@ -XXX,XX +XXX,XX @@
121
@@ -XXX,XX +XXX,XX @@
27
'discriminator': 'format',
122
#define MODE_PAGE_FLEXIBLE_DISK_GEOMETRY 0x05
28
'data': { 'luks': 'QCryptoBlockInfoLUKS' } }
123
#define MODE_PAGE_CACHING 0x08
29
124
#define MODE_PAGE_AUDIO_CTL 0x0e
30
+##
125
+#define MODE_PAGE_CONTROL 0x0a
31
+# @QCryptoBlockLUKSKeyslotState:
126
#define MODE_PAGE_POWER 0x1a
32
+#
127
#define MODE_PAGE_FAULT_FAIL 0x1c
33
+# Defines state of keyslots that are affected by the update
128
#define MODE_PAGE_TO_PROTECT 0x1d
34
+#
129
diff --git a/hw/ufs/lu.c b/hw/ufs/lu.c
35
+# @active: The slots contain the given password and marked as active
130
new file mode 100644
36
+# @inactive: The slots are erased (contain garbage) and marked as inactive
131
index XXXXXXX..XXXXXXX
37
+#
132
--- /dev/null
38
+# Since: 5.1
133
+++ b/hw/ufs/lu.c
39
+##
40
+{ 'enum': 'QCryptoBlockLUKSKeyslotState',
41
+ 'data': [ 'active', 'inactive' ] }
42
+
43
44
+##
45
+# @QCryptoBlockAmendOptionsLUKS:
46
+#
47
+# This struct defines the update parameters that activate/de-activate set
48
+# of keyslots
49
+#
50
+# @state: the desired state of the keyslots
51
+#
52
+# @new-secret: The ID of a QCryptoSecret object providing the password to be
53
+# written into added active keyslots
54
+#
55
+# @old-secret: Optional (for deactivation only)
56
+# If given will deactive all keyslots that
57
+# match password located in QCryptoSecret with this ID
58
+#
59
+# @iter-time: Optional (for activation only)
60
+# Number of milliseconds to spend in
61
+# PBKDF passphrase processing for the newly activated keyslot.
62
+# Currently defaults to 2000.
63
+#
64
+# @keyslot: Optional. ID of the keyslot to activate/deactivate.
65
+# For keyslot activation, keyslot should not be active already
66
+# (this is unsafe to update an active keyslot),
67
+# but possible if 'force' parameter is given.
68
+# If keyslot is not given, first free keyslot will be written.
69
+#
70
+# For keyslot deactivation, this parameter specifies the exact
71
+# keyslot to deactivate
72
+#
73
+# @secret: Optional. The ID of a QCryptoSecret object providing the
74
+# password to use to retrive current master key.
75
+# Defaults to the same secret that was used to open the image
76
+#
77
+#
78
+# Since 5.1
79
+##
80
+{ 'struct': 'QCryptoBlockAmendOptionsLUKS',
81
+ 'data': { 'state': 'QCryptoBlockLUKSKeyslotState',
82
+ '*new-secret': 'str',
83
+ '*old-secret': 'str',
84
+ '*keyslot': 'int',
85
+ '*iter-time': 'int',
86
+ '*secret': 'str' } }
87
88
##
89
# @QCryptoBlockAmendOptions:
90
@@ -XXX,XX +XXX,XX @@
134
@@ -XXX,XX +XXX,XX @@
91
'base': 'QCryptoBlockOptionsBase',
92
'discriminator': 'format',
93
'data': {
94
- } }
95
+ 'luks': 'QCryptoBlockAmendOptionsLUKS' } }
96
diff --git a/crypto/block-luks.c b/crypto/block-luks.c
97
index XXXXXXX..XXXXXXX 100644
98
--- a/crypto/block-luks.c
99
+++ b/crypto/block-luks.c
100
@@ -XXX,XX +XXX,XX @@
101
#include "qemu/uuid.h"
102
103
#include "qemu/coroutine.h"
104
+#include "qemu/bitmap.h"
105
106
/*
107
* Reference for the LUKS format implemented here is
108
@@ -XXX,XX +XXX,XX @@ typedef struct QCryptoBlockLUKSKeySlot QCryptoBlockLUKSKeySlot;
109
110
#define QCRYPTO_BLOCK_LUKS_SECTOR_SIZE 512LL
111
112
+#define QCRYPTO_BLOCK_LUKS_DEFAULT_ITER_TIME_MS 2000
113
+#define QCRYPTO_BLOCK_LUKS_ERASE_ITERATIONS 40
114
+
115
static const char qcrypto_block_luks_magic[QCRYPTO_BLOCK_LUKS_MAGIC_LEN] = {
116
'L', 'U', 'K', 'S', 0xBA, 0xBE
117
};
118
@@ -XXX,XX +XXX,XX @@ struct QCryptoBlockLUKS {
119
120
/* Hash algorithm used in pbkdf2 function */
121
QCryptoHashAlgorithm hash_alg;
122
+
123
+ /* Name of the secret that was used to open the image */
124
+ char *secret;
125
};
126
127
128
@@ -XXX,XX +XXX,XX @@ qcrypto_block_luks_store_key(QCryptoBlock *block,
129
Error **errp)
130
{
131
QCryptoBlockLUKS *luks = block->opaque;
132
- QCryptoBlockLUKSKeySlot *slot = &luks->header.key_slots[slot_idx];
133
+ QCryptoBlockLUKSKeySlot *slot;
134
g_autofree uint8_t *splitkey = NULL;
135
size_t splitkeylen;
136
g_autofree uint8_t *slotkey = NULL;
137
@@ -XXX,XX +XXX,XX @@ qcrypto_block_luks_store_key(QCryptoBlock *block,
138
uint64_t iters;
139
int ret = -1;
140
141
+ assert(slot_idx < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS);
142
+ slot = &luks->header.key_slots[slot_idx];
143
if (qcrypto_random_bytes(slot->salt,
144
QCRYPTO_BLOCK_LUKS_SALT_LEN,
145
errp) < 0) {
146
@@ -XXX,XX +XXX,XX @@ qcrypto_block_luks_load_key(QCryptoBlock *block,
147
Error **errp)
148
{
149
QCryptoBlockLUKS *luks = block->opaque;
150
- const QCryptoBlockLUKSKeySlot *slot = &luks->header.key_slots[slot_idx];
151
+ const QCryptoBlockLUKSKeySlot *slot;
152
g_autofree uint8_t *splitkey = NULL;
153
size_t splitkeylen;
154
g_autofree uint8_t *possiblekey = NULL;
155
@@ -XXX,XX +XXX,XX @@ qcrypto_block_luks_load_key(QCryptoBlock *block,
156
g_autoptr(QCryptoIVGen) ivgen = NULL;
157
size_t niv;
158
159
+ assert(slot_idx < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS);
160
+ slot = &luks->header.key_slots[slot_idx];
161
if (slot->active != QCRYPTO_BLOCK_LUKS_KEY_SLOT_ENABLED) {
162
return 0;
163
}
164
@@ -XXX,XX +XXX,XX @@ qcrypto_block_luks_find_key(QCryptoBlock *block,
165
return -1;
166
}
167
168
+/*
135
+/*
169
+ * Returns true if a slot i is marked as active
136
+ * QEMU UFS Logical Unit
170
+ * (contains encrypted copy of the master key)
137
+ *
138
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd. All rights reserved.
139
+ *
140
+ * Written by Jeuk Kim <jeuk20.kim@samsung.com>
141
+ *
142
+ * This code is licensed under the GNU GPL v2 or later.
171
+ */
143
+ */
172
+static bool
144
+
173
+qcrypto_block_luks_slot_active(const QCryptoBlockLUKS *luks,
145
+#include "qemu/osdep.h"
174
+ unsigned int slot_idx)
146
+#include "qemu/units.h"
175
+{
147
+#include "qapi/error.h"
176
+ uint32_t val;
148
+#include "qemu/memalign.h"
177
+
149
+#include "hw/scsi/scsi.h"
178
+ assert(slot_idx < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS);
150
+#include "scsi/constants.h"
179
+ val = luks->header.key_slots[slot_idx].active;
151
+#include "sysemu/block-backend.h"
180
+ return val == QCRYPTO_BLOCK_LUKS_KEY_SLOT_ENABLED;
152
+#include "qemu/cutils.h"
181
+}
153
+#include "trace.h"
154
+#include "ufs.h"
182
+
155
+
183
+/*
156
+/*
184
+ * Returns the number of slots that are marked as active
157
+ * The code below handling SCSI commands is copied from hw/scsi/scsi-disk.c,
185
+ * (slots that contain encrypted copy of the master key)
158
+ * with minor adjustments to make it work for UFS.
186
+ */
159
+ */
187
+static unsigned int
160
+
188
+qcrypto_block_luks_count_active_slots(const QCryptoBlockLUKS *luks)
161
+#define SCSI_DMA_BUF_SIZE (128 * KiB)
189
+{
162
+#define SCSI_MAX_INQUIRY_LEN 256
190
+ size_t i = 0;
163
+#define SCSI_INQUIRY_DATA_SIZE 36
191
+ unsigned int ret = 0;
164
+#define SCSI_MAX_MODE_LEN 256
192
+
165
+
193
+ for (i = 0; i < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS; i++) {
166
+typedef struct UfsSCSIReq {
194
+ if (qcrypto_block_luks_slot_active(luks, i)) {
167
+ SCSIRequest req;
195
+ ret++;
168
+ /* Both sector and sector_count are in terms of BDRV_SECTOR_SIZE bytes. */
196
+ }
169
+ uint64_t sector;
197
+ }
170
+ uint32_t sector_count;
198
+ return ret;
171
+ uint32_t buflen;
172
+ bool started;
173
+ bool need_fua_emulation;
174
+ struct iovec iov;
175
+ QEMUIOVector qiov;
176
+ BlockAcctCookie acct;
177
+} UfsSCSIReq;
178
+
179
+static void ufs_scsi_free_request(SCSIRequest *req)
180
+{
181
+ UfsSCSIReq *r = DO_UPCAST(UfsSCSIReq, req, req);
182
+
183
+ qemu_vfree(r->iov.iov_base);
184
+}
185
+
186
+static void scsi_check_condition(UfsSCSIReq *r, SCSISense sense)
187
+{
188
+ trace_ufs_scsi_check_condition(r->req.tag, sense.key, sense.asc,
189
+ sense.ascq);
190
+ scsi_req_build_sense(&r->req, sense);
191
+ scsi_req_complete(&r->req, CHECK_CONDITION);
192
+}
193
+
194
+static int ufs_scsi_emulate_vpd_page(SCSIRequest *req, uint8_t *outbuf,
195
+ uint32_t outbuf_len)
196
+{
197
+ UfsHc *u = UFS(req->bus->qbus.parent);
198
+ UfsLu *lu = DO_UPCAST(UfsLu, qdev, req->dev);
199
+ uint8_t page_code = req->cmd.buf[2];
200
+ int start, buflen = 0;
201
+
202
+ if (outbuf_len < SCSI_INQUIRY_DATA_SIZE) {
203
+ return -1;
204
+ }
205
+
206
+ outbuf[buflen++] = lu->qdev.type & 0x1f;
207
+ outbuf[buflen++] = page_code;
208
+ outbuf[buflen++] = 0x00;
209
+ outbuf[buflen++] = 0x00;
210
+ start = buflen;
211
+
212
+ switch (page_code) {
213
+ case 0x00: /* Supported page codes, mandatory */
214
+ {
215
+ trace_ufs_scsi_emulate_vpd_page_00(req->cmd.xfer);
216
+ outbuf[buflen++] = 0x00; /* list of supported pages (this page) */
217
+ if (u->params.serial) {
218
+ outbuf[buflen++] = 0x80; /* unit serial number */
219
+ }
220
+ outbuf[buflen++] = 0x87; /* mode page policy */
221
+ break;
222
+ }
223
+ case 0x80: /* Device serial number, optional */
224
+ {
225
+ int l;
226
+
227
+ if (!u->params.serial) {
228
+ trace_ufs_scsi_emulate_vpd_page_80_not_supported();
229
+ return -1;
230
+ }
231
+
232
+ l = strlen(u->params.serial);
233
+ if (l > SCSI_INQUIRY_DATA_SIZE) {
234
+ l = SCSI_INQUIRY_DATA_SIZE;
235
+ }
236
+
237
+ trace_ufs_scsi_emulate_vpd_page_80(req->cmd.xfer);
238
+ memcpy(outbuf + buflen, u->params.serial, l);
239
+ buflen += l;
240
+ break;
241
+ }
242
+ case 0x87: /* Mode Page Policy, mandatory */
243
+ {
244
+ trace_ufs_scsi_emulate_vpd_page_87(req->cmd.xfer);
245
+ outbuf[buflen++] = 0x3f; /* apply to all mode pages and subpages */
246
+ outbuf[buflen++] = 0xff;
247
+ outbuf[buflen++] = 0; /* shared */
248
+ outbuf[buflen++] = 0;
249
+ break;
250
+ }
251
+ default:
252
+ return -1;
253
+ }
254
+ /* done with EVPD */
255
+ assert(buflen - start <= 255);
256
+ outbuf[start - 1] = buflen - start;
257
+ return buflen;
258
+}
259
+
260
+static int ufs_scsi_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf,
261
+ uint32_t outbuf_len)
262
+{
263
+ int buflen = 0;
264
+
265
+ if (outbuf_len < SCSI_INQUIRY_DATA_SIZE) {
266
+ return -1;
267
+ }
268
+
269
+ if (req->cmd.buf[1] & 0x1) {
270
+ /* Vital product data */
271
+ return ufs_scsi_emulate_vpd_page(req, outbuf, outbuf_len);
272
+ }
273
+
274
+ /* Standard INQUIRY data */
275
+ if (req->cmd.buf[2] != 0) {
276
+ return -1;
277
+ }
278
+
279
+ /* PAGE CODE == 0 */
280
+ buflen = req->cmd.xfer;
281
+ if (buflen > SCSI_MAX_INQUIRY_LEN) {
282
+ buflen = SCSI_MAX_INQUIRY_LEN;
283
+ }
284
+
285
+ if (is_wlun(req->lun)) {
286
+ outbuf[0] = TYPE_WLUN;
287
+ } else {
288
+ outbuf[0] = 0;
289
+ }
290
+ outbuf[1] = 0;
291
+
292
+ strpadcpy((char *)&outbuf[16], 16, "QEMU UFS", ' ');
293
+ strpadcpy((char *)&outbuf[8], 8, "QEMU", ' ');
294
+
295
+ memset(&outbuf[32], 0, 4);
296
+
297
+ outbuf[2] = 0x06; /* SPC-4 */
298
+ outbuf[3] = 0x2;
299
+
300
+ if (buflen > SCSI_INQUIRY_DATA_SIZE) {
301
+ outbuf[4] = buflen - 5; /* Additional Length = (Len - 1) - 4 */
302
+ } else {
303
+ /*
304
+ * If the allocation length of CDB is too small, the additional
305
+ * length is not adjusted
306
+ */
307
+ outbuf[4] = SCSI_INQUIRY_DATA_SIZE - 5;
308
+ }
309
+
310
+ /* Support TCQ. */
311
+ outbuf[7] = req->bus->info->tcq ? 0x02 : 0;
312
+ return buflen;
313
+}
314
+
315
+static int mode_sense_page(UfsLu *lu, int page, uint8_t **p_outbuf,
316
+ int page_control)
317
+{
318
+ static const int mode_sense_valid[0x3f] = {
319
+ [MODE_PAGE_CACHING] = 1,
320
+ [MODE_PAGE_R_W_ERROR] = 1,
321
+ [MODE_PAGE_CONTROL] = 1,
322
+ };
323
+
324
+ uint8_t *p = *p_outbuf + 2;
325
+ int length;
326
+
327
+ assert(page < ARRAY_SIZE(mode_sense_valid));
328
+ if ((mode_sense_valid[page]) == 0) {
329
+ return -1;
330
+ }
331
+
332
+ /*
333
+ * If Changeable Values are requested, a mask denoting those mode parameters
334
+ * that are changeable shall be returned. As we currently don't support
335
+ * parameter changes via MODE_SELECT all bits are returned set to zero.
336
+ * The buffer was already memset to zero by the caller of this function.
337
+ */
338
+ switch (page) {
339
+ case MODE_PAGE_CACHING:
340
+ length = 0x12;
341
+ if (page_control == 1 || /* Changeable Values */
342
+ blk_enable_write_cache(lu->qdev.conf.blk)) {
343
+ p[0] = 4; /* WCE */
344
+ }
345
+ break;
346
+
347
+ case MODE_PAGE_R_W_ERROR:
348
+ length = 10;
349
+ if (page_control == 1) { /* Changeable Values */
350
+ break;
351
+ }
352
+ p[0] = 0x80; /* Automatic Write Reallocation Enabled */
353
+ break;
354
+
355
+ case MODE_PAGE_CONTROL:
356
+ length = 10;
357
+ if (page_control == 1) { /* Changeable Values */
358
+ break;
359
+ }
360
+ p[1] = 0x10; /* Queue Algorithm modifier */
361
+ p[8] = 0xff; /* Busy Timeout Period */
362
+ p[9] = 0xff;
363
+ break;
364
+
365
+ default:
366
+ return -1;
367
+ }
368
+
369
+ assert(length < 256);
370
+ (*p_outbuf)[0] = page;
371
+ (*p_outbuf)[1] = length;
372
+ *p_outbuf += length + 2;
373
+ return length + 2;
374
+}
375
+
376
+static int ufs_scsi_emulate_mode_sense(UfsSCSIReq *r, uint8_t *outbuf)
377
+{
378
+ UfsLu *lu = DO_UPCAST(UfsLu, qdev, r->req.dev);
379
+ bool dbd;
380
+ int page, buflen, ret, page_control;
381
+ uint8_t *p;
382
+ uint8_t dev_specific_param = 0;
383
+
384
+ dbd = (r->req.cmd.buf[1] & 0x8) != 0;
385
+ if (!dbd) {
386
+ return -1;
387
+ }
388
+
389
+ page = r->req.cmd.buf[2] & 0x3f;
390
+ page_control = (r->req.cmd.buf[2] & 0xc0) >> 6;
391
+
392
+ trace_ufs_scsi_emulate_mode_sense((r->req.cmd.buf[0] == MODE_SENSE) ? 6 :
393
+ 10,
394
+ page, r->req.cmd.xfer, page_control);
395
+ memset(outbuf, 0, r->req.cmd.xfer);
396
+ p = outbuf;
397
+
398
+ if (!blk_is_writable(lu->qdev.conf.blk)) {
399
+ dev_specific_param |= 0x80; /* Readonly. */
400
+ }
401
+
402
+ p[2] = 0; /* Medium type. */
403
+ p[3] = dev_specific_param;
404
+ p[6] = p[7] = 0; /* Block descriptor length. */
405
+ p += 8;
406
+
407
+ if (page_control == 3) {
408
+ /* Saved Values */
409
+ scsi_check_condition(r, SENSE_CODE(SAVING_PARAMS_NOT_SUPPORTED));
410
+ return -1;
411
+ }
412
+
413
+ if (page == 0x3f) {
414
+ for (page = 0; page <= 0x3e; page++) {
415
+ mode_sense_page(lu, page, &p, page_control);
416
+ }
417
+ } else {
418
+ ret = mode_sense_page(lu, page, &p, page_control);
419
+ if (ret == -1) {
420
+ return -1;
421
+ }
422
+ }
423
+
424
+ buflen = p - outbuf;
425
+ /*
426
+ * The mode data length field specifies the length in bytes of the
427
+ * following data that is available to be transferred. The mode data
428
+ * length does not include itself.
429
+ */
430
+ outbuf[0] = ((buflen - 2) >> 8) & 0xff;
431
+ outbuf[1] = (buflen - 2) & 0xff;
432
+ return buflen;
199
+}
433
+}
200
+
434
+
201
+/*
435
+/*
202
+ * Finds first key slot which is not active
436
+ * scsi_handle_rw_error has two return values. False means that the error
203
+ * Returns the key slot index, or -1 if it doesn't exist
437
+ * must be ignored, true means that the error has been processed and the
438
+ * caller should not do anything else for this request. Note that
439
+ * scsi_handle_rw_error always manages its reference counts, independent
440
+ * of the return value.
204
+ */
441
+ */
205
+static int
442
+static bool scsi_handle_rw_error(UfsSCSIReq *r, int ret, bool acct_failed)
206
+qcrypto_block_luks_find_free_keyslot(const QCryptoBlockLUKS *luks)
443
+{
207
+{
444
+ bool is_read = (r->req.cmd.mode == SCSI_XFER_FROM_DEV);
208
+ size_t i;
445
+ UfsLu *lu = DO_UPCAST(UfsLu, qdev, r->req.dev);
209
+
446
+ SCSISense sense = SENSE_CODE(NO_SENSE);
210
+ for (i = 0; i < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS; i++) {
447
+ int error = 0;
211
+ if (!qcrypto_block_luks_slot_active(luks, i)) {
448
+ bool req_has_sense = false;
212
+ return i;
449
+ BlockErrorAction action;
213
+ }
450
+ int status;
214
+ }
215
+ return -1;
216
+}
217
+
218
+/*
219
+ * Erases an keyslot given its index
220
+ * Returns:
221
+ * 0 if the keyslot was erased successfully
222
+ * -1 if a error occurred while erasing the keyslot
223
+ *
224
+ */
225
+static int
226
+qcrypto_block_luks_erase_key(QCryptoBlock *block,
227
+ unsigned int slot_idx,
228
+ QCryptoBlockWriteFunc writefunc,
229
+ void *opaque,
230
+ Error **errp)
231
+{
232
+ QCryptoBlockLUKS *luks = block->opaque;
233
+ QCryptoBlockLUKSKeySlot *slot;
234
+ g_autofree uint8_t *garbagesplitkey = NULL;
235
+ size_t splitkeylen;
236
+ size_t i;
237
+ Error *local_err = NULL;
238
+ int ret;
239
+
240
+ assert(slot_idx < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS);
241
+ slot = &luks->header.key_slots[slot_idx];
242
+
243
+ splitkeylen = luks->header.master_key_len * slot->stripes;
244
+ assert(splitkeylen > 0);
245
+
246
+ garbagesplitkey = g_new0(uint8_t, splitkeylen);
247
+
248
+ /* Reset the key slot header */
249
+ memset(slot->salt, 0, QCRYPTO_BLOCK_LUKS_SALT_LEN);
250
+ slot->iterations = 0;
251
+ slot->active = QCRYPTO_BLOCK_LUKS_KEY_SLOT_DISABLED;
252
+
253
+ ret = qcrypto_block_luks_store_header(block, writefunc,
254
+ opaque, &local_err);
255
+
451
+
256
+ if (ret < 0) {
452
+ if (ret < 0) {
257
+ error_propagate(errp, local_err);
453
+ status = scsi_sense_from_errno(-ret, &sense);
258
+ }
454
+ error = -ret;
455
+ } else {
456
+ /* A passthrough command has completed with nonzero status. */
457
+ status = ret;
458
+ if (status == CHECK_CONDITION) {
459
+ req_has_sense = true;
460
+ error = scsi_sense_buf_to_errno(r->req.sense, sizeof(r->req.sense));
461
+ } else {
462
+ error = EINVAL;
463
+ }
464
+ }
465
+
259
+ /*
466
+ /*
260
+ * Now try to erase the key material, even if the header
467
+ * Check whether the error has to be handled by the guest or should
261
+ * update failed
468
+ * rather follow the rerror=/werror= settings. Guest-handled errors
469
+ * are usually retried immediately, so do not post them to QMP and
470
+ * do not account them as failed I/O.
262
+ */
471
+ */
263
+ for (i = 0; i < QCRYPTO_BLOCK_LUKS_ERASE_ITERATIONS; i++) {
472
+ if (req_has_sense && scsi_sense_buf_is_guest_recoverable(
264
+ if (qcrypto_random_bytes(garbagesplitkey,
473
+ r->req.sense, sizeof(r->req.sense))) {
265
+ splitkeylen, &local_err) < 0) {
474
+ action = BLOCK_ERROR_ACTION_REPORT;
266
+ /*
475
+ acct_failed = false;
267
+ * If we failed to get the random data, still write
268
+ * at least zeros to the key slot at least once
269
+ */
270
+ error_propagate(errp, local_err);
271
+
272
+ if (i > 0) {
273
+ return -1;
274
+ }
275
+ }
276
+ if (writefunc(block,
277
+ slot->key_offset_sector * QCRYPTO_BLOCK_LUKS_SECTOR_SIZE,
278
+ garbagesplitkey,
279
+ splitkeylen,
280
+ opaque,
281
+ &local_err) != splitkeylen) {
282
+ error_propagate(errp, local_err);
283
+ return -1;
284
+ }
285
+ }
286
+ return ret;
287
+}
288
289
static int
290
qcrypto_block_luks_open(QCryptoBlock *block,
291
@@ -XXX,XX +XXX,XX @@ qcrypto_block_luks_open(QCryptoBlock *block,
292
293
luks = g_new0(QCryptoBlockLUKS, 1);
294
block->opaque = luks;
295
+ luks->secret = g_strdup(options->u.luks.key_secret);
296
297
if (qcrypto_block_luks_load_header(block, readfunc, opaque, errp) < 0) {
298
goto fail;
299
@@ -XXX,XX +XXX,XX @@ qcrypto_block_luks_open(QCryptoBlock *block,
300
fail:
301
qcrypto_block_free_cipher(block);
302
qcrypto_ivgen_free(block->ivgen);
303
+ g_free(luks->secret);
304
g_free(luks);
305
return -1;
306
}
307
@@ -XXX,XX +XXX,XX @@ qcrypto_block_luks_create(QCryptoBlock *block,
308
309
memcpy(&luks_opts, &options->u.luks, sizeof(luks_opts));
310
if (!luks_opts.has_iter_time) {
311
- luks_opts.iter_time = 2000;
312
+ luks_opts.iter_time = QCRYPTO_BLOCK_LUKS_DEFAULT_ITER_TIME_MS;
313
}
314
if (!luks_opts.has_cipher_alg) {
315
luks_opts.cipher_alg = QCRYPTO_CIPHER_ALG_AES_256;
316
@@ -XXX,XX +XXX,XX @@ qcrypto_block_luks_create(QCryptoBlock *block,
317
optprefix ? optprefix : "");
318
goto error;
319
}
320
+ luks->secret = g_strdup(options->u.luks.key_secret);
321
+
322
password = qcrypto_secret_lookup_as_utf8(luks_opts.key_secret, errp);
323
if (!password) {
324
goto error;
325
@@ -XXX,XX +XXX,XX @@ qcrypto_block_luks_create(QCryptoBlock *block,
326
qcrypto_block_free_cipher(block);
327
qcrypto_ivgen_free(block->ivgen);
328
329
+ g_free(luks->secret);
330
g_free(luks);
331
return -1;
332
}
333
334
+static int
335
+qcrypto_block_luks_amend_add_keyslot(QCryptoBlock *block,
336
+ QCryptoBlockReadFunc readfunc,
337
+ QCryptoBlockWriteFunc writefunc,
338
+ void *opaque,
339
+ QCryptoBlockAmendOptionsLUKS *opts_luks,
340
+ bool force,
341
+ Error **errp)
342
+{
343
+ QCryptoBlockLUKS *luks = block->opaque;
344
+ uint64_t iter_time = opts_luks->has_iter_time ?
345
+ opts_luks->iter_time :
346
+ QCRYPTO_BLOCK_LUKS_DEFAULT_ITER_TIME_MS;
347
+ int keyslot;
348
+ g_autofree char *old_password = NULL;
349
+ g_autofree char *new_password = NULL;
350
+ g_autofree uint8_t *master_key = NULL;
351
+
352
+ char *secret = opts_luks->has_secret ? opts_luks->secret : luks->secret;
353
+
354
+ if (!opts_luks->has_new_secret) {
355
+ error_setg(errp, "'new-secret' is required to activate a keyslot");
356
+ return -1;
357
+ }
358
+ if (opts_luks->has_old_secret) {
359
+ error_setg(errp,
360
+ "'old-secret' must not be given when activating keyslots");
361
+ return -1;
362
+ }
363
+
364
+ if (opts_luks->has_keyslot) {
365
+ keyslot = opts_luks->keyslot;
366
+ if (keyslot < 0 || keyslot >= QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS) {
367
+ error_setg(errp,
368
+ "Invalid keyslot %u specified, must be between 0 and %u",
369
+ keyslot, QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS - 1);
370
+ return -1;
371
+ }
372
+ } else {
476
+ } else {
373
+ keyslot = qcrypto_block_luks_find_free_keyslot(luks);
477
+ action = blk_get_error_action(lu->qdev.conf.blk, is_read, error);
374
+ if (keyslot == -1) {
478
+ blk_error_action(lu->qdev.conf.blk, action, is_read, error);
375
+ error_setg(errp,
479
+ }
376
+ "Can't add a keyslot - all keyslots are in use");
480
+
377
+ return -1;
481
+ switch (action) {
378
+ }
482
+ case BLOCK_ERROR_ACTION_REPORT:
379
+ }
483
+ if (acct_failed) {
380
+
484
+ block_acct_failed(blk_get_stats(lu->qdev.conf.blk), &r->acct);
381
+ if (!force && qcrypto_block_luks_slot_active(luks, keyslot)) {
485
+ }
382
+ error_setg(errp,
486
+ if (!req_has_sense && status == CHECK_CONDITION) {
383
+ "Refusing to overwrite active keyslot %i - "
487
+ scsi_req_build_sense(&r->req, sense);
384
+ "please erase it first",
488
+ }
385
+ keyslot);
489
+ scsi_req_complete(&r->req, status);
386
+ return -1;
490
+ return true;
387
+ }
491
+
388
+
492
+ case BLOCK_ERROR_ACTION_IGNORE:
389
+ /* Locate the password that will be used to retrieve the master key */
493
+ return false;
390
+ old_password = qcrypto_secret_lookup_as_utf8(secret, errp);
494
+
391
+ if (!old_password) {
495
+ case BLOCK_ERROR_ACTION_STOP:
392
+ return -1;
496
+ scsi_req_retry(&r->req);
393
+ }
497
+ return true;
394
+
498
+
395
+ /* Retrieve the master key */
396
+ master_key = g_new0(uint8_t, luks->header.master_key_len);
397
+
398
+ if (qcrypto_block_luks_find_key(block, old_password, master_key,
399
+ readfunc, opaque, errp) < 0) {
400
+ error_append_hint(errp, "Failed to retrieve the master key");
401
+ return -1;
402
+ }
403
+
404
+ /* Locate the new password*/
405
+ new_password = qcrypto_secret_lookup_as_utf8(opts_luks->new_secret, errp);
406
+ if (!new_password) {
407
+ return -1;
408
+ }
409
+
410
+ /* Now set the new keyslots */
411
+ if (qcrypto_block_luks_store_key(block, keyslot, new_password, master_key,
412
+ iter_time, writefunc, opaque, errp)) {
413
+ error_append_hint(errp, "Failed to write to keyslot %i", keyslot);
414
+ return -1;
415
+ }
416
+ return 0;
417
+}
418
+
419
+static int
420
+qcrypto_block_luks_amend_erase_keyslots(QCryptoBlock *block,
421
+ QCryptoBlockReadFunc readfunc,
422
+ QCryptoBlockWriteFunc writefunc,
423
+ void *opaque,
424
+ QCryptoBlockAmendOptionsLUKS *opts_luks,
425
+ bool force,
426
+ Error **errp)
427
+{
428
+ QCryptoBlockLUKS *luks = block->opaque;
429
+ g_autofree uint8_t *tmpkey = NULL;
430
+ g_autofree char *old_password = NULL;
431
+
432
+ if (opts_luks->has_new_secret) {
433
+ error_setg(errp,
434
+ "'new-secret' must not be given when erasing keyslots");
435
+ return -1;
436
+ }
437
+ if (opts_luks->has_iter_time) {
438
+ error_setg(errp,
439
+ "'iter-time' must not be given when erasing keyslots");
440
+ return -1;
441
+ }
442
+ if (opts_luks->has_secret) {
443
+ error_setg(errp,
444
+ "'secret' must not be given when erasing keyslots");
445
+ return -1;
446
+ }
447
+
448
+ /* Load the old password if given */
449
+ if (opts_luks->has_old_secret) {
450
+ old_password = qcrypto_secret_lookup_as_utf8(opts_luks->old_secret,
451
+ errp);
452
+ if (!old_password) {
453
+ return -1;
454
+ }
455
+
456
+ /*
457
+ * Allocate a temporary key buffer that we will need when
458
+ * checking if slot matches the given old password
459
+ */
460
+ tmpkey = g_new0(uint8_t, luks->header.master_key_len);
461
+ }
462
+
463
+ /* Erase an explicitly given keyslot */
464
+ if (opts_luks->has_keyslot) {
465
+ int keyslot = opts_luks->keyslot;
466
+
467
+ if (keyslot < 0 || keyslot >= QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS) {
468
+ error_setg(errp,
469
+ "Invalid keyslot %i specified, must be between 0 and %i",
470
+ keyslot, QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS - 1);
471
+ return -1;
472
+ }
473
+
474
+ if (opts_luks->has_old_secret) {
475
+ int rv = qcrypto_block_luks_load_key(block,
476
+ keyslot,
477
+ old_password,
478
+ tmpkey,
479
+ readfunc,
480
+ opaque,
481
+ errp);
482
+ if (rv == -1) {
483
+ return -1;
484
+ } else if (rv == 0) {
485
+ error_setg(errp,
486
+ "Given keyslot %i doesn't contain the given "
487
+ "old password for erase operation",
488
+ keyslot);
489
+ return -1;
490
+ }
491
+ }
492
+
493
+ if (!force && !qcrypto_block_luks_slot_active(luks, keyslot)) {
494
+ error_setg(errp,
495
+ "Given keyslot %i is already erased (inactive) ",
496
+ keyslot);
497
+ return -1;
498
+ }
499
+
500
+ if (!force && qcrypto_block_luks_count_active_slots(luks) == 1) {
501
+ error_setg(errp,
502
+ "Attempt to erase the only active keyslot %i "
503
+ "which will erase all the data in the image "
504
+ "irreversibly - refusing operation",
505
+ keyslot);
506
+ return -1;
507
+ }
508
+
509
+ if (qcrypto_block_luks_erase_key(block, keyslot,
510
+ writefunc, opaque, errp)) {
511
+ error_append_hint(errp, "Failed to erase keyslot %i", keyslot);
512
+ return -1;
513
+ }
514
+
515
+ /* Erase all keyslots that match the given old password */
516
+ } else if (opts_luks->has_old_secret) {
517
+
518
+ unsigned long slots_to_erase_bitmap = 0;
519
+ size_t i;
520
+ int slot_count;
521
+
522
+ assert(QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS <=
523
+ sizeof(slots_to_erase_bitmap) * 8);
524
+
525
+ for (i = 0; i < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS; i++) {
526
+ int rv = qcrypto_block_luks_load_key(block,
527
+ i,
528
+ old_password,
529
+ tmpkey,
530
+ readfunc,
531
+ opaque,
532
+ errp);
533
+ if (rv == -1) {
534
+ return -1;
535
+ } else if (rv == 1) {
536
+ bitmap_set(&slots_to_erase_bitmap, i, 1);
537
+ }
538
+ }
539
+
540
+ slot_count = bitmap_count_one(&slots_to_erase_bitmap,
541
+ QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS);
542
+ if (slot_count == 0) {
543
+ error_setg(errp,
544
+ "No keyslots match given (old) password for erase operation");
545
+ return -1;
546
+ }
547
+
548
+ if (!force &&
549
+ slot_count == qcrypto_block_luks_count_active_slots(luks)) {
550
+ error_setg(errp,
551
+ "All the active keyslots match the (old) password that "
552
+ "was given and erasing them will erase all the data in "
553
+ "the image irreversibly - refusing operation");
554
+ return -1;
555
+ }
556
+
557
+ /* Now apply the update */
558
+ for (i = 0; i < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS; i++) {
559
+ if (!test_bit(i, &slots_to_erase_bitmap)) {
560
+ continue;
561
+ }
562
+ if (qcrypto_block_luks_erase_key(block, i, writefunc,
563
+ opaque, errp)) {
564
+ error_append_hint(errp, "Failed to erase keyslot %zu", i);
565
+ return -1;
566
+ }
567
+ }
568
+ } else {
569
+ error_setg(errp,
570
+ "To erase keyslot(s), either explicit keyslot index "
571
+ "or the password currently contained in them must be given");
572
+ return -1;
573
+ }
574
+ return 0;
575
+}
576
+
577
+static int
578
+qcrypto_block_luks_amend_options(QCryptoBlock *block,
579
+ QCryptoBlockReadFunc readfunc,
580
+ QCryptoBlockWriteFunc writefunc,
581
+ void *opaque,
582
+ QCryptoBlockAmendOptions *options,
583
+ bool force,
584
+ Error **errp)
585
+{
586
+ QCryptoBlockAmendOptionsLUKS *opts_luks = &options->u.luks;
587
+
588
+ switch (opts_luks->state) {
589
+ case Q_CRYPTO_BLOCKLUKS_KEYSLOT_STATE_ACTIVE:
590
+ return qcrypto_block_luks_amend_add_keyslot(block, readfunc,
591
+ writefunc, opaque,
592
+ opts_luks, force, errp);
593
+ case Q_CRYPTO_BLOCKLUKS_KEYSLOT_STATE_INACTIVE:
594
+ return qcrypto_block_luks_amend_erase_keyslots(block, readfunc,
595
+ writefunc, opaque,
596
+ opts_luks, force, errp);
597
+ default:
499
+ default:
598
+ g_assert_not_reached();
500
+ g_assert_not_reached();
599
+ }
501
+ }
600
+}
502
+}
601
503
+
602
static int qcrypto_block_luks_get_info(QCryptoBlock *block,
504
+static bool ufs_scsi_req_check_error(UfsSCSIReq *r, int ret, bool acct_failed)
603
QCryptoBlockInfo *info,
505
+{
604
@@ -XXX,XX +XXX,XX @@ static int qcrypto_block_luks_get_info(QCryptoBlock *block,
506
+ if (r->req.io_canceled) {
605
507
+ scsi_req_cancel_complete(&r->req);
606
static void qcrypto_block_luks_cleanup(QCryptoBlock *block)
508
+ return true;
509
+ }
510
+
511
+ if (ret < 0) {
512
+ return scsi_handle_rw_error(r, ret, acct_failed);
513
+ }
514
+
515
+ return false;
516
+}
517
+
518
+static void scsi_aio_complete(void *opaque, int ret)
519
+{
520
+ UfsSCSIReq *r = (UfsSCSIReq *)opaque;
521
+ UfsLu *lu = DO_UPCAST(UfsLu, qdev, r->req.dev);
522
+
523
+ assert(r->req.aiocb != NULL);
524
+ r->req.aiocb = NULL;
525
+ aio_context_acquire(blk_get_aio_context(lu->qdev.conf.blk));
526
+ if (ufs_scsi_req_check_error(r, ret, true)) {
527
+ goto done;
528
+ }
529
+
530
+ block_acct_done(blk_get_stats(lu->qdev.conf.blk), &r->acct);
531
+ scsi_req_complete(&r->req, GOOD);
532
+
533
+done:
534
+ aio_context_release(blk_get_aio_context(lu->qdev.conf.blk));
535
+ scsi_req_unref(&r->req);
536
+}
537
+
538
+static int32_t ufs_scsi_emulate_command(SCSIRequest *req, uint8_t *buf)
539
+{
540
+ UfsSCSIReq *r = DO_UPCAST(UfsSCSIReq, req, req);
541
+ UfsLu *lu = DO_UPCAST(UfsLu, qdev, req->dev);
542
+ uint32_t last_block = 0;
543
+ uint8_t *outbuf;
544
+ int buflen;
545
+
546
+ switch (req->cmd.buf[0]) {
547
+ case INQUIRY:
548
+ case MODE_SENSE_10:
549
+ case START_STOP:
550
+ case REQUEST_SENSE:
551
+ break;
552
+
553
+ default:
554
+ if (!blk_is_available(lu->qdev.conf.blk)) {
555
+ scsi_check_condition(r, SENSE_CODE(NO_MEDIUM));
556
+ return 0;
557
+ }
558
+ break;
559
+ }
560
+
561
+ /*
562
+ * FIXME: we shouldn't return anything bigger than 4k, but the code
563
+ * requires the buffer to be as big as req->cmd.xfer in several
564
+ * places. So, do not allow CDBs with a very large ALLOCATION
565
+ * LENGTH. The real fix would be to modify scsi_read_data and
566
+ * dma_buf_read, so that they return data beyond the buflen
567
+ * as all zeros.
568
+ */
569
+ if (req->cmd.xfer > 65536) {
570
+ goto illegal_request;
571
+ }
572
+ r->buflen = MAX(4096, req->cmd.xfer);
573
+
574
+ if (!r->iov.iov_base) {
575
+ r->iov.iov_base = blk_blockalign(lu->qdev.conf.blk, r->buflen);
576
+ }
577
+
578
+ outbuf = r->iov.iov_base;
579
+ memset(outbuf, 0, r->buflen);
580
+ switch (req->cmd.buf[0]) {
581
+ case TEST_UNIT_READY:
582
+ assert(blk_is_available(lu->qdev.conf.blk));
583
+ break;
584
+ case INQUIRY:
585
+ buflen = ufs_scsi_emulate_inquiry(req, outbuf, r->buflen);
586
+ if (buflen < 0) {
587
+ goto illegal_request;
588
+ }
589
+ break;
590
+ case MODE_SENSE_10:
591
+ buflen = ufs_scsi_emulate_mode_sense(r, outbuf);
592
+ if (buflen < 0) {
593
+ goto illegal_request;
594
+ }
595
+ break;
596
+ case READ_CAPACITY_10:
597
+ /* The normal LEN field for this command is zero. */
598
+ memset(outbuf, 0, 8);
599
+ if (lu->qdev.max_lba > 0) {
600
+ last_block = lu->qdev.max_lba - 1;
601
+ };
602
+ outbuf[0] = (last_block >> 24) & 0xff;
603
+ outbuf[1] = (last_block >> 16) & 0xff;
604
+ outbuf[2] = (last_block >> 8) & 0xff;
605
+ outbuf[3] = last_block & 0xff;
606
+ outbuf[4] = (lu->qdev.blocksize >> 24) & 0xff;
607
+ outbuf[5] = (lu->qdev.blocksize >> 16) & 0xff;
608
+ outbuf[6] = (lu->qdev.blocksize >> 8) & 0xff;
609
+ outbuf[7] = lu->qdev.blocksize & 0xff;
610
+ break;
611
+ case REQUEST_SENSE:
612
+ /* Just return "NO SENSE". */
613
+ buflen = scsi_convert_sense(NULL, 0, outbuf, r->buflen,
614
+ (req->cmd.buf[1] & 1) == 0);
615
+ if (buflen < 0) {
616
+ goto illegal_request;
617
+ }
618
+ break;
619
+ case SYNCHRONIZE_CACHE:
620
+ /* The request is used as the AIO opaque value, so add a ref. */
621
+ scsi_req_ref(&r->req);
622
+ block_acct_start(blk_get_stats(lu->qdev.conf.blk), &r->acct, 0,
623
+ BLOCK_ACCT_FLUSH);
624
+ r->req.aiocb = blk_aio_flush(lu->qdev.conf.blk, scsi_aio_complete, r);
625
+ return 0;
626
+ case VERIFY_10:
627
+ trace_ufs_scsi_emulate_command_VERIFY((req->cmd.buf[1] >> 1) & 3);
628
+ if (req->cmd.buf[1] & 6) {
629
+ goto illegal_request;
630
+ }
631
+ break;
632
+ case SERVICE_ACTION_IN_16:
633
+ /* Service Action In subcommands. */
634
+ if ((req->cmd.buf[1] & 31) == SAI_READ_CAPACITY_16) {
635
+ trace_ufs_scsi_emulate_command_SAI_16();
636
+ memset(outbuf, 0, req->cmd.xfer);
637
+
638
+ if (lu->qdev.max_lba > 0) {
639
+ last_block = lu->qdev.max_lba - 1;
640
+ };
641
+ outbuf[0] = 0;
642
+ outbuf[1] = 0;
643
+ outbuf[2] = 0;
644
+ outbuf[3] = 0;
645
+ outbuf[4] = (last_block >> 24) & 0xff;
646
+ outbuf[5] = (last_block >> 16) & 0xff;
647
+ outbuf[6] = (last_block >> 8) & 0xff;
648
+ outbuf[7] = last_block & 0xff;
649
+ outbuf[8] = (lu->qdev.blocksize >> 24) & 0xff;
650
+ outbuf[9] = (lu->qdev.blocksize >> 16) & 0xff;
651
+ outbuf[10] = (lu->qdev.blocksize >> 8) & 0xff;
652
+ outbuf[11] = lu->qdev.blocksize & 0xff;
653
+ outbuf[12] = 0;
654
+ outbuf[13] = get_physical_block_exp(&lu->qdev.conf);
655
+
656
+ if (lu->unit_desc.provisioning_type == 2 ||
657
+ lu->unit_desc.provisioning_type == 3) {
658
+ outbuf[14] = 0x80;
659
+ }
660
+ /* Protection, exponent and lowest lba field left blank. */
661
+ break;
662
+ }
663
+ trace_ufs_scsi_emulate_command_SAI_unsupported();
664
+ goto illegal_request;
665
+ case MODE_SELECT_10:
666
+ trace_ufs_scsi_emulate_command_MODE_SELECT_10(r->req.cmd.xfer);
667
+ break;
668
+ case START_STOP:
669
+ /*
670
+ * TODO: START_STOP is not yet implemented. It always returns success.
671
+ * Revisit it when ufs power management is implemented.
672
+ */
673
+ trace_ufs_scsi_emulate_command_START_STOP();
674
+ break;
675
+ case FORMAT_UNIT:
676
+ trace_ufs_scsi_emulate_command_FORMAT_UNIT();
677
+ break;
678
+ case SEND_DIAGNOSTIC:
679
+ trace_ufs_scsi_emulate_command_SEND_DIAGNOSTIC();
680
+ break;
681
+ default:
682
+ trace_ufs_scsi_emulate_command_UNKNOWN(buf[0],
683
+ scsi_command_name(buf[0]));
684
+ scsi_check_condition(r, SENSE_CODE(INVALID_OPCODE));
685
+ return 0;
686
+ }
687
+ assert(!r->req.aiocb);
688
+ r->iov.iov_len = MIN(r->buflen, req->cmd.xfer);
689
+ if (r->iov.iov_len == 0) {
690
+ scsi_req_complete(&r->req, GOOD);
691
+ }
692
+ if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
693
+ assert(r->iov.iov_len == req->cmd.xfer);
694
+ return -r->iov.iov_len;
695
+ } else {
696
+ return r->iov.iov_len;
697
+ }
698
+
699
+illegal_request:
700
+ if (r->req.status == -1) {
701
+ scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
702
+ }
703
+ return 0;
704
+}
705
+
706
+static void ufs_scsi_emulate_read_data(SCSIRequest *req)
707
+{
708
+ UfsSCSIReq *r = DO_UPCAST(UfsSCSIReq, req, req);
709
+ int buflen = r->iov.iov_len;
710
+
711
+ if (buflen) {
712
+ trace_ufs_scsi_emulate_read_data(buflen);
713
+ r->iov.iov_len = 0;
714
+ r->started = true;
715
+ scsi_req_data(&r->req, buflen);
716
+ return;
717
+ }
718
+
719
+ /* This also clears the sense buffer for REQUEST SENSE. */
720
+ scsi_req_complete(&r->req, GOOD);
721
+}
722
+
723
+static int ufs_scsi_check_mode_select(UfsLu *lu, int page, uint8_t *inbuf,
724
+ int inlen)
725
+{
726
+ uint8_t mode_current[SCSI_MAX_MODE_LEN];
727
+ uint8_t mode_changeable[SCSI_MAX_MODE_LEN];
728
+ uint8_t *p;
729
+ int len, expected_len, changeable_len, i;
730
+
731
+ /*
732
+ * The input buffer does not include the page header, so it is
733
+ * off by 2 bytes.
734
+ */
735
+ expected_len = inlen + 2;
736
+ if (expected_len > SCSI_MAX_MODE_LEN) {
737
+ return -1;
738
+ }
739
+
740
+ /* MODE_PAGE_ALLS is only valid for MODE SENSE commands */
741
+ if (page == MODE_PAGE_ALLS) {
742
+ return -1;
743
+ }
744
+
745
+ p = mode_current;
746
+ memset(mode_current, 0, inlen + 2);
747
+ len = mode_sense_page(lu, page, &p, 0);
748
+ if (len < 0 || len != expected_len) {
749
+ return -1;
750
+ }
751
+
752
+ p = mode_changeable;
753
+ memset(mode_changeable, 0, inlen + 2);
754
+ changeable_len = mode_sense_page(lu, page, &p, 1);
755
+ assert(changeable_len == len);
756
+
757
+ /*
758
+ * Check that unchangeable bits are the same as what MODE SENSE
759
+ * would return.
760
+ */
761
+ for (i = 2; i < len; i++) {
762
+ if (((mode_current[i] ^ inbuf[i - 2]) & ~mode_changeable[i]) != 0) {
763
+ return -1;
764
+ }
765
+ }
766
+ return 0;
767
+}
768
+
769
+static void ufs_scsi_apply_mode_select(UfsLu *lu, int page, uint8_t *p)
770
+{
771
+ switch (page) {
772
+ case MODE_PAGE_CACHING:
773
+ blk_set_enable_write_cache(lu->qdev.conf.blk, (p[0] & 4) != 0);
774
+ break;
775
+
776
+ default:
777
+ break;
778
+ }
779
+}
780
+
781
+static int mode_select_pages(UfsSCSIReq *r, uint8_t *p, int len, bool change)
782
+{
783
+ UfsLu *lu = DO_UPCAST(UfsLu, qdev, r->req.dev);
784
+
785
+ while (len > 0) {
786
+ int page, page_len;
787
+
788
+ page = p[0] & 0x3f;
789
+ if (p[0] & 0x40) {
790
+ goto invalid_param;
791
+ } else {
792
+ if (len < 2) {
793
+ goto invalid_param_len;
794
+ }
795
+ page_len = p[1];
796
+ p += 2;
797
+ len -= 2;
798
+ }
799
+
800
+ if (page_len > len) {
801
+ goto invalid_param_len;
802
+ }
803
+
804
+ if (!change) {
805
+ if (ufs_scsi_check_mode_select(lu, page, p, page_len) < 0) {
806
+ goto invalid_param;
807
+ }
808
+ } else {
809
+ ufs_scsi_apply_mode_select(lu, page, p);
810
+ }
811
+
812
+ p += page_len;
813
+ len -= page_len;
814
+ }
815
+ return 0;
816
+
817
+invalid_param:
818
+ scsi_check_condition(r, SENSE_CODE(INVALID_PARAM));
819
+ return -1;
820
+
821
+invalid_param_len:
822
+ scsi_check_condition(r, SENSE_CODE(INVALID_PARAM_LEN));
823
+ return -1;
824
+}
825
+
826
+static void ufs_scsi_emulate_mode_select(UfsSCSIReq *r, uint8_t *inbuf)
827
+{
828
+ UfsLu *lu = DO_UPCAST(UfsLu, qdev, r->req.dev);
829
+ uint8_t *p = inbuf;
830
+ int len = r->req.cmd.xfer;
831
+ int hdr_len = 8;
832
+ int bd_len;
833
+ int pass;
834
+
835
+ /* We only support PF=1, SP=0. */
836
+ if ((r->req.cmd.buf[1] & 0x11) != 0x10) {
837
+ goto invalid_field;
838
+ }
839
+
840
+ if (len < hdr_len) {
841
+ goto invalid_param_len;
842
+ }
843
+
844
+ bd_len = lduw_be_p(&p[6]);
845
+ if (bd_len != 0) {
846
+ goto invalid_param;
847
+ }
848
+
849
+ len -= hdr_len;
850
+ p += hdr_len;
851
+
852
+ /* Ensure no change is made if there is an error! */
853
+ for (pass = 0; pass < 2; pass++) {
854
+ if (mode_select_pages(r, p, len, pass == 1) < 0) {
855
+ assert(pass == 0);
856
+ return;
857
+ }
858
+ }
859
+
860
+ if (!blk_enable_write_cache(lu->qdev.conf.blk)) {
861
+ /* The request is used as the AIO opaque value, so add a ref. */
862
+ scsi_req_ref(&r->req);
863
+ block_acct_start(blk_get_stats(lu->qdev.conf.blk), &r->acct, 0,
864
+ BLOCK_ACCT_FLUSH);
865
+ r->req.aiocb = blk_aio_flush(lu->qdev.conf.blk, scsi_aio_complete, r);
866
+ return;
867
+ }
868
+
869
+ scsi_req_complete(&r->req, GOOD);
870
+ return;
871
+
872
+invalid_param:
873
+ scsi_check_condition(r, SENSE_CODE(INVALID_PARAM));
874
+ return;
875
+
876
+invalid_param_len:
877
+ scsi_check_condition(r, SENSE_CODE(INVALID_PARAM_LEN));
878
+ return;
879
+
880
+invalid_field:
881
+ scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
882
+}
883
+
884
+/* block_num and nb_blocks expected to be in qdev blocksize */
885
+static inline bool check_lba_range(UfsLu *lu, uint64_t block_num,
886
+ uint32_t nb_blocks)
887
+{
888
+ /*
889
+ * The first line tests that no overflow happens when computing the last
890
+ * block. The second line tests that the last accessed block is in
891
+ * range.
892
+ *
893
+ * Careful, the computations should not underflow for nb_blocks == 0,
894
+ * and a 0-block read to the first LBA beyond the end of device is
895
+ * valid.
896
+ */
897
+ return (block_num <= block_num + nb_blocks &&
898
+ block_num + nb_blocks <= lu->qdev.max_lba + 1);
899
+}
900
+
901
+static void ufs_scsi_emulate_write_data(SCSIRequest *req)
902
+{
903
+ UfsSCSIReq *r = DO_UPCAST(UfsSCSIReq, req, req);
904
+
905
+ if (r->iov.iov_len) {
906
+ int buflen = r->iov.iov_len;
907
+ trace_ufs_scsi_emulate_write_data(buflen);
908
+ r->iov.iov_len = 0;
909
+ scsi_req_data(&r->req, buflen);
910
+ return;
911
+ }
912
+
913
+ switch (req->cmd.buf[0]) {
914
+ case MODE_SELECT_10:
915
+ /* This also clears the sense buffer for REQUEST SENSE. */
916
+ ufs_scsi_emulate_mode_select(r, r->iov.iov_base);
917
+ break;
918
+ default:
919
+ abort();
920
+ }
921
+}
922
+
923
+/* Return a pointer to the data buffer. */
924
+static uint8_t *ufs_scsi_get_buf(SCSIRequest *req)
925
+{
926
+ UfsSCSIReq *r = DO_UPCAST(UfsSCSIReq, req, req);
927
+
928
+ return (uint8_t *)r->iov.iov_base;
929
+}
930
+
931
+static int32_t ufs_scsi_dma_command(SCSIRequest *req, uint8_t *buf)
932
+{
933
+ UfsSCSIReq *r = DO_UPCAST(UfsSCSIReq, req, req);
934
+ UfsLu *lu = DO_UPCAST(UfsLu, qdev, req->dev);
935
+ uint32_t len;
936
+ uint8_t command;
937
+
938
+ command = buf[0];
939
+
940
+ if (!blk_is_available(lu->qdev.conf.blk)) {
941
+ scsi_check_condition(r, SENSE_CODE(NO_MEDIUM));
942
+ return 0;
943
+ }
944
+
945
+ len = scsi_data_cdb_xfer(r->req.cmd.buf);
946
+ switch (command) {
947
+ case READ_6:
948
+ case READ_10:
949
+ trace_ufs_scsi_dma_command_READ(r->req.cmd.lba, len);
950
+ if (r->req.cmd.buf[1] & 0xe0) {
951
+ goto illegal_request;
952
+ }
953
+ if (!check_lba_range(lu, r->req.cmd.lba, len)) {
954
+ goto illegal_lba;
955
+ }
956
+ r->sector = r->req.cmd.lba * (lu->qdev.blocksize / BDRV_SECTOR_SIZE);
957
+ r->sector_count = len * (lu->qdev.blocksize / BDRV_SECTOR_SIZE);
958
+ break;
959
+ case WRITE_6:
960
+ case WRITE_10:
961
+ trace_ufs_scsi_dma_command_WRITE(r->req.cmd.lba, len);
962
+ if (!blk_is_writable(lu->qdev.conf.blk)) {
963
+ scsi_check_condition(r, SENSE_CODE(WRITE_PROTECTED));
964
+ return 0;
965
+ }
966
+ if (r->req.cmd.buf[1] & 0xe0) {
967
+ goto illegal_request;
968
+ }
969
+ if (!check_lba_range(lu, r->req.cmd.lba, len)) {
970
+ goto illegal_lba;
971
+ }
972
+ r->sector = r->req.cmd.lba * (lu->qdev.blocksize / BDRV_SECTOR_SIZE);
973
+ r->sector_count = len * (lu->qdev.blocksize / BDRV_SECTOR_SIZE);
974
+ break;
975
+ default:
976
+ abort();
977
+ illegal_request:
978
+ scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
979
+ return 0;
980
+ illegal_lba:
981
+ scsi_check_condition(r, SENSE_CODE(LBA_OUT_OF_RANGE));
982
+ return 0;
983
+ }
984
+ r->need_fua_emulation = ((r->req.cmd.buf[1] & 8) != 0);
985
+ if (r->sector_count == 0) {
986
+ scsi_req_complete(&r->req, GOOD);
987
+ }
988
+ assert(r->iov.iov_len == 0);
989
+ if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
990
+ return -r->sector_count * BDRV_SECTOR_SIZE;
991
+ } else {
992
+ return r->sector_count * BDRV_SECTOR_SIZE;
993
+ }
994
+}
995
+
996
+static void scsi_write_do_fua(UfsSCSIReq *r)
997
+{
998
+ UfsLu *lu = DO_UPCAST(UfsLu, qdev, r->req.dev);
999
+
1000
+ assert(r->req.aiocb == NULL);
1001
+ assert(!r->req.io_canceled);
1002
+
1003
+ if (r->need_fua_emulation) {
1004
+ block_acct_start(blk_get_stats(lu->qdev.conf.blk), &r->acct, 0,
1005
+ BLOCK_ACCT_FLUSH);
1006
+ r->req.aiocb = blk_aio_flush(lu->qdev.conf.blk, scsi_aio_complete, r);
1007
+ return;
1008
+ }
1009
+
1010
+ scsi_req_complete(&r->req, GOOD);
1011
+ scsi_req_unref(&r->req);
1012
+}
1013
+
1014
+static void scsi_dma_complete_noio(UfsSCSIReq *r, int ret)
1015
+{
1016
+ assert(r->req.aiocb == NULL);
1017
+ if (ufs_scsi_req_check_error(r, ret, false)) {
1018
+ goto done;
1019
+ }
1020
+
1021
+ r->sector += r->sector_count;
1022
+ r->sector_count = 0;
1023
+ if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
1024
+ scsi_write_do_fua(r);
1025
+ return;
1026
+ } else {
1027
+ scsi_req_complete(&r->req, GOOD);
1028
+ }
1029
+
1030
+done:
1031
+ scsi_req_unref(&r->req);
1032
+}
1033
+
1034
+static void scsi_dma_complete(void *opaque, int ret)
1035
+{
1036
+ UfsSCSIReq *r = (UfsSCSIReq *)opaque;
1037
+ UfsLu *lu = DO_UPCAST(UfsLu, qdev, r->req.dev);
1038
+
1039
+ assert(r->req.aiocb != NULL);
1040
+ r->req.aiocb = NULL;
1041
+
1042
+ aio_context_acquire(blk_get_aio_context(lu->qdev.conf.blk));
1043
+ if (ret < 0) {
1044
+ block_acct_failed(blk_get_stats(lu->qdev.conf.blk), &r->acct);
1045
+ } else {
1046
+ block_acct_done(blk_get_stats(lu->qdev.conf.blk), &r->acct);
1047
+ }
1048
+ scsi_dma_complete_noio(r, ret);
1049
+ aio_context_release(blk_get_aio_context(lu->qdev.conf.blk));
1050
+}
1051
+
1052
+static BlockAIOCB *scsi_dma_readv(int64_t offset, QEMUIOVector *iov,
1053
+ BlockCompletionFunc *cb, void *cb_opaque,
1054
+ void *opaque)
1055
+{
1056
+ UfsSCSIReq *r = opaque;
1057
+ UfsLu *lu = DO_UPCAST(UfsLu, qdev, r->req.dev);
1058
+ return blk_aio_preadv(lu->qdev.conf.blk, offset, iov, 0, cb, cb_opaque);
1059
+}
1060
+
1061
+static void scsi_init_iovec(UfsSCSIReq *r, size_t size)
1062
+{
1063
+ UfsLu *lu = DO_UPCAST(UfsLu, qdev, r->req.dev);
1064
+
1065
+ if (!r->iov.iov_base) {
1066
+ r->buflen = size;
1067
+ r->iov.iov_base = blk_blockalign(lu->qdev.conf.blk, r->buflen);
1068
+ }
1069
+ r->iov.iov_len = MIN(r->sector_count * BDRV_SECTOR_SIZE, r->buflen);
1070
+ qemu_iovec_init_external(&r->qiov, &r->iov, 1);
1071
+}
1072
+
1073
+static void scsi_read_complete_noio(UfsSCSIReq *r, int ret)
1074
+{
1075
+ uint32_t n;
1076
+
1077
+ assert(r->req.aiocb == NULL);
1078
+ if (ufs_scsi_req_check_error(r, ret, false)) {
1079
+ goto done;
1080
+ }
1081
+
1082
+ n = r->qiov.size / BDRV_SECTOR_SIZE;
1083
+ r->sector += n;
1084
+ r->sector_count -= n;
1085
+ scsi_req_data(&r->req, r->qiov.size);
1086
+
1087
+done:
1088
+ scsi_req_unref(&r->req);
1089
+}
1090
+
1091
+static void scsi_read_complete(void *opaque, int ret)
1092
+{
1093
+ UfsSCSIReq *r = (UfsSCSIReq *)opaque;
1094
+ UfsLu *lu = DO_UPCAST(UfsLu, qdev, r->req.dev);
1095
+
1096
+ assert(r->req.aiocb != NULL);
1097
+ r->req.aiocb = NULL;
1098
+ trace_ufs_scsi_read_data_count(r->sector_count);
1099
+ aio_context_acquire(blk_get_aio_context(lu->qdev.conf.blk));
1100
+ if (ret < 0) {
1101
+ block_acct_failed(blk_get_stats(lu->qdev.conf.blk), &r->acct);
1102
+ } else {
1103
+ block_acct_done(blk_get_stats(lu->qdev.conf.blk), &r->acct);
1104
+ trace_ufs_scsi_read_complete(r->req.tag, r->qiov.size);
1105
+ }
1106
+ scsi_read_complete_noio(r, ret);
1107
+ aio_context_release(blk_get_aio_context(lu->qdev.conf.blk));
1108
+}
1109
+
1110
+/* Actually issue a read to the block device. */
1111
+static void scsi_do_read(UfsSCSIReq *r, int ret)
1112
+{
1113
+ UfsLu *lu = DO_UPCAST(UfsLu, qdev, r->req.dev);
1114
+
1115
+ assert(r->req.aiocb == NULL);
1116
+ if (ufs_scsi_req_check_error(r, ret, false)) {
1117
+ goto done;
1118
+ }
1119
+
1120
+ /* The request is used as the AIO opaque value, so add a ref. */
1121
+ scsi_req_ref(&r->req);
1122
+
1123
+ if (r->req.sg) {
1124
+ dma_acct_start(lu->qdev.conf.blk, &r->acct, r->req.sg, BLOCK_ACCT_READ);
1125
+ r->req.residual -= r->req.sg->size;
1126
+ r->req.aiocb = dma_blk_io(
1127
+ blk_get_aio_context(lu->qdev.conf.blk), r->req.sg,
1128
+ r->sector << BDRV_SECTOR_BITS, BDRV_SECTOR_SIZE, scsi_dma_readv, r,
1129
+ scsi_dma_complete, r, DMA_DIRECTION_FROM_DEVICE);
1130
+ } else {
1131
+ scsi_init_iovec(r, SCSI_DMA_BUF_SIZE);
1132
+ block_acct_start(blk_get_stats(lu->qdev.conf.blk), &r->acct,
1133
+ r->qiov.size, BLOCK_ACCT_READ);
1134
+ r->req.aiocb = scsi_dma_readv(r->sector << BDRV_SECTOR_BITS, &r->qiov,
1135
+ scsi_read_complete, r, r);
1136
+ }
1137
+
1138
+done:
1139
+ scsi_req_unref(&r->req);
1140
+}
1141
+
1142
+static void scsi_do_read_cb(void *opaque, int ret)
1143
+{
1144
+ UfsSCSIReq *r = (UfsSCSIReq *)opaque;
1145
+ UfsLu *lu = DO_UPCAST(UfsLu, qdev, r->req.dev);
1146
+
1147
+ assert(r->req.aiocb != NULL);
1148
+ r->req.aiocb = NULL;
1149
+
1150
+ aio_context_acquire(blk_get_aio_context(lu->qdev.conf.blk));
1151
+ if (ret < 0) {
1152
+ block_acct_failed(blk_get_stats(lu->qdev.conf.blk), &r->acct);
1153
+ } else {
1154
+ block_acct_done(blk_get_stats(lu->qdev.conf.blk), &r->acct);
1155
+ }
1156
+ scsi_do_read(opaque, ret);
1157
+ aio_context_release(blk_get_aio_context(lu->qdev.conf.blk));
1158
+}
1159
+
1160
+/* Read more data from scsi device into buffer. */
1161
+static void scsi_read_data(SCSIRequest *req)
1162
+{
1163
+ UfsSCSIReq *r = DO_UPCAST(UfsSCSIReq, req, req);
1164
+ UfsLu *lu = DO_UPCAST(UfsLu, qdev, r->req.dev);
1165
+ bool first;
1166
+
1167
+ trace_ufs_scsi_read_data_count(r->sector_count);
1168
+ if (r->sector_count == 0) {
1169
+ /* This also clears the sense buffer for REQUEST SENSE. */
1170
+ scsi_req_complete(&r->req, GOOD);
1171
+ return;
1172
+ }
1173
+
1174
+ /* No data transfer may already be in progress */
1175
+ assert(r->req.aiocb == NULL);
1176
+
1177
+ /* The request is used as the AIO opaque value, so add a ref. */
1178
+ scsi_req_ref(&r->req);
1179
+ if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
1180
+ trace_ufs_scsi_read_data_invalid();
1181
+ scsi_read_complete_noio(r, -EINVAL);
1182
+ return;
1183
+ }
1184
+
1185
+ if (!blk_is_available(req->dev->conf.blk)) {
1186
+ scsi_read_complete_noio(r, -ENOMEDIUM);
1187
+ return;
1188
+ }
1189
+
1190
+ first = !r->started;
1191
+ r->started = true;
1192
+ if (first && r->need_fua_emulation) {
1193
+ block_acct_start(blk_get_stats(lu->qdev.conf.blk), &r->acct, 0,
1194
+ BLOCK_ACCT_FLUSH);
1195
+ r->req.aiocb = blk_aio_flush(lu->qdev.conf.blk, scsi_do_read_cb, r);
1196
+ } else {
1197
+ scsi_do_read(r, 0);
1198
+ }
1199
+}
1200
+
1201
+static void scsi_write_complete_noio(UfsSCSIReq *r, int ret)
1202
+{
1203
+ uint32_t n;
1204
+
1205
+ assert(r->req.aiocb == NULL);
1206
+ if (ufs_scsi_req_check_error(r, ret, false)) {
1207
+ goto done;
1208
+ }
1209
+
1210
+ n = r->qiov.size / BDRV_SECTOR_SIZE;
1211
+ r->sector += n;
1212
+ r->sector_count -= n;
1213
+ if (r->sector_count == 0) {
1214
+ scsi_write_do_fua(r);
1215
+ return;
1216
+ } else {
1217
+ scsi_init_iovec(r, SCSI_DMA_BUF_SIZE);
1218
+ trace_ufs_scsi_write_complete_noio(r->req.tag, r->qiov.size);
1219
+ scsi_req_data(&r->req, r->qiov.size);
1220
+ }
1221
+
1222
+done:
1223
+ scsi_req_unref(&r->req);
1224
+}
1225
+
1226
+static void scsi_write_complete(void *opaque, int ret)
1227
+{
1228
+ UfsSCSIReq *r = (UfsSCSIReq *)opaque;
1229
+ UfsLu *lu = DO_UPCAST(UfsLu, qdev, r->req.dev);
1230
+
1231
+ assert(r->req.aiocb != NULL);
1232
+ r->req.aiocb = NULL;
1233
+
1234
+ aio_context_acquire(blk_get_aio_context(lu->qdev.conf.blk));
1235
+ if (ret < 0) {
1236
+ block_acct_failed(blk_get_stats(lu->qdev.conf.blk), &r->acct);
1237
+ } else {
1238
+ block_acct_done(blk_get_stats(lu->qdev.conf.blk), &r->acct);
1239
+ }
1240
+ scsi_write_complete_noio(r, ret);
1241
+ aio_context_release(blk_get_aio_context(lu->qdev.conf.blk));
1242
+}
1243
+
1244
+static BlockAIOCB *scsi_dma_writev(int64_t offset, QEMUIOVector *iov,
1245
+ BlockCompletionFunc *cb, void *cb_opaque,
1246
+ void *opaque)
1247
+{
1248
+ UfsSCSIReq *r = opaque;
1249
+ UfsLu *lu = DO_UPCAST(UfsLu, qdev, r->req.dev);
1250
+ return blk_aio_pwritev(lu->qdev.conf.blk, offset, iov, 0, cb, cb_opaque);
1251
+}
1252
+
1253
+static void scsi_write_data(SCSIRequest *req)
1254
+{
1255
+ UfsSCSIReq *r = DO_UPCAST(UfsSCSIReq, req, req);
1256
+ UfsLu *lu = DO_UPCAST(UfsLu, qdev, r->req.dev);
1257
+
1258
+ /* No data transfer may already be in progress */
1259
+ assert(r->req.aiocb == NULL);
1260
+
1261
+ /* The request is used as the AIO opaque value, so add a ref. */
1262
+ scsi_req_ref(&r->req);
1263
+ if (r->req.cmd.mode != SCSI_XFER_TO_DEV) {
1264
+ trace_ufs_scsi_write_data_invalid();
1265
+ scsi_write_complete_noio(r, -EINVAL);
1266
+ return;
1267
+ }
1268
+
1269
+ if (!r->req.sg && !r->qiov.size) {
1270
+ /* Called for the first time. Ask the driver to send us more data. */
1271
+ r->started = true;
1272
+ scsi_write_complete_noio(r, 0);
1273
+ return;
1274
+ }
1275
+ if (!blk_is_available(req->dev->conf.blk)) {
1276
+ scsi_write_complete_noio(r, -ENOMEDIUM);
1277
+ return;
1278
+ }
1279
+
1280
+ if (r->req.sg) {
1281
+ dma_acct_start(lu->qdev.conf.blk, &r->acct, r->req.sg,
1282
+ BLOCK_ACCT_WRITE);
1283
+ r->req.residual -= r->req.sg->size;
1284
+ r->req.aiocb = dma_blk_io(
1285
+ blk_get_aio_context(lu->qdev.conf.blk), r->req.sg,
1286
+ r->sector << BDRV_SECTOR_BITS, BDRV_SECTOR_SIZE, scsi_dma_writev, r,
1287
+ scsi_dma_complete, r, DMA_DIRECTION_TO_DEVICE);
1288
+ } else {
1289
+ block_acct_start(blk_get_stats(lu->qdev.conf.blk), &r->acct,
1290
+ r->qiov.size, BLOCK_ACCT_WRITE);
1291
+ r->req.aiocb = scsi_dma_writev(r->sector << BDRV_SECTOR_BITS, &r->qiov,
1292
+ scsi_write_complete, r, r);
1293
+ }
1294
+}
1295
+
1296
+static const SCSIReqOps ufs_scsi_emulate_reqops = {
1297
+ .size = sizeof(UfsSCSIReq),
1298
+ .free_req = ufs_scsi_free_request,
1299
+ .send_command = ufs_scsi_emulate_command,
1300
+ .read_data = ufs_scsi_emulate_read_data,
1301
+ .write_data = ufs_scsi_emulate_write_data,
1302
+ .get_buf = ufs_scsi_get_buf,
1303
+};
1304
+
1305
+static const SCSIReqOps ufs_scsi_dma_reqops = {
1306
+ .size = sizeof(UfsSCSIReq),
1307
+ .free_req = ufs_scsi_free_request,
1308
+ .send_command = ufs_scsi_dma_command,
1309
+ .read_data = scsi_read_data,
1310
+ .write_data = scsi_write_data,
1311
+ .get_buf = ufs_scsi_get_buf,
1312
+};
1313
+
1314
+/*
1315
+ * Following commands are not yet supported
1316
+ * PRE_FETCH(10),
1317
+ * UNMAP,
1318
+ * WRITE_BUFFER, READ_BUFFER,
1319
+ * SECURITY_PROTOCOL_IN, SECURITY_PROTOCOL_OUT
1320
+ */
1321
+static const SCSIReqOps *const ufs_scsi_reqops_dispatch[256] = {
1322
+ [TEST_UNIT_READY] = &ufs_scsi_emulate_reqops,
1323
+ [INQUIRY] = &ufs_scsi_emulate_reqops,
1324
+ [MODE_SENSE_10] = &ufs_scsi_emulate_reqops,
1325
+ [START_STOP] = &ufs_scsi_emulate_reqops,
1326
+ [READ_CAPACITY_10] = &ufs_scsi_emulate_reqops,
1327
+ [REQUEST_SENSE] = &ufs_scsi_emulate_reqops,
1328
+ [SYNCHRONIZE_CACHE] = &ufs_scsi_emulate_reqops,
1329
+ [MODE_SELECT_10] = &ufs_scsi_emulate_reqops,
1330
+ [VERIFY_10] = &ufs_scsi_emulate_reqops,
1331
+ [FORMAT_UNIT] = &ufs_scsi_emulate_reqops,
1332
+ [SERVICE_ACTION_IN_16] = &ufs_scsi_emulate_reqops,
1333
+ [SEND_DIAGNOSTIC] = &ufs_scsi_emulate_reqops,
1334
+
1335
+ [READ_6] = &ufs_scsi_dma_reqops,
1336
+ [READ_10] = &ufs_scsi_dma_reqops,
1337
+ [WRITE_6] = &ufs_scsi_dma_reqops,
1338
+ [WRITE_10] = &ufs_scsi_dma_reqops,
1339
+};
1340
+
1341
+static SCSIRequest *scsi_new_request(SCSIDevice *dev, uint32_t tag,
1342
+ uint32_t lun, uint8_t *buf,
1343
+ void *hba_private)
1344
+{
1345
+ UfsLu *lu = DO_UPCAST(UfsLu, qdev, dev);
1346
+ SCSIRequest *req;
1347
+ const SCSIReqOps *ops;
1348
+ uint8_t command;
1349
+
1350
+ command = buf[0];
1351
+ ops = ufs_scsi_reqops_dispatch[command];
1352
+ if (!ops) {
1353
+ ops = &ufs_scsi_emulate_reqops;
1354
+ }
1355
+ req = scsi_req_alloc(ops, &lu->qdev, tag, lun, hba_private);
1356
+
1357
+ return req;
1358
+}
1359
+
1360
+static Property ufs_lu_props[] = {
1361
+ DEFINE_PROP_DRIVE("drive", UfsLu, qdev.conf.blk),
1362
+ DEFINE_PROP_END_OF_LIST(),
1363
+};
1364
+
1365
+static bool ufs_lu_brdv_init(UfsLu *lu, Error **errp)
1366
+{
1367
+ SCSIDevice *dev = &lu->qdev;
1368
+ bool read_only;
1369
+
1370
+ if (!lu->qdev.conf.blk) {
1371
+ error_setg(errp, "drive property not set");
1372
+ return false;
1373
+ }
1374
+
1375
+ if (!blkconf_blocksizes(&lu->qdev.conf, errp)) {
1376
+ return false;
1377
+ }
1378
+
1379
+ if (blk_get_aio_context(lu->qdev.conf.blk) != qemu_get_aio_context() &&
1380
+ !lu->qdev.hba_supports_iothread) {
1381
+ error_setg(errp, "HBA does not support iothreads");
1382
+ return false;
1383
+ }
1384
+
1385
+ read_only = !blk_supports_write_perm(lu->qdev.conf.blk);
1386
+
1387
+ if (!blkconf_apply_backend_options(&dev->conf, read_only,
1388
+ dev->type == TYPE_DISK, errp)) {
1389
+ return false;
1390
+ }
1391
+
1392
+ if (blk_is_sg(lu->qdev.conf.blk)) {
1393
+ error_setg(errp, "unwanted /dev/sg*");
1394
+ return false;
1395
+ }
1396
+
1397
+ blk_iostatus_enable(lu->qdev.conf.blk);
1398
+ return true;
1399
+}
1400
+
1401
+static bool ufs_add_lu(UfsHc *u, UfsLu *lu, Error **errp)
1402
+{
1403
+ BlockBackend *blk = lu->qdev.conf.blk;
1404
+ int64_t brdv_len = blk_getlength(blk);
1405
+ uint64_t raw_dev_cap =
1406
+ be64_to_cpu(u->geometry_desc.total_raw_device_capacity);
1407
+
1408
+ if (u->device_desc.number_lu >= UFS_MAX_LUS) {
1409
+ error_setg(errp, "ufs host controller has too many logical units.");
1410
+ return false;
1411
+ }
1412
+
1413
+ if (u->lus[lu->lun] != NULL) {
1414
+ error_setg(errp, "ufs logical unit %d already exists.", lu->lun);
1415
+ return false;
1416
+ }
1417
+
1418
+ u->lus[lu->lun] = lu;
1419
+ u->device_desc.number_lu++;
1420
+ raw_dev_cap += (brdv_len >> UFS_GEOMETRY_CAPACITY_SHIFT);
1421
+ u->geometry_desc.total_raw_device_capacity = cpu_to_be64(raw_dev_cap);
1422
+ return true;
1423
+}
1424
+
1425
+static inline uint8_t ufs_log2(uint64_t input)
1426
+{
1427
+ int log = 0;
1428
+ while (input >>= 1) {
1429
+ log++;
1430
+ }
1431
+ return log;
1432
+}
1433
+
1434
+static void ufs_init_lu(UfsLu *lu)
1435
+{
1436
+ BlockBackend *blk = lu->qdev.conf.blk;
1437
+ int64_t brdv_len = blk_getlength(blk);
1438
+
1439
+ lu->lun = lu->qdev.lun;
1440
+ memset(&lu->unit_desc, 0, sizeof(lu->unit_desc));
1441
+ lu->unit_desc.length = sizeof(UnitDescriptor);
1442
+ lu->unit_desc.descriptor_idn = QUERY_DESC_IDN_UNIT;
1443
+ lu->unit_desc.lu_enable = 0x01;
1444
+ lu->unit_desc.logical_block_size = ufs_log2(lu->qdev.blocksize);
1445
+ lu->unit_desc.unit_index = lu->qdev.lun;
1446
+ lu->unit_desc.logical_block_count =
1447
+ cpu_to_be64(brdv_len / (1 << lu->unit_desc.logical_block_size));
1448
+}
1449
+
1450
+static bool ufs_lu_check_constraints(UfsLu *lu, Error **errp)
1451
+{
1452
+ if (!lu->qdev.conf.blk) {
1453
+ error_setg(errp, "drive property not set");
1454
+ return false;
1455
+ }
1456
+
1457
+ if (lu->qdev.channel != 0) {
1458
+ error_setg(errp, "ufs logical unit does not support channel");
1459
+ return false;
1460
+ }
1461
+
1462
+ if (lu->qdev.lun >= UFS_MAX_LUS) {
1463
+ error_setg(errp, "lun must be between 1 and %d", UFS_MAX_LUS - 1);
1464
+ return false;
1465
+ }
1466
+
1467
+ return true;
1468
+}
1469
+
1470
+static void ufs_lu_realize(SCSIDevice *dev, Error **errp)
1471
+{
1472
+ UfsLu *lu = DO_UPCAST(UfsLu, qdev, dev);
1473
+ BusState *s = qdev_get_parent_bus(&dev->qdev);
1474
+ UfsHc *u = UFS(s->parent);
1475
+ AioContext *ctx = NULL;
1476
+ uint64_t nb_sectors, nb_blocks;
1477
+
1478
+ if (!ufs_lu_check_constraints(lu, errp)) {
1479
+ return;
1480
+ }
1481
+
1482
+ if (lu->qdev.conf.blk) {
1483
+ ctx = blk_get_aio_context(lu->qdev.conf.blk);
1484
+ aio_context_acquire(ctx);
1485
+ if (!blkconf_blocksizes(&lu->qdev.conf, errp)) {
1486
+ goto out;
1487
+ }
1488
+ }
1489
+ lu->qdev.blocksize = UFS_BLOCK_SIZE;
1490
+ blk_get_geometry(lu->qdev.conf.blk, &nb_sectors);
1491
+ nb_blocks = nb_sectors / (lu->qdev.blocksize / BDRV_SECTOR_SIZE);
1492
+ if (nb_blocks > UINT32_MAX) {
1493
+ nb_blocks = UINT32_MAX;
1494
+ }
1495
+ lu->qdev.max_lba = nb_blocks;
1496
+ lu->qdev.type = TYPE_DISK;
1497
+
1498
+ ufs_init_lu(lu);
1499
+ if (!ufs_add_lu(u, lu, errp)) {
1500
+ goto out;
1501
+ }
1502
+
1503
+ ufs_lu_brdv_init(lu, errp);
1504
+out:
1505
+ if (ctx) {
1506
+ aio_context_release(ctx);
1507
+ }
1508
+}
1509
+
1510
+static void ufs_lu_unrealize(SCSIDevice *dev)
1511
+{
1512
+ UfsLu *lu = DO_UPCAST(UfsLu, qdev, dev);
1513
+
1514
+ blk_drain(lu->qdev.conf.blk);
1515
+}
1516
+
1517
+static void ufs_wlu_realize(DeviceState *qdev, Error **errp)
1518
+{
1519
+ UfsWLu *wlu = UFSWLU(qdev);
1520
+ SCSIDevice *dev = &wlu->qdev;
1521
+
1522
+ if (!is_wlun(dev->lun)) {
1523
+ error_setg(errp, "not well-known logical unit number");
1524
+ return;
1525
+ }
1526
+
1527
+ QTAILQ_INIT(&dev->requests);
1528
+}
1529
+
1530
+static void ufs_lu_class_init(ObjectClass *oc, void *data)
1531
+{
1532
+ DeviceClass *dc = DEVICE_CLASS(oc);
1533
+ SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(oc);
1534
+
1535
+ sc->realize = ufs_lu_realize;
1536
+ sc->unrealize = ufs_lu_unrealize;
1537
+ sc->alloc_req = scsi_new_request;
1538
+ dc->bus_type = TYPE_UFS_BUS;
1539
+ device_class_set_props(dc, ufs_lu_props);
1540
+ dc->desc = "Virtual UFS logical unit";
1541
+}
1542
+
1543
+static void ufs_wlu_class_init(ObjectClass *oc, void *data)
1544
+{
1545
+ DeviceClass *dc = DEVICE_CLASS(oc);
1546
+ SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(oc);
1547
+
1548
+ /*
1549
+ * The realize() function of TYPE_SCSI_DEVICE causes a segmentation fault
1550
+ * if a block drive does not exist. Define a new realize function for
1551
+ * well-known LUs that do not have a block drive.
1552
+ */
1553
+ dc->realize = ufs_wlu_realize;
1554
+ sc->alloc_req = scsi_new_request;
1555
+ dc->bus_type = TYPE_UFS_BUS;
1556
+ dc->desc = "Virtual UFS well-known logical unit";
1557
+}
1558
+
1559
+static const TypeInfo ufs_lu_info = {
1560
+ .name = TYPE_UFS_LU,
1561
+ .parent = TYPE_SCSI_DEVICE,
1562
+ .class_init = ufs_lu_class_init,
1563
+ .instance_size = sizeof(UfsLu),
1564
+};
1565
+
1566
+static const TypeInfo ufs_wlu_info = {
1567
+ .name = TYPE_UFS_WLU,
1568
+ .parent = TYPE_SCSI_DEVICE,
1569
+ .class_init = ufs_wlu_class_init,
1570
+ .instance_size = sizeof(UfsWLu),
1571
+};
1572
+
1573
+static void ufs_lu_register_types(void)
1574
+{
1575
+ type_register_static(&ufs_lu_info);
1576
+ type_register_static(&ufs_wlu_info);
1577
+}
1578
+
1579
+type_init(ufs_lu_register_types)
1580
diff --git a/hw/ufs/ufs.c b/hw/ufs/ufs.c
1581
index XXXXXXX..XXXXXXX 100644
1582
--- a/hw/ufs/ufs.c
1583
+++ b/hw/ufs/ufs.c
1584
@@ -XXX,XX +XXX,XX @@
1585
* SPDX-License-Identifier: GPL-2.0-or-later
1586
*/
1587
1588
+/**
1589
+ * Reference Specs: https://www.jedec.org/, 3.1
1590
+ *
1591
+ * Usage
1592
+ * -----
1593
+ *
1594
+ * Add options:
1595
+ * -drive file=<file>,if=none,id=<drive_id>
1596
+ * -device ufs,serial=<serial>,id=<bus_name>, \
1597
+ * nutrs=<N[optional]>,nutmrs=<N[optional]>
1598
+ * -device ufs-lu,drive=<drive_id>,bus=<bus_name>
1599
+ */
1600
+
1601
#include "qemu/osdep.h"
1602
#include "qapi/error.h"
1603
#include "migration/vmstate.h"
1604
@@ -XXX,XX +XXX,XX @@ static const MemoryRegionOps ufs_mmio_ops = {
1605
},
1606
};
1607
1608
+static QEMUSGList *ufs_get_sg_list(SCSIRequest *scsi_req)
1609
+{
1610
+ UfsRequest *req = scsi_req->hba_private;
1611
+ return req->sg;
1612
+}
1613
+
1614
+static void ufs_build_upiu_sense_data(UfsRequest *req, SCSIRequest *scsi_req)
1615
+{
1616
+ req->rsp_upiu.sr.sense_data_len = cpu_to_be16(scsi_req->sense_len);
1617
+ assert(scsi_req->sense_len <= SCSI_SENSE_LEN);
1618
+ memcpy(req->rsp_upiu.sr.sense_data, scsi_req->sense, scsi_req->sense_len);
1619
+}
1620
+
1621
static void ufs_build_upiu_header(UfsRequest *req, uint8_t trans_type,
1622
uint8_t flags, uint8_t response,
1623
uint8_t scsi_status,
1624
@@ -XXX,XX +XXX,XX @@ static void ufs_build_upiu_header(UfsRequest *req, uint8_t trans_type,
1625
req->rsp_upiu.header.data_segment_length = cpu_to_be16(data_segment_length);
1626
}
1627
1628
+static void ufs_scsi_command_complete(SCSIRequest *scsi_req, size_t resid)
1629
+{
1630
+ UfsRequest *req = scsi_req->hba_private;
1631
+ int16_t status = scsi_req->status;
1632
+ uint32_t expected_len = be32_to_cpu(req->req_upiu.sc.exp_data_transfer_len);
1633
+ uint32_t transfered_len = scsi_req->cmd.xfer - resid;
1634
+ uint8_t flags = 0, response = COMMAND_RESULT_SUCESS;
1635
+ uint16_t data_segment_length;
1636
+
1637
+ if (expected_len > transfered_len) {
1638
+ req->rsp_upiu.sr.residual_transfer_count =
1639
+ cpu_to_be32(expected_len - transfered_len);
1640
+ flags |= UFS_UPIU_FLAG_UNDERFLOW;
1641
+ } else if (expected_len < transfered_len) {
1642
+ req->rsp_upiu.sr.residual_transfer_count =
1643
+ cpu_to_be32(transfered_len - expected_len);
1644
+ flags |= UFS_UPIU_FLAG_OVERFLOW;
1645
+ }
1646
+
1647
+ if (status != 0) {
1648
+ ufs_build_upiu_sense_data(req, scsi_req);
1649
+ response = COMMAND_RESULT_FAIL;
1650
+ }
1651
+
1652
+ data_segment_length = cpu_to_be16(scsi_req->sense_len +
1653
+ sizeof(req->rsp_upiu.sr.sense_data_len));
1654
+ ufs_build_upiu_header(req, UPIU_TRANSACTION_RESPONSE, flags, response,
1655
+ status, data_segment_length);
1656
+
1657
+ ufs_complete_req(req, UFS_REQUEST_SUCCESS);
1658
+
1659
+ scsi_req->hba_private = NULL;
1660
+ scsi_req_unref(scsi_req);
1661
+}
1662
+
1663
+static const struct SCSIBusInfo ufs_scsi_info = {
1664
+ .tcq = true,
1665
+ .max_target = 0,
1666
+ .max_lun = UFS_MAX_LUS,
1667
+ .max_channel = 0,
1668
+
1669
+ .get_sg_list = ufs_get_sg_list,
1670
+ .complete = ufs_scsi_command_complete,
1671
+};
1672
+
1673
+static UfsReqResult ufs_exec_scsi_cmd(UfsRequest *req)
1674
+{
1675
+ UfsHc *u = req->hc;
1676
+ uint8_t lun = req->req_upiu.header.lun;
1677
+ uint8_t task_tag = req->req_upiu.header.task_tag;
1678
+ SCSIDevice *dev = NULL;
1679
+
1680
+ trace_ufs_exec_scsi_cmd(req->slot, lun, req->req_upiu.sc.cdb[0]);
1681
+
1682
+ if (!is_wlun(lun)) {
1683
+ if (lun >= u->device_desc.number_lu) {
1684
+ trace_ufs_err_scsi_cmd_invalid_lun(lun);
1685
+ return UFS_REQUEST_FAIL;
1686
+ } else if (u->lus[lun] == NULL) {
1687
+ trace_ufs_err_scsi_cmd_invalid_lun(lun);
1688
+ return UFS_REQUEST_FAIL;
1689
+ }
1690
+ }
1691
+
1692
+ switch (lun) {
1693
+ case UFS_UPIU_REPORT_LUNS_WLUN:
1694
+ dev = &u->report_wlu->qdev;
1695
+ break;
1696
+ case UFS_UPIU_UFS_DEVICE_WLUN:
1697
+ dev = &u->dev_wlu->qdev;
1698
+ break;
1699
+ case UFS_UPIU_BOOT_WLUN:
1700
+ dev = &u->boot_wlu->qdev;
1701
+ break;
1702
+ case UFS_UPIU_RPMB_WLUN:
1703
+ dev = &u->rpmb_wlu->qdev;
1704
+ break;
1705
+ default:
1706
+ dev = &u->lus[lun]->qdev;
1707
+ }
1708
+
1709
+ SCSIRequest *scsi_req = scsi_req_new(
1710
+ dev, task_tag, lun, req->req_upiu.sc.cdb, UFS_CDB_SIZE, req);
1711
+
1712
+ uint32_t len = scsi_req_enqueue(scsi_req);
1713
+ if (len) {
1714
+ scsi_req_continue(scsi_req);
1715
+ }
1716
+
1717
+ return UFS_REQUEST_NO_COMPLETE;
1718
+}
1719
+
1720
static UfsReqResult ufs_exec_nop_cmd(UfsRequest *req)
607
{
1721
{
608
- g_free(block->opaque);
1722
trace_ufs_exec_nop_cmd(req->slot);
609
+ QCryptoBlockLUKS *luks = block->opaque;
1723
@@ -XXX,XX +XXX,XX @@ static const RpmbUnitDescriptor rpmb_unit_desc = {
610
+ if (luks) {
1724
611
+ g_free(luks->secret);
1725
static QueryRespCode ufs_read_unit_desc(UfsRequest *req)
612
+ g_free(luks);
1726
{
1727
+ UfsHc *u = req->hc;
1728
uint8_t lun = req->req_upiu.qr.index;
1729
1730
- if (lun != UFS_UPIU_RPMB_WLUN && lun > UFS_MAX_LUS) {
1731
+ if (lun != UFS_UPIU_RPMB_WLUN &&
1732
+ (lun > UFS_MAX_LUS || u->lus[lun] == NULL)) {
1733
trace_ufs_err_query_invalid_index(req->req_upiu.qr.opcode, lun);
1734
return QUERY_RESULT_INVALID_INDEX;
1735
}
1736
@@ -XXX,XX +XXX,XX @@ static QueryRespCode ufs_read_unit_desc(UfsRequest *req)
1737
if (lun == UFS_UPIU_RPMB_WLUN) {
1738
memcpy(&req->rsp_upiu.qr.data, &rpmb_unit_desc, rpmb_unit_desc.length);
1739
} else {
1740
- /* unit descriptor is not yet supported */
1741
- return QUERY_RESULT_INVALID_INDEX;
1742
+ memcpy(&req->rsp_upiu.qr.data, &u->lus[lun]->unit_desc,
1743
+ sizeof(u->lus[lun]->unit_desc));
1744
}
1745
1746
return QUERY_RESULT_SUCCESS;
1747
@@ -XXX,XX +XXX,XX @@ static void ufs_exec_req(UfsRequest *req)
1748
req_result = ufs_exec_nop_cmd(req);
1749
break;
1750
case UPIU_TRANSACTION_COMMAND:
1751
- /* Not yet implemented */
1752
- req_result = UFS_REQUEST_FAIL;
1753
+ req_result = ufs_exec_scsi_cmd(req);
1754
break;
1755
case UPIU_TRANSACTION_QUERY_REQ:
1756
req_result = ufs_exec_query_cmd(req);
1757
@@ -XXX,XX +XXX,XX @@ static void ufs_exec_req(UfsRequest *req)
1758
req_result = UFS_REQUEST_FAIL;
1759
}
1760
1761
- ufs_complete_req(req, req_result);
1762
+ /*
1763
+ * The ufs_complete_req for scsi commands is handled by the
1764
+ * ufs_scsi_command_complete() callback function. Therefore, to avoid
1765
+ * duplicate processing, ufs_complete_req() is not called for scsi commands.
1766
+ */
1767
+ if (req_result != UFS_REQUEST_NO_COMPLETE) {
1768
+ ufs_complete_req(req, req_result);
613
+ }
1769
+ }
614
}
1770
}
615
1771
616
1772
static void ufs_process_req(void *opaque)
617
@@ -XXX,XX +XXX,XX @@ qcrypto_block_luks_encrypt(QCryptoBlock *block,
1773
@@ -XXX,XX +XXX,XX @@ static void ufs_init_hc(UfsHc *u)
618
const QCryptoBlockDriver qcrypto_block_driver_luks = {
1774
u->flags.permanently_disable_fw_update = 1;
619
.open = qcrypto_block_luks_open,
1775
}
620
.create = qcrypto_block_luks_create,
1776
621
+ .amend = qcrypto_block_luks_amend_options,
1777
+static bool ufs_init_wlu(UfsHc *u, UfsWLu **wlu, uint8_t wlun, Error **errp)
622
.get_info = qcrypto_block_luks_get_info,
1778
+{
623
.cleanup = qcrypto_block_luks_cleanup,
1779
+ UfsWLu *new_wlu = UFSWLU(qdev_new(TYPE_UFS_WLU));
624
.decrypt = qcrypto_block_luks_decrypt,
1780
+
1781
+ qdev_prop_set_uint32(DEVICE(new_wlu), "lun", wlun);
1782
+
1783
+ /*
1784
+ * The well-known lu shares the same bus as the normal lu. If the well-known
1785
+ * lu writes the same channel value as the normal lu, the report will be
1786
+ * made not only for the normal lu but also for the well-known lu at
1787
+ * REPORT_LUN time. To prevent this, the channel value of normal lu is fixed
1788
+ * to 0 and the channel value of well-known lu is fixed to 1.
1789
+ */
1790
+ qdev_prop_set_uint32(DEVICE(new_wlu), "channel", 1);
1791
+ if (!qdev_realize_and_unref(DEVICE(new_wlu), BUS(&u->bus), errp)) {
1792
+ return false;
1793
+ }
1794
+
1795
+ *wlu = new_wlu;
1796
+ return true;
1797
+}
1798
+
1799
static void ufs_realize(PCIDevice *pci_dev, Error **errp)
1800
{
1801
UfsHc *u = UFS(pci_dev);
1802
@@ -XXX,XX +XXX,XX @@ static void ufs_realize(PCIDevice *pci_dev, Error **errp)
1803
return;
1804
}
1805
1806
+ qbus_init(&u->bus, sizeof(UfsBus), TYPE_UFS_BUS, &pci_dev->qdev,
1807
+ u->parent_obj.qdev.id);
1808
+ u->bus.parent_bus.info = &ufs_scsi_info;
1809
+
1810
ufs_init_state(u);
1811
ufs_init_hc(u);
1812
ufs_init_pci(u, pci_dev);
1813
+
1814
+ if (!ufs_init_wlu(u, &u->report_wlu, UFS_UPIU_REPORT_LUNS_WLUN, errp)) {
1815
+ return;
1816
+ }
1817
+
1818
+ if (!ufs_init_wlu(u, &u->dev_wlu, UFS_UPIU_UFS_DEVICE_WLUN, errp)) {
1819
+ return;
1820
+ }
1821
+
1822
+ if (!ufs_init_wlu(u, &u->boot_wlu, UFS_UPIU_BOOT_WLUN, errp)) {
1823
+ return;
1824
+ }
1825
+
1826
+ if (!ufs_init_wlu(u, &u->rpmb_wlu, UFS_UPIU_RPMB_WLUN, errp)) {
1827
+ return;
1828
+ }
1829
}
1830
1831
static void ufs_exit(PCIDevice *pci_dev)
1832
{
1833
UfsHc *u = UFS(pci_dev);
1834
1835
+ if (u->dev_wlu) {
1836
+ object_unref(OBJECT(u->dev_wlu));
1837
+ u->dev_wlu = NULL;
1838
+ }
1839
+
1840
+ if (u->report_wlu) {
1841
+ object_unref(OBJECT(u->report_wlu));
1842
+ u->report_wlu = NULL;
1843
+ }
1844
+
1845
+ if (u->rpmb_wlu) {
1846
+ object_unref(OBJECT(u->rpmb_wlu));
1847
+ u->rpmb_wlu = NULL;
1848
+ }
1849
+
1850
+ if (u->boot_wlu) {
1851
+ object_unref(OBJECT(u->boot_wlu));
1852
+ u->boot_wlu = NULL;
1853
+ }
1854
+
1855
qemu_bh_delete(u->doorbell_bh);
1856
qemu_bh_delete(u->complete_bh);
1857
1858
@@ -XXX,XX +XXX,XX @@ static void ufs_class_init(ObjectClass *oc, void *data)
1859
dc->vmsd = &ufs_vmstate;
1860
}
1861
1862
+static bool ufs_bus_check_address(BusState *qbus, DeviceState *qdev,
1863
+ Error **errp)
1864
+{
1865
+ SCSIDevice *dev = SCSI_DEVICE(qdev);
1866
+ UfsBusClass *ubc = UFS_BUS_GET_CLASS(qbus);
1867
+ UfsHc *u = UFS(qbus->parent);
1868
+
1869
+ if (strcmp(object_get_typename(OBJECT(dev)), TYPE_UFS_WLU) == 0) {
1870
+ if (dev->lun != UFS_UPIU_REPORT_LUNS_WLUN &&
1871
+ dev->lun != UFS_UPIU_UFS_DEVICE_WLUN &&
1872
+ dev->lun != UFS_UPIU_BOOT_WLUN && dev->lun != UFS_UPIU_RPMB_WLUN) {
1873
+ error_setg(errp, "bad well-known lun: %d", dev->lun);
1874
+ return false;
1875
+ }
1876
+
1877
+ if ((dev->lun == UFS_UPIU_REPORT_LUNS_WLUN && u->report_wlu != NULL) ||
1878
+ (dev->lun == UFS_UPIU_UFS_DEVICE_WLUN && u->dev_wlu != NULL) ||
1879
+ (dev->lun == UFS_UPIU_BOOT_WLUN && u->boot_wlu != NULL) ||
1880
+ (dev->lun == UFS_UPIU_RPMB_WLUN && u->rpmb_wlu != NULL)) {
1881
+ error_setg(errp, "well-known lun %d already exists", dev->lun);
1882
+ return false;
1883
+ }
1884
+
1885
+ return true;
1886
+ }
1887
+
1888
+ if (strcmp(object_get_typename(OBJECT(dev)), TYPE_UFS_LU) != 0) {
1889
+ error_setg(errp, "%s cannot be connected to ufs-bus",
1890
+ object_get_typename(OBJECT(dev)));
1891
+ return false;
1892
+ }
1893
+
1894
+ return ubc->parent_check_address(qbus, qdev, errp);
1895
+}
1896
+
1897
+static void ufs_bus_class_init(ObjectClass *class, void *data)
1898
+{
1899
+ BusClass *bc = BUS_CLASS(class);
1900
+ UfsBusClass *ubc = UFS_BUS_CLASS(class);
1901
+ ubc->parent_check_address = bc->check_address;
1902
+ bc->check_address = ufs_bus_check_address;
1903
+}
1904
+
1905
static const TypeInfo ufs_info = {
1906
.name = TYPE_UFS,
1907
.parent = TYPE_PCI_DEVICE,
1908
@@ -XXX,XX +XXX,XX @@ static const TypeInfo ufs_info = {
1909
.interfaces = (InterfaceInfo[]){ { INTERFACE_PCIE_DEVICE }, {} },
1910
};
1911
1912
+static const TypeInfo ufs_bus_info = {
1913
+ .name = TYPE_UFS_BUS,
1914
+ .parent = TYPE_SCSI_BUS,
1915
+ .class_init = ufs_bus_class_init,
1916
+ .class_size = sizeof(UfsBusClass),
1917
+ .instance_size = sizeof(UfsBus),
1918
+};
1919
+
1920
static void ufs_register_types(void)
1921
{
1922
type_register_static(&ufs_info);
1923
+ type_register_static(&ufs_bus_info);
1924
}
1925
1926
type_init(ufs_register_types)
1927
diff --git a/hw/ufs/meson.build b/hw/ufs/meson.build
1928
index XXXXXXX..XXXXXXX 100644
1929
--- a/hw/ufs/meson.build
1930
+++ b/hw/ufs/meson.build
1931
@@ -1 +1 @@
1932
-system_ss.add(when: 'CONFIG_UFS_PCI', if_true: files('ufs.c'))
1933
+system_ss.add(when: 'CONFIG_UFS_PCI', if_true: files('ufs.c', 'lu.c'))
1934
diff --git a/hw/ufs/trace-events b/hw/ufs/trace-events
1935
index XXXXXXX..XXXXXXX 100644
1936
--- a/hw/ufs/trace-events
1937
+++ b/hw/ufs/trace-events
1938
@@ -XXX,XX +XXX,XX @@ ufs_exec_scsi_cmd(uint32_t slot, uint8_t lun, uint8_t opcode) "slot %"PRIu32", l
1939
ufs_exec_query_cmd(uint32_t slot, uint8_t opcode) "slot %"PRIu32", opcode 0x%"PRIx8""
1940
ufs_process_uiccmd(uint32_t uiccmd, uint32_t ucmdarg1, uint32_t ucmdarg2, uint32_t ucmdarg3) "uiccmd 0x%"PRIx32", ucmdarg1 0x%"PRIx32", ucmdarg2 0x%"PRIx32", ucmdarg3 0x%"PRIx32""
1941
1942
+# lu.c
1943
+ufs_scsi_check_condition(uint32_t tag, uint8_t key, uint8_t asc, uint8_t ascq) "Command complete tag=0x%x sense=%d/%d/%d"
1944
+ufs_scsi_read_complete(uint32_t tag, size_t size) "Data ready tag=0x%x len=%zd"
1945
+ufs_scsi_read_data_count(uint32_t sector_count) "Read sector_count=%d"
1946
+ufs_scsi_read_data_invalid(void) "Data transfer direction invalid"
1947
+ufs_scsi_write_complete_noio(uint32_t tag, size_t size) "Write complete tag=0x%x more=%zd"
1948
+ufs_scsi_write_data_invalid(void) "Data transfer direction invalid"
1949
+ufs_scsi_emulate_vpd_page_00(size_t xfer) "Inquiry EVPD[Supported pages] buffer size %zd"
1950
+ufs_scsi_emulate_vpd_page_80_not_supported(void) "Inquiry EVPD[Serial number] not supported"
1951
+ufs_scsi_emulate_vpd_page_80(size_t xfer) "Inquiry EVPD[Serial number] buffer size %zd"
1952
+ufs_scsi_emulate_vpd_page_87(size_t xfer) "Inquiry EVPD[Mode Page Policy] buffer size %zd"
1953
+ufs_scsi_emulate_mode_sense(int cmd, int page, size_t xfer, int control) "Mode Sense(%d) (page %d, xfer %zd, page_control %d)"
1954
+ufs_scsi_emulate_read_data(int buflen) "Read buf_len=%d"
1955
+ufs_scsi_emulate_write_data(int buflen) "Write buf_len=%d"
1956
+ufs_scsi_emulate_command_START_STOP(void) "START STOP UNIT"
1957
+ufs_scsi_emulate_command_FORMAT_UNIT(void) "FORMAT UNIT"
1958
+ufs_scsi_emulate_command_SEND_DIAGNOSTIC(void) "SEND DIAGNOSTIC"
1959
+ufs_scsi_emulate_command_SAI_16(void) "SAI READ CAPACITY(16)"
1960
+ufs_scsi_emulate_command_SAI_unsupported(void) "Unsupported Service Action In"
1961
+ufs_scsi_emulate_command_MODE_SELECT_10(size_t xfer) "Mode Select(10) (len %zd)"
1962
+ufs_scsi_emulate_command_VERIFY(int bytchk) "Verify (bytchk %d)"
1963
+ufs_scsi_emulate_command_UNKNOWN(int cmd, const char *name) "Unknown SCSI command (0x%2.2x=%s)"
1964
+ufs_scsi_dma_command_READ(uint64_t lba, uint32_t len) "Read (block %" PRIu64 ", count %u)"
1965
+ufs_scsi_dma_command_WRITE(uint64_t lba, int len) "Write (block %" PRIu64 ", count %u)"
1966
+
1967
# error condition
1968
ufs_err_dma_read_utrd(uint32_t slot, uint64_t addr) "failed to read utrd. UTRLDBR slot %"PRIu32", UTRD dma addr %"PRIu64""
1969
ufs_err_dma_read_req_upiu(uint32_t slot, uint64_t addr) "failed to read req upiu. UTRLDBR slot %"PRIu32", request upiu addr %"PRIu64""
625
--
1970
--
626
2.26.2
1971
2.41.0
627
628
diff view generated by jsdifflib
1
From: Maxim Levitsky <mlevitsk@redhat.com>
1
From: Jeuk Kim <jeuk20.kim@gmail.com>
2
2
3
This commit adds two tests, which test the new amend interface
3
This patch includes the following tests
4
of both luks raw images and qcow2 luks encrypted images.
4
Test mmio read
5
Test ufs device initialization and ufs-lu recognition
6
Test I/O (Performs a write followed by a read to verify)
5
7
6
Signed-off-by: Maxim Levitsky <mlevitsk@redhat.com>
8
Signed-off-by: Jeuk Kim <jeuk20.kim@samsung.com>
7
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
9
Acked-by: Thomas Huth <thuth@redhat.com>
8
Message-Id: <20200608094030.670121-11-mlevitsk@redhat.com>
10
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
Message-id: af6b8d54c049490b3533a784a0aeac4798bb9217.1691062912.git.jeuk20.kim@samsung.com
12
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
10
---
13
---
11
tests/qemu-iotests/293 | 207 +++++++++++++++++++++++++++++++++++++
14
MAINTAINERS | 1 +
12
tests/qemu-iotests/293.out | 99 ++++++++++++++++++
15
tests/qtest/ufs-test.c | 584 ++++++++++++++++++++++++++++++++++++++++
13
tests/qemu-iotests/294 | 90 ++++++++++++++++
16
tests/qtest/meson.build | 1 +
14
tests/qemu-iotests/294.out | 30 ++++++
17
3 files changed, 586 insertions(+)
15
tests/qemu-iotests/group | 2 +
18
create mode 100644 tests/qtest/ufs-test.c
16
5 files changed, 428 insertions(+)
17
create mode 100755 tests/qemu-iotests/293
18
create mode 100644 tests/qemu-iotests/293.out
19
create mode 100755 tests/qemu-iotests/294
20
create mode 100644 tests/qemu-iotests/294.out
21
19
22
diff --git a/tests/qemu-iotests/293 b/tests/qemu-iotests/293
20
diff --git a/MAINTAINERS b/MAINTAINERS
23
new file mode 100755
21
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX
22
--- a/MAINTAINERS
25
--- /dev/null
23
+++ b/MAINTAINERS
26
+++ b/tests/qemu-iotests/293
24
@@ -XXX,XX +XXX,XX @@ M: Jeuk Kim <jeuk20.kim@samsung.com>
27
@@ -XXX,XX +XXX,XX @@
25
S: Supported
28
+#!/usr/bin/env bash
26
F: hw/ufs/*
29
+#
27
F: include/block/ufs.h
30
+# Test encryption key management with luks
28
+F: tests/qtest/ufs-test.c
31
+# Based on 134
29
32
+#
30
megasas
33
+# Copyright (C) 2019 Red Hat, Inc.
31
M: Hannes Reinecke <hare@suse.com>
34
+#
32
diff --git a/tests/qtest/ufs-test.c b/tests/qtest/ufs-test.c
35
+# This program is free software; you can redistribute it and/or modify
36
+# it under the terms of the GNU General Public License as published by
37
+# the Free Software Foundation; either version 2 of the License, or
38
+# (at your option) any later version.
39
+#
40
+# This program is distributed in the hope that it will be useful,
41
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
42
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
43
+# GNU General Public License for more details.
44
+#
45
+# You should have received a copy of the GNU General Public License
46
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
47
+#
48
+
49
+# creator
50
+owner=mlevitsk@redhat.com
51
+
52
+seq=`basename $0`
53
+echo "QA output created by $seq"
54
+
55
+status=1    # failure is the default!
56
+
57
+_cleanup()
58
+{
59
+    _cleanup_test_img
60
+}
61
+trap "_cleanup; exit \$status" 0 1 2 3 15
62
+
63
+# get standard environment, filters and checks
64
+. ./common.rc
65
+. ./common.filter
66
+
67
+_supported_fmt qcow2 luks
68
+_supported_proto file #TODO
69
+
70
+QEMU_IO_OPTIONS=$QEMU_IO_OPTIONS_NO_FMT
71
+
72
+if [ "$IMGFMT" = "qcow2" ] ; then
73
+    PR="encrypt."
74
+    EXTRA_IMG_ARGS="-o encrypt.format=luks"
75
+fi
76
+
77
+
78
+# secrets: you are supposed to see the password as *******, see :-)
79
+S0="--object secret,id=sec0,data=hunter0"
80
+S1="--object secret,id=sec1,data=hunter1"
81
+S2="--object secret,id=sec2,data=hunter2"
82
+S3="--object secret,id=sec3,data=hunter3"
83
+S4="--object secret,id=sec4,data=hunter4"
84
+SECRETS="$S0 $S1 $S2 $S3 $S4"
85
+
86
+# image with given secret
87
+IMGS0="--image-opts driver=$IMGFMT,file.filename=$TEST_IMG,${PR}key-secret=sec0"
88
+IMGS1="--image-opts driver=$IMGFMT,file.filename=$TEST_IMG,${PR}key-secret=sec1"
89
+IMGS2="--image-opts driver=$IMGFMT,file.filename=$TEST_IMG,${PR}key-secret=sec2"
90
+IMGS3="--image-opts driver=$IMGFMT,file.filename=$TEST_IMG,${PR}key-secret=sec3"
91
+IMGS4="--image-opts driver=$IMGFMT,file.filename=$TEST_IMG,${PR}key-secret=sec4"
92
+
93
+
94
+echo "== creating a test image =="
95
+_make_test_img $S0 $EXTRA_IMG_ARGS -o ${PR}key-secret=sec0,${PR}iter-time=10 32M
96
+
97
+echo
98
+echo "== test that key 0 opens the image =="
99
+$QEMU_IO $S0 -c "read 0 4096" $IMGS0 | _filter_qemu_io | _filter_testdir
100
+
101
+echo
102
+echo "== adding a password to slot 4 =="
103
+$QEMU_IMG amend $SECRETS $IMGS0 -o ${PR}state=active,${PR}new-secret=sec4,${PR}iter-time=10,${PR}keyslot=4
104
+echo "== adding a password to slot 1 =="
105
+$QEMU_IMG amend $SECRETS $IMGS0 -o ${PR}state=active,${PR}new-secret=sec1,${PR}iter-time=10
106
+echo "== adding a password to slot 3 =="
107
+$QEMU_IMG amend $SECRETS $IMGS1 -o ${PR}state=active,${PR}new-secret=sec3,${PR}iter-time=10,${PR}keyslot=3
108
+
109
+echo "== adding a password to slot 2 =="
110
+$QEMU_IMG amend $SECRETS $IMGS3 -o ${PR}state=active,${PR}new-secret=sec2,${PR}iter-time=10
111
+
112
+
113
+echo "== erase slot 4 =="
114
+$QEMU_IMG amend $SECRETS $IMGS1 -o ${PR}state=inactive,${PR}keyslot=4 | _filter_img_create
115
+
116
+
117
+echo
118
+echo "== all secrets should work =="
119
+for IMG in "$IMGS0" "$IMGS1" "$IMGS2" "$IMGS3"; do
120
+    $QEMU_IO $SECRETS -c "read 0 4096" $IMG | _filter_qemu_io | _filter_testdir
121
+done
122
+
123
+echo
124
+echo "== erase slot 0 and try it =="
125
+$QEMU_IMG amend $SECRETS $IMGS1 -o ${PR}state=inactive,${PR}old-secret=sec0 | _filter_img_create
126
+$QEMU_IO $SECRETS -c "read 0 4096" $IMGS0 | _filter_qemu_io | _filter_testdir
127
+
128
+echo
129
+echo "== erase slot 2 and try it =="
130
+$QEMU_IMG amend $SECRETS $IMGS1 -o ${PR}state=inactive,${PR}keyslot=2 | _filter_img_create
131
+$QEMU_IO $SECRETS -c "read 0 4096" $IMGS2 | _filter_qemu_io | _filter_testdir
132
+
133
+
134
+# at this point slots 1 and 3 should be active
135
+
136
+echo
137
+echo "== filling 4 slots with secret 2 =="
138
+for i in $(seq 0 3) ; do
139
+    $QEMU_IMG amend $SECRETS $IMGS3 -o ${PR}state=active,${PR}new-secret=sec2,${PR}iter-time=10
140
+done
141
+
142
+echo
143
+echo "== adding secret 0 =="
144
+    $QEMU_IMG amend $SECRETS $IMGS3 -o ${PR}state=active,${PR}new-secret=sec0,${PR}iter-time=10
145
+
146
+echo
147
+echo "== adding secret 3 (last slot) =="
148
+    $QEMU_IMG amend $SECRETS $IMGS3 -o ${PR}state=active,${PR}new-secret=sec3,${PR}iter-time=10
149
+
150
+echo
151
+echo "== trying to add another slot (should fail) =="
152
+$QEMU_IMG amend $SECRETS $IMGS2 -o ${PR}state=active,${PR}new-secret=sec3,${PR}iter-time=10
153
+
154
+echo
155
+echo "== all secrets should work again =="
156
+for IMG in "$IMGS0" "$IMGS1" "$IMGS2" "$IMGS3"; do
157
+    $QEMU_IO $SECRETS -c "read 0 4096" $IMG | _filter_qemu_io | _filter_testdir
158
+done
159
+
160
+
161
+echo
162
+
163
+echo "== erase all keys of secret 2=="
164
+$QEMU_IMG amend $SECRETS $IMGS1 -o ${PR}state=inactive,${PR}old-secret=sec2
165
+
166
+echo "== erase all keys of secret 1=="
167
+$QEMU_IMG amend $SECRETS $IMGS1 -o ${PR}state=inactive,${PR}old-secret=sec1
168
+
169
+echo "== erase all keys of secret 0=="
170
+$QEMU_IMG amend $SECRETS $IMGS0 -o ${PR}state=inactive,${PR}old-secret=sec0
171
+
172
+echo "== erasing secret3 will fail now since it is the only secret (in 3 slots) =="
173
+$QEMU_IMG amend $SECRETS $IMGS3 -o ${PR}state=inactive,${PR}old-secret=sec3
174
+
175
+echo
176
+echo "== only secret3 should work now =="
177
+for IMG in "$IMGS0" "$IMGS1" "$IMGS2" "$IMGS3"; do
178
+    $QEMU_IO $SECRETS -c "read 0 4096" $IMG | _filter_qemu_io | _filter_testdir
179
+done
180
+
181
+echo
182
+echo "== add secret0 =="
183
+$QEMU_IMG amend $SECRETS $IMGS3 -o ${PR}state=active,${PR}new-secret=sec0,${PR}iter-time=10
184
+
185
+echo "== erase secret3 =="
186
+$QEMU_IMG amend $SECRETS $IMGS0 -o ${PR}state=inactive,${PR}old-secret=sec3
187
+
188
+echo
189
+echo "== only secret0 should work now =="
190
+for IMG in "$IMGS0" "$IMGS1" "$IMGS2" "$IMGS3"; do
191
+    $QEMU_IO $SECRETS -c "read 0 4096" $IMG | _filter_qemu_io | _filter_testdir
192
+done
193
+
194
+echo
195
+echo "== replace secret0 with secret1 (should fail) =="
196
+$QEMU_IMG amend $SECRETS $IMGS0 -o ${PR}state=active,${PR}new-secret=sec1,${PR}keyslot=0
197
+
198
+echo
199
+echo "== replace secret0 with secret1 with force (should work) =="
200
+$QEMU_IMG amend $SECRETS $IMGS0 -o ${PR}state=active,${PR}new-secret=sec1,${PR}iter-time=10,${PR}keyslot=0 --force
201
+
202
+echo
203
+echo "== only secret1 should work now =="
204
+for IMG in "$IMGS0" "$IMGS1" "$IMGS2" "$IMGS3"; do
205
+    $QEMU_IO $SECRETS -c "read 0 4096" $IMG | _filter_qemu_io | _filter_testdir
206
+done
207
+
208
+
209
+echo
210
+echo "== erase last secret (should fail) =="
211
+$QEMU_IMG amend $SECRETS $IMGS1 -o ${PR}state=inactive,${PR}keyslot=0
212
+$QEMU_IMG amend $SECRETS $IMGS1 -o ${PR}state=inactive,${PR}old-secret=sec1
213
+
214
+
215
+echo "== erase non existing secrets (should fail) =="
216
+$QEMU_IMG amend $SECRETS $IMGS1 -o ${PR}state=inactive,${PR}old-secret=sec5 --force
217
+$QEMU_IMG amend $SECRETS $IMGS1 -o ${PR}state=inactive,${PR}old-secret=sec0 --force
218
+$QEMU_IMG amend $SECRETS $IMGS1 -o ${PR}state=inactive,${PR}keyslot=1 --force
219
+
220
+echo
221
+echo "== erase last secret with force by slot (should work) =="
222
+$QEMU_IMG amend $SECRETS $IMGS1 -o ${PR}state=inactive,${PR}keyslot=0 --force
223
+
224
+echo
225
+echo "== we have no secrets now, data is lost forever =="
226
+for IMG in "$IMGS0" "$IMGS1" "$IMGS2" "$IMGS3"; do
227
+    $QEMU_IO $SECRETS -c "read 0 4096" $IMG | _filter_qemu_io | _filter_testdir
228
+done
229
+
230
+# success, all done
231
+echo "*** done"
232
+rm -f $seq.full
233
+status=0
234
+
235
diff --git a/tests/qemu-iotests/293.out b/tests/qemu-iotests/293.out
236
new file mode 100644
33
new file mode 100644
237
index XXXXXXX..XXXXXXX
34
index XXXXXXX..XXXXXXX
238
--- /dev/null
35
--- /dev/null
239
+++ b/tests/qemu-iotests/293.out
36
+++ b/tests/qtest/ufs-test.c
240
@@ -XXX,XX +XXX,XX @@
37
@@ -XXX,XX +XXX,XX @@
241
+QA output created by 293
38
+/*
242
+== creating a test image ==
39
+ * QTest testcase for UFS
243
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33554432
40
+ *
244
+
41
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd. All rights reserved.
245
+== test that key 0 opens the image ==
42
+ *
246
+read 4096/4096 bytes at offset 0
43
+ * SPDX-License-Identifier: GPL-2.0-or-later
247
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
44
+ */
248
+
45
+
249
+== adding a password to slot 4 ==
46
+#include "qemu/osdep.h"
250
+== adding a password to slot 1 ==
47
+#include "qemu/module.h"
251
+== adding a password to slot 3 ==
48
+#include "qemu/units.h"
252
+== adding a password to slot 2 ==
49
+#include "libqtest.h"
253
+== erase slot 4 ==
50
+#include "libqos/qgraph.h"
254
+
51
+#include "libqos/pci.h"
255
+== all secrets should work ==
52
+#include "scsi/constants.h"
256
+read 4096/4096 bytes at offset 0
53
+#include "include/block/ufs.h"
257
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
54
+
258
+read 4096/4096 bytes at offset 0
55
+/* Test images sizes in Bytes */
259
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
56
+#define TEST_IMAGE_SIZE (64 * 1024 * 1024)
260
+read 4096/4096 bytes at offset 0
57
+/* Timeout for various operations, in seconds. */
261
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
58
+#define TIMEOUT_SECONDS 10
262
+read 4096/4096 bytes at offset 0
59
+/* Maximum PRD entry count */
263
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
60
+#define MAX_PRD_ENTRY_COUNT 10
264
+
61
+#define PRD_ENTRY_DATA_SIZE 4096
265
+== erase slot 0 and try it ==
62
+/* Constants to build upiu */
266
+qemu-io: can't open: Invalid password, cannot unlock any keyslot
63
+#define UTP_COMMAND_DESCRIPTOR_SIZE 4096
267
+
64
+#define UTP_RESPONSE_UPIU_OFFSET 1024
268
+== erase slot 2 and try it ==
65
+#define UTP_PRDT_UPIU_OFFSET 2048
269
+qemu-io: can't open: Invalid password, cannot unlock any keyslot
66
+
270
+
67
+typedef struct QUfs QUfs;
271
+== filling 4 slots with secret 2 ==
68
+
272
+
69
+struct QUfs {
273
+== adding secret 0 ==
70
+ QOSGraphObject obj;
274
+
71
+ QPCIDevice dev;
275
+== adding secret 3 (last slot) ==
72
+ QPCIBar bar;
276
+
73
+
277
+== trying to add another slot (should fail) ==
74
+ uint64_t utrlba;
278
+qemu-img: Can't add a keyslot - all keyslots are in use
75
+ uint64_t utmrlba;
279
+
76
+ uint64_t cmd_desc_addr;
280
+== all secrets should work again ==
77
+ uint64_t data_buffer_addr;
281
+read 4096/4096 bytes at offset 0
78
+
282
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
79
+ bool enabled;
283
+read 4096/4096 bytes at offset 0
80
+};
284
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
81
+
285
+read 4096/4096 bytes at offset 0
82
+static inline uint32_t ufs_rreg(QUfs *ufs, size_t offset)
286
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
83
+{
287
+read 4096/4096 bytes at offset 0
84
+ return qpci_io_readl(&ufs->dev, ufs->bar, offset);
288
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
85
+}
289
+
86
+
290
+== erase all keys of secret 2==
87
+static inline void ufs_wreg(QUfs *ufs, size_t offset, uint32_t value)
291
+== erase all keys of secret 1==
88
+{
292
+== erase all keys of secret 0==
89
+ qpci_io_writel(&ufs->dev, ufs->bar, offset, value);
293
+== erasing secret3 will fail now since it is the only secret (in 3 slots) ==
90
+}
294
+qemu-img: All the active keyslots match the (old) password that was given and erasing them will erase all the data in the image irreversibly - refusing operation
91
+
295
+
92
+static void ufs_wait_for_irq(QUfs *ufs)
296
+== only secret3 should work now ==
93
+{
297
+qemu-io: can't open: Invalid password, cannot unlock any keyslot
94
+ uint64_t end_time;
298
+qemu-io: can't open: Invalid password, cannot unlock any keyslot
95
+ uint32_t is;
299
+qemu-io: can't open: Invalid password, cannot unlock any keyslot
96
+ /* Wait for device to reset as the linux driver does. */
300
+read 4096/4096 bytes at offset 0
97
+ end_time = g_get_monotonic_time() + TIMEOUT_SECONDS * G_TIME_SPAN_SECOND;
301
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
98
+ do {
302
+
99
+ qtest_clock_step(ufs->dev.bus->qts, 100);
303
+== add secret0 ==
100
+ is = ufs_rreg(ufs, A_IS);
304
+== erase secret3 ==
101
+ } while (is == 0 && g_get_monotonic_time() < end_time);
305
+
102
+}
306
+== only secret0 should work now ==
103
+
307
+read 4096/4096 bytes at offset 0
104
+static UtpTransferReqDesc ufs_build_req_utrd(uint64_t cmd_desc_addr,
308
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
105
+ uint8_t slot,
309
+qemu-io: can't open: Invalid password, cannot unlock any keyslot
106
+ uint32_t data_direction,
310
+qemu-io: can't open: Invalid password, cannot unlock any keyslot
107
+ uint16_t prd_table_length)
311
+qemu-io: can't open: Invalid password, cannot unlock any keyslot
108
+{
312
+
109
+ UtpTransferReqDesc req = { 0 };
313
+== replace secret0 with secret1 (should fail) ==
110
+ uint64_t command_desc_base_addr =
314
+qemu-img: Refusing to overwrite active keyslot 0 - please erase it first
111
+ cmd_desc_addr + slot * UTP_COMMAND_DESCRIPTOR_SIZE;
315
+
112
+
316
+== replace secret0 with secret1 with force (should work) ==
113
+ req.header.dword_0 =
317
+
114
+ cpu_to_le32(1 << 28 | data_direction | UTP_REQ_DESC_INT_CMD);
318
+== only secret1 should work now ==
115
+ req.header.dword_2 = cpu_to_le32(OCS_INVALID_COMMAND_STATUS);
319
+qemu-io: can't open: Invalid password, cannot unlock any keyslot
116
+
320
+read 4096/4096 bytes at offset 0
117
+ req.command_desc_base_addr_hi = cpu_to_le32(command_desc_base_addr >> 32);
321
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
118
+ req.command_desc_base_addr_lo =
322
+qemu-io: can't open: Invalid password, cannot unlock any keyslot
119
+ cpu_to_le32(command_desc_base_addr & 0xffffffff);
323
+qemu-io: can't open: Invalid password, cannot unlock any keyslot
120
+ req.response_upiu_offset =
324
+
121
+ cpu_to_le16(UTP_RESPONSE_UPIU_OFFSET / sizeof(uint32_t));
325
+== erase last secret (should fail) ==
122
+ req.response_upiu_length = cpu_to_le16(sizeof(UtpUpiuRsp));
326
+qemu-img: Attempt to erase the only active keyslot 0 which will erase all the data in the image irreversibly - refusing operation
123
+ req.prd_table_offset = cpu_to_le16(UTP_PRDT_UPIU_OFFSET / sizeof(uint32_t));
327
+qemu-img: All the active keyslots match the (old) password that was given and erasing them will erase all the data in the image irreversibly - refusing operation
124
+ req.prd_table_length = cpu_to_le16(prd_table_length);
328
+== erase non existing secrets (should fail) ==
125
+ return req;
329
+qemu-img: No secret with id 'sec5'
126
+}
330
+qemu-img: No keyslots match given (old) password for erase operation
127
+
331
+
128
+static void ufs_send_nop_out(QUfs *ufs, uint8_t slot,
332
+== erase last secret with force by slot (should work) ==
129
+ UtpTransferReqDesc *utrd_out, UtpUpiuRsp *rsp_out)
333
+
130
+{
334
+== we have no secrets now, data is lost forever ==
131
+ /* Build up utp transfer request descriptor */
335
+qemu-io: can't open: Invalid password, cannot unlock any keyslot
132
+ UtpTransferReqDesc utrd =
336
+qemu-io: can't open: Invalid password, cannot unlock any keyslot
133
+ ufs_build_req_utrd(ufs->cmd_desc_addr, slot, UTP_NO_DATA_TRANSFER, 0);
337
+qemu-io: can't open: Invalid password, cannot unlock any keyslot
134
+ uint64_t utrd_addr = ufs->utrlba + slot * sizeof(UtpTransferReqDesc);
338
+qemu-io: can't open: Invalid password, cannot unlock any keyslot
135
+ uint64_t req_upiu_addr =
339
+*** done
136
+ ufs->cmd_desc_addr + slot * UTP_COMMAND_DESCRIPTOR_SIZE;
340
diff --git a/tests/qemu-iotests/294 b/tests/qemu-iotests/294
137
+ uint64_t rsp_upiu_addr = req_upiu_addr + UTP_RESPONSE_UPIU_OFFSET;
341
new file mode 100755
138
+ qtest_memwrite(ufs->dev.bus->qts, utrd_addr, &utrd, sizeof(utrd));
342
index XXXXXXX..XXXXXXX
139
+
343
--- /dev/null
140
+ /* Build up request upiu */
344
+++ b/tests/qemu-iotests/294
141
+ UtpUpiuReq req_upiu = { 0 };
345
@@ -XXX,XX +XXX,XX @@
142
+ req_upiu.header.trans_type = UPIU_TRANSACTION_NOP_OUT;
346
+#
143
+ req_upiu.header.task_tag = slot;
347
+# Copyright (C) 2019 Red Hat, Inc.
144
+ qtest_memwrite(ufs->dev.bus->qts, req_upiu_addr, &req_upiu,
348
+#
145
+ sizeof(req_upiu));
349
+# This program is free software; you can redistribute it and/or modify
146
+
350
+# it under the terms of the GNU General Public License as published by
147
+ /* Ring Doorbell */
351
+# the Free Software Foundation; either version 2 of the License, or
148
+ ufs_wreg(ufs, A_UTRLDBR, 1);
352
+# (at your option) any later version.
149
+ ufs_wait_for_irq(ufs);
353
+#
150
+ g_assert_true(FIELD_EX32(ufs_rreg(ufs, A_IS), IS, UTRCS));
354
+# This program is distributed in the hope that it will be useful,
151
+ ufs_wreg(ufs, A_IS, FIELD_DP32(0, IS, UTRCS, 1));
355
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
152
+
356
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
153
+ qtest_memread(ufs->dev.bus->qts, utrd_addr, utrd_out, sizeof(*utrd_out));
357
+# GNU General Public License for more details.
154
+ qtest_memread(ufs->dev.bus->qts, rsp_upiu_addr, rsp_out, sizeof(*rsp_out));
358
+#
155
+}
359
+# You should have received a copy of the GNU General Public License
156
+
360
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
157
+static void ufs_send_query(QUfs *ufs, uint8_t slot, uint8_t query_function,
361
+#
158
+ uint8_t query_opcode, uint8_t idn, uint8_t index,
362
+
159
+ UtpTransferReqDesc *utrd_out, UtpUpiuRsp *rsp_out)
363
+# creator
160
+{
364
+owner=mlevitsk@redhat.com
161
+ /* Build up utp transfer request descriptor */
365
+
162
+ UtpTransferReqDesc utrd =
366
+seq=`basename $0`
163
+ ufs_build_req_utrd(ufs->cmd_desc_addr, slot, UTP_NO_DATA_TRANSFER, 0);
367
+echo "QA output created by $seq"
164
+ uint64_t utrd_addr = ufs->utrlba + slot * sizeof(UtpTransferReqDesc);
368
+
165
+ uint64_t req_upiu_addr =
369
+status=1    # failure is the default!
166
+ ufs->cmd_desc_addr + slot * UTP_COMMAND_DESCRIPTOR_SIZE;
370
+
167
+ uint64_t rsp_upiu_addr = req_upiu_addr + UTP_RESPONSE_UPIU_OFFSET;
371
+_cleanup()
168
+ qtest_memwrite(ufs->dev.bus->qts, utrd_addr, &utrd, sizeof(utrd));
372
+{
169
+
373
+    _cleanup_test_img
170
+ /* Build up request upiu */
374
+}
171
+ UtpUpiuReq req_upiu = { 0 };
375
+trap "_cleanup; exit \$status" 0 1 2 3 15
172
+ req_upiu.header.trans_type = UPIU_TRANSACTION_QUERY_REQ;
376
+
173
+ req_upiu.header.query_func = query_function;
377
+# get standard environment, filters and checks
174
+ req_upiu.header.task_tag = slot;
378
+. ./common.rc
175
+ /*
379
+. ./common.filter
176
+ * QEMU UFS does not currently support Write descriptor and Write attribute,
380
+
177
+ * so the value of data_segment_length is always 0.
381
+_supported_fmt luks
178
+ */
382
+_supported_proto file #TODO
179
+ req_upiu.header.data_segment_length = 0;
383
+
180
+ req_upiu.qr.opcode = query_opcode;
384
+QEMU_IO_OPTIONS=$QEMU_IO_OPTIONS_NO_FMT
181
+ req_upiu.qr.idn = idn;
385
+
182
+ req_upiu.qr.index = index;
386
+# you are supposed to see the password as *******, see :-)
183
+ qtest_memwrite(ufs->dev.bus->qts, req_upiu_addr, &req_upiu,
387
+S0="--object secret,id=sec0,data=hunter0"
184
+ sizeof(req_upiu));
388
+S1="--object secret,id=sec1,data=hunter1"
185
+
389
+SECRETS="$S0 $S1"
186
+ /* Ring Doorbell */
390
+
187
+ ufs_wreg(ufs, A_UTRLDBR, 1);
391
+
188
+ ufs_wait_for_irq(ufs);
392
+IMGS0="--image-opts driver=$IMGFMT,file.filename=$TEST_IMG,key-secret=sec0"
189
+ g_assert_true(FIELD_EX32(ufs_rreg(ufs, A_IS), IS, UTRCS));
393
+IMGS1="--image-opts driver=$IMGFMT,file.filename=$TEST_IMG,key-secret=sec1"
190
+ ufs_wreg(ufs, A_IS, FIELD_DP32(0, IS, UTRCS, 1));
394
+
191
+
395
+echo "== creating a test image =="
192
+ qtest_memread(ufs->dev.bus->qts, utrd_addr, utrd_out, sizeof(*utrd_out));
396
+_make_test_img $S0 -o "key-secret=sec0,iter-time=10" 32M
193
+ qtest_memread(ufs->dev.bus->qts, rsp_upiu_addr, rsp_out, sizeof(*rsp_out));
397
+
194
+}
398
+echo
195
+
399
+echo "== test that key 0 opens the image =="
196
+static void ufs_send_scsi_command(QUfs *ufs, uint8_t slot, uint8_t lun,
400
+$QEMU_IO $S0 -c "read 0 4096" $IMGS0 | _filter_qemu_io | _filter_testdir
197
+ const uint8_t *cdb, const uint8_t *data_in,
401
+
198
+ size_t data_in_len, uint8_t *data_out,
402
+echo
199
+ size_t data_out_len,
403
+echo "== adding a password to slot 1 =="
200
+ UtpTransferReqDesc *utrd_out,
404
+$QEMU_IMG amend $SECRETS $IMGS0 -o state=active,new-secret=sec1,keyslot=1,iter-time=10
201
+ UtpUpiuRsp *rsp_out)
405
+
202
+
406
+echo
203
+{
407
+echo "== 'backup' the image header =="
204
+ /* Build up PRDT */
408
+dd if=$TEST_IMG_FILE of=${TEST_IMG_FILE}.bk bs=4K skip=0 count=1
205
+ UfshcdSgEntry entries[MAX_PRD_ENTRY_COUNT] = {
409
+
206
+ 0,
410
+echo
207
+ };
411
+echo "== erase slot 0 =="
208
+ uint8_t flags;
412
+$QEMU_IMG amend $SECRETS $IMGS1 -o state=inactive,keyslot=0 | _filter_img_create
209
+ uint16_t prd_table_length, i;
413
+
210
+ uint32_t data_direction, data_len;
414
+echo
211
+ uint64_t req_upiu_addr =
415
+echo "== test that key 0 doesn't open the image =="
212
+ ufs->cmd_desc_addr + slot * UTP_COMMAND_DESCRIPTOR_SIZE;
416
+$QEMU_IO $S0 -c "read 0 4096" $IMGS0 | _filter_qemu_io | _filter_testdir
213
+ uint64_t prdt_addr = req_upiu_addr + UTP_PRDT_UPIU_OFFSET;
417
+
214
+
418
+echo
215
+ g_assert_true(data_in_len < MAX_PRD_ENTRY_COUNT * PRD_ENTRY_DATA_SIZE);
419
+echo "== 'restore' the image header =="
216
+ g_assert_true(data_out_len < MAX_PRD_ENTRY_COUNT * PRD_ENTRY_DATA_SIZE);
420
+dd if=${TEST_IMG_FILE}.bk of=${TEST_IMG_FILE} bs=4K skip=0 count=1 conv=notrunc
217
+ if (data_in_len > 0) {
421
+
218
+ g_assert_nonnull(data_in);
422
+echo
219
+ data_direction = UTP_HOST_TO_DEVICE;
423
+echo "== test that key 0 still doesn't open the image (key material is erased) =="
220
+ data_len = data_in_len;
424
+$QEMU_IO $SECRETS -c "read 0 4096" $IMGS0 | _filter_qemu_io | _filter_testdir
221
+ flags = UPIU_CMD_FLAGS_WRITE;
425
+
222
+ } else if (data_out_len > 0) {
426
+echo
223
+ g_assert_nonnull(data_out);
427
+echo "== test that key 1 still works =="
224
+ data_direction = UTP_DEVICE_TO_HOST;
428
+$QEMU_IO $SECRETS -c "read 0 4096" $IMGS1 | _filter_qemu_io | _filter_testdir
225
+ data_len = data_out_len;
429
+
226
+ flags = UPIU_CMD_FLAGS_READ;
430
+echo "*** done"
227
+ } else {
431
+rm -f $seq.full
228
+ data_direction = UTP_NO_DATA_TRANSFER;
432
+status=0
229
+ data_len = 0;
433
+
230
+ flags = UPIU_CMD_FLAGS_NONE;
434
+
231
+ }
435
+exit 0
232
+ prd_table_length = DIV_ROUND_UP(data_len, PRD_ENTRY_DATA_SIZE);
436
diff --git a/tests/qemu-iotests/294.out b/tests/qemu-iotests/294.out
233
+
437
new file mode 100644
234
+ qtest_memset(ufs->dev.bus->qts, ufs->data_buffer_addr, 0,
438
index XXXXXXX..XXXXXXX
235
+ MAX_PRD_ENTRY_COUNT * PRD_ENTRY_DATA_SIZE);
439
--- /dev/null
236
+ if (data_in_len) {
440
+++ b/tests/qemu-iotests/294.out
237
+ qtest_memwrite(ufs->dev.bus->qts, ufs->data_buffer_addr, data_in,
441
@@ -XXX,XX +XXX,XX @@
238
+ data_in_len);
442
+QA output created by 294
239
+ }
443
+== creating a test image ==
240
+
444
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33554432
241
+ for (i = 0; i < prd_table_length; i++) {
445
+
242
+ entries[i].addr =
446
+== test that key 0 opens the image ==
243
+ cpu_to_le64(ufs->data_buffer_addr + i * sizeof(UfshcdSgEntry));
447
+read 4096/4096 bytes at offset 0
244
+ if (i + 1 != prd_table_length) {
448
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
245
+ entries[i].size = cpu_to_le32(PRD_ENTRY_DATA_SIZE - 1);
449
+
246
+ } else {
450
+== adding a password to slot 1 ==
247
+ entries[i].size = cpu_to_le32(
451
+
248
+ data_len - (PRD_ENTRY_DATA_SIZE * (prd_table_length - 1)) - 1);
452
+== 'backup' the image header ==
249
+ }
453
+1+0 records in
250
+ }
454
+1+0 records out
251
+ qtest_memwrite(ufs->dev.bus->qts, prdt_addr, entries,
455
+
252
+ prd_table_length * sizeof(UfshcdSgEntry));
456
+== erase slot 0 ==
253
+
457
+
254
+ /* Build up utp transfer request descriptor */
458
+== test that key 0 doesn't open the image ==
255
+ UtpTransferReqDesc utrd = ufs_build_req_utrd(
459
+qemu-io: can't open: Invalid password, cannot unlock any keyslot
256
+ ufs->cmd_desc_addr, slot, data_direction, prd_table_length);
460
+
257
+ uint64_t utrd_addr = ufs->utrlba + slot * sizeof(UtpTransferReqDesc);
461
+== 'restore' the image header ==
258
+ uint64_t rsp_upiu_addr = req_upiu_addr + UTP_RESPONSE_UPIU_OFFSET;
462
+1+0 records in
259
+ qtest_memwrite(ufs->dev.bus->qts, utrd_addr, &utrd, sizeof(utrd));
463
+1+0 records out
260
+
464
+
261
+ /* Build up request upiu */
465
+== test that key 0 still doesn't open the image (key material is erased) ==
262
+ UtpUpiuReq req_upiu = { 0 };
466
+qemu-io: can't open: Invalid password, cannot unlock any keyslot
263
+ req_upiu.header.trans_type = UPIU_TRANSACTION_COMMAND;
467
+
264
+ req_upiu.header.flags = flags;
468
+== test that key 1 still works ==
265
+ req_upiu.header.lun = lun;
469
+read 4096/4096 bytes at offset 0
266
+ req_upiu.header.task_tag = slot;
470
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
267
+ req_upiu.sc.exp_data_transfer_len = cpu_to_be32(data_len);
471
+*** done
268
+ memcpy(req_upiu.sc.cdb, cdb, UFS_CDB_SIZE);
472
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
269
+ qtest_memwrite(ufs->dev.bus->qts, req_upiu_addr, &req_upiu,
270
+ sizeof(req_upiu));
271
+
272
+ /* Ring Doorbell */
273
+ ufs_wreg(ufs, A_UTRLDBR, 1);
274
+ ufs_wait_for_irq(ufs);
275
+ g_assert_true(FIELD_EX32(ufs_rreg(ufs, A_IS), IS, UTRCS));
276
+ ufs_wreg(ufs, A_IS, FIELD_DP32(0, IS, UTRCS, 1));
277
+
278
+ qtest_memread(ufs->dev.bus->qts, utrd_addr, utrd_out, sizeof(*utrd_out));
279
+ qtest_memread(ufs->dev.bus->qts, rsp_upiu_addr, rsp_out, sizeof(*rsp_out));
280
+ if (data_out_len) {
281
+ qtest_memread(ufs->dev.bus->qts, ufs->data_buffer_addr, data_out,
282
+ data_out_len);
283
+ }
284
+}
285
+
286
+/**
287
+ * Initialize Ufs host controller and logical unit.
288
+ * After running this function, you can make a transfer request to the UFS.
289
+ */
290
+static void ufs_init(QUfs *ufs, QGuestAllocator *alloc)
291
+{
292
+ uint64_t end_time;
293
+ uint32_t nutrs, nutmrs;
294
+ uint32_t hcs, is, ucmdarg2, cap;
295
+ uint32_t hce = 0, ie = 0;
296
+ UtpTransferReqDesc utrd;
297
+ UtpUpiuRsp rsp_upiu;
298
+
299
+ ufs->bar = qpci_iomap(&ufs->dev, 0, NULL);
300
+ qpci_device_enable(&ufs->dev);
301
+
302
+ /* Start host controller initialization */
303
+ hce = FIELD_DP32(hce, HCE, HCE, 1);
304
+ ufs_wreg(ufs, A_HCE, hce);
305
+
306
+ /* Wait for device to reset */
307
+ end_time = g_get_monotonic_time() + TIMEOUT_SECONDS * G_TIME_SPAN_SECOND;
308
+ do {
309
+ qtest_clock_step(ufs->dev.bus->qts, 100);
310
+ hce = FIELD_EX32(ufs_rreg(ufs, A_HCE), HCE, HCE);
311
+ } while (hce == 0 && g_get_monotonic_time() < end_time);
312
+ g_assert_cmpuint(hce, ==, 1);
313
+
314
+ /* Enable interrupt */
315
+ ie = FIELD_DP32(ie, IE, UCCE, 1);
316
+ ie = FIELD_DP32(ie, IE, UHESE, 1);
317
+ ie = FIELD_DP32(ie, IE, UHXSE, 1);
318
+ ie = FIELD_DP32(ie, IE, UPMSE, 1);
319
+ ufs_wreg(ufs, A_IE, ie);
320
+
321
+ /* Send DME_LINK_STARTUP uic command */
322
+ hcs = ufs_rreg(ufs, A_HCS);
323
+ g_assert_true(FIELD_EX32(hcs, HCS, UCRDY));
324
+
325
+ ufs_wreg(ufs, A_UCMDARG1, 0);
326
+ ufs_wreg(ufs, A_UCMDARG2, 0);
327
+ ufs_wreg(ufs, A_UCMDARG3, 0);
328
+ ufs_wreg(ufs, A_UICCMD, UIC_CMD_DME_LINK_STARTUP);
329
+
330
+ is = ufs_rreg(ufs, A_IS);
331
+ g_assert_true(FIELD_EX32(is, IS, UCCS));
332
+ ufs_wreg(ufs, A_IS, FIELD_DP32(0, IS, UCCS, 1));
333
+
334
+ ucmdarg2 = ufs_rreg(ufs, A_UCMDARG2);
335
+ g_assert_cmpuint(ucmdarg2, ==, 0);
336
+ is = ufs_rreg(ufs, A_IS);
337
+ g_assert_cmpuint(is, ==, 0);
338
+ hcs = ufs_rreg(ufs, A_HCS);
339
+ g_assert_true(FIELD_EX32(hcs, HCS, DP));
340
+ g_assert_true(FIELD_EX32(hcs, HCS, UTRLRDY));
341
+ g_assert_true(FIELD_EX32(hcs, HCS, UTMRLRDY));
342
+ g_assert_true(FIELD_EX32(hcs, HCS, UCRDY));
343
+
344
+ /* Enable all interrupt functions */
345
+ ie = FIELD_DP32(ie, IE, UTRCE, 1);
346
+ ie = FIELD_DP32(ie, IE, UEE, 1);
347
+ ie = FIELD_DP32(ie, IE, UPMSE, 1);
348
+ ie = FIELD_DP32(ie, IE, UHXSE, 1);
349
+ ie = FIELD_DP32(ie, IE, UHESE, 1);
350
+ ie = FIELD_DP32(ie, IE, UTMRCE, 1);
351
+ ie = FIELD_DP32(ie, IE, UCCE, 1);
352
+ ie = FIELD_DP32(ie, IE, DFEE, 1);
353
+ ie = FIELD_DP32(ie, IE, HCFEE, 1);
354
+ ie = FIELD_DP32(ie, IE, SBFEE, 1);
355
+ ie = FIELD_DP32(ie, IE, CEFEE, 1);
356
+ ufs_wreg(ufs, A_IE, ie);
357
+ ufs_wreg(ufs, A_UTRIACR, 0);
358
+
359
+ /* Enable tranfer request and task management request */
360
+ cap = ufs_rreg(ufs, A_CAP);
361
+ nutrs = FIELD_EX32(cap, CAP, NUTRS) + 1;
362
+ nutmrs = FIELD_EX32(cap, CAP, NUTMRS) + 1;
363
+ ufs->cmd_desc_addr =
364
+ guest_alloc(alloc, nutrs * UTP_COMMAND_DESCRIPTOR_SIZE);
365
+ ufs->data_buffer_addr =
366
+ guest_alloc(alloc, MAX_PRD_ENTRY_COUNT * PRD_ENTRY_DATA_SIZE);
367
+ ufs->utrlba = guest_alloc(alloc, nutrs * sizeof(UtpTransferReqDesc));
368
+ ufs->utmrlba = guest_alloc(alloc, nutmrs * sizeof(UtpTaskReqDesc));
369
+
370
+ ufs_wreg(ufs, A_UTRLBA, ufs->utrlba & 0xffffffff);
371
+ ufs_wreg(ufs, A_UTRLBAU, ufs->utrlba >> 32);
372
+ ufs_wreg(ufs, A_UTMRLBA, ufs->utmrlba & 0xffffffff);
373
+ ufs_wreg(ufs, A_UTMRLBAU, ufs->utmrlba >> 32);
374
+ ufs_wreg(ufs, A_UTRLRSR, 1);
375
+ ufs_wreg(ufs, A_UTMRLRSR, 1);
376
+
377
+ /* Send nop out to test transfer request */
378
+ ufs_send_nop_out(ufs, 0, &utrd, &rsp_upiu);
379
+ g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, OCS_SUCCESS);
380
+
381
+ /* Set fDeviceInit flag via query request */
382
+ ufs_send_query(ufs, 0, UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST,
383
+ UPIU_QUERY_OPCODE_SET_FLAG, QUERY_FLAG_IDN_FDEVICEINIT, 0,
384
+ &utrd, &rsp_upiu);
385
+ g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, OCS_SUCCESS);
386
+
387
+ /* Wait for device to reset */
388
+ end_time = g_get_monotonic_time() + TIMEOUT_SECONDS * G_TIME_SPAN_SECOND;
389
+ do {
390
+ qtest_clock_step(ufs->dev.bus->qts, 100);
391
+ ufs_send_query(ufs, 0, UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
392
+ UPIU_QUERY_OPCODE_READ_FLAG, QUERY_FLAG_IDN_FDEVICEINIT,
393
+ 0, &utrd, &rsp_upiu);
394
+ } while (be32_to_cpu(rsp_upiu.qr.value) != 0 &&
395
+ g_get_monotonic_time() < end_time);
396
+ g_assert_cmpuint(be32_to_cpu(rsp_upiu.qr.value), ==, 0);
397
+
398
+ ufs->enabled = true;
399
+}
400
+
401
+static void ufs_exit(QUfs *ufs, QGuestAllocator *alloc)
402
+{
403
+ if (ufs->enabled) {
404
+ guest_free(alloc, ufs->utrlba);
405
+ guest_free(alloc, ufs->utmrlba);
406
+ guest_free(alloc, ufs->cmd_desc_addr);
407
+ guest_free(alloc, ufs->data_buffer_addr);
408
+ }
409
+
410
+ qpci_iounmap(&ufs->dev, ufs->bar);
411
+}
412
+
413
+static void *ufs_get_driver(void *obj, const char *interface)
414
+{
415
+ QUfs *ufs = obj;
416
+
417
+ if (!g_strcmp0(interface, "pci-device")) {
418
+ return &ufs->dev;
419
+ }
420
+
421
+ fprintf(stderr, "%s not present in ufs\n", interface);
422
+ g_assert_not_reached();
423
+}
424
+
425
+static void *ufs_create(void *pci_bus, QGuestAllocator *alloc, void *addr)
426
+{
427
+ QUfs *ufs = g_new0(QUfs, 1);
428
+ QPCIBus *bus = pci_bus;
429
+
430
+ qpci_device_init(&ufs->dev, bus, addr);
431
+ ufs->obj.get_driver = ufs_get_driver;
432
+
433
+ return &ufs->obj;
434
+}
435
+
436
+static void ufstest_reg_read(void *obj, void *data, QGuestAllocator *alloc)
437
+{
438
+ QUfs *ufs = obj;
439
+ uint32_t cap;
440
+
441
+ ufs->bar = qpci_iomap(&ufs->dev, 0, NULL);
442
+ qpci_device_enable(&ufs->dev);
443
+
444
+ cap = ufs_rreg(ufs, A_CAP);
445
+ g_assert_cmpuint(FIELD_EX32(cap, CAP, NUTRS), ==, 31);
446
+ g_assert_cmpuint(FIELD_EX32(cap, CAP, NUTMRS), ==, 7);
447
+ g_assert_cmpuint(FIELD_EX32(cap, CAP, 64AS), ==, 1);
448
+
449
+ qpci_iounmap(&ufs->dev, ufs->bar);
450
+}
451
+
452
+static void ufstest_init(void *obj, void *data, QGuestAllocator *alloc)
453
+{
454
+ QUfs *ufs = obj;
455
+
456
+ uint8_t buf[4096] = { 0 };
457
+ const uint8_t report_luns_cdb[UFS_CDB_SIZE] = {
458
+ /* allocation length 4096 */
459
+ REPORT_LUNS, 0x00, 0x00, 0x00, 0x00, 0x00,
460
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00
461
+ };
462
+ const uint8_t test_unit_ready_cdb[UFS_CDB_SIZE] = {
463
+ TEST_UNIT_READY,
464
+ };
465
+ UtpTransferReqDesc utrd;
466
+ UtpUpiuRsp rsp_upiu;
467
+
468
+ ufs_init(ufs, alloc);
469
+
470
+ /* Check REPORT_LUNS */
471
+ ufs_send_scsi_command(ufs, 0, 0, report_luns_cdb, NULL, 0, buf, sizeof(buf),
472
+ &utrd, &rsp_upiu);
473
+ g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, OCS_SUCCESS);
474
+ g_assert_cmpuint(rsp_upiu.header.scsi_status, ==, GOOD);
475
+ /* LUN LIST LENGTH should be 8, in big endian */
476
+ g_assert_cmpuint(buf[3], ==, 8);
477
+ /* There is one logical unit whose lun is 0 */
478
+ g_assert_cmpuint(buf[9], ==, 0);
479
+
480
+ /* Check TEST_UNIT_READY */
481
+ ufs_send_scsi_command(ufs, 0, 0, test_unit_ready_cdb, NULL, 0, NULL, 0,
482
+ &utrd, &rsp_upiu);
483
+ g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, OCS_SUCCESS);
484
+ g_assert_cmpuint(rsp_upiu.header.scsi_status, ==, GOOD);
485
+
486
+ ufs_exit(ufs, alloc);
487
+}
488
+
489
+static void ufstest_read_write(void *obj, void *data, QGuestAllocator *alloc)
490
+{
491
+ QUfs *ufs = obj;
492
+ uint8_t read_buf[4096] = { 0 };
493
+ uint8_t write_buf[4096] = { 0 };
494
+ const uint8_t read_capacity_cdb[UFS_CDB_SIZE] = {
495
+ /* allocation length 4096 */
496
+ SERVICE_ACTION_IN_16,
497
+ SAI_READ_CAPACITY_16,
498
+ 0x00,
499
+ 0x00,
500
+ 0x00,
501
+ 0x00,
502
+ 0x00,
503
+ 0x00,
504
+ 0x00,
505
+ 0x00,
506
+ 0x00,
507
+ 0x00,
508
+ 0x10,
509
+ 0x00,
510
+ 0x00,
511
+ 0x00
512
+ };
513
+ const uint8_t read_cdb[UFS_CDB_SIZE] = {
514
+ /* READ(10) to LBA 0, transfer length 1 */
515
+ READ_10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00
516
+ };
517
+ const uint8_t write_cdb[UFS_CDB_SIZE] = {
518
+ /* WRITE(10) to LBA 0, transfer length 1 */
519
+ WRITE_10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00
520
+ };
521
+ uint32_t block_size;
522
+ UtpTransferReqDesc utrd;
523
+ UtpUpiuRsp rsp_upiu;
524
+
525
+ ufs_init(ufs, alloc);
526
+
527
+ /* Read capacity */
528
+ ufs_send_scsi_command(ufs, 0, 1, read_capacity_cdb, NULL, 0, read_buf,
529
+ sizeof(read_buf), &utrd, &rsp_upiu);
530
+ g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, OCS_SUCCESS);
531
+ g_assert_cmpuint(rsp_upiu.header.scsi_status, ==, COMMAND_RESULT_SUCESS);
532
+ block_size = ldl_be_p(&read_buf[8]);
533
+ g_assert_cmpuint(block_size, ==, 4096);
534
+
535
+ /* Write data */
536
+ memset(write_buf, rand() % 255 + 1, block_size);
537
+ ufs_send_scsi_command(ufs, 0, 1, write_cdb, write_buf, block_size, NULL, 0,
538
+ &utrd, &rsp_upiu);
539
+ g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, OCS_SUCCESS);
540
+ g_assert_cmpuint(rsp_upiu.header.scsi_status, ==, COMMAND_RESULT_SUCESS);
541
+
542
+ /* Read data and verify */
543
+ ufs_send_scsi_command(ufs, 0, 1, read_cdb, NULL, 0, read_buf, block_size,
544
+ &utrd, &rsp_upiu);
545
+ g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, OCS_SUCCESS);
546
+ g_assert_cmpuint(rsp_upiu.header.scsi_status, ==, COMMAND_RESULT_SUCESS);
547
+ g_assert_cmpint(memcmp(read_buf, write_buf, block_size), ==, 0);
548
+
549
+ ufs_exit(ufs, alloc);
550
+}
551
+
552
+static void drive_destroy(void *path)
553
+{
554
+ unlink(path);
555
+ g_free(path);
556
+ qos_invalidate_command_line();
557
+}
558
+
559
+static char *drive_create(void)
560
+{
561
+ int fd, ret;
562
+ char *t_path;
563
+
564
+ /* Create a temporary raw image */
565
+ fd = g_file_open_tmp("qtest-ufs.XXXXXX", &t_path, NULL);
566
+ g_assert_cmpint(fd, >=, 0);
567
+ ret = ftruncate(fd, TEST_IMAGE_SIZE);
568
+ g_assert_cmpint(ret, ==, 0);
569
+ close(fd);
570
+
571
+ g_test_queue_destroy(drive_destroy, t_path);
572
+ return t_path;
573
+}
574
+
575
+static void *ufs_blk_test_setup(GString *cmd_line, void *arg)
576
+{
577
+ char *tmp_path = drive_create();
578
+
579
+ g_string_append_printf(cmd_line,
580
+ " -blockdev file,filename=%s,node-name=drv1 "
581
+ "-device ufs-lu,bus=ufs0,drive=drv1,lun=1 ",
582
+ tmp_path);
583
+
584
+ return arg;
585
+}
586
+
587
+static void ufs_register_nodes(void)
588
+{
589
+ const char *arch;
590
+ QOSGraphEdgeOptions edge_opts = {
591
+ .before_cmd_line = "-blockdev null-co,node-name=drv0,read-zeroes=on",
592
+ .after_cmd_line = "-device ufs-lu,bus=ufs0,drive=drv0,lun=0",
593
+ .extra_device_opts = "addr=04.0,id=ufs0,nutrs=32,nutmrs=8"
594
+ };
595
+
596
+ QOSGraphTestOptions io_test_opts = {
597
+ .before = ufs_blk_test_setup,
598
+ };
599
+
600
+ add_qpci_address(&edge_opts, &(QPCIAddress){ .devfn = QPCI_DEVFN(4, 0) });
601
+
602
+ qos_node_create_driver("ufs", ufs_create);
603
+ qos_node_consumes("ufs", "pci-bus", &edge_opts);
604
+ qos_node_produces("ufs", "pci-device");
605
+
606
+ qos_add_test("reg-read", "ufs", ufstest_reg_read, NULL);
607
+
608
+ /*
609
+ * Check architecture
610
+ * TODO: Enable ufs io tests for ppc64
611
+ */
612
+ arch = qtest_get_arch();
613
+ if (!strcmp(arch, "ppc64")) {
614
+ g_test_message("Skipping ufs io tests for ppc64");
615
+ return;
616
+ }
617
+ qos_add_test("init", "ufs", ufstest_init, NULL);
618
+ qos_add_test("read-write", "ufs", ufstest_read_write, &io_test_opts);
619
+}
620
+
621
+libqos_init(ufs_register_nodes);
622
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
473
index XXXXXXX..XXXXXXX 100644
623
index XXXXXXX..XXXXXXX 100644
474
--- a/tests/qemu-iotests/group
624
--- a/tests/qtest/meson.build
475
+++ b/tests/qemu-iotests/group
625
+++ b/tests/qtest/meson.build
476
@@ -XXX,XX +XXX,XX @@
626
@@ -XXX,XX +XXX,XX @@ qos_test_ss.add(
477
290 rw auto quick
627
'virtio-iommu-test.c',
478
291 rw quick
628
'vmxnet3-test.c',
479
292 rw auto quick
629
'igb-test.c',
480
+293 rw auto
630
+ 'ufs-test.c',
481
+294 rw auto quick
631
)
482
297 meta
632
633
if config_all_devices.has_key('CONFIG_VIRTIO_SERIAL')
483
--
634
--
484
2.26.2
635
2.41.0
485
486
diff view generated by jsdifflib
1
From: Maxim Levitsky <mlevitsk@redhat.com>
1
From: Fabiano Rosas <farosas@suse.de>
2
2
3
Currently the implementation only supports amending the encryption
3
We can fail the blk_insert_bs() at init_blk_migration(), leaving the
4
options, unlike the qemu-img version
4
BlkMigDevState without a dirty_bitmap and BlockDriverState. Account
5
for the possibly missing elements when doing cleanup.
5
6
6
Signed-off-by: Maxim Levitsky <mlevitsk@redhat.com>
7
Fix the following crashes:
7
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
8
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
Thread 1 "qemu-system-x86" received signal SIGSEGV, Segmentation fault.
9
Message-Id: <20200608094030.670121-14-mlevitsk@redhat.com>
10
0x0000555555ec83ef in bdrv_release_dirty_bitmap (bitmap=0x0) at ../block/dirty-bitmap.c:359
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
359 BlockDriverState *bs = bitmap->bs;
12
#0 0x0000555555ec83ef in bdrv_release_dirty_bitmap (bitmap=0x0) at ../block/dirty-bitmap.c:359
13
#1 0x0000555555bba331 in unset_dirty_tracking () at ../migration/block.c:371
14
#2 0x0000555555bbad98 in block_migration_cleanup_bmds () at ../migration/block.c:681
15
16
Thread 1 "qemu-system-x86" received signal SIGSEGV, Segmentation fault.
17
0x0000555555e971ff in bdrv_op_unblock (bs=0x0, op=BLOCK_OP_TYPE_BACKUP_SOURCE, reason=0x0) at ../block.c:7073
18
7073 QLIST_FOREACH_SAFE(blocker, &bs->op_blockers[op], list, next) {
19
#0 0x0000555555e971ff in bdrv_op_unblock (bs=0x0, op=BLOCK_OP_TYPE_BACKUP_SOURCE, reason=0x0) at ../block.c:7073
20
#1 0x0000555555e9734a in bdrv_op_unblock_all (bs=0x0, reason=0x0) at ../block.c:7095
21
#2 0x0000555555bbae13 in block_migration_cleanup_bmds () at ../migration/block.c:690
22
23
Signed-off-by: Fabiano Rosas <farosas@suse.de>
24
Message-id: 20230731203338.27581-1-farosas@suse.de
25
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
11
---
26
---
12
qapi/block-core.json | 16 +++++++++++++++-
27
migration/block.c | 11 +++++++++--
13
block/qcow2.c | 39 +++++++++++++++++++++++++++++++++++++++
28
1 file changed, 9 insertions(+), 2 deletions(-)
14
2 files changed, 54 insertions(+), 1 deletion(-)
15
29
16
diff --git a/qapi/block-core.json b/qapi/block-core.json
30
diff --git a/migration/block.c b/migration/block.c
17
index XXXXXXX..XXXXXXX 100644
31
index XXXXXXX..XXXXXXX 100644
18
--- a/qapi/block-core.json
32
--- a/migration/block.c
19
+++ b/qapi/block-core.json
33
+++ b/migration/block.c
20
@@ -XXX,XX +XXX,XX @@
34
@@ -XXX,XX +XXX,XX @@ static void unset_dirty_tracking(void)
21
'data': { }
35
BlkMigDevState *bmds;
36
37
QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) {
38
- bdrv_release_dirty_bitmap(bmds->dirty_bitmap);
39
+ if (bmds->dirty_bitmap) {
40
+ bdrv_release_dirty_bitmap(bmds->dirty_bitmap);
41
+ }
42
}
22
}
43
}
23
44
24
+##
45
@@ -XXX,XX +XXX,XX @@ static int64_t get_remaining_dirty(void)
25
+# @BlockdevAmendOptionsQcow2:
46
static void block_migration_cleanup_bmds(void)
26
+#
47
{
27
+# Driver specific image amend options for qcow2.
48
BlkMigDevState *bmds;
28
+# For now, only encryption options can be amended
49
+ BlockDriverState *bs;
29
+#
50
AioContext *ctx;
30
+# @encrypt Encryption options to be amended
51
31
+#
52
unset_dirty_tracking();
32
+# Since: 5.1
53
33
+##
54
while ((bmds = QSIMPLEQ_FIRST(&block_mig_state.bmds_list)) != NULL) {
34
+{ 'struct': 'BlockdevAmendOptionsQcow2',
55
QSIMPLEQ_REMOVE_HEAD(&block_mig_state.bmds_list, entry);
35
+ 'data': { '*encrypt': 'QCryptoBlockAmendOptions' } }
56
- bdrv_op_unblock_all(blk_bs(bmds->blk), bmds->blocker);
36
+
57
+
37
##
58
+ bs = blk_bs(bmds->blk);
38
# @BlockdevAmendOptions:
59
+ if (bs) {
39
#
60
+ bdrv_op_unblock_all(bs, bmds->blocker);
40
@@ -XXX,XX +XXX,XX @@
41
'driver': 'BlockdevDriver' },
42
'discriminator': 'driver',
43
'data': {
44
- 'luks': 'BlockdevAmendOptionsLUKS' } }
45
+ 'luks': 'BlockdevAmendOptionsLUKS',
46
+ 'qcow2': 'BlockdevAmendOptionsQcow2' } }
47
48
##
49
# @x-blockdev-amend:
50
diff --git a/block/qcow2.c b/block/qcow2.c
51
index XXXXXXX..XXXXXXX 100644
52
--- a/block/qcow2.c
53
+++ b/block/qcow2.c
54
@@ -XXX,XX +XXX,XX @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
55
return 0;
56
}
57
58
+static int coroutine_fn qcow2_co_amend(BlockDriverState *bs,
59
+ BlockdevAmendOptions *opts,
60
+ bool force,
61
+ Error **errp)
62
+{
63
+ BlockdevAmendOptionsQcow2 *qopts = &opts->u.qcow2;
64
+ BDRVQcow2State *s = bs->opaque;
65
+ int ret = 0;
66
+
67
+ if (qopts->has_encrypt) {
68
+ if (!s->crypto) {
69
+ error_setg(errp, "image is not encrypted, can't amend");
70
+ return -EOPNOTSUPP;
71
+ }
61
+ }
72
+
62
error_free(bmds->blocker);
73
+ if (qopts->encrypt->format != Q_CRYPTO_BLOCK_FORMAT_LUKS) {
63
74
+ error_setg(errp,
64
/* Save ctx, because bmds->blk can disappear during blk_unref. */
75
+ "Amend can't be used to change the qcow2 encryption format");
76
+ return -EOPNOTSUPP;
77
+ }
78
+
79
+ if (s->crypt_method_header != QCOW_CRYPT_LUKS) {
80
+ error_setg(errp,
81
+ "Only LUKS encryption options can be amended for qcow2 with blockdev-amend");
82
+ return -EOPNOTSUPP;
83
+ }
84
+
85
+ ret = qcrypto_block_amend_options(s->crypto,
86
+ qcow2_crypto_hdr_read_func,
87
+ qcow2_crypto_hdr_write_func,
88
+ bs,
89
+ qopts->encrypt,
90
+ force,
91
+ errp);
92
+ }
93
+ return ret;
94
+}
95
+
96
/*
97
* If offset or size are negative, respectively, they will not be included in
98
* the BLOCK_IMAGE_CORRUPTED event emitted.
99
@@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_qcow2 = {
100
.mutable_opts = mutable_opts,
101
.bdrv_co_check = qcow2_co_check,
102
.bdrv_amend_options = qcow2_amend_options,
103
+ .bdrv_co_amend = qcow2_co_amend,
104
105
.bdrv_detach_aio_context = qcow2_detach_aio_context,
106
.bdrv_attach_aio_context = qcow2_attach_aio_context,
107
--
65
--
108
2.26.2
66
2.41.0
109
110
diff view generated by jsdifflib
1
From: Maxim Levitsky <mlevitsk@redhat.com>
1
From: Andrey Drobyshev <andrey.drobyshev@virtuozzo.com>
2
2
3
'force' option will be used for some unsafe amend operations.
3
This is going to be used in the subsequent commit as requests alignment
4
(in particular, during copy-on-read). This value only makes sense for
5
the formats which support subclusters (currently QCOW2 only). If this
6
field isn't set by driver's own bdrv_get_info() implementation, we
7
simply set it equal to the cluster size thus treating each cluster as
8
having a single subcluster.
4
9
5
This includes things like erasing last keyslot in luks based formats
10
Reviewed-by: Eric Blake <eblake@redhat.com>
6
(which destroys the data, unless the master key is backed up
11
Reviewed-by: Denis V. Lunev <den@openvz.org>
7
by external means), but that _might_ be desired result.
12
Signed-off-by: Andrey Drobyshev <andrey.drobyshev@virtuozzo.com>
13
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
14
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
15
Message-ID: <20230711172553.234055-2-andrey.drobyshev@virtuozzo.com>
16
---
17
include/block/block-common.h | 5 +++++
18
block.c | 7 +++++++
19
block/qcow2.c | 1 +
20
3 files changed, 13 insertions(+)
8
21
9
Signed-off-by: Maxim Levitsky <mlevitsk@redhat.com>
22
diff --git a/include/block/block-common.h b/include/block/block-common.h
10
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
11
Reviewed-by: Max Reitz <mreitz@redhat.com>
12
Message-Id: <20200608094030.670121-4-mlevitsk@redhat.com>
13
Signed-off-by: Max Reitz <mreitz@redhat.com>
14
---
15
docs/tools/qemu-img.rst | 5 ++++-
16
include/block/block.h | 1 +
17
include/block/block_int.h | 1 +
18
block.c | 4 +++-
19
block/qcow2.c | 1 +
20
qemu-img.c | 8 +++++++-
21
qemu-img-cmds.hx | 4 ++--
22
7 files changed, 19 insertions(+), 5 deletions(-)
23
24
diff --git a/docs/tools/qemu-img.rst b/docs/tools/qemu-img.rst
25
index XXXXXXX..XXXXXXX 100644
23
index XXXXXXX..XXXXXXX 100644
26
--- a/docs/tools/qemu-img.rst
24
--- a/include/block/block-common.h
27
+++ b/docs/tools/qemu-img.rst
25
+++ b/include/block/block-common.h
28
@@ -XXX,XX +XXX,XX @@ Command description:
26
@@ -XXX,XX +XXX,XX @@ typedef struct BlockZoneWps {
29
27
typedef struct BlockDriverInfo {
30
.. program:: qemu-img-commands
28
/* in bytes, 0 if irrelevant */
31
29
int cluster_size;
32
-.. option:: amend [--object OBJECTDEF] [--image-opts] [-p] [-q] [-f FMT] [-t CACHE] -o OPTIONS FILENAME
30
+ /*
33
+.. option:: amend [--object OBJECTDEF] [--image-opts] [-p] [-q] [-f FMT] [-t CACHE] [--force] -o OPTIONS FILENAME
31
+ * A fraction of cluster_size, if supported (currently QCOW2 only); if
34
32
+ * disabled or unsupported, set equal to cluster_size.
35
Amends the image format specific *OPTIONS* for the image file
33
+ */
36
*FILENAME*. Not all file formats support this operation.
34
+ int subcluster_size;
37
35
/* offset at which the VM state can be saved (0 if not possible) */
38
+ --force allows some unsafe operations. Currently for -f luks, it allows to
36
int64_t vm_state_offset;
39
+ erase the last encryption key, and to overwrite an active encryption key.
37
bool is_dirty;
40
+
41
.. option:: bench [-c COUNT] [-d DEPTH] [-f FMT] [--flush-interval=FLUSH_INTERVAL] [-i AIO] [-n] [--no-drain] [-o OFFSET] [--pattern=PATTERN] [-q] [-s BUFFER_SIZE] [-S STEP_SIZE] [-t CACHE] [-w] [-U] FILENAME
42
43
Run a simple sequential I/O benchmark on the specified image. If ``-w`` is
44
diff --git a/include/block/block.h b/include/block/block.h
45
index XXXXXXX..XXXXXXX 100644
46
--- a/include/block/block.h
47
+++ b/include/block/block.h
48
@@ -XXX,XX +XXX,XX @@ typedef void BlockDriverAmendStatusCB(BlockDriverState *bs, int64_t offset,
49
int64_t total_work_size, void *opaque);
50
int bdrv_amend_options(BlockDriverState *bs_new, QemuOpts *opts,
51
BlockDriverAmendStatusCB *status_cb, void *cb_opaque,
52
+ bool force,
53
Error **errp);
54
55
/* check if a named node can be replaced when doing drive-mirror */
56
diff --git a/include/block/block_int.h b/include/block/block_int.h
57
index XXXXXXX..XXXXXXX 100644
58
--- a/include/block/block_int.h
59
+++ b/include/block/block_int.h
60
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
61
int (*bdrv_amend_options)(BlockDriverState *bs, QemuOpts *opts,
62
BlockDriverAmendStatusCB *status_cb,
63
void *cb_opaque,
64
+ bool force,
65
Error **errp);
66
67
void (*bdrv_debug_event)(BlockDriverState *bs, BlkdebugEvent event);
68
diff --git a/block.c b/block.c
38
diff --git a/block.c b/block.c
69
index XXXXXXX..XXXXXXX 100644
39
index XXXXXXX..XXXXXXX 100644
70
--- a/block.c
40
--- a/block.c
71
+++ b/block.c
41
+++ b/block.c
72
@@ -XXX,XX +XXX,XX @@ void bdrv_remove_aio_context_notifier(BlockDriverState *bs,
42
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
73
74
int bdrv_amend_options(BlockDriverState *bs, QemuOpts *opts,
75
BlockDriverAmendStatusCB *status_cb, void *cb_opaque,
76
+ bool force,
77
Error **errp)
78
{
79
if (!bs->drv) {
80
@@ -XXX,XX +XXX,XX @@ int bdrv_amend_options(BlockDriverState *bs, QemuOpts *opts,
81
bs->drv->format_name);
82
return -ENOTSUP;
83
}
43
}
84
- return bs->drv->bdrv_amend_options(bs, opts, status_cb, cb_opaque, errp);
44
memset(bdi, 0, sizeof(*bdi));
85
+ return bs->drv->bdrv_amend_options(bs, opts, status_cb,
45
ret = drv->bdrv_co_get_info(bs, bdi);
86
+ cb_opaque, force, errp);
46
+ if (bdi->subcluster_size == 0) {
87
}
47
+ /*
88
48
+ * If the driver left this unset, subclusters are not supported.
89
/*
49
+ * Then it is safe to treat each cluster as having only one subcluster.
50
+ */
51
+ bdi->subcluster_size = bdi->cluster_size;
52
+ }
53
if (ret < 0) {
54
return ret;
55
}
90
diff --git a/block/qcow2.c b/block/qcow2.c
56
diff --git a/block/qcow2.c b/block/qcow2.c
91
index XXXXXXX..XXXXXXX 100644
57
index XXXXXXX..XXXXXXX 100644
92
--- a/block/qcow2.c
58
--- a/block/qcow2.c
93
+++ b/block/qcow2.c
59
+++ b/block/qcow2.c
94
@@ -XXX,XX +XXX,XX @@ static void qcow2_amend_helper_cb(BlockDriverState *bs,
60
@@ -XXX,XX +XXX,XX @@ qcow2_co_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
95
static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
96
BlockDriverAmendStatusCB *status_cb,
97
void *cb_opaque,
98
+ bool force,
99
Error **errp)
100
{
61
{
101
BDRVQcow2State *s = bs->opaque;
62
BDRVQcow2State *s = bs->opaque;
102
diff --git a/qemu-img.c b/qemu-img.c
63
bdi->cluster_size = s->cluster_size;
103
index XXXXXXX..XXXXXXX 100644
64
+ bdi->subcluster_size = s->subcluster_size;
104
--- a/qemu-img.c
65
bdi->vm_state_offset = qcow2_vm_state_offset(s);
105
+++ b/qemu-img.c
66
bdi->is_dirty = s->incompatible_features & QCOW2_INCOMPAT_DIRTY;
106
@@ -XXX,XX +XXX,XX @@ enum {
67
return 0;
107
OPTION_DISABLE = 273,
108
OPTION_MERGE = 274,
109
OPTION_BITMAPS = 275,
110
+ OPTION_FORCE = 276,
111
};
112
113
typedef enum OutputFormat {
114
@@ -XXX,XX +XXX,XX @@ static int img_amend(int argc, char **argv)
115
BlockBackend *blk = NULL;
116
BlockDriverState *bs = NULL;
117
bool image_opts = false;
118
+ bool force = false;
119
120
cache = BDRV_DEFAULT_CACHE;
121
for (;;) {
122
@@ -XXX,XX +XXX,XX @@ static int img_amend(int argc, char **argv)
123
{"help", no_argument, 0, 'h'},
124
{"object", required_argument, 0, OPTION_OBJECT},
125
{"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
126
+ {"force", no_argument, 0, OPTION_FORCE},
127
{0, 0, 0, 0}
128
};
129
c = getopt_long(argc, argv, ":ho:f:t:pq",
130
@@ -XXX,XX +XXX,XX @@ static int img_amend(int argc, char **argv)
131
case OPTION_IMAGE_OPTS:
132
image_opts = true;
133
break;
134
+ case OPTION_FORCE:
135
+ force = true;
136
+ break;
137
}
138
}
139
140
@@ -XXX,XX +XXX,XX @@ static int img_amend(int argc, char **argv)
141
142
/* In case the driver does not call amend_status_cb() */
143
qemu_progress_print(0.f, 0);
144
- ret = bdrv_amend_options(bs, opts, &amend_status_cb, NULL, &err);
145
+ ret = bdrv_amend_options(bs, opts, &amend_status_cb, NULL, force, &err);
146
qemu_progress_print(100.f, 0);
147
if (ret < 0) {
148
error_report_err(err);
149
diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx
150
index XXXXXXX..XXXXXXX 100644
151
--- a/qemu-img-cmds.hx
152
+++ b/qemu-img-cmds.hx
153
@@ -XXX,XX +XXX,XX @@ HXCOMM When amending the rST sections, please remember to copy the usage
154
HXCOMM over to the per-command sections in docs/tools/qemu-img.rst.
155
156
DEF("amend", img_amend,
157
- "amend [--object objectdef] [--image-opts] [-p] [-q] [-f fmt] [-t cache] -o options filename")
158
+ "amend [--object objectdef] [--image-opts] [-p] [-q] [-f fmt] [-t cache] [--force] -o options filename")
159
SRST
160
-.. option:: amend [--object OBJECTDEF] [--image-opts] [-p] [-q] [-f FMT] [-t CACHE] -o OPTIONS FILENAME
161
+.. option:: amend [--object OBJECTDEF] [--image-opts] [-p] [-q] [-f FMT] [-t CACHE] [--force] -o OPTIONS FILENAME
162
ERST
163
164
DEF("bench", img_bench,
165
--
68
--
166
2.26.2
69
2.41.0
167
168
diff view generated by jsdifflib
1
From: Maxim Levitsky <mlevitsk@redhat.com>
1
From: Andrey Drobyshev <andrey.drobyshev@virtuozzo.com>
2
2
3
Some options are only useful for creation
3
When target image is using subclusters, and we align the request during
4
(or hard to be amended, like cluster size for qcow2), while some other
4
copy-on-read, it makes sense to align to subcluster_size rather than
5
options are only useful for amend, like upcoming keyslot management
5
cluster_size. Otherwise we end up with unnecessary allocations.
6
options for luks
6
7
7
This commit renames bdrv_round_to_clusters() to bdrv_round_to_subclusters()
8
Since currently only qcow2 supports amend, move all its options
8
and utilizes subcluster_size field of BlockDriverInfo to make necessary
9
to a common macro and then include it in each action option list.
9
alignments. It affects copy-on-read as well as mirror job (which is
10
10
using bdrv_round_to_clusters()).
11
In future it might be useful to remove some options which are
11
12
not supported anyway from amend list, which currently
12
This change also fixes the following bug with failing assert (covered by
13
cause an error message if amended.
13
the test in the subsequent commit):
14
14
15
Signed-off-by: Maxim Levitsky <mlevitsk@redhat.com>
15
qemu-img create -f qcow2 base.qcow2 64K
16
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
16
qemu-img create -f qcow2 -o extended_l2=on,backing_file=base.qcow2,backing_fmt=qcow2 img.qcow2 64K
17
Reviewed-by: Max Reitz <mreitz@redhat.com>
17
qemu-io -c "write -P 0xaa 0 2K" img.qcow2
18
Message-Id: <20200608094030.670121-5-mlevitsk@redhat.com>
18
qemu-io -C -c "read -P 0x00 2K 62K" img.qcow2
19
Signed-off-by: Max Reitz <mreitz@redhat.com>
19
20
qemu-io: ../block/io.c:1236: bdrv_co_do_copy_on_readv: Assertion `skip_bytes < pnum' failed.
21
22
Reviewed-by: Eric Blake <eblake@redhat.com>
23
Reviewed-by: Denis V. Lunev <den@openvz.org>
24
Signed-off-by: Andrey Drobyshev <andrey.drobyshev@virtuozzo.com>
25
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
26
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
27
Message-ID: <20230711172553.234055-3-andrey.drobyshev@virtuozzo.com>
20
---
28
---
21
include/block/block_int.h | 4 +
29
include/block/block-io.h | 8 +++----
22
block/qcow2.c | 173 +++++++++++++++++++++-----------------
30
block/io.c | 50 ++++++++++++++++++++--------------------
23
qemu-img.c | 18 ++--
31
block/mirror.c | 8 +++----
24
3 files changed, 107 insertions(+), 88 deletions(-)
32
3 files changed, 33 insertions(+), 33 deletions(-)
25
33
26
diff --git a/include/block/block_int.h b/include/block/block_int.h
34
diff --git a/include/block/block-io.h b/include/block/block-io.h
27
index XXXXXXX..XXXXXXX 100644
35
index XXXXXXX..XXXXXXX 100644
28
--- a/include/block/block_int.h
36
--- a/include/block/block-io.h
29
+++ b/include/block/block_int.h
37
+++ b/include/block/block-io.h
30
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
38
@@ -XXX,XX +XXX,XX @@ bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi);
31
39
ImageInfoSpecific *bdrv_get_specific_info(BlockDriverState *bs,
32
/* List of options for creating images, terminated by name == NULL */
40
Error **errp);
33
QemuOptsList *create_opts;
41
BlockStatsSpecific *bdrv_get_specific_stats(BlockDriverState *bs);
34
+
42
-void bdrv_round_to_clusters(BlockDriverState *bs,
35
+ /* List of options for image amend */
43
- int64_t offset, int64_t bytes,
36
+ QemuOptsList *amend_opts;
44
- int64_t *cluster_offset,
37
+
45
- int64_t *cluster_bytes);
38
/*
46
+void bdrv_round_to_subclusters(BlockDriverState *bs,
39
* If this driver supports reopening images this contains a
47
+ int64_t offset, int64_t bytes,
40
* NULL-terminated list of the runtime options that can be
48
+ int64_t *cluster_offset,
41
diff --git a/block/qcow2.c b/block/qcow2.c
49
+ int64_t *cluster_bytes);
50
51
void bdrv_get_backing_filename(BlockDriverState *bs,
52
char *filename, int filename_size);
53
diff --git a/block/io.c b/block/io.c
42
index XXXXXXX..XXXXXXX 100644
54
index XXXXXXX..XXXXXXX 100644
43
--- a/block/qcow2.c
55
--- a/block/io.c
44
+++ b/block/qcow2.c
56
+++ b/block/io.c
45
@@ -XXX,XX +XXX,XX @@ void qcow2_signal_corruption(BlockDriverState *bs, bool fatal, int64_t offset,
57
@@ -XXX,XX +XXX,XX @@ BdrvTrackedRequest *coroutine_fn bdrv_co_get_self_request(BlockDriverState *bs)
46
s->signaled_corruption = true;
47
}
58
}
48
59
49
+#define QCOW_COMMON_OPTIONS \
60
/**
50
+ { \
61
- * Round a region to cluster boundaries
51
+ .name = BLOCK_OPT_SIZE, \
62
+ * Round a region to subcluster (if supported) or cluster boundaries
52
+ .type = QEMU_OPT_SIZE, \
63
*/
53
+ .help = "Virtual disk size" \
64
void coroutine_fn GRAPH_RDLOCK
54
+ }, \
65
-bdrv_round_to_clusters(BlockDriverState *bs, int64_t offset, int64_t bytes,
55
+ { \
66
- int64_t *cluster_offset, int64_t *cluster_bytes)
56
+ .name = BLOCK_OPT_COMPAT_LEVEL, \
67
+bdrv_round_to_subclusters(BlockDriverState *bs, int64_t offset, int64_t bytes,
57
+ .type = QEMU_OPT_STRING, \
68
+ int64_t *align_offset, int64_t *align_bytes)
58
+ .help = "Compatibility level (v2 [0.10] or v3 [1.1])" \
69
{
59
+ }, \
70
BlockDriverInfo bdi;
60
+ { \
71
IO_CODE();
61
+ .name = BLOCK_OPT_BACKING_FILE, \
72
- if (bdrv_co_get_info(bs, &bdi) < 0 || bdi.cluster_size == 0) {
62
+ .type = QEMU_OPT_STRING, \
73
- *cluster_offset = offset;
63
+ .help = "File name of a base image" \
74
- *cluster_bytes = bytes;
64
+ }, \
75
+ if (bdrv_co_get_info(bs, &bdi) < 0 || bdi.subcluster_size == 0) {
65
+ { \
76
+ *align_offset = offset;
66
+ .name = BLOCK_OPT_BACKING_FMT, \
77
+ *align_bytes = bytes;
67
+ .type = QEMU_OPT_STRING, \
78
} else {
68
+ .help = "Image format of the base image" \
79
- int64_t c = bdi.cluster_size;
69
+ }, \
80
- *cluster_offset = QEMU_ALIGN_DOWN(offset, c);
70
+ { \
81
- *cluster_bytes = QEMU_ALIGN_UP(offset - *cluster_offset + bytes, c);
71
+ .name = BLOCK_OPT_DATA_FILE, \
82
+ int64_t c = bdi.subcluster_size;
72
+ .type = QEMU_OPT_STRING, \
83
+ *align_offset = QEMU_ALIGN_DOWN(offset, c);
73
+ .help = "File name of an external data file" \
84
+ *align_bytes = QEMU_ALIGN_UP(offset - *align_offset + bytes, c);
74
+ }, \
75
+ { \
76
+ .name = BLOCK_OPT_DATA_FILE_RAW, \
77
+ .type = QEMU_OPT_BOOL, \
78
+ .help = "The external data file must stay valid " \
79
+ "as a raw image" \
80
+ }, \
81
+ { \
82
+ .name = BLOCK_OPT_ENCRYPT, \
83
+ .type = QEMU_OPT_BOOL, \
84
+ .help = "Encrypt the image with format 'aes'. (Deprecated " \
85
+ "in favor of " BLOCK_OPT_ENCRYPT_FORMAT "=aes)", \
86
+ }, \
87
+ { \
88
+ .name = BLOCK_OPT_ENCRYPT_FORMAT, \
89
+ .type = QEMU_OPT_STRING, \
90
+ .help = "Encrypt the image, format choices: 'aes', 'luks'", \
91
+ }, \
92
+ BLOCK_CRYPTO_OPT_DEF_KEY_SECRET("encrypt.", \
93
+ "ID of secret providing qcow AES key or LUKS passphrase"), \
94
+ BLOCK_CRYPTO_OPT_DEF_LUKS_CIPHER_ALG("encrypt."), \
95
+ BLOCK_CRYPTO_OPT_DEF_LUKS_CIPHER_MODE("encrypt."), \
96
+ BLOCK_CRYPTO_OPT_DEF_LUKS_IVGEN_ALG("encrypt."), \
97
+ BLOCK_CRYPTO_OPT_DEF_LUKS_IVGEN_HASH_ALG("encrypt."), \
98
+ BLOCK_CRYPTO_OPT_DEF_LUKS_HASH_ALG("encrypt."), \
99
+ BLOCK_CRYPTO_OPT_DEF_LUKS_ITER_TIME("encrypt."), \
100
+ { \
101
+ .name = BLOCK_OPT_CLUSTER_SIZE, \
102
+ .type = QEMU_OPT_SIZE, \
103
+ .help = "qcow2 cluster size", \
104
+ .def_value_str = stringify(DEFAULT_CLUSTER_SIZE) \
105
+ }, \
106
+ { \
107
+ .name = BLOCK_OPT_PREALLOC, \
108
+ .type = QEMU_OPT_STRING, \
109
+ .help = "Preallocation mode (allowed values: off, " \
110
+ "metadata, falloc, full)" \
111
+ }, \
112
+ { \
113
+ .name = BLOCK_OPT_LAZY_REFCOUNTS, \
114
+ .type = QEMU_OPT_BOOL, \
115
+ .help = "Postpone refcount updates", \
116
+ .def_value_str = "off" \
117
+ }, \
118
+ { \
119
+ .name = BLOCK_OPT_REFCOUNT_BITS, \
120
+ .type = QEMU_OPT_NUMBER, \
121
+ .help = "Width of a reference count entry in bits", \
122
+ .def_value_str = "16" \
123
+ }, \
124
+ { \
125
+ .name = BLOCK_OPT_COMPRESSION_TYPE, \
126
+ .type = QEMU_OPT_STRING, \
127
+ .help = "Compression method used for image cluster " \
128
+ "compression", \
129
+ .def_value_str = "zlib" \
130
+ }
131
+
132
static QemuOptsList qcow2_create_opts = {
133
.name = "qcow2-create-opts",
134
.head = QTAILQ_HEAD_INITIALIZER(qcow2_create_opts.head),
135
.desc = {
136
- {
137
- .name = BLOCK_OPT_SIZE,
138
- .type = QEMU_OPT_SIZE,
139
- .help = "Virtual disk size"
140
- },
141
- {
142
- .name = BLOCK_OPT_COMPAT_LEVEL,
143
- .type = QEMU_OPT_STRING,
144
- .help = "Compatibility level (v2 [0.10] or v3 [1.1])"
145
- },
146
- {
147
- .name = BLOCK_OPT_BACKING_FILE,
148
- .type = QEMU_OPT_STRING,
149
- .help = "File name of a base image"
150
- },
151
- {
152
- .name = BLOCK_OPT_BACKING_FMT,
153
- .type = QEMU_OPT_STRING,
154
- .help = "Image format of the base image"
155
- },
156
- {
157
- .name = BLOCK_OPT_DATA_FILE,
158
- .type = QEMU_OPT_STRING,
159
- .help = "File name of an external data file"
160
- },
161
- {
162
- .name = BLOCK_OPT_DATA_FILE_RAW,
163
- .type = QEMU_OPT_BOOL,
164
- .help = "The external data file must stay valid as a raw image"
165
- },
166
- {
167
- .name = BLOCK_OPT_ENCRYPT,
168
- .type = QEMU_OPT_BOOL,
169
- .help = "Encrypt the image with format 'aes'. (Deprecated "
170
- "in favor of " BLOCK_OPT_ENCRYPT_FORMAT "=aes)",
171
- },
172
- {
173
- .name = BLOCK_OPT_ENCRYPT_FORMAT,
174
- .type = QEMU_OPT_STRING,
175
- .help = "Encrypt the image, format choices: 'aes', 'luks'",
176
- },
177
- BLOCK_CRYPTO_OPT_DEF_KEY_SECRET("encrypt.",
178
- "ID of secret providing qcow AES key or LUKS passphrase"),
179
- BLOCK_CRYPTO_OPT_DEF_LUKS_CIPHER_ALG("encrypt."),
180
- BLOCK_CRYPTO_OPT_DEF_LUKS_CIPHER_MODE("encrypt."),
181
- BLOCK_CRYPTO_OPT_DEF_LUKS_IVGEN_ALG("encrypt."),
182
- BLOCK_CRYPTO_OPT_DEF_LUKS_IVGEN_HASH_ALG("encrypt."),
183
- BLOCK_CRYPTO_OPT_DEF_LUKS_HASH_ALG("encrypt."),
184
- BLOCK_CRYPTO_OPT_DEF_LUKS_ITER_TIME("encrypt."),
185
- {
186
- .name = BLOCK_OPT_CLUSTER_SIZE,
187
- .type = QEMU_OPT_SIZE,
188
- .help = "qcow2 cluster size",
189
- .def_value_str = stringify(DEFAULT_CLUSTER_SIZE)
190
- },
191
- {
192
- .name = BLOCK_OPT_PREALLOC,
193
- .type = QEMU_OPT_STRING,
194
- .help = "Preallocation mode (allowed values: off, metadata, "
195
- "falloc, full)"
196
- },
197
- {
198
- .name = BLOCK_OPT_LAZY_REFCOUNTS,
199
- .type = QEMU_OPT_BOOL,
200
- .help = "Postpone refcount updates",
201
- .def_value_str = "off"
202
- },
203
- {
204
- .name = BLOCK_OPT_REFCOUNT_BITS,
205
- .type = QEMU_OPT_NUMBER,
206
- .help = "Width of a reference count entry in bits",
207
- .def_value_str = "16"
208
- },
209
- {
210
- .name = BLOCK_OPT_COMPRESSION_TYPE,
211
- .type = QEMU_OPT_STRING,
212
- .help = "Compression method used for image cluster compression",
213
- .def_value_str = "zlib"
214
- },
215
+ QCOW_COMMON_OPTIONS,
216
+ { /* end of list */ }
217
+ }
218
+};
219
+
220
+static QemuOptsList qcow2_amend_opts = {
221
+ .name = "qcow2-amend-opts",
222
+ .head = QTAILQ_HEAD_INITIALIZER(qcow2_amend_opts.head),
223
+ .desc = {
224
+ QCOW_COMMON_OPTIONS,
225
{ /* end of list */ }
226
}
85
}
227
};
86
}
228
@@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_qcow2 = {
87
229
.bdrv_inactivate = qcow2_inactivate,
88
@@ -XXX,XX +XXX,XX @@ bdrv_co_do_copy_on_readv(BdrvChild *child, int64_t offset, int64_t bytes,
230
89
void *bounce_buffer = NULL;
231
.create_opts = &qcow2_create_opts,
90
232
+ .amend_opts = &qcow2_amend_opts,
91
BlockDriver *drv = bs->drv;
233
.strong_runtime_opts = qcow2_strong_runtime_opts,
92
- int64_t cluster_offset;
234
.mutable_opts = mutable_opts,
93
- int64_t cluster_bytes;
235
.bdrv_co_check = qcow2_co_check,
94
+ int64_t align_offset;
236
diff --git a/qemu-img.c b/qemu-img.c
95
+ int64_t align_bytes;
96
int64_t skip_bytes;
97
int ret;
98
int max_transfer = MIN_NON_ZERO(bs->bl.max_transfer,
99
@@ -XXX,XX +XXX,XX @@ bdrv_co_do_copy_on_readv(BdrvChild *child, int64_t offset, int64_t bytes,
100
* BDRV_REQUEST_MAX_BYTES (even when the original read did not), which
101
* is one reason we loop rather than doing it all at once.
102
*/
103
- bdrv_round_to_clusters(bs, offset, bytes, &cluster_offset, &cluster_bytes);
104
- skip_bytes = offset - cluster_offset;
105
+ bdrv_round_to_subclusters(bs, offset, bytes, &align_offset, &align_bytes);
106
+ skip_bytes = offset - align_offset;
107
108
trace_bdrv_co_do_copy_on_readv(bs, offset, bytes,
109
- cluster_offset, cluster_bytes);
110
+ align_offset, align_bytes);
111
112
- while (cluster_bytes) {
113
+ while (align_bytes) {
114
int64_t pnum;
115
116
if (skip_write) {
117
ret = 1; /* "already allocated", so nothing will be copied */
118
- pnum = MIN(cluster_bytes, max_transfer);
119
+ pnum = MIN(align_bytes, max_transfer);
120
} else {
121
- ret = bdrv_is_allocated(bs, cluster_offset,
122
- MIN(cluster_bytes, max_transfer), &pnum);
123
+ ret = bdrv_is_allocated(bs, align_offset,
124
+ MIN(align_bytes, max_transfer), &pnum);
125
if (ret < 0) {
126
/*
127
* Safe to treat errors in querying allocation as if
128
* unallocated; we'll probably fail again soon on the
129
* read, but at least that will set a decent errno.
130
*/
131
- pnum = MIN(cluster_bytes, max_transfer);
132
+ pnum = MIN(align_bytes, max_transfer);
133
}
134
135
/* Stop at EOF if the image ends in the middle of the cluster */
136
@@ -XXX,XX +XXX,XX @@ bdrv_co_do_copy_on_readv(BdrvChild *child, int64_t offset, int64_t bytes,
137
/* Must copy-on-read; use the bounce buffer */
138
pnum = MIN(pnum, MAX_BOUNCE_BUFFER);
139
if (!bounce_buffer) {
140
- int64_t max_we_need = MAX(pnum, cluster_bytes - pnum);
141
+ int64_t max_we_need = MAX(pnum, align_bytes - pnum);
142
int64_t max_allowed = MIN(max_transfer, MAX_BOUNCE_BUFFER);
143
int64_t bounce_buffer_len = MIN(max_we_need, max_allowed);
144
145
@@ -XXX,XX +XXX,XX @@ bdrv_co_do_copy_on_readv(BdrvChild *child, int64_t offset, int64_t bytes,
146
}
147
qemu_iovec_init_buf(&local_qiov, bounce_buffer, pnum);
148
149
- ret = bdrv_driver_preadv(bs, cluster_offset, pnum,
150
+ ret = bdrv_driver_preadv(bs, align_offset, pnum,
151
&local_qiov, 0, 0);
152
if (ret < 0) {
153
goto err;
154
@@ -XXX,XX +XXX,XX @@ bdrv_co_do_copy_on_readv(BdrvChild *child, int64_t offset, int64_t bytes,
155
/* FIXME: Should we (perhaps conditionally) be setting
156
* BDRV_REQ_MAY_UNMAP, if it will allow for a sparser copy
157
* that still correctly reads as zero? */
158
- ret = bdrv_co_do_pwrite_zeroes(bs, cluster_offset, pnum,
159
+ ret = bdrv_co_do_pwrite_zeroes(bs, align_offset, pnum,
160
BDRV_REQ_WRITE_UNCHANGED);
161
} else {
162
/* This does not change the data on the disk, it is not
163
* necessary to flush even in cache=writethrough mode.
164
*/
165
- ret = bdrv_driver_pwritev(bs, cluster_offset, pnum,
166
+ ret = bdrv_driver_pwritev(bs, align_offset, pnum,
167
&local_qiov, 0,
168
BDRV_REQ_WRITE_UNCHANGED);
169
}
170
@@ -XXX,XX +XXX,XX @@ bdrv_co_do_copy_on_readv(BdrvChild *child, int64_t offset, int64_t bytes,
171
}
172
}
173
174
- cluster_offset += pnum;
175
- cluster_bytes -= pnum;
176
+ align_offset += pnum;
177
+ align_bytes -= pnum;
178
progress += pnum - skip_bytes;
179
skip_bytes = 0;
180
}
181
diff --git a/block/mirror.c b/block/mirror.c
237
index XXXXXXX..XXXXXXX 100644
182
index XXXXXXX..XXXXXXX 100644
238
--- a/qemu-img.c
183
--- a/block/mirror.c
239
+++ b/qemu-img.c
184
+++ b/block/mirror.c
240
@@ -XXX,XX +XXX,XX @@ static int print_amend_option_help(const char *format)
185
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn mirror_cow_align(MirrorBlockJob *s, int64_t *offset,
241
return 1;
186
need_cow |= !test_bit((*offset + *bytes - 1) / s->granularity,
187
s->cow_bitmap);
188
if (need_cow) {
189
- bdrv_round_to_clusters(blk_bs(s->target), *offset, *bytes,
190
- &align_offset, &align_bytes);
191
+ bdrv_round_to_subclusters(blk_bs(s->target), *offset, *bytes,
192
+ &align_offset, &align_bytes);
242
}
193
}
243
194
244
- /* Every driver supporting amendment must have create_opts */
195
if (align_bytes > max_bytes) {
245
- assert(drv->create_opts);
196
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn mirror_iteration(MirrorBlockJob *s)
246
+ /* Every driver supporting amendment must have amend_opts */
197
int64_t target_offset;
247
+ assert(drv->amend_opts);
198
int64_t target_bytes;
248
199
WITH_GRAPH_RDLOCK_GUARD() {
249
printf("Creation options for '%s':\n", format);
200
- bdrv_round_to_clusters(blk_bs(s->target), offset, io_bytes,
250
- qemu_opts_print_help(drv->create_opts, false);
201
- &target_offset, &target_bytes);
251
+ qemu_opts_print_help(drv->amend_opts, false);
202
+ bdrv_round_to_subclusters(blk_bs(s->target), offset, io_bytes,
252
printf("\nNote that not all of these options may be amendable.\n");
203
+ &target_offset, &target_bytes);
253
return 0;
204
}
254
}
205
if (target_offset == offset &&
255
@@ -XXX,XX +XXX,XX @@ static int img_amend(int argc, char **argv)
206
target_bytes == io_bytes) {
256
Error *err = NULL;
257
int c, ret = 0;
258
char *options = NULL;
259
- QemuOptsList *create_opts = NULL;
260
+ QemuOptsList *amend_opts = NULL;
261
QemuOpts *opts = NULL;
262
const char *fmt = NULL, *filename, *cache;
263
int flags;
264
@@ -XXX,XX +XXX,XX @@ static int img_amend(int argc, char **argv)
265
goto out;
266
}
267
268
- /* Every driver supporting amendment must have create_opts */
269
- assert(bs->drv->create_opts);
270
+ /* Every driver supporting amendment must have amend_opts */
271
+ assert(bs->drv->amend_opts);
272
273
- create_opts = qemu_opts_append(create_opts, bs->drv->create_opts);
274
- opts = qemu_opts_create(create_opts, NULL, 0, &error_abort);
275
+ amend_opts = qemu_opts_append(amend_opts, bs->drv->amend_opts);
276
+ opts = qemu_opts_create(amend_opts, NULL, 0, &error_abort);
277
qemu_opts_do_parse(opts, options, NULL, &err);
278
if (err) {
279
error_report_err(err);
280
@@ -XXX,XX +XXX,XX @@ out:
281
out_no_progress:
282
blk_unref(blk);
283
qemu_opts_del(opts);
284
- qemu_opts_free(create_opts);
285
+ qemu_opts_free(amend_opts);
286
g_free(options);
287
288
if (ret) {
289
--
207
--
290
2.26.2
208
2.41.0
291
292
diff view generated by jsdifflib
Deleted patch
1
From: Maxim Levitsky <mlevitsk@redhat.com>
2
1
3
Some qcow2 create options can't be used for amend.
4
Remove them from the qcow2 create options and add generic logic to detect
5
such options in qemu-img
6
7
Signed-off-by: Maxim Levitsky <mlevitsk@redhat.com>
8
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
9
Message-Id: <20200608094030.670121-6-mlevitsk@redhat.com>
10
[mreitz: Dropped some iotests reference output hunks that became
11
unnecessary thanks to
12
"iotests: Make _filter_img_create more active"]
13
Signed-off-by: Max Reitz <mreitz@redhat.com>
14
---
15
block/qcow2.c | 138 +++++++++-----------------------
16
qemu-img.c | 18 ++++-
17
tests/qemu-iotests/049.out | 102 ++++++++++++------------
18
tests/qemu-iotests/061.out | 12 ++-
19
tests/qemu-iotests/082.out | 158 ++++---------------------------------
20
tests/qemu-iotests/085.out | 38 ++++-----
21
tests/qemu-iotests/144.out | 4 +-
22
tests/qemu-iotests/182.out | 2 +-
23
tests/qemu-iotests/185.out | 8 +-
24
tests/qemu-iotests/255.out | 8 +-
25
tests/qemu-iotests/274.out | 46 +++++------
26
tests/qemu-iotests/280.out | 2 +-
27
12 files changed, 183 insertions(+), 353 deletions(-)
28
29
diff --git a/block/qcow2.c b/block/qcow2.c
30
index XXXXXXX..XXXXXXX 100644
31
--- a/block/qcow2.c
32
+++ b/block/qcow2.c
33
@@ -XXX,XX +XXX,XX @@ static int qcow2_change_backing_file(BlockDriverState *bs,
34
return qcow2_update_header(bs);
35
}
36
37
-static int qcow2_crypt_method_from_format(const char *encryptfmt)
38
-{
39
- if (g_str_equal(encryptfmt, "luks")) {
40
- return QCOW_CRYPT_LUKS;
41
- } else if (g_str_equal(encryptfmt, "aes")) {
42
- return QCOW_CRYPT_AES;
43
- } else {
44
- return -EINVAL;
45
- }
46
-}
47
-
48
static int qcow2_set_up_encryption(BlockDriverState *bs,
49
QCryptoBlockCreateOptions *cryptoopts,
50
Error **errp)
51
@@ -XXX,XX +XXX,XX @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
52
bool lazy_refcounts = s->use_lazy_refcounts;
53
bool data_file_raw = data_file_is_raw(bs);
54
const char *compat = NULL;
55
- uint64_t cluster_size = s->cluster_size;
56
- bool encrypt;
57
- int encformat;
58
int refcount_bits = s->refcount_bits;
59
int ret;
60
QemuOptDesc *desc = opts->list->desc;
61
@@ -XXX,XX +XXX,XX @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
62
error_setg(errp, "Unknown compatibility level %s", compat);
63
return -EINVAL;
64
}
65
- } else if (!strcmp(desc->name, BLOCK_OPT_PREALLOC)) {
66
- error_setg(errp, "Cannot change preallocation mode");
67
- return -ENOTSUP;
68
} else if (!strcmp(desc->name, BLOCK_OPT_SIZE)) {
69
new_size = qemu_opt_get_size(opts, BLOCK_OPT_SIZE, 0);
70
} else if (!strcmp(desc->name, BLOCK_OPT_BACKING_FILE)) {
71
backing_file = qemu_opt_get(opts, BLOCK_OPT_BACKING_FILE);
72
} else if (!strcmp(desc->name, BLOCK_OPT_BACKING_FMT)) {
73
backing_format = qemu_opt_get(opts, BLOCK_OPT_BACKING_FMT);
74
- } else if (!strcmp(desc->name, BLOCK_OPT_ENCRYPT)) {
75
- encrypt = qemu_opt_get_bool(opts, BLOCK_OPT_ENCRYPT,
76
- !!s->crypto);
77
-
78
- if (encrypt != !!s->crypto) {
79
- error_setg(errp,
80
- "Changing the encryption flag is not supported");
81
- return -ENOTSUP;
82
- }
83
- } else if (!strcmp(desc->name, BLOCK_OPT_ENCRYPT_FORMAT)) {
84
- encformat = qcow2_crypt_method_from_format(
85
- qemu_opt_get(opts, BLOCK_OPT_ENCRYPT_FORMAT));
86
-
87
- if (encformat != s->crypt_method_header) {
88
- error_setg(errp,
89
- "Changing the encryption format is not supported");
90
- return -ENOTSUP;
91
- }
92
- } else if (g_str_has_prefix(desc->name, "encrypt.")) {
93
- error_setg(errp,
94
- "Changing the encryption parameters is not supported");
95
- return -ENOTSUP;
96
- } else if (!strcmp(desc->name, BLOCK_OPT_CLUSTER_SIZE)) {
97
- cluster_size = qemu_opt_get_size(opts, BLOCK_OPT_CLUSTER_SIZE,
98
- cluster_size);
99
- if (cluster_size != s->cluster_size) {
100
- error_setg(errp, "Changing the cluster size is not supported");
101
- return -ENOTSUP;
102
- }
103
} else if (!strcmp(desc->name, BLOCK_OPT_LAZY_REFCOUNTS)) {
104
lazy_refcounts = qemu_opt_get_bool(opts, BLOCK_OPT_LAZY_REFCOUNTS,
105
lazy_refcounts);
106
@@ -XXX,XX +XXX,XX @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
107
"images");
108
return -EINVAL;
109
}
110
- } else if (!strcmp(desc->name, BLOCK_OPT_COMPRESSION_TYPE)) {
111
- const char *ct_name =
112
- qemu_opt_get(opts, BLOCK_OPT_COMPRESSION_TYPE);
113
- int compression_type =
114
- qapi_enum_parse(&Qcow2CompressionType_lookup, ct_name, -1,
115
- NULL);
116
- if (compression_type == -1) {
117
- error_setg(errp, "Unknown compression type: %s", ct_name);
118
- return -ENOTSUP;
119
- }
120
-
121
- if (compression_type != s->compression_type) {
122
- error_setg(errp, "Changing the compression type "
123
- "is not supported");
124
- return -ENOTSUP;
125
- }
126
} else {
127
/* if this point is reached, this probably means a new option was
128
* added without having it covered here */
129
@@ -XXX,XX +XXX,XX @@ void qcow2_signal_corruption(BlockDriverState *bs, bool fatal, int64_t offset,
130
.help = "The external data file must stay valid " \
131
"as a raw image" \
132
}, \
133
- { \
134
- .name = BLOCK_OPT_ENCRYPT, \
135
- .type = QEMU_OPT_BOOL, \
136
- .help = "Encrypt the image with format 'aes'. (Deprecated " \
137
- "in favor of " BLOCK_OPT_ENCRYPT_FORMAT "=aes)", \
138
- }, \
139
- { \
140
- .name = BLOCK_OPT_ENCRYPT_FORMAT, \
141
- .type = QEMU_OPT_STRING, \
142
- .help = "Encrypt the image, format choices: 'aes', 'luks'", \
143
- }, \
144
- BLOCK_CRYPTO_OPT_DEF_KEY_SECRET("encrypt.", \
145
- "ID of secret providing qcow AES key or LUKS passphrase"), \
146
- BLOCK_CRYPTO_OPT_DEF_LUKS_CIPHER_ALG("encrypt."), \
147
- BLOCK_CRYPTO_OPT_DEF_LUKS_CIPHER_MODE("encrypt."), \
148
- BLOCK_CRYPTO_OPT_DEF_LUKS_IVGEN_ALG("encrypt."), \
149
- BLOCK_CRYPTO_OPT_DEF_LUKS_IVGEN_HASH_ALG("encrypt."), \
150
- BLOCK_CRYPTO_OPT_DEF_LUKS_HASH_ALG("encrypt."), \
151
- BLOCK_CRYPTO_OPT_DEF_LUKS_ITER_TIME("encrypt."), \
152
- { \
153
- .name = BLOCK_OPT_CLUSTER_SIZE, \
154
- .type = QEMU_OPT_SIZE, \
155
- .help = "qcow2 cluster size", \
156
- .def_value_str = stringify(DEFAULT_CLUSTER_SIZE) \
157
- }, \
158
- { \
159
- .name = BLOCK_OPT_PREALLOC, \
160
- .type = QEMU_OPT_STRING, \
161
- .help = "Preallocation mode (allowed values: off, " \
162
- "metadata, falloc, full)" \
163
- }, \
164
{ \
165
.name = BLOCK_OPT_LAZY_REFCOUNTS, \
166
.type = QEMU_OPT_BOOL, \
167
@@ -XXX,XX +XXX,XX @@ void qcow2_signal_corruption(BlockDriverState *bs, bool fatal, int64_t offset,
168
.type = QEMU_OPT_NUMBER, \
169
.help = "Width of a reference count entry in bits", \
170
.def_value_str = "16" \
171
- }, \
172
- { \
173
- .name = BLOCK_OPT_COMPRESSION_TYPE, \
174
- .type = QEMU_OPT_STRING, \
175
- .help = "Compression method used for image cluster " \
176
- "compression", \
177
- .def_value_str = "zlib" \
178
}
179
180
static QemuOptsList qcow2_create_opts = {
181
.name = "qcow2-create-opts",
182
.head = QTAILQ_HEAD_INITIALIZER(qcow2_create_opts.head),
183
.desc = {
184
+ { \
185
+ .name = BLOCK_OPT_ENCRYPT, \
186
+ .type = QEMU_OPT_BOOL, \
187
+ .help = "Encrypt the image with format 'aes'. (Deprecated " \
188
+ "in favor of " BLOCK_OPT_ENCRYPT_FORMAT "=aes)", \
189
+ }, \
190
+ { \
191
+ .name = BLOCK_OPT_ENCRYPT_FORMAT, \
192
+ .type = QEMU_OPT_STRING, \
193
+ .help = "Encrypt the image, format choices: 'aes', 'luks'", \
194
+ }, \
195
+ BLOCK_CRYPTO_OPT_DEF_KEY_SECRET("encrypt.", \
196
+ "ID of secret providing qcow AES key or LUKS passphrase"), \
197
+ BLOCK_CRYPTO_OPT_DEF_LUKS_CIPHER_ALG("encrypt."), \
198
+ BLOCK_CRYPTO_OPT_DEF_LUKS_CIPHER_MODE("encrypt."), \
199
+ BLOCK_CRYPTO_OPT_DEF_LUKS_IVGEN_ALG("encrypt."), \
200
+ BLOCK_CRYPTO_OPT_DEF_LUKS_IVGEN_HASH_ALG("encrypt."), \
201
+ BLOCK_CRYPTO_OPT_DEF_LUKS_HASH_ALG("encrypt."), \
202
+ BLOCK_CRYPTO_OPT_DEF_LUKS_ITER_TIME("encrypt."), \
203
+ { \
204
+ .name = BLOCK_OPT_CLUSTER_SIZE, \
205
+ .type = QEMU_OPT_SIZE, \
206
+ .help = "qcow2 cluster size", \
207
+ .def_value_str = stringify(DEFAULT_CLUSTER_SIZE) \
208
+ }, \
209
+ { \
210
+ .name = BLOCK_OPT_PREALLOC, \
211
+ .type = QEMU_OPT_STRING, \
212
+ .help = "Preallocation mode (allowed values: off, " \
213
+ "metadata, falloc, full)" \
214
+ }, \
215
+ { \
216
+ .name = BLOCK_OPT_COMPRESSION_TYPE, \
217
+ .type = QEMU_OPT_STRING, \
218
+ .help = "Compression method used for image cluster " \
219
+ "compression", \
220
+ .def_value_str = "zlib" \
221
+ },
222
QCOW_COMMON_OPTIONS,
223
{ /* end of list */ }
224
}
225
diff --git a/qemu-img.c b/qemu-img.c
226
index XXXXXXX..XXXXXXX 100644
227
--- a/qemu-img.c
228
+++ b/qemu-img.c
229
@@ -XXX,XX +XXX,XX @@ static int print_amend_option_help(const char *format)
230
/* Every driver supporting amendment must have amend_opts */
231
assert(drv->amend_opts);
232
233
- printf("Creation options for '%s':\n", format);
234
+ printf("Amend options for '%s':\n", format);
235
qemu_opts_print_help(drv->amend_opts, false);
236
- printf("\nNote that not all of these options may be amendable.\n");
237
return 0;
238
}
239
240
@@ -XXX,XX +XXX,XX @@ static int img_amend(int argc, char **argv)
241
amend_opts = qemu_opts_append(amend_opts, bs->drv->amend_opts);
242
opts = qemu_opts_create(amend_opts, NULL, 0, &error_abort);
243
qemu_opts_do_parse(opts, options, NULL, &err);
244
+
245
if (err) {
246
+ /* Try to parse options using the create options */
247
+ Error *err1 = NULL;
248
+ amend_opts = qemu_opts_append(amend_opts, bs->drv->create_opts);
249
+ qemu_opts_del(opts);
250
+ opts = qemu_opts_create(amend_opts, NULL, 0, &error_abort);
251
+ qemu_opts_do_parse(opts, options, NULL, &err1);
252
+
253
+ if (!err1) {
254
+ error_append_hint(&err,
255
+ "This option is only supported for image creation\n");
256
+ } else {
257
+ error_free(err1);
258
+ }
259
+
260
error_report_err(err);
261
ret = -1;
262
goto out;
263
diff --git a/tests/qemu-iotests/049.out b/tests/qemu-iotests/049.out
264
index XXXXXXX..XXXXXXX 100644
265
--- a/tests/qemu-iotests/049.out
266
+++ b/tests/qemu-iotests/049.out
267
@@ -XXX,XX +XXX,XX @@ QA output created by 049
268
== 1. Traditional size parameter ==
269
270
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1024
271
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
272
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16
273
274
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1024b
275
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
276
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16
277
278
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1k
279
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
280
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16
281
282
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1K
283
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
284
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16
285
286
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1M
287
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1048576 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
288
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1048576 lazy_refcounts=off refcount_bits=16
289
290
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1G
291
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1073741824 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
292
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1073741824 lazy_refcounts=off refcount_bits=16
293
294
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1T
295
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1099511627776 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
296
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1099511627776 lazy_refcounts=off refcount_bits=16
297
298
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1024.0
299
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
300
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16
301
302
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1024.0b
303
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
304
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16
305
306
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1.5k
307
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1536 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
308
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1536 lazy_refcounts=off refcount_bits=16
309
310
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1.5K
311
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1536 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
312
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1536 lazy_refcounts=off refcount_bits=16
313
314
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1.5M
315
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1572864 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
316
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1572864 lazy_refcounts=off refcount_bits=16
317
318
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1.5G
319
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1610612736 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
320
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1610612736 lazy_refcounts=off refcount_bits=16
321
322
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1.5T
323
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1649267441664 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
324
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1649267441664 lazy_refcounts=off refcount_bits=16
325
326
== 2. Specifying size via -o ==
327
328
qemu-img create -f qcow2 -o size=1024 TEST_DIR/t.qcow2
329
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
330
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16
331
332
qemu-img create -f qcow2 -o size=1024b TEST_DIR/t.qcow2
333
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
334
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16
335
336
qemu-img create -f qcow2 -o size=1k TEST_DIR/t.qcow2
337
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
338
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16
339
340
qemu-img create -f qcow2 -o size=1K TEST_DIR/t.qcow2
341
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
342
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16
343
344
qemu-img create -f qcow2 -o size=1M TEST_DIR/t.qcow2
345
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1048576 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
346
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1048576 lazy_refcounts=off refcount_bits=16
347
348
qemu-img create -f qcow2 -o size=1G TEST_DIR/t.qcow2
349
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1073741824 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
350
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1073741824 lazy_refcounts=off refcount_bits=16
351
352
qemu-img create -f qcow2 -o size=1T TEST_DIR/t.qcow2
353
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1099511627776 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
354
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1099511627776 lazy_refcounts=off refcount_bits=16
355
356
qemu-img create -f qcow2 -o size=1024.0 TEST_DIR/t.qcow2
357
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
358
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16
359
360
qemu-img create -f qcow2 -o size=1024.0b TEST_DIR/t.qcow2
361
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
362
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16
363
364
qemu-img create -f qcow2 -o size=1.5k TEST_DIR/t.qcow2
365
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1536 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
366
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1536 lazy_refcounts=off refcount_bits=16
367
368
qemu-img create -f qcow2 -o size=1.5K TEST_DIR/t.qcow2
369
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1536 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
370
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1536 lazy_refcounts=off refcount_bits=16
371
372
qemu-img create -f qcow2 -o size=1.5M TEST_DIR/t.qcow2
373
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1572864 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
374
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1572864 lazy_refcounts=off refcount_bits=16
375
376
qemu-img create -f qcow2 -o size=1.5G TEST_DIR/t.qcow2
377
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1610612736 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
378
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1610612736 lazy_refcounts=off refcount_bits=16
379
380
qemu-img create -f qcow2 -o size=1.5T TEST_DIR/t.qcow2
381
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1649267441664 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
382
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1649267441664 lazy_refcounts=off refcount_bits=16
383
384
== 3. Invalid sizes ==
385
386
@@ -XXX,XX +XXX,XX @@ qemu-img: TEST_DIR/t.qcow2: The image size must be specified only once
387
== Check correct interpretation of suffixes for cluster size ==
388
389
qemu-img create -f qcow2 -o cluster_size=1024 TEST_DIR/t.qcow2 64M
390
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=1024 lazy_refcounts=off refcount_bits=16 compression_type=zlib
391
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=1024 compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16
392
393
qemu-img create -f qcow2 -o cluster_size=1024b TEST_DIR/t.qcow2 64M
394
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=1024 lazy_refcounts=off refcount_bits=16 compression_type=zlib
395
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=1024 compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16
396
397
qemu-img create -f qcow2 -o cluster_size=1k TEST_DIR/t.qcow2 64M
398
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=1024 lazy_refcounts=off refcount_bits=16 compression_type=zlib
399
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=1024 compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16
400
401
qemu-img create -f qcow2 -o cluster_size=1K TEST_DIR/t.qcow2 64M
402
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=1024 lazy_refcounts=off refcount_bits=16 compression_type=zlib
403
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=1024 compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16
404
405
qemu-img create -f qcow2 -o cluster_size=1M TEST_DIR/t.qcow2 64M
406
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=1048576 lazy_refcounts=off refcount_bits=16 compression_type=zlib
407
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=1048576 compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16
408
409
qemu-img create -f qcow2 -o cluster_size=1024.0 TEST_DIR/t.qcow2 64M
410
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=1024 lazy_refcounts=off refcount_bits=16 compression_type=zlib
411
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=1024 compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16
412
413
qemu-img create -f qcow2 -o cluster_size=1024.0b TEST_DIR/t.qcow2 64M
414
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=1024 lazy_refcounts=off refcount_bits=16 compression_type=zlib
415
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=1024 compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16
416
417
qemu-img create -f qcow2 -o cluster_size=0.5k TEST_DIR/t.qcow2 64M
418
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=512 lazy_refcounts=off refcount_bits=16 compression_type=zlib
419
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=512 compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16
420
421
qemu-img create -f qcow2 -o cluster_size=0.5K TEST_DIR/t.qcow2 64M
422
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=512 lazy_refcounts=off refcount_bits=16 compression_type=zlib
423
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=512 compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16
424
425
qemu-img create -f qcow2 -o cluster_size=0.5M TEST_DIR/t.qcow2 64M
426
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=524288 lazy_refcounts=off refcount_bits=16 compression_type=zlib
427
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=524288 compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16
428
429
== Check compat level option ==
430
431
qemu-img create -f qcow2 -o compat=0.10 TEST_DIR/t.qcow2 64M
432
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=0.10 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
433
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=67108864 compat=0.10 lazy_refcounts=off refcount_bits=16
434
435
qemu-img create -f qcow2 -o compat=1.1 TEST_DIR/t.qcow2 64M
436
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=1.1 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
437
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=67108864 compat=1.1 lazy_refcounts=off refcount_bits=16
438
439
qemu-img create -f qcow2 -o compat=0.42 TEST_DIR/t.qcow2 64M
440
qemu-img: TEST_DIR/t.qcow2: Invalid parameter '0.42'
441
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=0.42 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
442
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=67108864 compat=0.42 lazy_refcounts=off refcount_bits=16
443
444
qemu-img create -f qcow2 -o compat=foobar TEST_DIR/t.qcow2 64M
445
qemu-img: TEST_DIR/t.qcow2: Invalid parameter 'foobar'
446
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=foobar cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
447
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=67108864 compat=foobar lazy_refcounts=off refcount_bits=16
448
449
== Check preallocation option ==
450
451
qemu-img create -f qcow2 -o preallocation=off TEST_DIR/t.qcow2 64M
452
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=65536 preallocation=off lazy_refcounts=off refcount_bits=16 compression_type=zlib
453
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 preallocation=off compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16
454
455
qemu-img create -f qcow2 -o preallocation=metadata TEST_DIR/t.qcow2 64M
456
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=65536 preallocation=metadata lazy_refcounts=off refcount_bits=16 compression_type=zlib
457
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 preallocation=metadata compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16
458
459
qemu-img create -f qcow2 -o preallocation=1234 TEST_DIR/t.qcow2 64M
460
qemu-img: TEST_DIR/t.qcow2: Invalid parameter '1234'
461
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=65536 preallocation=1234 lazy_refcounts=off refcount_bits=16 compression_type=zlib
462
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 preallocation=1234 compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16
463
464
== Check encryption option ==
465
466
qemu-img create -f qcow2 -o encryption=off TEST_DIR/t.qcow2 64M
467
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
468
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 encryption=off cluster_size=65536 compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16
469
470
qemu-img create -f qcow2 --object secret,id=sec0,data=123456 -o encryption=on,encrypt.key-secret=sec0 TEST_DIR/t.qcow2 64M
471
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=on encrypt.key-secret=sec0 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
472
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 encryption=on encrypt.key-secret=sec0 cluster_size=65536 compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16
473
474
== Check lazy_refcounts option (only with v3) ==
475
476
qemu-img create -f qcow2 -o compat=1.1,lazy_refcounts=off TEST_DIR/t.qcow2 64M
477
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=1.1 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
478
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=67108864 compat=1.1 lazy_refcounts=off refcount_bits=16
479
480
qemu-img create -f qcow2 -o compat=1.1,lazy_refcounts=on TEST_DIR/t.qcow2 64M
481
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=1.1 cluster_size=65536 lazy_refcounts=on refcount_bits=16 compression_type=zlib
482
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=67108864 compat=1.1 lazy_refcounts=on refcount_bits=16
483
484
qemu-img create -f qcow2 -o compat=0.10,lazy_refcounts=off TEST_DIR/t.qcow2 64M
485
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=0.10 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
486
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=67108864 compat=0.10 lazy_refcounts=off refcount_bits=16
487
488
qemu-img create -f qcow2 -o compat=0.10,lazy_refcounts=on TEST_DIR/t.qcow2 64M
489
qemu-img: TEST_DIR/t.qcow2: Lazy refcounts only supported with compatibility level 1.1 and above (use version=v3 or greater)
490
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=0.10 cluster_size=65536 lazy_refcounts=on refcount_bits=16 compression_type=zlib
491
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=67108864 compat=0.10 lazy_refcounts=on refcount_bits=16
492
493
*** done
494
diff --git a/tests/qemu-iotests/061.out b/tests/qemu-iotests/061.out
495
index XXXXXXX..XXXXXXX 100644
496
--- a/tests/qemu-iotests/061.out
497
+++ b/tests/qemu-iotests/061.out
498
@@ -XXX,XX +XXX,XX @@ qemu-img: Lazy refcounts only supported with compatibility level 1.1 and above (
499
qemu-img: Lazy refcounts only supported with compatibility level 1.1 and above (use compat=1.1 or greater)
500
qemu-img: Unknown compatibility level 0.42
501
qemu-img: Invalid parameter 'foo'
502
-qemu-img: Changing the cluster size is not supported
503
-qemu-img: Changing the encryption flag is not supported
504
-qemu-img: Cannot change preallocation mode
505
+qemu-img: Invalid parameter 'cluster_size'
506
+This option is only supported for image creation
507
+qemu-img: Invalid parameter 'encryption'
508
+This option is only supported for image creation
509
+qemu-img: Invalid parameter 'preallocation'
510
+This option is only supported for image creation
511
512
=== Testing correct handling of unset value ===
513
514
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
515
Should work:
516
Should not work:
517
-qemu-img: Changing the cluster size is not supported
518
+qemu-img: Invalid parameter 'cluster_size'
519
+This option is only supported for image creation
520
521
=== Testing zero expansion on inactive clusters ===
522
523
diff --git a/tests/qemu-iotests/082.out b/tests/qemu-iotests/082.out
524
index XXXXXXX..XXXXXXX 100644
525
--- a/tests/qemu-iotests/082.out
526
+++ b/tests/qemu-iotests/082.out
527
@@ -XXX,XX +XXX,XX @@ QA output created by 082
528
=== create: Options specified more than once ===
529
530
Testing: create -f foo -f qcow2 TEST_DIR/t.qcow2 128M
531
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
532
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 lazy_refcounts=off refcount_bits=16
533
image: TEST_DIR/t.IMGFMT
534
file format: IMGFMT
535
virtual size: 128 MiB (134217728 bytes)
536
cluster_size: 65536
537
538
Testing: create -f qcow2 -o cluster_size=4k -o lazy_refcounts=on TEST_DIR/t.qcow2 128M
539
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 cluster_size=4096 lazy_refcounts=on refcount_bits=16 compression_type=zlib
540
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=4096 compression_type=zlib size=134217728 lazy_refcounts=on refcount_bits=16
541
image: TEST_DIR/t.IMGFMT
542
file format: IMGFMT
543
virtual size: 128 MiB (134217728 bytes)
544
@@ -XXX,XX +XXX,XX @@ Format specific information:
545
corrupt: false
546
547
Testing: create -f qcow2 -o cluster_size=4k -o lazy_refcounts=on -o cluster_size=8k TEST_DIR/t.qcow2 128M
548
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 cluster_size=8192 lazy_refcounts=on refcount_bits=16 compression_type=zlib
549
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=8192 compression_type=zlib size=134217728 lazy_refcounts=on refcount_bits=16
550
image: TEST_DIR/t.IMGFMT
551
file format: IMGFMT
552
virtual size: 128 MiB (134217728 bytes)
553
@@ -XXX,XX +XXX,XX @@ Format specific information:
554
corrupt: false
555
556
Testing: create -f qcow2 -o cluster_size=4k,cluster_size=8k TEST_DIR/t.qcow2 128M
557
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 cluster_size=8192 lazy_refcounts=off refcount_bits=16 compression_type=zlib
558
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=8192 compression_type=zlib size=134217728 lazy_refcounts=off refcount_bits=16
559
image: TEST_DIR/t.IMGFMT
560
file format: IMGFMT
561
virtual size: 128 MiB (134217728 bytes)
562
@@ -XXX,XX +XXX,XX @@ Supported options:
563
size=<size> - Virtual disk size
564
565
Testing: create -f qcow2 -u -o backing_file=TEST_DIR/t.qcow2,,help TEST_DIR/t.qcow2 128M
566
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/t.qcow2,,help cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
567
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/t.qcow2,,help lazy_refcounts=off refcount_bits=16
568
569
Testing: create -f qcow2 -u -o backing_file=TEST_DIR/t.qcow2,,? TEST_DIR/t.qcow2 128M
570
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/t.qcow2,,? cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
571
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/t.qcow2,,? lazy_refcounts=off refcount_bits=16
572
573
Testing: create -f qcow2 -o backing_file=TEST_DIR/t.qcow2, -o help TEST_DIR/t.qcow2 128M
574
qemu-img: Invalid option list: backing_file=TEST_DIR/t.qcow2,
575
@@ -XXX,XX +XXX,XX @@ qemu-img: Format driver 'bochs' does not support image creation
576
=== convert: Options specified more than once ===
577
578
Testing: create -f qcow2 TEST_DIR/t.qcow2 128M
579
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
580
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 lazy_refcounts=off refcount_bits=16
581
582
Testing: convert -f foo -f qcow2 TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base
583
image: TEST_DIR/t.IMGFMT.base
584
@@ -XXX,XX +XXX,XX @@ cluster_size: 65536
585
=== amend: help for -o ===
586
587
Testing: amend -f qcow2 -o help TEST_DIR/t.qcow2
588
-Creation options for 'qcow2':
589
+Amend options for 'qcow2':
590
backing_file=<str> - File name of a base image
591
backing_fmt=<str> - Image format of the base image
592
- cluster_size=<size> - qcow2 cluster size
593
compat=<str> - Compatibility level (v2 [0.10] or v3 [1.1])
594
- compression_type=<str> - Compression method used for image cluster compression
595
data_file=<str> - File name of an external data file
596
data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image
597
- encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
598
- encrypt.cipher-mode=<str> - Name of encryption cipher mode
599
- encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
600
- encrypt.hash-alg=<str> - Name of encryption hash algorithm
601
- encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
602
- encrypt.ivgen-alg=<str> - Name of IV generator algorithm
603
- encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
604
- encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
605
- encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
606
lazy_refcounts=<bool (on/off)> - Postpone refcount updates
607
- preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
608
refcount_bits=<num> - Width of a reference count entry in bits
609
size=<size> - Virtual disk size
610
611
-Note that not all of these options may be amendable.
612
-
613
Testing: amend -f qcow2 -o ? TEST_DIR/t.qcow2
614
-Creation options for 'qcow2':
615
+Amend options for 'qcow2':
616
backing_file=<str> - File name of a base image
617
backing_fmt=<str> - Image format of the base image
618
- cluster_size=<size> - qcow2 cluster size
619
compat=<str> - Compatibility level (v2 [0.10] or v3 [1.1])
620
- compression_type=<str> - Compression method used for image cluster compression
621
data_file=<str> - File name of an external data file
622
data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image
623
- encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
624
- encrypt.cipher-mode=<str> - Name of encryption cipher mode
625
- encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
626
- encrypt.hash-alg=<str> - Name of encryption hash algorithm
627
- encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
628
- encrypt.ivgen-alg=<str> - Name of IV generator algorithm
629
- encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
630
- encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
631
- encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
632
lazy_refcounts=<bool (on/off)> - Postpone refcount updates
633
- preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
634
refcount_bits=<num> - Width of a reference count entry in bits
635
size=<size> - Virtual disk size
636
637
-Note that not all of these options may be amendable.
638
-
639
Testing: amend -f qcow2 -o cluster_size=4k,help TEST_DIR/t.qcow2
640
-Creation options for 'qcow2':
641
+Amend options for 'qcow2':
642
backing_file=<str> - File name of a base image
643
backing_fmt=<str> - Image format of the base image
644
- cluster_size=<size> - qcow2 cluster size
645
compat=<str> - Compatibility level (v2 [0.10] or v3 [1.1])
646
- compression_type=<str> - Compression method used for image cluster compression
647
data_file=<str> - File name of an external data file
648
data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image
649
- encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
650
- encrypt.cipher-mode=<str> - Name of encryption cipher mode
651
- encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
652
- encrypt.hash-alg=<str> - Name of encryption hash algorithm
653
- encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
654
- encrypt.ivgen-alg=<str> - Name of IV generator algorithm
655
- encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
656
- encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
657
- encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
658
lazy_refcounts=<bool (on/off)> - Postpone refcount updates
659
- preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
660
refcount_bits=<num> - Width of a reference count entry in bits
661
size=<size> - Virtual disk size
662
663
-Note that not all of these options may be amendable.
664
-
665
Testing: amend -f qcow2 -o cluster_size=4k,? TEST_DIR/t.qcow2
666
-Creation options for 'qcow2':
667
+Amend options for 'qcow2':
668
backing_file=<str> - File name of a base image
669
backing_fmt=<str> - Image format of the base image
670
- cluster_size=<size> - qcow2 cluster size
671
compat=<str> - Compatibility level (v2 [0.10] or v3 [1.1])
672
- compression_type=<str> - Compression method used for image cluster compression
673
data_file=<str> - File name of an external data file
674
data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image
675
- encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
676
- encrypt.cipher-mode=<str> - Name of encryption cipher mode
677
- encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
678
- encrypt.hash-alg=<str> - Name of encryption hash algorithm
679
- encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
680
- encrypt.ivgen-alg=<str> - Name of IV generator algorithm
681
- encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
682
- encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
683
- encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
684
lazy_refcounts=<bool (on/off)> - Postpone refcount updates
685
- preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
686
refcount_bits=<num> - Width of a reference count entry in bits
687
size=<size> - Virtual disk size
688
689
-Note that not all of these options may be amendable.
690
-
691
Testing: amend -f qcow2 -o help,cluster_size=4k TEST_DIR/t.qcow2
692
-Creation options for 'qcow2':
693
+Amend options for 'qcow2':
694
backing_file=<str> - File name of a base image
695
backing_fmt=<str> - Image format of the base image
696
- cluster_size=<size> - qcow2 cluster size
697
compat=<str> - Compatibility level (v2 [0.10] or v3 [1.1])
698
- compression_type=<str> - Compression method used for image cluster compression
699
data_file=<str> - File name of an external data file
700
data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image
701
- encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
702
- encrypt.cipher-mode=<str> - Name of encryption cipher mode
703
- encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
704
- encrypt.hash-alg=<str> - Name of encryption hash algorithm
705
- encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
706
- encrypt.ivgen-alg=<str> - Name of IV generator algorithm
707
- encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
708
- encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
709
- encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
710
lazy_refcounts=<bool (on/off)> - Postpone refcount updates
711
- preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
712
refcount_bits=<num> - Width of a reference count entry in bits
713
size=<size> - Virtual disk size
714
715
-Note that not all of these options may be amendable.
716
-
717
Testing: amend -f qcow2 -o ?,cluster_size=4k TEST_DIR/t.qcow2
718
-Creation options for 'qcow2':
719
+Amend options for 'qcow2':
720
backing_file=<str> - File name of a base image
721
backing_fmt=<str> - Image format of the base image
722
- cluster_size=<size> - qcow2 cluster size
723
compat=<str> - Compatibility level (v2 [0.10] or v3 [1.1])
724
- compression_type=<str> - Compression method used for image cluster compression
725
data_file=<str> - File name of an external data file
726
data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image
727
- encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
728
- encrypt.cipher-mode=<str> - Name of encryption cipher mode
729
- encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
730
- encrypt.hash-alg=<str> - Name of encryption hash algorithm
731
- encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
732
- encrypt.ivgen-alg=<str> - Name of IV generator algorithm
733
- encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
734
- encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
735
- encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
736
lazy_refcounts=<bool (on/off)> - Postpone refcount updates
737
- preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
738
refcount_bits=<num> - Width of a reference count entry in bits
739
size=<size> - Virtual disk size
740
741
-Note that not all of these options may be amendable.
742
-
743
Testing: amend -f qcow2 -o cluster_size=4k -o help TEST_DIR/t.qcow2
744
-Creation options for 'qcow2':
745
+Amend options for 'qcow2':
746
backing_file=<str> - File name of a base image
747
backing_fmt=<str> - Image format of the base image
748
- cluster_size=<size> - qcow2 cluster size
749
compat=<str> - Compatibility level (v2 [0.10] or v3 [1.1])
750
- compression_type=<str> - Compression method used for image cluster compression
751
data_file=<str> - File name of an external data file
752
data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image
753
- encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
754
- encrypt.cipher-mode=<str> - Name of encryption cipher mode
755
- encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
756
- encrypt.hash-alg=<str> - Name of encryption hash algorithm
757
- encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
758
- encrypt.ivgen-alg=<str> - Name of IV generator algorithm
759
- encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
760
- encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
761
- encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
762
lazy_refcounts=<bool (on/off)> - Postpone refcount updates
763
- preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
764
refcount_bits=<num> - Width of a reference count entry in bits
765
size=<size> - Virtual disk size
766
767
-Note that not all of these options may be amendable.
768
-
769
Testing: amend -f qcow2 -o cluster_size=4k -o ? TEST_DIR/t.qcow2
770
-Creation options for 'qcow2':
771
+Amend options for 'qcow2':
772
backing_file=<str> - File name of a base image
773
backing_fmt=<str> - Image format of the base image
774
- cluster_size=<size> - qcow2 cluster size
775
compat=<str> - Compatibility level (v2 [0.10] or v3 [1.1])
776
- compression_type=<str> - Compression method used for image cluster compression
777
data_file=<str> - File name of an external data file
778
data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image
779
- encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
780
- encrypt.cipher-mode=<str> - Name of encryption cipher mode
781
- encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
782
- encrypt.hash-alg=<str> - Name of encryption hash algorithm
783
- encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
784
- encrypt.ivgen-alg=<str> - Name of IV generator algorithm
785
- encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
786
- encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
787
- encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
788
lazy_refcounts=<bool (on/off)> - Postpone refcount updates
789
- preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
790
refcount_bits=<num> - Width of a reference count entry in bits
791
size=<size> - Virtual disk size
792
793
-Note that not all of these options may be amendable.
794
-
795
Testing: amend -f qcow2 -o backing_file=TEST_DIR/t.qcow2,,help TEST_DIR/t.qcow2
796
797
Testing: rebase -u -b -f qcow2 TEST_DIR/t.qcow2
798
@@ -XXX,XX +XXX,XX @@ Testing: amend -f qcow2 -o backing_file=TEST_DIR/t.qcow2 -o ,, -o help TEST_DIR/
799
qemu-img: Invalid option list: ,,
800
801
Testing: amend -f qcow2 -o help
802
-Creation options for 'qcow2':
803
+Amend options for 'qcow2':
804
backing_file=<str> - File name of a base image
805
backing_fmt=<str> - Image format of the base image
806
- cluster_size=<size> - qcow2 cluster size
807
compat=<str> - Compatibility level (v2 [0.10] or v3 [1.1])
808
- compression_type=<str> - Compression method used for image cluster compression
809
data_file=<str> - File name of an external data file
810
data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image
811
- encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
812
- encrypt.cipher-mode=<str> - Name of encryption cipher mode
813
- encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
814
- encrypt.hash-alg=<str> - Name of encryption hash algorithm
815
- encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
816
- encrypt.ivgen-alg=<str> - Name of IV generator algorithm
817
- encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
818
- encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
819
- encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
820
lazy_refcounts=<bool (on/off)> - Postpone refcount updates
821
- preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
822
refcount_bits=<num> - Width of a reference count entry in bits
823
size=<size> - Virtual disk size
824
825
-Note that not all of these options may be amendable.
826
-
827
Testing: amend -o help
828
qemu-img: Expecting one image file name
829
830
diff --git a/tests/qemu-iotests/085.out b/tests/qemu-iotests/085.out
831
index XXXXXXX..XXXXXXX 100644
832
--- a/tests/qemu-iotests/085.out
833
+++ b/tests/qemu-iotests/085.out
834
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT.2', fmt=IMGFMT size=134217728
835
=== Create a single snapshot on virtio0 ===
836
837
{ 'execute': 'blockdev-snapshot-sync', 'arguments': { 'device': 'virtio0', 'snapshot-file':'TEST_DIR/1-snapshot-v0.IMGFMT', 'format': 'IMGFMT' } }
838
-Formatting 'TEST_DIR/1-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/t.qcow2.1 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
839
+Formatting 'TEST_DIR/1-snapshot-v0.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/t.qcow2.1 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
840
{"return": {}}
841
842
=== Invalid command - missing device and nodename ===
843
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/1-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file
844
=== Create several transactional group snapshots ===
845
846
{ 'execute': 'transaction', 'arguments': {'actions': [ { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio0', 'snapshot-file': 'TEST_DIR/2-snapshot-v0.IMGFMT' } }, { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio1', 'snapshot-file': 'TEST_DIR/2-snapshot-v1.IMGFMT' } } ] } }
847
-Formatting 'TEST_DIR/2-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/1-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
848
-Formatting 'TEST_DIR/2-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/t.qcow2.2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
849
+Formatting 'TEST_DIR/2-snapshot-v0.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/1-snapshot-v0.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
850
+Formatting 'TEST_DIR/2-snapshot-v1.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/t.qcow2.2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
851
{"return": {}}
852
{ 'execute': 'transaction', 'arguments': {'actions': [ { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio0', 'snapshot-file': 'TEST_DIR/3-snapshot-v0.IMGFMT' } }, { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio1', 'snapshot-file': 'TEST_DIR/3-snapshot-v1.IMGFMT' } } ] } }
853
-Formatting 'TEST_DIR/3-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/2-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
854
-Formatting 'TEST_DIR/3-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/2-snapshot-v1.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
855
+Formatting 'TEST_DIR/3-snapshot-v0.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/2-snapshot-v0.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
856
+Formatting 'TEST_DIR/3-snapshot-v1.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/2-snapshot-v1.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
857
{"return": {}}
858
{ 'execute': 'transaction', 'arguments': {'actions': [ { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio0', 'snapshot-file': 'TEST_DIR/4-snapshot-v0.IMGFMT' } }, { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio1', 'snapshot-file': 'TEST_DIR/4-snapshot-v1.IMGFMT' } } ] } }
859
-Formatting 'TEST_DIR/4-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/3-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
860
-Formatting 'TEST_DIR/4-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/3-snapshot-v1.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
861
+Formatting 'TEST_DIR/4-snapshot-v0.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/3-snapshot-v0.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
862
+Formatting 'TEST_DIR/4-snapshot-v1.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/3-snapshot-v1.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
863
{"return": {}}
864
{ 'execute': 'transaction', 'arguments': {'actions': [ { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio0', 'snapshot-file': 'TEST_DIR/5-snapshot-v0.IMGFMT' } }, { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio1', 'snapshot-file': 'TEST_DIR/5-snapshot-v1.IMGFMT' } } ] } }
865
-Formatting 'TEST_DIR/5-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/4-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
866
-Formatting 'TEST_DIR/5-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/4-snapshot-v1.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
867
+Formatting 'TEST_DIR/5-snapshot-v0.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/4-snapshot-v0.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
868
+Formatting 'TEST_DIR/5-snapshot-v1.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/4-snapshot-v1.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
869
{"return": {}}
870
{ 'execute': 'transaction', 'arguments': {'actions': [ { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio0', 'snapshot-file': 'TEST_DIR/6-snapshot-v0.IMGFMT' } }, { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio1', 'snapshot-file': 'TEST_DIR/6-snapshot-v1.IMGFMT' } } ] } }
871
-Formatting 'TEST_DIR/6-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/5-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
872
-Formatting 'TEST_DIR/6-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/5-snapshot-v1.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
873
+Formatting 'TEST_DIR/6-snapshot-v0.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/5-snapshot-v0.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
874
+Formatting 'TEST_DIR/6-snapshot-v1.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/5-snapshot-v1.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
875
{"return": {}}
876
{ 'execute': 'transaction', 'arguments': {'actions': [ { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio0', 'snapshot-file': 'TEST_DIR/7-snapshot-v0.IMGFMT' } }, { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio1', 'snapshot-file': 'TEST_DIR/7-snapshot-v1.IMGFMT' } } ] } }
877
-Formatting 'TEST_DIR/7-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/6-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
878
-Formatting 'TEST_DIR/7-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/6-snapshot-v1.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
879
+Formatting 'TEST_DIR/7-snapshot-v0.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/6-snapshot-v0.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
880
+Formatting 'TEST_DIR/7-snapshot-v1.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/6-snapshot-v1.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
881
{"return": {}}
882
{ 'execute': 'transaction', 'arguments': {'actions': [ { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio0', 'snapshot-file': 'TEST_DIR/8-snapshot-v0.IMGFMT' } }, { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio1', 'snapshot-file': 'TEST_DIR/8-snapshot-v1.IMGFMT' } } ] } }
883
-Formatting 'TEST_DIR/8-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/7-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
884
-Formatting 'TEST_DIR/8-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/7-snapshot-v1.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
885
+Formatting 'TEST_DIR/8-snapshot-v0.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/7-snapshot-v0.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
886
+Formatting 'TEST_DIR/8-snapshot-v1.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/7-snapshot-v1.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
887
{"return": {}}
888
{ 'execute': 'transaction', 'arguments': {'actions': [ { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio0', 'snapshot-file': 'TEST_DIR/9-snapshot-v0.IMGFMT' } }, { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio1', 'snapshot-file': 'TEST_DIR/9-snapshot-v1.IMGFMT' } } ] } }
889
-Formatting 'TEST_DIR/9-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/8-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
890
-Formatting 'TEST_DIR/9-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/8-snapshot-v1.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
891
+Formatting 'TEST_DIR/9-snapshot-v0.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/8-snapshot-v0.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
892
+Formatting 'TEST_DIR/9-snapshot-v1.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/8-snapshot-v1.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
893
{"return": {}}
894
{ 'execute': 'transaction', 'arguments': {'actions': [ { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio0', 'snapshot-file': 'TEST_DIR/10-snapshot-v0.IMGFMT' } }, { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio1', 'snapshot-file': 'TEST_DIR/10-snapshot-v1.IMGFMT' } } ] } }
895
-Formatting 'TEST_DIR/10-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/9-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
896
-Formatting 'TEST_DIR/10-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/9-snapshot-v1.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
897
+Formatting 'TEST_DIR/10-snapshot-v0.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/9-snapshot-v0.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
898
+Formatting 'TEST_DIR/10-snapshot-v1.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/9-snapshot-v1.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
899
{"return": {}}
900
901
=== Create a couple of snapshots using blockdev-snapshot ===
902
diff --git a/tests/qemu-iotests/144.out b/tests/qemu-iotests/144.out
903
index XXXXXXX..XXXXXXX 100644
904
--- a/tests/qemu-iotests/144.out
905
+++ b/tests/qemu-iotests/144.out
906
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=536870912
907
{ 'execute': 'qmp_capabilities' }
908
{"return": {}}
909
{ 'execute': 'blockdev-snapshot-sync', 'arguments': { 'device': 'virtio0', 'snapshot-file':'TEST_DIR/tmp.IMGFMT', 'format': 'IMGFMT' } }
910
-Formatting 'TEST_DIR/tmp.qcow2', fmt=qcow2 size=536870912 backing_file=TEST_DIR/t.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
911
+Formatting 'TEST_DIR/tmp.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=536870912 backing_file=TEST_DIR/t.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
912
{"return": {}}
913
914
=== Performing block-commit on active layer ===
915
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/tmp.qcow2', fmt=qcow2 size=536870912 backing_file=TEST_DIR/
916
=== Performing Live Snapshot 2 ===
917
918
{ 'execute': 'blockdev-snapshot-sync', 'arguments': { 'device': 'virtio0', 'snapshot-file':'TEST_DIR/tmp2.IMGFMT', 'format': 'IMGFMT' } }
919
-Formatting 'TEST_DIR/tmp2.qcow2', fmt=qcow2 size=536870912 backing_file=TEST_DIR/t.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
920
+Formatting 'TEST_DIR/tmp2.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=536870912 backing_file=TEST_DIR/t.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
921
{"return": {}}
922
*** done
923
diff --git a/tests/qemu-iotests/182.out b/tests/qemu-iotests/182.out
924
index XXXXXXX..XXXXXXX 100644
925
--- a/tests/qemu-iotests/182.out
926
+++ b/tests/qemu-iotests/182.out
927
@@ -XXX,XX +XXX,XX @@ Is another process using the image [TEST_DIR/t.qcow2]?
928
{'execute': 'blockdev-add', 'arguments': { 'node-name': 'node0', 'driver': 'file', 'filename': 'TEST_DIR/t.IMGFMT', 'locking': 'on' } }
929
{"return": {}}
930
{'execute': 'blockdev-snapshot-sync', 'arguments': { 'node-name': 'node0', 'snapshot-file': 'TEST_DIR/t.IMGFMT.overlay', 'snapshot-node-name': 'node1' } }
931
-Formatting 'TEST_DIR/t.qcow2.overlay', fmt=qcow2 size=197120 backing_file=TEST_DIR/t.qcow2 backing_fmt=file cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
932
+Formatting 'TEST_DIR/t.qcow2.overlay', fmt=qcow2 cluster_size=65536 compression_type=zlib size=197120 backing_file=TEST_DIR/t.qcow2 backing_fmt=file lazy_refcounts=off refcount_bits=16
933
{"return": {}}
934
{'execute': 'blockdev-add', 'arguments': { 'node-name': 'node1', 'driver': 'file', 'filename': 'TEST_DIR/t.IMGFMT', 'locking': 'on' } }
935
{"return": {}}
936
diff --git a/tests/qemu-iotests/185.out b/tests/qemu-iotests/185.out
937
index XXXXXXX..XXXXXXX 100644
938
--- a/tests/qemu-iotests/185.out
939
+++ b/tests/qemu-iotests/185.out
940
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864
941
=== Creating backing chain ===
942
943
{ 'execute': 'blockdev-snapshot-sync', 'arguments': { 'device': 'disk', 'snapshot-file': 'TEST_DIR/t.IMGFMT.mid', 'format': 'IMGFMT', 'mode': 'absolute-paths' } }
944
-Formatting 'TEST_DIR/t.qcow2.mid', fmt=qcow2 size=67108864 backing_file=TEST_DIR/t.qcow2.base backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
945
+Formatting 'TEST_DIR/t.qcow2.mid', fmt=qcow2 cluster_size=65536 compression_type=zlib size=67108864 backing_file=TEST_DIR/t.qcow2.base backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
946
{"return": {}}
947
{ 'execute': 'human-monitor-command', 'arguments': { 'command-line': 'qemu-io disk "write 0 4M"' } }
948
wrote 4194304/4194304 bytes at offset 0
949
4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
950
{"return": ""}
951
{ 'execute': 'blockdev-snapshot-sync', 'arguments': { 'device': 'disk', 'snapshot-file': 'TEST_DIR/t.IMGFMT', 'format': 'IMGFMT', 'mode': 'absolute-paths' } }
952
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 backing_file=TEST_DIR/t.qcow2.mid backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
953
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=67108864 backing_file=TEST_DIR/t.qcow2.mid backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
954
{"return": {}}
955
956
=== Start commit job and exit qemu ===
957
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 backing_file=TEST_DIR/t.q
958
{ 'execute': 'qmp_capabilities' }
959
{"return": {}}
960
{ 'execute': 'drive-mirror', 'arguments': { 'device': 'disk', 'target': 'TEST_DIR/t.IMGFMT.copy', 'format': 'IMGFMT', 'sync': 'full', 'speed': 65536 } }
961
-Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 size=67108864 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
962
+Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 cluster_size=65536 compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16
963
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "disk"}}
964
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "disk"}}
965
{"return": {}}
966
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 size=67108864 cluster_size=65536 l
967
{ 'execute': 'qmp_capabilities' }
968
{"return": {}}
969
{ 'execute': 'drive-backup', 'arguments': { 'device': 'disk', 'target': 'TEST_DIR/t.IMGFMT.copy', 'format': 'IMGFMT', 'sync': 'full', 'speed': 65536 } }
970
-Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 size=67108864 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
971
+Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 cluster_size=65536 compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16
972
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "disk"}}
973
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "disk"}}
974
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "paused", "id": "disk"}}
975
diff --git a/tests/qemu-iotests/255.out b/tests/qemu-iotests/255.out
976
index XXXXXXX..XXXXXXX 100644
977
--- a/tests/qemu-iotests/255.out
978
+++ b/tests/qemu-iotests/255.out
979
@@ -XXX,XX +XXX,XX @@ Finishing a commit job with background reads
980
981
=== Create backing chain and start VM ===
982
983
-Formatting 'TEST_DIR/PID-t.qcow2.mid', fmt=qcow2 size=134217728 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
984
+Formatting 'TEST_DIR/PID-t.qcow2.mid', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 lazy_refcounts=off refcount_bits=16
985
986
-Formatting 'TEST_DIR/PID-t.qcow2', fmt=qcow2 size=134217728 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
987
+Formatting 'TEST_DIR/PID-t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 lazy_refcounts=off refcount_bits=16
988
989
=== Start background read requests ===
990
991
@@ -XXX,XX +XXX,XX @@ Closing the VM while a job is being cancelled
992
993
=== Create images and start VM ===
994
995
-Formatting 'TEST_DIR/PID-src.qcow2', fmt=qcow2 size=134217728 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
996
+Formatting 'TEST_DIR/PID-src.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 lazy_refcounts=off refcount_bits=16
997
998
-Formatting 'TEST_DIR/PID-dst.qcow2', fmt=qcow2 size=134217728 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
999
+Formatting 'TEST_DIR/PID-dst.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 lazy_refcounts=off refcount_bits=16
1000
1001
wrote 1048576/1048576 bytes at offset 0
1002
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1003
diff --git a/tests/qemu-iotests/274.out b/tests/qemu-iotests/274.out
1004
index XXXXXXX..XXXXXXX 100644
1005
--- a/tests/qemu-iotests/274.out
1006
+++ b/tests/qemu-iotests/274.out
1007
@@ -XXX,XX +XXX,XX @@
1008
== Commit tests ==
1009
-Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=2097152 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
1010
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 compression_type=zlib size=2097152 lazy_refcounts=off refcount_bits=16
1011
1012
-Formatting 'TEST_DIR/PID-mid', fmt=qcow2 size=1048576 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
1013
+Formatting 'TEST_DIR/PID-mid', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1048576 backing_file=TEST_DIR/PID-base lazy_refcounts=off refcount_bits=16
1014
1015
-Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=2097152 backing_file=TEST_DIR/PID-mid cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
1016
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 compression_type=zlib size=2097152 backing_file=TEST_DIR/PID-mid lazy_refcounts=off refcount_bits=16
1017
1018
wrote 2097152/2097152 bytes at offset 0
1019
2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1020
@@ -XXX,XX +XXX,XX @@ read 1048576/1048576 bytes at offset 1048576
1021
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1022
1023
=== Testing HMP commit (top -> mid) ===
1024
-Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=2097152 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
1025
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 compression_type=zlib size=2097152 lazy_refcounts=off refcount_bits=16
1026
1027
-Formatting 'TEST_DIR/PID-mid', fmt=qcow2 size=1048576 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
1028
+Formatting 'TEST_DIR/PID-mid', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1048576 backing_file=TEST_DIR/PID-base lazy_refcounts=off refcount_bits=16
1029
1030
-Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=2097152 backing_file=TEST_DIR/PID-mid cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
1031
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 compression_type=zlib size=2097152 backing_file=TEST_DIR/PID-mid lazy_refcounts=off refcount_bits=16
1032
1033
wrote 2097152/2097152 bytes at offset 0
1034
2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1035
@@ -XXX,XX +XXX,XX @@ read 1048576/1048576 bytes at offset 1048576
1036
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1037
1038
=== Testing QMP active commit (top -> mid) ===
1039
-Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=2097152 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
1040
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 compression_type=zlib size=2097152 lazy_refcounts=off refcount_bits=16
1041
1042
-Formatting 'TEST_DIR/PID-mid', fmt=qcow2 size=1048576 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
1043
+Formatting 'TEST_DIR/PID-mid', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1048576 backing_file=TEST_DIR/PID-base lazy_refcounts=off refcount_bits=16
1044
1045
-Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=2097152 backing_file=TEST_DIR/PID-mid cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
1046
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 compression_type=zlib size=2097152 backing_file=TEST_DIR/PID-mid lazy_refcounts=off refcount_bits=16
1047
1048
wrote 2097152/2097152 bytes at offset 0
1049
2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1050
@@ -XXX,XX +XXX,XX @@ read 1048576/1048576 bytes at offset 1048576
1051
1052
== Resize tests ==
1053
=== preallocation=off ===
1054
-Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=6442450944 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
1055
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 compression_type=zlib size=6442450944 lazy_refcounts=off refcount_bits=16
1056
1057
-Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=1073741824 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
1058
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1073741824 backing_file=TEST_DIR/PID-base lazy_refcounts=off refcount_bits=16
1059
1060
wrote 65536/65536 bytes at offset 5368709120
1061
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1062
@@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 5368709120
1063
{ "start": 1073741824, "length": 7516192768, "depth": 0, "zero": true, "data": false}]
1064
1065
=== preallocation=metadata ===
1066
-Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=34359738368 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
1067
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 compression_type=zlib size=34359738368 lazy_refcounts=off refcount_bits=16
1068
1069
-Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=32212254720 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
1070
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 compression_type=zlib size=32212254720 backing_file=TEST_DIR/PID-base lazy_refcounts=off refcount_bits=16
1071
1072
wrote 65536/65536 bytes at offset 33285996544
1073
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1074
@@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 33285996544
1075
{ "start": 34896609280, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 2685075456}]
1076
1077
=== preallocation=falloc ===
1078
-Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=10485760 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
1079
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 compression_type=zlib size=10485760 lazy_refcounts=off refcount_bits=16
1080
1081
-Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=5242880 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
1082
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 compression_type=zlib size=5242880 backing_file=TEST_DIR/PID-base lazy_refcounts=off refcount_bits=16
1083
1084
wrote 65536/65536 bytes at offset 9437184
1085
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1086
@@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 9437184
1087
{ "start": 5242880, "length": 10485760, "depth": 0, "zero": false, "data": true, "offset": 327680}]
1088
1089
=== preallocation=full ===
1090
-Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=16777216 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
1091
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 compression_type=zlib size=16777216 lazy_refcounts=off refcount_bits=16
1092
1093
-Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=8388608 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
1094
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 compression_type=zlib size=8388608 backing_file=TEST_DIR/PID-base lazy_refcounts=off refcount_bits=16
1095
1096
wrote 65536/65536 bytes at offset 11534336
1097
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1098
@@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 11534336
1099
{ "start": 8388608, "length": 4194304, "depth": 0, "zero": false, "data": true, "offset": 327680}]
1100
1101
=== preallocation=off ===
1102
-Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=393216 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
1103
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 compression_type=zlib size=393216 lazy_refcounts=off refcount_bits=16
1104
1105
-Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=259072 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
1106
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 compression_type=zlib size=259072 backing_file=TEST_DIR/PID-base lazy_refcounts=off refcount_bits=16
1107
1108
wrote 65536/65536 bytes at offset 259072
1109
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1110
@@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 259072
1111
{ "start": 262144, "length": 262144, "depth": 0, "zero": true, "data": false}]
1112
1113
=== preallocation=off ===
1114
-Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=409600 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
1115
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 compression_type=zlib size=409600 lazy_refcounts=off refcount_bits=16
1116
1117
-Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=262144 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
1118
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 compression_type=zlib size=262144 backing_file=TEST_DIR/PID-base lazy_refcounts=off refcount_bits=16
1119
1120
wrote 65536/65536 bytes at offset 344064
1121
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1122
@@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 344064
1123
{ "start": 262144, "length": 262144, "depth": 0, "zero": true, "data": false}]
1124
1125
=== preallocation=off ===
1126
-Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=524288 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
1127
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 compression_type=zlib size=524288 lazy_refcounts=off refcount_bits=16
1128
1129
-Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=262144 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
1130
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 compression_type=zlib size=262144 backing_file=TEST_DIR/PID-base lazy_refcounts=off refcount_bits=16
1131
1132
wrote 65536/65536 bytes at offset 446464
1133
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1134
diff --git a/tests/qemu-iotests/280.out b/tests/qemu-iotests/280.out
1135
index XXXXXXX..XXXXXXX 100644
1136
--- a/tests/qemu-iotests/280.out
1137
+++ b/tests/qemu-iotests/280.out
1138
@@ -XXX,XX +XXX,XX @@
1139
-Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=67108864 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib
1140
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16
1141
1142
=== Launch VM ===
1143
Enabling migration QMP events on VM...
1144
--
1145
2.26.2
1146
1147
diff view generated by jsdifflib
Deleted patch
1
From: Maxim Levitsky <mlevitsk@redhat.com>
2
1
3
rename the write_func to create_write_func, and init_func to create_init_func.
4
This is preparation for other write_func that will be used to update the encryption keys.
5
6
No functional changes
7
8
Signed-off-by: Maxim Levitsky <mlevitsk@redhat.com>
9
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
10
Message-Id: <20200608094030.670121-7-mlevitsk@redhat.com>
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
12
---
13
block/crypto.c | 25 ++++++++++++-------------
14
1 file changed, 12 insertions(+), 13 deletions(-)
15
16
diff --git a/block/crypto.c b/block/crypto.c
17
index XXXXXXX..XXXXXXX 100644
18
--- a/block/crypto.c
19
+++ b/block/crypto.c
20
@@ -XXX,XX +XXX,XX @@ struct BlockCryptoCreateData {
21
};
22
23
24
-static ssize_t block_crypto_write_func(QCryptoBlock *block,
25
- size_t offset,
26
- const uint8_t *buf,
27
- size_t buflen,
28
- void *opaque,
29
- Error **errp)
30
+static ssize_t block_crypto_create_write_func(QCryptoBlock *block,
31
+ size_t offset,
32
+ const uint8_t *buf,
33
+ size_t buflen,
34
+ void *opaque,
35
+ Error **errp)
36
{
37
struct BlockCryptoCreateData *data = opaque;
38
ssize_t ret;
39
@@ -XXX,XX +XXX,XX @@ static ssize_t block_crypto_write_func(QCryptoBlock *block,
40
return ret;
41
}
42
43
-
44
-static ssize_t block_crypto_init_func(QCryptoBlock *block,
45
- size_t headerlen,
46
- void *opaque,
47
- Error **errp)
48
+static ssize_t block_crypto_create_init_func(QCryptoBlock *block,
49
+ size_t headerlen,
50
+ void *opaque,
51
+ Error **errp)
52
{
53
struct BlockCryptoCreateData *data = opaque;
54
Error *local_error = NULL;
55
@@ -XXX,XX +XXX,XX @@ static int block_crypto_co_create_generic(BlockDriverState *bs,
56
};
57
58
crypto = qcrypto_block_create(opts, NULL,
59
- block_crypto_init_func,
60
- block_crypto_write_func,
61
+ block_crypto_create_init_func,
62
+ block_crypto_create_write_func,
63
&data,
64
errp);
65
66
--
67
2.26.2
68
69
diff view generated by jsdifflib
Deleted patch
1
From: Maxim Levitsky <mlevitsk@redhat.com>
2
1
3
This implements the encryption key management using the generic code in
4
qcrypto layer and exposes it to the user via qemu-img
5
6
This code adds another 'write_func' because the initialization
7
write_func works directly on the underlying file, and amend
8
works on instance of luks device.
9
10
This commit also adds a 'hack/workaround' I and Kevin Wolf (thanks)
11
made to make the driver both support write sharing (to avoid breaking the users),
12
and be safe against concurrent metadata update (the keyslots)
13
14
Eventually the write sharing for luks driver will be deprecated
15
and removed together with this hack.
16
17
The hack is that we ask (as a format driver) for BLK_PERM_CONSISTENT_READ
18
and then when we want to update the keys, we unshare that permission.
19
So if someone else has the image open, even readonly, encryption
20
key update will fail gracefully.
21
22
Also thanks to Daniel Berrange for the idea of
23
unsharing read, rather that write permission which allows
24
to avoid cases when the other user had opened the image read-only.
25
26
Signed-off-by: Maxim Levitsky <mlevitsk@redhat.com>
27
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
28
Reviewed-by: Max Reitz <mreitz@redhat.com>
29
Message-Id: <20200608094030.670121-8-mlevitsk@redhat.com>
30
Signed-off-by: Max Reitz <mreitz@redhat.com>
31
---
32
block/crypto.h | 34 +++++++++++++
33
block/crypto.c | 130 +++++++++++++++++++++++++++++++++++++++++++++++--
34
2 files changed, 161 insertions(+), 3 deletions(-)
35
36
diff --git a/block/crypto.h b/block/crypto.h
37
index XXXXXXX..XXXXXXX 100644
38
--- a/block/crypto.h
39
+++ b/block/crypto.h
40
@@ -XXX,XX +XXX,XX @@
41
#define BLOCK_CRYPTO_OPT_LUKS_IVGEN_HASH_ALG "ivgen-hash-alg"
42
#define BLOCK_CRYPTO_OPT_LUKS_HASH_ALG "hash-alg"
43
#define BLOCK_CRYPTO_OPT_LUKS_ITER_TIME "iter-time"
44
+#define BLOCK_CRYPTO_OPT_LUKS_KEYSLOT "keyslot"
45
+#define BLOCK_CRYPTO_OPT_LUKS_STATE "state"
46
+#define BLOCK_CRYPTO_OPT_LUKS_OLD_SECRET "old-secret"
47
+#define BLOCK_CRYPTO_OPT_LUKS_NEW_SECRET "new-secret"
48
+
49
50
#define BLOCK_CRYPTO_OPT_DEF_LUKS_KEY_SECRET(prefix) \
51
BLOCK_CRYPTO_OPT_DEF_KEY_SECRET(prefix, \
52
@@ -XXX,XX +XXX,XX @@
53
.help = "Time to spend in PBKDF in milliseconds", \
54
}
55
56
+#define BLOCK_CRYPTO_OPT_DEF_LUKS_STATE(prefix) \
57
+ { \
58
+ .name = prefix BLOCK_CRYPTO_OPT_LUKS_STATE, \
59
+ .type = QEMU_OPT_STRING, \
60
+ .help = "Select new state of affected keyslots (active/inactive)",\
61
+ }
62
+
63
+#define BLOCK_CRYPTO_OPT_DEF_LUKS_KEYSLOT(prefix) \
64
+ { \
65
+ .name = prefix BLOCK_CRYPTO_OPT_LUKS_KEYSLOT, \
66
+ .type = QEMU_OPT_NUMBER, \
67
+ .help = "Select a single keyslot to modify explicitly",\
68
+ }
69
+
70
+#define BLOCK_CRYPTO_OPT_DEF_LUKS_OLD_SECRET(prefix) \
71
+ { \
72
+ .name = prefix BLOCK_CRYPTO_OPT_LUKS_OLD_SECRET, \
73
+ .type = QEMU_OPT_STRING, \
74
+ .help = "Select all keyslots that match this password", \
75
+ }
76
+
77
+#define BLOCK_CRYPTO_OPT_DEF_LUKS_NEW_SECRET(prefix) \
78
+ { \
79
+ .name = prefix BLOCK_CRYPTO_OPT_LUKS_NEW_SECRET, \
80
+ .type = QEMU_OPT_STRING, \
81
+ .help = "New secret to set in the matching keyslots. " \
82
+ "Empty string to erase", \
83
+ }
84
+
85
QCryptoBlockCreateOptions *
86
block_crypto_create_opts_init(QDict *opts, Error **errp);
87
88
diff --git a/block/crypto.c b/block/crypto.c
89
index XXXXXXX..XXXXXXX 100644
90
--- a/block/crypto.c
91
+++ b/block/crypto.c
92
@@ -XXX,XX +XXX,XX @@ typedef struct BlockCrypto BlockCrypto;
93
94
struct BlockCrypto {
95
QCryptoBlock *block;
96
+ bool updating_keys;
97
};
98
99
100
@@ -XXX,XX +XXX,XX @@ static ssize_t block_crypto_read_func(QCryptoBlock *block,
101
return ret;
102
}
103
104
+static ssize_t block_crypto_write_func(QCryptoBlock *block,
105
+ size_t offset,
106
+ const uint8_t *buf,
107
+ size_t buflen,
108
+ void *opaque,
109
+ Error **errp)
110
+{
111
+ BlockDriverState *bs = opaque;
112
+ ssize_t ret;
113
+
114
+ ret = bdrv_pwrite(bs->file, offset, buf, buflen);
115
+ if (ret < 0) {
116
+ error_setg_errno(errp, -ret, "Could not write encryption header");
117
+ return ret;
118
+ }
119
+ return ret;
120
+}
121
+
122
123
struct BlockCryptoCreateData {
124
BlockBackend *blk;
125
@@ -XXX,XX +XXX,XX @@ static QemuOptsList block_crypto_create_opts_luks = {
126
};
127
128
129
+static QemuOptsList block_crypto_amend_opts_luks = {
130
+ .name = "crypto",
131
+ .head = QTAILQ_HEAD_INITIALIZER(block_crypto_create_opts_luks.head),
132
+ .desc = {
133
+ BLOCK_CRYPTO_OPT_DEF_LUKS_STATE(""),
134
+ BLOCK_CRYPTO_OPT_DEF_LUKS_KEYSLOT(""),
135
+ BLOCK_CRYPTO_OPT_DEF_LUKS_OLD_SECRET(""),
136
+ BLOCK_CRYPTO_OPT_DEF_LUKS_NEW_SECRET(""),
137
+ BLOCK_CRYPTO_OPT_DEF_LUKS_ITER_TIME(""),
138
+ { /* end of list */ }
139
+ },
140
+};
141
+
142
QCryptoBlockOpenOptions *
143
block_crypto_open_opts_init(QDict *opts, Error **errp)
144
{
145
@@ -XXX,XX +XXX,XX @@ block_crypto_get_specific_info_luks(BlockDriverState *bs, Error **errp)
146
return spec_info;
147
}
148
149
+static int
150
+block_crypto_amend_options_luks(BlockDriverState *bs,
151
+ QemuOpts *opts,
152
+ BlockDriverAmendStatusCB *status_cb,
153
+ void *cb_opaque,
154
+ bool force,
155
+ Error **errp)
156
+{
157
+ BlockCrypto *crypto = bs->opaque;
158
+ QDict *cryptoopts = NULL;
159
+ QCryptoBlockAmendOptions *amend_options = NULL;
160
+ int ret;
161
+
162
+ assert(crypto);
163
+ assert(crypto->block);
164
+ crypto->updating_keys = true;
165
+
166
+ ret = bdrv_child_refresh_perms(bs, bs->file, errp);
167
+ if (ret < 0) {
168
+ goto cleanup;
169
+ }
170
+
171
+ cryptoopts = qemu_opts_to_qdict(opts, NULL);
172
+ qdict_put_str(cryptoopts, "format", "luks");
173
+ amend_options = block_crypto_amend_opts_init(cryptoopts, errp);
174
+ if (!amend_options) {
175
+ ret = -EINVAL;
176
+ goto cleanup;
177
+ }
178
+
179
+ ret = qcrypto_block_amend_options(crypto->block,
180
+ block_crypto_read_func,
181
+ block_crypto_write_func,
182
+ bs,
183
+ amend_options,
184
+ force,
185
+ errp);
186
+cleanup:
187
+ crypto->updating_keys = false;
188
+ bdrv_child_refresh_perms(bs, bs->file, errp);
189
+ qapi_free_QCryptoBlockAmendOptions(amend_options);
190
+ qobject_unref(cryptoopts);
191
+ return ret;
192
+}
193
+
194
+
195
+static void
196
+block_crypto_child_perms(BlockDriverState *bs, BdrvChild *c,
197
+ const BdrvChildRole role,
198
+ BlockReopenQueue *reopen_queue,
199
+ uint64_t perm, uint64_t shared,
200
+ uint64_t *nperm, uint64_t *nshared)
201
+{
202
+
203
+ BlockCrypto *crypto = bs->opaque;
204
+
205
+ bdrv_default_perms(bs, c, role, reopen_queue, perm, shared, nperm, nshared);
206
+
207
+ /*
208
+ * For backward compatibility, manually share the write
209
+ * and resize permission
210
+ */
211
+ *nshared |= (BLK_PERM_WRITE | BLK_PERM_RESIZE);
212
+ /*
213
+ * Since we are not fully a format driver, don't always request
214
+ * the read/resize permission but only when explicitly
215
+ * requested
216
+ */
217
+ *nperm &= ~(BLK_PERM_WRITE | BLK_PERM_RESIZE);
218
+ *nperm |= perm & (BLK_PERM_WRITE | BLK_PERM_RESIZE);
219
+
220
+ /*
221
+ * This driver doesn't modify LUKS metadata except
222
+ * when updating the encryption slots.
223
+ * Thus unlike a proper format driver we don't ask for
224
+ * shared write/read permission. However we need it
225
+ * when we are updating the keys, to ensure that only we
226
+ * have access to the device.
227
+ *
228
+ * Encryption update will set the crypto->updating_keys
229
+ * during that period and refresh permissions
230
+ *
231
+ */
232
+ if (crypto->updating_keys) {
233
+ /* need exclusive write access for header update */
234
+ *nperm |= BLK_PERM_WRITE;
235
+ /* unshare read and write permission */
236
+ *nshared &= ~(BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE);
237
+ }
238
+}
239
+
240
+
241
static const char *const block_crypto_strong_runtime_opts[] = {
242
BLOCK_CRYPTO_OPT_LUKS_KEY_SECRET,
243
244
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_crypto_luks = {
245
.bdrv_probe = block_crypto_probe_luks,
246
.bdrv_open = block_crypto_open_luks,
247
.bdrv_close = block_crypto_close,
248
- /* This driver doesn't modify LUKS metadata except when creating image.
249
- * Allow share-rw=on as a special case. */
250
- .bdrv_child_perm = bdrv_default_perms,
251
+ .bdrv_child_perm = block_crypto_child_perms,
252
.bdrv_co_create = block_crypto_co_create_luks,
253
.bdrv_co_create_opts = block_crypto_co_create_opts_luks,
254
.bdrv_co_truncate = block_crypto_co_truncate,
255
.create_opts = &block_crypto_create_opts_luks,
256
+ .amend_opts = &block_crypto_amend_opts_luks,
257
258
.bdrv_reopen_prepare = block_crypto_reopen_prepare,
259
.bdrv_refresh_limits = block_crypto_refresh_limits,
260
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_crypto_luks = {
261
.bdrv_measure = block_crypto_measure,
262
.bdrv_get_info = block_crypto_get_info_luks,
263
.bdrv_get_specific_info = block_crypto_get_specific_info_luks,
264
+ .bdrv_amend_options = block_crypto_amend_options_luks,
265
266
.is_format = true,
267
268
--
269
2.26.2
270
271
diff view generated by jsdifflib
Deleted patch
1
From: Maxim Levitsky <mlevitsk@redhat.com>
2
1
3
Now that we have all the infrastructure in place,
4
wire it in the qcow2 driver and expose this to the user.
5
6
Signed-off-by: Maxim Levitsky <mlevitsk@redhat.com>
7
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
Message-Id: <20200608094030.670121-9-mlevitsk@redhat.com>
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
---
12
block/qcow2.c | 71 +++++++++++++++++++++++++++++++++-----
13
tests/qemu-iotests/082.out | 45 ++++++++++++++++++++++++
14
2 files changed, 107 insertions(+), 9 deletions(-)
15
16
diff --git a/block/qcow2.c b/block/qcow2.c
17
index XXXXXXX..XXXXXXX 100644
18
--- a/block/qcow2.c
19
+++ b/block/qcow2.c
20
@@ -XXX,XX +XXX,XX @@ static ssize_t qcow2_crypto_hdr_write_func(QCryptoBlock *block, size_t offset,
21
return ret;
22
}
23
24
+static QDict*
25
+qcow2_extract_crypto_opts(QemuOpts *opts, const char *fmt, Error **errp)
26
+{
27
+ QDict *cryptoopts_qdict;
28
+ QDict *opts_qdict;
29
+
30
+ /* Extract "encrypt." options into a qdict */
31
+ opts_qdict = qemu_opts_to_qdict(opts, NULL);
32
+ qdict_extract_subqdict(opts_qdict, &cryptoopts_qdict, "encrypt.");
33
+ qobject_unref(opts_qdict);
34
+ qdict_put_str(cryptoopts_qdict, "format", fmt);
35
+ return cryptoopts_qdict;
36
+}
37
38
/*
39
* read qcow2 extension and fill bs
40
@@ -XXX,XX +XXX,XX @@ static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs,
41
42
if (has_luks) {
43
g_autoptr(QCryptoBlockCreateOptions) create_opts = NULL;
44
- QDict *opts_qdict;
45
- QDict *cryptoopts;
46
+ QDict *cryptoopts = qcow2_extract_crypto_opts(opts, "luks", errp);
47
size_t headerlen;
48
49
- opts_qdict = qemu_opts_to_qdict(opts, NULL);
50
- qdict_extract_subqdict(opts_qdict, &cryptoopts, "encrypt.");
51
- qobject_unref(opts_qdict);
52
-
53
- qdict_put_str(cryptoopts, "format", "luks");
54
-
55
create_opts = block_crypto_create_opts_init(cryptoopts, errp);
56
qobject_unref(cryptoopts);
57
if (!create_opts) {
58
@@ -XXX,XX +XXX,XX @@ typedef enum Qcow2AmendOperation {
59
QCOW2_NO_OPERATION = 0,
60
61
QCOW2_UPGRADING,
62
+ QCOW2_UPDATING_ENCRYPTION,
63
QCOW2_CHANGING_REFCOUNT_ORDER,
64
QCOW2_DOWNGRADING,
65
} Qcow2AmendOperation;
66
@@ -XXX,XX +XXX,XX @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
67
int ret;
68
QemuOptDesc *desc = opts->list->desc;
69
Qcow2AmendHelperCBInfo helper_cb_info;
70
+ bool encryption_update = false;
71
72
while (desc && desc->name) {
73
if (!qemu_opt_find(opts, desc->name)) {
74
@@ -XXX,XX +XXX,XX @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
75
backing_file = qemu_opt_get(opts, BLOCK_OPT_BACKING_FILE);
76
} else if (!strcmp(desc->name, BLOCK_OPT_BACKING_FMT)) {
77
backing_format = qemu_opt_get(opts, BLOCK_OPT_BACKING_FMT);
78
+ } else if (g_str_has_prefix(desc->name, "encrypt.")) {
79
+ if (!s->crypto) {
80
+ error_setg(errp,
81
+ "Can't amend encryption options - encryption not present");
82
+ return -EINVAL;
83
+ }
84
+ if (s->crypt_method_header != QCOW_CRYPT_LUKS) {
85
+ error_setg(errp,
86
+ "Only LUKS encryption options can be amended");
87
+ return -ENOTSUP;
88
+ }
89
+ encryption_update = true;
90
} else if (!strcmp(desc->name, BLOCK_OPT_LAZY_REFCOUNTS)) {
91
lazy_refcounts = qemu_opt_get_bool(opts, BLOCK_OPT_LAZY_REFCOUNTS,
92
lazy_refcounts);
93
@@ -XXX,XX +XXX,XX @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
94
.original_status_cb = status_cb,
95
.original_cb_opaque = cb_opaque,
96
.total_operations = (new_version != old_version)
97
- + (s->refcount_bits != refcount_bits)
98
+ + (s->refcount_bits != refcount_bits) +
99
+ (encryption_update == true)
100
};
101
102
/* Upgrade first (some features may require compat=1.1) */
103
@@ -XXX,XX +XXX,XX @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
104
}
105
}
106
107
+ if (encryption_update) {
108
+ QDict *amend_opts_dict;
109
+ QCryptoBlockAmendOptions *amend_opts;
110
+
111
+ helper_cb_info.current_operation = QCOW2_UPDATING_ENCRYPTION;
112
+ amend_opts_dict = qcow2_extract_crypto_opts(opts, "luks", errp);
113
+ if (!amend_opts_dict) {
114
+ return -EINVAL;
115
+ }
116
+ amend_opts = block_crypto_amend_opts_init(amend_opts_dict, errp);
117
+ qobject_unref(amend_opts_dict);
118
+ if (!amend_opts) {
119
+ return -EINVAL;
120
+ }
121
+ ret = qcrypto_block_amend_options(s->crypto,
122
+ qcow2_crypto_hdr_read_func,
123
+ qcow2_crypto_hdr_write_func,
124
+ bs,
125
+ amend_opts,
126
+ force,
127
+ errp);
128
+ qapi_free_QCryptoBlockAmendOptions(amend_opts);
129
+ if (ret < 0) {
130
+ return ret;
131
+ }
132
+ }
133
+
134
if (s->refcount_bits != refcount_bits) {
135
int refcount_order = ctz32(refcount_bits);
136
137
@@ -XXX,XX +XXX,XX @@ static QemuOptsList qcow2_amend_opts = {
138
.name = "qcow2-amend-opts",
139
.head = QTAILQ_HEAD_INITIALIZER(qcow2_amend_opts.head),
140
.desc = {
141
+ BLOCK_CRYPTO_OPT_DEF_LUKS_STATE("encrypt."),
142
+ BLOCK_CRYPTO_OPT_DEF_LUKS_KEYSLOT("encrypt."),
143
+ BLOCK_CRYPTO_OPT_DEF_LUKS_OLD_SECRET("encrypt."),
144
+ BLOCK_CRYPTO_OPT_DEF_LUKS_NEW_SECRET("encrypt."),
145
+ BLOCK_CRYPTO_OPT_DEF_LUKS_ITER_TIME("encrypt."),
146
QCOW_COMMON_OPTIONS,
147
{ /* end of list */ }
148
}
149
diff --git a/tests/qemu-iotests/082.out b/tests/qemu-iotests/082.out
150
index XXXXXXX..XXXXXXX 100644
151
--- a/tests/qemu-iotests/082.out
152
+++ b/tests/qemu-iotests/082.out
153
@@ -XXX,XX +XXX,XX @@ Amend options for 'qcow2':
154
compat=<str> - Compatibility level (v2 [0.10] or v3 [1.1])
155
data_file=<str> - File name of an external data file
156
data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image
157
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
158
+ encrypt.keyslot=<num> - Select a single keyslot to modify explicitly
159
+ encrypt.new-secret=<str> - New secret to set in the matching keyslots. Empty string to erase
160
+ encrypt.old-secret=<str> - Select all keyslots that match this password
161
+ encrypt.state=<str> - Select new state of affected keyslots (active/inactive)
162
lazy_refcounts=<bool (on/off)> - Postpone refcount updates
163
refcount_bits=<num> - Width of a reference count entry in bits
164
size=<size> - Virtual disk size
165
@@ -XXX,XX +XXX,XX @@ Amend options for 'qcow2':
166
compat=<str> - Compatibility level (v2 [0.10] or v3 [1.1])
167
data_file=<str> - File name of an external data file
168
data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image
169
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
170
+ encrypt.keyslot=<num> - Select a single keyslot to modify explicitly
171
+ encrypt.new-secret=<str> - New secret to set in the matching keyslots. Empty string to erase
172
+ encrypt.old-secret=<str> - Select all keyslots that match this password
173
+ encrypt.state=<str> - Select new state of affected keyslots (active/inactive)
174
lazy_refcounts=<bool (on/off)> - Postpone refcount updates
175
refcount_bits=<num> - Width of a reference count entry in bits
176
size=<size> - Virtual disk size
177
@@ -XXX,XX +XXX,XX @@ Amend options for 'qcow2':
178
compat=<str> - Compatibility level (v2 [0.10] or v3 [1.1])
179
data_file=<str> - File name of an external data file
180
data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image
181
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
182
+ encrypt.keyslot=<num> - Select a single keyslot to modify explicitly
183
+ encrypt.new-secret=<str> - New secret to set in the matching keyslots. Empty string to erase
184
+ encrypt.old-secret=<str> - Select all keyslots that match this password
185
+ encrypt.state=<str> - Select new state of affected keyslots (active/inactive)
186
lazy_refcounts=<bool (on/off)> - Postpone refcount updates
187
refcount_bits=<num> - Width of a reference count entry in bits
188
size=<size> - Virtual disk size
189
@@ -XXX,XX +XXX,XX @@ Amend options for 'qcow2':
190
compat=<str> - Compatibility level (v2 [0.10] or v3 [1.1])
191
data_file=<str> - File name of an external data file
192
data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image
193
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
194
+ encrypt.keyslot=<num> - Select a single keyslot to modify explicitly
195
+ encrypt.new-secret=<str> - New secret to set in the matching keyslots. Empty string to erase
196
+ encrypt.old-secret=<str> - Select all keyslots that match this password
197
+ encrypt.state=<str> - Select new state of affected keyslots (active/inactive)
198
lazy_refcounts=<bool (on/off)> - Postpone refcount updates
199
refcount_bits=<num> - Width of a reference count entry in bits
200
size=<size> - Virtual disk size
201
@@ -XXX,XX +XXX,XX @@ Amend options for 'qcow2':
202
compat=<str> - Compatibility level (v2 [0.10] or v3 [1.1])
203
data_file=<str> - File name of an external data file
204
data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image
205
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
206
+ encrypt.keyslot=<num> - Select a single keyslot to modify explicitly
207
+ encrypt.new-secret=<str> - New secret to set in the matching keyslots. Empty string to erase
208
+ encrypt.old-secret=<str> - Select all keyslots that match this password
209
+ encrypt.state=<str> - Select new state of affected keyslots (active/inactive)
210
lazy_refcounts=<bool (on/off)> - Postpone refcount updates
211
refcount_bits=<num> - Width of a reference count entry in bits
212
size=<size> - Virtual disk size
213
@@ -XXX,XX +XXX,XX @@ Amend options for 'qcow2':
214
compat=<str> - Compatibility level (v2 [0.10] or v3 [1.1])
215
data_file=<str> - File name of an external data file
216
data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image
217
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
218
+ encrypt.keyslot=<num> - Select a single keyslot to modify explicitly
219
+ encrypt.new-secret=<str> - New secret to set in the matching keyslots. Empty string to erase
220
+ encrypt.old-secret=<str> - Select all keyslots that match this password
221
+ encrypt.state=<str> - Select new state of affected keyslots (active/inactive)
222
lazy_refcounts=<bool (on/off)> - Postpone refcount updates
223
refcount_bits=<num> - Width of a reference count entry in bits
224
size=<size> - Virtual disk size
225
@@ -XXX,XX +XXX,XX @@ Amend options for 'qcow2':
226
compat=<str> - Compatibility level (v2 [0.10] or v3 [1.1])
227
data_file=<str> - File name of an external data file
228
data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image
229
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
230
+ encrypt.keyslot=<num> - Select a single keyslot to modify explicitly
231
+ encrypt.new-secret=<str> - New secret to set in the matching keyslots. Empty string to erase
232
+ encrypt.old-secret=<str> - Select all keyslots that match this password
233
+ encrypt.state=<str> - Select new state of affected keyslots (active/inactive)
234
lazy_refcounts=<bool (on/off)> - Postpone refcount updates
235
refcount_bits=<num> - Width of a reference count entry in bits
236
size=<size> - Virtual disk size
237
@@ -XXX,XX +XXX,XX @@ Amend options for 'qcow2':
238
compat=<str> - Compatibility level (v2 [0.10] or v3 [1.1])
239
data_file=<str> - File name of an external data file
240
data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image
241
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
242
+ encrypt.keyslot=<num> - Select a single keyslot to modify explicitly
243
+ encrypt.new-secret=<str> - New secret to set in the matching keyslots. Empty string to erase
244
+ encrypt.old-secret=<str> - Select all keyslots that match this password
245
+ encrypt.state=<str> - Select new state of affected keyslots (active/inactive)
246
lazy_refcounts=<bool (on/off)> - Postpone refcount updates
247
refcount_bits=<num> - Width of a reference count entry in bits
248
size=<size> - Virtual disk size
249
@@ -XXX,XX +XXX,XX @@ Amend options for 'qcow2':
250
compat=<str> - Compatibility level (v2 [0.10] or v3 [1.1])
251
data_file=<str> - File name of an external data file
252
data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image
253
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
254
+ encrypt.keyslot=<num> - Select a single keyslot to modify explicitly
255
+ encrypt.new-secret=<str> - New secret to set in the matching keyslots. Empty string to erase
256
+ encrypt.old-secret=<str> - Select all keyslots that match this password
257
+ encrypt.state=<str> - Select new state of affected keyslots (active/inactive)
258
lazy_refcounts=<bool (on/off)> - Postpone refcount updates
259
refcount_bits=<num> - Width of a reference count entry in bits
260
size=<size> - Virtual disk size
261
--
262
2.26.2
263
264
diff view generated by jsdifflib
Deleted patch
1
From: Maxim Levitsky <mlevitsk@redhat.com>
2
1
3
Signed-off-by: Maxim Levitsky <mlevitsk@redhat.com>
4
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
5
Reviewed-by: Max Reitz <mreitz@redhat.com>
6
Message-Id: <20200608094030.670121-13-mlevitsk@redhat.com>
7
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
---
9
qapi/block-core.json | 14 ++++++++-
10
block/crypto.c | 72 ++++++++++++++++++++++++++++++++------------
11
2 files changed, 66 insertions(+), 20 deletions(-)
12
13
diff --git a/qapi/block-core.json b/qapi/block-core.json
14
index XXXXXXX..XXXXXXX 100644
15
--- a/qapi/block-core.json
16
+++ b/qapi/block-core.json
17
@@ -XXX,XX +XXX,XX @@
18
'data': { 'job-id': 'str',
19
'options': 'BlockdevCreateOptions' } }
20
21
+##
22
+# @BlockdevAmendOptionsLUKS:
23
+#
24
+# Driver specific image amend options for LUKS.
25
+#
26
+# Since: 5.1
27
+##
28
+{ 'struct': 'BlockdevAmendOptionsLUKS',
29
+ 'base': 'QCryptoBlockAmendOptionsLUKS',
30
+ 'data': { }
31
+}
32
+
33
##
34
# @BlockdevAmendOptions:
35
#
36
@@ -XXX,XX +XXX,XX @@
37
'driver': 'BlockdevDriver' },
38
'discriminator': 'driver',
39
'data': {
40
- } }
41
+ 'luks': 'BlockdevAmendOptionsLUKS' } }
42
43
##
44
# @x-blockdev-amend:
45
diff --git a/block/crypto.c b/block/crypto.c
46
index XXXXXXX..XXXXXXX 100644
47
--- a/block/crypto.c
48
+++ b/block/crypto.c
49
@@ -XXX,XX +XXX,XX @@ block_crypto_get_specific_info_luks(BlockDriverState *bs, Error **errp)
50
}
51
52
static int
53
-block_crypto_amend_options_luks(BlockDriverState *bs,
54
- QemuOpts *opts,
55
- BlockDriverAmendStatusCB *status_cb,
56
- void *cb_opaque,
57
- bool force,
58
- Error **errp)
59
+block_crypto_amend_options_generic_luks(BlockDriverState *bs,
60
+ QCryptoBlockAmendOptions *amend_options,
61
+ bool force,
62
+ Error **errp)
63
{
64
BlockCrypto *crypto = bs->opaque;
65
- QDict *cryptoopts = NULL;
66
- QCryptoBlockAmendOptions *amend_options = NULL;
67
int ret;
68
69
assert(crypto);
70
assert(crypto->block);
71
- crypto->updating_keys = true;
72
73
+ /* apply for exclusive read/write permissions to the underlying file*/
74
+ crypto->updating_keys = true;
75
ret = bdrv_child_refresh_perms(bs, bs->file, errp);
76
- if (ret < 0) {
77
- goto cleanup;
78
- }
79
-
80
- cryptoopts = qemu_opts_to_qdict(opts, NULL);
81
- qdict_put_str(cryptoopts, "format", "luks");
82
- amend_options = block_crypto_amend_opts_init(cryptoopts, errp);
83
- if (!amend_options) {
84
- ret = -EINVAL;
85
+ if (ret) {
86
goto cleanup;
87
}
88
89
@@ -XXX,XX +XXX,XX @@ block_crypto_amend_options_luks(BlockDriverState *bs,
90
force,
91
errp);
92
cleanup:
93
+ /* release exclusive read/write permissions to the underlying file*/
94
crypto->updating_keys = false;
95
bdrv_child_refresh_perms(bs, bs->file, errp);
96
- qapi_free_QCryptoBlockAmendOptions(amend_options);
97
+ return ret;
98
+}
99
+
100
+static int
101
+block_crypto_amend_options_luks(BlockDriverState *bs,
102
+ QemuOpts *opts,
103
+ BlockDriverAmendStatusCB *status_cb,
104
+ void *cb_opaque,
105
+ bool force,
106
+ Error **errp)
107
+{
108
+ BlockCrypto *crypto = bs->opaque;
109
+ QDict *cryptoopts = NULL;
110
+ QCryptoBlockAmendOptions *amend_options = NULL;
111
+ int ret = -EINVAL;
112
+
113
+ assert(crypto);
114
+ assert(crypto->block);
115
+
116
+ cryptoopts = qemu_opts_to_qdict(opts, NULL);
117
+ qdict_put_str(cryptoopts, "format", "luks");
118
+ amend_options = block_crypto_amend_opts_init(cryptoopts, errp);
119
qobject_unref(cryptoopts);
120
+ if (!amend_options) {
121
+ goto cleanup;
122
+ }
123
+ ret = block_crypto_amend_options_generic_luks(bs, amend_options,
124
+ force, errp);
125
+cleanup:
126
+ qapi_free_QCryptoBlockAmendOptions(amend_options);
127
return ret;
128
}
129
130
+static int
131
+coroutine_fn block_crypto_co_amend_luks(BlockDriverState *bs,
132
+ BlockdevAmendOptions *opts,
133
+ bool force,
134
+ Error **errp)
135
+{
136
+ QCryptoBlockAmendOptions amend_opts;
137
+
138
+ amend_opts = (QCryptoBlockAmendOptions) {
139
+ .format = Q_CRYPTO_BLOCK_FORMAT_LUKS,
140
+ .u.luks = *qapi_BlockdevAmendOptionsLUKS_base(&opts->u.luks),
141
+ };
142
+ return block_crypto_amend_options_generic_luks(bs, &amend_opts,
143
+ force, errp);
144
+}
145
146
static void
147
block_crypto_child_perms(BlockDriverState *bs, BdrvChild *c,
148
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_crypto_luks = {
149
.bdrv_get_info = block_crypto_get_info_luks,
150
.bdrv_get_specific_info = block_crypto_get_specific_info_luks,
151
.bdrv_amend_options = block_crypto_amend_options_luks,
152
+ .bdrv_co_amend = block_crypto_co_amend_luks,
153
154
.is_format = true,
155
156
--
157
2.26.2
158
159
diff view generated by jsdifflib
Deleted patch
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
2
1
3
Commit 96927c744 replaced qdev_init_nofail() call by
4
isa_realize_and_unref() which has a different error
5
message. Update the test output accordingly.
6
7
Gitlab CI error after merging b77b5b3dc7:
8
https://gitlab.com/qemu-project/qemu/-/jobs/597414772#L4375
9
10
Reported-by: Thomas Huth <thuth@redhat.com>
11
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
12
Message-Id: <20200616154949.6586-1-philmd@redhat.com>
13
Reviewed-by: Thomas Huth <thuth@redhat.com>
14
Signed-off-by: Max Reitz <mreitz@redhat.com>
15
---
16
tests/qemu-iotests/051.pc.out | 4 ++--
17
1 file changed, 2 insertions(+), 2 deletions(-)
18
19
diff --git a/tests/qemu-iotests/051.pc.out b/tests/qemu-iotests/051.pc.out
20
index XXXXXXX..XXXXXXX 100644
21
--- a/tests/qemu-iotests/051.pc.out
22
+++ b/tests/qemu-iotests/051.pc.out
23
@@ -XXX,XX +XXX,XX @@ QEMU X.Y.Z monitor - type 'help' for more information
24
25
Testing: -drive if=ide
26
QEMU X.Y.Z monitor - type 'help' for more information
27
-(qemu) QEMU_PROG: Initialization of device ide-hd failed: Device needs media, but drive is empty
28
+(qemu) QEMU_PROG: Device needs media, but drive is empty
29
30
Testing: -drive if=virtio
31
QEMU X.Y.Z monitor - type 'help' for more information
32
@@ -XXX,XX +XXX,XX @@ QEMU X.Y.Z monitor - type 'help' for more information
33
34
Testing: -drive file=TEST_DIR/t.qcow2,if=ide,readonly=on
35
QEMU X.Y.Z monitor - type 'help' for more information
36
-(qemu) QEMU_PROG: Initialization of device ide-hd failed: Block node is read-only
37
+(qemu) QEMU_PROG: Block node is read-only
38
39
Testing: -drive file=TEST_DIR/t.qcow2,if=virtio,readonly=on
40
QEMU X.Y.Z monitor - type 'help' for more information
41
--
42
2.26.2
43
44
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Andrey Drobyshev <andrey.drobyshev@virtuozzo.com>
2
2
3
820c6bee534ec3b added testing of qcow2.py into 291, and it breaks 291
3
Add testcase which checks that allocations during copy-on-read are
4
with external data file. Actually, 291 is bad place for qcow2.py
4
performed on the subcluster basis when subclusters are enabled in target
5
testing, better add a separate test.
5
image.
6
6
7
For now, drop qcow2.py testing from 291 to fix the regression.
7
This testcase also triggers the following assert with previous commit
8
not being applied, so we check that as well:
8
9
9
Fixes: 820c6bee534ec3b
10
qemu-io: ../block/io.c:1236: bdrv_co_do_copy_on_readv: Assertion `skip_bytes < pnum' failed.
10
Reported-by: Max Reitz <mreitz@redhat.com>
11
11
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
12
Message-Id: <20200618154052.8629-1-vsementsov@virtuozzo.com>
13
Reviewed-by: Eric Blake <eblake@redhat.com>
12
Reviewed-by: Eric Blake <eblake@redhat.com>
14
Signed-off-by: Max Reitz <mreitz@redhat.com>
13
Reviewed-by: Denis V. Lunev <den@openvz.org>
14
Signed-off-by: Andrey Drobyshev <andrey.drobyshev@virtuozzo.com>
15
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
16
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
17
Message-ID: <20230711172553.234055-4-andrey.drobyshev@virtuozzo.com>
15
---
18
---
16
tests/qemu-iotests/291 | 4 ----
19
tests/qemu-iotests/197 | 29 +++++++++++++++++++++++++++++
17
tests/qemu-iotests/291.out | 33 ---------------------------------
20
tests/qemu-iotests/197.out | 24 ++++++++++++++++++++++++
18
2 files changed, 37 deletions(-)
21
2 files changed, 53 insertions(+)
19
22
20
diff --git a/tests/qemu-iotests/291 b/tests/qemu-iotests/291
23
diff --git a/tests/qemu-iotests/197 b/tests/qemu-iotests/197
21
index XXXXXXX..XXXXXXX 100755
24
index XXXXXXX..XXXXXXX 100755
22
--- a/tests/qemu-iotests/291
25
--- a/tests/qemu-iotests/197
23
+++ b/tests/qemu-iotests/291
26
+++ b/tests/qemu-iotests/197
24
@@ -XXX,XX +XXX,XX @@ $QEMU_IO -c 'w 1M 1M' -f $IMGFMT "$TEST_IMG" | _filter_qemu_io
27
@@ -XXX,XX +XXX,XX @@ $QEMU_IO -f qcow2 -C -c 'read 0 1024' "$TEST_WRAP" | _filter_qemu_io
25
$QEMU_IMG bitmap --disable -f $IMGFMT "$TEST_IMG" b1
28
$QEMU_IO -f qcow2 -c map "$TEST_WRAP"
26
$QEMU_IMG bitmap --enable -f $IMGFMT "$TEST_IMG" b2
29
_check_test_img
27
$QEMU_IO -c 'w 2M 1M' -f $IMGFMT "$TEST_IMG" | _filter_qemu_io
30
28
-echo "Check resulting qcow2 header extensions:"
31
+echo
29
-$PYTHON qcow2.py "$TEST_IMG" dump-header-exts
32
+echo '=== Copy-on-read with subclusters ==='
30
33
+echo
31
echo
34
+
32
echo "=== Bitmap preservation not possible to non-qcow2 ==="
35
+# Create base and top images 64K (1 cluster) each. Make subclusters enabled
33
@@ -XXX,XX +XXX,XX @@ $QEMU_IMG bitmap --merge tmp -f $IMGFMT "$TEST_IMG" b0
36
+# for the top image
34
$QEMU_IMG bitmap --remove --image-opts \
37
+_make_test_img 64K
35
driver=$IMGFMT,file.driver=file,file.filename="$TEST_IMG" tmp
38
+IMGPROTO=file IMGFMT=qcow2 TEST_IMG_FILE="$TEST_WRAP" \
36
_img_info --format-specific
39
+ _make_test_img --no-opts -o extended_l2=true -F "$IMGFMT" -b "$TEST_IMG" \
37
-echo "Check resulting qcow2 header extensions:"
40
+ 64K | _filter_img_create
38
-$PYTHON qcow2.py "$TEST_IMG" dump-header-exts
41
+
39
42
+$QEMU_IO -c "write -P 0xaa 0 64k" "$TEST_IMG" | _filter_qemu_io
40
echo
43
+
41
echo "=== Check bitmap contents ==="
44
+# Allocate individual subclusters in the top image, and not the whole cluster
42
diff --git a/tests/qemu-iotests/291.out b/tests/qemu-iotests/291.out
45
+$QEMU_IO -c "write -P 0xbb 28K 2K" -c "write -P 0xcc 34K 2K" "$TEST_WRAP" \
46
+ | _filter_qemu_io
47
+
48
+# Only 2 subclusters should be allocated in the top image at this point
49
+$QEMU_IMG map "$TEST_WRAP" | _filter_qemu_img_map
50
+
51
+# Actual copy-on-read operation
52
+$QEMU_IO -C -c "read -P 0xaa 30K 4K" "$TEST_WRAP" | _filter_qemu_io
53
+
54
+# And here we should have 4 subclusters allocated right in the middle of the
55
+# top image. Make sure the whole cluster remains unallocated
56
+$QEMU_IMG map "$TEST_WRAP" | _filter_qemu_img_map
57
+
58
+_check_test_img
59
+
60
# success, all done
61
echo '*** done'
62
status=0
63
diff --git a/tests/qemu-iotests/197.out b/tests/qemu-iotests/197.out
43
index XXXXXXX..XXXXXXX 100644
64
index XXXXXXX..XXXXXXX 100644
44
--- a/tests/qemu-iotests/291.out
65
--- a/tests/qemu-iotests/197.out
45
+++ b/tests/qemu-iotests/291.out
66
+++ b/tests/qemu-iotests/197.out
46
@@ -XXX,XX +XXX,XX @@ wrote 1048576/1048576 bytes at offset 1048576
67
@@ -XXX,XX +XXX,XX @@ read 1024/1024 bytes at offset 0
47
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
68
1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
48
wrote 1048576/1048576 bytes at offset 2097152
69
1 KiB (0x400) bytes allocated at offset 0 bytes (0x0)
49
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
70
No errors were found on the image.
50
-Check resulting qcow2 header extensions:
71
+
51
-Header extension:
72
+=== Copy-on-read with subclusters ===
52
-magic 0xe2792aca (Backing format)
73
+
53
-length 5
74
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=65536
54
-data 'qcow2'
75
+Formatting 'TEST_DIR/t.wrap.IMGFMT', fmt=IMGFMT size=65536 backing_file=TEST_DIR/t.IMGFMT backing_fmt=IMGFMT
55
-
76
+wrote 65536/65536 bytes at offset 0
56
-Header extension:
77
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
57
-magic 0x6803f857 (Feature table)
78
+wrote 2048/2048 bytes at offset 28672
58
-length 336
79
+2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
59
-data <binary>
80
+wrote 2048/2048 bytes at offset 34816
60
-
81
+2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
61
-Header extension:
82
+Offset Length File
62
-magic 0x23852875 (Bitmaps)
83
+0 0x7000 TEST_DIR/t.IMGFMT
63
-length 24
84
+0x7000 0x800 TEST_DIR/t.wrap.IMGFMT
64
-nb_bitmaps 2
85
+0x7800 0x1000 TEST_DIR/t.IMGFMT
65
-reserved32 0
86
+0x8800 0x800 TEST_DIR/t.wrap.IMGFMT
66
-bitmap_directory_size 0x40
87
+0x9000 0x7000 TEST_DIR/t.IMGFMT
67
-bitmap_directory_offset 0x510000
88
+read 4096/4096 bytes at offset 30720
68
-
89
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
69
90
+Offset Length File
70
=== Bitmap preservation not possible to non-qcow2 ===
91
+0 0x7000 TEST_DIR/t.IMGFMT
71
92
+0x7000 0x2000 TEST_DIR/t.wrap.IMGFMT
72
@@ -XXX,XX +XXX,XX @@ Format specific information:
93
+0x9000 0x7000 TEST_DIR/t.IMGFMT
73
granularity: 65536
94
+No errors were found on the image.
74
refcount bits: 16
95
*** done
75
corrupt: false
76
-Check resulting qcow2 header extensions:
77
-Header extension:
78
-magic 0x6803f857 (Feature table)
79
-length 336
80
-data <binary>
81
-
82
-Header extension:
83
-magic 0x23852875 (Bitmaps)
84
-length 24
85
-nb_bitmaps 3
86
-reserved32 0
87
-bitmap_directory_size 0x60
88
-bitmap_directory_offset 0x520000
89
-
90
91
=== Check bitmap contents ===
92
93
--
96
--
94
2.26.2
97
2.41.0
95
96
diff view generated by jsdifflib