1
The following changes since commit bfec359afba088aaacc7d316f43302f28c6e642a:
1
The following changes since commit 474f3938d79ab36b9231c9ad3b5a9314c2aeacde:
2
2
3
Merge remote-tracking branch 'remotes/armbru/tags/pull-qdev-2017-04-21' into staging (2017-04-21 11:42:03 +0100)
3
Merge remote-tracking branch 'remotes/amarkovic/tags/mips-queue-jun-21-2019' into staging (2019-06-21 15:40:50 +0100)
4
4
5
are available in the git repository at:
5
are available in the Git repository at:
6
6
7
git://github.com/codyprime/qemu-kvm-jtc.git tags/block-pull-request
7
https://github.com/XanClic/qemu.git tags/pull-block-2019-06-24
8
8
9
for you to fetch changes up to 1507631e438930bc07f776f303af127a9cdb4d41:
9
for you to fetch changes up to ab5d4a30f7f3803ca5106b370969c1b7b54136f8:
10
10
11
qemu-iotests: _cleanup_qemu must be called on exit (2017-04-21 08:32:44 -0400)
11
iotests: Fix 205 for concurrent runs (2019-06-24 16:01:40 +0200)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
Block patches:
15
- The SSH block driver now uses libssh instead of libssh2
16
- The VMDK block driver gets read-only support for the seSparse
17
subformat
18
- Various fixes
14
19
15
Block patches for 2.10
20
---
21
22
v2:
23
- Squashed Pino's fix for pre-0.8 libssh into the libssh patch
16
24
17
----------------------------------------------------------------
25
----------------------------------------------------------------
26
Anton Nefedov (1):
27
iotest 134: test cluster-misaligned encrypted write
18
28
19
Ashish Mittal (2):
29
Klaus Birkelund Jensen (1):
20
block/vxhs.c: Add support for a new block device type called "vxhs"
30
nvme: do not advertise support for unsupported arbitration mechanism
21
block/vxhs.c: Add qemu-iotests for new block device type "vxhs"
22
31
23
Jeff Cody (10):
32
Max Reitz (1):
24
qemu-iotests: exclude vxhs from image creation via protocol
33
iotests: Fix 205 for concurrent runs
25
block: add bdrv_set_read_only() helper function
26
block: do not set BDS read_only if copy_on_read enabled
27
block: honor BDRV_O_ALLOW_RDWR when clearing bs->read_only
28
block: code movement
29
block: introduce bdrv_can_set_read_only()
30
block: use bdrv_can_set_read_only() during reopen
31
block/rbd - update variable names to more apt names
32
block/rbd: Add support for reopen()
33
qemu-iotests: _cleanup_qemu must be called on exit
34
34
35
block.c | 56 +++-
35
Pino Toscano (1):
36
block/Makefile.objs | 2 +
36
ssh: switch from libssh2 to libssh
37
block/bochs.c | 5 +-
37
38
block/cloop.c | 5 +-
38
Sam Eiderman (3):
39
block/dmg.c | 6 +-
39
vmdk: Fix comment regarding max l1_size coverage
40
block/rbd.c | 65 +++--
40
vmdk: Reduce the max bound for L1 table size
41
block/trace-events | 17 ++
41
vmdk: Add read-only support for seSparse snapshots
42
block/vvfat.c | 19 +-
42
43
block/vxhs.c | 575 +++++++++++++++++++++++++++++++++++++++
43
Vladimir Sementsov-Ogievskiy (1):
44
configure | 39 +++
44
blockdev: enable non-root nodes for transaction drive-backup source
45
include/block/block.h | 2 +
45
46
qapi/block-core.json | 23 +-
46
configure | 65 +-
47
tests/qemu-iotests/017 | 1 +
47
block/Makefile.objs | 6 +-
48
tests/qemu-iotests/020 | 1 +
48
block/ssh.c | 652 ++++++++++--------
49
tests/qemu-iotests/028 | 1 +
49
block/vmdk.c | 372 +++++++++-
50
tests/qemu-iotests/029 | 1 +
50
blockdev.c | 2 +-
51
tests/qemu-iotests/073 | 1 +
51
hw/block/nvme.c | 1 -
52
tests/qemu-iotests/094 | 11 +-
52
.travis.yml | 4 +-
53
tests/qemu-iotests/102 | 5 +-
53
block/trace-events | 14 +-
54
tests/qemu-iotests/109 | 1 +
54
docs/qemu-block-drivers.texi | 2 +-
55
tests/qemu-iotests/114 | 1 +
55
.../dockerfiles/debian-win32-cross.docker | 1 -
56
tests/qemu-iotests/117 | 1 +
56
.../dockerfiles/debian-win64-cross.docker | 1 -
57
tests/qemu-iotests/130 | 2 +
57
tests/docker/dockerfiles/fedora.docker | 4 +-
58
tests/qemu-iotests/134 | 1 +
58
tests/docker/dockerfiles/ubuntu.docker | 2 +-
59
tests/qemu-iotests/140 | 1 +
59
tests/docker/dockerfiles/ubuntu1804.docker | 2 +-
60
tests/qemu-iotests/141 | 1 +
60
tests/qemu-iotests/059.out | 2 +-
61
tests/qemu-iotests/143 | 1 +
61
tests/qemu-iotests/134 | 9 +
62
tests/qemu-iotests/156 | 2 +
62
tests/qemu-iotests/134.out | 10 +
63
tests/qemu-iotests/158 | 1 +
63
tests/qemu-iotests/205 | 2 +-
64
tests/qemu-iotests/common | 6 +
64
tests/qemu-iotests/207 | 54 +-
65
tests/qemu-iotests/common.config | 13 +
65
tests/qemu-iotests/207.out | 2 +-
66
tests/qemu-iotests/common.filter | 1 +
66
20 files changed, 823 insertions(+), 384 deletions(-)
67
tests/qemu-iotests/common.rc | 19 ++
68
33 files changed, 844 insertions(+), 42 deletions(-)
69
create mode 100644 block/vxhs.c
70
67
71
--
68
--
72
2.9.3
69
2.21.0
73
70
74
71
diff view generated by jsdifflib
1
For the tests that use the common.qemu functions for running a QEMU
1
From: Klaus Birkelund Jensen <klaus@birkelund.eu>
2
process, _cleanup_qemu must be called in the exit function.
3
2
4
If it is not, if the qemu process aborts, then not all of the droppings
3
The device mistakenly reports that the Weighted Round Robin with Urgent
5
are cleaned up (e.g. pidfile, fifos).
4
Priority Class arbitration mechanism is supported.
6
5
7
This updates those tests that did not have a cleanup in qemu-iotests.
6
It is not.
8
7
9
(I swapped spaces for tabs in test 102 as well)
8
Signed-off-by: Klaus Birkelund Jensen <klaus.jensen@cnexlabs.com>
9
Message-id: 20190606092530.14206-1-klaus@birkelund.eu
10
Acked-by: Maxim Levitsky <mlevitsk@redhat.com>
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
12
---
13
hw/block/nvme.c | 1 -
14
1 file changed, 1 deletion(-)
10
15
11
Reported-by: Eric Blake <eblake@redhat.com>
16
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
12
Reviewed-by: Eric Blake <eblake@redhat.com>
17
index XXXXXXX..XXXXXXX 100644
13
Signed-off-by: Jeff Cody <jcody@redhat.com>
18
--- a/hw/block/nvme.c
14
Message-id: d59c2f6ad6c1da8b9b3c7f357c94a7122ccfc55a.1492544096.git.jcody@redhat.com
19
+++ b/hw/block/nvme.c
15
---
20
@@ -XXX,XX +XXX,XX @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp)
16
tests/qemu-iotests/028 | 1 +
21
n->bar.cap = 0;
17
tests/qemu-iotests/094 | 11 ++++++++---
22
NVME_CAP_SET_MQES(n->bar.cap, 0x7ff);
18
tests/qemu-iotests/102 | 5 +++--
23
NVME_CAP_SET_CQR(n->bar.cap, 1);
19
tests/qemu-iotests/109 | 1 +
24
- NVME_CAP_SET_AMS(n->bar.cap, 1);
20
tests/qemu-iotests/117 | 1 +
25
NVME_CAP_SET_TO(n->bar.cap, 0xf);
21
tests/qemu-iotests/130 | 1 +
26
NVME_CAP_SET_CSS(n->bar.cap, 1);
22
tests/qemu-iotests/140 | 1 +
27
NVME_CAP_SET_MPSMAX(n->bar.cap, 4);
23
tests/qemu-iotests/141 | 1 +
24
tests/qemu-iotests/143 | 1 +
25
tests/qemu-iotests/156 | 1 +
26
10 files changed, 19 insertions(+), 5 deletions(-)
27
28
diff --git a/tests/qemu-iotests/028 b/tests/qemu-iotests/028
29
index XXXXXXX..XXXXXXX 100755
30
--- a/tests/qemu-iotests/028
31
+++ b/tests/qemu-iotests/028
32
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
33
34
_cleanup()
35
{
36
+ _cleanup_qemu
37
rm -f "${TEST_IMG}.copy"
38
_cleanup_test_img
39
}
40
diff --git a/tests/qemu-iotests/094 b/tests/qemu-iotests/094
41
index XXXXXXX..XXXXXXX 100755
42
--- a/tests/qemu-iotests/094
43
+++ b/tests/qemu-iotests/094
44
@@ -XXX,XX +XXX,XX @@ echo "QA output created by $seq"
45
here="$PWD"
46
status=1    # failure is the default!
47
48
-trap "exit \$status" 0 1 2 3 15
49
+_cleanup()
50
+{
51
+ _cleanup_qemu
52
+ _cleanup_test_img
53
+ rm -f "$TEST_DIR/source.$IMGFMT"
54
+}
55
+
56
+trap "_cleanup; exit \$status" 0 1 2 3 15
57
58
# get standard environment, filters and checks
59
. ./common.rc
60
@@ -XXX,XX +XXX,XX @@ _send_qemu_cmd $QEMU_HANDLE \
61
62
wait=1 _cleanup_qemu
63
64
-_cleanup_test_img
65
-rm -f "$TEST_DIR/source.$IMGFMT"
66
67
# success, all done
68
echo '*** done'
69
diff --git a/tests/qemu-iotests/102 b/tests/qemu-iotests/102
70
index XXXXXXX..XXXXXXX 100755
71
--- a/tests/qemu-iotests/102
72
+++ b/tests/qemu-iotests/102
73
@@ -XXX,XX +XXX,XX @@ seq=$(basename $0)
74
echo "QA output created by $seq"
75
76
here=$PWD
77
-status=1    # failure is the default!
78
+status=1 # failure is the default!
79
80
_cleanup()
81
{
82
-    _cleanup_test_img
83
+ _cleanup_qemu
84
+ _cleanup_test_img
85
}
86
trap "_cleanup; exit \$status" 0 1 2 3 15
87
88
diff --git a/tests/qemu-iotests/109 b/tests/qemu-iotests/109
89
index XXXXXXX..XXXXXXX 100755
90
--- a/tests/qemu-iotests/109
91
+++ b/tests/qemu-iotests/109
92
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
93
94
_cleanup()
95
{
96
+ _cleanup_qemu
97
rm -f $TEST_IMG.src
98
    _cleanup_test_img
99
}
100
diff --git a/tests/qemu-iotests/117 b/tests/qemu-iotests/117
101
index XXXXXXX..XXXXXXX 100755
102
--- a/tests/qemu-iotests/117
103
+++ b/tests/qemu-iotests/117
104
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
105
106
_cleanup()
107
{
108
+ _cleanup_qemu
109
    _cleanup_test_img
110
}
111
trap "_cleanup; exit \$status" 0 1 2 3 15
112
diff --git a/tests/qemu-iotests/130 b/tests/qemu-iotests/130
113
index XXXXXXX..XXXXXXX 100755
114
--- a/tests/qemu-iotests/130
115
+++ b/tests/qemu-iotests/130
116
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
117
118
_cleanup()
119
{
120
+ _cleanup_qemu
121
_cleanup_test_img
122
}
123
trap "_cleanup; exit \$status" 0 1 2 3 15
124
diff --git a/tests/qemu-iotests/140 b/tests/qemu-iotests/140
125
index XXXXXXX..XXXXXXX 100755
126
--- a/tests/qemu-iotests/140
127
+++ b/tests/qemu-iotests/140
128
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
129
130
_cleanup()
131
{
132
+ _cleanup_qemu
133
_cleanup_test_img
134
rm -f "$TEST_DIR/nbd"
135
}
136
diff --git a/tests/qemu-iotests/141 b/tests/qemu-iotests/141
137
index XXXXXXX..XXXXXXX 100755
138
--- a/tests/qemu-iotests/141
139
+++ b/tests/qemu-iotests/141
140
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
141
142
_cleanup()
143
{
144
+ _cleanup_qemu
145
_cleanup_test_img
146
rm -f "$TEST_DIR/{b,m,o}.$IMGFMT"
147
}
148
diff --git a/tests/qemu-iotests/143 b/tests/qemu-iotests/143
149
index XXXXXXX..XXXXXXX 100755
150
--- a/tests/qemu-iotests/143
151
+++ b/tests/qemu-iotests/143
152
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
153
154
_cleanup()
155
{
156
+ _cleanup_qemu
157
rm -f "$TEST_DIR/nbd"
158
}
159
trap "_cleanup; exit \$status" 0 1 2 3 15
160
diff --git a/tests/qemu-iotests/156 b/tests/qemu-iotests/156
161
index XXXXXXX..XXXXXXX 100755
162
--- a/tests/qemu-iotests/156
163
+++ b/tests/qemu-iotests/156
164
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
165
166
_cleanup()
167
{
168
+ _cleanup_qemu
169
rm -f "$TEST_IMG{,.target}{,.backing,.overlay}"
170
}
171
trap "_cleanup; exit \$status" 0 1 2 3 15
172
--
28
--
173
2.9.3
29
2.21.0
174
30
175
31
diff view generated by jsdifflib
1
This adds support for reopen in rbd, for changing between r/w and r/o.
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
Note, that this is only a flag change, but we will block a change from
3
We forget to enable it for transaction .prepare, while it is already
4
r/o to r/w if we are using an RBD internal snapshot.
4
enabled in do_drive_backup since commit a2d665c1bc362
5
"blockdev: loosen restrictions on drive-backup source node"
5
6
6
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
7
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
Signed-off-by: Jeff Cody <jcody@redhat.com>
8
Message-id: 20190618140804.59214-1-vsementsov@virtuozzo.com
8
Reviewed-by: John Snow <jsnow@redhat.com>
9
Reviewed-by: John Snow <jsnow@redhat.com>
9
Message-id: d4e87539167ec6527d44c97b164eabcccf96e4f3.1491597120.git.jcody@redhat.com
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
---
11
---
11
block/rbd.c | 21 +++++++++++++++++++++
12
blockdev.c | 2 +-
12
1 file changed, 21 insertions(+)
13
1 file changed, 1 insertion(+), 1 deletion(-)
13
14
14
diff --git a/block/rbd.c b/block/rbd.c
15
diff --git a/blockdev.c b/blockdev.c
15
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
16
--- a/block/rbd.c
17
--- a/blockdev.c
17
+++ b/block/rbd.c
18
+++ b/blockdev.c
18
@@ -XXX,XX +XXX,XX @@ failed_opts:
19
@@ -XXX,XX +XXX,XX @@ static void drive_backup_prepare(BlkActionState *common, Error **errp)
19
return r;
20
assert(common->action->type == TRANSACTION_ACTION_KIND_DRIVE_BACKUP);
20
}
21
backup = common->action->u.drive_backup.data;
21
22
22
+
23
- bs = qmp_get_root_bs(backup->device, errp);
23
+/* Since RBD is currently always opened R/W via the API,
24
+ bs = bdrv_lookup_bs(backup->device, backup->device, errp);
24
+ * we just need to check if we are using a snapshot or not, in
25
if (!bs) {
25
+ * order to determine if we will allow it to be R/W */
26
return;
26
+static int qemu_rbd_reopen_prepare(BDRVReopenState *state,
27
}
27
+ BlockReopenQueue *queue, Error **errp)
28
+{
29
+ BDRVRBDState *s = state->bs->opaque;
30
+ int ret = 0;
31
+
32
+ if (s->snap && state->flags & BDRV_O_RDWR) {
33
+ error_setg(errp,
34
+ "Cannot change node '%s' to r/w when using RBD snapshot",
35
+ bdrv_get_device_or_node_name(state->bs));
36
+ ret = -EINVAL;
37
+ }
38
+
39
+ return ret;
40
+}
41
+
42
static void qemu_rbd_close(BlockDriverState *bs)
43
{
44
BDRVRBDState *s = bs->opaque;
45
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_rbd = {
46
.bdrv_parse_filename = qemu_rbd_parse_filename,
47
.bdrv_file_open = qemu_rbd_open,
48
.bdrv_close = qemu_rbd_close,
49
+ .bdrv_reopen_prepare = qemu_rbd_reopen_prepare,
50
.bdrv_create = qemu_rbd_create,
51
.bdrv_has_zero_init = bdrv_has_zero_init_1,
52
.bdrv_get_info = qemu_rbd_getinfo,
53
--
28
--
54
2.9.3
29
2.21.0
55
30
56
31
diff view generated by jsdifflib
1
The protocol VXHS does not support image creation. Some tests expect
1
From: Anton Nefedov <anton.nefedov@virtuozzo.com>
2
to be able to create images through the protocol. Exclude VXHS from
3
these tests.
4
2
5
Signed-off-by: Jeff Cody <jcody@redhat.com>
3
COW (even empty/zero) areas require encryption too
4
5
Signed-off-by: Anton Nefedov <anton.nefedov@virtuozzo.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
8
Reviewed-by: Alberto Garcia <berto@igalia.com>
9
Message-id: 20190516143028.81155-1-anton.nefedov@virtuozzo.com
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
6
---
11
---
7
tests/qemu-iotests/017 | 1 +
12
tests/qemu-iotests/134 | 9 +++++++++
8
tests/qemu-iotests/020 | 1 +
13
tests/qemu-iotests/134.out | 10 ++++++++++
9
tests/qemu-iotests/029 | 1 +
14
2 files changed, 19 insertions(+)
10
tests/qemu-iotests/073 | 1 +
11
tests/qemu-iotests/114 | 1 +
12
tests/qemu-iotests/130 | 1 +
13
tests/qemu-iotests/134 | 1 +
14
tests/qemu-iotests/156 | 1 +
15
tests/qemu-iotests/158 | 1 +
16
9 files changed, 9 insertions(+)
17
15
18
diff --git a/tests/qemu-iotests/017 b/tests/qemu-iotests/017
19
index XXXXXXX..XXXXXXX 100755
20
--- a/tests/qemu-iotests/017
21
+++ b/tests/qemu-iotests/017
22
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
23
# Any format supporting backing files
24
_supported_fmt qcow qcow2 vmdk qed
25
_supported_proto generic
26
+_unsupported_proto vxhs
27
_supported_os Linux
28
_unsupported_imgopts "subformat=monolithicFlat" "subformat=twoGbMaxExtentFlat"
29
30
diff --git a/tests/qemu-iotests/020 b/tests/qemu-iotests/020
31
index XXXXXXX..XXXXXXX 100755
32
--- a/tests/qemu-iotests/020
33
+++ b/tests/qemu-iotests/020
34
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
35
# Any format supporting backing files
36
_supported_fmt qcow qcow2 vmdk qed
37
_supported_proto generic
38
+_unsupported_proto vxhs
39
_supported_os Linux
40
_unsupported_imgopts "subformat=monolithicFlat" \
41
"subformat=twoGbMaxExtentFlat" \
42
diff --git a/tests/qemu-iotests/029 b/tests/qemu-iotests/029
43
index XXXXXXX..XXXXXXX 100755
44
--- a/tests/qemu-iotests/029
45
+++ b/tests/qemu-iotests/029
46
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
47
# Any format supporting intenal snapshots
48
_supported_fmt qcow2
49
_supported_proto generic
50
+_unsupported_proto vxhs
51
_supported_os Linux
52
# Internal snapshots are (currently) impossible with refcount_bits=1
53
_unsupported_imgopts 'refcount_bits=1[^0-9]'
54
diff --git a/tests/qemu-iotests/073 b/tests/qemu-iotests/073
55
index XXXXXXX..XXXXXXX 100755
56
--- a/tests/qemu-iotests/073
57
+++ b/tests/qemu-iotests/073
58
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
59
60
_supported_fmt qcow2
61
_supported_proto generic
62
+_unsupported_proto vxhs
63
_supported_os Linux
64
65
CLUSTER_SIZE=64k
66
diff --git a/tests/qemu-iotests/114 b/tests/qemu-iotests/114
67
index XXXXXXX..XXXXXXX 100755
68
--- a/tests/qemu-iotests/114
69
+++ b/tests/qemu-iotests/114
70
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
71
72
_supported_fmt qcow2
73
_supported_proto generic
74
+_unsupported_proto vxhs
75
_supported_os Linux
76
77
78
diff --git a/tests/qemu-iotests/130 b/tests/qemu-iotests/130
79
index XXXXXXX..XXXXXXX 100755
80
--- a/tests/qemu-iotests/130
81
+++ b/tests/qemu-iotests/130
82
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
83
84
_supported_fmt qcow2
85
_supported_proto generic
86
+_unsupported_proto vxhs
87
_supported_os Linux
88
89
qemu_comm_method="monitor"
90
diff --git a/tests/qemu-iotests/134 b/tests/qemu-iotests/134
16
diff --git a/tests/qemu-iotests/134 b/tests/qemu-iotests/134
91
index XXXXXXX..XXXXXXX 100755
17
index XXXXXXX..XXXXXXX 100755
92
--- a/tests/qemu-iotests/134
18
--- a/tests/qemu-iotests/134
93
+++ b/tests/qemu-iotests/134
19
+++ b/tests/qemu-iotests/134
94
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
20
@@ -XXX,XX +XXX,XX @@ echo
95
21
echo "== reading whole image =="
96
_supported_fmt qcow2
22
$QEMU_IO --object $SECRET -c "read 0 $size" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir
97
_supported_proto generic
23
98
+_unsupported_proto vxhs
24
+echo
99
_supported_os Linux
25
+echo "== rewriting cluster part =="
100
26
+$QEMU_IO --object $SECRET -c "write -P 0xb 512 512" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir
101
27
+
102
diff --git a/tests/qemu-iotests/156 b/tests/qemu-iotests/156
28
+echo
103
index XXXXXXX..XXXXXXX 100755
29
+echo "== verify pattern =="
104
--- a/tests/qemu-iotests/156
30
+$QEMU_IO --object $SECRET -c "read -P 0 0 512" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir
105
+++ b/tests/qemu-iotests/156
31
+$QEMU_IO --object $SECRET -c "read -P 0xb 512 512" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir
106
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
32
+
107
33
echo
108
_supported_fmt qcow2 qed
34
echo "== rewriting whole image =="
109
_supported_proto generic
35
$QEMU_IO --object $SECRET -c "write -P 0xa 0 $size" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir
110
+_unsupported_proto vxhs
36
diff --git a/tests/qemu-iotests/134.out b/tests/qemu-iotests/134.out
111
_supported_os Linux
37
index XXXXXXX..XXXXXXX 100644
112
38
--- a/tests/qemu-iotests/134.out
113
# Create source disk
39
+++ b/tests/qemu-iotests/134.out
114
diff --git a/tests/qemu-iotests/158 b/tests/qemu-iotests/158
40
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encryption=on encrypt.
115
index XXXXXXX..XXXXXXX 100755
41
read 134217728/134217728 bytes at offset 0
116
--- a/tests/qemu-iotests/158
42
128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
117
+++ b/tests/qemu-iotests/158
43
118
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
44
+== rewriting cluster part ==
119
45
+wrote 512/512 bytes at offset 512
120
_supported_fmt qcow2
46
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
121
_supported_proto generic
47
+
122
+_unsupported_proto vxhs
48
+== verify pattern ==
123
_supported_os Linux
49
+read 512/512 bytes at offset 0
124
50
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
125
51
+read 512/512 bytes at offset 512
52
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
53
+
54
== rewriting whole image ==
55
wrote 134217728/134217728 bytes at offset 0
56
128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
126
--
57
--
127
2.9.3
58
2.21.0
128
59
129
60
diff view generated by jsdifflib
1
Update 'clientname' to be 'user', which tracks better with both
1
From: Sam Eiderman <shmuel.eiderman@oracle.com>
2
the QAPI and rados variable naming.
3
2
4
Update 'name' to be 'image_name', as it indicates the rbd image.
3
Commit b0651b8c246d ("vmdk: Move l1_size check into vmdk_add_extent")
5
Naming it 'image' would have been ideal, but we are using that for
4
extended the l1_size check from VMDK4 to VMDK3 but did not update the
6
the rados_image_t value returned by rbd_open().
5
default coverage in the moved comment.
7
6
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
7
The previous vmdk4 calculation:
9
Signed-off-by: Jeff Cody <jcody@redhat.com>
8
10
Reviewed-by: John Snow <jsnow@redhat.com>
9
(512 * 1024 * 1024) * 512(l2 entries) * 65536(grain) = 16PB
11
Message-id: b7ec1fb2e1cf36f9b6911631447a5b0422590b7d.1491597120.git.jcody@redhat.com
10
11
The added vmdk3 calculation:
12
13
(512 * 1024 * 1024) * 4096(l2 entries) * 512(grain) = 1PB
14
15
Adding the calculation of vmdk3 to the comment.
16
17
In any case, VMware does not offer virtual disks more than 2TB for
18
vmdk4/vmdk3 or 64TB for the new undocumented seSparse format which is
19
not implemented yet in qemu.
20
21
Reviewed-by: Karl Heubaum <karl.heubaum@oracle.com>
22
Reviewed-by: Eyal Moscovici <eyal.moscovici@oracle.com>
23
Reviewed-by: Liran Alon <liran.alon@oracle.com>
24
Reviewed-by: Arbel Moshe <arbel.moshe@oracle.com>
25
Signed-off-by: Sam Eiderman <shmuel.eiderman@oracle.com>
26
Message-id: 20190620091057.47441-2-shmuel.eiderman@oracle.com
27
Reviewed-by: yuchenlin <yuchenlin@synology.com>
28
Reviewed-by: Max Reitz <mreitz@redhat.com>
29
Signed-off-by: Max Reitz <mreitz@redhat.com>
12
---
30
---
13
block/rbd.c | 33 +++++++++++++++++----------------
31
block/vmdk.c | 11 ++++++++---
14
1 file changed, 17 insertions(+), 16 deletions(-)
32
1 file changed, 8 insertions(+), 3 deletions(-)
15
33
16
diff --git a/block/rbd.c b/block/rbd.c
34
diff --git a/block/vmdk.c b/block/vmdk.c
17
index XXXXXXX..XXXXXXX 100644
35
index XXXXXXX..XXXXXXX 100644
18
--- a/block/rbd.c
36
--- a/block/vmdk.c
19
+++ b/block/rbd.c
37
+++ b/block/vmdk.c
20
@@ -XXX,XX +XXX,XX @@ typedef struct BDRVRBDState {
38
@@ -XXX,XX +XXX,XX @@ static int vmdk_add_extent(BlockDriverState *bs,
21
rados_t cluster;
39
return -EFBIG;
22
rados_ioctx_t io_ctx;
23
rbd_image_t image;
24
- char *name;
25
+ char *image_name;
26
char *snap;
27
} BDRVRBDState;
28
29
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_create(const char *filename, QemuOpts *opts, Error **errp)
30
int64_t bytes = 0;
31
int64_t objsize;
32
int obj_order = 0;
33
- const char *pool, *name, *conf, *clientname, *keypairs;
34
+ const char *pool, *image_name, *conf, *user, *keypairs;
35
const char *secretid;
36
rados_t cluster;
37
rados_ioctx_t io_ctx;
38
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_create(const char *filename, QemuOpts *opts, Error **errp)
39
*/
40
pool = qdict_get_try_str(options, "pool");
41
conf = qdict_get_try_str(options, "conf");
42
- clientname = qdict_get_try_str(options, "user");
43
- name = qdict_get_try_str(options, "image");
44
+ user = qdict_get_try_str(options, "user");
45
+ image_name = qdict_get_try_str(options, "image");
46
keypairs = qdict_get_try_str(options, "=keyvalue-pairs");
47
48
- ret = rados_create(&cluster, clientname);
49
+ ret = rados_create(&cluster, user);
50
if (ret < 0) {
51
error_setg_errno(errp, -ret, "error initializing");
52
goto exit;
53
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_create(const char *filename, QemuOpts *opts, Error **errp)
54
goto shutdown;
55
}
40
}
56
41
if (l1_size > 512 * 1024 * 1024) {
57
- ret = rbd_create(io_ctx, name, bytes, &obj_order);
42
- /* Although with big capacity and small l1_entry_sectors, we can get a
58
+ ret = rbd_create(io_ctx, image_name, bytes, &obj_order);
43
+ /*
59
if (ret < 0) {
44
+ * Although with big capacity and small l1_entry_sectors, we can get a
60
error_setg_errno(errp, -ret, "error rbd create");
45
* big l1_size, we don't want unbounded value to allocate the table.
46
- * Limit it to 512M, which is 16PB for default cluster and L2 table
47
- * size */
48
+ * Limit it to 512M, which is:
49
+ * 16PB - for default "Hosted Sparse Extent" (VMDK4)
50
+ * cluster size: 64KB, L2 table size: 512 entries
51
+ * 1PB - for default "ESXi Host Sparse Extent" (VMDK3/vmfsSparse)
52
+ * cluster size: 512B, L2 table size: 4096 entries
53
+ */
54
error_setg(errp, "L1 size too big");
55
return -EFBIG;
61
}
56
}
62
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
63
Error **errp)
64
{
65
BDRVRBDState *s = bs->opaque;
66
- const char *pool, *snap, *conf, *clientname, *name, *keypairs;
67
+ const char *pool, *snap, *conf, *user, *image_name, *keypairs;
68
const char *secretid;
69
QemuOpts *opts;
70
Error *local_err = NULL;
71
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
72
pool = qemu_opt_get(opts, "pool");
73
conf = qemu_opt_get(opts, "conf");
74
snap = qemu_opt_get(opts, "snapshot");
75
- clientname = qemu_opt_get(opts, "user");
76
- name = qemu_opt_get(opts, "image");
77
+ user = qemu_opt_get(opts, "user");
78
+ image_name = qemu_opt_get(opts, "image");
79
keypairs = qemu_opt_get(opts, "=keyvalue-pairs");
80
81
- if (!pool || !name) {
82
+ if (!pool || !image_name) {
83
error_setg(errp, "Parameters 'pool' and 'image' are required");
84
r = -EINVAL;
85
goto failed_opts;
86
}
87
88
- r = rados_create(&s->cluster, clientname);
89
+ r = rados_create(&s->cluster, user);
90
if (r < 0) {
91
error_setg_errno(errp, -r, "error initializing");
92
goto failed_opts;
93
}
94
95
s->snap = g_strdup(snap);
96
- s->name = g_strdup(name);
97
+ s->image_name = g_strdup(image_name);
98
99
/* try default location when conf=NULL, but ignore failure */
100
r = rados_conf_read_file(s->cluster, conf);
101
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
102
}
103
104
/* rbd_open is always r/w */
105
- r = rbd_open(s->io_ctx, s->name, &s->image, s->snap);
106
+ r = rbd_open(s->io_ctx, s->image_name, &s->image, s->snap);
107
if (r < 0) {
108
- error_setg_errno(errp, -r, "error reading header from %s", s->name);
109
+ error_setg_errno(errp, -r, "error reading header from %s",
110
+ s->image_name);
111
goto failed_open;
112
}
113
114
@@ -XXX,XX +XXX,XX @@ failed_open:
115
failed_shutdown:
116
rados_shutdown(s->cluster);
117
g_free(s->snap);
118
- g_free(s->name);
119
+ g_free(s->image_name);
120
failed_opts:
121
qemu_opts_del(opts);
122
g_free(mon_host);
123
@@ -XXX,XX +XXX,XX @@ static void qemu_rbd_close(BlockDriverState *bs)
124
rbd_close(s->image);
125
rados_ioctx_destroy(s->io_ctx);
126
g_free(s->snap);
127
- g_free(s->name);
128
+ g_free(s->image_name);
129
rados_shutdown(s->cluster);
130
}
131
132
--
57
--
133
2.9.3
58
2.21.0
134
59
135
60
diff view generated by jsdifflib
1
Introduce check function for setting read_only flags. Will return < 0 on
1
From: Sam Eiderman <shmuel.eiderman@oracle.com>
2
error, with appropriate Error value set. Does not alter any flags.
3
2
4
Signed-off-by: Jeff Cody <jcody@redhat.com>
3
512M of L1 entries is a very loose bound, only 32M are required to store
5
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
4
the maximal supported VMDK file size of 2TB.
6
Reviewed-by: John Snow <jsnow@redhat.com>
5
7
Message-id: e2bba34ac3bc76a0c42adc390413f358ae0566e8.1491597120.git.jcody@redhat.com
6
Fixed qemu-iotest 59# - now failure occures before on impossible L1
7
table size.
8
9
Reviewed-by: Karl Heubaum <karl.heubaum@oracle.com>
10
Reviewed-by: Eyal Moscovici <eyal.moscovici@oracle.com>
11
Reviewed-by: Liran Alon <liran.alon@oracle.com>
12
Reviewed-by: Arbel Moshe <arbel.moshe@oracle.com>
13
Signed-off-by: Sam Eiderman <shmuel.eiderman@oracle.com>
14
Message-id: 20190620091057.47441-3-shmuel.eiderman@oracle.com
15
Reviewed-by: Max Reitz <mreitz@redhat.com>
16
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
---
17
---
9
block.c | 14 +++++++++++++-
18
block/vmdk.c | 13 +++++++------
10
include/block/block.h | 1 +
19
tests/qemu-iotests/059.out | 2 +-
11
2 files changed, 14 insertions(+), 1 deletion(-)
20
2 files changed, 8 insertions(+), 7 deletions(-)
12
21
13
diff --git a/block.c b/block.c
22
diff --git a/block/vmdk.c b/block/vmdk.c
14
index XXXXXXX..XXXXXXX 100644
23
index XXXXXXX..XXXXXXX 100644
15
--- a/block.c
24
--- a/block/vmdk.c
16
+++ b/block.c
25
+++ b/block/vmdk.c
17
@@ -XXX,XX +XXX,XX @@ bool bdrv_is_read_only(BlockDriverState *bs)
26
@@ -XXX,XX +XXX,XX @@ static int vmdk_add_extent(BlockDriverState *bs,
18
return bs->read_only;
27
error_setg(errp, "Invalid granularity, image may be corrupt");
19
}
28
return -EFBIG;
20
21
-int bdrv_set_read_only(BlockDriverState *bs, bool read_only, Error **errp)
22
+int bdrv_can_set_read_only(BlockDriverState *bs, bool read_only, Error **errp)
23
{
24
/* Do not set read_only if copy_on_read is enabled */
25
if (bs->copy_on_read && read_only) {
26
@@ -XXX,XX +XXX,XX @@ int bdrv_set_read_only(BlockDriverState *bs, bool read_only, Error **errp)
27
return -EPERM;
28
}
29
}
29
30
- if (l1_size > 512 * 1024 * 1024) {
30
+ return 0;
31
+ if (l1_size > 32 * 1024 * 1024) {
31
+}
32
/*
32
+
33
* Although with big capacity and small l1_entry_sectors, we can get a
33
+int bdrv_set_read_only(BlockDriverState *bs, bool read_only, Error **errp)
34
* big l1_size, we don't want unbounded value to allocate the table.
34
+{
35
- * Limit it to 512M, which is:
35
+ int ret = 0;
36
- * 16PB - for default "Hosted Sparse Extent" (VMDK4)
36
+
37
- * cluster size: 64KB, L2 table size: 512 entries
37
+ ret = bdrv_can_set_read_only(bs, read_only, errp);
38
- * 1PB - for default "ESXi Host Sparse Extent" (VMDK3/vmfsSparse)
38
+ if (ret < 0) {
39
- * cluster size: 512B, L2 table size: 4096 entries
39
+ return ret;
40
+ * Limit it to 32M, which is enough to store:
40
+ }
41
+ * 8TB - for both VMDK3 & VMDK4 with
41
+
42
+ * minimal cluster size: 512B
42
bs->read_only = read_only;
43
+ * minimal L2 table size: 512 entries
43
return 0;
44
+ * 8 TB is still more than the maximal value supported for
44
}
45
+ * VMDK3 & VMDK4 which is 2TB.
45
diff --git a/include/block/block.h b/include/block/block.h
46
*/
47
error_setg(errp, "L1 size too big");
48
return -EFBIG;
49
diff --git a/tests/qemu-iotests/059.out b/tests/qemu-iotests/059.out
46
index XXXXXXX..XXXXXXX 100644
50
index XXXXXXX..XXXXXXX 100644
47
--- a/include/block/block.h
51
--- a/tests/qemu-iotests/059.out
48
+++ b/include/block/block.h
52
+++ b/tests/qemu-iotests/059.out
49
@@ -XXX,XX +XXX,XX @@ int bdrv_is_allocated_above(BlockDriverState *top, BlockDriverState *base,
53
@@ -XXX,XX +XXX,XX @@ Offset Length Mapped to File
50
int64_t sector_num, int nb_sectors, int *pnum);
54
0x140000000 0x10000 0x50000 TEST_DIR/t-s003.vmdk
51
55
52
bool bdrv_is_read_only(BlockDriverState *bs);
56
=== Testing afl image with a very large capacity ===
53
+int bdrv_can_set_read_only(BlockDriverState *bs, bool read_only, Error **errp);
57
-qemu-img: Can't get image size 'TEST_DIR/afl9.IMGFMT': File too large
54
int bdrv_set_read_only(BlockDriverState *bs, bool read_only, Error **errp);
58
+qemu-img: Could not open 'TEST_DIR/afl9.IMGFMT': L1 size too big
55
bool bdrv_is_sg(BlockDriverState *bs);
59
*** done
56
bool bdrv_is_inserted(BlockDriverState *bs);
57
--
60
--
58
2.9.3
61
2.21.0
59
62
60
63
diff view generated by jsdifflib
1
A few block drivers will set the BDS read_only flag from their
1
From: Sam Eiderman <shmuel.eiderman@oracle.com>
2
.bdrv_open() function. This means the bs->read_only flag could
2
3
be set after we enable copy_on_read, as the BDRV_O_COPY_ON_READ
3
Until ESXi 6.5 VMware used the vmfsSparse format for snapshots (VMDK3 in
4
flag check occurs prior to the call to bdrv->bdrv_open().
4
QEMU).
5
5
6
This adds an error return to bdrv_set_read_only(), and an error will be
6
This format was lacking in the following:
7
return if we try to set the BDS to read_only while copy_on_read is
7
8
enabled.
8
* Grain directory (L1) and grain table (L2) entries were 32-bit,
9
9
allowing access to only 2TB (slightly less) of data.
10
This patch also changes the behavior of vvfat. Before, vvfat could
10
* The grain size (default) was 512 bytes - leading to data
11
override the drive 'readonly' flag with its own, internal 'rw' flag.
11
fragmentation and many grain tables.
12
12
* For space reclamation purposes, it was necessary to find all the
13
For instance, this -drive parameter would result in a writable image:
13
grains which are not pointed to by any grain table - so a reverse
14
14
mapping of "offset of grain in vmdk" to "grain table" must be
15
"-drive format=vvfat,dir=/tmp/vvfat,rw,if=virtio,readonly=on"
15
constructed - which takes large amounts of CPU/RAM.
16
16
17
This is not correct. Now, attempting to use the above -drive parameter
17
The format specification can be found in VMware's documentation:
18
will result in an error (i.e., 'rw' is incompatible with 'readonly=on').
18
https://www.vmware.com/support/developer/vddk/vmdk_50_technote.pdf
19
19
20
Signed-off-by: Jeff Cody <jcody@redhat.com>
20
In ESXi 6.5, to support snapshot files larger than 2TB, a new format was
21
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
21
introduced: SESparse (Space Efficient).
22
Reviewed-by: John Snow <jsnow@redhat.com>
22
23
Message-id: 0c5b4c1cc2c651471b131f21376dfd5ea24d2196.1491597120.git.jcody@redhat.com
23
This format fixes the above issues:
24
25
* All entries are now 64-bit.
26
* The grain size (default) is 4KB.
27
* Grain directory and grain tables are now located at the beginning
28
of the file.
29
+ seSparse format reserves space for all grain tables.
30
+ Grain tables can be addressed using an index.
31
+ Grains are located in the end of the file and can also be
32
addressed with an index.
33
- seSparse vmdks of large disks (64TB) have huge preallocated
34
headers - mainly due to L2 tables, even for empty snapshots.
35
* The header contains a reverse mapping ("backmap") of "offset of
36
grain in vmdk" to "grain table" and a bitmap ("free bitmap") which
37
specifies for each grain - whether it is allocated or not.
38
Using these data structures we can implement space reclamation
39
efficiently.
40
* Due to the fact that the header now maintains two mappings:
41
* The regular one (grain directory & grain tables)
42
* A reverse one (backmap and free bitmap)
43
These data structures can lose consistency upon crash and result
44
in a corrupted VMDK.
45
Therefore, a journal is also added to the VMDK and is replayed
46
when the VMware reopens the file after a crash.
47
48
Since ESXi 6.7 - SESparse is the only snapshot format available.
49
50
Unfortunately, VMware does not provide documentation regarding the new
51
seSparse format.
52
53
This commit is based on black-box research of the seSparse format.
54
Various in-guest block operations and their effect on the snapshot file
55
were tested.
56
57
The only VMware provided source of information (regarding the underlying
58
implementation) was a log file on the ESXi:
59
60
/var/log/hostd.log
61
62
Whenever an seSparse snapshot is created - the log is being populated
63
with seSparse records.
64
65
Relevant log records are of the form:
66
67
[...] Const Header:
68
[...] constMagic = 0xcafebabe
69
[...] version = 2.1
70
[...] capacity = 204800
71
[...] grainSize = 8
72
[...] grainTableSize = 64
73
[...] flags = 0
74
[...] Extents:
75
[...] Header : <1 : 1>
76
[...] JournalHdr : <2 : 2>
77
[...] Journal : <2048 : 2048>
78
[...] GrainDirectory : <4096 : 2048>
79
[...] GrainTables : <6144 : 2048>
80
[...] FreeBitmap : <8192 : 2048>
81
[...] BackMap : <10240 : 2048>
82
[...] Grain : <12288 : 204800>
83
[...] Volatile Header:
84
[...] volatileMagic = 0xcafecafe
85
[...] FreeGTNumber = 0
86
[...] nextTxnSeqNumber = 0
87
[...] replayJournal = 0
88
89
The sizes that are seen in the log file are in sectors.
90
Extents are of the following format: <offset : size>
91
92
This commit is a strict implementation which enforces:
93
* magics
94
* version number 2.1
95
* grain size of 8 sectors (4KB)
96
* grain table size of 64 sectors
97
* zero flags
98
* extent locations
99
100
Additionally, this commit proivdes only a subset of the functionality
101
offered by seSparse's format:
102
* Read-only
103
* No journal replay
104
* No space reclamation
105
* No unmap support
106
107
Hence, journal header, journal, free bitmap and backmap extents are
108
unused, only the "classic" (L1 -> L2 -> data) grain access is
109
implemented.
110
111
However there are several differences in the grain access itself.
112
Grain directory (L1):
113
* Grain directory entries are indexes (not offsets) to grain
114
tables.
115
* Valid grain directory entries have their highest nibble set to
116
0x1.
117
* Since grain tables are always located in the beginning of the
118
file - the index can fit into 32 bits - so we can use its low
119
part if it's valid.
120
Grain table (L2):
121
* Grain table entries are indexes (not offsets) to grains.
122
* If the highest nibble of the entry is:
123
0x0:
124
The grain in not allocated.
125
The rest of the bytes are 0.
126
0x1:
127
The grain is unmapped - guest sees a zero grain.
128
The rest of the bits point to the previously mapped grain,
129
see 0x3 case.
130
0x2:
131
The grain is zero.
132
0x3:
133
The grain is allocated - to get the index calculate:
134
((entry & 0x0fff000000000000) >> 48) |
135
((entry & 0x0000ffffffffffff) << 12)
136
* The difference between 0x1 and 0x2 is that 0x1 is an unallocated
137
grain which results from the guest using sg_unmap to unmap the
138
grain - but the grain itself still exists in the grain extent - a
139
space reclamation procedure should delete it.
140
Unmapping a zero grain has no effect (0x2 will not change to 0x1)
141
but unmapping an unallocated grain will (0x0 to 0x1) - naturally.
142
143
In order to implement seSparse some fields had to be changed to support
144
both 32-bit and 64-bit entry sizes.
145
146
Reviewed-by: Karl Heubaum <karl.heubaum@oracle.com>
147
Reviewed-by: Eyal Moscovici <eyal.moscovici@oracle.com>
148
Reviewed-by: Arbel Moshe <arbel.moshe@oracle.com>
149
Signed-off-by: Sam Eiderman <shmuel.eiderman@oracle.com>
150
Message-id: 20190620091057.47441-4-shmuel.eiderman@oracle.com
151
Signed-off-by: Max Reitz <mreitz@redhat.com>
24
---
152
---
25
block.c | 10 +++++++++-
153
block/vmdk.c | 358 ++++++++++++++++++++++++++++++++++++++++++++++++---
26
block/bochs.c | 5 ++++-
154
1 file changed, 342 insertions(+), 16 deletions(-)
27
block/cloop.c | 5 ++++-
155
28
block/dmg.c | 6 +++++-
156
diff --git a/block/vmdk.c b/block/vmdk.c
29
block/rbd.c | 11 ++++++++++-
30
block/vvfat.c | 19 +++++++++++++++----
31
include/block/block.h | 2 +-
32
7 files changed, 48 insertions(+), 10 deletions(-)
33
34
diff --git a/block.c b/block.c
35
index XXXXXXX..XXXXXXX 100644
157
index XXXXXXX..XXXXXXX 100644
36
--- a/block.c
158
--- a/block/vmdk.c
37
+++ b/block.c
159
+++ b/block/vmdk.c
38
@@ -XXX,XX +XXX,XX @@ void path_combine(char *dest, int dest_size,
160
@@ -XXX,XX +XXX,XX @@ typedef struct {
39
}
161
uint16_t compressAlgorithm;
162
} QEMU_PACKED VMDK4Header;
163
164
+typedef struct VMDKSESparseConstHeader {
165
+ uint64_t magic;
166
+ uint64_t version;
167
+ uint64_t capacity;
168
+ uint64_t grain_size;
169
+ uint64_t grain_table_size;
170
+ uint64_t flags;
171
+ uint64_t reserved1;
172
+ uint64_t reserved2;
173
+ uint64_t reserved3;
174
+ uint64_t reserved4;
175
+ uint64_t volatile_header_offset;
176
+ uint64_t volatile_header_size;
177
+ uint64_t journal_header_offset;
178
+ uint64_t journal_header_size;
179
+ uint64_t journal_offset;
180
+ uint64_t journal_size;
181
+ uint64_t grain_dir_offset;
182
+ uint64_t grain_dir_size;
183
+ uint64_t grain_tables_offset;
184
+ uint64_t grain_tables_size;
185
+ uint64_t free_bitmap_offset;
186
+ uint64_t free_bitmap_size;
187
+ uint64_t backmap_offset;
188
+ uint64_t backmap_size;
189
+ uint64_t grains_offset;
190
+ uint64_t grains_size;
191
+ uint8_t pad[304];
192
+} QEMU_PACKED VMDKSESparseConstHeader;
193
+
194
+typedef struct VMDKSESparseVolatileHeader {
195
+ uint64_t magic;
196
+ uint64_t free_gt_number;
197
+ uint64_t next_txn_seq_number;
198
+ uint64_t replay_journal;
199
+ uint8_t pad[480];
200
+} QEMU_PACKED VMDKSESparseVolatileHeader;
201
+
202
#define L2_CACHE_SIZE 16
203
204
typedef struct VmdkExtent {
205
@@ -XXX,XX +XXX,XX @@ typedef struct VmdkExtent {
206
bool compressed;
207
bool has_marker;
208
bool has_zero_grain;
209
+ bool sesparse;
210
+ uint64_t sesparse_l2_tables_offset;
211
+ uint64_t sesparse_clusters_offset;
212
+ int32_t entry_size;
213
int version;
214
int64_t sectors;
215
int64_t end_sector;
216
int64_t flat_start_offset;
217
int64_t l1_table_offset;
218
int64_t l1_backup_table_offset;
219
- uint32_t *l1_table;
220
+ void *l1_table;
221
uint32_t *l1_backup_table;
222
unsigned int l1_size;
223
uint32_t l1_entry_sectors;
224
225
unsigned int l2_size;
226
- uint32_t *l2_cache;
227
+ void *l2_cache;
228
uint32_t l2_cache_offsets[L2_CACHE_SIZE];
229
uint32_t l2_cache_counts[L2_CACHE_SIZE];
230
231
@@ -XXX,XX +XXX,XX @@ static int vmdk_add_extent(BlockDriverState *bs,
232
* minimal L2 table size: 512 entries
233
* 8 TB is still more than the maximal value supported for
234
* VMDK3 & VMDK4 which is 2TB.
235
+ * 64TB - for "ESXi seSparse Extent"
236
+ * minimal cluster size: 512B (default is 4KB)
237
+ * L2 table size: 4096 entries (const).
238
+ * 64TB is more than the maximal value supported for
239
+ * seSparse VMDKs (which is slightly less than 64TB)
240
*/
241
error_setg(errp, "L1 size too big");
242
return -EFBIG;
243
@@ -XXX,XX +XXX,XX @@ static int vmdk_add_extent(BlockDriverState *bs,
244
extent->l2_size = l2_size;
245
extent->cluster_sectors = flat ? sectors : cluster_sectors;
246
extent->next_cluster_sector = ROUND_UP(nb_sectors, cluster_sectors);
247
+ extent->entry_size = sizeof(uint32_t);
248
249
if (s->num_extents > 1) {
250
extent->end_sector = (*(extent - 1)).end_sector + extent->sectors;
251
@@ -XXX,XX +XXX,XX @@ static int vmdk_init_tables(BlockDriverState *bs, VmdkExtent *extent,
252
int i;
253
254
/* read the L1 table */
255
- l1_size = extent->l1_size * sizeof(uint32_t);
256
+ l1_size = extent->l1_size * extent->entry_size;
257
extent->l1_table = g_try_malloc(l1_size);
258
if (l1_size && extent->l1_table == NULL) {
259
return -ENOMEM;
260
@@ -XXX,XX +XXX,XX @@ static int vmdk_init_tables(BlockDriverState *bs, VmdkExtent *extent,
261
goto fail_l1;
262
}
263
for (i = 0; i < extent->l1_size; i++) {
264
- le32_to_cpus(&extent->l1_table[i]);
265
+ if (extent->entry_size == sizeof(uint64_t)) {
266
+ le64_to_cpus((uint64_t *)extent->l1_table + i);
267
+ } else {
268
+ assert(extent->entry_size == sizeof(uint32_t));
269
+ le32_to_cpus((uint32_t *)extent->l1_table + i);
270
+ }
271
}
272
273
if (extent->l1_backup_table_offset) {
274
+ assert(!extent->sesparse);
275
extent->l1_backup_table = g_try_malloc(l1_size);
276
if (l1_size && extent->l1_backup_table == NULL) {
277
ret = -ENOMEM;
278
@@ -XXX,XX +XXX,XX @@ static int vmdk_init_tables(BlockDriverState *bs, VmdkExtent *extent,
279
}
280
281
extent->l2_cache =
282
- g_new(uint32_t, extent->l2_size * L2_CACHE_SIZE);
283
+ g_malloc(extent->entry_size * extent->l2_size * L2_CACHE_SIZE);
284
return 0;
285
fail_l1b:
286
g_free(extent->l1_backup_table);
287
@@ -XXX,XX +XXX,XX @@ static int vmdk_open_vmfs_sparse(BlockDriverState *bs,
288
return ret;
40
}
289
}
41
290
42
-void bdrv_set_read_only(BlockDriverState *bs, bool read_only)
291
+#define SESPARSE_CONST_HEADER_MAGIC UINT64_C(0x00000000cafebabe)
43
+int bdrv_set_read_only(BlockDriverState *bs, bool read_only, Error **errp)
292
+#define SESPARSE_VOLATILE_HEADER_MAGIC UINT64_C(0x00000000cafecafe)
44
{
293
+
45
+ /* Do not set read_only if copy_on_read is enabled */
294
+/* Strict checks - format not officially documented */
46
+ if (bs->copy_on_read && read_only) {
295
+static int check_se_sparse_const_header(VMDKSESparseConstHeader *header,
47
+ error_setg(errp, "Can't set node '%s' to r/o with copy-on-read enabled",
296
+ Error **errp)
48
+ bdrv_get_device_or_node_name(bs));
297
+{
298
+ header->magic = le64_to_cpu(header->magic);
299
+ header->version = le64_to_cpu(header->version);
300
+ header->grain_size = le64_to_cpu(header->grain_size);
301
+ header->grain_table_size = le64_to_cpu(header->grain_table_size);
302
+ header->flags = le64_to_cpu(header->flags);
303
+ header->reserved1 = le64_to_cpu(header->reserved1);
304
+ header->reserved2 = le64_to_cpu(header->reserved2);
305
+ header->reserved3 = le64_to_cpu(header->reserved3);
306
+ header->reserved4 = le64_to_cpu(header->reserved4);
307
+
308
+ header->volatile_header_offset =
309
+ le64_to_cpu(header->volatile_header_offset);
310
+ header->volatile_header_size = le64_to_cpu(header->volatile_header_size);
311
+
312
+ header->journal_header_offset = le64_to_cpu(header->journal_header_offset);
313
+ header->journal_header_size = le64_to_cpu(header->journal_header_size);
314
+
315
+ header->journal_offset = le64_to_cpu(header->journal_offset);
316
+ header->journal_size = le64_to_cpu(header->journal_size);
317
+
318
+ header->grain_dir_offset = le64_to_cpu(header->grain_dir_offset);
319
+ header->grain_dir_size = le64_to_cpu(header->grain_dir_size);
320
+
321
+ header->grain_tables_offset = le64_to_cpu(header->grain_tables_offset);
322
+ header->grain_tables_size = le64_to_cpu(header->grain_tables_size);
323
+
324
+ header->free_bitmap_offset = le64_to_cpu(header->free_bitmap_offset);
325
+ header->free_bitmap_size = le64_to_cpu(header->free_bitmap_size);
326
+
327
+ header->backmap_offset = le64_to_cpu(header->backmap_offset);
328
+ header->backmap_size = le64_to_cpu(header->backmap_size);
329
+
330
+ header->grains_offset = le64_to_cpu(header->grains_offset);
331
+ header->grains_size = le64_to_cpu(header->grains_size);
332
+
333
+ if (header->magic != SESPARSE_CONST_HEADER_MAGIC) {
334
+ error_setg(errp, "Bad const header magic: 0x%016" PRIx64,
335
+ header->magic);
49
+ return -EINVAL;
336
+ return -EINVAL;
50
+ }
337
+ }
51
+
338
+
52
bs->read_only = read_only;
339
+ if (header->version != 0x0000000200000001) {
340
+ error_setg(errp, "Unsupported version: 0x%016" PRIx64,
341
+ header->version);
342
+ return -ENOTSUP;
343
+ }
344
+
345
+ if (header->grain_size != 8) {
346
+ error_setg(errp, "Unsupported grain size: %" PRIu64,
347
+ header->grain_size);
348
+ return -ENOTSUP;
349
+ }
350
+
351
+ if (header->grain_table_size != 64) {
352
+ error_setg(errp, "Unsupported grain table size: %" PRIu64,
353
+ header->grain_table_size);
354
+ return -ENOTSUP;
355
+ }
356
+
357
+ if (header->flags != 0) {
358
+ error_setg(errp, "Unsupported flags: 0x%016" PRIx64,
359
+ header->flags);
360
+ return -ENOTSUP;
361
+ }
362
+
363
+ if (header->reserved1 != 0 || header->reserved2 != 0 ||
364
+ header->reserved3 != 0 || header->reserved4 != 0) {
365
+ error_setg(errp, "Unsupported reserved bits:"
366
+ " 0x%016" PRIx64 " 0x%016" PRIx64
367
+ " 0x%016" PRIx64 " 0x%016" PRIx64,
368
+ header->reserved1, header->reserved2,
369
+ header->reserved3, header->reserved4);
370
+ return -ENOTSUP;
371
+ }
372
+
373
+ /* check that padding is 0 */
374
+ if (!buffer_is_zero(header->pad, sizeof(header->pad))) {
375
+ error_setg(errp, "Unsupported non-zero const header padding");
376
+ return -ENOTSUP;
377
+ }
378
+
53
+ return 0;
379
+ return 0;
54
}
380
+}
55
381
+
56
void bdrv_get_full_backing_filename_from_filename(const char *backed,
382
+static int check_se_sparse_volatile_header(VMDKSESparseVolatileHeader *header,
57
diff --git a/block/bochs.c b/block/bochs.c
383
+ Error **errp)
58
index XXXXXXX..XXXXXXX 100644
384
+{
59
--- a/block/bochs.c
385
+ header->magic = le64_to_cpu(header->magic);
60
+++ b/block/bochs.c
386
+ header->free_gt_number = le64_to_cpu(header->free_gt_number);
61
@@ -XXX,XX +XXX,XX @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags,
387
+ header->next_txn_seq_number = le64_to_cpu(header->next_txn_seq_number);
62
return -EINVAL;
388
+ header->replay_journal = le64_to_cpu(header->replay_journal);
63
}
389
+
64
390
+ if (header->magic != SESPARSE_VOLATILE_HEADER_MAGIC) {
65
- bdrv_set_read_only(bs, true); /* no write support yet */
391
+ error_setg(errp, "Bad volatile header magic: 0x%016" PRIx64,
66
+ ret = bdrv_set_read_only(bs, true, errp); /* no write support yet */
392
+ header->magic);
393
+ return -EINVAL;
394
+ }
395
+
396
+ if (header->replay_journal) {
397
+ error_setg(errp, "Image is dirty, Replaying journal not supported");
398
+ return -ENOTSUP;
399
+ }
400
+
401
+ /* check that padding is 0 */
402
+ if (!buffer_is_zero(header->pad, sizeof(header->pad))) {
403
+ error_setg(errp, "Unsupported non-zero volatile header padding");
404
+ return -ENOTSUP;
405
+ }
406
+
407
+ return 0;
408
+}
409
+
410
+static int vmdk_open_se_sparse(BlockDriverState *bs,
411
+ BdrvChild *file,
412
+ int flags, Error **errp)
413
+{
414
+ int ret;
415
+ VMDKSESparseConstHeader const_header;
416
+ VMDKSESparseVolatileHeader volatile_header;
417
+ VmdkExtent *extent;
418
+
419
+ ret = bdrv_apply_auto_read_only(bs,
420
+ "No write support for seSparse images available", errp);
67
+ if (ret < 0) {
421
+ if (ret < 0) {
68
+ return ret;
422
+ return ret;
69
+ }
423
+ }
70
424
+
71
ret = bdrv_pread(bs->file, 0, &bochs, sizeof(bochs));
425
+ assert(sizeof(const_header) == SECTOR_SIZE);
72
if (ret < 0) {
426
+
73
diff --git a/block/cloop.c b/block/cloop.c
427
+ ret = bdrv_pread(file, 0, &const_header, sizeof(const_header));
74
index XXXXXXX..XXXXXXX 100644
428
+ if (ret < 0) {
75
--- a/block/cloop.c
429
+ bdrv_refresh_filename(file->bs);
76
+++ b/block/cloop.c
430
+ error_setg_errno(errp, -ret,
77
@@ -XXX,XX +XXX,XX @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
431
+ "Could not read const header from file '%s'",
78
return -EINVAL;
432
+ file->bs->filename);
79
}
433
+ return ret;
80
434
+ }
81
- bdrv_set_read_only(bs, true);
435
+
82
+ ret = bdrv_set_read_only(bs, true, errp);
436
+ /* check const header */
437
+ ret = check_se_sparse_const_header(&const_header, errp);
83
+ if (ret < 0) {
438
+ if (ret < 0) {
84
+ return ret;
439
+ return ret;
85
+ }
440
+ }
86
441
+
87
/* read header */
442
+ assert(sizeof(volatile_header) == SECTOR_SIZE);
88
ret = bdrv_pread(bs->file, 128, &s->block_size, 4);
443
+
89
diff --git a/block/dmg.c b/block/dmg.c
444
+ ret = bdrv_pread(file,
90
index XXXXXXX..XXXXXXX 100644
445
+ const_header.volatile_header_offset * SECTOR_SIZE,
91
--- a/block/dmg.c
446
+ &volatile_header, sizeof(volatile_header));
92
+++ b/block/dmg.c
447
+ if (ret < 0) {
93
@@ -XXX,XX +XXX,XX @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
448
+ bdrv_refresh_filename(file->bs);
94
return -EINVAL;
449
+ error_setg_errno(errp, -ret,
95
}
450
+ "Could not read volatile header from file '%s'",
96
451
+ file->bs->filename);
97
+ ret = bdrv_set_read_only(bs, true, errp);
452
+ return ret;
453
+ }
454
+
455
+ /* check volatile header */
456
+ ret = check_se_sparse_volatile_header(&volatile_header, errp);
98
+ if (ret < 0) {
457
+ if (ret < 0) {
99
+ return ret;
458
+ return ret;
100
+ }
459
+ }
101
+
460
+
102
block_module_load_one("dmg-bz2");
461
+ ret = vmdk_add_extent(bs, file, false,
103
- bdrv_set_read_only(bs, true);
462
+ const_header.capacity,
104
463
+ const_header.grain_dir_offset * SECTOR_SIZE,
105
s->n_chunks = 0;
464
+ 0,
106
s->offsets = s->lengths = s->sectors = s->sectorcounts = NULL;
465
+ const_header.grain_dir_size *
107
diff --git a/block/rbd.c b/block/rbd.c
466
+ SECTOR_SIZE / sizeof(uint64_t),
108
index XXXXXXX..XXXXXXX 100644
467
+ const_header.grain_table_size *
109
--- a/block/rbd.c
468
+ SECTOR_SIZE / sizeof(uint64_t),
110
+++ b/block/rbd.c
469
+ const_header.grain_size,
111
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
470
+ &extent,
112
goto failed_shutdown;
471
+ errp);
113
}
472
+ if (ret < 0) {
114
473
+ return ret;
115
+ /* rbd_open is always r/w */
474
+ }
116
r = rbd_open(s->io_ctx, s->name, &s->image, s->snap);
475
+
117
if (r < 0) {
476
+ extent->sesparse = true;
118
error_setg_errno(errp, -r, "error reading header from %s", s->name);
477
+ extent->sesparse_l2_tables_offset = const_header.grain_tables_offset;
119
goto failed_open;
478
+ extent->sesparse_clusters_offset = const_header.grains_offset;
120
}
479
+ extent->entry_size = sizeof(uint64_t);
121
480
+
122
- bdrv_set_read_only(bs, (s->snap != NULL));
481
+ ret = vmdk_init_tables(bs, extent, errp);
123
+ /* If we are using an rbd snapshot, we must be r/o, otherwise
482
+ if (ret) {
124
+ * leave as-is */
483
+ /* free extent allocated by vmdk_add_extent */
125
+ if (s->snap != NULL) {
484
+ vmdk_free_last_extent(bs);
126
+ r = bdrv_set_read_only(bs, true, &local_err);
485
+ }
127
+ if (r < 0) {
486
+
128
+ error_propagate(errp, local_err);
487
+ return ret;
129
+ goto failed_open;
488
+}
489
+
490
static int vmdk_open_desc_file(BlockDriverState *bs, int flags, char *buf,
491
QDict *options, Error **errp);
492
493
@@ -XXX,XX +XXX,XX @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
494
* RW [size in sectors] SPARSE "file-name.vmdk"
495
* RW [size in sectors] VMFS "file-name.vmdk"
496
* RW [size in sectors] VMFSSPARSE "file-name.vmdk"
497
+ * RW [size in sectors] SESPARSE "file-name.vmdk"
498
*/
499
flat_offset = -1;
500
matches = sscanf(p, "%10s %" SCNd64 " %10s \"%511[^\n\r\"]\" %" SCNd64,
501
@@ -XXX,XX +XXX,XX @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
502
503
if (sectors <= 0 ||
504
(strcmp(type, "FLAT") && strcmp(type, "SPARSE") &&
505
- strcmp(type, "VMFS") && strcmp(type, "VMFSSPARSE")) ||
506
+ strcmp(type, "VMFS") && strcmp(type, "VMFSSPARSE") &&
507
+ strcmp(type, "SESPARSE")) ||
508
(strcmp(access, "RW"))) {
509
continue;
510
}
511
@@ -XXX,XX +XXX,XX @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
512
return ret;
513
}
514
extent = &s->extents[s->num_extents - 1];
515
+ } else if (!strcmp(type, "SESPARSE")) {
516
+ ret = vmdk_open_se_sparse(bs, extent_file, bs->open_flags, errp);
517
+ if (ret) {
518
+ bdrv_unref_child(bs, extent_file);
519
+ return ret;
520
+ }
521
+ extent = &s->extents[s->num_extents - 1];
522
} else {
523
error_setg(errp, "Unsupported extent type '%s'", type);
524
bdrv_unref_child(bs, extent_file);
525
@@ -XXX,XX +XXX,XX @@ static int vmdk_open_desc_file(BlockDriverState *bs, int flags, char *buf,
526
if (strcmp(ct, "monolithicFlat") &&
527
strcmp(ct, "vmfs") &&
528
strcmp(ct, "vmfsSparse") &&
529
+ strcmp(ct, "seSparse") &&
530
strcmp(ct, "twoGbMaxExtentSparse") &&
531
strcmp(ct, "twoGbMaxExtentFlat")) {
532
error_setg(errp, "Unsupported image type '%s'", ct);
533
@@ -XXX,XX +XXX,XX @@ static int get_cluster_offset(BlockDriverState *bs,
534
{
535
unsigned int l1_index, l2_offset, l2_index;
536
int min_index, i, j;
537
- uint32_t min_count, *l2_table;
538
+ uint32_t min_count;
539
+ void *l2_table;
540
bool zeroed = false;
541
int64_t ret;
542
int64_t cluster_sector;
543
+ unsigned int l2_size_bytes = extent->l2_size * extent->entry_size;
544
545
if (m_data) {
546
m_data->valid = 0;
547
@@ -XXX,XX +XXX,XX @@ static int get_cluster_offset(BlockDriverState *bs,
548
if (l1_index >= extent->l1_size) {
549
return VMDK_ERROR;
550
}
551
- l2_offset = extent->l1_table[l1_index];
552
+ if (extent->sesparse) {
553
+ uint64_t l2_offset_u64;
554
+
555
+ assert(extent->entry_size == sizeof(uint64_t));
556
+
557
+ l2_offset_u64 = ((uint64_t *)extent->l1_table)[l1_index];
558
+ if (l2_offset_u64 == 0) {
559
+ l2_offset = 0;
560
+ } else if ((l2_offset_u64 & 0xffffffff00000000) != 0x1000000000000000) {
561
+ /*
562
+ * Top most nibble is 0x1 if grain table is allocated.
563
+ * strict check - top most 4 bytes must be 0x10000000 since max
564
+ * supported size is 64TB for disk - so no more than 64TB / 16MB
565
+ * grain directories which is smaller than uint32,
566
+ * where 16MB is the only supported default grain table coverage.
567
+ */
568
+ return VMDK_ERROR;
569
+ } else {
570
+ l2_offset_u64 = l2_offset_u64 & 0x00000000ffffffff;
571
+ l2_offset_u64 = extent->sesparse_l2_tables_offset +
572
+ l2_offset_u64 * l2_size_bytes / SECTOR_SIZE;
573
+ if (l2_offset_u64 > 0x00000000ffffffff) {
574
+ return VMDK_ERROR;
575
+ }
576
+ l2_offset = (unsigned int)(l2_offset_u64);
130
+ }
577
+ }
131
+ }
578
+ } else {
132
579
+ assert(extent->entry_size == sizeof(uint32_t));
133
qemu_opts_del(opts);
580
+ l2_offset = ((uint32_t *)extent->l1_table)[l1_index];
134
return 0;
581
+ }
135
diff --git a/block/vvfat.c b/block/vvfat.c
582
if (!l2_offset) {
136
index XXXXXXX..XXXXXXX 100644
583
return VMDK_UNALLOC;
137
--- a/block/vvfat.c
584
}
138
+++ b/block/vvfat.c
585
@@ -XXX,XX +XXX,XX @@ static int get_cluster_offset(BlockDriverState *bs,
139
@@ -XXX,XX +XXX,XX @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags,
586
extent->l2_cache_counts[j] >>= 1;
140
587
}
141
s->current_cluster=0xffffffff;
588
}
142
589
- l2_table = extent->l2_cache + (i * extent->l2_size);
143
- /* read only is the default for safety */
590
+ l2_table = (char *)extent->l2_cache + (i * l2_size_bytes);
144
- bdrv_set_read_only(bs, true);
591
goto found;
145
s->qcow = NULL;
592
}
146
s->qcow_filename = NULL;
593
}
147
s->fat2 = NULL;
594
@@ -XXX,XX +XXX,XX @@ static int get_cluster_offset(BlockDriverState *bs,
148
@@ -XXX,XX +XXX,XX @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags,
595
min_index = i;
149
s->sector_count = cyls * heads * secs - (s->first_sectors_number - 1);
596
}
150
597
}
151
if (qemu_opt_get_bool(opts, "rw", false)) {
598
- l2_table = extent->l2_cache + (min_index * extent->l2_size);
152
- ret = enable_write_target(bs, errp);
599
+ l2_table = (char *)extent->l2_cache + (min_index * l2_size_bytes);
153
+ if (!bdrv_is_read_only(bs)) {
600
BLKDBG_EVENT(extent->file, BLKDBG_L2_LOAD);
154
+ ret = enable_write_target(bs, errp);
601
if (bdrv_pread(extent->file,
155
+ if (ret < 0) {
602
(int64_t)l2_offset * 512,
156
+ goto fail;
603
l2_table,
604
- extent->l2_size * sizeof(uint32_t)
605
- ) != extent->l2_size * sizeof(uint32_t)) {
606
+ l2_size_bytes
607
+ ) != l2_size_bytes) {
608
return VMDK_ERROR;
609
}
610
611
@@ -XXX,XX +XXX,XX @@ static int get_cluster_offset(BlockDriverState *bs,
612
extent->l2_cache_counts[min_index] = 1;
613
found:
614
l2_index = ((offset >> 9) / extent->cluster_sectors) % extent->l2_size;
615
- cluster_sector = le32_to_cpu(l2_table[l2_index]);
616
617
- if (extent->has_zero_grain && cluster_sector == VMDK_GTE_ZEROED) {
618
- zeroed = true;
619
+ if (extent->sesparse) {
620
+ cluster_sector = le64_to_cpu(((uint64_t *)l2_table)[l2_index]);
621
+ switch (cluster_sector & 0xf000000000000000) {
622
+ case 0x0000000000000000:
623
+ /* unallocated grain */
624
+ if (cluster_sector != 0) {
625
+ return VMDK_ERROR;
157
+ }
626
+ }
158
+ } else {
627
+ break;
159
+ ret = -EPERM;
628
+ case 0x1000000000000000:
160
+ error_setg(errp,
629
+ /* scsi-unmapped grain - fallthrough */
161
+ "Unable to set VVFAT to 'rw' when drive is read-only");
630
+ case 0x2000000000000000:
162
+ goto fail;
631
+ /* zero grain */
632
+ zeroed = true;
633
+ break;
634
+ case 0x3000000000000000:
635
+ /* allocated grain */
636
+ cluster_sector = (((cluster_sector & 0x0fff000000000000) >> 48) |
637
+ ((cluster_sector & 0x0000ffffffffffff) << 12));
638
+ cluster_sector = extent->sesparse_clusters_offset +
639
+ cluster_sector * extent->cluster_sectors;
640
+ break;
641
+ default:
642
+ return VMDK_ERROR;
163
+ }
643
+ }
164
+ } else {
644
+ } else {
165
+ /* read only is the default for safety */
645
+ cluster_sector = le32_to_cpu(((uint32_t *)l2_table)[l2_index]);
166
+ ret = bdrv_set_read_only(bs, true, &local_err);
646
+
167
if (ret < 0) {
647
+ if (extent->has_zero_grain && cluster_sector == VMDK_GTE_ZEROED) {
168
+ error_propagate(errp, local_err);
648
+ zeroed = true;
169
goto fail;
649
+ }
650
}
651
652
if (!cluster_sector || zeroed) {
653
if (!allocate) {
654
return zeroed ? VMDK_ZEROED : VMDK_UNALLOC;
170
}
655
}
171
- bdrv_set_read_only(bs, false);
656
+ assert(!extent->sesparse);
172
}
657
173
658
if (extent->next_cluster_sector >= VMDK_EXTENT_MAX_SECTORS) {
174
bs->total_sectors = cyls * heads * secs;
659
return VMDK_ERROR;
175
diff --git a/include/block/block.h b/include/block/block.h
660
@@ -XXX,XX +XXX,XX @@ static int get_cluster_offset(BlockDriverState *bs,
176
index XXXXXXX..XXXXXXX 100644
661
m_data->l1_index = l1_index;
177
--- a/include/block/block.h
662
m_data->l2_index = l2_index;
178
+++ b/include/block/block.h
663
m_data->l2_offset = l2_offset;
179
@@ -XXX,XX +XXX,XX @@ int bdrv_is_allocated_above(BlockDriverState *top, BlockDriverState *base,
664
- m_data->l2_cache_entry = &l2_table[l2_index];
180
int64_t sector_num, int nb_sectors, int *pnum);
665
+ m_data->l2_cache_entry = ((uint32_t *)l2_table) + l2_index;
181
666
}
182
bool bdrv_is_read_only(BlockDriverState *bs);
667
}
183
-void bdrv_set_read_only(BlockDriverState *bs, bool read_only);
668
*cluster_offset = cluster_sector << BDRV_SECTOR_BITS;
184
+int bdrv_set_read_only(BlockDriverState *bs, bool read_only, Error **errp);
669
@@ -XXX,XX +XXX,XX @@ static int vmdk_pwritev(BlockDriverState *bs, uint64_t offset,
185
bool bdrv_is_sg(BlockDriverState *bs);
670
if (!extent) {
186
bool bdrv_is_inserted(BlockDriverState *bs);
671
return -EIO;
187
int bdrv_media_changed(BlockDriverState *bs);
672
}
673
+ if (extent->sesparse) {
674
+ return -ENOTSUP;
675
+ }
676
offset_in_cluster = vmdk_find_offset_in_cluster(extent, offset);
677
n_bytes = MIN(bytes, extent->cluster_sectors * BDRV_SECTOR_SIZE
678
- offset_in_cluster);
188
--
679
--
189
2.9.3
680
2.21.0
190
681
191
682
diff view generated by jsdifflib
1
From: Ashish Mittal <ashmit602@gmail.com>
1
From: Pino Toscano <ptoscano@redhat.com>
2
2
3
Source code for the qnio library that this code loads can be downloaded from:
3
Rewrite the implementation of the ssh block driver to use libssh instead
4
https://github.com/VeritasHyperScale/libqnio.git
4
of libssh2. The libssh library has various advantages over libssh2:
5
- easier API for authentication (for example for using ssh-agent)
6
- easier API for known_hosts handling
7
- supports newer types of keys in known_hosts
5
8
6
Sample command line using JSON syntax:
9
Use APIs/features available in libssh 0.8 conditionally, to support
7
./x86_64-softmmu/qemu-system-x86_64 -name instance-00000008 -S -vnc 0.0.0.0:0
10
older versions (which are not recommended though).
8
-k en-us -vga cirrus -device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x5
9
-msg timestamp=on
10
'json:{"driver":"vxhs","vdisk-id":"c3e9095a-a5ee-4dce-afeb-2a59fb387410",
11
"server":{"host":"172.172.17.4","port":"9999"}}'
12
11
13
Sample command line using URI syntax:
12
Adjust the iotest 207 according to the different error message, and to
14
qemu-img convert -f raw -O raw -n
13
find the default key type for localhost (to properly compare the
15
/var/lib/nova/instances/_base/0c5eacd5ebea5ed914b6a3e7b18f1ce734c386ad
14
fingerprint with).
16
vxhs://192.168.0.1:9999/c6718f6b-0401-441d-a8c3-1f0064d75ee0
15
Contributed-by: Max Reitz <mreitz@redhat.com>
17
16
18
Sample command line using TLS credentials (run in secure mode):
17
Adjust the various Docker/Travis scripts to use libssh when available
19
./qemu-io --object
18
instead of libssh2. The mingw/mxe testing is dropped for now, as there
20
tls-creds-x509,id=tls0,dir=/etc/pki/qemu/vxhs,endpoint=client -c 'read
19
are no packages for it.
21
-v 66000 2.5k' 'json:{"server.host": "127.0.0.1", "server.port": "9999",
22
"vdisk-id": "/test.raw", "driver": "vxhs", "tls-creds":"tls0"}'
23
20
24
Signed-off-by: Ashish Mittal <Ashish.Mittal@veritas.com>
21
Signed-off-by: Pino Toscano <ptoscano@redhat.com>
25
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
22
Tested-by: Philippe Mathieu-Daudé <philmd@redhat.com>
26
Reviewed-by: Jeff Cody <jcody@redhat.com>
23
Acked-by: Alex Bennée <alex.bennee@linaro.org>
27
Signed-off-by: Jeff Cody <jcody@redhat.com>
24
Message-id: 20190620200840.17655-1-ptoscano@redhat.com
28
Message-id: 1491277689-24949-2-git-send-email-Ashish.Mittal@veritas.com
25
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
26
Message-id: 5873173.t2JhDm7DL7@lindworm.usersys.redhat.com
27
Signed-off-by: Max Reitz <mreitz@redhat.com>
29
---
28
---
30
block/Makefile.objs | 2 +
29
configure | 65 +-
31
block/trace-events | 17 ++
30
block/Makefile.objs | 6 +-
32
block/vxhs.c | 575 +++++++++++++++++++++++++++++++++++++++++++++++++++
31
block/ssh.c | 652 ++++++++++--------
33
configure | 39 ++++
32
.travis.yml | 4 +-
34
qapi/block-core.json | 23 ++-
33
block/trace-events | 14 +-
35
5 files changed, 654 insertions(+), 2 deletions(-)
34
docs/qemu-block-drivers.texi | 2 +-
36
create mode 100644 block/vxhs.c
35
.../dockerfiles/debian-win32-cross.docker | 1 -
36
.../dockerfiles/debian-win64-cross.docker | 1 -
37
tests/docker/dockerfiles/fedora.docker | 4 +-
38
tests/docker/dockerfiles/ubuntu.docker | 2 +-
39
tests/docker/dockerfiles/ubuntu1804.docker | 2 +-
40
tests/qemu-iotests/207 | 54 +-
41
tests/qemu-iotests/207.out | 2 +-
42
13 files changed, 449 insertions(+), 360 deletions(-)
37
43
44
diff --git a/configure b/configure
45
index XXXXXXX..XXXXXXX 100755
46
--- a/configure
47
+++ b/configure
48
@@ -XXX,XX +XXX,XX @@ auth_pam=""
49
vte=""
50
virglrenderer=""
51
tpm=""
52
-libssh2=""
53
+libssh=""
54
live_block_migration="yes"
55
numa=""
56
tcmalloc="no"
57
@@ -XXX,XX +XXX,XX @@ for opt do
58
;;
59
--enable-tpm) tpm="yes"
60
;;
61
- --disable-libssh2) libssh2="no"
62
+ --disable-libssh) libssh="no"
63
;;
64
- --enable-libssh2) libssh2="yes"
65
+ --enable-libssh) libssh="yes"
66
;;
67
--disable-live-block-migration) live_block_migration="no"
68
;;
69
@@ -XXX,XX +XXX,XX @@ disabled with --disable-FEATURE, default is enabled if available:
70
coroutine-pool coroutine freelist (better performance)
71
glusterfs GlusterFS backend
72
tpm TPM support
73
- libssh2 ssh block device support
74
+ libssh ssh block device support
75
numa libnuma support
76
libxml2 for Parallels image format
77
tcmalloc tcmalloc support
78
@@ -XXX,XX +XXX,XX @@ EOF
79
fi
80
81
##########################################
82
-# libssh2 probe
83
-min_libssh2_version=1.2.8
84
-if test "$libssh2" != "no" ; then
85
- if $pkg_config --atleast-version=$min_libssh2_version libssh2; then
86
- libssh2_cflags=$($pkg_config libssh2 --cflags)
87
- libssh2_libs=$($pkg_config libssh2 --libs)
88
- libssh2=yes
89
+# libssh probe
90
+if test "$libssh" != "no" ; then
91
+ if $pkg_config --exists libssh; then
92
+ libssh_cflags=$($pkg_config libssh --cflags)
93
+ libssh_libs=$($pkg_config libssh --libs)
94
+ libssh=yes
95
else
96
- if test "$libssh2" = "yes" ; then
97
- error_exit "libssh2 >= $min_libssh2_version required for --enable-libssh2"
98
+ if test "$libssh" = "yes" ; then
99
+ error_exit "libssh required for --enable-libssh"
100
fi
101
- libssh2=no
102
+ libssh=no
103
fi
104
fi
105
106
##########################################
107
-# libssh2_sftp_fsync probe
108
+# Check for libssh 0.8
109
+# This is done like this instead of using the LIBSSH_VERSION_* and
110
+# SSH_VERSION_* macros because some distributions in the past shipped
111
+# snapshots of the future 0.8 from Git, and those snapshots did not
112
+# have updated version numbers (still referring to 0.7.0).
113
114
-if test "$libssh2" = "yes"; then
115
+if test "$libssh" = "yes"; then
116
cat > $TMPC <<EOF
117
-#include <stdio.h>
118
-#include <libssh2.h>
119
-#include <libssh2_sftp.h>
120
-int main(void) {
121
- LIBSSH2_SESSION *session;
122
- LIBSSH2_SFTP *sftp;
123
- LIBSSH2_SFTP_HANDLE *sftp_handle;
124
- session = libssh2_session_init ();
125
- sftp = libssh2_sftp_init (session);
126
- sftp_handle = libssh2_sftp_open (sftp, "/", 0, 0);
127
- libssh2_sftp_fsync (sftp_handle);
128
- return 0;
129
-}
130
+#include <libssh/libssh.h>
131
+int main(void) { return ssh_get_server_publickey(NULL, NULL); }
132
EOF
133
- # libssh2_cflags/libssh2_libs defined in previous test.
134
- if compile_prog "$libssh2_cflags" "$libssh2_libs" ; then
135
- QEMU_CFLAGS="-DHAS_LIBSSH2_SFTP_FSYNC $QEMU_CFLAGS"
136
+ if compile_prog "$libssh_cflags" "$libssh_libs"; then
137
+ libssh_cflags="-DHAVE_LIBSSH_0_8 $libssh_cflags"
138
fi
139
fi
140
141
@@ -XXX,XX +XXX,XX @@ echo "GlusterFS support $glusterfs"
142
echo "gcov $gcov_tool"
143
echo "gcov enabled $gcov"
144
echo "TPM support $tpm"
145
-echo "libssh2 support $libssh2"
146
+echo "libssh support $libssh"
147
echo "QOM debugging $qom_cast_debug"
148
echo "Live block migration $live_block_migration"
149
echo "lzo support $lzo"
150
@@ -XXX,XX +XXX,XX @@ if test "$glusterfs_iocb_has_stat" = "yes" ; then
151
echo "CONFIG_GLUSTERFS_IOCB_HAS_STAT=y" >> $config_host_mak
152
fi
153
154
-if test "$libssh2" = "yes" ; then
155
- echo "CONFIG_LIBSSH2=m" >> $config_host_mak
156
- echo "LIBSSH2_CFLAGS=$libssh2_cflags" >> $config_host_mak
157
- echo "LIBSSH2_LIBS=$libssh2_libs" >> $config_host_mak
158
+if test "$libssh" = "yes" ; then
159
+ echo "CONFIG_LIBSSH=m" >> $config_host_mak
160
+ echo "LIBSSH_CFLAGS=$libssh_cflags" >> $config_host_mak
161
+ echo "LIBSSH_LIBS=$libssh_libs" >> $config_host_mak
162
fi
163
164
if test "$live_block_migration" = "yes" ; then
38
diff --git a/block/Makefile.objs b/block/Makefile.objs
165
diff --git a/block/Makefile.objs b/block/Makefile.objs
39
index XXXXXXX..XXXXXXX 100644
166
index XXXXXXX..XXXXXXX 100644
40
--- a/block/Makefile.objs
167
--- a/block/Makefile.objs
41
+++ b/block/Makefile.objs
168
+++ b/block/Makefile.objs
42
@@ -XXX,XX +XXX,XX @@ block-obj-$(CONFIG_LIBNFS) += nfs.o
169
@@ -XXX,XX +XXX,XX @@ block-obj-$(CONFIG_CURL) += curl.o
43
block-obj-$(CONFIG_CURL) += curl.o
44
block-obj-$(CONFIG_RBD) += rbd.o
170
block-obj-$(CONFIG_RBD) += rbd.o
45
block-obj-$(CONFIG_GLUSTERFS) += gluster.o
171
block-obj-$(CONFIG_GLUSTERFS) += gluster.o
46
+block-obj-$(CONFIG_VXHS) += vxhs.o
172
block-obj-$(CONFIG_VXHS) += vxhs.o
47
block-obj-$(CONFIG_LIBSSH2) += ssh.o
173
-block-obj-$(CONFIG_LIBSSH2) += ssh.o
174
+block-obj-$(CONFIG_LIBSSH) += ssh.o
48
block-obj-y += accounting.o dirty-bitmap.o
175
block-obj-y += accounting.o dirty-bitmap.o
49
block-obj-y += write-threshold.o
176
block-obj-y += write-threshold.o
50
@@ -XXX,XX +XXX,XX @@ rbd.o-cflags := $(RBD_CFLAGS)
177
block-obj-y += backup.o
51
rbd.o-libs := $(RBD_LIBS)
178
@@ -XXX,XX +XXX,XX @@ rbd.o-libs := $(RBD_LIBS)
52
gluster.o-cflags := $(GLUSTERFS_CFLAGS)
179
gluster.o-cflags := $(GLUSTERFS_CFLAGS)
53
gluster.o-libs := $(GLUSTERFS_LIBS)
180
gluster.o-libs := $(GLUSTERFS_LIBS)
54
+vxhs.o-libs := $(VXHS_LIBS)
181
vxhs.o-libs := $(VXHS_LIBS)
55
ssh.o-cflags := $(LIBSSH2_CFLAGS)
182
-ssh.o-cflags := $(LIBSSH2_CFLAGS)
56
ssh.o-libs := $(LIBSSH2_LIBS)
183
-ssh.o-libs := $(LIBSSH2_LIBS)
57
block-obj-$(if $(CONFIG_BZIP2),m,n) += dmg-bz2.o
184
+ssh.o-cflags := $(LIBSSH_CFLAGS)
185
+ssh.o-libs := $(LIBSSH_LIBS)
186
block-obj-dmg-bz2-$(CONFIG_BZIP2) += dmg-bz2.o
187
block-obj-$(if $(CONFIG_DMG),m,n) += $(block-obj-dmg-bz2-y)
188
dmg-bz2.o-libs := $(BZIP2_LIBS)
189
diff --git a/block/ssh.c b/block/ssh.c
190
index XXXXXXX..XXXXXXX 100644
191
--- a/block/ssh.c
192
+++ b/block/ssh.c
193
@@ -XXX,XX +XXX,XX @@
194
195
#include "qemu/osdep.h"
196
197
-#include <libssh2.h>
198
-#include <libssh2_sftp.h>
199
+#include <libssh/libssh.h>
200
+#include <libssh/sftp.h>
201
202
#include "block/block_int.h"
203
#include "block/qdict.h"
204
@@ -XXX,XX +XXX,XX @@
205
#include "trace.h"
206
207
/*
208
- * TRACE_LIBSSH2=<bitmask> enables tracing in libssh2 itself. Note
209
- * that this requires that libssh2 was specially compiled with the
210
- * `./configure --enable-debug' option, so most likely you will have
211
- * to compile it yourself. The meaning of <bitmask> is described
212
- * here: http://www.libssh2.org/libssh2_trace.html
213
+ * TRACE_LIBSSH=<level> enables tracing in libssh itself.
214
+ * The meaning of <level> is described here:
215
+ * http://api.libssh.org/master/group__libssh__log.html
216
*/
217
-#define TRACE_LIBSSH2 0 /* or try: LIBSSH2_TRACE_SFTP */
218
+#define TRACE_LIBSSH 0 /* see: SSH_LOG_* */
219
220
typedef struct BDRVSSHState {
221
/* Coroutine. */
222
@@ -XXX,XX +XXX,XX @@ typedef struct BDRVSSHState {
223
224
/* SSH connection. */
225
int sock; /* socket */
226
- LIBSSH2_SESSION *session; /* ssh session */
227
- LIBSSH2_SFTP *sftp; /* sftp session */
228
- LIBSSH2_SFTP_HANDLE *sftp_handle; /* sftp remote file handle */
229
+ ssh_session session; /* ssh session */
230
+ sftp_session sftp; /* sftp session */
231
+ sftp_file sftp_handle; /* sftp remote file handle */
232
233
- /* See ssh_seek() function below. */
234
- int64_t offset;
235
- bool offset_op_read;
236
-
237
- /* File attributes at open. We try to keep the .filesize field
238
+ /*
239
+ * File attributes at open. We try to keep the .size field
240
* updated if it changes (eg by writing at the end of the file).
241
*/
242
- LIBSSH2_SFTP_ATTRIBUTES attrs;
243
+ sftp_attributes attrs;
244
245
InetSocketAddress *inet;
246
247
@@ -XXX,XX +XXX,XX @@ static void ssh_state_init(BDRVSSHState *s)
248
{
249
memset(s, 0, sizeof *s);
250
s->sock = -1;
251
- s->offset = -1;
252
qemu_co_mutex_init(&s->lock);
253
}
254
255
@@ -XXX,XX +XXX,XX @@ static void ssh_state_free(BDRVSSHState *s)
256
{
257
g_free(s->user);
258
259
+ if (s->attrs) {
260
+ sftp_attributes_free(s->attrs);
261
+ }
262
if (s->sftp_handle) {
263
- libssh2_sftp_close(s->sftp_handle);
264
+ sftp_close(s->sftp_handle);
265
}
266
if (s->sftp) {
267
- libssh2_sftp_shutdown(s->sftp);
268
+ sftp_free(s->sftp);
269
}
270
if (s->session) {
271
- libssh2_session_disconnect(s->session,
272
- "from qemu ssh client: "
273
- "user closed the connection");
274
- libssh2_session_free(s->session);
275
- }
276
- if (s->sock >= 0) {
277
- close(s->sock);
278
+ ssh_disconnect(s->session);
279
+ ssh_free(s->session); /* This frees s->sock */
280
}
281
}
282
283
@@ -XXX,XX +XXX,XX @@ session_error_setg(Error **errp, BDRVSSHState *s, const char *fs, ...)
284
va_end(args);
285
286
if (s->session) {
287
- char *ssh_err;
288
+ const char *ssh_err;
289
int ssh_err_code;
290
291
- /* This is not an errno. See <libssh2.h>. */
292
- ssh_err_code = libssh2_session_last_error(s->session,
293
- &ssh_err, NULL, 0);
294
- error_setg(errp, "%s: %s (libssh2 error code: %d)",
295
+ /* This is not an errno. See <libssh/libssh.h>. */
296
+ ssh_err = ssh_get_error(s->session);
297
+ ssh_err_code = ssh_get_error_code(s->session);
298
+ error_setg(errp, "%s: %s (libssh error code: %d)",
299
msg, ssh_err, ssh_err_code);
300
} else {
301
error_setg(errp, "%s", msg);
302
@@ -XXX,XX +XXX,XX @@ sftp_error_setg(Error **errp, BDRVSSHState *s, const char *fs, ...)
303
va_end(args);
304
305
if (s->sftp) {
306
- char *ssh_err;
307
+ const char *ssh_err;
308
int ssh_err_code;
309
- unsigned long sftp_err_code;
310
+ int sftp_err_code;
311
312
- /* This is not an errno. See <libssh2.h>. */
313
- ssh_err_code = libssh2_session_last_error(s->session,
314
- &ssh_err, NULL, 0);
315
- /* See <libssh2_sftp.h>. */
316
- sftp_err_code = libssh2_sftp_last_error((s)->sftp);
317
+ /* This is not an errno. See <libssh/libssh.h>. */
318
+ ssh_err = ssh_get_error(s->session);
319
+ ssh_err_code = ssh_get_error_code(s->session);
320
+ /* See <libssh/sftp.h>. */
321
+ sftp_err_code = sftp_get_error(s->sftp);
322
323
error_setg(errp,
324
- "%s: %s (libssh2 error code: %d, sftp error code: %lu)",
325
+ "%s: %s (libssh error code: %d, sftp error code: %d)",
326
msg, ssh_err, ssh_err_code, sftp_err_code);
327
} else {
328
error_setg(errp, "%s", msg);
329
@@ -XXX,XX +XXX,XX @@ sftp_error_setg(Error **errp, BDRVSSHState *s, const char *fs, ...)
330
331
static void sftp_error_trace(BDRVSSHState *s, const char *op)
332
{
333
- char *ssh_err;
334
+ const char *ssh_err;
335
int ssh_err_code;
336
- unsigned long sftp_err_code;
337
+ int sftp_err_code;
338
339
- /* This is not an errno. See <libssh2.h>. */
340
- ssh_err_code = libssh2_session_last_error(s->session,
341
- &ssh_err, NULL, 0);
342
- /* See <libssh2_sftp.h>. */
343
- sftp_err_code = libssh2_sftp_last_error((s)->sftp);
344
+ /* This is not an errno. See <libssh/libssh.h>. */
345
+ ssh_err = ssh_get_error(s->session);
346
+ ssh_err_code = ssh_get_error_code(s->session);
347
+ /* See <libssh/sftp.h>. */
348
+ sftp_err_code = sftp_get_error(s->sftp);
349
350
trace_sftp_error(op, ssh_err, ssh_err_code, sftp_err_code);
351
}
352
@@ -XXX,XX +XXX,XX @@ static void ssh_parse_filename(const char *filename, QDict *options,
353
parse_uri(filename, options, errp);
354
}
355
356
-static int check_host_key_knownhosts(BDRVSSHState *s,
357
- const char *host, int port, Error **errp)
358
+static int check_host_key_knownhosts(BDRVSSHState *s, Error **errp)
359
{
360
- const char *home;
361
- char *knh_file = NULL;
362
- LIBSSH2_KNOWNHOSTS *knh = NULL;
363
- struct libssh2_knownhost *found;
364
- int ret, r;
365
- const char *hostkey;
366
- size_t len;
367
- int type;
368
-
369
- hostkey = libssh2_session_hostkey(s->session, &len, &type);
370
- if (!hostkey) {
371
+ int ret;
372
+#ifdef HAVE_LIBSSH_0_8
373
+ enum ssh_known_hosts_e state;
374
+ int r;
375
+ ssh_key pubkey;
376
+ enum ssh_keytypes_e pubkey_type;
377
+ unsigned char *server_hash = NULL;
378
+ size_t server_hash_len;
379
+ char *fingerprint = NULL;
380
+
381
+ state = ssh_session_is_known_server(s->session);
382
+ trace_ssh_server_status(state);
383
+
384
+ switch (state) {
385
+ case SSH_KNOWN_HOSTS_OK:
386
+ /* OK */
387
+ trace_ssh_check_host_key_knownhosts();
388
+ break;
389
+ case SSH_KNOWN_HOSTS_CHANGED:
390
ret = -EINVAL;
391
- session_error_setg(errp, s, "failed to read remote host key");
392
+ r = ssh_get_server_publickey(s->session, &pubkey);
393
+ if (r == 0) {
394
+ r = ssh_get_publickey_hash(pubkey, SSH_PUBLICKEY_HASH_SHA256,
395
+ &server_hash, &server_hash_len);
396
+ pubkey_type = ssh_key_type(pubkey);
397
+ ssh_key_free(pubkey);
398
+ }
399
+ if (r == 0) {
400
+ fingerprint = ssh_get_fingerprint_hash(SSH_PUBLICKEY_HASH_SHA256,
401
+ server_hash,
402
+ server_hash_len);
403
+ ssh_clean_pubkey_hash(&server_hash);
404
+ }
405
+ if (fingerprint) {
406
+ error_setg(errp,
407
+ "host key (%s key with fingerprint %s) does not match "
408
+ "the one in known_hosts; this may be a possible attack",
409
+ ssh_key_type_to_char(pubkey_type), fingerprint);
410
+ ssh_string_free_char(fingerprint);
411
+ } else {
412
+ error_setg(errp,
413
+ "host key does not match the one in known_hosts; this "
414
+ "may be a possible attack");
415
+ }
416
goto out;
417
- }
418
-
419
- knh = libssh2_knownhost_init(s->session);
420
- if (!knh) {
421
+ case SSH_KNOWN_HOSTS_OTHER:
422
ret = -EINVAL;
423
- session_error_setg(errp, s,
424
- "failed to initialize known hosts support");
425
+ error_setg(errp,
426
+ "host key for this server not found, another type exists");
427
+ goto out;
428
+ case SSH_KNOWN_HOSTS_UNKNOWN:
429
+ ret = -EINVAL;
430
+ error_setg(errp, "no host key was found in known_hosts");
431
+ goto out;
432
+ case SSH_KNOWN_HOSTS_NOT_FOUND:
433
+ ret = -ENOENT;
434
+ error_setg(errp, "known_hosts file not found");
435
+ goto out;
436
+ case SSH_KNOWN_HOSTS_ERROR:
437
+ ret = -EINVAL;
438
+ error_setg(errp, "error while checking the host");
439
+ goto out;
440
+ default:
441
+ ret = -EINVAL;
442
+ error_setg(errp, "error while checking for known server (%d)", state);
443
goto out;
444
}
445
+#else /* !HAVE_LIBSSH_0_8 */
446
+ int state;
447
448
- home = getenv("HOME");
449
- if (home) {
450
- knh_file = g_strdup_printf("%s/.ssh/known_hosts", home);
451
- } else {
452
- knh_file = g_strdup_printf("/root/.ssh/known_hosts");
453
- }
454
-
455
- /* Read all known hosts from OpenSSH-style known_hosts file. */
456
- libssh2_knownhost_readfile(knh, knh_file, LIBSSH2_KNOWNHOST_FILE_OPENSSH);
457
+ state = ssh_is_server_known(s->session);
458
+ trace_ssh_server_status(state);
459
460
- r = libssh2_knownhost_checkp(knh, host, port, hostkey, len,
461
- LIBSSH2_KNOWNHOST_TYPE_PLAIN|
462
- LIBSSH2_KNOWNHOST_KEYENC_RAW,
463
- &found);
464
- switch (r) {
465
- case LIBSSH2_KNOWNHOST_CHECK_MATCH:
466
+ switch (state) {
467
+ case SSH_SERVER_KNOWN_OK:
468
/* OK */
469
- trace_ssh_check_host_key_knownhosts(found->key);
470
+ trace_ssh_check_host_key_knownhosts();
471
break;
472
- case LIBSSH2_KNOWNHOST_CHECK_MISMATCH:
473
+ case SSH_SERVER_KNOWN_CHANGED:
474
ret = -EINVAL;
475
- session_error_setg(errp, s,
476
- "host key does not match the one in known_hosts"
477
- " (found key %s)", found->key);
478
+ error_setg(errp,
479
+ "host key does not match the one in known_hosts; this "
480
+ "may be a possible attack");
481
goto out;
482
- case LIBSSH2_KNOWNHOST_CHECK_NOTFOUND:
483
+ case SSH_SERVER_FOUND_OTHER:
484
ret = -EINVAL;
485
- session_error_setg(errp, s, "no host key was found in known_hosts");
486
+ error_setg(errp,
487
+ "host key for this server not found, another type exists");
488
+ goto out;
489
+ case SSH_SERVER_FILE_NOT_FOUND:
490
+ ret = -ENOENT;
491
+ error_setg(errp, "known_hosts file not found");
492
goto out;
493
- case LIBSSH2_KNOWNHOST_CHECK_FAILURE:
494
+ case SSH_SERVER_NOT_KNOWN:
495
ret = -EINVAL;
496
- session_error_setg(errp, s,
497
- "failure matching the host key with known_hosts");
498
+ error_setg(errp, "no host key was found in known_hosts");
499
+ goto out;
500
+ case SSH_SERVER_ERROR:
501
+ ret = -EINVAL;
502
+ error_setg(errp, "server error");
503
goto out;
504
default:
505
ret = -EINVAL;
506
- session_error_setg(errp, s, "unknown error matching the host key"
507
- " with known_hosts (%d)", r);
508
+ error_setg(errp, "error while checking for known server (%d)", state);
509
goto out;
510
}
511
+#endif /* !HAVE_LIBSSH_0_8 */
512
513
/* known_hosts checking successful. */
514
ret = 0;
515
516
out:
517
- if (knh != NULL) {
518
- libssh2_knownhost_free(knh);
519
- }
520
- g_free(knh_file);
521
return ret;
522
}
523
524
@@ -XXX,XX +XXX,XX @@ static int compare_fingerprint(const unsigned char *fingerprint, size_t len,
525
526
static int
527
check_host_key_hash(BDRVSSHState *s, const char *hash,
528
- int hash_type, size_t fingerprint_len, Error **errp)
529
+ enum ssh_publickey_hash_type type, Error **errp)
530
{
531
- const char *fingerprint;
532
-
533
- fingerprint = libssh2_hostkey_hash(s->session, hash_type);
534
- if (!fingerprint) {
535
+ int r;
536
+ ssh_key pubkey;
537
+ unsigned char *server_hash;
538
+ size_t server_hash_len;
539
+
540
+#ifdef HAVE_LIBSSH_0_8
541
+ r = ssh_get_server_publickey(s->session, &pubkey);
542
+#else
543
+ r = ssh_get_publickey(s->session, &pubkey);
544
+#endif
545
+ if (r != SSH_OK) {
546
session_error_setg(errp, s, "failed to read remote host key");
547
return -EINVAL;
548
}
549
550
- if(compare_fingerprint((unsigned char *) fingerprint, fingerprint_len,
551
- hash) != 0) {
552
+ r = ssh_get_publickey_hash(pubkey, type, &server_hash, &server_hash_len);
553
+ ssh_key_free(pubkey);
554
+ if (r != 0) {
555
+ session_error_setg(errp, s,
556
+ "failed reading the hash of the server SSH key");
557
+ return -EINVAL;
558
+ }
559
+
560
+ r = compare_fingerprint(server_hash, server_hash_len, hash);
561
+ ssh_clean_pubkey_hash(&server_hash);
562
+ if (r != 0) {
563
error_setg(errp, "remote host key does not match host_key_check '%s'",
564
hash);
565
return -EPERM;
566
@@ -XXX,XX +XXX,XX @@ check_host_key_hash(BDRVSSHState *s, const char *hash,
567
return 0;
568
}
569
570
-static int check_host_key(BDRVSSHState *s, const char *host, int port,
571
- SshHostKeyCheck *hkc, Error **errp)
572
+static int check_host_key(BDRVSSHState *s, SshHostKeyCheck *hkc, Error **errp)
573
{
574
SshHostKeyCheckMode mode;
575
576
@@ -XXX,XX +XXX,XX @@ static int check_host_key(BDRVSSHState *s, const char *host, int port,
577
case SSH_HOST_KEY_CHECK_MODE_HASH:
578
if (hkc->u.hash.type == SSH_HOST_KEY_CHECK_HASH_TYPE_MD5) {
579
return check_host_key_hash(s, hkc->u.hash.hash,
580
- LIBSSH2_HOSTKEY_HASH_MD5, 16, errp);
581
+ SSH_PUBLICKEY_HASH_MD5, errp);
582
} else if (hkc->u.hash.type == SSH_HOST_KEY_CHECK_HASH_TYPE_SHA1) {
583
return check_host_key_hash(s, hkc->u.hash.hash,
584
- LIBSSH2_HOSTKEY_HASH_SHA1, 20, errp);
585
+ SSH_PUBLICKEY_HASH_SHA1, errp);
586
}
587
g_assert_not_reached();
588
break;
589
case SSH_HOST_KEY_CHECK_MODE_KNOWN_HOSTS:
590
- return check_host_key_knownhosts(s, host, port, errp);
591
+ return check_host_key_knownhosts(s, errp);
592
default:
593
g_assert_not_reached();
594
}
595
@@ -XXX,XX +XXX,XX @@ static int check_host_key(BDRVSSHState *s, const char *host, int port,
596
return -EINVAL;
597
}
598
599
-static int authenticate(BDRVSSHState *s, const char *user, Error **errp)
600
+static int authenticate(BDRVSSHState *s, Error **errp)
601
{
602
int r, ret;
603
- const char *userauthlist;
604
- LIBSSH2_AGENT *agent = NULL;
605
- struct libssh2_agent_publickey *identity;
606
- struct libssh2_agent_publickey *prev_identity = NULL;
607
+ int method;
608
609
- userauthlist = libssh2_userauth_list(s->session, user, strlen(user));
610
- if (strstr(userauthlist, "publickey") == NULL) {
611
+ /* Try to authenticate with the "none" method. */
612
+ r = ssh_userauth_none(s->session, NULL);
613
+ if (r == SSH_AUTH_ERROR) {
614
ret = -EPERM;
615
- error_setg(errp,
616
- "remote server does not support \"publickey\" authentication");
617
+ session_error_setg(errp, s, "failed to authenticate using none "
618
+ "authentication");
619
goto out;
620
- }
621
-
622
- /* Connect to ssh-agent and try each identity in turn. */
623
- agent = libssh2_agent_init(s->session);
624
- if (!agent) {
625
- ret = -EINVAL;
626
- session_error_setg(errp, s, "failed to initialize ssh-agent support");
627
- goto out;
628
- }
629
- if (libssh2_agent_connect(agent)) {
630
- ret = -ECONNREFUSED;
631
- session_error_setg(errp, s, "failed to connect to ssh-agent");
632
- goto out;
633
- }
634
- if (libssh2_agent_list_identities(agent)) {
635
- ret = -EINVAL;
636
- session_error_setg(errp, s,
637
- "failed requesting identities from ssh-agent");
638
+ } else if (r == SSH_AUTH_SUCCESS) {
639
+ /* Authenticated! */
640
+ ret = 0;
641
goto out;
642
}
643
644
- for(;;) {
645
- r = libssh2_agent_get_identity(agent, &identity, prev_identity);
646
- if (r == 1) { /* end of list */
647
- break;
648
- }
649
- if (r < 0) {
650
+ method = ssh_userauth_list(s->session, NULL);
651
+ trace_ssh_auth_methods(method);
652
+
653
+ /*
654
+ * Try to authenticate with publickey, using the ssh-agent
655
+ * if available.
656
+ */
657
+ if (method & SSH_AUTH_METHOD_PUBLICKEY) {
658
+ r = ssh_userauth_publickey_auto(s->session, NULL, NULL);
659
+ if (r == SSH_AUTH_ERROR) {
660
ret = -EINVAL;
661
- session_error_setg(errp, s,
662
- "failed to obtain identity from ssh-agent");
663
+ session_error_setg(errp, s, "failed to authenticate using "
664
+ "publickey authentication");
665
goto out;
666
- }
667
- r = libssh2_agent_userauth(agent, user, identity);
668
- if (r == 0) {
669
+ } else if (r == SSH_AUTH_SUCCESS) {
670
/* Authenticated! */
671
ret = 0;
672
goto out;
673
}
674
- /* Failed to authenticate with this identity, try the next one. */
675
- prev_identity = identity;
676
}
677
678
ret = -EPERM;
679
@@ -XXX,XX +XXX,XX @@ static int authenticate(BDRVSSHState *s, const char *user, Error **errp)
680
"and the identities held by your ssh-agent");
681
682
out:
683
- if (agent != NULL) {
684
- /* Note: libssh2 implementation implicitly calls
685
- * libssh2_agent_disconnect if necessary.
686
- */
687
- libssh2_agent_free(agent);
688
- }
689
-
690
return ret;
691
}
692
693
@@ -XXX,XX +XXX,XX @@ static int connect_to_ssh(BDRVSSHState *s, BlockdevOptionsSsh *opts,
694
int ssh_flags, int creat_mode, Error **errp)
695
{
696
int r, ret;
697
- long port = 0;
698
+ unsigned int port = 0;
699
+ int new_sock = -1;
700
701
if (opts->has_user) {
702
s->user = g_strdup(opts->user);
703
@@ -XXX,XX +XXX,XX @@ static int connect_to_ssh(BDRVSSHState *s, BlockdevOptionsSsh *opts,
704
s->inet = opts->server;
705
opts->server = NULL;
706
707
- if (qemu_strtol(s->inet->port, NULL, 10, &port) < 0) {
708
+ if (qemu_strtoui(s->inet->port, NULL, 10, &port) < 0) {
709
error_setg(errp, "Use only numeric port value");
710
ret = -EINVAL;
711
goto err;
712
}
713
714
/* Open the socket and connect. */
715
- s->sock = inet_connect_saddr(s->inet, errp);
716
- if (s->sock < 0) {
717
+ new_sock = inet_connect_saddr(s->inet, errp);
718
+ if (new_sock < 0) {
719
ret = -EIO;
720
goto err;
721
}
722
723
+ /*
724
+ * Try to disable the Nagle algorithm on TCP sockets to reduce latency,
725
+ * but do not fail if it cannot be disabled.
726
+ */
727
+ r = socket_set_nodelay(new_sock);
728
+ if (r < 0) {
729
+ warn_report("can't set TCP_NODELAY for the ssh server %s: %s",
730
+ s->inet->host, strerror(errno));
731
+ }
732
+
733
/* Create SSH session. */
734
- s->session = libssh2_session_init();
735
+ s->session = ssh_new();
736
if (!s->session) {
737
ret = -EINVAL;
738
- session_error_setg(errp, s, "failed to initialize libssh2 session");
739
+ session_error_setg(errp, s, "failed to initialize libssh session");
740
goto err;
741
}
742
743
-#if TRACE_LIBSSH2 != 0
744
- libssh2_trace(s->session, TRACE_LIBSSH2);
745
-#endif
746
+ /*
747
+ * Make sure we are in blocking mode during the connection and
748
+ * authentication phases.
749
+ */
750
+ ssh_set_blocking(s->session, 1);
751
752
- r = libssh2_session_handshake(s->session, s->sock);
753
- if (r != 0) {
754
+ r = ssh_options_set(s->session, SSH_OPTIONS_USER, s->user);
755
+ if (r < 0) {
756
+ ret = -EINVAL;
757
+ session_error_setg(errp, s,
758
+ "failed to set the user in the libssh session");
759
+ goto err;
760
+ }
761
+
762
+ r = ssh_options_set(s->session, SSH_OPTIONS_HOST, s->inet->host);
763
+ if (r < 0) {
764
+ ret = -EINVAL;
765
+ session_error_setg(errp, s,
766
+ "failed to set the host in the libssh session");
767
+ goto err;
768
+ }
769
+
770
+ if (port > 0) {
771
+ r = ssh_options_set(s->session, SSH_OPTIONS_PORT, &port);
772
+ if (r < 0) {
773
+ ret = -EINVAL;
774
+ session_error_setg(errp, s,
775
+ "failed to set the port in the libssh session");
776
+ goto err;
777
+ }
778
+ }
779
+
780
+ r = ssh_options_set(s->session, SSH_OPTIONS_COMPRESSION, "none");
781
+ if (r < 0) {
782
+ ret = -EINVAL;
783
+ session_error_setg(errp, s,
784
+ "failed to disable the compression in the libssh "
785
+ "session");
786
+ goto err;
787
+ }
788
+
789
+ /* Read ~/.ssh/config. */
790
+ r = ssh_options_parse_config(s->session, NULL);
791
+ if (r < 0) {
792
+ ret = -EINVAL;
793
+ session_error_setg(errp, s, "failed to parse ~/.ssh/config");
794
+ goto err;
795
+ }
796
+
797
+ r = ssh_options_set(s->session, SSH_OPTIONS_FD, &new_sock);
798
+ if (r < 0) {
799
+ ret = -EINVAL;
800
+ session_error_setg(errp, s,
801
+ "failed to set the socket in the libssh session");
802
+ goto err;
803
+ }
804
+ /* libssh took ownership of the socket. */
805
+ s->sock = new_sock;
806
+ new_sock = -1;
807
+
808
+ /* Connect. */
809
+ r = ssh_connect(s->session);
810
+ if (r != SSH_OK) {
811
ret = -EINVAL;
812
session_error_setg(errp, s, "failed to establish SSH session");
813
goto err;
814
}
815
816
/* Check the remote host's key against known_hosts. */
817
- ret = check_host_key(s, s->inet->host, port, opts->host_key_check, errp);
818
+ ret = check_host_key(s, opts->host_key_check, errp);
819
if (ret < 0) {
820
goto err;
821
}
822
823
/* Authenticate. */
824
- ret = authenticate(s, s->user, errp);
825
+ ret = authenticate(s, errp);
826
if (ret < 0) {
827
goto err;
828
}
829
830
/* Start SFTP. */
831
- s->sftp = libssh2_sftp_init(s->session);
832
+ s->sftp = sftp_new(s->session);
833
if (!s->sftp) {
834
- session_error_setg(errp, s, "failed to initialize sftp handle");
835
+ session_error_setg(errp, s, "failed to create sftp handle");
836
+ ret = -EINVAL;
837
+ goto err;
838
+ }
839
+
840
+ r = sftp_init(s->sftp);
841
+ if (r < 0) {
842
+ sftp_error_setg(errp, s, "failed to initialize sftp handle");
843
ret = -EINVAL;
844
goto err;
845
}
846
847
/* Open the remote file. */
848
trace_ssh_connect_to_ssh(opts->path, ssh_flags, creat_mode);
849
- s->sftp_handle = libssh2_sftp_open(s->sftp, opts->path, ssh_flags,
850
- creat_mode);
851
+ s->sftp_handle = sftp_open(s->sftp, opts->path, ssh_flags, creat_mode);
852
if (!s->sftp_handle) {
853
- session_error_setg(errp, s, "failed to open remote file '%s'",
854
- opts->path);
855
+ sftp_error_setg(errp, s, "failed to open remote file '%s'",
856
+ opts->path);
857
ret = -EINVAL;
858
goto err;
859
}
860
861
- r = libssh2_sftp_fstat(s->sftp_handle, &s->attrs);
862
- if (r < 0) {
863
+ /* Make sure the SFTP file is handled in blocking mode. */
864
+ sftp_file_set_blocking(s->sftp_handle);
865
+
866
+ s->attrs = sftp_fstat(s->sftp_handle);
867
+ if (!s->attrs) {
868
sftp_error_setg(errp, s, "failed to read file attributes");
869
return -EINVAL;
870
}
871
@@ -XXX,XX +XXX,XX @@ static int connect_to_ssh(BDRVSSHState *s, BlockdevOptionsSsh *opts,
872
return 0;
873
874
err:
875
+ if (s->attrs) {
876
+ sftp_attributes_free(s->attrs);
877
+ }
878
+ s->attrs = NULL;
879
if (s->sftp_handle) {
880
- libssh2_sftp_close(s->sftp_handle);
881
+ sftp_close(s->sftp_handle);
882
}
883
s->sftp_handle = NULL;
884
if (s->sftp) {
885
- libssh2_sftp_shutdown(s->sftp);
886
+ sftp_free(s->sftp);
887
}
888
s->sftp = NULL;
889
if (s->session) {
890
- libssh2_session_disconnect(s->session,
891
- "from qemu ssh client: "
892
- "error opening connection");
893
- libssh2_session_free(s->session);
894
+ ssh_disconnect(s->session);
895
+ ssh_free(s->session);
896
}
897
s->session = NULL;
898
+ s->sock = -1;
899
+ if (new_sock >= 0) {
900
+ close(new_sock);
901
+ }
902
903
return ret;
904
}
905
@@ -XXX,XX +XXX,XX @@ static int ssh_file_open(BlockDriverState *bs, QDict *options, int bdrv_flags,
906
907
ssh_state_init(s);
908
909
- ssh_flags = LIBSSH2_FXF_READ;
910
+ ssh_flags = 0;
911
if (bdrv_flags & BDRV_O_RDWR) {
912
- ssh_flags |= LIBSSH2_FXF_WRITE;
913
+ ssh_flags |= O_RDWR;
914
+ } else {
915
+ ssh_flags |= O_RDONLY;
916
}
917
918
opts = ssh_parse_options(options, errp);
919
@@ -XXX,XX +XXX,XX @@ static int ssh_file_open(BlockDriverState *bs, QDict *options, int bdrv_flags,
920
}
921
922
/* Go non-blocking. */
923
- libssh2_session_set_blocking(s->session, 0);
924
+ ssh_set_blocking(s->session, 0);
925
926
qapi_free_BlockdevOptionsSsh(opts);
927
928
return 0;
929
930
err:
931
- if (s->sock >= 0) {
932
- close(s->sock);
933
- }
934
- s->sock = -1;
935
-
936
qapi_free_BlockdevOptionsSsh(opts);
937
938
return ret;
939
@@ -XXX,XX +XXX,XX @@ static int ssh_grow_file(BDRVSSHState *s, int64_t offset, Error **errp)
940
{
941
ssize_t ret;
942
char c[1] = { '\0' };
943
- int was_blocking = libssh2_session_get_blocking(s->session);
944
+ int was_blocking = ssh_is_blocking(s->session);
945
946
/* offset must be strictly greater than the current size so we do
947
* not overwrite anything */
948
- assert(offset > 0 && offset > s->attrs.filesize);
949
+ assert(offset > 0 && offset > s->attrs->size);
950
951
- libssh2_session_set_blocking(s->session, 1);
952
+ ssh_set_blocking(s->session, 1);
953
954
- libssh2_sftp_seek64(s->sftp_handle, offset - 1);
955
- ret = libssh2_sftp_write(s->sftp_handle, c, 1);
956
+ sftp_seek64(s->sftp_handle, offset - 1);
957
+ ret = sftp_write(s->sftp_handle, c, 1);
958
959
- libssh2_session_set_blocking(s->session, was_blocking);
960
+ ssh_set_blocking(s->session, was_blocking);
961
962
if (ret < 0) {
963
sftp_error_setg(errp, s, "Failed to grow file");
964
return -EIO;
965
}
966
967
- s->attrs.filesize = offset;
968
+ s->attrs->size = offset;
969
return 0;
970
}
971
972
@@ -XXX,XX +XXX,XX @@ static int ssh_co_create(BlockdevCreateOptions *options, Error **errp)
973
ssh_state_init(&s);
974
975
ret = connect_to_ssh(&s, opts->location,
976
- LIBSSH2_FXF_READ|LIBSSH2_FXF_WRITE|
977
- LIBSSH2_FXF_CREAT|LIBSSH2_FXF_TRUNC,
978
+ O_RDWR | O_CREAT | O_TRUNC,
979
0644, errp);
980
if (ret < 0) {
981
goto fail;
982
@@ -XXX,XX +XXX,XX @@ static int ssh_has_zero_init(BlockDriverState *bs)
983
/* Assume false, unless we can positively prove it's true. */
984
int has_zero_init = 0;
985
986
- if (s->attrs.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) {
987
- if (s->attrs.permissions & LIBSSH2_SFTP_S_IFREG) {
988
- has_zero_init = 1;
989
- }
990
+ if (s->attrs->type == SSH_FILEXFER_TYPE_REGULAR) {
991
+ has_zero_init = 1;
992
}
993
994
return has_zero_init;
995
@@ -XXX,XX +XXX,XX @@ static coroutine_fn void co_yield(BDRVSSHState *s, BlockDriverState *bs)
996
.co = qemu_coroutine_self()
997
};
998
999
- r = libssh2_session_block_directions(s->session);
1000
+ r = ssh_get_poll_flags(s->session);
1001
1002
- if (r & LIBSSH2_SESSION_BLOCK_INBOUND) {
1003
+ if (r & SSH_READ_PENDING) {
1004
rd_handler = restart_coroutine;
1005
}
1006
- if (r & LIBSSH2_SESSION_BLOCK_OUTBOUND) {
1007
+ if (r & SSH_WRITE_PENDING) {
1008
wr_handler = restart_coroutine;
1009
}
1010
1011
@@ -XXX,XX +XXX,XX @@ static coroutine_fn void co_yield(BDRVSSHState *s, BlockDriverState *bs)
1012
trace_ssh_co_yield_back(s->sock);
1013
}
1014
1015
-/* SFTP has a function `libssh2_sftp_seek64' which seeks to a position
1016
- * in the remote file. Notice that it just updates a field in the
1017
- * sftp_handle structure, so there is no network traffic and it cannot
1018
- * fail.
1019
- *
1020
- * However, `libssh2_sftp_seek64' does have a catastrophic effect on
1021
- * performance since it causes the handle to throw away all in-flight
1022
- * reads and buffered readahead data. Therefore this function tries
1023
- * to be intelligent about when to call the underlying libssh2 function.
1024
- */
1025
-#define SSH_SEEK_WRITE 0
1026
-#define SSH_SEEK_READ 1
1027
-#define SSH_SEEK_FORCE 2
1028
-
1029
-static void ssh_seek(BDRVSSHState *s, int64_t offset, int flags)
1030
-{
1031
- bool op_read = (flags & SSH_SEEK_READ) != 0;
1032
- bool force = (flags & SSH_SEEK_FORCE) != 0;
1033
-
1034
- if (force || op_read != s->offset_op_read || offset != s->offset) {
1035
- trace_ssh_seek(offset);
1036
- libssh2_sftp_seek64(s->sftp_handle, offset);
1037
- s->offset = offset;
1038
- s->offset_op_read = op_read;
1039
- }
1040
-}
1041
-
1042
static coroutine_fn int ssh_read(BDRVSSHState *s, BlockDriverState *bs,
1043
int64_t offset, size_t size,
1044
QEMUIOVector *qiov)
1045
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int ssh_read(BDRVSSHState *s, BlockDriverState *bs,
1046
1047
trace_ssh_read(offset, size);
1048
1049
- ssh_seek(s, offset, SSH_SEEK_READ);
1050
+ trace_ssh_seek(offset);
1051
+ sftp_seek64(s->sftp_handle, offset);
1052
1053
/* This keeps track of the current iovec element ('i'), where we
1054
* will write to next ('buf'), and the end of the current iovec
1055
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int ssh_read(BDRVSSHState *s, BlockDriverState *bs,
1056
buf = i->iov_base;
1057
end_of_vec = i->iov_base + i->iov_len;
1058
1059
- /* libssh2 has a hard-coded limit of 2000 bytes per request,
1060
- * although it will also do readahead behind our backs. Therefore
1061
- * we may have to do repeated reads here until we have read 'size'
1062
- * bytes.
1063
- */
1064
for (got = 0; got < size; ) {
1065
+ size_t request_read_size;
1066
again:
1067
- trace_ssh_read_buf(buf, end_of_vec - buf);
1068
- r = libssh2_sftp_read(s->sftp_handle, buf, end_of_vec - buf);
1069
- trace_ssh_read_return(r);
1070
+ /*
1071
+ * The size of SFTP packets is limited to 32K bytes, so limit
1072
+ * the amount of data requested to 16K, as libssh currently
1073
+ * does not handle multiple requests on its own.
1074
+ */
1075
+ request_read_size = MIN(end_of_vec - buf, 16384);
1076
+ trace_ssh_read_buf(buf, end_of_vec - buf, request_read_size);
1077
+ r = sftp_read(s->sftp_handle, buf, request_read_size);
1078
+ trace_ssh_read_return(r, sftp_get_error(s->sftp));
1079
1080
- if (r == LIBSSH2_ERROR_EAGAIN || r == LIBSSH2_ERROR_TIMEOUT) {
1081
+ if (r == SSH_AGAIN) {
1082
co_yield(s, bs);
1083
goto again;
1084
}
1085
- if (r < 0) {
1086
- sftp_error_trace(s, "read");
1087
- s->offset = -1;
1088
- return -EIO;
1089
- }
1090
- if (r == 0) {
1091
+ if (r == SSH_EOF || (r == 0 && sftp_get_error(s->sftp) == SSH_FX_EOF)) {
1092
/* EOF: Short read so pad the buffer with zeroes and return it. */
1093
qemu_iovec_memset(qiov, got, 0, size - got);
1094
return 0;
1095
}
1096
+ if (r <= 0) {
1097
+ sftp_error_trace(s, "read");
1098
+ return -EIO;
1099
+ }
1100
1101
got += r;
1102
buf += r;
1103
- s->offset += r;
1104
if (buf >= end_of_vec && got < size) {
1105
i++;
1106
buf = i->iov_base;
1107
@@ -XXX,XX +XXX,XX @@ static int ssh_write(BDRVSSHState *s, BlockDriverState *bs,
1108
1109
trace_ssh_write(offset, size);
1110
1111
- ssh_seek(s, offset, SSH_SEEK_WRITE);
1112
+ trace_ssh_seek(offset);
1113
+ sftp_seek64(s->sftp_handle, offset);
1114
1115
/* This keeps track of the current iovec element ('i'), where we
1116
* will read from next ('buf'), and the end of the current iovec
1117
@@ -XXX,XX +XXX,XX @@ static int ssh_write(BDRVSSHState *s, BlockDriverState *bs,
1118
end_of_vec = i->iov_base + i->iov_len;
1119
1120
for (written = 0; written < size; ) {
1121
+ size_t request_write_size;
1122
again:
1123
- trace_ssh_write_buf(buf, end_of_vec - buf);
1124
- r = libssh2_sftp_write(s->sftp_handle, buf, end_of_vec - buf);
1125
- trace_ssh_write_return(r);
1126
+ /*
1127
+ * Avoid too large data packets, as libssh currently does not
1128
+ * handle multiple requests on its own.
1129
+ */
1130
+ request_write_size = MIN(end_of_vec - buf, 131072);
1131
+ trace_ssh_write_buf(buf, end_of_vec - buf, request_write_size);
1132
+ r = sftp_write(s->sftp_handle, buf, request_write_size);
1133
+ trace_ssh_write_return(r, sftp_get_error(s->sftp));
1134
1135
- if (r == LIBSSH2_ERROR_EAGAIN || r == LIBSSH2_ERROR_TIMEOUT) {
1136
+ if (r == SSH_AGAIN) {
1137
co_yield(s, bs);
1138
goto again;
1139
}
1140
if (r < 0) {
1141
sftp_error_trace(s, "write");
1142
- s->offset = -1;
1143
return -EIO;
1144
}
1145
- /* The libssh2 API is very unclear about this. A comment in
1146
- * the code says "nothing was acked, and no EAGAIN was
1147
- * received!" which apparently means that no data got sent
1148
- * out, and the underlying channel didn't return any EAGAIN
1149
- * indication. I think this is a bug in either libssh2 or
1150
- * OpenSSH (server-side). In any case, forcing a seek (to
1151
- * discard libssh2 internal buffers), and then trying again
1152
- * works for me.
1153
- */
1154
- if (r == 0) {
1155
- ssh_seek(s, offset + written, SSH_SEEK_WRITE|SSH_SEEK_FORCE);
1156
- co_yield(s, bs);
1157
- goto again;
1158
- }
1159
1160
written += r;
1161
buf += r;
1162
- s->offset += r;
1163
if (buf >= end_of_vec && written < size) {
1164
i++;
1165
buf = i->iov_base;
1166
end_of_vec = i->iov_base + i->iov_len;
1167
}
1168
1169
- if (offset + written > s->attrs.filesize)
1170
- s->attrs.filesize = offset + written;
1171
+ if (offset + written > s->attrs->size) {
1172
+ s->attrs->size = offset + written;
1173
+ }
1174
}
1175
1176
return 0;
1177
@@ -XXX,XX +XXX,XX @@ static void unsafe_flush_warning(BDRVSSHState *s, const char *what)
1178
}
1179
}
1180
1181
-#ifdef HAS_LIBSSH2_SFTP_FSYNC
1182
+#ifdef HAVE_LIBSSH_0_8
1183
1184
static coroutine_fn int ssh_flush(BDRVSSHState *s, BlockDriverState *bs)
1185
{
1186
int r;
1187
1188
trace_ssh_flush();
1189
+
1190
+ if (!sftp_extension_supported(s->sftp, "fsync@openssh.com", "1")) {
1191
+ unsafe_flush_warning(s, "OpenSSH >= 6.3");
1192
+ return 0;
1193
+ }
1194
again:
1195
- r = libssh2_sftp_fsync(s->sftp_handle);
1196
- if (r == LIBSSH2_ERROR_EAGAIN || r == LIBSSH2_ERROR_TIMEOUT) {
1197
+ r = sftp_fsync(s->sftp_handle);
1198
+ if (r == SSH_AGAIN) {
1199
co_yield(s, bs);
1200
goto again;
1201
}
1202
- if (r == LIBSSH2_ERROR_SFTP_PROTOCOL &&
1203
- libssh2_sftp_last_error(s->sftp) == LIBSSH2_FX_OP_UNSUPPORTED) {
1204
- unsafe_flush_warning(s, "OpenSSH >= 6.3");
1205
- return 0;
1206
- }
1207
if (r < 0) {
1208
sftp_error_trace(s, "fsync");
1209
return -EIO;
1210
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int ssh_co_flush(BlockDriverState *bs)
1211
return ret;
1212
}
1213
1214
-#else /* !HAS_LIBSSH2_SFTP_FSYNC */
1215
+#else /* !HAVE_LIBSSH_0_8 */
1216
1217
static coroutine_fn int ssh_co_flush(BlockDriverState *bs)
1218
{
1219
BDRVSSHState *s = bs->opaque;
1220
1221
- unsafe_flush_warning(s, "libssh2 >= 1.4.4");
1222
+ unsafe_flush_warning(s, "libssh >= 0.8.0");
1223
return 0;
1224
}
1225
1226
-#endif /* !HAS_LIBSSH2_SFTP_FSYNC */
1227
+#endif /* !HAVE_LIBSSH_0_8 */
1228
1229
static int64_t ssh_getlength(BlockDriverState *bs)
1230
{
1231
BDRVSSHState *s = bs->opaque;
1232
int64_t length;
1233
1234
- /* Note we cannot make a libssh2 call here. */
1235
- length = (int64_t) s->attrs.filesize;
1236
+ /* Note we cannot make a libssh call here. */
1237
+ length = (int64_t) s->attrs->size;
1238
trace_ssh_getlength(length);
1239
1240
return length;
1241
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn ssh_co_truncate(BlockDriverState *bs, int64_t offset,
1242
return -ENOTSUP;
1243
}
1244
1245
- if (offset < s->attrs.filesize) {
1246
+ if (offset < s->attrs->size) {
1247
error_setg(errp, "ssh driver does not support shrinking files");
1248
return -ENOTSUP;
1249
}
1250
1251
- if (offset == s->attrs.filesize) {
1252
+ if (offset == s->attrs->size) {
1253
return 0;
1254
}
1255
1256
@@ -XXX,XX +XXX,XX @@ static void bdrv_ssh_init(void)
1257
{
1258
int r;
1259
1260
- r = libssh2_init(0);
1261
+ r = ssh_init();
1262
if (r != 0) {
1263
- fprintf(stderr, "libssh2 initialization failed, %d\n", r);
1264
+ fprintf(stderr, "libssh initialization failed, %d\n", r);
1265
exit(EXIT_FAILURE);
1266
}
1267
1268
+#if TRACE_LIBSSH != 0
1269
+ ssh_set_log_level(TRACE_LIBSSH);
1270
+#endif
1271
+
1272
bdrv_register(&bdrv_ssh);
1273
}
1274
1275
diff --git a/.travis.yml b/.travis.yml
1276
index XXXXXXX..XXXXXXX 100644
1277
--- a/.travis.yml
1278
+++ b/.travis.yml
1279
@@ -XXX,XX +XXX,XX @@ addons:
1280
- libseccomp-dev
1281
- libspice-protocol-dev
1282
- libspice-server-dev
1283
- - libssh2-1-dev
1284
+ - libssh-dev
1285
- liburcu-dev
1286
- libusb-1.0-0-dev
1287
- libvte-2.91-dev
1288
@@ -XXX,XX +XXX,XX @@ matrix:
1289
- libseccomp-dev
1290
- libspice-protocol-dev
1291
- libspice-server-dev
1292
- - libssh2-1-dev
1293
+ - libssh-dev
1294
- liburcu-dev
1295
- libusb-1.0-0-dev
1296
- libvte-2.91-dev
58
diff --git a/block/trace-events b/block/trace-events
1297
diff --git a/block/trace-events b/block/trace-events
59
index XXXXXXX..XXXXXXX 100644
1298
index XXXXXXX..XXXXXXX 100644
60
--- a/block/trace-events
1299
--- a/block/trace-events
61
+++ b/block/trace-events
1300
+++ b/block/trace-events
62
@@ -XXX,XX +XXX,XX @@ qed_aio_write_data(void *s, void *acb, int ret, uint64_t offset, size_t len) "s
1301
@@ -XXX,XX +XXX,XX @@ nbd_client_connect_success(const char *export_name) "export '%s'"
63
qed_aio_write_prefill(void *s, void *acb, uint64_t start, size_t len, uint64_t offset) "s %p acb %p start %"PRIu64" len %zu offset %"PRIu64
1302
# ssh.c
64
qed_aio_write_postfill(void *s, void *acb, uint64_t start, size_t len, uint64_t offset) "s %p acb %p start %"PRIu64" len %zu offset %"PRIu64
1303
ssh_restart_coroutine(void *co) "co=%p"
65
qed_aio_write_main(void *s, void *acb, int ret, uint64_t offset, size_t len) "s %p acb %p ret %d offset %"PRIu64" len %zu"
1304
ssh_flush(void) "fsync"
66
+
1305
-ssh_check_host_key_knownhosts(const char *key) "host key OK: %s"
67
+# block/vxhs.c
1306
+ssh_check_host_key_knownhosts(void) "host key OK"
68
+vxhs_iio_callback(int error) "ctx is NULL: error %d"
1307
ssh_connect_to_ssh(char *path, int flags, int mode) "opening file %s flags=0x%x creat_mode=0%o"
69
+vxhs_iio_callback_chnfail(int err, int error) "QNIO channel failed, no i/o %d, %d"
1308
ssh_co_yield(int sock, void *rd_handler, void *wr_handler) "s->sock=%d rd_handler=%p wr_handler=%p"
70
+vxhs_iio_callback_unknwn(int opcode, int err) "unexpected opcode %d, errno %d"
1309
ssh_co_yield_back(int sock) "s->sock=%d - back"
71
+vxhs_aio_rw_invalid(int req) "Invalid I/O request iodir %d"
1310
ssh_getlength(int64_t length) "length=%" PRIi64
72
+vxhs_aio_rw_ioerr(char *guid, int iodir, uint64_t size, uint64_t off, void *acb, int ret, int err) "IO ERROR (vDisk %s) FOR : Read/Write = %d size = %lu offset = %lu ACB = %p. Error = %d, errno = %d"
1311
ssh_co_create_opts(uint64_t size) "total_size=%" PRIu64
73
+vxhs_get_vdisk_stat_err(char *guid, int ret, int err) "vDisk (%s) stat ioctl failed, ret = %d, errno = %d"
1312
ssh_read(int64_t offset, size_t size) "offset=%" PRIi64 " size=%zu"
74
+vxhs_get_vdisk_stat(char *vdisk_guid, uint64_t vdisk_size) "vDisk %s stat ioctl returned size %lu"
1313
-ssh_read_buf(void *buf, size_t size) "sftp_read buf=%p size=%zu"
75
+vxhs_complete_aio(void *acb, uint64_t ret) "aio failed acb %p ret %ld"
1314
-ssh_read_return(ssize_t ret) "sftp_read returned %zd"
76
+vxhs_parse_uri_filename(const char *filename) "URI passed via bdrv_parse_filename %s"
1315
+ssh_read_buf(void *buf, size_t size, size_t actual_size) "sftp_read buf=%p size=%zu (actual size=%zu)"
77
+vxhs_open_vdiskid(const char *vdisk_id) "Opening vdisk-id %s"
1316
+ssh_read_return(ssize_t ret, int sftp_err) "sftp_read returned %zd (sftp error=%d)"
78
+vxhs_open_hostinfo(char *of_vsa_addr, int port) "Adding host %s:%d to BDRVVXHSState"
1317
ssh_write(int64_t offset, size_t size) "offset=%" PRIi64 " size=%zu"
79
+vxhs_open_iio_open(const char *host) "Failed to connect to storage agent on host %s"
1318
-ssh_write_buf(void *buf, size_t size) "sftp_write buf=%p size=%zu"
80
+vxhs_parse_uri_hostinfo(char *host, int port) "Host: IP %s, Port %d"
1319
-ssh_write_return(ssize_t ret) "sftp_write returned %zd"
81
+vxhs_close(char *vdisk_guid) "Closing vdisk %s"
1320
+ssh_write_buf(void *buf, size_t size, size_t actual_size) "sftp_write buf=%p size=%zu (actual size=%zu)"
82
+vxhs_get_creds(const char *cacert, const char *client_key, const char *client_cert) "cacert %s, client_key %s, client_cert %s"
1321
+ssh_write_return(ssize_t ret, int sftp_err) "sftp_write returned %zd (sftp error=%d)"
83
diff --git a/block/vxhs.c b/block/vxhs.c
1322
ssh_seek(int64_t offset) "seeking to offset=%" PRIi64
84
new file mode 100644
1323
+ssh_auth_methods(int methods) "auth methods=0x%x"
85
index XXXXXXX..XXXXXXX
1324
+ssh_server_status(int status) "server status=%d"
86
--- /dev/null
1325
87
+++ b/block/vxhs.c
1326
# curl.c
88
@@ -XXX,XX +XXX,XX @@
1327
curl_timer_cb(long timeout_ms) "timer callback timeout_ms %ld"
89
+/*
1328
@@ -XXX,XX +XXX,XX @@ sheepdog_snapshot_create(const char *sn_name, const char *id) "%s %s"
90
+ * QEMU Block driver for Veritas HyperScale (VxHS)
1329
sheepdog_snapshot_create_inode(const char *name, uint32_t snap, uint32_t vdi) "s->inode: name %s snap_id 0x%" PRIx32 " vdi 0x%" PRIx32
91
+ *
1330
92
+ * Copyright (c) 2017 Veritas Technologies LLC.
1331
# ssh.c
93
+ *
1332
-sftp_error(const char *op, const char *ssh_err, int ssh_err_code, unsigned long sftp_err_code) "%s failed: %s (libssh2 error code: %d, sftp error code: %lu)"
94
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
1333
+sftp_error(const char *op, const char *ssh_err, int ssh_err_code, int sftp_err_code) "%s failed: %s (libssh error code: %d, sftp error code: %d)"
95
+ * See the COPYING file in the top-level directory.
1334
diff --git a/docs/qemu-block-drivers.texi b/docs/qemu-block-drivers.texi
96
+ *
1335
index XXXXXXX..XXXXXXX 100644
97
+ */
1336
--- a/docs/qemu-block-drivers.texi
98
+
1337
+++ b/docs/qemu-block-drivers.texi
99
+#include "qemu/osdep.h"
1338
@@ -XXX,XX +XXX,XX @@ print a warning when @code{fsync} is not supported:
100
+#include <qnio/qnio_api.h>
1339
101
+#include <sys/param.h>
1340
warning: ssh server @code{ssh.example.com:22} does not support fsync
102
+#include "block/block_int.h"
1341
103
+#include "qapi/qmp/qerror.h"
1342
-With sufficiently new versions of libssh2 and OpenSSH, @code{fsync} is
104
+#include "qapi/qmp/qdict.h"
1343
+With sufficiently new versions of libssh and OpenSSH, @code{fsync} is
105
+#include "qapi/qmp/qstring.h"
1344
supported.
106
+#include "trace.h"
1345
107
+#include "qemu/uri.h"
1346
@node disk_images_nvme
108
+#include "qapi/error.h"
1347
diff --git a/tests/docker/dockerfiles/debian-win32-cross.docker b/tests/docker/dockerfiles/debian-win32-cross.docker
109
+#include "qemu/uuid.h"
1348
index XXXXXXX..XXXXXXX 100644
110
+#include "crypto/tlscredsx509.h"
1349
--- a/tests/docker/dockerfiles/debian-win32-cross.docker
111
+
1350
+++ b/tests/docker/dockerfiles/debian-win32-cross.docker
112
+#define VXHS_OPT_FILENAME "filename"
1351
@@ -XXX,XX +XXX,XX @@ RUN DEBIAN_FRONTEND=noninteractive eatmydata \
113
+#define VXHS_OPT_VDISK_ID "vdisk-id"
1352
mxe-$TARGET-w64-mingw32.shared-curl \
114
+#define VXHS_OPT_SERVER "server"
1353
mxe-$TARGET-w64-mingw32.shared-glib \
115
+#define VXHS_OPT_HOST "host"
1354
mxe-$TARGET-w64-mingw32.shared-libgcrypt \
116
+#define VXHS_OPT_PORT "port"
1355
- mxe-$TARGET-w64-mingw32.shared-libssh2 \
117
+
1356
mxe-$TARGET-w64-mingw32.shared-libusb1 \
118
+/* Only accessed under QEMU global mutex */
1357
mxe-$TARGET-w64-mingw32.shared-lzo \
119
+static uint32_t vxhs_ref;
1358
mxe-$TARGET-w64-mingw32.shared-nettle \
120
+
1359
diff --git a/tests/docker/dockerfiles/debian-win64-cross.docker b/tests/docker/dockerfiles/debian-win64-cross.docker
121
+typedef enum {
1360
index XXXXXXX..XXXXXXX 100644
122
+ VDISK_AIO_READ,
1361
--- a/tests/docker/dockerfiles/debian-win64-cross.docker
123
+ VDISK_AIO_WRITE,
1362
+++ b/tests/docker/dockerfiles/debian-win64-cross.docker
124
+} VDISKAIOCmd;
1363
@@ -XXX,XX +XXX,XX @@ RUN DEBIAN_FRONTEND=noninteractive eatmydata \
125
+
1364
mxe-$TARGET-w64-mingw32.shared-curl \
126
+/*
1365
mxe-$TARGET-w64-mingw32.shared-glib \
127
+ * HyperScale AIO callbacks structure
1366
mxe-$TARGET-w64-mingw32.shared-libgcrypt \
128
+ */
1367
- mxe-$TARGET-w64-mingw32.shared-libssh2 \
129
+typedef struct VXHSAIOCB {
1368
mxe-$TARGET-w64-mingw32.shared-libusb1 \
130
+ BlockAIOCB common;
1369
mxe-$TARGET-w64-mingw32.shared-lzo \
131
+ int err;
1370
mxe-$TARGET-w64-mingw32.shared-nettle \
132
+} VXHSAIOCB;
1371
diff --git a/tests/docker/dockerfiles/fedora.docker b/tests/docker/dockerfiles/fedora.docker
133
+
1372
index XXXXXXX..XXXXXXX 100644
134
+typedef struct VXHSvDiskHostsInfo {
1373
--- a/tests/docker/dockerfiles/fedora.docker
135
+ void *dev_handle; /* Device handle */
1374
+++ b/tests/docker/dockerfiles/fedora.docker
136
+ char *host; /* Host name or IP */
1375
@@ -XXX,XX +XXX,XX @@ ENV PACKAGES \
137
+ int port; /* Host's port number */
1376
libpng-devel \
138
+} VXHSvDiskHostsInfo;
1377
librbd-devel \
139
+
1378
libseccomp-devel \
140
+/*
1379
- libssh2-devel \
141
+ * Structure per vDisk maintained for state
1380
+ libssh-devel \
142
+ */
1381
libubsan \
143
+typedef struct BDRVVXHSState {
1382
libusbx-devel \
144
+ VXHSvDiskHostsInfo vdisk_hostinfo; /* Per host info */
1383
libxml2-devel \
145
+ char *vdisk_guid;
1384
@@ -XXX,XX +XXX,XX @@ ENV PACKAGES \
146
+ char *tlscredsid; /* tlscredsid */
1385
mingw32-gtk3 \
147
+} BDRVVXHSState;
1386
mingw32-libjpeg-turbo \
148
+
1387
mingw32-libpng \
149
+static void vxhs_complete_aio_bh(void *opaque)
1388
- mingw32-libssh2 \
150
+{
1389
mingw32-libtasn1 \
151
+ VXHSAIOCB *acb = opaque;
1390
mingw32-nettle \
152
+ BlockCompletionFunc *cb = acb->common.cb;
1391
mingw32-pixman \
153
+ void *cb_opaque = acb->common.opaque;
1392
@@ -XXX,XX +XXX,XX @@ ENV PACKAGES \
154
+ int ret = 0;
1393
mingw64-gtk3 \
155
+
1394
mingw64-libjpeg-turbo \
156
+ if (acb->err != 0) {
1395
mingw64-libpng \
157
+ trace_vxhs_complete_aio(acb, acb->err);
1396
- mingw64-libssh2 \
158
+ ret = (-EIO);
1397
mingw64-libtasn1 \
159
+ }
1398
mingw64-nettle \
160
+
1399
mingw64-pixman \
161
+ qemu_aio_unref(acb);
1400
diff --git a/tests/docker/dockerfiles/ubuntu.docker b/tests/docker/dockerfiles/ubuntu.docker
162
+ cb(cb_opaque, ret);
1401
index XXXXXXX..XXXXXXX 100644
163
+}
1402
--- a/tests/docker/dockerfiles/ubuntu.docker
164
+
1403
+++ b/tests/docker/dockerfiles/ubuntu.docker
165
+/*
1404
@@ -XXX,XX +XXX,XX @@ ENV PACKAGES flex bison \
166
+ * Called from a libqnio thread
1405
libsnappy-dev \
167
+ */
1406
libspice-protocol-dev \
168
+static void vxhs_iio_callback(void *ctx, uint32_t opcode, uint32_t error)
1407
libspice-server-dev \
169
+{
1408
- libssh2-1-dev \
170
+ VXHSAIOCB *acb = NULL;
1409
+ libssh-dev \
171
+
1410
libusb-1.0-0-dev \
172
+ switch (opcode) {
1411
libusbredirhost-dev \
173
+ case IRP_READ_REQUEST:
1412
libvdeplug-dev \
174
+ case IRP_WRITE_REQUEST:
1413
diff --git a/tests/docker/dockerfiles/ubuntu1804.docker b/tests/docker/dockerfiles/ubuntu1804.docker
175
+
1414
index XXXXXXX..XXXXXXX 100644
176
+ /*
1415
--- a/tests/docker/dockerfiles/ubuntu1804.docker
177
+ * ctx is VXHSAIOCB*
1416
+++ b/tests/docker/dockerfiles/ubuntu1804.docker
178
+ * ctx is NULL if error is QNIOERROR_CHANNEL_HUP
1417
@@ -XXX,XX +XXX,XX @@ ENV PACKAGES flex bison \
179
+ */
1418
libsnappy-dev \
180
+ if (ctx) {
1419
libspice-protocol-dev \
181
+ acb = ctx;
1420
libspice-server-dev \
182
+ } else {
1421
- libssh2-1-dev \
183
+ trace_vxhs_iio_callback(error);
1422
+ libssh-dev \
184
+ goto out;
1423
libusb-1.0-0-dev \
185
+ }
1424
libusbredirhost-dev \
186
+
1425
libvdeplug-dev \
187
+ if (error) {
1426
diff --git a/tests/qemu-iotests/207 b/tests/qemu-iotests/207
188
+ if (!acb->err) {
189
+ acb->err = error;
190
+ }
191
+ trace_vxhs_iio_callback(error);
192
+ }
193
+
194
+ aio_bh_schedule_oneshot(bdrv_get_aio_context(acb->common.bs),
195
+ vxhs_complete_aio_bh, acb);
196
+ break;
197
+
198
+ default:
199
+ if (error == QNIOERROR_HUP) {
200
+ /*
201
+ * Channel failed, spontaneous notification,
202
+ * not in response to I/O
203
+ */
204
+ trace_vxhs_iio_callback_chnfail(error, errno);
205
+ } else {
206
+ trace_vxhs_iio_callback_unknwn(opcode, error);
207
+ }
208
+ break;
209
+ }
210
+out:
211
+ return;
212
+}
213
+
214
+static QemuOptsList runtime_opts = {
215
+ .name = "vxhs",
216
+ .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
217
+ .desc = {
218
+ {
219
+ .name = VXHS_OPT_FILENAME,
220
+ .type = QEMU_OPT_STRING,
221
+ .help = "URI to the Veritas HyperScale image",
222
+ },
223
+ {
224
+ .name = VXHS_OPT_VDISK_ID,
225
+ .type = QEMU_OPT_STRING,
226
+ .help = "UUID of the VxHS vdisk",
227
+ },
228
+ {
229
+ .name = "tls-creds",
230
+ .type = QEMU_OPT_STRING,
231
+ .help = "ID of the TLS/SSL credentials to use",
232
+ },
233
+ { /* end of list */ }
234
+ },
235
+};
236
+
237
+static QemuOptsList runtime_tcp_opts = {
238
+ .name = "vxhs_tcp",
239
+ .head = QTAILQ_HEAD_INITIALIZER(runtime_tcp_opts.head),
240
+ .desc = {
241
+ {
242
+ .name = VXHS_OPT_HOST,
243
+ .type = QEMU_OPT_STRING,
244
+ .help = "host address (ipv4 addresses)",
245
+ },
246
+ {
247
+ .name = VXHS_OPT_PORT,
248
+ .type = QEMU_OPT_NUMBER,
249
+ .help = "port number on which VxHSD is listening (default 9999)",
250
+ .def_value_str = "9999"
251
+ },
252
+ { /* end of list */ }
253
+ },
254
+};
255
+
256
+/*
257
+ * Parse incoming URI and populate *options with the host
258
+ * and device information
259
+ */
260
+static int vxhs_parse_uri(const char *filename, QDict *options)
261
+{
262
+ URI *uri = NULL;
263
+ char *port;
264
+ int ret = 0;
265
+
266
+ trace_vxhs_parse_uri_filename(filename);
267
+ uri = uri_parse(filename);
268
+ if (!uri || !uri->server || !uri->path) {
269
+ uri_free(uri);
270
+ return -EINVAL;
271
+ }
272
+
273
+ qdict_put(options, VXHS_OPT_SERVER".host", qstring_from_str(uri->server));
274
+
275
+ if (uri->port) {
276
+ port = g_strdup_printf("%d", uri->port);
277
+ qdict_put(options, VXHS_OPT_SERVER".port", qstring_from_str(port));
278
+ g_free(port);
279
+ }
280
+
281
+ qdict_put(options, "vdisk-id", qstring_from_str(uri->path));
282
+
283
+ trace_vxhs_parse_uri_hostinfo(uri->server, uri->port);
284
+ uri_free(uri);
285
+
286
+ return ret;
287
+}
288
+
289
+static void vxhs_parse_filename(const char *filename, QDict *options,
290
+ Error **errp)
291
+{
292
+ if (qdict_haskey(options, "vdisk-id") || qdict_haskey(options, "server")) {
293
+ error_setg(errp, "vdisk-id/server and a file name may not be specified "
294
+ "at the same time");
295
+ return;
296
+ }
297
+
298
+ if (strstr(filename, "://")) {
299
+ int ret = vxhs_parse_uri(filename, options);
300
+ if (ret < 0) {
301
+ error_setg(errp, "Invalid URI. URI should be of the form "
302
+ " vxhs://<host_ip>:<port>/<vdisk-id>");
303
+ }
304
+ }
305
+}
306
+
307
+static int vxhs_init_and_ref(void)
308
+{
309
+ if (vxhs_ref++ == 0) {
310
+ if (iio_init(QNIO_VERSION, vxhs_iio_callback)) {
311
+ return -ENODEV;
312
+ }
313
+ }
314
+ return 0;
315
+}
316
+
317
+static void vxhs_unref(void)
318
+{
319
+ if (--vxhs_ref == 0) {
320
+ iio_fini();
321
+ }
322
+}
323
+
324
+static void vxhs_get_tls_creds(const char *id, char **cacert,
325
+ char **key, char **cert, Error **errp)
326
+{
327
+ Object *obj;
328
+ QCryptoTLSCreds *creds;
329
+ QCryptoTLSCredsX509 *creds_x509;
330
+
331
+ obj = object_resolve_path_component(
332
+ object_get_objects_root(), id);
333
+
334
+ if (!obj) {
335
+ error_setg(errp, "No TLS credentials with id '%s'",
336
+ id);
337
+ return;
338
+ }
339
+
340
+ creds_x509 = (QCryptoTLSCredsX509 *)
341
+ object_dynamic_cast(obj, TYPE_QCRYPTO_TLS_CREDS_X509);
342
+
343
+ if (!creds_x509) {
344
+ error_setg(errp, "Object with id '%s' is not TLS credentials",
345
+ id);
346
+ return;
347
+ }
348
+
349
+ creds = &creds_x509->parent_obj;
350
+
351
+ if (creds->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT) {
352
+ error_setg(errp,
353
+ "Expecting TLS credentials with a client endpoint");
354
+ return;
355
+ }
356
+
357
+ /*
358
+ * Get the cacert, client_cert and client_key file names.
359
+ */
360
+ if (!creds->dir) {
361
+ error_setg(errp, "TLS object missing 'dir' property value");
362
+ return;
363
+ }
364
+
365
+ *cacert = g_strdup_printf("%s/%s", creds->dir,
366
+ QCRYPTO_TLS_CREDS_X509_CA_CERT);
367
+ *cert = g_strdup_printf("%s/%s", creds->dir,
368
+ QCRYPTO_TLS_CREDS_X509_CLIENT_CERT);
369
+ *key = g_strdup_printf("%s/%s", creds->dir,
370
+ QCRYPTO_TLS_CREDS_X509_CLIENT_KEY);
371
+}
372
+
373
+static int vxhs_open(BlockDriverState *bs, QDict *options,
374
+ int bdrv_flags, Error **errp)
375
+{
376
+ BDRVVXHSState *s = bs->opaque;
377
+ void *dev_handlep;
378
+ QDict *backing_options = NULL;
379
+ QemuOpts *opts = NULL;
380
+ QemuOpts *tcp_opts = NULL;
381
+ char *of_vsa_addr = NULL;
382
+ Error *local_err = NULL;
383
+ const char *vdisk_id_opt;
384
+ const char *server_host_opt;
385
+ int ret = 0;
386
+ char *cacert = NULL;
387
+ char *client_key = NULL;
388
+ char *client_cert = NULL;
389
+
390
+ ret = vxhs_init_and_ref();
391
+ if (ret < 0) {
392
+ ret = -EINVAL;
393
+ goto out;
394
+ }
395
+
396
+ /* Create opts info from runtime_opts and runtime_tcp_opts list */
397
+ opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
398
+ tcp_opts = qemu_opts_create(&runtime_tcp_opts, NULL, 0, &error_abort);
399
+
400
+ qemu_opts_absorb_qdict(opts, options, &local_err);
401
+ if (local_err) {
402
+ ret = -EINVAL;
403
+ goto out;
404
+ }
405
+
406
+ /* vdisk-id is the disk UUID */
407
+ vdisk_id_opt = qemu_opt_get(opts, VXHS_OPT_VDISK_ID);
408
+ if (!vdisk_id_opt) {
409
+ error_setg(&local_err, QERR_MISSING_PARAMETER, VXHS_OPT_VDISK_ID);
410
+ ret = -EINVAL;
411
+ goto out;
412
+ }
413
+
414
+ /* vdisk-id may contain a leading '/' */
415
+ if (strlen(vdisk_id_opt) > UUID_FMT_LEN + 1) {
416
+ error_setg(&local_err, "vdisk-id cannot be more than %d characters",
417
+ UUID_FMT_LEN);
418
+ ret = -EINVAL;
419
+ goto out;
420
+ }
421
+
422
+ s->vdisk_guid = g_strdup(vdisk_id_opt);
423
+ trace_vxhs_open_vdiskid(vdisk_id_opt);
424
+
425
+ /* get the 'server.' arguments */
426
+ qdict_extract_subqdict(options, &backing_options, VXHS_OPT_SERVER".");
427
+
428
+ qemu_opts_absorb_qdict(tcp_opts, backing_options, &local_err);
429
+ if (local_err != NULL) {
430
+ ret = -EINVAL;
431
+ goto out;
432
+ }
433
+
434
+ server_host_opt = qemu_opt_get(tcp_opts, VXHS_OPT_HOST);
435
+ if (!server_host_opt) {
436
+ error_setg(&local_err, QERR_MISSING_PARAMETER,
437
+ VXHS_OPT_SERVER"."VXHS_OPT_HOST);
438
+ ret = -EINVAL;
439
+ goto out;
440
+ }
441
+
442
+ if (strlen(server_host_opt) > MAXHOSTNAMELEN) {
443
+ error_setg(&local_err, "server.host cannot be more than %d characters",
444
+ MAXHOSTNAMELEN);
445
+ ret = -EINVAL;
446
+ goto out;
447
+ }
448
+
449
+ /* check if we got tls-creds via the --object argument */
450
+ s->tlscredsid = g_strdup(qemu_opt_get(opts, "tls-creds"));
451
+ if (s->tlscredsid) {
452
+ vxhs_get_tls_creds(s->tlscredsid, &cacert, &client_key,
453
+ &client_cert, &local_err);
454
+ if (local_err != NULL) {
455
+ ret = -EINVAL;
456
+ goto out;
457
+ }
458
+ trace_vxhs_get_creds(cacert, client_key, client_cert);
459
+ }
460
+
461
+ s->vdisk_hostinfo.host = g_strdup(server_host_opt);
462
+ s->vdisk_hostinfo.port = g_ascii_strtoll(qemu_opt_get(tcp_opts,
463
+ VXHS_OPT_PORT),
464
+ NULL, 0);
465
+
466
+ trace_vxhs_open_hostinfo(s->vdisk_hostinfo.host,
467
+ s->vdisk_hostinfo.port);
468
+
469
+ of_vsa_addr = g_strdup_printf("of://%s:%d",
470
+ s->vdisk_hostinfo.host,
471
+ s->vdisk_hostinfo.port);
472
+
473
+ /*
474
+ * Open qnio channel to storage agent if not opened before
475
+ */
476
+ dev_handlep = iio_open(of_vsa_addr, s->vdisk_guid, 0,
477
+ cacert, client_key, client_cert);
478
+ if (dev_handlep == NULL) {
479
+ trace_vxhs_open_iio_open(of_vsa_addr);
480
+ ret = -ENODEV;
481
+ goto out;
482
+ }
483
+ s->vdisk_hostinfo.dev_handle = dev_handlep;
484
+
485
+out:
486
+ g_free(of_vsa_addr);
487
+ QDECREF(backing_options);
488
+ qemu_opts_del(tcp_opts);
489
+ qemu_opts_del(opts);
490
+ g_free(cacert);
491
+ g_free(client_key);
492
+ g_free(client_cert);
493
+
494
+ if (ret < 0) {
495
+ vxhs_unref();
496
+ error_propagate(errp, local_err);
497
+ g_free(s->vdisk_hostinfo.host);
498
+ g_free(s->vdisk_guid);
499
+ g_free(s->tlscredsid);
500
+ s->vdisk_guid = NULL;
501
+ }
502
+
503
+ return ret;
504
+}
505
+
506
+static const AIOCBInfo vxhs_aiocb_info = {
507
+ .aiocb_size = sizeof(VXHSAIOCB)
508
+};
509
+
510
+/*
511
+ * This allocates QEMU-VXHS callback for each IO
512
+ * and is passed to QNIO. When QNIO completes the work,
513
+ * it will be passed back through the callback.
514
+ */
515
+static BlockAIOCB *vxhs_aio_rw(BlockDriverState *bs, int64_t sector_num,
516
+ QEMUIOVector *qiov, int nb_sectors,
517
+ BlockCompletionFunc *cb, void *opaque,
518
+ VDISKAIOCmd iodir)
519
+{
520
+ VXHSAIOCB *acb = NULL;
521
+ BDRVVXHSState *s = bs->opaque;
522
+ size_t size;
523
+ uint64_t offset;
524
+ int iio_flags = 0;
525
+ int ret = 0;
526
+ void *dev_handle = s->vdisk_hostinfo.dev_handle;
527
+
528
+ offset = sector_num * BDRV_SECTOR_SIZE;
529
+ size = nb_sectors * BDRV_SECTOR_SIZE;
530
+ acb = qemu_aio_get(&vxhs_aiocb_info, bs, cb, opaque);
531
+
532
+ /*
533
+ * Initialize VXHSAIOCB.
534
+ */
535
+ acb->err = 0;
536
+
537
+ iio_flags = IIO_FLAG_ASYNC;
538
+
539
+ switch (iodir) {
540
+ case VDISK_AIO_WRITE:
541
+ ret = iio_writev(dev_handle, acb, qiov->iov, qiov->niov,
542
+ offset, (uint64_t)size, iio_flags);
543
+ break;
544
+ case VDISK_AIO_READ:
545
+ ret = iio_readv(dev_handle, acb, qiov->iov, qiov->niov,
546
+ offset, (uint64_t)size, iio_flags);
547
+ break;
548
+ default:
549
+ trace_vxhs_aio_rw_invalid(iodir);
550
+ goto errout;
551
+ }
552
+
553
+ if (ret != 0) {
554
+ trace_vxhs_aio_rw_ioerr(s->vdisk_guid, iodir, size, offset,
555
+ acb, ret, errno);
556
+ goto errout;
557
+ }
558
+ return &acb->common;
559
+
560
+errout:
561
+ qemu_aio_unref(acb);
562
+ return NULL;
563
+}
564
+
565
+static BlockAIOCB *vxhs_aio_readv(BlockDriverState *bs,
566
+ int64_t sector_num, QEMUIOVector *qiov,
567
+ int nb_sectors,
568
+ BlockCompletionFunc *cb, void *opaque)
569
+{
570
+ return vxhs_aio_rw(bs, sector_num, qiov, nb_sectors, cb,
571
+ opaque, VDISK_AIO_READ);
572
+}
573
+
574
+static BlockAIOCB *vxhs_aio_writev(BlockDriverState *bs,
575
+ int64_t sector_num, QEMUIOVector *qiov,
576
+ int nb_sectors,
577
+ BlockCompletionFunc *cb, void *opaque)
578
+{
579
+ return vxhs_aio_rw(bs, sector_num, qiov, nb_sectors,
580
+ cb, opaque, VDISK_AIO_WRITE);
581
+}
582
+
583
+static void vxhs_close(BlockDriverState *bs)
584
+{
585
+ BDRVVXHSState *s = bs->opaque;
586
+
587
+ trace_vxhs_close(s->vdisk_guid);
588
+
589
+ g_free(s->vdisk_guid);
590
+ s->vdisk_guid = NULL;
591
+
592
+ /*
593
+ * Close vDisk device
594
+ */
595
+ if (s->vdisk_hostinfo.dev_handle) {
596
+ iio_close(s->vdisk_hostinfo.dev_handle);
597
+ s->vdisk_hostinfo.dev_handle = NULL;
598
+ }
599
+
600
+ vxhs_unref();
601
+
602
+ /*
603
+ * Free the dynamically allocated host string etc
604
+ */
605
+ g_free(s->vdisk_hostinfo.host);
606
+ g_free(s->tlscredsid);
607
+ s->tlscredsid = NULL;
608
+ s->vdisk_hostinfo.host = NULL;
609
+ s->vdisk_hostinfo.port = 0;
610
+}
611
+
612
+static int64_t vxhs_get_vdisk_stat(BDRVVXHSState *s)
613
+{
614
+ int64_t vdisk_size = -1;
615
+ int ret = 0;
616
+ void *dev_handle = s->vdisk_hostinfo.dev_handle;
617
+
618
+ ret = iio_ioctl(dev_handle, IOR_VDISK_STAT, &vdisk_size, 0);
619
+ if (ret < 0) {
620
+ trace_vxhs_get_vdisk_stat_err(s->vdisk_guid, ret, errno);
621
+ return -EIO;
622
+ }
623
+
624
+ trace_vxhs_get_vdisk_stat(s->vdisk_guid, vdisk_size);
625
+ return vdisk_size;
626
+}
627
+
628
+/*
629
+ * Returns the size of vDisk in bytes. This is required
630
+ * by QEMU block upper block layer so that it is visible
631
+ * to guest.
632
+ */
633
+static int64_t vxhs_getlength(BlockDriverState *bs)
634
+{
635
+ BDRVVXHSState *s = bs->opaque;
636
+ int64_t vdisk_size;
637
+
638
+ vdisk_size = vxhs_get_vdisk_stat(s);
639
+ if (vdisk_size < 0) {
640
+ return -EIO;
641
+ }
642
+
643
+ return vdisk_size;
644
+}
645
+
646
+static BlockDriver bdrv_vxhs = {
647
+ .format_name = "vxhs",
648
+ .protocol_name = "vxhs",
649
+ .instance_size = sizeof(BDRVVXHSState),
650
+ .bdrv_file_open = vxhs_open,
651
+ .bdrv_parse_filename = vxhs_parse_filename,
652
+ .bdrv_close = vxhs_close,
653
+ .bdrv_getlength = vxhs_getlength,
654
+ .bdrv_aio_readv = vxhs_aio_readv,
655
+ .bdrv_aio_writev = vxhs_aio_writev,
656
+};
657
+
658
+static void bdrv_vxhs_init(void)
659
+{
660
+ bdrv_register(&bdrv_vxhs);
661
+}
662
+
663
+block_init(bdrv_vxhs_init);
664
diff --git a/configure b/configure
665
index XXXXXXX..XXXXXXX 100755
1427
index XXXXXXX..XXXXXXX 100755
666
--- a/configure
1428
--- a/tests/qemu-iotests/207
667
+++ b/configure
1429
+++ b/tests/qemu-iotests/207
668
@@ -XXX,XX +XXX,XX @@ numa=""
1430
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.img') as disk_path, \
669
tcmalloc="no"
1431
670
jemalloc="no"
1432
iotests.img_info_log(remote_path)
671
replication="yes"
1433
672
+vxhs=""
1434
- md5_key = subprocess.check_output(
673
1435
- 'ssh-keyscan -t rsa 127.0.0.1 2>/dev/null | grep -v "\\^#" | ' +
674
supported_cpu="no"
1436
- 'cut -d" " -f3 | base64 -d | md5sum -b | cut -d" " -f1',
675
supported_os="no"
1437
- shell=True).rstrip().decode('ascii')
676
@@ -XXX,XX +XXX,XX @@ for opt do
1438
+ keys = subprocess.check_output(
677
;;
1439
+ 'ssh-keyscan 127.0.0.1 2>/dev/null | grep -v "\\^#" | ' +
678
--enable-replication) replication="yes"
1440
+ 'cut -d" " -f3',
679
;;
1441
+ shell=True).rstrip().decode('ascii').split('\n')
680
+ --disable-vxhs) vxhs="no"
1442
+
681
+ ;;
1443
+ # Mappings of base64 representations to digests
682
+ --enable-vxhs) vxhs="yes"
1444
+ md5_keys = {}
683
+ ;;
1445
+ sha1_keys = {}
684
*)
1446
+
685
echo "ERROR: unknown option $opt"
1447
+ for key in keys:
686
echo "Try '$0 --help' for more information"
1448
+ md5_keys[key] = subprocess.check_output(
687
@@ -XXX,XX +XXX,XX @@ disabled with --disable-FEATURE, default is enabled if available:
1449
+ 'echo %s | base64 -d | md5sum -b | cut -d" " -f1' % key,
688
xfsctl xfsctl support
1450
+ shell=True).rstrip().decode('ascii')
689
qom-cast-debug cast debugging support
1451
+
690
tools build qemu-io, qemu-nbd and qemu-image tools
1452
+ sha1_keys[key] = subprocess.check_output(
691
+ vxhs Veritas HyperScale vDisk backend support
1453
+ 'echo %s | base64 -d | sha1sum -b | cut -d" " -f1' % key,
692
1454
+ shell=True).rstrip().decode('ascii')
693
NOTE: The object files are built at the place where configure is launched
1455
694
EOF
1456
vm.launch()
695
@@ -XXX,XX +XXX,XX @@ if compile_prog "" "" ; then
1457
+
696
fi
1458
+ # Find correct key first
697
1459
+ matching_key = None
698
##########################################
1460
+ for key in keys:
699
+# Veritas HyperScale block driver VxHS
1461
+ result = vm.qmp('blockdev-add',
700
+# Check if libvxhs is installed
1462
+ driver='ssh', node_name='node0', path=disk_path,
701
+
1463
+ server={
702
+if test "$vxhs" != "no" ; then
1464
+ 'host': '127.0.0.1',
703
+ cat > $TMPC <<EOF
1465
+ 'port': '22',
704
+#include <stdint.h>
1466
+ }, host_key_check={
705
+#include <qnio/qnio_api.h>
1467
+ 'mode': 'hash',
706
+
1468
+ 'type': 'md5',
707
+void *vxhs_callback;
1469
+ 'hash': md5_keys[key],
708
+
1470
+ })
709
+int main(void) {
1471
+
710
+ iio_init(QNIO_VERSION, vxhs_callback);
1472
+ if 'error' not in result:
711
+ return 0;
1473
+ vm.qmp('blockdev-del', node_name='node0')
712
+}
1474
+ matching_key = key
713
+EOF
1475
+ break
714
+ vxhs_libs="-lvxhs -lssl"
1476
+
715
+ if compile_prog "" "$vxhs_libs" ; then
1477
+ if matching_key is None:
716
+ vxhs=yes
1478
+ vm.shutdown()
717
+ else
1479
+ iotests.notrun('Did not find a key that fits 127.0.0.1')
718
+ if test "$vxhs" = "yes" ; then
1480
+
719
+ feature_not_found "vxhs block device" "Install libvxhs See github"
1481
blockdev_create(vm, { 'driver': 'ssh',
720
+ fi
1482
'location': {
721
+ vxhs=no
1483
'path': disk_path,
722
+ fi
1484
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.img') as disk_path, \
723
+fi
1485
'host-key-check': {
724
+
1486
'mode': 'hash',
725
+##########################################
1487
'type': 'md5',
726
# End of CC checks
1488
- 'hash': md5_key,
727
# After here, no more $cc or $ld runs
1489
+ 'hash': md5_keys[matching_key],
728
1490
}
729
@@ -XXX,XX +XXX,XX @@ echo "tcmalloc support $tcmalloc"
1491
},
730
echo "jemalloc support $jemalloc"
1492
'size': 8388608 })
731
echo "avx2 optimization $avx2_opt"
1493
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.img') as disk_path, \
732
echo "replication support $replication"
1494
733
+echo "VxHS block device $vxhs"
1495
iotests.img_info_log(remote_path)
734
1496
735
if test "$sdl_too_old" = "yes"; then
1497
- sha1_key = subprocess.check_output(
736
echo "-> Your SDL version is too old - please upgrade to have SDL support"
1498
- 'ssh-keyscan -t rsa 127.0.0.1 2>/dev/null | grep -v "\\^#" | ' +
737
@@ -XXX,XX +XXX,XX @@ if test "$pthread_setname_np" = "yes" ; then
1499
- 'cut -d" " -f3 | base64 -d | sha1sum -b | cut -d" " -f1',
738
echo "CONFIG_PTHREAD_SETNAME_NP=y" >> $config_host_mak
1500
- shell=True).rstrip().decode('ascii')
739
fi
1501
-
740
1502
vm.launch()
741
+if test "$vxhs" = "yes" ; then
1503
blockdev_create(vm, { 'driver': 'ssh',
742
+ echo "CONFIG_VXHS=y" >> $config_host_mak
1504
'location': {
743
+ echo "VXHS_LIBS=$vxhs_libs" >> $config_host_mak
1505
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.img') as disk_path, \
744
+fi
1506
'host-key-check': {
745
+
1507
'mode': 'hash',
746
if test "$tcg_interpreter" = "yes"; then
1508
'type': 'sha1',
747
QEMU_INCLUDES="-I\$(SRC_PATH)/tcg/tci $QEMU_INCLUDES"
1509
- 'hash': sha1_key,
748
elif test "$ARCH" = "sparc64" ; then
1510
+ 'hash': sha1_keys[matching_key],
749
diff --git a/qapi/block-core.json b/qapi/block-core.json
1511
}
1512
},
1513
'size': 4194304 })
1514
diff --git a/tests/qemu-iotests/207.out b/tests/qemu-iotests/207.out
750
index XXXXXXX..XXXXXXX 100644
1515
index XXXXXXX..XXXXXXX 100644
751
--- a/qapi/block-core.json
1516
--- a/tests/qemu-iotests/207.out
752
+++ b/qapi/block-core.json
1517
+++ b/tests/qemu-iotests/207.out
753
@@ -XXX,XX +XXX,XX @@
1518
@@ -XXX,XX +XXX,XX @@ virtual size: 4 MiB (4194304 bytes)
754
#
1519
755
# Drivers that are supported in block device operations.
1520
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"mode": "none"}, "path": "/this/is/not/an/existing/path", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 4194304}}}
756
#
1521
{"return": {}}
757
+# @vxhs: Since 2.10
1522
-Job failed: failed to open remote file '/this/is/not/an/existing/path': Failed opening remote file (libssh2 error code: -31)
758
+#
1523
+Job failed: failed to open remote file '/this/is/not/an/existing/path': SFTP server: No such file (libssh error code: 1, sftp error code: 2)
759
# Since: 2.9
1524
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
760
##
1525
{"return": {}}
761
{ 'enum': 'BlockdevDriver',
1526
762
@@ -XXX,XX +XXX,XX @@
763
'host_device', 'http', 'https', 'iscsi', 'luks', 'nbd', 'nfs',
764
'null-aio', 'null-co', 'parallels', 'qcow', 'qcow2', 'qed',
765
'quorum', 'raw', 'rbd', 'replication', 'sheepdog', 'ssh',
766
- 'vdi', 'vhdx', 'vmdk', 'vpc', 'vvfat' ] }
767
+ 'vdi', 'vhdx', 'vmdk', 'vpc', 'vvfat', 'vxhs' ] }
768
769
##
770
# @BlockdevOptionsFile:
771
@@ -XXX,XX +XXX,XX @@
772
'data': { '*offset': 'int', '*size': 'int' } }
773
774
##
775
+# @BlockdevOptionsVxHS:
776
+#
777
+# Driver specific block device options for VxHS
778
+#
779
+# @vdisk-id: UUID of VxHS volume
780
+# @server: vxhs server IP, port
781
+# @tls-creds: TLS credentials ID
782
+#
783
+# Since: 2.10
784
+##
785
+{ 'struct': 'BlockdevOptionsVxHS',
786
+ 'data': { 'vdisk-id': 'str',
787
+ 'server': 'InetSocketAddressBase',
788
+ '*tls-creds': 'str' } }
789
+
790
+##
791
# @BlockdevOptions:
792
#
793
# Options for creating a block device. Many options are available for all
794
@@ -XXX,XX +XXX,XX @@
795
'vhdx': 'BlockdevOptionsGenericFormat',
796
'vmdk': 'BlockdevOptionsGenericCOWFormat',
797
'vpc': 'BlockdevOptionsGenericFormat',
798
- 'vvfat': 'BlockdevOptionsVVFAT'
799
+ 'vvfat': 'BlockdevOptionsVVFAT',
800
+ 'vxhs': 'BlockdevOptionsVxHS'
801
} }
802
803
##
804
--
1527
--
805
2.9.3
1528
2.21.0
806
1529
807
1530
diff view generated by jsdifflib
Deleted patch
1
From: Ashish Mittal <ashmit602@gmail.com>
2
1
3
These changes use a vxhs test server that is a part of the following
4
repository:
5
https://github.com/VeritasHyperScale/libqnio.git
6
7
Signed-off-by: Ashish Mittal <Ashish.Mittal@veritas.com>
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
9
Reviewed-by: Jeff Cody <jcody@redhat.com>
10
Signed-off-by: Jeff Cody <jcody@redhat.com>
11
Message-id: 1491277689-24949-3-git-send-email-Ashish.Mittal@veritas.com
12
---
13
tests/qemu-iotests/common | 6 ++++++
14
tests/qemu-iotests/common.config | 13 +++++++++++++
15
tests/qemu-iotests/common.filter | 1 +
16
tests/qemu-iotests/common.rc | 19 +++++++++++++++++++
17
4 files changed, 39 insertions(+)
18
19
diff --git a/tests/qemu-iotests/common b/tests/qemu-iotests/common
20
index XXXXXXX..XXXXXXX 100644
21
--- a/tests/qemu-iotests/common
22
+++ b/tests/qemu-iotests/common
23
@@ -XXX,XX +XXX,XX @@ check options
24
-ssh test ssh
25
-nfs test nfs
26
-luks test luks
27
+ -vxhs test vxhs
28
-xdiff graphical mode diff
29
-nocache use O_DIRECT on backing file
30
-misalign misalign memory allocations
31
@@ -XXX,XX +XXX,XX @@ testlist options
32
xpand=false
33
;;
34
35
+ -vxhs)
36
+ IMGPROTO=vxhs
37
+ xpand=false
38
+ ;;
39
+
40
-ssh)
41
IMGPROTO=ssh
42
xpand=false
43
diff --git a/tests/qemu-iotests/common.config b/tests/qemu-iotests/common.config
44
index XXXXXXX..XXXXXXX 100644
45
--- a/tests/qemu-iotests/common.config
46
+++ b/tests/qemu-iotests/common.config
47
@@ -XXX,XX +XXX,XX @@ if [ -z "$QEMU_NBD_PROG" ]; then
48
export QEMU_NBD_PROG="`set_prog_path qemu-nbd`"
49
fi
50
51
+if [ -z "$QEMU_VXHS_PROG" ]; then
52
+ export QEMU_VXHS_PROG="`set_prog_path qnio_server`"
53
+fi
54
+
55
_qemu_wrapper()
56
{
57
(
58
@@ -XXX,XX +XXX,XX @@ _qemu_nbd_wrapper()
59
)
60
}
61
62
+_qemu_vxhs_wrapper()
63
+{
64
+ (
65
+ echo $BASHPID > "${TEST_DIR}/qemu-vxhs.pid"
66
+ exec "$QEMU_VXHS_PROG" $QEMU_VXHS_OPTIONS "$@"
67
+ )
68
+}
69
+
70
export QEMU=_qemu_wrapper
71
export QEMU_IMG=_qemu_img_wrapper
72
export QEMU_IO=_qemu_io_wrapper
73
export QEMU_NBD=_qemu_nbd_wrapper
74
+export QEMU_VXHS=_qemu_vxhs_wrapper
75
76
QEMU_IMG_EXTRA_ARGS=
77
if [ "$IMGOPTSSYNTAX" = "true" ]; then
78
diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter
79
index XXXXXXX..XXXXXXX 100644
80
--- a/tests/qemu-iotests/common.filter
81
+++ b/tests/qemu-iotests/common.filter
82
@@ -XXX,XX +XXX,XX @@ _filter_img_info()
83
-e "s#$TEST_DIR#TEST_DIR#g" \
84
-e "s#$IMGFMT#IMGFMT#g" \
85
-e 's#nbd://127.0.0.1:10810$#TEST_DIR/t.IMGFMT#g' \
86
+ -e 's#json.*vdisk-id.*vxhs"}}#TEST_DIR/t.IMGFMT#' \
87
-e "/encrypted: yes/d" \
88
-e "/cluster_size: [0-9]\\+/d" \
89
-e "/table_size: [0-9]\\+/d" \
90
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
91
index XXXXXXX..XXXXXXX 100644
92
--- a/tests/qemu-iotests/common.rc
93
+++ b/tests/qemu-iotests/common.rc
94
@@ -XXX,XX +XXX,XX @@ else
95
elif [ "$IMGPROTO" = "nfs" ]; then
96
TEST_DIR="nfs://127.0.0.1/$TEST_DIR"
97
TEST_IMG=$TEST_DIR/t.$IMGFMT
98
+ elif [ "$IMGPROTO" = "vxhs" ]; then
99
+ TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT
100
+ TEST_IMG="vxhs://127.0.0.1:9999/t.$IMGFMT"
101
else
102
TEST_IMG=$IMGPROTO:$TEST_DIR/t.$IMGFMT
103
fi
104
@@ -XXX,XX +XXX,XX @@ _make_test_img()
105
eval "$QEMU_NBD -v -t -b 127.0.0.1 -p 10810 -f $IMGFMT $TEST_IMG_FILE >/dev/null &"
106
sleep 1 # FIXME: qemu-nbd needs to be listening before we continue
107
fi
108
+
109
+ # Start QNIO server on image directory for vxhs protocol
110
+ if [ $IMGPROTO = "vxhs" ]; then
111
+ eval "$QEMU_VXHS -d $TEST_DIR > /dev/null &"
112
+ sleep 1 # Wait for server to come up.
113
+ fi
114
}
115
116
_rm_test_img()
117
@@ -XXX,XX +XXX,XX @@ _cleanup_test_img()
118
fi
119
rm -f "$TEST_IMG_FILE"
120
;;
121
+ vxhs)
122
+ if [ -f "${TEST_DIR}/qemu-vxhs.pid" ]; then
123
+ local QEMU_VXHS_PID
124
+ read QEMU_VXHS_PID < "${TEST_DIR}/qemu-vxhs.pid"
125
+ kill ${QEMU_VXHS_PID} >/dev/null 2>&1
126
+ rm -f "${TEST_DIR}/qemu-vxhs.pid"
127
+ fi
128
+ rm -f "$TEST_IMG_FILE"
129
+ ;;
130
+
131
file)
132
_rm_test_img "$TEST_DIR/t.$IMGFMT"
133
_rm_test_img "$TEST_DIR/t.$IMGFMT.orig"
134
--
135
2.9.3
136
137
diff view generated by jsdifflib
Deleted patch
1
We have a helper wrapper for checking for the BDS read_only flag,
2
add a helper wrapper to set the read_only flag as well.
3
1
4
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
5
Signed-off-by: Jeff Cody <jcody@redhat.com>
6
Reviewed-by: John Snow <jsnow@redhat.com>
7
Message-id: 9b18972d05f5fa2ac16c014f0af98d680553048d.1491597120.git.jcody@redhat.com
8
---
9
block.c | 5 +++++
10
block/bochs.c | 2 +-
11
block/cloop.c | 2 +-
12
block/dmg.c | 2 +-
13
block/rbd.c | 2 +-
14
block/vvfat.c | 4 ++--
15
include/block/block.h | 1 +
16
7 files changed, 12 insertions(+), 6 deletions(-)
17
18
diff --git a/block.c b/block.c
19
index XXXXXXX..XXXXXXX 100644
20
--- a/block.c
21
+++ b/block.c
22
@@ -XXX,XX +XXX,XX @@ void path_combine(char *dest, int dest_size,
23
}
24
}
25
26
+void bdrv_set_read_only(BlockDriverState *bs, bool read_only)
27
+{
28
+ bs->read_only = read_only;
29
+}
30
+
31
void bdrv_get_full_backing_filename_from_filename(const char *backed,
32
const char *backing,
33
char *dest, size_t sz,
34
diff --git a/block/bochs.c b/block/bochs.c
35
index XXXXXXX..XXXXXXX 100644
36
--- a/block/bochs.c
37
+++ b/block/bochs.c
38
@@ -XXX,XX +XXX,XX @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags,
39
return -EINVAL;
40
}
41
42
- bs->read_only = true; /* no write support yet */
43
+ bdrv_set_read_only(bs, true); /* no write support yet */
44
45
ret = bdrv_pread(bs->file, 0, &bochs, sizeof(bochs));
46
if (ret < 0) {
47
diff --git a/block/cloop.c b/block/cloop.c
48
index XXXXXXX..XXXXXXX 100644
49
--- a/block/cloop.c
50
+++ b/block/cloop.c
51
@@ -XXX,XX +XXX,XX @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
52
return -EINVAL;
53
}
54
55
- bs->read_only = true;
56
+ bdrv_set_read_only(bs, true);
57
58
/* read header */
59
ret = bdrv_pread(bs->file, 128, &s->block_size, 4);
60
diff --git a/block/dmg.c b/block/dmg.c
61
index XXXXXXX..XXXXXXX 100644
62
--- a/block/dmg.c
63
+++ b/block/dmg.c
64
@@ -XXX,XX +XXX,XX @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
65
}
66
67
block_module_load_one("dmg-bz2");
68
- bs->read_only = true;
69
+ bdrv_set_read_only(bs, true);
70
71
s->n_chunks = 0;
72
s->offsets = s->lengths = s->sectors = s->sectorcounts = NULL;
73
diff --git a/block/rbd.c b/block/rbd.c
74
index XXXXXXX..XXXXXXX 100644
75
--- a/block/rbd.c
76
+++ b/block/rbd.c
77
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
78
goto failed_open;
79
}
80
81
- bs->read_only = (s->snap != NULL);
82
+ bdrv_set_read_only(bs, (s->snap != NULL));
83
84
qemu_opts_del(opts);
85
return 0;
86
diff --git a/block/vvfat.c b/block/vvfat.c
87
index XXXXXXX..XXXXXXX 100644
88
--- a/block/vvfat.c
89
+++ b/block/vvfat.c
90
@@ -XXX,XX +XXX,XX @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags,
91
s->current_cluster=0xffffffff;
92
93
/* read only is the default for safety */
94
- bs->read_only = true;
95
+ bdrv_set_read_only(bs, true);
96
s->qcow = NULL;
97
s->qcow_filename = NULL;
98
s->fat2 = NULL;
99
@@ -XXX,XX +XXX,XX @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags,
100
if (ret < 0) {
101
goto fail;
102
}
103
- bs->read_only = false;
104
+ bdrv_set_read_only(bs, false);
105
}
106
107
bs->total_sectors = cyls * heads * secs;
108
diff --git a/include/block/block.h b/include/block/block.h
109
index XXXXXXX..XXXXXXX 100644
110
--- a/include/block/block.h
111
+++ b/include/block/block.h
112
@@ -XXX,XX +XXX,XX @@ int bdrv_is_allocated_above(BlockDriverState *top, BlockDriverState *base,
113
int64_t sector_num, int nb_sectors, int *pnum);
114
115
bool bdrv_is_read_only(BlockDriverState *bs);
116
+void bdrv_set_read_only(BlockDriverState *bs, bool read_only);
117
bool bdrv_is_sg(BlockDriverState *bs);
118
bool bdrv_is_inserted(BlockDriverState *bs);
119
int bdrv_media_changed(BlockDriverState *bs);
120
--
121
2.9.3
122
123
diff view generated by jsdifflib
Deleted patch
1
The BDRV_O_ALLOW_RDWR flag allows / prohibits the changing of
2
the BDS 'read_only' state, but there are a few places where it
3
is ignored. In the bdrv_set_read_only() helper, make sure to
4
honor the flag.
5
1
6
Signed-off-by: Jeff Cody <jcody@redhat.com>
7
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
8
Reviewed-by: John Snow <jsnow@redhat.com>
9
Message-id: be2e5fb2d285cbece2b6d06bed54a6f56520d251.1491597120.git.jcody@redhat.com
10
---
11
block.c | 7 +++++++
12
1 file changed, 7 insertions(+)
13
14
diff --git a/block.c b/block.c
15
index XXXXXXX..XXXXXXX 100644
16
--- a/block.c
17
+++ b/block.c
18
@@ -XXX,XX +XXX,XX @@ int bdrv_set_read_only(BlockDriverState *bs, bool read_only, Error **errp)
19
return -EINVAL;
20
}
21
22
+ /* Do not clear read_only if it is prohibited */
23
+ if (!read_only && !(bs->open_flags & BDRV_O_ALLOW_RDWR)) {
24
+ error_setg(errp, "Node '%s' is read only",
25
+ bdrv_get_device_or_node_name(bs));
26
+ return -EPERM;
27
+ }
28
+
29
bs->read_only = read_only;
30
return 0;
31
}
32
--
33
2.9.3
34
35
diff view generated by jsdifflib
Deleted patch
1
Move bdrv_is_read_only() up with its friends.
2
1
3
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
4
Reviewed-by: John Snow <jsnow@redhat.com>
5
Signed-off-by: Jeff Cody <jcody@redhat.com>
6
Message-id: 73b2399459760c32506f9407efb9dddb3a2789de.1491597120.git.jcody@redhat.com
7
---
8
block.c | 10 +++++-----
9
1 file changed, 5 insertions(+), 5 deletions(-)
10
11
diff --git a/block.c b/block.c
12
index XXXXXXX..XXXXXXX 100644
13
--- a/block.c
14
+++ b/block.c
15
@@ -XXX,XX +XXX,XX @@ void path_combine(char *dest, int dest_size,
16
}
17
}
18
19
+bool bdrv_is_read_only(BlockDriverState *bs)
20
+{
21
+ return bs->read_only;
22
+}
23
+
24
int bdrv_set_read_only(BlockDriverState *bs, bool read_only, Error **errp)
25
{
26
/* Do not set read_only if copy_on_read is enabled */
27
@@ -XXX,XX +XXX,XX @@ void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr)
28
*nb_sectors_ptr = nb_sectors < 0 ? 0 : nb_sectors;
29
}
30
31
-bool bdrv_is_read_only(BlockDriverState *bs)
32
-{
33
- return bs->read_only;
34
-}
35
-
36
bool bdrv_is_sg(BlockDriverState *bs)
37
{
38
return bs->sg;
39
--
40
2.9.3
41
42
diff view generated by jsdifflib
1
Signed-off-by: Jeff Cody <jcody@redhat.com>
1
Tests should place their files into the test directory. This includes
2
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
2
Unix sockets. 205 currently fails to do so, which prevents it from
3
Reviewed-by: John Snow <jsnow@redhat.com>
3
being run concurrently.
4
Message-id: 00aed7ffdd7be4b9ed9ce1007d50028a72b34ebe.1491597120.git.jcody@redhat.com
4
5
Signed-off-by: Max Reitz <mreitz@redhat.com>
6
Message-id: 20190618210238.9524-1-mreitz@redhat.com
7
Reviewed-by: Eric Blake <eblake@redhat.com>
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
5
---
9
---
6
block.c | 14 ++++++++------
10
tests/qemu-iotests/205 | 2 +-
7
1 file changed, 8 insertions(+), 6 deletions(-)
11
1 file changed, 1 insertion(+), 1 deletion(-)
8
12
9
diff --git a/block.c b/block.c
13
diff --git a/tests/qemu-iotests/205 b/tests/qemu-iotests/205
10
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100755
11
--- a/block.c
15
--- a/tests/qemu-iotests/205
12
+++ b/block.c
16
+++ b/tests/qemu-iotests/205
13
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,
17
@@ -XXX,XX +XXX,XX @@ import iotests
14
BlockDriver *drv;
18
import time
15
QemuOpts *opts;
19
from iotests import qemu_img_create, qemu_io, filter_qemu_io, QemuIoInteractive
16
const char *value;
20
17
+ bool read_only;
21
-nbd_sock = 'nbd_sock'
18
22
+nbd_sock = os.path.join(iotests.test_dir, 'nbd_sock')
19
assert(reopen_state != NULL);
23
nbd_uri = 'nbd+unix:///exp?socket=' + nbd_sock
20
assert(reopen_state->bs->drv != NULL);
24
disk = os.path.join(iotests.test_dir, 'disk')
21
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,
22
qdict_put(reopen_state->options, "driver", qstring_from_str(value));
23
}
24
25
- /* if we are to stay read-only, do not allow permission change
26
- * to r/w */
27
- if (!(reopen_state->bs->open_flags & BDRV_O_ALLOW_RDWR) &&
28
- reopen_state->flags & BDRV_O_RDWR) {
29
- error_setg(errp, "Node '%s' is read only",
30
- bdrv_get_device_or_node_name(reopen_state->bs));
31
+ /* If we are to stay read-only, do not allow permission change
32
+ * to r/w. Attempting to set to r/w may fail if either BDRV_O_ALLOW_RDWR is
33
+ * not set, or if the BDS still has copy_on_read enabled */
34
+ read_only = !(reopen_state->flags & BDRV_O_RDWR);
35
+ ret = bdrv_can_set_read_only(reopen_state->bs, read_only, &local_err);
36
+ if (local_err) {
37
+ error_propagate(errp, local_err);
38
goto error;
39
}
40
25
41
--
26
--
42
2.9.3
27
2.21.0
43
28
44
29
diff view generated by jsdifflib