1 | The following changes since commit 33d609990621dea6c7d056c86f707b8811320ac1: | 1 | The following changes since commit 474f3938d79ab36b9231c9ad3b5a9314c2aeacde: |
---|---|---|---|
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/amarkovic/tags/mips-queue-jun-21-2019' into staging (2019-06-21 15:40:50 +0100) |
4 | 4 | ||
5 | are available in the Git repository at: | 5 | are available in the Git repository at: |
6 | 6 | ||
7 | https://github.com/XanClic/qemu.git tags/pull-block-2019-06-21 | 7 | https://github.com/XanClic/qemu.git tags/pull-block-2019-06-24 |
8 | 8 | ||
9 | for you to fetch changes up to e2a76186f7948b8b75d1b2b52638de7c2f7f7472: | 9 | for you to fetch changes up to ab5d4a30f7f3803ca5106b370969c1b7b54136f8: |
10 | 10 | ||
11 | iotests: Fix 205 for concurrent runs (2019-06-21 14:40:28 +0200) | 11 | iotests: Fix 205 for concurrent runs (2019-06-24 16:01:40 +0200) |
12 | 12 | ||
13 | ---------------------------------------------------------------- | 13 | ---------------------------------------------------------------- |
14 | Block patches: | 14 | Block patches: |
15 | - The SSH block driver now uses libssh instead of libssh2 | 15 | - The SSH block driver now uses libssh instead of libssh2 |
16 | - The VMDK block driver gets read-only support for the seSparse | 16 | - The VMDK block driver gets read-only support for the seSparse |
17 | subformat | 17 | subformat |
18 | - Various fixes | 18 | - Various fixes |
19 | |||
20 | --- | ||
21 | |||
22 | v2: | ||
23 | - Squashed Pino's fix for pre-0.8 libssh into the libssh patch | ||
19 | 24 | ||
20 | ---------------------------------------------------------------- | 25 | ---------------------------------------------------------------- |
21 | Anton Nefedov (1): | 26 | Anton Nefedov (1): |
22 | iotest 134: test cluster-misaligned encrypted write | 27 | iotest 134: test cluster-misaligned encrypted write |
23 | 28 | ||
... | ... | ||
38 | Vladimir Sementsov-Ogievskiy (1): | 43 | Vladimir Sementsov-Ogievskiy (1): |
39 | blockdev: enable non-root nodes for transaction drive-backup source | 44 | blockdev: enable non-root nodes for transaction drive-backup source |
40 | 45 | ||
41 | configure | 65 +- | 46 | configure | 65 +- |
42 | block/Makefile.objs | 6 +- | 47 | block/Makefile.objs | 6 +- |
43 | block/ssh.c | 673 ++++++++++-------- | 48 | block/ssh.c | 652 ++++++++++-------- |
44 | block/vmdk.c | 372 +++++++++- | 49 | block/vmdk.c | 372 +++++++++- |
45 | blockdev.c | 2 +- | 50 | blockdev.c | 2 +- |
46 | hw/block/nvme.c | 1 - | 51 | hw/block/nvme.c | 1 - |
47 | .travis.yml | 4 +- | 52 | .travis.yml | 4 +- |
48 | block/trace-events | 14 +- | 53 | block/trace-events | 14 +- |
... | ... | ||
56 | tests/qemu-iotests/134 | 9 + | 61 | tests/qemu-iotests/134 | 9 + |
57 | tests/qemu-iotests/134.out | 10 + | 62 | tests/qemu-iotests/134.out | 10 + |
58 | tests/qemu-iotests/205 | 2 +- | 63 | tests/qemu-iotests/205 | 2 +- |
59 | tests/qemu-iotests/207 | 54 +- | 64 | tests/qemu-iotests/207 | 54 +- |
60 | tests/qemu-iotests/207.out | 2 +- | 65 | tests/qemu-iotests/207.out | 2 +- |
61 | 20 files changed, 844 insertions(+), 384 deletions(-) | 66 | 20 files changed, 823 insertions(+), 384 deletions(-) |
62 | 67 | ||
63 | -- | 68 | -- |
64 | 2.21.0 | 69 | 2.21.0 |
65 | 70 | ||
66 | 71 | diff view generated by jsdifflib |
1 | From: Klaus Birkelund Jensen <klaus@birkelund.eu> | 1 | From: Klaus Birkelund Jensen <klaus@birkelund.eu> |
---|---|---|---|
2 | 2 | ||
3 | The device mistakenly reports that the Weighted Round Robin with Urgent | 3 | The device mistakenly reports that the Weighted Round Robin with Urgent |
4 | Priority Class arbitration mechanism is supported. | 4 | Priority Class arbitration mechanism is supported. |
5 | 5 | ||
6 | It is not. | 6 | It is not. |
7 | 7 | ||
8 | Signed-off-by: Klaus Birkelund Jensen <klaus.jensen@cnexlabs.com> | 8 | Signed-off-by: Klaus Birkelund Jensen <klaus.jensen@cnexlabs.com> |
9 | Message-id: 20190606092530.14206-1-klaus@birkelund.eu | 9 | Message-id: 20190606092530.14206-1-klaus@birkelund.eu |
10 | Acked-by: Maxim Levitsky <mlevitsk@redhat.com> | 10 | Acked-by: Maxim Levitsky <mlevitsk@redhat.com> |
11 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 11 | Signed-off-by: Max Reitz <mreitz@redhat.com> |
12 | --- | 12 | --- |
13 | hw/block/nvme.c | 1 - | 13 | hw/block/nvme.c | 1 - |
14 | 1 file changed, 1 deletion(-) | 14 | 1 file changed, 1 deletion(-) |
15 | 15 | ||
16 | diff --git a/hw/block/nvme.c b/hw/block/nvme.c | 16 | diff --git a/hw/block/nvme.c b/hw/block/nvme.c |
17 | index XXXXXXX..XXXXXXX 100644 | 17 | index XXXXXXX..XXXXXXX 100644 |
18 | --- a/hw/block/nvme.c | 18 | --- a/hw/block/nvme.c |
19 | +++ b/hw/block/nvme.c | 19 | +++ b/hw/block/nvme.c |
20 | @@ -XXX,XX +XXX,XX @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp) | 20 | @@ -XXX,XX +XXX,XX @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp) |
21 | n->bar.cap = 0; | 21 | n->bar.cap = 0; |
22 | NVME_CAP_SET_MQES(n->bar.cap, 0x7ff); | 22 | NVME_CAP_SET_MQES(n->bar.cap, 0x7ff); |
23 | NVME_CAP_SET_CQR(n->bar.cap, 1); | 23 | NVME_CAP_SET_CQR(n->bar.cap, 1); |
24 | - NVME_CAP_SET_AMS(n->bar.cap, 1); | 24 | - NVME_CAP_SET_AMS(n->bar.cap, 1); |
25 | NVME_CAP_SET_TO(n->bar.cap, 0xf); | 25 | NVME_CAP_SET_TO(n->bar.cap, 0xf); |
26 | NVME_CAP_SET_CSS(n->bar.cap, 1); | 26 | NVME_CAP_SET_CSS(n->bar.cap, 1); |
27 | NVME_CAP_SET_MPSMAX(n->bar.cap, 4); | 27 | NVME_CAP_SET_MPSMAX(n->bar.cap, 4); |
28 | -- | 28 | -- |
29 | 2.21.0 | 29 | 2.21.0 |
30 | 30 | ||
31 | 31 | diff view generated by jsdifflib |
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> |
---|---|---|---|
2 | 2 | ||
3 | We forget to enable it for transaction .prepare, while it is already | 3 | We forget to enable it for transaction .prepare, while it is already |
4 | enabled in do_drive_backup since commit a2d665c1bc362 | 4 | enabled in do_drive_backup since commit a2d665c1bc362 |
5 | "blockdev: loosen restrictions on drive-backup source node" | 5 | "blockdev: loosen restrictions on drive-backup source node" |
6 | 6 | ||
7 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 7 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> |
8 | Message-id: 20190618140804.59214-1-vsementsov@virtuozzo.com | 8 | Message-id: 20190618140804.59214-1-vsementsov@virtuozzo.com |
9 | Reviewed-by: John Snow <jsnow@redhat.com> | 9 | Reviewed-by: John Snow <jsnow@redhat.com> |
10 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 10 | Signed-off-by: Max Reitz <mreitz@redhat.com> |
11 | --- | 11 | --- |
12 | blockdev.c | 2 +- | 12 | blockdev.c | 2 +- |
13 | 1 file changed, 1 insertion(+), 1 deletion(-) | 13 | 1 file changed, 1 insertion(+), 1 deletion(-) |
14 | 14 | ||
15 | diff --git a/blockdev.c b/blockdev.c | 15 | diff --git a/blockdev.c b/blockdev.c |
16 | index XXXXXXX..XXXXXXX 100644 | 16 | index XXXXXXX..XXXXXXX 100644 |
17 | --- a/blockdev.c | 17 | --- a/blockdev.c |
18 | +++ b/blockdev.c | 18 | +++ b/blockdev.c |
19 | @@ -XXX,XX +XXX,XX @@ static void drive_backup_prepare(BlkActionState *common, Error **errp) | 19 | @@ -XXX,XX +XXX,XX @@ static void drive_backup_prepare(BlkActionState *common, Error **errp) |
20 | assert(common->action->type == TRANSACTION_ACTION_KIND_DRIVE_BACKUP); | 20 | assert(common->action->type == TRANSACTION_ACTION_KIND_DRIVE_BACKUP); |
21 | backup = common->action->u.drive_backup.data; | 21 | backup = common->action->u.drive_backup.data; |
22 | 22 | ||
23 | - bs = qmp_get_root_bs(backup->device, errp); | 23 | - bs = qmp_get_root_bs(backup->device, errp); |
24 | + bs = bdrv_lookup_bs(backup->device, backup->device, errp); | 24 | + bs = bdrv_lookup_bs(backup->device, backup->device, errp); |
25 | if (!bs) { | 25 | if (!bs) { |
26 | return; | 26 | return; |
27 | } | 27 | } |
28 | -- | 28 | -- |
29 | 2.21.0 | 29 | 2.21.0 |
30 | 30 | ||
31 | 31 | diff view generated by jsdifflib |
1 | From: Anton Nefedov <anton.nefedov@virtuozzo.com> | 1 | From: Anton Nefedov <anton.nefedov@virtuozzo.com> |
---|---|---|---|
2 | 2 | ||
3 | COW (even empty/zero) areas require encryption too | 3 | COW (even empty/zero) areas require encryption too |
4 | 4 | ||
5 | Signed-off-by: Anton Nefedov <anton.nefedov@virtuozzo.com> | 5 | Signed-off-by: Anton Nefedov <anton.nefedov@virtuozzo.com> |
6 | Reviewed-by: Eric Blake <eblake@redhat.com> | 6 | Reviewed-by: Eric Blake <eblake@redhat.com> |
7 | Reviewed-by: Max Reitz <mreitz@redhat.com> | 7 | Reviewed-by: Max Reitz <mreitz@redhat.com> |
8 | Reviewed-by: Alberto Garcia <berto@igalia.com> | 8 | Reviewed-by: Alberto Garcia <berto@igalia.com> |
9 | Message-id: 20190516143028.81155-1-anton.nefedov@virtuozzo.com | 9 | Message-id: 20190516143028.81155-1-anton.nefedov@virtuozzo.com |
10 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 10 | Signed-off-by: Max Reitz <mreitz@redhat.com> |
11 | --- | 11 | --- |
12 | tests/qemu-iotests/134 | 9 +++++++++ | 12 | tests/qemu-iotests/134 | 9 +++++++++ |
13 | tests/qemu-iotests/134.out | 10 ++++++++++ | 13 | tests/qemu-iotests/134.out | 10 ++++++++++ |
14 | 2 files changed, 19 insertions(+) | 14 | 2 files changed, 19 insertions(+) |
15 | 15 | ||
16 | diff --git a/tests/qemu-iotests/134 b/tests/qemu-iotests/134 | 16 | diff --git a/tests/qemu-iotests/134 b/tests/qemu-iotests/134 |
17 | index XXXXXXX..XXXXXXX 100755 | 17 | index XXXXXXX..XXXXXXX 100755 |
18 | --- a/tests/qemu-iotests/134 | 18 | --- a/tests/qemu-iotests/134 |
19 | +++ b/tests/qemu-iotests/134 | 19 | +++ b/tests/qemu-iotests/134 |
20 | @@ -XXX,XX +XXX,XX @@ echo | 20 | @@ -XXX,XX +XXX,XX @@ echo |
21 | echo "== reading whole image ==" | 21 | echo "== reading whole image ==" |
22 | $QEMU_IO --object $SECRET -c "read 0 $size" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir | 22 | $QEMU_IO --object $SECRET -c "read 0 $size" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir |
23 | 23 | ||
24 | +echo | 24 | +echo |
25 | +echo "== rewriting cluster part ==" | 25 | +echo "== rewriting cluster part ==" |
26 | +$QEMU_IO --object $SECRET -c "write -P 0xb 512 512" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir | 26 | +$QEMU_IO --object $SECRET -c "write -P 0xb 512 512" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir |
27 | + | 27 | + |
28 | +echo | 28 | +echo |
29 | +echo "== verify pattern ==" | 29 | +echo "== verify pattern ==" |
30 | +$QEMU_IO --object $SECRET -c "read -P 0 0 512" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir | 30 | +$QEMU_IO --object $SECRET -c "read -P 0 0 512" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir |
31 | +$QEMU_IO --object $SECRET -c "read -P 0xb 512 512" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir | 31 | +$QEMU_IO --object $SECRET -c "read -P 0xb 512 512" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir |
32 | + | 32 | + |
33 | echo | 33 | echo |
34 | echo "== rewriting whole image ==" | 34 | echo "== rewriting whole image ==" |
35 | $QEMU_IO --object $SECRET -c "write -P 0xa 0 $size" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir | 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 | 36 | diff --git a/tests/qemu-iotests/134.out b/tests/qemu-iotests/134.out |
37 | index XXXXXXX..XXXXXXX 100644 | 37 | index XXXXXXX..XXXXXXX 100644 |
38 | --- a/tests/qemu-iotests/134.out | 38 | --- a/tests/qemu-iotests/134.out |
39 | +++ b/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. | 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 | 41 | read 134217728/134217728 bytes at offset 0 |
42 | 128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | 42 | 128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) |
43 | 43 | ||
44 | +== rewriting cluster part == | 44 | +== rewriting cluster part == |
45 | +wrote 512/512 bytes at offset 512 | 45 | +wrote 512/512 bytes at offset 512 |
46 | +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | 46 | +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) |
47 | + | 47 | + |
48 | +== verify pattern == | 48 | +== verify pattern == |
49 | +read 512/512 bytes at offset 0 | 49 | +read 512/512 bytes at offset 0 |
50 | +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | 50 | +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) |
51 | +read 512/512 bytes at offset 512 | 51 | +read 512/512 bytes at offset 512 |
52 | +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | 52 | +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) |
53 | + | 53 | + |
54 | == rewriting whole image == | 54 | == rewriting whole image == |
55 | wrote 134217728/134217728 bytes at offset 0 | 55 | wrote 134217728/134217728 bytes at offset 0 |
56 | 128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | 56 | 128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) |
57 | -- | 57 | -- |
58 | 2.21.0 | 58 | 2.21.0 |
59 | 59 | ||
60 | 60 | diff view generated by jsdifflib |
1 | From: Sam Eiderman <shmuel.eiderman@oracle.com> | 1 | From: Sam Eiderman <shmuel.eiderman@oracle.com> |
---|---|---|---|
2 | 2 | ||
3 | Commit b0651b8c246d ("vmdk: Move l1_size check into vmdk_add_extent") | 3 | Commit b0651b8c246d ("vmdk: Move l1_size check into vmdk_add_extent") |
4 | extended the l1_size check from VMDK4 to VMDK3 but did not update the | 4 | extended the l1_size check from VMDK4 to VMDK3 but did not update the |
5 | default coverage in the moved comment. | 5 | default coverage in the moved comment. |
6 | 6 | ||
7 | The previous vmdk4 calculation: | 7 | The previous vmdk4 calculation: |
8 | 8 | ||
9 | (512 * 1024 * 1024) * 512(l2 entries) * 65536(grain) = 16PB | 9 | (512 * 1024 * 1024) * 512(l2 entries) * 65536(grain) = 16PB |
10 | 10 | ||
11 | The added vmdk3 calculation: | 11 | The added vmdk3 calculation: |
12 | 12 | ||
13 | (512 * 1024 * 1024) * 4096(l2 entries) * 512(grain) = 1PB | 13 | (512 * 1024 * 1024) * 4096(l2 entries) * 512(grain) = 1PB |
14 | 14 | ||
15 | Adding the calculation of vmdk3 to the comment. | 15 | Adding the calculation of vmdk3 to the comment. |
16 | 16 | ||
17 | In any case, VMware does not offer virtual disks more than 2TB for | 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 | 18 | vmdk4/vmdk3 or 64TB for the new undocumented seSparse format which is |
19 | not implemented yet in qemu. | 19 | not implemented yet in qemu. |
20 | 20 | ||
21 | Reviewed-by: Karl Heubaum <karl.heubaum@oracle.com> | 21 | Reviewed-by: Karl Heubaum <karl.heubaum@oracle.com> |
22 | Reviewed-by: Eyal Moscovici <eyal.moscovici@oracle.com> | 22 | Reviewed-by: Eyal Moscovici <eyal.moscovici@oracle.com> |
23 | Reviewed-by: Liran Alon <liran.alon@oracle.com> | 23 | Reviewed-by: Liran Alon <liran.alon@oracle.com> |
24 | Reviewed-by: Arbel Moshe <arbel.moshe@oracle.com> | 24 | Reviewed-by: Arbel Moshe <arbel.moshe@oracle.com> |
25 | Signed-off-by: Sam Eiderman <shmuel.eiderman@oracle.com> | 25 | Signed-off-by: Sam Eiderman <shmuel.eiderman@oracle.com> |
26 | Message-id: 20190620091057.47441-2-shmuel.eiderman@oracle.com | 26 | Message-id: 20190620091057.47441-2-shmuel.eiderman@oracle.com |
27 | Reviewed-by: yuchenlin <yuchenlin@synology.com> | 27 | Reviewed-by: yuchenlin <yuchenlin@synology.com> |
28 | Reviewed-by: Max Reitz <mreitz@redhat.com> | 28 | Reviewed-by: Max Reitz <mreitz@redhat.com> |
29 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 29 | Signed-off-by: Max Reitz <mreitz@redhat.com> |
30 | --- | 30 | --- |
31 | block/vmdk.c | 11 ++++++++--- | 31 | block/vmdk.c | 11 ++++++++--- |
32 | 1 file changed, 8 insertions(+), 3 deletions(-) | 32 | 1 file changed, 8 insertions(+), 3 deletions(-) |
33 | 33 | ||
34 | diff --git a/block/vmdk.c b/block/vmdk.c | 34 | diff --git a/block/vmdk.c b/block/vmdk.c |
35 | index XXXXXXX..XXXXXXX 100644 | 35 | index XXXXXXX..XXXXXXX 100644 |
36 | --- a/block/vmdk.c | 36 | --- a/block/vmdk.c |
37 | +++ b/block/vmdk.c | 37 | +++ b/block/vmdk.c |
38 | @@ -XXX,XX +XXX,XX @@ static int vmdk_add_extent(BlockDriverState *bs, | 38 | @@ -XXX,XX +XXX,XX @@ static int vmdk_add_extent(BlockDriverState *bs, |
39 | return -EFBIG; | 39 | return -EFBIG; |
40 | } | 40 | } |
41 | if (l1_size > 512 * 1024 * 1024) { | 41 | if (l1_size > 512 * 1024 * 1024) { |
42 | - /* Although with big capacity and small l1_entry_sectors, we can get a | 42 | - /* Although with big capacity and small l1_entry_sectors, we can get a |
43 | + /* | 43 | + /* |
44 | + * Although with big capacity and small l1_entry_sectors, we can get a | 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. | 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 | 46 | - * Limit it to 512M, which is 16PB for default cluster and L2 table |
47 | - * size */ | 47 | - * size */ |
48 | + * Limit it to 512M, which is: | 48 | + * Limit it to 512M, which is: |
49 | + * 16PB - for default "Hosted Sparse Extent" (VMDK4) | 49 | + * 16PB - for default "Hosted Sparse Extent" (VMDK4) |
50 | + * cluster size: 64KB, L2 table size: 512 entries | 50 | + * cluster size: 64KB, L2 table size: 512 entries |
51 | + * 1PB - for default "ESXi Host Sparse Extent" (VMDK3/vmfsSparse) | 51 | + * 1PB - for default "ESXi Host Sparse Extent" (VMDK3/vmfsSparse) |
52 | + * cluster size: 512B, L2 table size: 4096 entries | 52 | + * cluster size: 512B, L2 table size: 4096 entries |
53 | + */ | 53 | + */ |
54 | error_setg(errp, "L1 size too big"); | 54 | error_setg(errp, "L1 size too big"); |
55 | return -EFBIG; | 55 | return -EFBIG; |
56 | } | 56 | } |
57 | -- | 57 | -- |
58 | 2.21.0 | 58 | 2.21.0 |
59 | 59 | ||
60 | 60 | diff view generated by jsdifflib |
1 | From: Sam Eiderman <shmuel.eiderman@oracle.com> | 1 | From: Sam Eiderman <shmuel.eiderman@oracle.com> |
---|---|---|---|
2 | 2 | ||
3 | 512M of L1 entries is a very loose bound, only 32M are required to store | 3 | 512M of L1 entries is a very loose bound, only 32M are required to store |
4 | the maximal supported VMDK file size of 2TB. | 4 | the maximal supported VMDK file size of 2TB. |
5 | 5 | ||
6 | Fixed qemu-iotest 59# - now failure occures before on impossible L1 | 6 | Fixed qemu-iotest 59# - now failure occures before on impossible L1 |
7 | table size. | 7 | table size. |
8 | 8 | ||
9 | Reviewed-by: Karl Heubaum <karl.heubaum@oracle.com> | 9 | Reviewed-by: Karl Heubaum <karl.heubaum@oracle.com> |
10 | Reviewed-by: Eyal Moscovici <eyal.moscovici@oracle.com> | 10 | Reviewed-by: Eyal Moscovici <eyal.moscovici@oracle.com> |
11 | Reviewed-by: Liran Alon <liran.alon@oracle.com> | 11 | Reviewed-by: Liran Alon <liran.alon@oracle.com> |
12 | Reviewed-by: Arbel Moshe <arbel.moshe@oracle.com> | 12 | Reviewed-by: Arbel Moshe <arbel.moshe@oracle.com> |
13 | Signed-off-by: Sam Eiderman <shmuel.eiderman@oracle.com> | 13 | Signed-off-by: Sam Eiderman <shmuel.eiderman@oracle.com> |
14 | Message-id: 20190620091057.47441-3-shmuel.eiderman@oracle.com | 14 | Message-id: 20190620091057.47441-3-shmuel.eiderman@oracle.com |
15 | Reviewed-by: Max Reitz <mreitz@redhat.com> | 15 | Reviewed-by: Max Reitz <mreitz@redhat.com> |
16 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 16 | Signed-off-by: Max Reitz <mreitz@redhat.com> |
17 | --- | 17 | --- |
18 | block/vmdk.c | 13 +++++++------ | 18 | block/vmdk.c | 13 +++++++------ |
19 | tests/qemu-iotests/059.out | 2 +- | 19 | tests/qemu-iotests/059.out | 2 +- |
20 | 2 files changed, 8 insertions(+), 7 deletions(-) | 20 | 2 files changed, 8 insertions(+), 7 deletions(-) |
21 | 21 | ||
22 | diff --git a/block/vmdk.c b/block/vmdk.c | 22 | diff --git a/block/vmdk.c b/block/vmdk.c |
23 | index XXXXXXX..XXXXXXX 100644 | 23 | index XXXXXXX..XXXXXXX 100644 |
24 | --- a/block/vmdk.c | 24 | --- a/block/vmdk.c |
25 | +++ b/block/vmdk.c | 25 | +++ b/block/vmdk.c |
26 | @@ -XXX,XX +XXX,XX @@ static int vmdk_add_extent(BlockDriverState *bs, | 26 | @@ -XXX,XX +XXX,XX @@ static int vmdk_add_extent(BlockDriverState *bs, |
27 | error_setg(errp, "Invalid granularity, image may be corrupt"); | 27 | error_setg(errp, "Invalid granularity, image may be corrupt"); |
28 | return -EFBIG; | 28 | return -EFBIG; |
29 | } | 29 | } |
30 | - if (l1_size > 512 * 1024 * 1024) { | 30 | - if (l1_size > 512 * 1024 * 1024) { |
31 | + if (l1_size > 32 * 1024 * 1024) { | 31 | + if (l1_size > 32 * 1024 * 1024) { |
32 | /* | 32 | /* |
33 | * Although with big capacity and small l1_entry_sectors, we can get a | 33 | * Although with big capacity and small l1_entry_sectors, we can get a |
34 | * big l1_size, we don't want unbounded value to allocate the table. | 34 | * big l1_size, we don't want unbounded value to allocate the table. |
35 | - * Limit it to 512M, which is: | 35 | - * Limit it to 512M, which is: |
36 | - * 16PB - for default "Hosted Sparse Extent" (VMDK4) | 36 | - * 16PB - for default "Hosted Sparse Extent" (VMDK4) |
37 | - * cluster size: 64KB, L2 table size: 512 entries | 37 | - * cluster size: 64KB, L2 table size: 512 entries |
38 | - * 1PB - for default "ESXi Host Sparse Extent" (VMDK3/vmfsSparse) | 38 | - * 1PB - for default "ESXi Host Sparse Extent" (VMDK3/vmfsSparse) |
39 | - * cluster size: 512B, L2 table size: 4096 entries | 39 | - * cluster size: 512B, L2 table size: 4096 entries |
40 | + * Limit it to 32M, which is enough to store: | 40 | + * Limit it to 32M, which is enough to store: |
41 | + * 8TB - for both VMDK3 & VMDK4 with | 41 | + * 8TB - for both VMDK3 & VMDK4 with |
42 | + * minimal cluster size: 512B | 42 | + * minimal cluster size: 512B |
43 | + * minimal L2 table size: 512 entries | 43 | + * minimal L2 table size: 512 entries |
44 | + * 8 TB is still more than the maximal value supported for | 44 | + * 8 TB is still more than the maximal value supported for |
45 | + * VMDK3 & VMDK4 which is 2TB. | 45 | + * VMDK3 & VMDK4 which is 2TB. |
46 | */ | 46 | */ |
47 | error_setg(errp, "L1 size too big"); | 47 | error_setg(errp, "L1 size too big"); |
48 | return -EFBIG; | 48 | return -EFBIG; |
49 | diff --git a/tests/qemu-iotests/059.out b/tests/qemu-iotests/059.out | 49 | diff --git a/tests/qemu-iotests/059.out b/tests/qemu-iotests/059.out |
50 | index XXXXXXX..XXXXXXX 100644 | 50 | index XXXXXXX..XXXXXXX 100644 |
51 | --- a/tests/qemu-iotests/059.out | 51 | --- a/tests/qemu-iotests/059.out |
52 | +++ b/tests/qemu-iotests/059.out | 52 | +++ b/tests/qemu-iotests/059.out |
53 | @@ -XXX,XX +XXX,XX @@ Offset Length Mapped to File | 53 | @@ -XXX,XX +XXX,XX @@ Offset Length Mapped to File |
54 | 0x140000000 0x10000 0x50000 TEST_DIR/t-s003.vmdk | 54 | 0x140000000 0x10000 0x50000 TEST_DIR/t-s003.vmdk |
55 | 55 | ||
56 | === Testing afl image with a very large capacity === | 56 | === Testing afl image with a very large capacity === |
57 | -qemu-img: Can't get image size 'TEST_DIR/afl9.IMGFMT': File too large | 57 | -qemu-img: Can't get image size 'TEST_DIR/afl9.IMGFMT': File too large |
58 | +qemu-img: Could not open 'TEST_DIR/afl9.IMGFMT': L1 size too big | 58 | +qemu-img: Could not open 'TEST_DIR/afl9.IMGFMT': L1 size too big |
59 | *** done | 59 | *** done |
60 | -- | 60 | -- |
61 | 2.21.0 | 61 | 2.21.0 |
62 | 62 | ||
63 | 63 | diff view generated by jsdifflib |
1 | From: Sam Eiderman <shmuel.eiderman@oracle.com> | 1 | From: Sam Eiderman <shmuel.eiderman@oracle.com> |
---|---|---|---|
2 | 2 | ||
3 | Until ESXi 6.5 VMware used the vmfsSparse format for snapshots (VMDK3 in | 3 | Until ESXi 6.5 VMware used the vmfsSparse format for snapshots (VMDK3 in |
4 | QEMU). | 4 | QEMU). |
5 | 5 | ||
6 | This format was lacking in the following: | 6 | This format was lacking in the following: |
7 | 7 | ||
8 | * Grain directory (L1) and grain table (L2) entries were 32-bit, | 8 | * Grain directory (L1) and grain table (L2) entries were 32-bit, |
9 | allowing access to only 2TB (slightly less) of data. | 9 | allowing access to only 2TB (slightly less) of data. |
10 | * The grain size (default) was 512 bytes - leading to data | 10 | * The grain size (default) was 512 bytes - leading to data |
11 | fragmentation and many grain tables. | 11 | fragmentation and many grain tables. |
12 | * For space reclamation purposes, it was necessary to find all the | 12 | * For space reclamation purposes, it was necessary to find all the |
13 | grains which are not pointed to by any grain table - so a reverse | 13 | grains which are not pointed to by any grain table - so a reverse |
14 | mapping of "offset of grain in vmdk" to "grain table" must be | 14 | mapping of "offset of grain in vmdk" to "grain table" must be |
15 | constructed - which takes large amounts of CPU/RAM. | 15 | constructed - which takes large amounts of CPU/RAM. |
16 | 16 | ||
17 | The format specification can be found in VMware's documentation: | 17 | The format specification can be found in VMware's documentation: |
18 | https://www.vmware.com/support/developer/vddk/vmdk_50_technote.pdf | 18 | https://www.vmware.com/support/developer/vddk/vmdk_50_technote.pdf |
19 | 19 | ||
20 | In ESXi 6.5, to support snapshot files larger than 2TB, a new format was | 20 | In ESXi 6.5, to support snapshot files larger than 2TB, a new format was |
21 | introduced: SESparse (Space Efficient). | 21 | introduced: SESparse (Space Efficient). |
22 | 22 | ||
23 | This format fixes the above issues: | 23 | This format fixes the above issues: |
24 | 24 | ||
25 | * All entries are now 64-bit. | 25 | * All entries are now 64-bit. |
26 | * The grain size (default) is 4KB. | 26 | * The grain size (default) is 4KB. |
27 | * Grain directory and grain tables are now located at the beginning | 27 | * Grain directory and grain tables are now located at the beginning |
28 | of the file. | 28 | of the file. |
29 | + seSparse format reserves space for all grain tables. | 29 | + seSparse format reserves space for all grain tables. |
30 | + Grain tables can be addressed using an index. | 30 | + Grain tables can be addressed using an index. |
31 | + Grains are located in the end of the file and can also be | 31 | + Grains are located in the end of the file and can also be |
32 | addressed with an index. | 32 | addressed with an index. |
33 | - seSparse vmdks of large disks (64TB) have huge preallocated | 33 | - seSparse vmdks of large disks (64TB) have huge preallocated |
34 | headers - mainly due to L2 tables, even for empty snapshots. | 34 | headers - mainly due to L2 tables, even for empty snapshots. |
35 | * The header contains a reverse mapping ("backmap") of "offset of | 35 | * The header contains a reverse mapping ("backmap") of "offset of |
36 | grain in vmdk" to "grain table" and a bitmap ("free bitmap") which | 36 | grain in vmdk" to "grain table" and a bitmap ("free bitmap") which |
37 | specifies for each grain - whether it is allocated or not. | 37 | specifies for each grain - whether it is allocated or not. |
38 | Using these data structures we can implement space reclamation | 38 | Using these data structures we can implement space reclamation |
39 | efficiently. | 39 | efficiently. |
40 | * Due to the fact that the header now maintains two mappings: | 40 | * Due to the fact that the header now maintains two mappings: |
41 | * The regular one (grain directory & grain tables) | 41 | * The regular one (grain directory & grain tables) |
42 | * A reverse one (backmap and free bitmap) | 42 | * A reverse one (backmap and free bitmap) |
43 | These data structures can lose consistency upon crash and result | 43 | These data structures can lose consistency upon crash and result |
44 | in a corrupted VMDK. | 44 | in a corrupted VMDK. |
45 | Therefore, a journal is also added to the VMDK and is replayed | 45 | Therefore, a journal is also added to the VMDK and is replayed |
46 | when the VMware reopens the file after a crash. | 46 | when the VMware reopens the file after a crash. |
47 | 47 | ||
48 | Since ESXi 6.7 - SESparse is the only snapshot format available. | 48 | Since ESXi 6.7 - SESparse is the only snapshot format available. |
49 | 49 | ||
50 | Unfortunately, VMware does not provide documentation regarding the new | 50 | Unfortunately, VMware does not provide documentation regarding the new |
51 | seSparse format. | 51 | seSparse format. |
52 | 52 | ||
53 | This commit is based on black-box research of the seSparse format. | 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 | 54 | Various in-guest block operations and their effect on the snapshot file |
55 | were tested. | 55 | were tested. |
56 | 56 | ||
57 | The only VMware provided source of information (regarding the underlying | 57 | The only VMware provided source of information (regarding the underlying |
58 | implementation) was a log file on the ESXi: | 58 | implementation) was a log file on the ESXi: |
59 | 59 | ||
60 | /var/log/hostd.log | 60 | /var/log/hostd.log |
61 | 61 | ||
62 | Whenever an seSparse snapshot is created - the log is being populated | 62 | Whenever an seSparse snapshot is created - the log is being populated |
63 | with seSparse records. | 63 | with seSparse records. |
64 | 64 | ||
65 | Relevant log records are of the form: | 65 | Relevant log records are of the form: |
66 | 66 | ||
67 | [...] Const Header: | 67 | [...] Const Header: |
68 | [...] constMagic = 0xcafebabe | 68 | [...] constMagic = 0xcafebabe |
69 | [...] version = 2.1 | 69 | [...] version = 2.1 |
70 | [...] capacity = 204800 | 70 | [...] capacity = 204800 |
71 | [...] grainSize = 8 | 71 | [...] grainSize = 8 |
72 | [...] grainTableSize = 64 | 72 | [...] grainTableSize = 64 |
73 | [...] flags = 0 | 73 | [...] flags = 0 |
74 | [...] Extents: | 74 | [...] Extents: |
75 | [...] Header : <1 : 1> | 75 | [...] Header : <1 : 1> |
76 | [...] JournalHdr : <2 : 2> | 76 | [...] JournalHdr : <2 : 2> |
77 | [...] Journal : <2048 : 2048> | 77 | [...] Journal : <2048 : 2048> |
78 | [...] GrainDirectory : <4096 : 2048> | 78 | [...] GrainDirectory : <4096 : 2048> |
79 | [...] GrainTables : <6144 : 2048> | 79 | [...] GrainTables : <6144 : 2048> |
80 | [...] FreeBitmap : <8192 : 2048> | 80 | [...] FreeBitmap : <8192 : 2048> |
81 | [...] BackMap : <10240 : 2048> | 81 | [...] BackMap : <10240 : 2048> |
82 | [...] Grain : <12288 : 204800> | 82 | [...] Grain : <12288 : 204800> |
83 | [...] Volatile Header: | 83 | [...] Volatile Header: |
84 | [...] volatileMagic = 0xcafecafe | 84 | [...] volatileMagic = 0xcafecafe |
85 | [...] FreeGTNumber = 0 | 85 | [...] FreeGTNumber = 0 |
86 | [...] nextTxnSeqNumber = 0 | 86 | [...] nextTxnSeqNumber = 0 |
87 | [...] replayJournal = 0 | 87 | [...] replayJournal = 0 |
88 | 88 | ||
89 | The sizes that are seen in the log file are in sectors. | 89 | The sizes that are seen in the log file are in sectors. |
90 | Extents are of the following format: <offset : size> | 90 | Extents are of the following format: <offset : size> |
91 | 91 | ||
92 | This commit is a strict implementation which enforces: | 92 | This commit is a strict implementation which enforces: |
93 | * magics | 93 | * magics |
94 | * version number 2.1 | 94 | * version number 2.1 |
95 | * grain size of 8 sectors (4KB) | 95 | * grain size of 8 sectors (4KB) |
96 | * grain table size of 64 sectors | 96 | * grain table size of 64 sectors |
97 | * zero flags | 97 | * zero flags |
98 | * extent locations | 98 | * extent locations |
99 | 99 | ||
100 | Additionally, this commit proivdes only a subset of the functionality | 100 | Additionally, this commit proivdes only a subset of the functionality |
101 | offered by seSparse's format: | 101 | offered by seSparse's format: |
102 | * Read-only | 102 | * Read-only |
103 | * No journal replay | 103 | * No journal replay |
104 | * No space reclamation | 104 | * No space reclamation |
105 | * No unmap support | 105 | * No unmap support |
106 | 106 | ||
107 | Hence, journal header, journal, free bitmap and backmap extents are | 107 | Hence, journal header, journal, free bitmap and backmap extents are |
108 | unused, only the "classic" (L1 -> L2 -> data) grain access is | 108 | unused, only the "classic" (L1 -> L2 -> data) grain access is |
109 | implemented. | 109 | implemented. |
110 | 110 | ||
111 | However there are several differences in the grain access itself. | 111 | However there are several differences in the grain access itself. |
112 | Grain directory (L1): | 112 | Grain directory (L1): |
113 | * Grain directory entries are indexes (not offsets) to grain | 113 | * Grain directory entries are indexes (not offsets) to grain |
114 | tables. | 114 | tables. |
115 | * Valid grain directory entries have their highest nibble set to | 115 | * Valid grain directory entries have their highest nibble set to |
116 | 0x1. | 116 | 0x1. |
117 | * Since grain tables are always located in the beginning of the | 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 | 118 | file - the index can fit into 32 bits - so we can use its low |
119 | part if it's valid. | 119 | part if it's valid. |
120 | Grain table (L2): | 120 | Grain table (L2): |
121 | * Grain table entries are indexes (not offsets) to grains. | 121 | * Grain table entries are indexes (not offsets) to grains. |
122 | * If the highest nibble of the entry is: | 122 | * If the highest nibble of the entry is: |
123 | 0x0: | 123 | 0x0: |
124 | The grain in not allocated. | 124 | The grain in not allocated. |
125 | The rest of the bytes are 0. | 125 | The rest of the bytes are 0. |
126 | 0x1: | 126 | 0x1: |
127 | The grain is unmapped - guest sees a zero grain. | 127 | The grain is unmapped - guest sees a zero grain. |
128 | The rest of the bits point to the previously mapped grain, | 128 | The rest of the bits point to the previously mapped grain, |
129 | see 0x3 case. | 129 | see 0x3 case. |
130 | 0x2: | 130 | 0x2: |
131 | The grain is zero. | 131 | The grain is zero. |
132 | 0x3: | 132 | 0x3: |
133 | The grain is allocated - to get the index calculate: | 133 | The grain is allocated - to get the index calculate: |
134 | ((entry & 0x0fff000000000000) >> 48) | | 134 | ((entry & 0x0fff000000000000) >> 48) | |
135 | ((entry & 0x0000ffffffffffff) << 12) | 135 | ((entry & 0x0000ffffffffffff) << 12) |
136 | * The difference between 0x1 and 0x2 is that 0x1 is an unallocated | 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 | 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 | 138 | grain - but the grain itself still exists in the grain extent - a |
139 | space reclamation procedure should delete it. | 139 | space reclamation procedure should delete it. |
140 | Unmapping a zero grain has no effect (0x2 will not change to 0x1) | 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. | 141 | but unmapping an unallocated grain will (0x0 to 0x1) - naturally. |
142 | 142 | ||
143 | In order to implement seSparse some fields had to be changed to support | 143 | In order to implement seSparse some fields had to be changed to support |
144 | both 32-bit and 64-bit entry sizes. | 144 | both 32-bit and 64-bit entry sizes. |
145 | 145 | ||
146 | Reviewed-by: Karl Heubaum <karl.heubaum@oracle.com> | 146 | Reviewed-by: Karl Heubaum <karl.heubaum@oracle.com> |
147 | Reviewed-by: Eyal Moscovici <eyal.moscovici@oracle.com> | 147 | Reviewed-by: Eyal Moscovici <eyal.moscovici@oracle.com> |
148 | Reviewed-by: Arbel Moshe <arbel.moshe@oracle.com> | 148 | Reviewed-by: Arbel Moshe <arbel.moshe@oracle.com> |
149 | Signed-off-by: Sam Eiderman <shmuel.eiderman@oracle.com> | 149 | Signed-off-by: Sam Eiderman <shmuel.eiderman@oracle.com> |
150 | Message-id: 20190620091057.47441-4-shmuel.eiderman@oracle.com | 150 | Message-id: 20190620091057.47441-4-shmuel.eiderman@oracle.com |
151 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 151 | Signed-off-by: Max Reitz <mreitz@redhat.com> |
152 | --- | 152 | --- |
153 | block/vmdk.c | 358 ++++++++++++++++++++++++++++++++++++++++++++++++--- | 153 | block/vmdk.c | 358 ++++++++++++++++++++++++++++++++++++++++++++++++--- |
154 | 1 file changed, 342 insertions(+), 16 deletions(-) | 154 | 1 file changed, 342 insertions(+), 16 deletions(-) |
155 | 155 | ||
156 | diff --git a/block/vmdk.c b/block/vmdk.c | 156 | diff --git a/block/vmdk.c b/block/vmdk.c |
157 | index XXXXXXX..XXXXXXX 100644 | 157 | index XXXXXXX..XXXXXXX 100644 |
158 | --- a/block/vmdk.c | 158 | --- a/block/vmdk.c |
159 | +++ b/block/vmdk.c | 159 | +++ b/block/vmdk.c |
160 | @@ -XXX,XX +XXX,XX @@ typedef struct { | 160 | @@ -XXX,XX +XXX,XX @@ typedef struct { |
161 | uint16_t compressAlgorithm; | 161 | uint16_t compressAlgorithm; |
162 | } QEMU_PACKED VMDK4Header; | 162 | } QEMU_PACKED VMDK4Header; |
163 | 163 | ||
164 | +typedef struct VMDKSESparseConstHeader { | 164 | +typedef struct VMDKSESparseConstHeader { |
165 | + uint64_t magic; | 165 | + uint64_t magic; |
166 | + uint64_t version; | 166 | + uint64_t version; |
167 | + uint64_t capacity; | 167 | + uint64_t capacity; |
168 | + uint64_t grain_size; | 168 | + uint64_t grain_size; |
169 | + uint64_t grain_table_size; | 169 | + uint64_t grain_table_size; |
170 | + uint64_t flags; | 170 | + uint64_t flags; |
171 | + uint64_t reserved1; | 171 | + uint64_t reserved1; |
172 | + uint64_t reserved2; | 172 | + uint64_t reserved2; |
173 | + uint64_t reserved3; | 173 | + uint64_t reserved3; |
174 | + uint64_t reserved4; | 174 | + uint64_t reserved4; |
175 | + uint64_t volatile_header_offset; | 175 | + uint64_t volatile_header_offset; |
176 | + uint64_t volatile_header_size; | 176 | + uint64_t volatile_header_size; |
177 | + uint64_t journal_header_offset; | 177 | + uint64_t journal_header_offset; |
178 | + uint64_t journal_header_size; | 178 | + uint64_t journal_header_size; |
179 | + uint64_t journal_offset; | 179 | + uint64_t journal_offset; |
180 | + uint64_t journal_size; | 180 | + uint64_t journal_size; |
181 | + uint64_t grain_dir_offset; | 181 | + uint64_t grain_dir_offset; |
182 | + uint64_t grain_dir_size; | 182 | + uint64_t grain_dir_size; |
183 | + uint64_t grain_tables_offset; | 183 | + uint64_t grain_tables_offset; |
184 | + uint64_t grain_tables_size; | 184 | + uint64_t grain_tables_size; |
185 | + uint64_t free_bitmap_offset; | 185 | + uint64_t free_bitmap_offset; |
186 | + uint64_t free_bitmap_size; | 186 | + uint64_t free_bitmap_size; |
187 | + uint64_t backmap_offset; | 187 | + uint64_t backmap_offset; |
188 | + uint64_t backmap_size; | 188 | + uint64_t backmap_size; |
189 | + uint64_t grains_offset; | 189 | + uint64_t grains_offset; |
190 | + uint64_t grains_size; | 190 | + uint64_t grains_size; |
191 | + uint8_t pad[304]; | 191 | + uint8_t pad[304]; |
192 | +} QEMU_PACKED VMDKSESparseConstHeader; | 192 | +} QEMU_PACKED VMDKSESparseConstHeader; |
193 | + | 193 | + |
194 | +typedef struct VMDKSESparseVolatileHeader { | 194 | +typedef struct VMDKSESparseVolatileHeader { |
195 | + uint64_t magic; | 195 | + uint64_t magic; |
196 | + uint64_t free_gt_number; | 196 | + uint64_t free_gt_number; |
197 | + uint64_t next_txn_seq_number; | 197 | + uint64_t next_txn_seq_number; |
198 | + uint64_t replay_journal; | 198 | + uint64_t replay_journal; |
199 | + uint8_t pad[480]; | 199 | + uint8_t pad[480]; |
200 | +} QEMU_PACKED VMDKSESparseVolatileHeader; | 200 | +} QEMU_PACKED VMDKSESparseVolatileHeader; |
201 | + | 201 | + |
202 | #define L2_CACHE_SIZE 16 | 202 | #define L2_CACHE_SIZE 16 |
203 | 203 | ||
204 | typedef struct VmdkExtent { | 204 | typedef struct VmdkExtent { |
205 | @@ -XXX,XX +XXX,XX @@ typedef struct VmdkExtent { | 205 | @@ -XXX,XX +XXX,XX @@ typedef struct VmdkExtent { |
206 | bool compressed; | 206 | bool compressed; |
207 | bool has_marker; | 207 | bool has_marker; |
208 | bool has_zero_grain; | 208 | bool has_zero_grain; |
209 | + bool sesparse; | 209 | + bool sesparse; |
210 | + uint64_t sesparse_l2_tables_offset; | 210 | + uint64_t sesparse_l2_tables_offset; |
211 | + uint64_t sesparse_clusters_offset; | 211 | + uint64_t sesparse_clusters_offset; |
212 | + int32_t entry_size; | 212 | + int32_t entry_size; |
213 | int version; | 213 | int version; |
214 | int64_t sectors; | 214 | int64_t sectors; |
215 | int64_t end_sector; | 215 | int64_t end_sector; |
216 | int64_t flat_start_offset; | 216 | int64_t flat_start_offset; |
217 | int64_t l1_table_offset; | 217 | int64_t l1_table_offset; |
218 | int64_t l1_backup_table_offset; | 218 | int64_t l1_backup_table_offset; |
219 | - uint32_t *l1_table; | 219 | - uint32_t *l1_table; |
220 | + void *l1_table; | 220 | + void *l1_table; |
221 | uint32_t *l1_backup_table; | 221 | uint32_t *l1_backup_table; |
222 | unsigned int l1_size; | 222 | unsigned int l1_size; |
223 | uint32_t l1_entry_sectors; | 223 | uint32_t l1_entry_sectors; |
224 | 224 | ||
225 | unsigned int l2_size; | 225 | unsigned int l2_size; |
226 | - uint32_t *l2_cache; | 226 | - uint32_t *l2_cache; |
227 | + void *l2_cache; | 227 | + void *l2_cache; |
228 | uint32_t l2_cache_offsets[L2_CACHE_SIZE]; | 228 | uint32_t l2_cache_offsets[L2_CACHE_SIZE]; |
229 | uint32_t l2_cache_counts[L2_CACHE_SIZE]; | 229 | uint32_t l2_cache_counts[L2_CACHE_SIZE]; |
230 | 230 | ||
231 | @@ -XXX,XX +XXX,XX @@ static int vmdk_add_extent(BlockDriverState *bs, | 231 | @@ -XXX,XX +XXX,XX @@ static int vmdk_add_extent(BlockDriverState *bs, |
232 | * minimal L2 table size: 512 entries | 232 | * minimal L2 table size: 512 entries |
233 | * 8 TB is still more than the maximal value supported for | 233 | * 8 TB is still more than the maximal value supported for |
234 | * VMDK3 & VMDK4 which is 2TB. | 234 | * VMDK3 & VMDK4 which is 2TB. |
235 | + * 64TB - for "ESXi seSparse Extent" | 235 | + * 64TB - for "ESXi seSparse Extent" |
236 | + * minimal cluster size: 512B (default is 4KB) | 236 | + * minimal cluster size: 512B (default is 4KB) |
237 | + * L2 table size: 4096 entries (const). | 237 | + * L2 table size: 4096 entries (const). |
238 | + * 64TB is more than the maximal value supported for | 238 | + * 64TB is more than the maximal value supported for |
239 | + * seSparse VMDKs (which is slightly less than 64TB) | 239 | + * seSparse VMDKs (which is slightly less than 64TB) |
240 | */ | 240 | */ |
241 | error_setg(errp, "L1 size too big"); | 241 | error_setg(errp, "L1 size too big"); |
242 | return -EFBIG; | 242 | return -EFBIG; |
243 | @@ -XXX,XX +XXX,XX @@ static int vmdk_add_extent(BlockDriverState *bs, | 243 | @@ -XXX,XX +XXX,XX @@ static int vmdk_add_extent(BlockDriverState *bs, |
244 | extent->l2_size = l2_size; | 244 | extent->l2_size = l2_size; |
245 | extent->cluster_sectors = flat ? sectors : cluster_sectors; | 245 | extent->cluster_sectors = flat ? sectors : cluster_sectors; |
246 | extent->next_cluster_sector = ROUND_UP(nb_sectors, cluster_sectors); | 246 | extent->next_cluster_sector = ROUND_UP(nb_sectors, cluster_sectors); |
247 | + extent->entry_size = sizeof(uint32_t); | 247 | + extent->entry_size = sizeof(uint32_t); |
248 | 248 | ||
249 | if (s->num_extents > 1) { | 249 | if (s->num_extents > 1) { |
250 | extent->end_sector = (*(extent - 1)).end_sector + extent->sectors; | 250 | extent->end_sector = (*(extent - 1)).end_sector + extent->sectors; |
251 | @@ -XXX,XX +XXX,XX @@ static int vmdk_init_tables(BlockDriverState *bs, VmdkExtent *extent, | 251 | @@ -XXX,XX +XXX,XX @@ static int vmdk_init_tables(BlockDriverState *bs, VmdkExtent *extent, |
252 | int i; | 252 | int i; |
253 | 253 | ||
254 | /* read the L1 table */ | 254 | /* read the L1 table */ |
255 | - l1_size = extent->l1_size * sizeof(uint32_t); | 255 | - l1_size = extent->l1_size * sizeof(uint32_t); |
256 | + l1_size = extent->l1_size * extent->entry_size; | 256 | + l1_size = extent->l1_size * extent->entry_size; |
257 | extent->l1_table = g_try_malloc(l1_size); | 257 | extent->l1_table = g_try_malloc(l1_size); |
258 | if (l1_size && extent->l1_table == NULL) { | 258 | if (l1_size && extent->l1_table == NULL) { |
259 | return -ENOMEM; | 259 | return -ENOMEM; |
260 | @@ -XXX,XX +XXX,XX @@ static int vmdk_init_tables(BlockDriverState *bs, VmdkExtent *extent, | 260 | @@ -XXX,XX +XXX,XX @@ static int vmdk_init_tables(BlockDriverState *bs, VmdkExtent *extent, |
261 | goto fail_l1; | 261 | goto fail_l1; |
262 | } | 262 | } |
263 | for (i = 0; i < extent->l1_size; i++) { | 263 | for (i = 0; i < extent->l1_size; i++) { |
264 | - le32_to_cpus(&extent->l1_table[i]); | 264 | - le32_to_cpus(&extent->l1_table[i]); |
265 | + if (extent->entry_size == sizeof(uint64_t)) { | 265 | + if (extent->entry_size == sizeof(uint64_t)) { |
266 | + le64_to_cpus((uint64_t *)extent->l1_table + i); | 266 | + le64_to_cpus((uint64_t *)extent->l1_table + i); |
267 | + } else { | 267 | + } else { |
268 | + assert(extent->entry_size == sizeof(uint32_t)); | 268 | + assert(extent->entry_size == sizeof(uint32_t)); |
269 | + le32_to_cpus((uint32_t *)extent->l1_table + i); | 269 | + le32_to_cpus((uint32_t *)extent->l1_table + i); |
270 | + } | 270 | + } |
271 | } | 271 | } |
272 | 272 | ||
273 | if (extent->l1_backup_table_offset) { | 273 | if (extent->l1_backup_table_offset) { |
274 | + assert(!extent->sesparse); | 274 | + assert(!extent->sesparse); |
275 | extent->l1_backup_table = g_try_malloc(l1_size); | 275 | extent->l1_backup_table = g_try_malloc(l1_size); |
276 | if (l1_size && extent->l1_backup_table == NULL) { | 276 | if (l1_size && extent->l1_backup_table == NULL) { |
277 | ret = -ENOMEM; | 277 | ret = -ENOMEM; |
278 | @@ -XXX,XX +XXX,XX @@ static int vmdk_init_tables(BlockDriverState *bs, VmdkExtent *extent, | 278 | @@ -XXX,XX +XXX,XX @@ static int vmdk_init_tables(BlockDriverState *bs, VmdkExtent *extent, |
279 | } | 279 | } |
280 | 280 | ||
281 | extent->l2_cache = | 281 | extent->l2_cache = |
282 | - g_new(uint32_t, extent->l2_size * L2_CACHE_SIZE); | 282 | - g_new(uint32_t, extent->l2_size * L2_CACHE_SIZE); |
283 | + g_malloc(extent->entry_size * extent->l2_size * L2_CACHE_SIZE); | 283 | + g_malloc(extent->entry_size * extent->l2_size * L2_CACHE_SIZE); |
284 | return 0; | 284 | return 0; |
285 | fail_l1b: | 285 | fail_l1b: |
286 | g_free(extent->l1_backup_table); | 286 | g_free(extent->l1_backup_table); |
287 | @@ -XXX,XX +XXX,XX @@ static int vmdk_open_vmfs_sparse(BlockDriverState *bs, | 287 | @@ -XXX,XX +XXX,XX @@ static int vmdk_open_vmfs_sparse(BlockDriverState *bs, |
288 | return ret; | 288 | return ret; |
289 | } | 289 | } |
290 | 290 | ||
291 | +#define SESPARSE_CONST_HEADER_MAGIC UINT64_C(0x00000000cafebabe) | 291 | +#define SESPARSE_CONST_HEADER_MAGIC UINT64_C(0x00000000cafebabe) |
292 | +#define SESPARSE_VOLATILE_HEADER_MAGIC UINT64_C(0x00000000cafecafe) | 292 | +#define SESPARSE_VOLATILE_HEADER_MAGIC UINT64_C(0x00000000cafecafe) |
293 | + | 293 | + |
294 | +/* Strict checks - format not officially documented */ | 294 | +/* Strict checks - format not officially documented */ |
295 | +static int check_se_sparse_const_header(VMDKSESparseConstHeader *header, | 295 | +static int check_se_sparse_const_header(VMDKSESparseConstHeader *header, |
296 | + Error **errp) | 296 | + Error **errp) |
297 | +{ | 297 | +{ |
298 | + header->magic = le64_to_cpu(header->magic); | 298 | + header->magic = le64_to_cpu(header->magic); |
299 | + header->version = le64_to_cpu(header->version); | 299 | + header->version = le64_to_cpu(header->version); |
300 | + header->grain_size = le64_to_cpu(header->grain_size); | 300 | + header->grain_size = le64_to_cpu(header->grain_size); |
301 | + header->grain_table_size = le64_to_cpu(header->grain_table_size); | 301 | + header->grain_table_size = le64_to_cpu(header->grain_table_size); |
302 | + header->flags = le64_to_cpu(header->flags); | 302 | + header->flags = le64_to_cpu(header->flags); |
303 | + header->reserved1 = le64_to_cpu(header->reserved1); | 303 | + header->reserved1 = le64_to_cpu(header->reserved1); |
304 | + header->reserved2 = le64_to_cpu(header->reserved2); | 304 | + header->reserved2 = le64_to_cpu(header->reserved2); |
305 | + header->reserved3 = le64_to_cpu(header->reserved3); | 305 | + header->reserved3 = le64_to_cpu(header->reserved3); |
306 | + header->reserved4 = le64_to_cpu(header->reserved4); | 306 | + header->reserved4 = le64_to_cpu(header->reserved4); |
307 | + | 307 | + |
308 | + header->volatile_header_offset = | 308 | + header->volatile_header_offset = |
309 | + le64_to_cpu(header->volatile_header_offset); | 309 | + le64_to_cpu(header->volatile_header_offset); |
310 | + header->volatile_header_size = le64_to_cpu(header->volatile_header_size); | 310 | + header->volatile_header_size = le64_to_cpu(header->volatile_header_size); |
311 | + | 311 | + |
312 | + header->journal_header_offset = le64_to_cpu(header->journal_header_offset); | 312 | + header->journal_header_offset = le64_to_cpu(header->journal_header_offset); |
313 | + header->journal_header_size = le64_to_cpu(header->journal_header_size); | 313 | + header->journal_header_size = le64_to_cpu(header->journal_header_size); |
314 | + | 314 | + |
315 | + header->journal_offset = le64_to_cpu(header->journal_offset); | 315 | + header->journal_offset = le64_to_cpu(header->journal_offset); |
316 | + header->journal_size = le64_to_cpu(header->journal_size); | 316 | + header->journal_size = le64_to_cpu(header->journal_size); |
317 | + | 317 | + |
318 | + header->grain_dir_offset = le64_to_cpu(header->grain_dir_offset); | 318 | + header->grain_dir_offset = le64_to_cpu(header->grain_dir_offset); |
319 | + header->grain_dir_size = le64_to_cpu(header->grain_dir_size); | 319 | + header->grain_dir_size = le64_to_cpu(header->grain_dir_size); |
320 | + | 320 | + |
321 | + header->grain_tables_offset = le64_to_cpu(header->grain_tables_offset); | 321 | + header->grain_tables_offset = le64_to_cpu(header->grain_tables_offset); |
322 | + header->grain_tables_size = le64_to_cpu(header->grain_tables_size); | 322 | + header->grain_tables_size = le64_to_cpu(header->grain_tables_size); |
323 | + | 323 | + |
324 | + header->free_bitmap_offset = le64_to_cpu(header->free_bitmap_offset); | 324 | + header->free_bitmap_offset = le64_to_cpu(header->free_bitmap_offset); |
325 | + header->free_bitmap_size = le64_to_cpu(header->free_bitmap_size); | 325 | + header->free_bitmap_size = le64_to_cpu(header->free_bitmap_size); |
326 | + | 326 | + |
327 | + header->backmap_offset = le64_to_cpu(header->backmap_offset); | 327 | + header->backmap_offset = le64_to_cpu(header->backmap_offset); |
328 | + header->backmap_size = le64_to_cpu(header->backmap_size); | 328 | + header->backmap_size = le64_to_cpu(header->backmap_size); |
329 | + | 329 | + |
330 | + header->grains_offset = le64_to_cpu(header->grains_offset); | 330 | + header->grains_offset = le64_to_cpu(header->grains_offset); |
331 | + header->grains_size = le64_to_cpu(header->grains_size); | 331 | + header->grains_size = le64_to_cpu(header->grains_size); |
332 | + | 332 | + |
333 | + if (header->magic != SESPARSE_CONST_HEADER_MAGIC) { | 333 | + if (header->magic != SESPARSE_CONST_HEADER_MAGIC) { |
334 | + error_setg(errp, "Bad const header magic: 0x%016" PRIx64, | 334 | + error_setg(errp, "Bad const header magic: 0x%016" PRIx64, |
335 | + header->magic); | 335 | + header->magic); |
336 | + return -EINVAL; | 336 | + return -EINVAL; |
337 | + } | 337 | + } |
338 | + | 338 | + |
339 | + if (header->version != 0x0000000200000001) { | 339 | + if (header->version != 0x0000000200000001) { |
340 | + error_setg(errp, "Unsupported version: 0x%016" PRIx64, | 340 | + error_setg(errp, "Unsupported version: 0x%016" PRIx64, |
341 | + header->version); | 341 | + header->version); |
342 | + return -ENOTSUP; | 342 | + return -ENOTSUP; |
343 | + } | 343 | + } |
344 | + | 344 | + |
345 | + if (header->grain_size != 8) { | 345 | + if (header->grain_size != 8) { |
346 | + error_setg(errp, "Unsupported grain size: %" PRIu64, | 346 | + error_setg(errp, "Unsupported grain size: %" PRIu64, |
347 | + header->grain_size); | 347 | + header->grain_size); |
348 | + return -ENOTSUP; | 348 | + return -ENOTSUP; |
349 | + } | 349 | + } |
350 | + | 350 | + |
351 | + if (header->grain_table_size != 64) { | 351 | + if (header->grain_table_size != 64) { |
352 | + error_setg(errp, "Unsupported grain table size: %" PRIu64, | 352 | + error_setg(errp, "Unsupported grain table size: %" PRIu64, |
353 | + header->grain_table_size); | 353 | + header->grain_table_size); |
354 | + return -ENOTSUP; | 354 | + return -ENOTSUP; |
355 | + } | 355 | + } |
356 | + | 356 | + |
357 | + if (header->flags != 0) { | 357 | + if (header->flags != 0) { |
358 | + error_setg(errp, "Unsupported flags: 0x%016" PRIx64, | 358 | + error_setg(errp, "Unsupported flags: 0x%016" PRIx64, |
359 | + header->flags); | 359 | + header->flags); |
360 | + return -ENOTSUP; | 360 | + return -ENOTSUP; |
361 | + } | 361 | + } |
362 | + | 362 | + |
363 | + if (header->reserved1 != 0 || header->reserved2 != 0 || | 363 | + if (header->reserved1 != 0 || header->reserved2 != 0 || |
364 | + header->reserved3 != 0 || header->reserved4 != 0) { | 364 | + header->reserved3 != 0 || header->reserved4 != 0) { |
365 | + error_setg(errp, "Unsupported reserved bits:" | 365 | + error_setg(errp, "Unsupported reserved bits:" |
366 | + " 0x%016" PRIx64 " 0x%016" PRIx64 | 366 | + " 0x%016" PRIx64 " 0x%016" PRIx64 |
367 | + " 0x%016" PRIx64 " 0x%016" PRIx64, | 367 | + " 0x%016" PRIx64 " 0x%016" PRIx64, |
368 | + header->reserved1, header->reserved2, | 368 | + header->reserved1, header->reserved2, |
369 | + header->reserved3, header->reserved4); | 369 | + header->reserved3, header->reserved4); |
370 | + return -ENOTSUP; | 370 | + return -ENOTSUP; |
371 | + } | 371 | + } |
372 | + | 372 | + |
373 | + /* check that padding is 0 */ | 373 | + /* check that padding is 0 */ |
374 | + if (!buffer_is_zero(header->pad, sizeof(header->pad))) { | 374 | + if (!buffer_is_zero(header->pad, sizeof(header->pad))) { |
375 | + error_setg(errp, "Unsupported non-zero const header padding"); | 375 | + error_setg(errp, "Unsupported non-zero const header padding"); |
376 | + return -ENOTSUP; | 376 | + return -ENOTSUP; |
377 | + } | 377 | + } |
378 | + | 378 | + |
379 | + return 0; | 379 | + return 0; |
380 | +} | 380 | +} |
381 | + | 381 | + |
382 | +static int check_se_sparse_volatile_header(VMDKSESparseVolatileHeader *header, | 382 | +static int check_se_sparse_volatile_header(VMDKSESparseVolatileHeader *header, |
383 | + Error **errp) | 383 | + Error **errp) |
384 | +{ | 384 | +{ |
385 | + header->magic = le64_to_cpu(header->magic); | 385 | + header->magic = le64_to_cpu(header->magic); |
386 | + header->free_gt_number = le64_to_cpu(header->free_gt_number); | 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); | 387 | + header->next_txn_seq_number = le64_to_cpu(header->next_txn_seq_number); |
388 | + header->replay_journal = le64_to_cpu(header->replay_journal); | 388 | + header->replay_journal = le64_to_cpu(header->replay_journal); |
389 | + | 389 | + |
390 | + if (header->magic != SESPARSE_VOLATILE_HEADER_MAGIC) { | 390 | + if (header->magic != SESPARSE_VOLATILE_HEADER_MAGIC) { |
391 | + error_setg(errp, "Bad volatile header magic: 0x%016" PRIx64, | 391 | + error_setg(errp, "Bad volatile header magic: 0x%016" PRIx64, |
392 | + header->magic); | 392 | + header->magic); |
393 | + return -EINVAL; | 393 | + return -EINVAL; |
394 | + } | 394 | + } |
395 | + | 395 | + |
396 | + if (header->replay_journal) { | 396 | + if (header->replay_journal) { |
397 | + error_setg(errp, "Image is dirty, Replaying journal not supported"); | 397 | + error_setg(errp, "Image is dirty, Replaying journal not supported"); |
398 | + return -ENOTSUP; | 398 | + return -ENOTSUP; |
399 | + } | 399 | + } |
400 | + | 400 | + |
401 | + /* check that padding is 0 */ | 401 | + /* check that padding is 0 */ |
402 | + if (!buffer_is_zero(header->pad, sizeof(header->pad))) { | 402 | + if (!buffer_is_zero(header->pad, sizeof(header->pad))) { |
403 | + error_setg(errp, "Unsupported non-zero volatile header padding"); | 403 | + error_setg(errp, "Unsupported non-zero volatile header padding"); |
404 | + return -ENOTSUP; | 404 | + return -ENOTSUP; |
405 | + } | 405 | + } |
406 | + | 406 | + |
407 | + return 0; | 407 | + return 0; |
408 | +} | 408 | +} |
409 | + | 409 | + |
410 | +static int vmdk_open_se_sparse(BlockDriverState *bs, | 410 | +static int vmdk_open_se_sparse(BlockDriverState *bs, |
411 | + BdrvChild *file, | 411 | + BdrvChild *file, |
412 | + int flags, Error **errp) | 412 | + int flags, Error **errp) |
413 | +{ | 413 | +{ |
414 | + int ret; | 414 | + int ret; |
415 | + VMDKSESparseConstHeader const_header; | 415 | + VMDKSESparseConstHeader const_header; |
416 | + VMDKSESparseVolatileHeader volatile_header; | 416 | + VMDKSESparseVolatileHeader volatile_header; |
417 | + VmdkExtent *extent; | 417 | + VmdkExtent *extent; |
418 | + | 418 | + |
419 | + ret = bdrv_apply_auto_read_only(bs, | 419 | + ret = bdrv_apply_auto_read_only(bs, |
420 | + "No write support for seSparse images available", errp); | 420 | + "No write support for seSparse images available", errp); |
421 | + if (ret < 0) { | 421 | + if (ret < 0) { |
422 | + return ret; | 422 | + return ret; |
423 | + } | 423 | + } |
424 | + | 424 | + |
425 | + assert(sizeof(const_header) == SECTOR_SIZE); | 425 | + assert(sizeof(const_header) == SECTOR_SIZE); |
426 | + | 426 | + |
427 | + ret = bdrv_pread(file, 0, &const_header, sizeof(const_header)); | 427 | + ret = bdrv_pread(file, 0, &const_header, sizeof(const_header)); |
428 | + if (ret < 0) { | 428 | + if (ret < 0) { |
429 | + bdrv_refresh_filename(file->bs); | 429 | + bdrv_refresh_filename(file->bs); |
430 | + error_setg_errno(errp, -ret, | 430 | + error_setg_errno(errp, -ret, |
431 | + "Could not read const header from file '%s'", | 431 | + "Could not read const header from file '%s'", |
432 | + file->bs->filename); | 432 | + file->bs->filename); |
433 | + return ret; | 433 | + return ret; |
434 | + } | 434 | + } |
435 | + | 435 | + |
436 | + /* check const header */ | 436 | + /* check const header */ |
437 | + ret = check_se_sparse_const_header(&const_header, errp); | 437 | + ret = check_se_sparse_const_header(&const_header, errp); |
438 | + if (ret < 0) { | 438 | + if (ret < 0) { |
439 | + return ret; | 439 | + return ret; |
440 | + } | 440 | + } |
441 | + | 441 | + |
442 | + assert(sizeof(volatile_header) == SECTOR_SIZE); | 442 | + assert(sizeof(volatile_header) == SECTOR_SIZE); |
443 | + | 443 | + |
444 | + ret = bdrv_pread(file, | 444 | + ret = bdrv_pread(file, |
445 | + const_header.volatile_header_offset * SECTOR_SIZE, | 445 | + const_header.volatile_header_offset * SECTOR_SIZE, |
446 | + &volatile_header, sizeof(volatile_header)); | 446 | + &volatile_header, sizeof(volatile_header)); |
447 | + if (ret < 0) { | 447 | + if (ret < 0) { |
448 | + bdrv_refresh_filename(file->bs); | 448 | + bdrv_refresh_filename(file->bs); |
449 | + error_setg_errno(errp, -ret, | 449 | + error_setg_errno(errp, -ret, |
450 | + "Could not read volatile header from file '%s'", | 450 | + "Could not read volatile header from file '%s'", |
451 | + file->bs->filename); | 451 | + file->bs->filename); |
452 | + return ret; | 452 | + return ret; |
453 | + } | 453 | + } |
454 | + | 454 | + |
455 | + /* check volatile header */ | 455 | + /* check volatile header */ |
456 | + ret = check_se_sparse_volatile_header(&volatile_header, errp); | 456 | + ret = check_se_sparse_volatile_header(&volatile_header, errp); |
457 | + if (ret < 0) { | 457 | + if (ret < 0) { |
458 | + return ret; | 458 | + return ret; |
459 | + } | 459 | + } |
460 | + | 460 | + |
461 | + ret = vmdk_add_extent(bs, file, false, | 461 | + ret = vmdk_add_extent(bs, file, false, |
462 | + const_header.capacity, | 462 | + const_header.capacity, |
463 | + const_header.grain_dir_offset * SECTOR_SIZE, | 463 | + const_header.grain_dir_offset * SECTOR_SIZE, |
464 | + 0, | 464 | + 0, |
465 | + const_header.grain_dir_size * | 465 | + const_header.grain_dir_size * |
466 | + SECTOR_SIZE / sizeof(uint64_t), | 466 | + SECTOR_SIZE / sizeof(uint64_t), |
467 | + const_header.grain_table_size * | 467 | + const_header.grain_table_size * |
468 | + SECTOR_SIZE / sizeof(uint64_t), | 468 | + SECTOR_SIZE / sizeof(uint64_t), |
469 | + const_header.grain_size, | 469 | + const_header.grain_size, |
470 | + &extent, | 470 | + &extent, |
471 | + errp); | 471 | + errp); |
472 | + if (ret < 0) { | 472 | + if (ret < 0) { |
473 | + return ret; | 473 | + return ret; |
474 | + } | 474 | + } |
475 | + | 475 | + |
476 | + extent->sesparse = true; | 476 | + extent->sesparse = true; |
477 | + extent->sesparse_l2_tables_offset = const_header.grain_tables_offset; | 477 | + extent->sesparse_l2_tables_offset = const_header.grain_tables_offset; |
478 | + extent->sesparse_clusters_offset = const_header.grains_offset; | 478 | + extent->sesparse_clusters_offset = const_header.grains_offset; |
479 | + extent->entry_size = sizeof(uint64_t); | 479 | + extent->entry_size = sizeof(uint64_t); |
480 | + | 480 | + |
481 | + ret = vmdk_init_tables(bs, extent, errp); | 481 | + ret = vmdk_init_tables(bs, extent, errp); |
482 | + if (ret) { | 482 | + if (ret) { |
483 | + /* free extent allocated by vmdk_add_extent */ | 483 | + /* free extent allocated by vmdk_add_extent */ |
484 | + vmdk_free_last_extent(bs); | 484 | + vmdk_free_last_extent(bs); |
485 | + } | 485 | + } |
486 | + | 486 | + |
487 | + return ret; | 487 | + return ret; |
488 | +} | 488 | +} |
489 | + | 489 | + |
490 | static int vmdk_open_desc_file(BlockDriverState *bs, int flags, char *buf, | 490 | static int vmdk_open_desc_file(BlockDriverState *bs, int flags, char *buf, |
491 | QDict *options, Error **errp); | 491 | QDict *options, Error **errp); |
492 | 492 | ||
493 | @@ -XXX,XX +XXX,XX @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs, | 493 | @@ -XXX,XX +XXX,XX @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs, |
494 | * RW [size in sectors] SPARSE "file-name.vmdk" | 494 | * RW [size in sectors] SPARSE "file-name.vmdk" |
495 | * RW [size in sectors] VMFS "file-name.vmdk" | 495 | * RW [size in sectors] VMFS "file-name.vmdk" |
496 | * RW [size in sectors] VMFSSPARSE "file-name.vmdk" | 496 | * RW [size in sectors] VMFSSPARSE "file-name.vmdk" |
497 | + * RW [size in sectors] SESPARSE "file-name.vmdk" | 497 | + * RW [size in sectors] SESPARSE "file-name.vmdk" |
498 | */ | 498 | */ |
499 | flat_offset = -1; | 499 | flat_offset = -1; |
500 | matches = sscanf(p, "%10s %" SCNd64 " %10s \"%511[^\n\r\"]\" %" SCNd64, | 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, | 501 | @@ -XXX,XX +XXX,XX @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs, |
502 | 502 | ||
503 | if (sectors <= 0 || | 503 | if (sectors <= 0 || |
504 | (strcmp(type, "FLAT") && strcmp(type, "SPARSE") && | 504 | (strcmp(type, "FLAT") && strcmp(type, "SPARSE") && |
505 | - strcmp(type, "VMFS") && strcmp(type, "VMFSSPARSE")) || | 505 | - strcmp(type, "VMFS") && strcmp(type, "VMFSSPARSE")) || |
506 | + strcmp(type, "VMFS") && strcmp(type, "VMFSSPARSE") && | 506 | + strcmp(type, "VMFS") && strcmp(type, "VMFSSPARSE") && |
507 | + strcmp(type, "SESPARSE")) || | 507 | + strcmp(type, "SESPARSE")) || |
508 | (strcmp(access, "RW"))) { | 508 | (strcmp(access, "RW"))) { |
509 | continue; | 509 | continue; |
510 | } | 510 | } |
511 | @@ -XXX,XX +XXX,XX @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs, | 511 | @@ -XXX,XX +XXX,XX @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs, |
512 | return ret; | 512 | return ret; |
513 | } | 513 | } |
514 | extent = &s->extents[s->num_extents - 1]; | 514 | extent = &s->extents[s->num_extents - 1]; |
515 | + } else if (!strcmp(type, "SESPARSE")) { | 515 | + } else if (!strcmp(type, "SESPARSE")) { |
516 | + ret = vmdk_open_se_sparse(bs, extent_file, bs->open_flags, errp); | 516 | + ret = vmdk_open_se_sparse(bs, extent_file, bs->open_flags, errp); |
517 | + if (ret) { | 517 | + if (ret) { |
518 | + bdrv_unref_child(bs, extent_file); | 518 | + bdrv_unref_child(bs, extent_file); |
519 | + return ret; | 519 | + return ret; |
520 | + } | 520 | + } |
521 | + extent = &s->extents[s->num_extents - 1]; | 521 | + extent = &s->extents[s->num_extents - 1]; |
522 | } else { | 522 | } else { |
523 | error_setg(errp, "Unsupported extent type '%s'", type); | 523 | error_setg(errp, "Unsupported extent type '%s'", type); |
524 | bdrv_unref_child(bs, extent_file); | 524 | bdrv_unref_child(bs, extent_file); |
525 | @@ -XXX,XX +XXX,XX @@ static int vmdk_open_desc_file(BlockDriverState *bs, int flags, char *buf, | 525 | @@ -XXX,XX +XXX,XX @@ static int vmdk_open_desc_file(BlockDriverState *bs, int flags, char *buf, |
526 | if (strcmp(ct, "monolithicFlat") && | 526 | if (strcmp(ct, "monolithicFlat") && |
527 | strcmp(ct, "vmfs") && | 527 | strcmp(ct, "vmfs") && |
528 | strcmp(ct, "vmfsSparse") && | 528 | strcmp(ct, "vmfsSparse") && |
529 | + strcmp(ct, "seSparse") && | 529 | + strcmp(ct, "seSparse") && |
530 | strcmp(ct, "twoGbMaxExtentSparse") && | 530 | strcmp(ct, "twoGbMaxExtentSparse") && |
531 | strcmp(ct, "twoGbMaxExtentFlat")) { | 531 | strcmp(ct, "twoGbMaxExtentFlat")) { |
532 | error_setg(errp, "Unsupported image type '%s'", ct); | 532 | error_setg(errp, "Unsupported image type '%s'", ct); |
533 | @@ -XXX,XX +XXX,XX @@ static int get_cluster_offset(BlockDriverState *bs, | 533 | @@ -XXX,XX +XXX,XX @@ static int get_cluster_offset(BlockDriverState *bs, |
534 | { | 534 | { |
535 | unsigned int l1_index, l2_offset, l2_index; | 535 | unsigned int l1_index, l2_offset, l2_index; |
536 | int min_index, i, j; | 536 | int min_index, i, j; |
537 | - uint32_t min_count, *l2_table; | 537 | - uint32_t min_count, *l2_table; |
538 | + uint32_t min_count; | 538 | + uint32_t min_count; |
539 | + void *l2_table; | 539 | + void *l2_table; |
540 | bool zeroed = false; | 540 | bool zeroed = false; |
541 | int64_t ret; | 541 | int64_t ret; |
542 | int64_t cluster_sector; | 542 | int64_t cluster_sector; |
543 | + unsigned int l2_size_bytes = extent->l2_size * extent->entry_size; | 543 | + unsigned int l2_size_bytes = extent->l2_size * extent->entry_size; |
544 | 544 | ||
545 | if (m_data) { | 545 | if (m_data) { |
546 | m_data->valid = 0; | 546 | m_data->valid = 0; |
547 | @@ -XXX,XX +XXX,XX @@ static int get_cluster_offset(BlockDriverState *bs, | 547 | @@ -XXX,XX +XXX,XX @@ static int get_cluster_offset(BlockDriverState *bs, |
548 | if (l1_index >= extent->l1_size) { | 548 | if (l1_index >= extent->l1_size) { |
549 | return VMDK_ERROR; | 549 | return VMDK_ERROR; |
550 | } | 550 | } |
551 | - l2_offset = extent->l1_table[l1_index]; | 551 | - l2_offset = extent->l1_table[l1_index]; |
552 | + if (extent->sesparse) { | 552 | + if (extent->sesparse) { |
553 | + uint64_t l2_offset_u64; | 553 | + uint64_t l2_offset_u64; |
554 | + | 554 | + |
555 | + assert(extent->entry_size == sizeof(uint64_t)); | 555 | + assert(extent->entry_size == sizeof(uint64_t)); |
556 | + | 556 | + |
557 | + l2_offset_u64 = ((uint64_t *)extent->l1_table)[l1_index]; | 557 | + l2_offset_u64 = ((uint64_t *)extent->l1_table)[l1_index]; |
558 | + if (l2_offset_u64 == 0) { | 558 | + if (l2_offset_u64 == 0) { |
559 | + l2_offset = 0; | 559 | + l2_offset = 0; |
560 | + } else if ((l2_offset_u64 & 0xffffffff00000000) != 0x1000000000000000) { | 560 | + } else if ((l2_offset_u64 & 0xffffffff00000000) != 0x1000000000000000) { |
561 | + /* | 561 | + /* |
562 | + * Top most nibble is 0x1 if grain table is allocated. | 562 | + * Top most nibble is 0x1 if grain table is allocated. |
563 | + * strict check - top most 4 bytes must be 0x10000000 since max | 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 | 564 | + * supported size is 64TB for disk - so no more than 64TB / 16MB |
565 | + * grain directories which is smaller than uint32, | 565 | + * grain directories which is smaller than uint32, |
566 | + * where 16MB is the only supported default grain table coverage. | 566 | + * where 16MB is the only supported default grain table coverage. |
567 | + */ | 567 | + */ |
568 | + return VMDK_ERROR; | 568 | + return VMDK_ERROR; |
569 | + } else { | 569 | + } else { |
570 | + l2_offset_u64 = l2_offset_u64 & 0x00000000ffffffff; | 570 | + l2_offset_u64 = l2_offset_u64 & 0x00000000ffffffff; |
571 | + l2_offset_u64 = extent->sesparse_l2_tables_offset + | 571 | + l2_offset_u64 = extent->sesparse_l2_tables_offset + |
572 | + l2_offset_u64 * l2_size_bytes / SECTOR_SIZE; | 572 | + l2_offset_u64 * l2_size_bytes / SECTOR_SIZE; |
573 | + if (l2_offset_u64 > 0x00000000ffffffff) { | 573 | + if (l2_offset_u64 > 0x00000000ffffffff) { |
574 | + return VMDK_ERROR; | 574 | + return VMDK_ERROR; |
575 | + } | 575 | + } |
576 | + l2_offset = (unsigned int)(l2_offset_u64); | 576 | + l2_offset = (unsigned int)(l2_offset_u64); |
577 | + } | 577 | + } |
578 | + } else { | 578 | + } else { |
579 | + assert(extent->entry_size == sizeof(uint32_t)); | 579 | + assert(extent->entry_size == sizeof(uint32_t)); |
580 | + l2_offset = ((uint32_t *)extent->l1_table)[l1_index]; | 580 | + l2_offset = ((uint32_t *)extent->l1_table)[l1_index]; |
581 | + } | 581 | + } |
582 | if (!l2_offset) { | 582 | if (!l2_offset) { |
583 | return VMDK_UNALLOC; | 583 | return VMDK_UNALLOC; |
584 | } | 584 | } |
585 | @@ -XXX,XX +XXX,XX @@ static int get_cluster_offset(BlockDriverState *bs, | 585 | @@ -XXX,XX +XXX,XX @@ static int get_cluster_offset(BlockDriverState *bs, |
586 | extent->l2_cache_counts[j] >>= 1; | 586 | extent->l2_cache_counts[j] >>= 1; |
587 | } | 587 | } |
588 | } | 588 | } |
589 | - l2_table = extent->l2_cache + (i * extent->l2_size); | 589 | - l2_table = extent->l2_cache + (i * extent->l2_size); |
590 | + l2_table = (char *)extent->l2_cache + (i * l2_size_bytes); | 590 | + l2_table = (char *)extent->l2_cache + (i * l2_size_bytes); |
591 | goto found; | 591 | goto found; |
592 | } | 592 | } |
593 | } | 593 | } |
594 | @@ -XXX,XX +XXX,XX @@ static int get_cluster_offset(BlockDriverState *bs, | 594 | @@ -XXX,XX +XXX,XX @@ static int get_cluster_offset(BlockDriverState *bs, |
595 | min_index = i; | 595 | min_index = i; |
596 | } | 596 | } |
597 | } | 597 | } |
598 | - l2_table = extent->l2_cache + (min_index * extent->l2_size); | 598 | - l2_table = extent->l2_cache + (min_index * extent->l2_size); |
599 | + l2_table = (char *)extent->l2_cache + (min_index * l2_size_bytes); | 599 | + l2_table = (char *)extent->l2_cache + (min_index * l2_size_bytes); |
600 | BLKDBG_EVENT(extent->file, BLKDBG_L2_LOAD); | 600 | BLKDBG_EVENT(extent->file, BLKDBG_L2_LOAD); |
601 | if (bdrv_pread(extent->file, | 601 | if (bdrv_pread(extent->file, |
602 | (int64_t)l2_offset * 512, | 602 | (int64_t)l2_offset * 512, |
603 | l2_table, | 603 | l2_table, |
604 | - extent->l2_size * sizeof(uint32_t) | 604 | - extent->l2_size * sizeof(uint32_t) |
605 | - ) != extent->l2_size * sizeof(uint32_t)) { | 605 | - ) != extent->l2_size * sizeof(uint32_t)) { |
606 | + l2_size_bytes | 606 | + l2_size_bytes |
607 | + ) != l2_size_bytes) { | 607 | + ) != l2_size_bytes) { |
608 | return VMDK_ERROR; | 608 | return VMDK_ERROR; |
609 | } | 609 | } |
610 | 610 | ||
611 | @@ -XXX,XX +XXX,XX @@ static int get_cluster_offset(BlockDriverState *bs, | 611 | @@ -XXX,XX +XXX,XX @@ static int get_cluster_offset(BlockDriverState *bs, |
612 | extent->l2_cache_counts[min_index] = 1; | 612 | extent->l2_cache_counts[min_index] = 1; |
613 | found: | 613 | found: |
614 | l2_index = ((offset >> 9) / extent->cluster_sectors) % extent->l2_size; | 614 | l2_index = ((offset >> 9) / extent->cluster_sectors) % extent->l2_size; |
615 | - cluster_sector = le32_to_cpu(l2_table[l2_index]); | 615 | - cluster_sector = le32_to_cpu(l2_table[l2_index]); |
616 | 616 | ||
617 | - if (extent->has_zero_grain && cluster_sector == VMDK_GTE_ZEROED) { | 617 | - if (extent->has_zero_grain && cluster_sector == VMDK_GTE_ZEROED) { |
618 | - zeroed = true; | 618 | - zeroed = true; |
619 | + if (extent->sesparse) { | 619 | + if (extent->sesparse) { |
620 | + cluster_sector = le64_to_cpu(((uint64_t *)l2_table)[l2_index]); | 620 | + cluster_sector = le64_to_cpu(((uint64_t *)l2_table)[l2_index]); |
621 | + switch (cluster_sector & 0xf000000000000000) { | 621 | + switch (cluster_sector & 0xf000000000000000) { |
622 | + case 0x0000000000000000: | 622 | + case 0x0000000000000000: |
623 | + /* unallocated grain */ | 623 | + /* unallocated grain */ |
624 | + if (cluster_sector != 0) { | 624 | + if (cluster_sector != 0) { |
625 | + return VMDK_ERROR; | 625 | + return VMDK_ERROR; |
626 | + } | 626 | + } |
627 | + break; | 627 | + break; |
628 | + case 0x1000000000000000: | 628 | + case 0x1000000000000000: |
629 | + /* scsi-unmapped grain - fallthrough */ | 629 | + /* scsi-unmapped grain - fallthrough */ |
630 | + case 0x2000000000000000: | 630 | + case 0x2000000000000000: |
631 | + /* zero grain */ | 631 | + /* zero grain */ |
632 | + zeroed = true; | 632 | + zeroed = true; |
633 | + break; | 633 | + break; |
634 | + case 0x3000000000000000: | 634 | + case 0x3000000000000000: |
635 | + /* allocated grain */ | 635 | + /* allocated grain */ |
636 | + cluster_sector = (((cluster_sector & 0x0fff000000000000) >> 48) | | 636 | + cluster_sector = (((cluster_sector & 0x0fff000000000000) >> 48) | |
637 | + ((cluster_sector & 0x0000ffffffffffff) << 12)); | 637 | + ((cluster_sector & 0x0000ffffffffffff) << 12)); |
638 | + cluster_sector = extent->sesparse_clusters_offset + | 638 | + cluster_sector = extent->sesparse_clusters_offset + |
639 | + cluster_sector * extent->cluster_sectors; | 639 | + cluster_sector * extent->cluster_sectors; |
640 | + break; | 640 | + break; |
641 | + default: | 641 | + default: |
642 | + return VMDK_ERROR; | 642 | + return VMDK_ERROR; |
643 | + } | 643 | + } |
644 | + } else { | 644 | + } else { |
645 | + cluster_sector = le32_to_cpu(((uint32_t *)l2_table)[l2_index]); | 645 | + cluster_sector = le32_to_cpu(((uint32_t *)l2_table)[l2_index]); |
646 | + | 646 | + |
647 | + if (extent->has_zero_grain && cluster_sector == VMDK_GTE_ZEROED) { | 647 | + if (extent->has_zero_grain && cluster_sector == VMDK_GTE_ZEROED) { |
648 | + zeroed = true; | 648 | + zeroed = true; |
649 | + } | 649 | + } |
650 | } | 650 | } |
651 | 651 | ||
652 | if (!cluster_sector || zeroed) { | 652 | if (!cluster_sector || zeroed) { |
653 | if (!allocate) { | 653 | if (!allocate) { |
654 | return zeroed ? VMDK_ZEROED : VMDK_UNALLOC; | 654 | return zeroed ? VMDK_ZEROED : VMDK_UNALLOC; |
655 | } | 655 | } |
656 | + assert(!extent->sesparse); | 656 | + assert(!extent->sesparse); |
657 | 657 | ||
658 | if (extent->next_cluster_sector >= VMDK_EXTENT_MAX_SECTORS) { | 658 | if (extent->next_cluster_sector >= VMDK_EXTENT_MAX_SECTORS) { |
659 | return VMDK_ERROR; | 659 | return VMDK_ERROR; |
660 | @@ -XXX,XX +XXX,XX @@ static int get_cluster_offset(BlockDriverState *bs, | 660 | @@ -XXX,XX +XXX,XX @@ static int get_cluster_offset(BlockDriverState *bs, |
661 | m_data->l1_index = l1_index; | 661 | m_data->l1_index = l1_index; |
662 | m_data->l2_index = l2_index; | 662 | m_data->l2_index = l2_index; |
663 | m_data->l2_offset = l2_offset; | 663 | m_data->l2_offset = l2_offset; |
664 | - m_data->l2_cache_entry = &l2_table[l2_index]; | 664 | - m_data->l2_cache_entry = &l2_table[l2_index]; |
665 | + m_data->l2_cache_entry = ((uint32_t *)l2_table) + l2_index; | 665 | + m_data->l2_cache_entry = ((uint32_t *)l2_table) + l2_index; |
666 | } | 666 | } |
667 | } | 667 | } |
668 | *cluster_offset = cluster_sector << BDRV_SECTOR_BITS; | 668 | *cluster_offset = cluster_sector << BDRV_SECTOR_BITS; |
669 | @@ -XXX,XX +XXX,XX @@ static int vmdk_pwritev(BlockDriverState *bs, uint64_t offset, | 669 | @@ -XXX,XX +XXX,XX @@ static int vmdk_pwritev(BlockDriverState *bs, uint64_t offset, |
670 | if (!extent) { | 670 | if (!extent) { |
671 | return -EIO; | 671 | return -EIO; |
672 | } | 672 | } |
673 | + if (extent->sesparse) { | 673 | + if (extent->sesparse) { |
674 | + return -ENOTSUP; | 674 | + return -ENOTSUP; |
675 | + } | 675 | + } |
676 | offset_in_cluster = vmdk_find_offset_in_cluster(extent, offset); | 676 | offset_in_cluster = vmdk_find_offset_in_cluster(extent, offset); |
677 | n_bytes = MIN(bytes, extent->cluster_sectors * BDRV_SECTOR_SIZE | 677 | n_bytes = MIN(bytes, extent->cluster_sectors * BDRV_SECTOR_SIZE |
678 | - offset_in_cluster); | 678 | - offset_in_cluster); |
679 | -- | 679 | -- |
680 | 2.21.0 | 680 | 2.21.0 |
681 | 681 | ||
682 | 682 | diff view generated by jsdifflib |
... | ... | ||
---|---|---|---|
21 | Signed-off-by: Pino Toscano <ptoscano@redhat.com> | 21 | Signed-off-by: Pino Toscano <ptoscano@redhat.com> |
22 | Tested-by: Philippe Mathieu-Daudé <philmd@redhat.com> | 22 | Tested-by: Philippe Mathieu-Daudé <philmd@redhat.com> |
23 | Acked-by: Alex Bennée <alex.bennee@linaro.org> | 23 | Acked-by: Alex Bennée <alex.bennee@linaro.org> |
24 | Message-id: 20190620200840.17655-1-ptoscano@redhat.com | 24 | Message-id: 20190620200840.17655-1-ptoscano@redhat.com |
25 | Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> | 25 | Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> |
26 | Message-id: 5873173.t2JhDm7DL7@lindworm.usersys.redhat.com | ||
26 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 27 | Signed-off-by: Max Reitz <mreitz@redhat.com> |
27 | --- | 28 | --- |
28 | configure | 65 +- | 29 | configure | 65 +- |
29 | block/Makefile.objs | 6 +- | 30 | block/Makefile.objs | 6 +- |
30 | block/ssh.c | 673 ++++++++++-------- | 31 | block/ssh.c | 652 ++++++++++-------- |
31 | .travis.yml | 4 +- | 32 | .travis.yml | 4 +- |
32 | block/trace-events | 14 +- | 33 | block/trace-events | 14 +- |
33 | docs/qemu-block-drivers.texi | 2 +- | 34 | docs/qemu-block-drivers.texi | 2 +- |
34 | .../dockerfiles/debian-win32-cross.docker | 1 - | 35 | .../dockerfiles/debian-win32-cross.docker | 1 - |
35 | .../dockerfiles/debian-win64-cross.docker | 1 - | 36 | .../dockerfiles/debian-win64-cross.docker | 1 - |
36 | tests/docker/dockerfiles/fedora.docker | 4 +- | 37 | tests/docker/dockerfiles/fedora.docker | 4 +- |
37 | tests/docker/dockerfiles/ubuntu.docker | 2 +- | 38 | tests/docker/dockerfiles/ubuntu.docker | 2 +- |
38 | tests/docker/dockerfiles/ubuntu1804.docker | 2 +- | 39 | tests/docker/dockerfiles/ubuntu1804.docker | 2 +- |
39 | tests/qemu-iotests/207 | 54 +- | 40 | tests/qemu-iotests/207 | 54 +- |
40 | tests/qemu-iotests/207.out | 2 +- | 41 | tests/qemu-iotests/207.out | 2 +- |
41 | 13 files changed, 470 insertions(+), 360 deletions(-) | 42 | 13 files changed, 449 insertions(+), 360 deletions(-) |
42 | 43 | ||
43 | diff --git a/configure b/configure | 44 | diff --git a/configure b/configure |
44 | index XXXXXXX..XXXXXXX 100755 | 45 | index XXXXXXX..XXXXXXX 100755 |
45 | --- a/configure | 46 | --- a/configure |
46 | +++ b/configure | 47 | +++ b/configure |
... | ... | ||
366 | - int type; | 367 | - int type; |
367 | - | 368 | - |
368 | - hostkey = libssh2_session_hostkey(s->session, &len, &type); | 369 | - hostkey = libssh2_session_hostkey(s->session, &len, &type); |
369 | - if (!hostkey) { | 370 | - if (!hostkey) { |
370 | + int ret; | 371 | + int ret; |
372 | +#ifdef HAVE_LIBSSH_0_8 | ||
373 | + enum ssh_known_hosts_e state; | ||
371 | + int r; | 374 | + int r; |
372 | + ssh_key pubkey; | 375 | + ssh_key pubkey; |
373 | + enum ssh_keytypes_e pubkey_type; | 376 | + enum ssh_keytypes_e pubkey_type; |
374 | + unsigned char *server_hash = NULL; | 377 | + unsigned char *server_hash = NULL; |
375 | + size_t server_hash_len; | 378 | + size_t server_hash_len; |
376 | + char *fingerprint = NULL; | 379 | + char *fingerprint = NULL; |
377 | +#ifdef HAVE_LIBSSH_0_8 | ||
378 | + enum ssh_known_hosts_e state; | ||
379 | + | 380 | + |
380 | + state = ssh_session_is_known_server(s->session); | 381 | + state = ssh_session_is_known_server(s->session); |
381 | + trace_ssh_server_status(state); | 382 | + trace_ssh_server_status(state); |
382 | + | 383 | + |
383 | + switch (state) { | 384 | + switch (state) { |
... | ... | ||
472 | + case SSH_SERVER_KNOWN_CHANGED: | 473 | + case SSH_SERVER_KNOWN_CHANGED: |
473 | ret = -EINVAL; | 474 | ret = -EINVAL; |
474 | - session_error_setg(errp, s, | 475 | - session_error_setg(errp, s, |
475 | - "host key does not match the one in known_hosts" | 476 | - "host key does not match the one in known_hosts" |
476 | - " (found key %s)", found->key); | 477 | - " (found key %s)", found->key); |
477 | + r = ssh_get_publickey(s->session, &pubkey); | 478 | + error_setg(errp, |
478 | + if (r == 0) { | 479 | + "host key does not match the one in known_hosts; this " |
479 | + r = ssh_get_publickey_hash(pubkey, SSH_PUBLICKEY_HASH_SHA1, | 480 | + "may be a possible attack"); |
480 | + &server_hash, &server_hash_len); | 481 | goto out; |
481 | + pubkey_type = ssh_key_type(pubkey); | 482 | - case LIBSSH2_KNOWNHOST_CHECK_NOTFOUND: |
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: | 483 | + case SSH_SERVER_FOUND_OTHER: |
503 | + ret = -EINVAL; | 484 | ret = -EINVAL; |
485 | - session_error_setg(errp, s, "no host key was found in known_hosts"); | ||
504 | + error_setg(errp, | 486 | + error_setg(errp, |
505 | + "host key for this server not found, another type exists"); | 487 | + "host key for this server not found, another type exists"); |
506 | + goto out; | 488 | + goto out; |
507 | + case SSH_SERVER_FILE_NOT_FOUND: | 489 | + case SSH_SERVER_FILE_NOT_FOUND: |
508 | + ret = -ENOENT; | 490 | + ret = -ENOENT; |
509 | + error_setg(errp, "known_hosts file not found"); | 491 | + error_setg(errp, "known_hosts file not found"); |
510 | goto out; | 492 | goto out; |
511 | - case LIBSSH2_KNOWNHOST_CHECK_NOTFOUND: | 493 | - case LIBSSH2_KNOWNHOST_CHECK_FAILURE: |
512 | + case SSH_SERVER_NOT_KNOWN: | 494 | + 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; | 495 | ret = -EINVAL; |
520 | - session_error_setg(errp, s, | 496 | - session_error_setg(errp, s, |
521 | - "failure matching the host key with known_hosts"); | 497 | - "failure matching the host key with known_hosts"); |
498 | + error_setg(errp, "no host key was found in known_hosts"); | ||
499 | + goto out; | ||
500 | + case SSH_SERVER_ERROR: | ||
501 | + ret = -EINVAL; | ||
522 | + error_setg(errp, "server error"); | 502 | + error_setg(errp, "server error"); |
523 | goto out; | 503 | goto out; |
524 | default: | 504 | default: |
525 | ret = -EINVAL; | 505 | ret = -EINVAL; |
526 | - session_error_setg(errp, s, "unknown error matching the host key" | 506 | - session_error_setg(errp, s, "unknown error matching the host key" |
... | ... | diff view generated by jsdifflib |
1 | Tests should place their files into the test directory. This includes | 1 | Tests should place their files into the test directory. This includes |
---|---|---|---|
2 | Unix sockets. 205 currently fails to do so, which prevents it from | 2 | Unix sockets. 205 currently fails to do so, which prevents it from |
3 | being run concurrently. | 3 | being run concurrently. |
4 | 4 | ||
5 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 5 | Signed-off-by: Max Reitz <mreitz@redhat.com> |
6 | Message-id: 20190618210238.9524-1-mreitz@redhat.com | 6 | Message-id: 20190618210238.9524-1-mreitz@redhat.com |
7 | Reviewed-by: Eric Blake <eblake@redhat.com> | 7 | Reviewed-by: Eric Blake <eblake@redhat.com> |
8 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 8 | Signed-off-by: Max Reitz <mreitz@redhat.com> |
9 | --- | 9 | --- |
10 | tests/qemu-iotests/205 | 2 +- | 10 | tests/qemu-iotests/205 | 2 +- |
11 | 1 file changed, 1 insertion(+), 1 deletion(-) | 11 | 1 file changed, 1 insertion(+), 1 deletion(-) |
12 | 12 | ||
13 | diff --git a/tests/qemu-iotests/205 b/tests/qemu-iotests/205 | 13 | diff --git a/tests/qemu-iotests/205 b/tests/qemu-iotests/205 |
14 | index XXXXXXX..XXXXXXX 100755 | 14 | index XXXXXXX..XXXXXXX 100755 |
15 | --- a/tests/qemu-iotests/205 | 15 | --- a/tests/qemu-iotests/205 |
16 | +++ b/tests/qemu-iotests/205 | 16 | +++ b/tests/qemu-iotests/205 |
17 | @@ -XXX,XX +XXX,XX @@ import iotests | 17 | @@ -XXX,XX +XXX,XX @@ import iotests |
18 | import time | 18 | import time |
19 | from iotests import qemu_img_create, qemu_io, filter_qemu_io, QemuIoInteractive | 19 | from iotests import qemu_img_create, qemu_io, filter_qemu_io, QemuIoInteractive |
20 | 20 | ||
21 | -nbd_sock = 'nbd_sock' | 21 | -nbd_sock = 'nbd_sock' |
22 | +nbd_sock = os.path.join(iotests.test_dir, 'nbd_sock') | 22 | +nbd_sock = os.path.join(iotests.test_dir, 'nbd_sock') |
23 | nbd_uri = 'nbd+unix:///exp?socket=' + nbd_sock | 23 | nbd_uri = 'nbd+unix:///exp?socket=' + nbd_sock |
24 | disk = os.path.join(iotests.test_dir, 'disk') | 24 | disk = os.path.join(iotests.test_dir, 'disk') |
25 | 25 | ||
26 | -- | 26 | -- |
27 | 2.21.0 | 27 | 2.21.0 |
28 | 28 | ||
29 | 29 | diff view generated by jsdifflib |