1
The following changes since commit 33d609990621dea6c7d056c86f707b8811320ac1:
1
The following changes since commit 6c769690ac845fa62642a5f93b4e4bd906adab95:
2
2
3
Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging (2019-06-18 17:00:52 +0100)
3
Merge remote-tracking branch 'remotes/vsementsov/tags/pull-simplebench-2021-05-04' into staging (2021-05-21 12:02:34 +0100)
4
4
5
are available in the Git repository at:
5
are available in the Git repository at:
6
6
7
https://github.com/XanClic/qemu.git tags/pull-block-2019-06-21
7
https://gitlab.com/stefanha/qemu.git tags/block-pull-request
8
8
9
for you to fetch changes up to e2a76186f7948b8b75d1b2b52638de7c2f7f7472:
9
for you to fetch changes up to 0a6f0c76a030710780ce10d6347a70f098024d21:
10
10
11
iotests: Fix 205 for concurrent runs (2019-06-21 14:40:28 +0200)
11
coroutine-sleep: introduce qemu_co_sleep (2021-05-21 18:22:33 +0100)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
Block patches:
14
Pull request
15
- The SSH block driver now uses libssh instead of libssh2
15
16
- The VMDK block driver gets read-only support for the seSparse
16
(Resent due to an email preparation mistake.)
17
subformat
18
- Various fixes
19
17
20
----------------------------------------------------------------
18
----------------------------------------------------------------
21
Anton Nefedov (1):
22
iotest 134: test cluster-misaligned encrypted write
23
19
24
Klaus Birkelund Jensen (1):
20
Paolo Bonzini (6):
25
nvme: do not advertise support for unsupported arbitration mechanism
21
coroutine-sleep: use a stack-allocated timer
22
coroutine-sleep: disallow NULL QemuCoSleepState** argument
23
coroutine-sleep: allow qemu_co_sleep_wake that wakes nothing
24
coroutine-sleep: move timer out of QemuCoSleepState
25
coroutine-sleep: replace QemuCoSleepState pointer with struct in the
26
API
27
coroutine-sleep: introduce qemu_co_sleep
26
28
27
Max Reitz (1):
29
Philippe Mathieu-Daudé (1):
28
iotests: Fix 205 for concurrent runs
30
bitops.h: Improve find_xxx_bit() documentation
29
31
30
Pino Toscano (1):
32
Zenghui Yu (1):
31
ssh: switch from libssh2 to libssh
33
multi-process: Initialize variables declared with g_auto*
32
34
33
Sam Eiderman (3):
35
include/qemu/bitops.h | 15 ++++++--
34
vmdk: Fix comment regarding max l1_size coverage
36
include/qemu/coroutine.h | 27 ++++++++-----
35
vmdk: Reduce the max bound for L1 table size
37
block/block-copy.c | 10 ++---
36
vmdk: Add read-only support for seSparse snapshots
38
block/nbd.c | 14 +++----
37
39
hw/remote/memory.c | 5 +--
38
Vladimir Sementsov-Ogievskiy (1):
40
hw/remote/proxy.c | 3 +-
39
blockdev: enable non-root nodes for transaction drive-backup source
41
util/qemu-coroutine-sleep.c | 75 +++++++++++++++++++------------------
40
42
7 files changed, 79 insertions(+), 70 deletions(-)
41
configure | 65 +-
42
block/Makefile.objs | 6 +-
43
block/ssh.c | 673 ++++++++++--------
44
block/vmdk.c | 372 +++++++++-
45
blockdev.c | 2 +-
46
hw/block/nvme.c | 1 -
47
.travis.yml | 4 +-
48
block/trace-events | 14 +-
49
docs/qemu-block-drivers.texi | 2 +-
50
.../dockerfiles/debian-win32-cross.docker | 1 -
51
.../dockerfiles/debian-win64-cross.docker | 1 -
52
tests/docker/dockerfiles/fedora.docker | 4 +-
53
tests/docker/dockerfiles/ubuntu.docker | 2 +-
54
tests/docker/dockerfiles/ubuntu1804.docker | 2 +-
55
tests/qemu-iotests/059.out | 2 +-
56
tests/qemu-iotests/134 | 9 +
57
tests/qemu-iotests/134.out | 10 +
58
tests/qemu-iotests/205 | 2 +-
59
tests/qemu-iotests/207 | 54 +-
60
tests/qemu-iotests/207.out | 2 +-
61
20 files changed, 844 insertions(+), 384 deletions(-)
62
43
63
--
44
--
64
2.21.0
45
2.31.1
65
46
66
diff view generated by jsdifflib
1
Tests should place their files into the test directory. This includes
1
From: Zenghui Yu <yuzenghui@huawei.com>
2
Unix sockets. 205 currently fails to do so, which prevents it from
3
being run concurrently.
4
2
5
Signed-off-by: Max Reitz <mreitz@redhat.com>
3
Quote docs/devel/style.rst (section "Automatic memory deallocation"):
6
Message-id: 20190618210238.9524-1-mreitz@redhat.com
4
7
Reviewed-by: Eric Blake <eblake@redhat.com>
5
* Variables declared with g_auto* MUST always be initialized,
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
6
otherwise the cleanup function will use uninitialized stack memory
7
8
Initialize @name properly to get rid of the compilation error (using
9
gcc-7.3.0 on CentOS):
10
11
../hw/remote/proxy.c: In function 'pci_proxy_dev_realize':
12
/usr/include/glib-2.0/glib/glib-autocleanups.h:28:3: error: 'name' may be used uninitialized in this function [-Werror=maybe-uninitialized]
13
g_free (*pp);
14
^~~~~~~~~~~~
15
../hw/remote/proxy.c:350:30: note: 'name' was declared here
16
g_autofree char *name;
17
^~~~
18
19
Signed-off-by: Zenghui Yu <yuzenghui@huawei.com>
20
Reviewed-by: Jagannathan Raman <jag.raman@oracle.com>
21
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
22
Reviewed-by: Miroslav Rezanina <mrezanin@redhat.com>
23
Message-id: 20210312112143.1369-1-yuzenghui@huawei.com
24
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
9
---
25
---
10
tests/qemu-iotests/205 | 2 +-
26
hw/remote/memory.c | 5 ++---
11
1 file changed, 1 insertion(+), 1 deletion(-)
27
hw/remote/proxy.c | 3 +--
28
2 files changed, 3 insertions(+), 5 deletions(-)
12
29
13
diff --git a/tests/qemu-iotests/205 b/tests/qemu-iotests/205
30
diff --git a/hw/remote/memory.c b/hw/remote/memory.c
14
index XXXXXXX..XXXXXXX 100755
31
index XXXXXXX..XXXXXXX 100644
15
--- a/tests/qemu-iotests/205
32
--- a/hw/remote/memory.c
16
+++ b/tests/qemu-iotests/205
33
+++ b/hw/remote/memory.c
17
@@ -XXX,XX +XXX,XX @@ import iotests
34
@@ -XXX,XX +XXX,XX @@ void remote_sysmem_reconfig(MPQemuMsg *msg, Error **errp)
18
import time
35
19
from iotests import qemu_img_create, qemu_io, filter_qemu_io, QemuIoInteractive
36
remote_sysmem_reset();
20
37
21
-nbd_sock = 'nbd_sock'
38
- for (region = 0; region < msg->num_fds; region++) {
22
+nbd_sock = os.path.join(iotests.test_dir, 'nbd_sock')
39
- g_autofree char *name;
23
nbd_uri = 'nbd+unix:///exp?socket=' + nbd_sock
40
+ for (region = 0; region < msg->num_fds; region++, suffix++) {
24
disk = os.path.join(iotests.test_dir, 'disk')
41
+ g_autofree char *name = g_strdup_printf("remote-mem-%u", suffix);
25
42
subregion = g_new(MemoryRegion, 1);
43
- name = g_strdup_printf("remote-mem-%u", suffix++);
44
memory_region_init_ram_from_fd(subregion, NULL,
45
name, sysmem_info->sizes[region],
46
true, msg->fds[region],
47
diff --git a/hw/remote/proxy.c b/hw/remote/proxy.c
48
index XXXXXXX..XXXXXXX 100644
49
--- a/hw/remote/proxy.c
50
+++ b/hw/remote/proxy.c
51
@@ -XXX,XX +XXX,XX @@ static void probe_pci_info(PCIDevice *dev, Error **errp)
52
PCI_BASE_ADDRESS_SPACE_IO : PCI_BASE_ADDRESS_SPACE_MEMORY;
53
54
if (size) {
55
- g_autofree char *name;
56
+ g_autofree char *name = g_strdup_printf("bar-region-%d", i);
57
pdev->region[i].dev = pdev;
58
pdev->region[i].present = true;
59
if (type == PCI_BASE_ADDRESS_SPACE_MEMORY) {
60
pdev->region[i].memory = true;
61
}
62
- name = g_strdup_printf("bar-region-%d", i);
63
memory_region_init_io(&pdev->region[i].mr, OBJECT(pdev),
64
&proxy_mr_ops, &pdev->region[i],
65
name, size);
26
--
66
--
27
2.21.0
67
2.31.1
28
68
29
diff view generated by jsdifflib
1
From: Sam Eiderman <shmuel.eiderman@oracle.com>
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
2
2
3
512M of L1 entries is a very loose bound, only 32M are required to store
3
Document the following functions return the bitmap size
4
the maximal supported VMDK file size of 2TB.
4
if no matching bit is found:
5
5
6
Fixed qemu-iotest 59# - now failure occures before on impossible L1
6
- find_first_bit
7
table size.
7
- find_next_bit
8
- find_last_bit
9
- find_first_zero_bit
10
- find_next_zero_bit
8
11
9
Reviewed-by: Karl Heubaum <karl.heubaum@oracle.com>
12
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
10
Reviewed-by: Eyal Moscovici <eyal.moscovici@oracle.com>
13
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
11
Reviewed-by: Liran Alon <liran.alon@oracle.com>
14
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
12
Reviewed-by: Arbel Moshe <arbel.moshe@oracle.com>
15
Message-id: 20210510200758.2623154-2-philmd@redhat.com
13
Signed-off-by: Sam Eiderman <shmuel.eiderman@oracle.com>
16
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.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>
17
---
17
---
18
block/vmdk.c | 13 +++++++------
18
include/qemu/bitops.h | 15 ++++++++++++---
19
tests/qemu-iotests/059.out | 2 +-
19
1 file changed, 12 insertions(+), 3 deletions(-)
20
2 files changed, 8 insertions(+), 7 deletions(-)
21
20
22
diff --git a/block/vmdk.c b/block/vmdk.c
21
diff --git a/include/qemu/bitops.h b/include/qemu/bitops.h
23
index XXXXXXX..XXXXXXX 100644
22
index XXXXXXX..XXXXXXX 100644
24
--- a/block/vmdk.c
23
--- a/include/qemu/bitops.h
25
+++ b/block/vmdk.c
24
+++ b/include/qemu/bitops.h
26
@@ -XXX,XX +XXX,XX @@ static int vmdk_add_extent(BlockDriverState *bs,
25
@@ -XXX,XX +XXX,XX @@ static inline int test_bit(long nr, const unsigned long *addr)
27
error_setg(errp, "Invalid granularity, image may be corrupt");
26
* @addr: The address to start the search at
28
return -EFBIG;
27
* @size: The maximum size to search
29
}
28
*
30
- if (l1_size > 512 * 1024 * 1024) {
29
- * Returns the bit number of the first set bit, or size.
31
+ if (l1_size > 32 * 1024 * 1024) {
30
+ * Returns the bit number of the last set bit,
32
/*
31
+ * or @size if there is no set bit in the bitmap.
33
* Although with big capacity and small l1_entry_sectors, we can get a
32
*/
34
* big l1_size, we don't want unbounded value to allocate the table.
33
unsigned long find_last_bit(const unsigned long *addr,
35
- * Limit it to 512M, which is:
34
unsigned long size);
36
- * 16PB - for default "Hosted Sparse Extent" (VMDK4)
35
@@ -XXX,XX +XXX,XX @@ unsigned long find_last_bit(const unsigned long *addr,
37
- * cluster size: 64KB, L2 table size: 512 entries
36
* @addr: The address to base the search on
38
- * 1PB - for default "ESXi Host Sparse Extent" (VMDK3/vmfsSparse)
37
* @offset: The bitnumber to start searching at
39
- * cluster size: 512B, L2 table size: 4096 entries
38
* @size: The bitmap size in bits
40
+ * Limit it to 32M, which is enough to store:
39
+ *
41
+ * 8TB - for both VMDK3 & VMDK4 with
40
+ * Returns the bit number of the next set bit,
42
+ * minimal cluster size: 512B
41
+ * or @size if there are no further set bits in the bitmap.
43
+ * minimal L2 table size: 512 entries
42
*/
44
+ * 8 TB is still more than the maximal value supported for
43
unsigned long find_next_bit(const unsigned long *addr,
45
+ * VMDK3 & VMDK4 which is 2TB.
44
unsigned long size,
46
*/
45
@@ -XXX,XX +XXX,XX @@ unsigned long find_next_bit(const unsigned long *addr,
47
error_setg(errp, "L1 size too big");
46
* @addr: The address to base the search on
48
return -EFBIG;
47
* @offset: The bitnumber to start searching at
49
diff --git a/tests/qemu-iotests/059.out b/tests/qemu-iotests/059.out
48
* @size: The bitmap size in bits
50
index XXXXXXX..XXXXXXX 100644
49
+ *
51
--- a/tests/qemu-iotests/059.out
50
+ * Returns the bit number of the next cleared bit,
52
+++ b/tests/qemu-iotests/059.out
51
+ * or @size if there are no further clear bits in the bitmap.
53
@@ -XXX,XX +XXX,XX @@ Offset Length Mapped to File
52
*/
54
0x140000000 0x10000 0x50000 TEST_DIR/t-s003.vmdk
53
55
54
unsigned long find_next_zero_bit(const unsigned long *addr,
56
=== Testing afl image with a very large capacity ===
55
@@ -XXX,XX +XXX,XX @@ unsigned long find_next_zero_bit(const unsigned long *addr,
57
-qemu-img: Can't get image size 'TEST_DIR/afl9.IMGFMT': File too large
56
* @addr: The address to start the search at
58
+qemu-img: Could not open 'TEST_DIR/afl9.IMGFMT': L1 size too big
57
* @size: The maximum size to search
59
*** done
58
*
59
- * Returns the bit number of the first set bit.
60
+ * Returns the bit number of the first set bit,
61
+ * or @size if there is no set bit in the bitmap.
62
*/
63
static inline unsigned long find_first_bit(const unsigned long *addr,
64
unsigned long size)
65
@@ -XXX,XX +XXX,XX @@ static inline unsigned long find_first_bit(const unsigned long *addr,
66
* @addr: The address to start the search at
67
* @size: The maximum size to search
68
*
69
- * Returns the bit number of the first cleared bit.
70
+ * Returns the bit number of the first cleared bit,
71
+ * or @size if there is no clear bit in the bitmap.
72
*/
73
static inline unsigned long find_first_zero_bit(const unsigned long *addr,
74
unsigned long size)
60
--
75
--
61
2.21.0
76
2.31.1
62
77
63
diff view generated by jsdifflib
1
From: Sam Eiderman <shmuel.eiderman@oracle.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
Commit b0651b8c246d ("vmdk: Move l1_size check into vmdk_add_extent")
3
The lifetime of the timer is well-known (it cannot outlive
4
extended the l1_size check from VMDK4 to VMDK3 but did not update the
4
qemu_co_sleep_ns_wakeable, because it's deleted by the time the
5
default coverage in the moved comment.
5
coroutine resumes), so it is not necessary to place it on the heap.
6
6
7
The previous vmdk4 calculation:
7
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
8
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
9
Message-id: 20210517100548.28806-2-pbonzini@redhat.com
10
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
11
---
12
util/qemu-coroutine-sleep.c | 9 ++++-----
13
1 file changed, 4 insertions(+), 5 deletions(-)
8
14
9
(512 * 1024 * 1024) * 512(l2 entries) * 65536(grain) = 16PB
15
diff --git a/util/qemu-coroutine-sleep.c b/util/qemu-coroutine-sleep.c
16
index XXXXXXX..XXXXXXX 100644
17
--- a/util/qemu-coroutine-sleep.c
18
+++ b/util/qemu-coroutine-sleep.c
19
@@ -XXX,XX +XXX,XX @@ static const char *qemu_co_sleep_ns__scheduled = "qemu_co_sleep_ns";
20
21
struct QemuCoSleepState {
22
Coroutine *co;
23
- QEMUTimer *ts;
24
+ QEMUTimer ts;
25
QemuCoSleepState **user_state_pointer;
26
};
27
28
@@ -XXX,XX +XXX,XX @@ void qemu_co_sleep_wake(QemuCoSleepState *sleep_state)
29
if (sleep_state->user_state_pointer) {
30
*sleep_state->user_state_pointer = NULL;
31
}
32
- timer_del(sleep_state->ts);
33
+ timer_del(&sleep_state->ts);
34
aio_co_wake(sleep_state->co);
35
}
36
37
@@ -XXX,XX +XXX,XX @@ void coroutine_fn qemu_co_sleep_ns_wakeable(QEMUClockType type, int64_t ns,
38
AioContext *ctx = qemu_get_current_aio_context();
39
QemuCoSleepState state = {
40
.co = qemu_coroutine_self(),
41
- .ts = aio_timer_new(ctx, type, SCALE_NS, co_sleep_cb, &state),
42
.user_state_pointer = sleep_state,
43
};
44
45
@@ -XXX,XX +XXX,XX @@ void coroutine_fn qemu_co_sleep_ns_wakeable(QEMUClockType type, int64_t ns,
46
abort();
47
}
48
49
+ aio_timer_init(ctx, &state.ts, type, SCALE_NS, co_sleep_cb, &state);
50
if (sleep_state) {
51
*sleep_state = &state;
52
}
53
- timer_mod(state.ts, qemu_clock_get_ns(type) + ns);
54
+ timer_mod(&state.ts, qemu_clock_get_ns(type) + ns);
55
qemu_coroutine_yield();
56
if (sleep_state) {
57
/*
58
@@ -XXX,XX +XXX,XX @@ void coroutine_fn qemu_co_sleep_ns_wakeable(QEMUClockType type, int64_t ns,
59
*/
60
assert(*sleep_state == NULL);
61
}
62
- timer_free(state.ts);
63
}
64
--
65
2.31.1
10
66
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>
30
---
31
block/vmdk.c | 11 ++++++++---
32
1 file changed, 8 insertions(+), 3 deletions(-)
33
34
diff --git a/block/vmdk.c b/block/vmdk.c
35
index XXXXXXX..XXXXXXX 100644
36
--- a/block/vmdk.c
37
+++ b/block/vmdk.c
38
@@ -XXX,XX +XXX,XX @@ static int vmdk_add_extent(BlockDriverState *bs,
39
return -EFBIG;
40
}
41
if (l1_size > 512 * 1024 * 1024) {
42
- /* Although with big capacity and small l1_entry_sectors, we can get a
43
+ /*
44
+ * Although with big capacity and small l1_entry_sectors, we can get a
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;
56
}
57
--
58
2.21.0
59
60
diff view generated by jsdifflib
1
From: Anton Nefedov <anton.nefedov@virtuozzo.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
COW (even empty/zero) areas require encryption too
3
Simplify the code by removing conditionals. qemu_co_sleep_ns
4
can simply point the argument to an on-stack temporary.
4
5
5
Signed-off-by: Anton Nefedov <anton.nefedov@virtuozzo.com>
6
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
7
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
8
Message-id: 20210517100548.28806-3-pbonzini@redhat.com
8
Reviewed-by: Alberto Garcia <berto@igalia.com>
9
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
9
Message-id: 20190516143028.81155-1-anton.nefedov@virtuozzo.com
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
---
10
---
12
tests/qemu-iotests/134 | 9 +++++++++
11
include/qemu/coroutine.h | 5 +++--
13
tests/qemu-iotests/134.out | 10 ++++++++++
12
util/qemu-coroutine-sleep.c | 18 +++++-------------
14
2 files changed, 19 insertions(+)
13
2 files changed, 8 insertions(+), 15 deletions(-)
15
14
16
diff --git a/tests/qemu-iotests/134 b/tests/qemu-iotests/134
15
diff --git a/include/qemu/coroutine.h b/include/qemu/coroutine.h
17
index XXXXXXX..XXXXXXX 100755
16
index XXXXXXX..XXXXXXX 100644
18
--- a/tests/qemu-iotests/134
17
--- a/include/qemu/coroutine.h
19
+++ b/tests/qemu-iotests/134
18
+++ b/include/qemu/coroutine.h
20
@@ -XXX,XX +XXX,XX @@ echo
19
@@ -XXX,XX +XXX,XX @@ typedef struct QemuCoSleepState QemuCoSleepState;
21
echo "== reading whole image =="
20
22
$QEMU_IO --object $SECRET -c "read 0 $size" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir
21
/**
23
22
* Yield the coroutine for a given duration. During this yield, @sleep_state
24
+echo
23
- * (if not NULL) is set to an opaque pointer, which may be used for
25
+echo "== rewriting cluster part =="
24
+ * is set to an opaque pointer, which may be used for
26
+$QEMU_IO --object $SECRET -c "write -P 0xb 512 512" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir
25
* qemu_co_sleep_wake(). Be careful, the pointer is set back to zero when the
26
* timer fires. Don't save the obtained value to other variables and don't call
27
* qemu_co_sleep_wake from another aio context.
28
@@ -XXX,XX +XXX,XX @@ void coroutine_fn qemu_co_sleep_ns_wakeable(QEMUClockType type, int64_t ns,
29
QemuCoSleepState **sleep_state);
30
static inline void coroutine_fn qemu_co_sleep_ns(QEMUClockType type, int64_t ns)
31
{
32
- qemu_co_sleep_ns_wakeable(type, ns, NULL);
33
+ QemuCoSleepState *unused = NULL;
34
+ qemu_co_sleep_ns_wakeable(type, ns, &unused);
35
}
36
37
/**
38
diff --git a/util/qemu-coroutine-sleep.c b/util/qemu-coroutine-sleep.c
39
index XXXXXXX..XXXXXXX 100644
40
--- a/util/qemu-coroutine-sleep.c
41
+++ b/util/qemu-coroutine-sleep.c
42
@@ -XXX,XX +XXX,XX @@ void qemu_co_sleep_wake(QemuCoSleepState *sleep_state)
43
qemu_co_sleep_ns__scheduled, NULL);
44
45
assert(scheduled == qemu_co_sleep_ns__scheduled);
46
- if (sleep_state->user_state_pointer) {
47
- *sleep_state->user_state_pointer = NULL;
48
- }
49
+ *sleep_state->user_state_pointer = NULL;
50
timer_del(&sleep_state->ts);
51
aio_co_wake(sleep_state->co);
52
}
53
@@ -XXX,XX +XXX,XX @@ void coroutine_fn qemu_co_sleep_ns_wakeable(QEMUClockType type, int64_t ns,
54
}
55
56
aio_timer_init(ctx, &state.ts, type, SCALE_NS, co_sleep_cb, &state);
57
- if (sleep_state) {
58
- *sleep_state = &state;
59
- }
60
+ *sleep_state = &state;
61
timer_mod(&state.ts, qemu_clock_get_ns(type) + ns);
62
qemu_coroutine_yield();
63
- if (sleep_state) {
64
- /*
65
- * Note that *sleep_state is cleared during qemu_co_sleep_wake
66
- * before resuming this coroutine.
67
- */
68
- assert(*sleep_state == NULL);
69
- }
27
+
70
+
28
+echo
71
+ /* qemu_co_sleep_wake clears *sleep_state before resuming this coroutine. */
29
+echo "== verify pattern =="
72
+ assert(*sleep_state == NULL);
30
+$QEMU_IO --object $SECRET -c "read -P 0 0 512" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir
73
}
31
+$QEMU_IO --object $SECRET -c "read -P 0xb 512 512" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir
32
+
33
echo
34
echo "== rewriting whole image =="
35
$QEMU_IO --object $SECRET -c "write -P 0xa 0 $size" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir
36
diff --git a/tests/qemu-iotests/134.out b/tests/qemu-iotests/134.out
37
index XXXXXXX..XXXXXXX 100644
38
--- a/tests/qemu-iotests/134.out
39
+++ b/tests/qemu-iotests/134.out
40
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encryption=on encrypt.
41
read 134217728/134217728 bytes at offset 0
42
128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
43
44
+== rewriting cluster part ==
45
+wrote 512/512 bytes at offset 512
46
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
47
+
48
+== verify pattern ==
49
+read 512/512 bytes at offset 0
50
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
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)
57
--
74
--
58
2.21.0
75
2.31.1
59
76
60
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
We forget to enable it for transaction .prepare, while it is already
3
All callers of qemu_co_sleep_wake are checking whether they are passing
4
enabled in do_drive_backup since commit a2d665c1bc362
4
a NULL argument inside the pointer-to-pointer: do the check in
5
"blockdev: loosen restrictions on drive-backup source node"
5
qemu_co_sleep_wake itself.
6
6
7
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
As a side effect, qemu_co_sleep_wake can be called more than once and
8
Message-id: 20190618140804.59214-1-vsementsov@virtuozzo.com
8
it will only wake the coroutine once; after the first time, the argument
9
Reviewed-by: John Snow <jsnow@redhat.com>
9
will be set to NULL via *sleep_state->user_state_pointer. However, this
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
would not be safe unless co_sleep_cb keeps using the QemuCoSleepState*
11
directly, so make it go through the pointer-to-pointer instead.
12
13
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
14
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
15
Message-id: 20210517100548.28806-4-pbonzini@redhat.com
16
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
11
---
17
---
12
blockdev.c | 2 +-
18
block/block-copy.c | 4 +---
13
1 file changed, 1 insertion(+), 1 deletion(-)
19
block/nbd.c | 8 ++------
20
util/qemu-coroutine-sleep.c | 21 ++++++++++++---------
21
3 files changed, 15 insertions(+), 18 deletions(-)
14
22
15
diff --git a/blockdev.c b/blockdev.c
23
diff --git a/block/block-copy.c b/block/block-copy.c
16
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX 100644
17
--- a/blockdev.c
25
--- a/block/block-copy.c
18
+++ b/blockdev.c
26
+++ b/block/block-copy.c
19
@@ -XXX,XX +XXX,XX @@ static void drive_backup_prepare(BlkActionState *common, Error **errp)
27
@@ -XXX,XX +XXX,XX @@ out:
20
assert(common->action->type == TRANSACTION_ACTION_KIND_DRIVE_BACKUP);
28
21
backup = common->action->u.drive_backup.data;
29
void block_copy_kick(BlockCopyCallState *call_state)
22
30
{
23
- bs = qmp_get_root_bs(backup->device, errp);
31
- if (call_state->sleep_state) {
24
+ bs = bdrv_lookup_bs(backup->device, backup->device, errp);
32
- qemu_co_sleep_wake(call_state->sleep_state);
25
if (!bs) {
33
- }
26
return;
34
+ qemu_co_sleep_wake(call_state->sleep_state);
35
}
36
37
/*
38
diff --git a/block/nbd.c b/block/nbd.c
39
index XXXXXXX..XXXXXXX 100644
40
--- a/block/nbd.c
41
+++ b/block/nbd.c
42
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn nbd_client_co_drain_begin(BlockDriverState *bs)
43
BDRVNBDState *s = (BDRVNBDState *)bs->opaque;
44
45
s->drained = true;
46
- if (s->connection_co_sleep_ns_state) {
47
- qemu_co_sleep_wake(s->connection_co_sleep_ns_state);
48
- }
49
+ qemu_co_sleep_wake(s->connection_co_sleep_ns_state);
50
51
nbd_co_establish_connection_cancel(bs, false);
52
53
@@ -XXX,XX +XXX,XX @@ static void nbd_teardown_connection(BlockDriverState *bs)
54
55
s->state = NBD_CLIENT_QUIT;
56
if (s->connection_co) {
57
- if (s->connection_co_sleep_ns_state) {
58
- qemu_co_sleep_wake(s->connection_co_sleep_ns_state);
59
- }
60
+ qemu_co_sleep_wake(s->connection_co_sleep_ns_state);
61
nbd_co_establish_connection_cancel(bs, true);
27
}
62
}
63
if (qemu_in_coroutine()) {
64
diff --git a/util/qemu-coroutine-sleep.c b/util/qemu-coroutine-sleep.c
65
index XXXXXXX..XXXXXXX 100644
66
--- a/util/qemu-coroutine-sleep.c
67
+++ b/util/qemu-coroutine-sleep.c
68
@@ -XXX,XX +XXX,XX @@ struct QemuCoSleepState {
69
70
void qemu_co_sleep_wake(QemuCoSleepState *sleep_state)
71
{
72
- /* Write of schedule protected by barrier write in aio_co_schedule */
73
- const char *scheduled = qatomic_cmpxchg(&sleep_state->co->scheduled,
74
- qemu_co_sleep_ns__scheduled, NULL);
75
+ if (sleep_state) {
76
+ /* Write of schedule protected by barrier write in aio_co_schedule */
77
+ const char *scheduled = qatomic_cmpxchg(&sleep_state->co->scheduled,
78
+ qemu_co_sleep_ns__scheduled, NULL);
79
80
- assert(scheduled == qemu_co_sleep_ns__scheduled);
81
- *sleep_state->user_state_pointer = NULL;
82
- timer_del(&sleep_state->ts);
83
- aio_co_wake(sleep_state->co);
84
+ assert(scheduled == qemu_co_sleep_ns__scheduled);
85
+ *sleep_state->user_state_pointer = NULL;
86
+ timer_del(&sleep_state->ts);
87
+ aio_co_wake(sleep_state->co);
88
+ }
89
}
90
91
static void co_sleep_cb(void *opaque)
92
{
93
- qemu_co_sleep_wake(opaque);
94
+ QemuCoSleepState **sleep_state = opaque;
95
+ qemu_co_sleep_wake(*sleep_state);
96
}
97
98
void coroutine_fn qemu_co_sleep_ns_wakeable(QEMUClockType type, int64_t ns,
99
@@ -XXX,XX +XXX,XX @@ void coroutine_fn qemu_co_sleep_ns_wakeable(QEMUClockType type, int64_t ns,
100
abort();
101
}
102
103
- aio_timer_init(ctx, &state.ts, type, SCALE_NS, co_sleep_cb, &state);
104
+ aio_timer_init(ctx, &state.ts, type, SCALE_NS, co_sleep_cb, sleep_state);
105
*sleep_state = &state;
106
timer_mod(&state.ts, qemu_clock_get_ns(type) + ns);
107
qemu_coroutine_yield();
28
--
108
--
29
2.21.0
109
2.31.1
30
110
31
diff view generated by jsdifflib
1
From: Pino Toscano <ptoscano@redhat.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
Rewrite the implementation of the ssh block driver to use libssh instead
3
This simplification is enabled by the previous patch. Now aio_co_wake
4
of libssh2. The libssh library has various advantages over libssh2:
4
will only be called once, therefore we do not care about a spurious
5
- easier API for authentication (for example for using ssh-agent)
5
firing of the timer after a qemu_co_sleep_wake.
6
- easier API for known_hosts handling
7
- supports newer types of keys in known_hosts
8
6
9
Use APIs/features available in libssh 0.8 conditionally, to support
7
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
10
older versions (which are not recommended though).
8
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
9
Message-id: 20210517100548.28806-5-pbonzini@redhat.com
10
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
11
---
12
util/qemu-coroutine-sleep.c | 8 ++++----
13
1 file changed, 4 insertions(+), 4 deletions(-)
11
14
12
Adjust the iotest 207 according to the different error message, and to
15
diff --git a/util/qemu-coroutine-sleep.c b/util/qemu-coroutine-sleep.c
13
find the default key type for localhost (to properly compare the
14
fingerprint with).
15
Contributed-by: Max Reitz <mreitz@redhat.com>
16
17
Adjust the various Docker/Travis scripts to use libssh when available
18
instead of libssh2. The mingw/mxe testing is dropped for now, as there
19
are no packages for it.
20
21
Signed-off-by: Pino Toscano <ptoscano@redhat.com>
22
Tested-by: Philippe Mathieu-Daudé <philmd@redhat.com>
23
Acked-by: Alex Bennée <alex.bennee@linaro.org>
24
Message-id: 20190620200840.17655-1-ptoscano@redhat.com
25
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
26
Signed-off-by: Max Reitz <mreitz@redhat.com>
27
---
28
configure | 65 +-
29
block/Makefile.objs | 6 +-
30
block/ssh.c | 673 ++++++++++--------
31
.travis.yml | 4 +-
32
block/trace-events | 14 +-
33
docs/qemu-block-drivers.texi | 2 +-
34
.../dockerfiles/debian-win32-cross.docker | 1 -
35
.../dockerfiles/debian-win64-cross.docker | 1 -
36
tests/docker/dockerfiles/fedora.docker | 4 +-
37
tests/docker/dockerfiles/ubuntu.docker | 2 +-
38
tests/docker/dockerfiles/ubuntu1804.docker | 2 +-
39
tests/qemu-iotests/207 | 54 +-
40
tests/qemu-iotests/207.out | 2 +-
41
13 files changed, 470 insertions(+), 360 deletions(-)
42
43
diff --git a/configure b/configure
44
index XXXXXXX..XXXXXXX 100755
45
--- a/configure
46
+++ b/configure
47
@@ -XXX,XX +XXX,XX @@ auth_pam=""
48
vte=""
49
virglrenderer=""
50
tpm=""
51
-libssh2=""
52
+libssh=""
53
live_block_migration="yes"
54
numa=""
55
tcmalloc="no"
56
@@ -XXX,XX +XXX,XX @@ for opt do
57
;;
58
--enable-tpm) tpm="yes"
59
;;
60
- --disable-libssh2) libssh2="no"
61
+ --disable-libssh) libssh="no"
62
;;
63
- --enable-libssh2) libssh2="yes"
64
+ --enable-libssh) libssh="yes"
65
;;
66
--disable-live-block-migration) live_block_migration="no"
67
;;
68
@@ -XXX,XX +XXX,XX @@ disabled with --disable-FEATURE, default is enabled if available:
69
coroutine-pool coroutine freelist (better performance)
70
glusterfs GlusterFS backend
71
tpm TPM support
72
- libssh2 ssh block device support
73
+ libssh ssh block device support
74
numa libnuma support
75
libxml2 for Parallels image format
76
tcmalloc tcmalloc support
77
@@ -XXX,XX +XXX,XX @@ EOF
78
fi
79
80
##########################################
81
-# libssh2 probe
82
-min_libssh2_version=1.2.8
83
-if test "$libssh2" != "no" ; then
84
- if $pkg_config --atleast-version=$min_libssh2_version libssh2; then
85
- libssh2_cflags=$($pkg_config libssh2 --cflags)
86
- libssh2_libs=$($pkg_config libssh2 --libs)
87
- libssh2=yes
88
+# libssh probe
89
+if test "$libssh" != "no" ; then
90
+ if $pkg_config --exists libssh; then
91
+ libssh_cflags=$($pkg_config libssh --cflags)
92
+ libssh_libs=$($pkg_config libssh --libs)
93
+ libssh=yes
94
else
95
- if test "$libssh2" = "yes" ; then
96
- error_exit "libssh2 >= $min_libssh2_version required for --enable-libssh2"
97
+ if test "$libssh" = "yes" ; then
98
+ error_exit "libssh required for --enable-libssh"
99
fi
100
- libssh2=no
101
+ libssh=no
102
fi
103
fi
104
105
##########################################
106
-# libssh2_sftp_fsync probe
107
+# Check for libssh 0.8
108
+# This is done like this instead of using the LIBSSH_VERSION_* and
109
+# SSH_VERSION_* macros because some distributions in the past shipped
110
+# snapshots of the future 0.8 from Git, and those snapshots did not
111
+# have updated version numbers (still referring to 0.7.0).
112
113
-if test "$libssh2" = "yes"; then
114
+if test "$libssh" = "yes"; then
115
cat > $TMPC <<EOF
116
-#include <stdio.h>
117
-#include <libssh2.h>
118
-#include <libssh2_sftp.h>
119
-int main(void) {
120
- LIBSSH2_SESSION *session;
121
- LIBSSH2_SFTP *sftp;
122
- LIBSSH2_SFTP_HANDLE *sftp_handle;
123
- session = libssh2_session_init ();
124
- sftp = libssh2_sftp_init (session);
125
- sftp_handle = libssh2_sftp_open (sftp, "/", 0, 0);
126
- libssh2_sftp_fsync (sftp_handle);
127
- return 0;
128
-}
129
+#include <libssh/libssh.h>
130
+int main(void) { return ssh_get_server_publickey(NULL, NULL); }
131
EOF
132
- # libssh2_cflags/libssh2_libs defined in previous test.
133
- if compile_prog "$libssh2_cflags" "$libssh2_libs" ; then
134
- QEMU_CFLAGS="-DHAS_LIBSSH2_SFTP_FSYNC $QEMU_CFLAGS"
135
+ if compile_prog "$libssh_cflags" "$libssh_libs"; then
136
+ libssh_cflags="-DHAVE_LIBSSH_0_8 $libssh_cflags"
137
fi
138
fi
139
140
@@ -XXX,XX +XXX,XX @@ echo "GlusterFS support $glusterfs"
141
echo "gcov $gcov_tool"
142
echo "gcov enabled $gcov"
143
echo "TPM support $tpm"
144
-echo "libssh2 support $libssh2"
145
+echo "libssh support $libssh"
146
echo "QOM debugging $qom_cast_debug"
147
echo "Live block migration $live_block_migration"
148
echo "lzo support $lzo"
149
@@ -XXX,XX +XXX,XX @@ if test "$glusterfs_iocb_has_stat" = "yes" ; then
150
echo "CONFIG_GLUSTERFS_IOCB_HAS_STAT=y" >> $config_host_mak
151
fi
152
153
-if test "$libssh2" = "yes" ; then
154
- echo "CONFIG_LIBSSH2=m" >> $config_host_mak
155
- echo "LIBSSH2_CFLAGS=$libssh2_cflags" >> $config_host_mak
156
- echo "LIBSSH2_LIBS=$libssh2_libs" >> $config_host_mak
157
+if test "$libssh" = "yes" ; then
158
+ echo "CONFIG_LIBSSH=m" >> $config_host_mak
159
+ echo "LIBSSH_CFLAGS=$libssh_cflags" >> $config_host_mak
160
+ echo "LIBSSH_LIBS=$libssh_libs" >> $config_host_mak
161
fi
162
163
if test "$live_block_migration" = "yes" ; then
164
diff --git a/block/Makefile.objs b/block/Makefile.objs
165
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
166
--- a/block/Makefile.objs
17
--- a/util/qemu-coroutine-sleep.c
167
+++ b/block/Makefile.objs
18
+++ b/util/qemu-coroutine-sleep.c
168
@@ -XXX,XX +XXX,XX @@ block-obj-$(CONFIG_CURL) += curl.o
19
@@ -XXX,XX +XXX,XX @@ static const char *qemu_co_sleep_ns__scheduled = "qemu_co_sleep_ns";
169
block-obj-$(CONFIG_RBD) += rbd.o
20
170
block-obj-$(CONFIG_GLUSTERFS) += gluster.o
21
struct QemuCoSleepState {
171
block-obj-$(CONFIG_VXHS) += vxhs.o
22
Coroutine *co;
172
-block-obj-$(CONFIG_LIBSSH2) += ssh.o
23
- QEMUTimer ts;
173
+block-obj-$(CONFIG_LIBSSH) += ssh.o
24
QemuCoSleepState **user_state_pointer;
174
block-obj-y += accounting.o dirty-bitmap.o
25
};
175
block-obj-y += write-threshold.o
26
176
block-obj-y += backup.o
27
@@ -XXX,XX +XXX,XX @@ void qemu_co_sleep_wake(QemuCoSleepState *sleep_state)
177
@@ -XXX,XX +XXX,XX @@ rbd.o-libs := $(RBD_LIBS)
28
178
gluster.o-cflags := $(GLUSTERFS_CFLAGS)
29
assert(scheduled == qemu_co_sleep_ns__scheduled);
179
gluster.o-libs := $(GLUSTERFS_LIBS)
30
*sleep_state->user_state_pointer = NULL;
180
vxhs.o-libs := $(VXHS_LIBS)
31
- timer_del(&sleep_state->ts);
181
-ssh.o-cflags := $(LIBSSH2_CFLAGS)
32
aio_co_wake(sleep_state->co);
182
-ssh.o-libs := $(LIBSSH2_LIBS)
183
+ssh.o-cflags := $(LIBSSH_CFLAGS)
184
+ssh.o-libs := $(LIBSSH_LIBS)
185
block-obj-dmg-bz2-$(CONFIG_BZIP2) += dmg-bz2.o
186
block-obj-$(if $(CONFIG_DMG),m,n) += $(block-obj-dmg-bz2-y)
187
dmg-bz2.o-libs := $(BZIP2_LIBS)
188
diff --git a/block/ssh.c b/block/ssh.c
189
index XXXXXXX..XXXXXXX 100644
190
--- a/block/ssh.c
191
+++ b/block/ssh.c
192
@@ -XXX,XX +XXX,XX @@
193
194
#include "qemu/osdep.h"
195
196
-#include <libssh2.h>
197
-#include <libssh2_sftp.h>
198
+#include <libssh/libssh.h>
199
+#include <libssh/sftp.h>
200
201
#include "block/block_int.h"
202
#include "block/qdict.h"
203
@@ -XXX,XX +XXX,XX @@
204
#include "trace.h"
205
206
/*
207
- * TRACE_LIBSSH2=<bitmask> enables tracing in libssh2 itself. Note
208
- * that this requires that libssh2 was specially compiled with the
209
- * `./configure --enable-debug' option, so most likely you will have
210
- * to compile it yourself. The meaning of <bitmask> is described
211
- * here: http://www.libssh2.org/libssh2_trace.html
212
+ * TRACE_LIBSSH=<level> enables tracing in libssh itself.
213
+ * The meaning of <level> is described here:
214
+ * http://api.libssh.org/master/group__libssh__log.html
215
*/
216
-#define TRACE_LIBSSH2 0 /* or try: LIBSSH2_TRACE_SFTP */
217
+#define TRACE_LIBSSH 0 /* see: SSH_LOG_* */
218
219
typedef struct BDRVSSHState {
220
/* Coroutine. */
221
@@ -XXX,XX +XXX,XX @@ typedef struct BDRVSSHState {
222
223
/* SSH connection. */
224
int sock; /* socket */
225
- LIBSSH2_SESSION *session; /* ssh session */
226
- LIBSSH2_SFTP *sftp; /* sftp session */
227
- LIBSSH2_SFTP_HANDLE *sftp_handle; /* sftp remote file handle */
228
+ ssh_session session; /* ssh session */
229
+ sftp_session sftp; /* sftp session */
230
+ sftp_file sftp_handle; /* sftp remote file handle */
231
232
- /* See ssh_seek() function below. */
233
- int64_t offset;
234
- bool offset_op_read;
235
-
236
- /* File attributes at open. We try to keep the .filesize field
237
+ /*
238
+ * File attributes at open. We try to keep the .size field
239
* updated if it changes (eg by writing at the end of the file).
240
*/
241
- LIBSSH2_SFTP_ATTRIBUTES attrs;
242
+ sftp_attributes attrs;
243
244
InetSocketAddress *inet;
245
246
@@ -XXX,XX +XXX,XX @@ static void ssh_state_init(BDRVSSHState *s)
247
{
248
memset(s, 0, sizeof *s);
249
s->sock = -1;
250
- s->offset = -1;
251
qemu_co_mutex_init(&s->lock);
252
}
253
254
@@ -XXX,XX +XXX,XX @@ static void ssh_state_free(BDRVSSHState *s)
255
{
256
g_free(s->user);
257
258
+ if (s->attrs) {
259
+ sftp_attributes_free(s->attrs);
260
+ }
261
if (s->sftp_handle) {
262
- libssh2_sftp_close(s->sftp_handle);
263
+ sftp_close(s->sftp_handle);
264
}
265
if (s->sftp) {
266
- libssh2_sftp_shutdown(s->sftp);
267
+ sftp_free(s->sftp);
268
}
269
if (s->session) {
270
- libssh2_session_disconnect(s->session,
271
- "from qemu ssh client: "
272
- "user closed the connection");
273
- libssh2_session_free(s->session);
274
- }
275
- if (s->sock >= 0) {
276
- close(s->sock);
277
+ ssh_disconnect(s->session);
278
+ ssh_free(s->session); /* This frees s->sock */
279
}
33
}
280
}
34
}
281
35
@@ -XXX,XX +XXX,XX @@ void coroutine_fn qemu_co_sleep_ns_wakeable(QEMUClockType type, int64_t ns,
282
@@ -XXX,XX +XXX,XX @@ session_error_setg(Error **errp, BDRVSSHState *s, const char *fs, ...)
36
QemuCoSleepState **sleep_state)
283
va_end(args);
284
285
if (s->session) {
286
- char *ssh_err;
287
+ const char *ssh_err;
288
int ssh_err_code;
289
290
- /* This is not an errno. See <libssh2.h>. */
291
- ssh_err_code = libssh2_session_last_error(s->session,
292
- &ssh_err, NULL, 0);
293
- error_setg(errp, "%s: %s (libssh2 error code: %d)",
294
+ /* This is not an errno. See <libssh/libssh.h>. */
295
+ ssh_err = ssh_get_error(s->session);
296
+ ssh_err_code = ssh_get_error_code(s->session);
297
+ error_setg(errp, "%s: %s (libssh error code: %d)",
298
msg, ssh_err, ssh_err_code);
299
} else {
300
error_setg(errp, "%s", msg);
301
@@ -XXX,XX +XXX,XX @@ sftp_error_setg(Error **errp, BDRVSSHState *s, const char *fs, ...)
302
va_end(args);
303
304
if (s->sftp) {
305
- char *ssh_err;
306
+ const char *ssh_err;
307
int ssh_err_code;
308
- unsigned long sftp_err_code;
309
+ int sftp_err_code;
310
311
- /* This is not an errno. See <libssh2.h>. */
312
- ssh_err_code = libssh2_session_last_error(s->session,
313
- &ssh_err, NULL, 0);
314
- /* See <libssh2_sftp.h>. */
315
- sftp_err_code = libssh2_sftp_last_error((s)->sftp);
316
+ /* This is not an errno. See <libssh/libssh.h>. */
317
+ ssh_err = ssh_get_error(s->session);
318
+ ssh_err_code = ssh_get_error_code(s->session);
319
+ /* See <libssh/sftp.h>. */
320
+ sftp_err_code = sftp_get_error(s->sftp);
321
322
error_setg(errp,
323
- "%s: %s (libssh2 error code: %d, sftp error code: %lu)",
324
+ "%s: %s (libssh error code: %d, sftp error code: %d)",
325
msg, ssh_err, ssh_err_code, sftp_err_code);
326
} else {
327
error_setg(errp, "%s", msg);
328
@@ -XXX,XX +XXX,XX @@ sftp_error_setg(Error **errp, BDRVSSHState *s, const char *fs, ...)
329
330
static void sftp_error_trace(BDRVSSHState *s, const char *op)
331
{
37
{
332
- char *ssh_err;
38
AioContext *ctx = qemu_get_current_aio_context();
333
+ const char *ssh_err;
39
+ QEMUTimer ts;
334
int ssh_err_code;
40
QemuCoSleepState state = {
335
- unsigned long sftp_err_code;
41
.co = qemu_coroutine_self(),
336
+ int sftp_err_code;
42
.user_state_pointer = sleep_state,
337
43
@@ -XXX,XX +XXX,XX @@ void coroutine_fn qemu_co_sleep_ns_wakeable(QEMUClockType type, int64_t ns,
338
- /* This is not an errno. See <libssh2.h>. */
44
abort();
339
- ssh_err_code = libssh2_session_last_error(s->session,
340
- &ssh_err, NULL, 0);
341
- /* See <libssh2_sftp.h>. */
342
- sftp_err_code = libssh2_sftp_last_error((s)->sftp);
343
+ /* This is not an errno. See <libssh/libssh.h>. */
344
+ ssh_err = ssh_get_error(s->session);
345
+ ssh_err_code = ssh_get_error_code(s->session);
346
+ /* See <libssh/sftp.h>. */
347
+ sftp_err_code = sftp_get_error(s->sftp);
348
349
trace_sftp_error(op, ssh_err, ssh_err_code, sftp_err_code);
350
}
351
@@ -XXX,XX +XXX,XX @@ static void ssh_parse_filename(const char *filename, QDict *options,
352
parse_uri(filename, options, errp);
353
}
354
355
-static int check_host_key_knownhosts(BDRVSSHState *s,
356
- const char *host, int port, Error **errp)
357
+static int check_host_key_knownhosts(BDRVSSHState *s, Error **errp)
358
{
359
- const char *home;
360
- char *knh_file = NULL;
361
- LIBSSH2_KNOWNHOSTS *knh = NULL;
362
- struct libssh2_knownhost *found;
363
- int ret, r;
364
- const char *hostkey;
365
- size_t len;
366
- int type;
367
-
368
- hostkey = libssh2_session_hostkey(s->session, &len, &type);
369
- if (!hostkey) {
370
+ int ret;
371
+ int r;
372
+ ssh_key pubkey;
373
+ enum ssh_keytypes_e pubkey_type;
374
+ unsigned char *server_hash = NULL;
375
+ size_t server_hash_len;
376
+ char *fingerprint = NULL;
377
+#ifdef HAVE_LIBSSH_0_8
378
+ enum ssh_known_hosts_e state;
379
+
380
+ state = ssh_session_is_known_server(s->session);
381
+ trace_ssh_server_status(state);
382
+
383
+ switch (state) {
384
+ case SSH_KNOWN_HOSTS_OK:
385
+ /* OK */
386
+ trace_ssh_check_host_key_knownhosts();
387
+ break;
388
+ case SSH_KNOWN_HOSTS_CHANGED:
389
ret = -EINVAL;
390
- session_error_setg(errp, s, "failed to read remote host key");
391
+ r = ssh_get_server_publickey(s->session, &pubkey);
392
+ if (r == 0) {
393
+ r = ssh_get_publickey_hash(pubkey, SSH_PUBLICKEY_HASH_SHA256,
394
+ &server_hash, &server_hash_len);
395
+ pubkey_type = ssh_key_type(pubkey);
396
+ ssh_key_free(pubkey);
397
+ }
398
+ if (r == 0) {
399
+ fingerprint = ssh_get_fingerprint_hash(SSH_PUBLICKEY_HASH_SHA256,
400
+ server_hash,
401
+ server_hash_len);
402
+ ssh_clean_pubkey_hash(&server_hash);
403
+ }
404
+ if (fingerprint) {
405
+ error_setg(errp,
406
+ "host key (%s key with fingerprint %s) does not match "
407
+ "the one in known_hosts; this may be a possible attack",
408
+ ssh_key_type_to_char(pubkey_type), fingerprint);
409
+ ssh_string_free_char(fingerprint);
410
+ } else {
411
+ error_setg(errp,
412
+ "host key does not match the one in known_hosts; this "
413
+ "may be a possible attack");
414
+ }
415
goto out;
416
- }
417
-
418
- knh = libssh2_knownhost_init(s->session);
419
- if (!knh) {
420
+ case SSH_KNOWN_HOSTS_OTHER:
421
ret = -EINVAL;
422
- session_error_setg(errp, s,
423
- "failed to initialize known hosts support");
424
+ error_setg(errp,
425
+ "host key for this server not found, another type exists");
426
+ goto out;
427
+ case SSH_KNOWN_HOSTS_UNKNOWN:
428
+ ret = -EINVAL;
429
+ error_setg(errp, "no host key was found in known_hosts");
430
+ goto out;
431
+ case SSH_KNOWN_HOSTS_NOT_FOUND:
432
+ ret = -ENOENT;
433
+ error_setg(errp, "known_hosts file not found");
434
+ goto out;
435
+ case SSH_KNOWN_HOSTS_ERROR:
436
+ ret = -EINVAL;
437
+ error_setg(errp, "error while checking the host");
438
+ goto out;
439
+ default:
440
+ ret = -EINVAL;
441
+ error_setg(errp, "error while checking for known server (%d)", state);
442
goto out;
443
}
45
}
444
+#else /* !HAVE_LIBSSH_0_8 */
46
445
+ int state;
47
- aio_timer_init(ctx, &state.ts, type, SCALE_NS, co_sleep_cb, sleep_state);
446
48
+ aio_timer_init(ctx, &ts, type, SCALE_NS, co_sleep_cb, sleep_state);
447
- home = getenv("HOME");
49
*sleep_state = &state;
448
- if (home) {
50
- timer_mod(&state.ts, qemu_clock_get_ns(type) + ns);
449
- knh_file = g_strdup_printf("%s/.ssh/known_hosts", home);
51
+ timer_mod(&ts, qemu_clock_get_ns(type) + ns);
450
- } else {
52
qemu_coroutine_yield();
451
- knh_file = g_strdup_printf("/root/.ssh/known_hosts");
53
+ timer_del(&ts);
452
- }
54
453
-
55
/* qemu_co_sleep_wake clears *sleep_state before resuming this coroutine. */
454
- /* Read all known hosts from OpenSSH-style known_hosts file. */
56
assert(*sleep_state == NULL);
455
- libssh2_knownhost_readfile(knh, knh_file, LIBSSH2_KNOWNHOST_FILE_OPENSSH);
456
+ state = ssh_is_server_known(s->session);
457
+ trace_ssh_server_status(state);
458
459
- r = libssh2_knownhost_checkp(knh, host, port, hostkey, len,
460
- LIBSSH2_KNOWNHOST_TYPE_PLAIN|
461
- LIBSSH2_KNOWNHOST_KEYENC_RAW,
462
- &found);
463
- switch (r) {
464
- case LIBSSH2_KNOWNHOST_CHECK_MATCH:
465
+ switch (state) {
466
+ case SSH_SERVER_KNOWN_OK:
467
/* OK */
468
- trace_ssh_check_host_key_knownhosts(found->key);
469
+ trace_ssh_check_host_key_knownhosts();
470
break;
471
- case LIBSSH2_KNOWNHOST_CHECK_MISMATCH:
472
+ case SSH_SERVER_KNOWN_CHANGED:
473
ret = -EINVAL;
474
- session_error_setg(errp, s,
475
- "host key does not match the one in known_hosts"
476
- " (found key %s)", found->key);
477
+ r = ssh_get_publickey(s->session, &pubkey);
478
+ if (r == 0) {
479
+ r = ssh_get_publickey_hash(pubkey, SSH_PUBLICKEY_HASH_SHA1,
480
+ &server_hash, &server_hash_len);
481
+ pubkey_type = ssh_key_type(pubkey);
482
+ ssh_key_free(pubkey);
483
+ }
484
+ if (r == 0) {
485
+ fingerprint = ssh_get_fingerprint_hash(SSH_PUBLICKEY_HASH_SHA1,
486
+ server_hash,
487
+ server_hash_len);
488
+ ssh_clean_pubkey_hash(&server_hash);
489
+ }
490
+ if (fingerprint) {
491
+ error_setg(errp,
492
+ "host key (%s key with fingerprint %s) does not match "
493
+ "the one in known_hosts; this may be a possible attack",
494
+ ssh_key_type_to_char(pubkey_type), fingerprint);
495
+ ssh_string_free_char(fingerprint);
496
+ } else {
497
+ error_setg(errp,
498
+ "host key does not match the one in known_hosts; this "
499
+ "may be a possible attack");
500
+ }
501
+ goto out;
502
+ case SSH_SERVER_FOUND_OTHER:
503
+ ret = -EINVAL;
504
+ error_setg(errp,
505
+ "host key for this server not found, another type exists");
506
+ goto out;
507
+ case SSH_SERVER_FILE_NOT_FOUND:
508
+ ret = -ENOENT;
509
+ error_setg(errp, "known_hosts file not found");
510
goto out;
511
- case LIBSSH2_KNOWNHOST_CHECK_NOTFOUND:
512
+ case SSH_SERVER_NOT_KNOWN:
513
ret = -EINVAL;
514
- session_error_setg(errp, s, "no host key was found in known_hosts");
515
+ error_setg(errp, "no host key was found in known_hosts");
516
goto out;
517
- case LIBSSH2_KNOWNHOST_CHECK_FAILURE:
518
+ case SSH_SERVER_ERROR:
519
ret = -EINVAL;
520
- session_error_setg(errp, s,
521
- "failure matching the host key with known_hosts");
522
+ error_setg(errp, "server error");
523
goto out;
524
default:
525
ret = -EINVAL;
526
- session_error_setg(errp, s, "unknown error matching the host key"
527
- " with known_hosts (%d)", r);
528
+ error_setg(errp, "error while checking for known server (%d)", state);
529
goto out;
530
}
531
+#endif /* !HAVE_LIBSSH_0_8 */
532
533
/* known_hosts checking successful. */
534
ret = 0;
535
536
out:
537
- if (knh != NULL) {
538
- libssh2_knownhost_free(knh);
539
- }
540
- g_free(knh_file);
541
return ret;
542
}
543
544
@@ -XXX,XX +XXX,XX @@ static int compare_fingerprint(const unsigned char *fingerprint, size_t len,
545
546
static int
547
check_host_key_hash(BDRVSSHState *s, const char *hash,
548
- int hash_type, size_t fingerprint_len, Error **errp)
549
+ enum ssh_publickey_hash_type type, Error **errp)
550
{
551
- const char *fingerprint;
552
-
553
- fingerprint = libssh2_hostkey_hash(s->session, hash_type);
554
- if (!fingerprint) {
555
+ int r;
556
+ ssh_key pubkey;
557
+ unsigned char *server_hash;
558
+ size_t server_hash_len;
559
+
560
+#ifdef HAVE_LIBSSH_0_8
561
+ r = ssh_get_server_publickey(s->session, &pubkey);
562
+#else
563
+ r = ssh_get_publickey(s->session, &pubkey);
564
+#endif
565
+ if (r != SSH_OK) {
566
session_error_setg(errp, s, "failed to read remote host key");
567
return -EINVAL;
568
}
569
570
- if(compare_fingerprint((unsigned char *) fingerprint, fingerprint_len,
571
- hash) != 0) {
572
+ r = ssh_get_publickey_hash(pubkey, type, &server_hash, &server_hash_len);
573
+ ssh_key_free(pubkey);
574
+ if (r != 0) {
575
+ session_error_setg(errp, s,
576
+ "failed reading the hash of the server SSH key");
577
+ return -EINVAL;
578
+ }
579
+
580
+ r = compare_fingerprint(server_hash, server_hash_len, hash);
581
+ ssh_clean_pubkey_hash(&server_hash);
582
+ if (r != 0) {
583
error_setg(errp, "remote host key does not match host_key_check '%s'",
584
hash);
585
return -EPERM;
586
@@ -XXX,XX +XXX,XX @@ check_host_key_hash(BDRVSSHState *s, const char *hash,
587
return 0;
588
}
589
590
-static int check_host_key(BDRVSSHState *s, const char *host, int port,
591
- SshHostKeyCheck *hkc, Error **errp)
592
+static int check_host_key(BDRVSSHState *s, SshHostKeyCheck *hkc, Error **errp)
593
{
594
SshHostKeyCheckMode mode;
595
596
@@ -XXX,XX +XXX,XX @@ static int check_host_key(BDRVSSHState *s, const char *host, int port,
597
case SSH_HOST_KEY_CHECK_MODE_HASH:
598
if (hkc->u.hash.type == SSH_HOST_KEY_CHECK_HASH_TYPE_MD5) {
599
return check_host_key_hash(s, hkc->u.hash.hash,
600
- LIBSSH2_HOSTKEY_HASH_MD5, 16, errp);
601
+ SSH_PUBLICKEY_HASH_MD5, errp);
602
} else if (hkc->u.hash.type == SSH_HOST_KEY_CHECK_HASH_TYPE_SHA1) {
603
return check_host_key_hash(s, hkc->u.hash.hash,
604
- LIBSSH2_HOSTKEY_HASH_SHA1, 20, errp);
605
+ SSH_PUBLICKEY_HASH_SHA1, errp);
606
}
607
g_assert_not_reached();
608
break;
609
case SSH_HOST_KEY_CHECK_MODE_KNOWN_HOSTS:
610
- return check_host_key_knownhosts(s, host, port, errp);
611
+ return check_host_key_knownhosts(s, errp);
612
default:
613
g_assert_not_reached();
614
}
615
@@ -XXX,XX +XXX,XX @@ static int check_host_key(BDRVSSHState *s, const char *host, int port,
616
return -EINVAL;
617
}
618
619
-static int authenticate(BDRVSSHState *s, const char *user, Error **errp)
620
+static int authenticate(BDRVSSHState *s, Error **errp)
621
{
622
int r, ret;
623
- const char *userauthlist;
624
- LIBSSH2_AGENT *agent = NULL;
625
- struct libssh2_agent_publickey *identity;
626
- struct libssh2_agent_publickey *prev_identity = NULL;
627
+ int method;
628
629
- userauthlist = libssh2_userauth_list(s->session, user, strlen(user));
630
- if (strstr(userauthlist, "publickey") == NULL) {
631
+ /* Try to authenticate with the "none" method. */
632
+ r = ssh_userauth_none(s->session, NULL);
633
+ if (r == SSH_AUTH_ERROR) {
634
ret = -EPERM;
635
- error_setg(errp,
636
- "remote server does not support \"publickey\" authentication");
637
+ session_error_setg(errp, s, "failed to authenticate using none "
638
+ "authentication");
639
goto out;
640
- }
641
-
642
- /* Connect to ssh-agent and try each identity in turn. */
643
- agent = libssh2_agent_init(s->session);
644
- if (!agent) {
645
- ret = -EINVAL;
646
- session_error_setg(errp, s, "failed to initialize ssh-agent support");
647
- goto out;
648
- }
649
- if (libssh2_agent_connect(agent)) {
650
- ret = -ECONNREFUSED;
651
- session_error_setg(errp, s, "failed to connect to ssh-agent");
652
- goto out;
653
- }
654
- if (libssh2_agent_list_identities(agent)) {
655
- ret = -EINVAL;
656
- session_error_setg(errp, s,
657
- "failed requesting identities from ssh-agent");
658
+ } else if (r == SSH_AUTH_SUCCESS) {
659
+ /* Authenticated! */
660
+ ret = 0;
661
goto out;
662
}
663
664
- for(;;) {
665
- r = libssh2_agent_get_identity(agent, &identity, prev_identity);
666
- if (r == 1) { /* end of list */
667
- break;
668
- }
669
- if (r < 0) {
670
+ method = ssh_userauth_list(s->session, NULL);
671
+ trace_ssh_auth_methods(method);
672
+
673
+ /*
674
+ * Try to authenticate with publickey, using the ssh-agent
675
+ * if available.
676
+ */
677
+ if (method & SSH_AUTH_METHOD_PUBLICKEY) {
678
+ r = ssh_userauth_publickey_auto(s->session, NULL, NULL);
679
+ if (r == SSH_AUTH_ERROR) {
680
ret = -EINVAL;
681
- session_error_setg(errp, s,
682
- "failed to obtain identity from ssh-agent");
683
+ session_error_setg(errp, s, "failed to authenticate using "
684
+ "publickey authentication");
685
goto out;
686
- }
687
- r = libssh2_agent_userauth(agent, user, identity);
688
- if (r == 0) {
689
+ } else if (r == SSH_AUTH_SUCCESS) {
690
/* Authenticated! */
691
ret = 0;
692
goto out;
693
}
694
- /* Failed to authenticate with this identity, try the next one. */
695
- prev_identity = identity;
696
}
697
698
ret = -EPERM;
699
@@ -XXX,XX +XXX,XX @@ static int authenticate(BDRVSSHState *s, const char *user, Error **errp)
700
"and the identities held by your ssh-agent");
701
702
out:
703
- if (agent != NULL) {
704
- /* Note: libssh2 implementation implicitly calls
705
- * libssh2_agent_disconnect if necessary.
706
- */
707
- libssh2_agent_free(agent);
708
- }
709
-
710
return ret;
711
}
712
713
@@ -XXX,XX +XXX,XX @@ static int connect_to_ssh(BDRVSSHState *s, BlockdevOptionsSsh *opts,
714
int ssh_flags, int creat_mode, Error **errp)
715
{
716
int r, ret;
717
- long port = 0;
718
+ unsigned int port = 0;
719
+ int new_sock = -1;
720
721
if (opts->has_user) {
722
s->user = g_strdup(opts->user);
723
@@ -XXX,XX +XXX,XX @@ static int connect_to_ssh(BDRVSSHState *s, BlockdevOptionsSsh *opts,
724
s->inet = opts->server;
725
opts->server = NULL;
726
727
- if (qemu_strtol(s->inet->port, NULL, 10, &port) < 0) {
728
+ if (qemu_strtoui(s->inet->port, NULL, 10, &port) < 0) {
729
error_setg(errp, "Use only numeric port value");
730
ret = -EINVAL;
731
goto err;
732
}
733
734
/* Open the socket and connect. */
735
- s->sock = inet_connect_saddr(s->inet, errp);
736
- if (s->sock < 0) {
737
+ new_sock = inet_connect_saddr(s->inet, errp);
738
+ if (new_sock < 0) {
739
ret = -EIO;
740
goto err;
741
}
742
743
+ /*
744
+ * Try to disable the Nagle algorithm on TCP sockets to reduce latency,
745
+ * but do not fail if it cannot be disabled.
746
+ */
747
+ r = socket_set_nodelay(new_sock);
748
+ if (r < 0) {
749
+ warn_report("can't set TCP_NODELAY for the ssh server %s: %s",
750
+ s->inet->host, strerror(errno));
751
+ }
752
+
753
/* Create SSH session. */
754
- s->session = libssh2_session_init();
755
+ s->session = ssh_new();
756
if (!s->session) {
757
ret = -EINVAL;
758
- session_error_setg(errp, s, "failed to initialize libssh2 session");
759
+ session_error_setg(errp, s, "failed to initialize libssh session");
760
goto err;
761
}
762
763
-#if TRACE_LIBSSH2 != 0
764
- libssh2_trace(s->session, TRACE_LIBSSH2);
765
-#endif
766
+ /*
767
+ * Make sure we are in blocking mode during the connection and
768
+ * authentication phases.
769
+ */
770
+ ssh_set_blocking(s->session, 1);
771
772
- r = libssh2_session_handshake(s->session, s->sock);
773
- if (r != 0) {
774
+ r = ssh_options_set(s->session, SSH_OPTIONS_USER, s->user);
775
+ if (r < 0) {
776
+ ret = -EINVAL;
777
+ session_error_setg(errp, s,
778
+ "failed to set the user in the libssh session");
779
+ goto err;
780
+ }
781
+
782
+ r = ssh_options_set(s->session, SSH_OPTIONS_HOST, s->inet->host);
783
+ if (r < 0) {
784
+ ret = -EINVAL;
785
+ session_error_setg(errp, s,
786
+ "failed to set the host in the libssh session");
787
+ goto err;
788
+ }
789
+
790
+ if (port > 0) {
791
+ r = ssh_options_set(s->session, SSH_OPTIONS_PORT, &port);
792
+ if (r < 0) {
793
+ ret = -EINVAL;
794
+ session_error_setg(errp, s,
795
+ "failed to set the port in the libssh session");
796
+ goto err;
797
+ }
798
+ }
799
+
800
+ r = ssh_options_set(s->session, SSH_OPTIONS_COMPRESSION, "none");
801
+ if (r < 0) {
802
+ ret = -EINVAL;
803
+ session_error_setg(errp, s,
804
+ "failed to disable the compression in the libssh "
805
+ "session");
806
+ goto err;
807
+ }
808
+
809
+ /* Read ~/.ssh/config. */
810
+ r = ssh_options_parse_config(s->session, NULL);
811
+ if (r < 0) {
812
+ ret = -EINVAL;
813
+ session_error_setg(errp, s, "failed to parse ~/.ssh/config");
814
+ goto err;
815
+ }
816
+
817
+ r = ssh_options_set(s->session, SSH_OPTIONS_FD, &new_sock);
818
+ if (r < 0) {
819
+ ret = -EINVAL;
820
+ session_error_setg(errp, s,
821
+ "failed to set the socket in the libssh session");
822
+ goto err;
823
+ }
824
+ /* libssh took ownership of the socket. */
825
+ s->sock = new_sock;
826
+ new_sock = -1;
827
+
828
+ /* Connect. */
829
+ r = ssh_connect(s->session);
830
+ if (r != SSH_OK) {
831
ret = -EINVAL;
832
session_error_setg(errp, s, "failed to establish SSH session");
833
goto err;
834
}
835
836
/* Check the remote host's key against known_hosts. */
837
- ret = check_host_key(s, s->inet->host, port, opts->host_key_check, errp);
838
+ ret = check_host_key(s, opts->host_key_check, errp);
839
if (ret < 0) {
840
goto err;
841
}
842
843
/* Authenticate. */
844
- ret = authenticate(s, s->user, errp);
845
+ ret = authenticate(s, errp);
846
if (ret < 0) {
847
goto err;
848
}
849
850
/* Start SFTP. */
851
- s->sftp = libssh2_sftp_init(s->session);
852
+ s->sftp = sftp_new(s->session);
853
if (!s->sftp) {
854
- session_error_setg(errp, s, "failed to initialize sftp handle");
855
+ session_error_setg(errp, s, "failed to create sftp handle");
856
+ ret = -EINVAL;
857
+ goto err;
858
+ }
859
+
860
+ r = sftp_init(s->sftp);
861
+ if (r < 0) {
862
+ sftp_error_setg(errp, s, "failed to initialize sftp handle");
863
ret = -EINVAL;
864
goto err;
865
}
866
867
/* Open the remote file. */
868
trace_ssh_connect_to_ssh(opts->path, ssh_flags, creat_mode);
869
- s->sftp_handle = libssh2_sftp_open(s->sftp, opts->path, ssh_flags,
870
- creat_mode);
871
+ s->sftp_handle = sftp_open(s->sftp, opts->path, ssh_flags, creat_mode);
872
if (!s->sftp_handle) {
873
- session_error_setg(errp, s, "failed to open remote file '%s'",
874
- opts->path);
875
+ sftp_error_setg(errp, s, "failed to open remote file '%s'",
876
+ opts->path);
877
ret = -EINVAL;
878
goto err;
879
}
880
881
- r = libssh2_sftp_fstat(s->sftp_handle, &s->attrs);
882
- if (r < 0) {
883
+ /* Make sure the SFTP file is handled in blocking mode. */
884
+ sftp_file_set_blocking(s->sftp_handle);
885
+
886
+ s->attrs = sftp_fstat(s->sftp_handle);
887
+ if (!s->attrs) {
888
sftp_error_setg(errp, s, "failed to read file attributes");
889
return -EINVAL;
890
}
891
@@ -XXX,XX +XXX,XX @@ static int connect_to_ssh(BDRVSSHState *s, BlockdevOptionsSsh *opts,
892
return 0;
893
894
err:
895
+ if (s->attrs) {
896
+ sftp_attributes_free(s->attrs);
897
+ }
898
+ s->attrs = NULL;
899
if (s->sftp_handle) {
900
- libssh2_sftp_close(s->sftp_handle);
901
+ sftp_close(s->sftp_handle);
902
}
903
s->sftp_handle = NULL;
904
if (s->sftp) {
905
- libssh2_sftp_shutdown(s->sftp);
906
+ sftp_free(s->sftp);
907
}
908
s->sftp = NULL;
909
if (s->session) {
910
- libssh2_session_disconnect(s->session,
911
- "from qemu ssh client: "
912
- "error opening connection");
913
- libssh2_session_free(s->session);
914
+ ssh_disconnect(s->session);
915
+ ssh_free(s->session);
916
}
917
s->session = NULL;
918
+ s->sock = -1;
919
+ if (new_sock >= 0) {
920
+ close(new_sock);
921
+ }
922
923
return ret;
924
}
925
@@ -XXX,XX +XXX,XX @@ static int ssh_file_open(BlockDriverState *bs, QDict *options, int bdrv_flags,
926
927
ssh_state_init(s);
928
929
- ssh_flags = LIBSSH2_FXF_READ;
930
+ ssh_flags = 0;
931
if (bdrv_flags & BDRV_O_RDWR) {
932
- ssh_flags |= LIBSSH2_FXF_WRITE;
933
+ ssh_flags |= O_RDWR;
934
+ } else {
935
+ ssh_flags |= O_RDONLY;
936
}
937
938
opts = ssh_parse_options(options, errp);
939
@@ -XXX,XX +XXX,XX @@ static int ssh_file_open(BlockDriverState *bs, QDict *options, int bdrv_flags,
940
}
941
942
/* Go non-blocking. */
943
- libssh2_session_set_blocking(s->session, 0);
944
+ ssh_set_blocking(s->session, 0);
945
946
qapi_free_BlockdevOptionsSsh(opts);
947
948
return 0;
949
950
err:
951
- if (s->sock >= 0) {
952
- close(s->sock);
953
- }
954
- s->sock = -1;
955
-
956
qapi_free_BlockdevOptionsSsh(opts);
957
958
return ret;
959
@@ -XXX,XX +XXX,XX @@ static int ssh_grow_file(BDRVSSHState *s, int64_t offset, Error **errp)
960
{
961
ssize_t ret;
962
char c[1] = { '\0' };
963
- int was_blocking = libssh2_session_get_blocking(s->session);
964
+ int was_blocking = ssh_is_blocking(s->session);
965
966
/* offset must be strictly greater than the current size so we do
967
* not overwrite anything */
968
- assert(offset > 0 && offset > s->attrs.filesize);
969
+ assert(offset > 0 && offset > s->attrs->size);
970
971
- libssh2_session_set_blocking(s->session, 1);
972
+ ssh_set_blocking(s->session, 1);
973
974
- libssh2_sftp_seek64(s->sftp_handle, offset - 1);
975
- ret = libssh2_sftp_write(s->sftp_handle, c, 1);
976
+ sftp_seek64(s->sftp_handle, offset - 1);
977
+ ret = sftp_write(s->sftp_handle, c, 1);
978
979
- libssh2_session_set_blocking(s->session, was_blocking);
980
+ ssh_set_blocking(s->session, was_blocking);
981
982
if (ret < 0) {
983
sftp_error_setg(errp, s, "Failed to grow file");
984
return -EIO;
985
}
986
987
- s->attrs.filesize = offset;
988
+ s->attrs->size = offset;
989
return 0;
990
}
991
992
@@ -XXX,XX +XXX,XX @@ static int ssh_co_create(BlockdevCreateOptions *options, Error **errp)
993
ssh_state_init(&s);
994
995
ret = connect_to_ssh(&s, opts->location,
996
- LIBSSH2_FXF_READ|LIBSSH2_FXF_WRITE|
997
- LIBSSH2_FXF_CREAT|LIBSSH2_FXF_TRUNC,
998
+ O_RDWR | O_CREAT | O_TRUNC,
999
0644, errp);
1000
if (ret < 0) {
1001
goto fail;
1002
@@ -XXX,XX +XXX,XX @@ static int ssh_has_zero_init(BlockDriverState *bs)
1003
/* Assume false, unless we can positively prove it's true. */
1004
int has_zero_init = 0;
1005
1006
- if (s->attrs.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) {
1007
- if (s->attrs.permissions & LIBSSH2_SFTP_S_IFREG) {
1008
- has_zero_init = 1;
1009
- }
1010
+ if (s->attrs->type == SSH_FILEXFER_TYPE_REGULAR) {
1011
+ has_zero_init = 1;
1012
}
1013
1014
return has_zero_init;
1015
@@ -XXX,XX +XXX,XX @@ static coroutine_fn void co_yield(BDRVSSHState *s, BlockDriverState *bs)
1016
.co = qemu_coroutine_self()
1017
};
1018
1019
- r = libssh2_session_block_directions(s->session);
1020
+ r = ssh_get_poll_flags(s->session);
1021
1022
- if (r & LIBSSH2_SESSION_BLOCK_INBOUND) {
1023
+ if (r & SSH_READ_PENDING) {
1024
rd_handler = restart_coroutine;
1025
}
1026
- if (r & LIBSSH2_SESSION_BLOCK_OUTBOUND) {
1027
+ if (r & SSH_WRITE_PENDING) {
1028
wr_handler = restart_coroutine;
1029
}
1030
1031
@@ -XXX,XX +XXX,XX @@ static coroutine_fn void co_yield(BDRVSSHState *s, BlockDriverState *bs)
1032
trace_ssh_co_yield_back(s->sock);
1033
}
1034
1035
-/* SFTP has a function `libssh2_sftp_seek64' which seeks to a position
1036
- * in the remote file. Notice that it just updates a field in the
1037
- * sftp_handle structure, so there is no network traffic and it cannot
1038
- * fail.
1039
- *
1040
- * However, `libssh2_sftp_seek64' does have a catastrophic effect on
1041
- * performance since it causes the handle to throw away all in-flight
1042
- * reads and buffered readahead data. Therefore this function tries
1043
- * to be intelligent about when to call the underlying libssh2 function.
1044
- */
1045
-#define SSH_SEEK_WRITE 0
1046
-#define SSH_SEEK_READ 1
1047
-#define SSH_SEEK_FORCE 2
1048
-
1049
-static void ssh_seek(BDRVSSHState *s, int64_t offset, int flags)
1050
-{
1051
- bool op_read = (flags & SSH_SEEK_READ) != 0;
1052
- bool force = (flags & SSH_SEEK_FORCE) != 0;
1053
-
1054
- if (force || op_read != s->offset_op_read || offset != s->offset) {
1055
- trace_ssh_seek(offset);
1056
- libssh2_sftp_seek64(s->sftp_handle, offset);
1057
- s->offset = offset;
1058
- s->offset_op_read = op_read;
1059
- }
1060
-}
1061
-
1062
static coroutine_fn int ssh_read(BDRVSSHState *s, BlockDriverState *bs,
1063
int64_t offset, size_t size,
1064
QEMUIOVector *qiov)
1065
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int ssh_read(BDRVSSHState *s, BlockDriverState *bs,
1066
1067
trace_ssh_read(offset, size);
1068
1069
- ssh_seek(s, offset, SSH_SEEK_READ);
1070
+ trace_ssh_seek(offset);
1071
+ sftp_seek64(s->sftp_handle, offset);
1072
1073
/* This keeps track of the current iovec element ('i'), where we
1074
* will write to next ('buf'), and the end of the current iovec
1075
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int ssh_read(BDRVSSHState *s, BlockDriverState *bs,
1076
buf = i->iov_base;
1077
end_of_vec = i->iov_base + i->iov_len;
1078
1079
- /* libssh2 has a hard-coded limit of 2000 bytes per request,
1080
- * although it will also do readahead behind our backs. Therefore
1081
- * we may have to do repeated reads here until we have read 'size'
1082
- * bytes.
1083
- */
1084
for (got = 0; got < size; ) {
1085
+ size_t request_read_size;
1086
again:
1087
- trace_ssh_read_buf(buf, end_of_vec - buf);
1088
- r = libssh2_sftp_read(s->sftp_handle, buf, end_of_vec - buf);
1089
- trace_ssh_read_return(r);
1090
+ /*
1091
+ * The size of SFTP packets is limited to 32K bytes, so limit
1092
+ * the amount of data requested to 16K, as libssh currently
1093
+ * does not handle multiple requests on its own.
1094
+ */
1095
+ request_read_size = MIN(end_of_vec - buf, 16384);
1096
+ trace_ssh_read_buf(buf, end_of_vec - buf, request_read_size);
1097
+ r = sftp_read(s->sftp_handle, buf, request_read_size);
1098
+ trace_ssh_read_return(r, sftp_get_error(s->sftp));
1099
1100
- if (r == LIBSSH2_ERROR_EAGAIN || r == LIBSSH2_ERROR_TIMEOUT) {
1101
+ if (r == SSH_AGAIN) {
1102
co_yield(s, bs);
1103
goto again;
1104
}
1105
- if (r < 0) {
1106
- sftp_error_trace(s, "read");
1107
- s->offset = -1;
1108
- return -EIO;
1109
- }
1110
- if (r == 0) {
1111
+ if (r == SSH_EOF || (r == 0 && sftp_get_error(s->sftp) == SSH_FX_EOF)) {
1112
/* EOF: Short read so pad the buffer with zeroes and return it. */
1113
qemu_iovec_memset(qiov, got, 0, size - got);
1114
return 0;
1115
}
1116
+ if (r <= 0) {
1117
+ sftp_error_trace(s, "read");
1118
+ return -EIO;
1119
+ }
1120
1121
got += r;
1122
buf += r;
1123
- s->offset += r;
1124
if (buf >= end_of_vec && got < size) {
1125
i++;
1126
buf = i->iov_base;
1127
@@ -XXX,XX +XXX,XX @@ static int ssh_write(BDRVSSHState *s, BlockDriverState *bs,
1128
1129
trace_ssh_write(offset, size);
1130
1131
- ssh_seek(s, offset, SSH_SEEK_WRITE);
1132
+ trace_ssh_seek(offset);
1133
+ sftp_seek64(s->sftp_handle, offset);
1134
1135
/* This keeps track of the current iovec element ('i'), where we
1136
* will read from next ('buf'), and the end of the current iovec
1137
@@ -XXX,XX +XXX,XX @@ static int ssh_write(BDRVSSHState *s, BlockDriverState *bs,
1138
end_of_vec = i->iov_base + i->iov_len;
1139
1140
for (written = 0; written < size; ) {
1141
+ size_t request_write_size;
1142
again:
1143
- trace_ssh_write_buf(buf, end_of_vec - buf);
1144
- r = libssh2_sftp_write(s->sftp_handle, buf, end_of_vec - buf);
1145
- trace_ssh_write_return(r);
1146
+ /*
1147
+ * Avoid too large data packets, as libssh currently does not
1148
+ * handle multiple requests on its own.
1149
+ */
1150
+ request_write_size = MIN(end_of_vec - buf, 131072);
1151
+ trace_ssh_write_buf(buf, end_of_vec - buf, request_write_size);
1152
+ r = sftp_write(s->sftp_handle, buf, request_write_size);
1153
+ trace_ssh_write_return(r, sftp_get_error(s->sftp));
1154
1155
- if (r == LIBSSH2_ERROR_EAGAIN || r == LIBSSH2_ERROR_TIMEOUT) {
1156
+ if (r == SSH_AGAIN) {
1157
co_yield(s, bs);
1158
goto again;
1159
}
1160
if (r < 0) {
1161
sftp_error_trace(s, "write");
1162
- s->offset = -1;
1163
return -EIO;
1164
}
1165
- /* The libssh2 API is very unclear about this. A comment in
1166
- * the code says "nothing was acked, and no EAGAIN was
1167
- * received!" which apparently means that no data got sent
1168
- * out, and the underlying channel didn't return any EAGAIN
1169
- * indication. I think this is a bug in either libssh2 or
1170
- * OpenSSH (server-side). In any case, forcing a seek (to
1171
- * discard libssh2 internal buffers), and then trying again
1172
- * works for me.
1173
- */
1174
- if (r == 0) {
1175
- ssh_seek(s, offset + written, SSH_SEEK_WRITE|SSH_SEEK_FORCE);
1176
- co_yield(s, bs);
1177
- goto again;
1178
- }
1179
1180
written += r;
1181
buf += r;
1182
- s->offset += r;
1183
if (buf >= end_of_vec && written < size) {
1184
i++;
1185
buf = i->iov_base;
1186
end_of_vec = i->iov_base + i->iov_len;
1187
}
1188
1189
- if (offset + written > s->attrs.filesize)
1190
- s->attrs.filesize = offset + written;
1191
+ if (offset + written > s->attrs->size) {
1192
+ s->attrs->size = offset + written;
1193
+ }
1194
}
1195
1196
return 0;
1197
@@ -XXX,XX +XXX,XX @@ static void unsafe_flush_warning(BDRVSSHState *s, const char *what)
1198
}
1199
}
1200
1201
-#ifdef HAS_LIBSSH2_SFTP_FSYNC
1202
+#ifdef HAVE_LIBSSH_0_8
1203
1204
static coroutine_fn int ssh_flush(BDRVSSHState *s, BlockDriverState *bs)
1205
{
1206
int r;
1207
1208
trace_ssh_flush();
1209
+
1210
+ if (!sftp_extension_supported(s->sftp, "fsync@openssh.com", "1")) {
1211
+ unsafe_flush_warning(s, "OpenSSH >= 6.3");
1212
+ return 0;
1213
+ }
1214
again:
1215
- r = libssh2_sftp_fsync(s->sftp_handle);
1216
- if (r == LIBSSH2_ERROR_EAGAIN || r == LIBSSH2_ERROR_TIMEOUT) {
1217
+ r = sftp_fsync(s->sftp_handle);
1218
+ if (r == SSH_AGAIN) {
1219
co_yield(s, bs);
1220
goto again;
1221
}
1222
- if (r == LIBSSH2_ERROR_SFTP_PROTOCOL &&
1223
- libssh2_sftp_last_error(s->sftp) == LIBSSH2_FX_OP_UNSUPPORTED) {
1224
- unsafe_flush_warning(s, "OpenSSH >= 6.3");
1225
- return 0;
1226
- }
1227
if (r < 0) {
1228
sftp_error_trace(s, "fsync");
1229
return -EIO;
1230
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int ssh_co_flush(BlockDriverState *bs)
1231
return ret;
1232
}
1233
1234
-#else /* !HAS_LIBSSH2_SFTP_FSYNC */
1235
+#else /* !HAVE_LIBSSH_0_8 */
1236
1237
static coroutine_fn int ssh_co_flush(BlockDriverState *bs)
1238
{
1239
BDRVSSHState *s = bs->opaque;
1240
1241
- unsafe_flush_warning(s, "libssh2 >= 1.4.4");
1242
+ unsafe_flush_warning(s, "libssh >= 0.8.0");
1243
return 0;
1244
}
1245
1246
-#endif /* !HAS_LIBSSH2_SFTP_FSYNC */
1247
+#endif /* !HAVE_LIBSSH_0_8 */
1248
1249
static int64_t ssh_getlength(BlockDriverState *bs)
1250
{
1251
BDRVSSHState *s = bs->opaque;
1252
int64_t length;
1253
1254
- /* Note we cannot make a libssh2 call here. */
1255
- length = (int64_t) s->attrs.filesize;
1256
+ /* Note we cannot make a libssh call here. */
1257
+ length = (int64_t) s->attrs->size;
1258
trace_ssh_getlength(length);
1259
1260
return length;
1261
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn ssh_co_truncate(BlockDriverState *bs, int64_t offset,
1262
return -ENOTSUP;
1263
}
1264
1265
- if (offset < s->attrs.filesize) {
1266
+ if (offset < s->attrs->size) {
1267
error_setg(errp, "ssh driver does not support shrinking files");
1268
return -ENOTSUP;
1269
}
1270
1271
- if (offset == s->attrs.filesize) {
1272
+ if (offset == s->attrs->size) {
1273
return 0;
1274
}
1275
1276
@@ -XXX,XX +XXX,XX @@ static void bdrv_ssh_init(void)
1277
{
1278
int r;
1279
1280
- r = libssh2_init(0);
1281
+ r = ssh_init();
1282
if (r != 0) {
1283
- fprintf(stderr, "libssh2 initialization failed, %d\n", r);
1284
+ fprintf(stderr, "libssh initialization failed, %d\n", r);
1285
exit(EXIT_FAILURE);
1286
}
1287
1288
+#if TRACE_LIBSSH != 0
1289
+ ssh_set_log_level(TRACE_LIBSSH);
1290
+#endif
1291
+
1292
bdrv_register(&bdrv_ssh);
1293
}
1294
1295
diff --git a/.travis.yml b/.travis.yml
1296
index XXXXXXX..XXXXXXX 100644
1297
--- a/.travis.yml
1298
+++ b/.travis.yml
1299
@@ -XXX,XX +XXX,XX @@ addons:
1300
- libseccomp-dev
1301
- libspice-protocol-dev
1302
- libspice-server-dev
1303
- - libssh2-1-dev
1304
+ - libssh-dev
1305
- liburcu-dev
1306
- libusb-1.0-0-dev
1307
- libvte-2.91-dev
1308
@@ -XXX,XX +XXX,XX @@ matrix:
1309
- libseccomp-dev
1310
- libspice-protocol-dev
1311
- libspice-server-dev
1312
- - libssh2-1-dev
1313
+ - libssh-dev
1314
- liburcu-dev
1315
- libusb-1.0-0-dev
1316
- libvte-2.91-dev
1317
diff --git a/block/trace-events b/block/trace-events
1318
index XXXXXXX..XXXXXXX 100644
1319
--- a/block/trace-events
1320
+++ b/block/trace-events
1321
@@ -XXX,XX +XXX,XX @@ nbd_client_connect_success(const char *export_name) "export '%s'"
1322
# ssh.c
1323
ssh_restart_coroutine(void *co) "co=%p"
1324
ssh_flush(void) "fsync"
1325
-ssh_check_host_key_knownhosts(const char *key) "host key OK: %s"
1326
+ssh_check_host_key_knownhosts(void) "host key OK"
1327
ssh_connect_to_ssh(char *path, int flags, int mode) "opening file %s flags=0x%x creat_mode=0%o"
1328
ssh_co_yield(int sock, void *rd_handler, void *wr_handler) "s->sock=%d rd_handler=%p wr_handler=%p"
1329
ssh_co_yield_back(int sock) "s->sock=%d - back"
1330
ssh_getlength(int64_t length) "length=%" PRIi64
1331
ssh_co_create_opts(uint64_t size) "total_size=%" PRIu64
1332
ssh_read(int64_t offset, size_t size) "offset=%" PRIi64 " size=%zu"
1333
-ssh_read_buf(void *buf, size_t size) "sftp_read buf=%p size=%zu"
1334
-ssh_read_return(ssize_t ret) "sftp_read returned %zd"
1335
+ssh_read_buf(void *buf, size_t size, size_t actual_size) "sftp_read buf=%p size=%zu (actual size=%zu)"
1336
+ssh_read_return(ssize_t ret, int sftp_err) "sftp_read returned %zd (sftp error=%d)"
1337
ssh_write(int64_t offset, size_t size) "offset=%" PRIi64 " size=%zu"
1338
-ssh_write_buf(void *buf, size_t size) "sftp_write buf=%p size=%zu"
1339
-ssh_write_return(ssize_t ret) "sftp_write returned %zd"
1340
+ssh_write_buf(void *buf, size_t size, size_t actual_size) "sftp_write buf=%p size=%zu (actual size=%zu)"
1341
+ssh_write_return(ssize_t ret, int sftp_err) "sftp_write returned %zd (sftp error=%d)"
1342
ssh_seek(int64_t offset) "seeking to offset=%" PRIi64
1343
+ssh_auth_methods(int methods) "auth methods=0x%x"
1344
+ssh_server_status(int status) "server status=%d"
1345
1346
# curl.c
1347
curl_timer_cb(long timeout_ms) "timer callback timeout_ms %ld"
1348
@@ -XXX,XX +XXX,XX @@ sheepdog_snapshot_create(const char *sn_name, const char *id) "%s %s"
1349
sheepdog_snapshot_create_inode(const char *name, uint32_t snap, uint32_t vdi) "s->inode: name %s snap_id 0x%" PRIx32 " vdi 0x%" PRIx32
1350
1351
# ssh.c
1352
-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)"
1353
+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)"
1354
diff --git a/docs/qemu-block-drivers.texi b/docs/qemu-block-drivers.texi
1355
index XXXXXXX..XXXXXXX 100644
1356
--- a/docs/qemu-block-drivers.texi
1357
+++ b/docs/qemu-block-drivers.texi
1358
@@ -XXX,XX +XXX,XX @@ print a warning when @code{fsync} is not supported:
1359
1360
warning: ssh server @code{ssh.example.com:22} does not support fsync
1361
1362
-With sufficiently new versions of libssh2 and OpenSSH, @code{fsync} is
1363
+With sufficiently new versions of libssh and OpenSSH, @code{fsync} is
1364
supported.
1365
1366
@node disk_images_nvme
1367
diff --git a/tests/docker/dockerfiles/debian-win32-cross.docker b/tests/docker/dockerfiles/debian-win32-cross.docker
1368
index XXXXXXX..XXXXXXX 100644
1369
--- a/tests/docker/dockerfiles/debian-win32-cross.docker
1370
+++ b/tests/docker/dockerfiles/debian-win32-cross.docker
1371
@@ -XXX,XX +XXX,XX @@ RUN DEBIAN_FRONTEND=noninteractive eatmydata \
1372
mxe-$TARGET-w64-mingw32.shared-curl \
1373
mxe-$TARGET-w64-mingw32.shared-glib \
1374
mxe-$TARGET-w64-mingw32.shared-libgcrypt \
1375
- mxe-$TARGET-w64-mingw32.shared-libssh2 \
1376
mxe-$TARGET-w64-mingw32.shared-libusb1 \
1377
mxe-$TARGET-w64-mingw32.shared-lzo \
1378
mxe-$TARGET-w64-mingw32.shared-nettle \
1379
diff --git a/tests/docker/dockerfiles/debian-win64-cross.docker b/tests/docker/dockerfiles/debian-win64-cross.docker
1380
index XXXXXXX..XXXXXXX 100644
1381
--- a/tests/docker/dockerfiles/debian-win64-cross.docker
1382
+++ b/tests/docker/dockerfiles/debian-win64-cross.docker
1383
@@ -XXX,XX +XXX,XX @@ RUN DEBIAN_FRONTEND=noninteractive eatmydata \
1384
mxe-$TARGET-w64-mingw32.shared-curl \
1385
mxe-$TARGET-w64-mingw32.shared-glib \
1386
mxe-$TARGET-w64-mingw32.shared-libgcrypt \
1387
- mxe-$TARGET-w64-mingw32.shared-libssh2 \
1388
mxe-$TARGET-w64-mingw32.shared-libusb1 \
1389
mxe-$TARGET-w64-mingw32.shared-lzo \
1390
mxe-$TARGET-w64-mingw32.shared-nettle \
1391
diff --git a/tests/docker/dockerfiles/fedora.docker b/tests/docker/dockerfiles/fedora.docker
1392
index XXXXXXX..XXXXXXX 100644
1393
--- a/tests/docker/dockerfiles/fedora.docker
1394
+++ b/tests/docker/dockerfiles/fedora.docker
1395
@@ -XXX,XX +XXX,XX @@ ENV PACKAGES \
1396
libpng-devel \
1397
librbd-devel \
1398
libseccomp-devel \
1399
- libssh2-devel \
1400
+ libssh-devel \
1401
libubsan \
1402
libusbx-devel \
1403
libxml2-devel \
1404
@@ -XXX,XX +XXX,XX @@ ENV PACKAGES \
1405
mingw32-gtk3 \
1406
mingw32-libjpeg-turbo \
1407
mingw32-libpng \
1408
- mingw32-libssh2 \
1409
mingw32-libtasn1 \
1410
mingw32-nettle \
1411
mingw32-pixman \
1412
@@ -XXX,XX +XXX,XX @@ ENV PACKAGES \
1413
mingw64-gtk3 \
1414
mingw64-libjpeg-turbo \
1415
mingw64-libpng \
1416
- mingw64-libssh2 \
1417
mingw64-libtasn1 \
1418
mingw64-nettle \
1419
mingw64-pixman \
1420
diff --git a/tests/docker/dockerfiles/ubuntu.docker b/tests/docker/dockerfiles/ubuntu.docker
1421
index XXXXXXX..XXXXXXX 100644
1422
--- a/tests/docker/dockerfiles/ubuntu.docker
1423
+++ b/tests/docker/dockerfiles/ubuntu.docker
1424
@@ -XXX,XX +XXX,XX @@ ENV PACKAGES flex bison \
1425
libsnappy-dev \
1426
libspice-protocol-dev \
1427
libspice-server-dev \
1428
- libssh2-1-dev \
1429
+ libssh-dev \
1430
libusb-1.0-0-dev \
1431
libusbredirhost-dev \
1432
libvdeplug-dev \
1433
diff --git a/tests/docker/dockerfiles/ubuntu1804.docker b/tests/docker/dockerfiles/ubuntu1804.docker
1434
index XXXXXXX..XXXXXXX 100644
1435
--- a/tests/docker/dockerfiles/ubuntu1804.docker
1436
+++ b/tests/docker/dockerfiles/ubuntu1804.docker
1437
@@ -XXX,XX +XXX,XX @@ ENV PACKAGES flex bison \
1438
libsnappy-dev \
1439
libspice-protocol-dev \
1440
libspice-server-dev \
1441
- libssh2-1-dev \
1442
+ libssh-dev \
1443
libusb-1.0-0-dev \
1444
libusbredirhost-dev \
1445
libvdeplug-dev \
1446
diff --git a/tests/qemu-iotests/207 b/tests/qemu-iotests/207
1447
index XXXXXXX..XXXXXXX 100755
1448
--- a/tests/qemu-iotests/207
1449
+++ b/tests/qemu-iotests/207
1450
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.img') as disk_path, \
1451
1452
iotests.img_info_log(remote_path)
1453
1454
- md5_key = subprocess.check_output(
1455
- 'ssh-keyscan -t rsa 127.0.0.1 2>/dev/null | grep -v "\\^#" | ' +
1456
- 'cut -d" " -f3 | base64 -d | md5sum -b | cut -d" " -f1',
1457
- shell=True).rstrip().decode('ascii')
1458
+ keys = subprocess.check_output(
1459
+ 'ssh-keyscan 127.0.0.1 2>/dev/null | grep -v "\\^#" | ' +
1460
+ 'cut -d" " -f3',
1461
+ shell=True).rstrip().decode('ascii').split('\n')
1462
+
1463
+ # Mappings of base64 representations to digests
1464
+ md5_keys = {}
1465
+ sha1_keys = {}
1466
+
1467
+ for key in keys:
1468
+ md5_keys[key] = subprocess.check_output(
1469
+ 'echo %s | base64 -d | md5sum -b | cut -d" " -f1' % key,
1470
+ shell=True).rstrip().decode('ascii')
1471
+
1472
+ sha1_keys[key] = subprocess.check_output(
1473
+ 'echo %s | base64 -d | sha1sum -b | cut -d" " -f1' % key,
1474
+ shell=True).rstrip().decode('ascii')
1475
1476
vm.launch()
1477
+
1478
+ # Find correct key first
1479
+ matching_key = None
1480
+ for key in keys:
1481
+ result = vm.qmp('blockdev-add',
1482
+ driver='ssh', node_name='node0', path=disk_path,
1483
+ server={
1484
+ 'host': '127.0.0.1',
1485
+ 'port': '22',
1486
+ }, host_key_check={
1487
+ 'mode': 'hash',
1488
+ 'type': 'md5',
1489
+ 'hash': md5_keys[key],
1490
+ })
1491
+
1492
+ if 'error' not in result:
1493
+ vm.qmp('blockdev-del', node_name='node0')
1494
+ matching_key = key
1495
+ break
1496
+
1497
+ if matching_key is None:
1498
+ vm.shutdown()
1499
+ iotests.notrun('Did not find a key that fits 127.0.0.1')
1500
+
1501
blockdev_create(vm, { 'driver': 'ssh',
1502
'location': {
1503
'path': disk_path,
1504
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.img') as disk_path, \
1505
'host-key-check': {
1506
'mode': 'hash',
1507
'type': 'md5',
1508
- 'hash': md5_key,
1509
+ 'hash': md5_keys[matching_key],
1510
}
1511
},
1512
'size': 8388608 })
1513
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.img') as disk_path, \
1514
1515
iotests.img_info_log(remote_path)
1516
1517
- sha1_key = subprocess.check_output(
1518
- 'ssh-keyscan -t rsa 127.0.0.1 2>/dev/null | grep -v "\\^#" | ' +
1519
- 'cut -d" " -f3 | base64 -d | sha1sum -b | cut -d" " -f1',
1520
- shell=True).rstrip().decode('ascii')
1521
-
1522
vm.launch()
1523
blockdev_create(vm, { 'driver': 'ssh',
1524
'location': {
1525
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.img') as disk_path, \
1526
'host-key-check': {
1527
'mode': 'hash',
1528
'type': 'sha1',
1529
- 'hash': sha1_key,
1530
+ 'hash': sha1_keys[matching_key],
1531
}
1532
},
1533
'size': 4194304 })
1534
diff --git a/tests/qemu-iotests/207.out b/tests/qemu-iotests/207.out
1535
index XXXXXXX..XXXXXXX 100644
1536
--- a/tests/qemu-iotests/207.out
1537
+++ b/tests/qemu-iotests/207.out
1538
@@ -XXX,XX +XXX,XX @@ virtual size: 4 MiB (4194304 bytes)
1539
1540
{"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}}}
1541
{"return": {}}
1542
-Job failed: failed to open remote file '/this/is/not/an/existing/path': Failed opening remote file (libssh2 error code: -31)
1543
+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)
1544
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
1545
{"return": {}}
1546
1547
--
57
--
1548
2.21.0
58
2.31.1
1549
59
1550
diff view generated by jsdifflib
1
From: Sam Eiderman <shmuel.eiderman@oracle.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
Until ESXi 6.5 VMware used the vmfsSparse format for snapshots (VMDK3 in
3
Right now, users of qemu_co_sleep_ns_wakeable are simply passing
4
QEMU).
4
a pointer to QemuCoSleepState by reference to the function. But
5
5
QemuCoSleepState really is just a Coroutine*; making the
6
This format was lacking in the following:
6
content of the struct public is just as efficient and lets us
7
7
skip the user_state_pointer indirection.
8
* Grain directory (L1) and grain table (L2) entries were 32-bit,
8
9
allowing access to only 2TB (slightly less) of data.
9
Since the usage is changed, take the occasion to rename the
10
* The grain size (default) was 512 bytes - leading to data
10
struct to QemuCoSleep.
11
fragmentation and many grain tables.
11
12
* For space reclamation purposes, it was necessary to find all the
12
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
13
grains which are not pointed to by any grain table - so a reverse
13
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
14
mapping of "offset of grain in vmdk" to "grain table" must be
14
Message-id: 20210517100548.28806-6-pbonzini@redhat.com
15
constructed - which takes large amounts of CPU/RAM.
15
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
16
17
The format specification can be found in VMware's documentation:
18
https://www.vmware.com/support/developer/vddk/vmdk_50_technote.pdf
19
20
In ESXi 6.5, to support snapshot files larger than 2TB, a new format was
21
introduced: SESparse (Space Efficient).
22
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>
152
---
16
---
153
block/vmdk.c | 358 ++++++++++++++++++++++++++++++++++++++++++++++++---
17
include/qemu/coroutine.h | 23 +++++++++++----------
154
1 file changed, 342 insertions(+), 16 deletions(-)
18
block/block-copy.c | 8 ++++----
155
19
block/nbd.c | 10 ++++-----
156
diff --git a/block/vmdk.c b/block/vmdk.c
20
util/qemu-coroutine-sleep.c | 41 ++++++++++++++++---------------------
157
index XXXXXXX..XXXXXXX 100644
21
4 files changed, 39 insertions(+), 43 deletions(-)
158
--- a/block/vmdk.c
22
159
+++ b/block/vmdk.c
23
diff --git a/include/qemu/coroutine.h b/include/qemu/coroutine.h
160
@@ -XXX,XX +XXX,XX @@ typedef struct {
24
index XXXXXXX..XXXXXXX 100644
161
uint16_t compressAlgorithm;
25
--- a/include/qemu/coroutine.h
162
} QEMU_PACKED VMDK4Header;
26
+++ b/include/qemu/coroutine.h
163
27
@@ -XXX,XX +XXX,XX @@ void qemu_co_rwlock_wrlock(CoRwlock *lock);
164
+typedef struct VMDKSESparseConstHeader {
28
*/
165
+ uint64_t magic;
29
void qemu_co_rwlock_unlock(CoRwlock *lock);
166
+ uint64_t version;
30
167
+ uint64_t capacity;
31
-typedef struct QemuCoSleepState QemuCoSleepState;
168
+ uint64_t grain_size;
32
+typedef struct QemuCoSleep {
169
+ uint64_t grain_table_size;
33
+ Coroutine *to_wake;
170
+ uint64_t flags;
34
+} QemuCoSleep;
171
+ uint64_t reserved1;
35
172
+ uint64_t reserved2;
36
/**
173
+ uint64_t reserved3;
37
- * Yield the coroutine for a given duration. During this yield, @sleep_state
174
+ uint64_t reserved4;
38
- * is set to an opaque pointer, which may be used for
175
+ uint64_t volatile_header_offset;
39
- * qemu_co_sleep_wake(). Be careful, the pointer is set back to zero when the
176
+ uint64_t volatile_header_size;
40
- * timer fires. Don't save the obtained value to other variables and don't call
177
+ uint64_t journal_header_offset;
41
- * qemu_co_sleep_wake from another aio context.
178
+ uint64_t journal_header_size;
42
+ * Yield the coroutine for a given duration. Initializes @w so that,
179
+ uint64_t journal_offset;
43
+ * during this yield, it can be passed to qemu_co_sleep_wake() to
180
+ uint64_t journal_size;
44
+ * terminate the sleep.
181
+ uint64_t grain_dir_offset;
45
*/
182
+ uint64_t grain_dir_size;
46
-void coroutine_fn qemu_co_sleep_ns_wakeable(QEMUClockType type, int64_t ns,
183
+ uint64_t grain_tables_offset;
47
- QemuCoSleepState **sleep_state);
184
+ uint64_t grain_tables_size;
48
+void coroutine_fn qemu_co_sleep_ns_wakeable(QemuCoSleep *w,
185
+ uint64_t free_bitmap_offset;
49
+ QEMUClockType type, int64_t ns);
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
+
50
+
194
+typedef struct VMDKSESparseVolatileHeader {
51
static inline void coroutine_fn qemu_co_sleep_ns(QEMUClockType type, int64_t ns)
195
+ uint64_t magic;
52
{
196
+ uint64_t free_gt_number;
53
- QemuCoSleepState *unused = NULL;
197
+ uint64_t next_txn_seq_number;
54
- qemu_co_sleep_ns_wakeable(type, ns, &unused);
198
+ uint64_t replay_journal;
55
+ QemuCoSleep w = { 0 };
199
+ uint8_t pad[480];
56
+ qemu_co_sleep_ns_wakeable(&w, type, ns);
200
+} QEMU_PACKED VMDKSESparseVolatileHeader;
57
}
201
+
58
202
#define L2_CACHE_SIZE 16
59
/**
203
60
@@ -XXX,XX +XXX,XX @@ static inline void coroutine_fn qemu_co_sleep_ns(QEMUClockType type, int64_t ns)
204
typedef struct VmdkExtent {
61
* qemu_co_sleep_ns() and should be checked to be non-NULL before calling
205
@@ -XXX,XX +XXX,XX @@ typedef struct VmdkExtent {
62
* qemu_co_sleep_wake().
206
bool compressed;
63
*/
207
bool has_marker;
64
-void qemu_co_sleep_wake(QemuCoSleepState *sleep_state);
208
bool has_zero_grain;
65
+void qemu_co_sleep_wake(QemuCoSleep *w);
209
+ bool sesparse;
66
210
+ uint64_t sesparse_l2_tables_offset;
67
/**
211
+ uint64_t sesparse_clusters_offset;
68
* Yield until a file descriptor becomes readable
212
+ int32_t entry_size;
69
diff --git a/block/block-copy.c b/block/block-copy.c
213
int version;
70
index XXXXXXX..XXXXXXX 100644
214
int64_t sectors;
71
--- a/block/block-copy.c
215
int64_t end_sector;
72
+++ b/block/block-copy.c
216
int64_t flat_start_offset;
73
@@ -XXX,XX +XXX,XX @@ typedef struct BlockCopyCallState {
217
int64_t l1_table_offset;
74
/* State */
218
int64_t l1_backup_table_offset;
75
int ret;
219
- uint32_t *l1_table;
76
bool finished;
220
+ void *l1_table;
77
- QemuCoSleepState *sleep_state;
221
uint32_t *l1_backup_table;
78
+ QemuCoSleep sleep;
222
unsigned int l1_size;
79
bool cancelled;
223
uint32_t l1_entry_sectors;
80
224
81
/* OUT parameters */
225
unsigned int l2_size;
82
@@ -XXX,XX +XXX,XX @@ block_copy_dirty_clusters(BlockCopyCallState *call_state)
226
- uint32_t *l2_cache;
83
if (ns > 0) {
227
+ void *l2_cache;
84
block_copy_task_end(task, -EAGAIN);
228
uint32_t l2_cache_offsets[L2_CACHE_SIZE];
85
g_free(task);
229
uint32_t l2_cache_counts[L2_CACHE_SIZE];
86
- qemu_co_sleep_ns_wakeable(QEMU_CLOCK_REALTIME, ns,
230
87
- &call_state->sleep_state);
231
@@ -XXX,XX +XXX,XX @@ static int vmdk_add_extent(BlockDriverState *bs,
88
+ qemu_co_sleep_ns_wakeable(&call_state->sleep,
232
* minimal L2 table size: 512 entries
89
+ QEMU_CLOCK_REALTIME, ns);
233
* 8 TB is still more than the maximal value supported for
90
continue;
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;
289
}
290
291
+#define SESPARSE_CONST_HEADER_MAGIC UINT64_C(0x00000000cafebabe)
292
+#define SESPARSE_VOLATILE_HEADER_MAGIC UINT64_C(0x00000000cafecafe)
293
+
294
+/* Strict checks - format not officially documented */
295
+static int check_se_sparse_const_header(VMDKSESparseConstHeader *header,
296
+ Error **errp)
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);
336
+ return -EINVAL;
337
+ }
338
+
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
+
379
+ return 0;
380
+}
381
+
382
+static int check_se_sparse_volatile_header(VMDKSESparseVolatileHeader *header,
383
+ Error **errp)
384
+{
385
+ header->magic = le64_to_cpu(header->magic);
386
+ header->free_gt_number = le64_to_cpu(header->free_gt_number);
387
+ header->next_txn_seq_number = le64_to_cpu(header->next_txn_seq_number);
388
+ header->replay_journal = le64_to_cpu(header->replay_journal);
389
+
390
+ if (header->magic != SESPARSE_VOLATILE_HEADER_MAGIC) {
391
+ error_setg(errp, "Bad volatile header magic: 0x%016" PRIx64,
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);
421
+ if (ret < 0) {
422
+ return ret;
423
+ }
424
+
425
+ assert(sizeof(const_header) == SECTOR_SIZE);
426
+
427
+ ret = bdrv_pread(file, 0, &const_header, sizeof(const_header));
428
+ if (ret < 0) {
429
+ bdrv_refresh_filename(file->bs);
430
+ error_setg_errno(errp, -ret,
431
+ "Could not read const header from file '%s'",
432
+ file->bs->filename);
433
+ return ret;
434
+ }
435
+
436
+ /* check const header */
437
+ ret = check_se_sparse_const_header(&const_header, errp);
438
+ if (ret < 0) {
439
+ return ret;
440
+ }
441
+
442
+ assert(sizeof(volatile_header) == SECTOR_SIZE);
443
+
444
+ ret = bdrv_pread(file,
445
+ const_header.volatile_header_offset * SECTOR_SIZE,
446
+ &volatile_header, sizeof(volatile_header));
447
+ if (ret < 0) {
448
+ bdrv_refresh_filename(file->bs);
449
+ error_setg_errno(errp, -ret,
450
+ "Could not read volatile header from file '%s'",
451
+ file->bs->filename);
452
+ return ret;
453
+ }
454
+
455
+ /* check volatile header */
456
+ ret = check_se_sparse_volatile_header(&volatile_header, errp);
457
+ if (ret < 0) {
458
+ return ret;
459
+ }
460
+
461
+ ret = vmdk_add_extent(bs, file, false,
462
+ const_header.capacity,
463
+ const_header.grain_dir_offset * SECTOR_SIZE,
464
+ 0,
465
+ const_header.grain_dir_size *
466
+ SECTOR_SIZE / sizeof(uint64_t),
467
+ const_header.grain_table_size *
468
+ SECTOR_SIZE / sizeof(uint64_t),
469
+ const_header.grain_size,
470
+ &extent,
471
+ errp);
472
+ if (ret < 0) {
473
+ return ret;
474
+ }
475
+
476
+ extent->sesparse = true;
477
+ extent->sesparse_l2_tables_offset = const_header.grain_tables_offset;
478
+ extent->sesparse_clusters_offset = const_header.grains_offset;
479
+ extent->entry_size = sizeof(uint64_t);
480
+
481
+ ret = vmdk_init_tables(bs, extent, errp);
482
+ if (ret) {
483
+ /* free extent allocated by vmdk_add_extent */
484
+ vmdk_free_last_extent(bs);
485
+ }
486
+
487
+ return ret;
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);
577
+ }
578
+ } else {
579
+ assert(extent->entry_size == sizeof(uint32_t));
580
+ l2_offset = ((uint32_t *)extent->l1_table)[l1_index];
581
+ }
582
if (!l2_offset) {
583
return VMDK_UNALLOC;
584
}
585
@@ -XXX,XX +XXX,XX @@ static int get_cluster_offset(BlockDriverState *bs,
586
extent->l2_cache_counts[j] >>= 1;
587
}
91
}
588
}
92
}
589
- l2_table = extent->l2_cache + (i * extent->l2_size);
93
@@ -XXX,XX +XXX,XX @@ out:
590
+ l2_table = (char *)extent->l2_cache + (i * l2_size_bytes);
94
591
goto found;
95
void block_copy_kick(BlockCopyCallState *call_state)
592
}
96
{
97
- qemu_co_sleep_wake(call_state->sleep_state);
98
+ qemu_co_sleep_wake(&call_state->sleep);
99
}
100
101
/*
102
diff --git a/block/nbd.c b/block/nbd.c
103
index XXXXXXX..XXXXXXX 100644
104
--- a/block/nbd.c
105
+++ b/block/nbd.c
106
@@ -XXX,XX +XXX,XX @@ typedef struct BDRVNBDState {
107
CoQueue free_sema;
108
Coroutine *connection_co;
109
Coroutine *teardown_co;
110
- QemuCoSleepState *connection_co_sleep_ns_state;
111
+ QemuCoSleep reconnect_sleep;
112
bool drained;
113
bool wait_drained_end;
114
int in_flight;
115
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn nbd_client_co_drain_begin(BlockDriverState *bs)
116
BDRVNBDState *s = (BDRVNBDState *)bs->opaque;
117
118
s->drained = true;
119
- qemu_co_sleep_wake(s->connection_co_sleep_ns_state);
120
+ qemu_co_sleep_wake(&s->reconnect_sleep);
121
122
nbd_co_establish_connection_cancel(bs, false);
123
124
@@ -XXX,XX +XXX,XX @@ static void nbd_teardown_connection(BlockDriverState *bs)
125
126
s->state = NBD_CLIENT_QUIT;
127
if (s->connection_co) {
128
- qemu_co_sleep_wake(s->connection_co_sleep_ns_state);
129
+ qemu_co_sleep_wake(&s->reconnect_sleep);
130
nbd_co_establish_connection_cancel(bs, true);
593
}
131
}
594
@@ -XXX,XX +XXX,XX @@ static int get_cluster_offset(BlockDriverState *bs,
132
if (qemu_in_coroutine()) {
595
min_index = i;
133
@@ -XXX,XX +XXX,XX @@ static coroutine_fn void nbd_co_reconnect_loop(BDRVNBDState *s)
596
}
134
}
135
bdrv_inc_in_flight(s->bs);
136
} else {
137
- qemu_co_sleep_ns_wakeable(QEMU_CLOCK_REALTIME, timeout,
138
- &s->connection_co_sleep_ns_state);
139
+ qemu_co_sleep_ns_wakeable(&s->reconnect_sleep,
140
+ QEMU_CLOCK_REALTIME, timeout);
141
if (s->drained) {
142
continue;
143
}
144
diff --git a/util/qemu-coroutine-sleep.c b/util/qemu-coroutine-sleep.c
145
index XXXXXXX..XXXXXXX 100644
146
--- a/util/qemu-coroutine-sleep.c
147
+++ b/util/qemu-coroutine-sleep.c
148
@@ -XXX,XX +XXX,XX @@
149
150
static const char *qemu_co_sleep_ns__scheduled = "qemu_co_sleep_ns";
151
152
-struct QemuCoSleepState {
153
+void qemu_co_sleep_wake(QemuCoSleep *w)
154
+{
155
Coroutine *co;
156
- QemuCoSleepState **user_state_pointer;
157
-};
158
159
-void qemu_co_sleep_wake(QemuCoSleepState *sleep_state)
160
-{
161
- if (sleep_state) {
162
+ co = w->to_wake;
163
+ w->to_wake = NULL;
164
+ if (co) {
165
/* Write of schedule protected by barrier write in aio_co_schedule */
166
- const char *scheduled = qatomic_cmpxchg(&sleep_state->co->scheduled,
167
+ const char *scheduled = qatomic_cmpxchg(&co->scheduled,
168
qemu_co_sleep_ns__scheduled, NULL);
169
170
assert(scheduled == qemu_co_sleep_ns__scheduled);
171
- *sleep_state->user_state_pointer = NULL;
172
- aio_co_wake(sleep_state->co);
173
+ aio_co_wake(co);
597
}
174
}
598
- l2_table = extent->l2_cache + (min_index * extent->l2_size);
175
}
599
+ l2_table = (char *)extent->l2_cache + (min_index * l2_size_bytes);
176
600
BLKDBG_EVENT(extent->file, BLKDBG_L2_LOAD);
177
static void co_sleep_cb(void *opaque)
601
if (bdrv_pread(extent->file,
178
{
602
(int64_t)l2_offset * 512,
179
- QemuCoSleepState **sleep_state = opaque;
603
l2_table,
180
- qemu_co_sleep_wake(*sleep_state);
604
- extent->l2_size * sizeof(uint32_t)
181
+ QemuCoSleep *w = opaque;
605
- ) != extent->l2_size * sizeof(uint32_t)) {
182
+ qemu_co_sleep_wake(w);
606
+ l2_size_bytes
183
}
607
+ ) != l2_size_bytes) {
184
608
return VMDK_ERROR;
185
-void coroutine_fn qemu_co_sleep_ns_wakeable(QEMUClockType type, int64_t ns,
186
- QemuCoSleepState **sleep_state)
187
+void coroutine_fn qemu_co_sleep_ns_wakeable(QemuCoSleep *w,
188
+ QEMUClockType type, int64_t ns)
189
{
190
+ Coroutine *co = qemu_coroutine_self();
191
AioContext *ctx = qemu_get_current_aio_context();
192
QEMUTimer ts;
193
- QemuCoSleepState state = {
194
- .co = qemu_coroutine_self(),
195
- .user_state_pointer = sleep_state,
196
- };
197
198
- const char *scheduled = qatomic_cmpxchg(&state.co->scheduled, NULL,
199
- qemu_co_sleep_ns__scheduled);
200
+ const char *scheduled = qatomic_cmpxchg(&co->scheduled, NULL,
201
+ qemu_co_sleep_ns__scheduled);
202
if (scheduled) {
203
fprintf(stderr,
204
"%s: Co-routine was already scheduled in '%s'\n",
205
@@ -XXX,XX +XXX,XX @@ void coroutine_fn qemu_co_sleep_ns_wakeable(QEMUClockType type, int64_t ns,
206
abort();
609
}
207
}
610
208
611
@@ -XXX,XX +XXX,XX @@ static int get_cluster_offset(BlockDriverState *bs,
209
- aio_timer_init(ctx, &ts, type, SCALE_NS, co_sleep_cb, sleep_state);
612
extent->l2_cache_counts[min_index] = 1;
210
- *sleep_state = &state;
613
found:
211
+ w->to_wake = co;
614
l2_index = ((offset >> 9) / extent->cluster_sectors) % extent->l2_size;
212
+ aio_timer_init(ctx, &ts, type, SCALE_NS, co_sleep_cb, w),
615
- cluster_sector = le32_to_cpu(l2_table[l2_index]);
213
timer_mod(&ts, qemu_clock_get_ns(type) + ns);
616
214
qemu_coroutine_yield();
617
- if (extent->has_zero_grain && cluster_sector == VMDK_GTE_ZEROED) {
215
timer_del(&ts);
618
- zeroed = true;
216
619
+ if (extent->sesparse) {
217
- /* qemu_co_sleep_wake clears *sleep_state before resuming this coroutine. */
620
+ cluster_sector = le64_to_cpu(((uint64_t *)l2_table)[l2_index]);
218
- assert(*sleep_state == NULL);
621
+ switch (cluster_sector & 0xf000000000000000) {
219
+ /* w->to_wake is cleared before resuming this coroutine. */
622
+ case 0x0000000000000000:
220
+ assert(w->to_wake == NULL);
623
+ /* unallocated grain */
221
}
624
+ if (cluster_sector != 0) {
625
+ return VMDK_ERROR;
626
+ }
627
+ break;
628
+ case 0x1000000000000000:
629
+ /* scsi-unmapped grain - fallthrough */
630
+ case 0x2000000000000000:
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;
643
+ }
644
+ } else {
645
+ cluster_sector = le32_to_cpu(((uint32_t *)l2_table)[l2_index]);
646
+
647
+ if (extent->has_zero_grain && cluster_sector == VMDK_GTE_ZEROED) {
648
+ zeroed = true;
649
+ }
650
}
651
652
if (!cluster_sector || zeroed) {
653
if (!allocate) {
654
return zeroed ? VMDK_ZEROED : VMDK_UNALLOC;
655
}
656
+ assert(!extent->sesparse);
657
658
if (extent->next_cluster_sector >= VMDK_EXTENT_MAX_SECTORS) {
659
return VMDK_ERROR;
660
@@ -XXX,XX +XXX,XX @@ static int get_cluster_offset(BlockDriverState *bs,
661
m_data->l1_index = l1_index;
662
m_data->l2_index = l2_index;
663
m_data->l2_offset = l2_offset;
664
- m_data->l2_cache_entry = &l2_table[l2_index];
665
+ m_data->l2_cache_entry = ((uint32_t *)l2_table) + l2_index;
666
}
667
}
668
*cluster_offset = cluster_sector << BDRV_SECTOR_BITS;
669
@@ -XXX,XX +XXX,XX @@ static int vmdk_pwritev(BlockDriverState *bs, uint64_t offset,
670
if (!extent) {
671
return -EIO;
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);
679
--
222
--
680
2.21.0
223
2.31.1
681
224
682
diff view generated by jsdifflib
1
From: Klaus Birkelund Jensen <klaus@birkelund.eu>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
The device mistakenly reports that the Weighted Round Robin with Urgent
3
Allow using QemuCoSleep to sleep forever until woken by qemu_co_sleep_wake.
4
Priority Class arbitration mechanism is supported.
4
This makes the logic of qemu_co_sleep_ns_wakeable easy to understand.
5
5
6
It is not.
6
In the future we will introduce an API that can work even if the
7
sleep and wake happen from different threads. For now, initializing
8
w->to_wake after timer_mod is fine because the timer can only fire in
9
the same AioContext.
7
10
8
Signed-off-by: Klaus Birkelund Jensen <klaus.jensen@cnexlabs.com>
11
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
9
Message-id: 20190606092530.14206-1-klaus@birkelund.eu
12
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
10
Acked-by: Maxim Levitsky <mlevitsk@redhat.com>
13
Message-id: 20210517100548.28806-7-pbonzini@redhat.com
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
14
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
12
---
15
---
13
hw/block/nvme.c | 1 -
16
include/qemu/coroutine.h | 5 +++++
14
1 file changed, 1 deletion(-)
17
util/qemu-coroutine-sleep.c | 26 +++++++++++++++++++-------
18
2 files changed, 24 insertions(+), 7 deletions(-)
15
19
16
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
20
diff --git a/include/qemu/coroutine.h b/include/qemu/coroutine.h
17
index XXXXXXX..XXXXXXX 100644
21
index XXXXXXX..XXXXXXX 100644
18
--- a/hw/block/nvme.c
22
--- a/include/qemu/coroutine.h
19
+++ b/hw/block/nvme.c
23
+++ b/include/qemu/coroutine.h
20
@@ -XXX,XX +XXX,XX @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp)
24
@@ -XXX,XX +XXX,XX @@ typedef struct QemuCoSleep {
21
n->bar.cap = 0;
25
void coroutine_fn qemu_co_sleep_ns_wakeable(QemuCoSleep *w,
22
NVME_CAP_SET_MQES(n->bar.cap, 0x7ff);
26
QEMUClockType type, int64_t ns);
23
NVME_CAP_SET_CQR(n->bar.cap, 1);
27
24
- NVME_CAP_SET_AMS(n->bar.cap, 1);
28
+/**
25
NVME_CAP_SET_TO(n->bar.cap, 0xf);
29
+ * Yield the coroutine until the next call to qemu_co_sleep_wake.
26
NVME_CAP_SET_CSS(n->bar.cap, 1);
30
+ */
27
NVME_CAP_SET_MPSMAX(n->bar.cap, 4);
31
+void coroutine_fn qemu_co_sleep(QemuCoSleep *w);
32
+
33
static inline void coroutine_fn qemu_co_sleep_ns(QEMUClockType type, int64_t ns)
34
{
35
QemuCoSleep w = { 0 };
36
diff --git a/util/qemu-coroutine-sleep.c b/util/qemu-coroutine-sleep.c
37
index XXXXXXX..XXXXXXX 100644
38
--- a/util/qemu-coroutine-sleep.c
39
+++ b/util/qemu-coroutine-sleep.c
40
@@ -XXX,XX +XXX,XX @@ static void co_sleep_cb(void *opaque)
41
qemu_co_sleep_wake(w);
42
}
43
44
-void coroutine_fn qemu_co_sleep_ns_wakeable(QemuCoSleep *w,
45
- QEMUClockType type, int64_t ns)
46
+void coroutine_fn qemu_co_sleep(QemuCoSleep *w)
47
{
48
Coroutine *co = qemu_coroutine_self();
49
- AioContext *ctx = qemu_get_current_aio_context();
50
- QEMUTimer ts;
51
52
const char *scheduled = qatomic_cmpxchg(&co->scheduled, NULL,
53
qemu_co_sleep_ns__scheduled);
54
@@ -XXX,XX +XXX,XX @@ void coroutine_fn qemu_co_sleep_ns_wakeable(QemuCoSleep *w,
55
}
56
57
w->to_wake = co;
58
- aio_timer_init(ctx, &ts, type, SCALE_NS, co_sleep_cb, w),
59
- timer_mod(&ts, qemu_clock_get_ns(type) + ns);
60
qemu_coroutine_yield();
61
- timer_del(&ts);
62
63
/* w->to_wake is cleared before resuming this coroutine. */
64
assert(w->to_wake == NULL);
65
}
66
+
67
+void coroutine_fn qemu_co_sleep_ns_wakeable(QemuCoSleep *w,
68
+ QEMUClockType type, int64_t ns)
69
+{
70
+ AioContext *ctx = qemu_get_current_aio_context();
71
+ QEMUTimer ts;
72
+
73
+ aio_timer_init(ctx, &ts, type, SCALE_NS, co_sleep_cb, w);
74
+ timer_mod(&ts, qemu_clock_get_ns(type) + ns);
75
+
76
+ /*
77
+ * The timer will fire in the current AiOContext, so the callback
78
+ * must happen after qemu_co_sleep yields and there is no race
79
+ * between timer_mod and qemu_co_sleep.
80
+ */
81
+ qemu_co_sleep(w);
82
+ timer_del(&ts);
83
+}
28
--
84
--
29
2.21.0
85
2.31.1
30
86
31
diff view generated by jsdifflib