[libvirt] [PATCH 00/15] qemu: Implement non-shared storage migration via TLS (blockdev-add saga)

Implement the non-shared storage migration when TLS is enabled. This is done by using blockdev-add to add the NBD endpoint with the TLS environment alias configured properly. Peter Krempa (15): qemu: block: Don't nest storage layer properties into format layer conf: domain: Export virDomainStorageSourceParse qemu: migration: Don't access disk members without lock qemu: caps: Add capability for blockdev-add/blockdev-del qemu: monitor: Factor out and document code to format QMP command qemu: monitor: Add implementation for blockdev-add and blockdev-del qemu: monitor: Introduce support for blockdev-mirror qemu: block: Add helpers for hot-adding virStorageSource via blockdev qemu: domain: Extract NBD disk migration private data formatting qemu: domain: Extract parsing of NBD status XML qemu: domain: Add private data for NBD migration storage source definition test: Add status XML test for NBD tls storage migration qemu: migration: Rename NBD migration functions qemu: migration: Extract code responsible for calling drive-mirror qemu: migration: Add support for transporting NBD over TLS src/conf/domain_conf.c | 2 +- src/conf/domain_conf.h | 6 + src/libvirt_private.syms | 1 + src/qemu/qemu_block.c | 163 +++++++- src/qemu/qemu_block.h | 34 ++ src/qemu/qemu_capabilities.c | 2 + src/qemu/qemu_capabilities.h | 1 + src/qemu/qemu_domain.c | 242 +++++++++-- src/qemu/qemu_domain.h | 1 + src/qemu/qemu_migration.c | 306 ++++++++++---- src/qemu/qemu_monitor.c | 59 +++ src/qemu/qemu_monitor.h | 16 + src/qemu/qemu_monitor_json.c | 164 +++++++- src/qemu/qemu_monitor_json.h | 18 + tests/qemublocktest.c | 11 +- .../xml2json/block-raw-noopts.json | 15 +- .../qemublocktestdata/xml2json/dir-fat-cache.json | 27 +- .../qemublocktestdata/xml2json/dir-fat-floppy.json | 19 +- .../xml2json/dir-fat-readonly.json | 19 +- .../xml2json/file-backing_basic-aio_threads.json | 82 ++-- .../file-backing_basic-cache-directsync.json | 108 ++--- .../xml2json/file-backing_basic-cache-none.json | 108 ++--- .../xml2json/file-backing_basic-cache-unsafe.json | 108 ++--- .../file-backing_basic-cache-writeback.json | 108 ++--- .../file-backing_basic-cache-writethrough.json | 108 ++--- .../xml2json/file-backing_basic-detect.json | 76 ++-- .../xml2json/file-backing_basic-noopts.json | 60 +-- .../xml2json/file-backing_basic-unmap-detect.json | 76 ++-- .../xml2json/file-backing_basic-unmap-ignore.json | 76 ++-- .../xml2json/file-backing_basic-unmap.json | 76 ++-- .../xml2json/file-bochs-noopts.json | 15 +- .../xml2json/file-cloop-noopts.json | 15 +- .../xml2json/file-dmg-noopts.json | 15 +- .../xml2json/file-ploop-noopts.json | 15 +- .../file-qcow2-backing-chain-encryption.json | 30 +- .../xml2json/file-qcow2-backing-chain-noopts.json | 150 +++---- .../file-qcow2-backing-chain-unterminated.json | 30 +- .../xml2json/file-raw-aio_native.json | 25 +- .../qemublocktestdata/xml2json/file-raw-luks.json | 15 +- .../xml2json/file-raw-noopts.json | 15 +- .../xml2json/file-vdi-noopts.json | 15 +- .../xml2json/file-vhd-noopts.json | 15 +- .../xml2json/file-vpc-noopts.json | 15 +- .../network-qcow2-backing-chain-cache-unsafe.json | 74 ++-- ...etwork-qcow2-backing-chain-encryption_auth.json | 64 +-- tests/qemucapabilitiesdata/caps_2.10.0.aarch64.xml | 1 + tests/qemucapabilitiesdata/caps_2.10.0.ppc64.xml | 1 + tests/qemucapabilitiesdata/caps_2.10.0.s390x.xml | 1 + tests/qemucapabilitiesdata/caps_2.10.0.x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_2.11.0.s390x.xml | 1 + tests/qemucapabilitiesdata/caps_2.12.0.aarch64.xml | 1 + tests/qemucapabilitiesdata/caps_2.12.0.ppc64.xml | 1 + tests/qemucapabilitiesdata/caps_2.12.0.s390x.xml | 1 + tests/qemucapabilitiesdata/caps_2.12.0.x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_2.9.0.ppc64.xml | 1 + tests/qemucapabilitiesdata/caps_2.9.0.s390x.xml | 1 + tests/qemucapabilitiesdata/caps_2.9.0.x86_64.xml | 1 + .../migration-out-nbd-tls-in.xml | 464 +++++++++++++++++++++ .../migration-out-nbd-tls-out.xml | 1 + tests/qemuxml2xmltest.c | 1 + 60 files changed, 2172 insertions(+), 906 deletions(-) create mode 100644 tests/qemustatusxml2xmldata/migration-out-nbd-tls-in.xml create mode 120000 tests/qemustatusxml2xmldata/migration-out-nbd-tls-out.xml -- 2.16.2

Reference the storage via node name rather than inlining it. This is the approach that will be used with -blockdev/blockdev-add since it allows more control and is more future proof. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_block.c | 8 +- tests/qemublocktest.c | 11 +- .../xml2json/block-raw-noopts.json | 15 ++- .../qemublocktestdata/xml2json/dir-fat-cache.json | 27 ++-- .../qemublocktestdata/xml2json/dir-fat-floppy.json | 19 +-- .../xml2json/dir-fat-readonly.json | 19 +-- .../xml2json/file-backing_basic-aio_threads.json | 82 +++++------ .../file-backing_basic-cache-directsync.json | 108 ++++++++------- .../xml2json/file-backing_basic-cache-none.json | 108 ++++++++------- .../xml2json/file-backing_basic-cache-unsafe.json | 108 ++++++++------- .../file-backing_basic-cache-writeback.json | 108 ++++++++------- .../file-backing_basic-cache-writethrough.json | 108 ++++++++------- .../xml2json/file-backing_basic-detect.json | 76 ++++++----- .../xml2json/file-backing_basic-noopts.json | 60 +++++---- .../xml2json/file-backing_basic-unmap-detect.json | 76 ++++++----- .../xml2json/file-backing_basic-unmap-ignore.json | 76 ++++++----- .../xml2json/file-backing_basic-unmap.json | 76 ++++++----- .../xml2json/file-bochs-noopts.json | 15 ++- .../xml2json/file-cloop-noopts.json | 15 ++- .../xml2json/file-dmg-noopts.json | 15 ++- .../xml2json/file-ploop-noopts.json | 15 ++- .../file-qcow2-backing-chain-encryption.json | 30 +++-- .../xml2json/file-qcow2-backing-chain-noopts.json | 150 +++++++++++---------- .../file-qcow2-backing-chain-unterminated.json | 30 +++-- .../xml2json/file-raw-aio_native.json | 25 ++-- .../qemublocktestdata/xml2json/file-raw-luks.json | 15 ++- .../xml2json/file-raw-noopts.json | 15 ++- .../xml2json/file-vdi-noopts.json | 15 ++- .../xml2json/file-vhd-noopts.json | 15 ++- .../xml2json/file-vpc-noopts.json | 15 ++- .../network-qcow2-backing-chain-cache-unsafe.json | 74 +++++----- ...etwork-qcow2-backing-chain-encryption_auth.json | 64 ++++----- 32 files changed, 834 insertions(+), 759 deletions(-) diff --git a/src/qemu/qemu_block.c b/src/qemu/qemu_block.c index 12f37cda01..a514e8a055 100644 --- a/src/qemu/qemu_block.c +++ b/src/qemu/qemu_block.c @@ -1432,7 +1432,6 @@ virJSONValuePtr qemuBlockStorageSourceGetBlockdevProps(virStorageSourcePtr src) { bool backingSupported = src->format >= VIR_STORAGE_FILE_BACKING; - virJSONValuePtr storage = NULL; virJSONValuePtr props = NULL; virJSONValuePtr ret = NULL; @@ -1446,13 +1445,9 @@ qemuBlockStorageSourceGetBlockdevProps(virStorageSourcePtr src) if (!(props = qemuBlockStorageSourceGetBlockdevFormatProps(src))) goto cleanup; - if (!(storage = qemuBlockStorageSourceGetBackendProps(src, false))) + if (virJSONValueObjectAppendString(props, "file", src->nodestorage) < 0) goto cleanup; - if (virJSONValueObjectAppend(props, "file", storage) < 0) - goto cleanup; - storage = NULL; - if (src->backingStore && backingSupported) { if (virStorageSourceHasBacking(src)) { if (virJSONValueObjectAppendString(props, "backing", @@ -1469,7 +1464,6 @@ qemuBlockStorageSourceGetBlockdevProps(virStorageSourcePtr src) VIR_STEAL_PTR(ret, props); cleanup: - virJSONValueFree(storage); virJSONValueFree(props); return ret; } diff --git a/tests/qemublocktest.c b/tests/qemublocktest.c index eae1ca8ee3..d671505969 100644 --- a/tests/qemublocktest.c +++ b/tests/qemublocktest.c @@ -191,7 +191,8 @@ testQemuDiskXMLToProps(const void *opaque) struct testQemuDiskXMLToJSONData *data = (void *) opaque; virDomainDiskDefPtr disk = NULL; virStorageSourcePtr n; - virJSONValuePtr props = NULL; + virJSONValuePtr formatProps = NULL; + virJSONValuePtr storageProps = NULL; char *xmlpath = NULL; char *xmlstr = NULL; int ret = -1; @@ -221,7 +222,8 @@ testQemuDiskXMLToProps(const void *opaque) if (testQemuDiskXMLToJSONFakeSecrets(n) < 0) goto cleanup; - if (!(props = qemuBlockStorageSourceGetBlockdevProps(n))) { + if (!(formatProps = qemuBlockStorageSourceGetBlockdevProps(n)) || + !(storageProps = qemuBlockStorageSourceGetBackendProps(n, false))) { if (!data->fail) { VIR_TEST_VERBOSE("failed to generate qemu blockdev props\n"); goto cleanup; @@ -231,13 +233,16 @@ testQemuDiskXMLToProps(const void *opaque) goto cleanup; } - if (VIR_APPEND_ELEMENT(data->props, data->nprops, props) < 0) + if (VIR_APPEND_ELEMENT(data->props, data->nprops, formatProps) < 0 || + VIR_APPEND_ELEMENT(data->props, data->nprops, storageProps) < 0) goto cleanup; } ret = 0; cleanup: + virJSONValueFree(formatProps); + virJSONValueFree(storageProps); virDomainDiskDefFree(disk); VIR_FREE(xmlpath); VIR_FREE(xmlstr); diff --git a/tests/qemublocktestdata/xml2json/block-raw-noopts.json b/tests/qemublocktestdata/xml2json/block-raw-noopts.json index 25bf77d5aa..f223659c76 100644 --- a/tests/qemublocktestdata/xml2json/block-raw-noopts.json +++ b/tests/qemublocktestdata/xml2json/block-raw-noopts.json @@ -2,11 +2,12 @@ "node-name": "0123456789ABCDEF0123456789ABCDE", "read-only": false, "driver": "raw", - "file": { - "driver": "host_device", - "filename": "/dev/blah", - "node-name": "0123456789ABCDEF0123456789ABCDE", - "read-only": false, - "discard": "unmap" - } + "file": "0123456789ABCDEF0123456789ABCDE" +} +{ + "driver": "host_device", + "filename": "/dev/blah", + "node-name": "0123456789ABCDEF0123456789ABCDE", + "read-only": false, + "discard": "unmap" } diff --git a/tests/qemublocktestdata/xml2json/dir-fat-cache.json b/tests/qemublocktestdata/xml2json/dir-fat-cache.json index 8c0a045ed5..ef33add681 100644 --- a/tests/qemublocktestdata/xml2json/dir-fat-cache.json +++ b/tests/qemublocktestdata/xml2json/dir-fat-cache.json @@ -6,17 +6,18 @@ "no-flush": false }, "driver": "raw", - "file": { - "driver": "vvfat", - "dir": "/var/somefiles", - "floppy": false, - "rw": false, - "node-name": "node-s", - "cache": { - "direct": true, - "no-flush": false - }, - "read-only": true, - "discard": "unmap" - } + "file": "node-s" +} +{ + "driver": "vvfat", + "dir": "/var/somefiles", + "floppy": false, + "rw": false, + "node-name": "node-s", + "cache": { + "direct": true, + "no-flush": false + }, + "read-only": true, + "discard": "unmap" } diff --git a/tests/qemublocktestdata/xml2json/dir-fat-floppy.json b/tests/qemublocktestdata/xml2json/dir-fat-floppy.json index 9685acaa8b..db7954a6bc 100644 --- a/tests/qemublocktestdata/xml2json/dir-fat-floppy.json +++ b/tests/qemublocktestdata/xml2json/dir-fat-floppy.json @@ -2,13 +2,14 @@ "node-name": "node-f", "read-only": true, "driver": "raw", - "file": { - "driver": "vvfat", - "dir": "/var/somefiles", - "floppy": true, - "rw": false, - "node-name": "node-s", - "read-only": true, - "discard": "unmap" - } + "file": "node-s" +} +{ + "driver": "vvfat", + "dir": "/var/somefiles", + "floppy": true, + "rw": false, + "node-name": "node-s", + "read-only": true, + "discard": "unmap" } diff --git a/tests/qemublocktestdata/xml2json/dir-fat-readonly.json b/tests/qemublocktestdata/xml2json/dir-fat-readonly.json index 7d35d255cc..a306fb4d47 100644 --- a/tests/qemublocktestdata/xml2json/dir-fat-readonly.json +++ b/tests/qemublocktestdata/xml2json/dir-fat-readonly.json @@ -2,13 +2,14 @@ "node-name": "node-f", "read-only": true, "driver": "raw", - "file": { - "driver": "vvfat", - "dir": "/var/somefiles", - "floppy": false, - "rw": false, - "node-name": "node-s", - "read-only": true, - "discard": "unmap" - } + "file": "node-s" +} +{ + "driver": "vvfat", + "dir": "/var/somefiles", + "floppy": false, + "rw": false, + "node-name": "node-s", + "read-only": true, + "discard": "unmap" } diff --git a/tests/qemublocktestdata/xml2json/file-backing_basic-aio_threads.json b/tests/qemublocktestdata/xml2json/file-backing_basic-aio_threads.json index dcaf905085..a9bdd1bcc2 100644 --- a/tests/qemublocktestdata/xml2json/file-backing_basic-aio_threads.json +++ b/tests/qemublocktestdata/xml2json/file-backing_basic-aio_threads.json @@ -2,61 +2,65 @@ "node-name": "node-a-f", "read-only": false, "driver": "qcow", - "file": { - "driver": "file", - "filename": "/var/lib/libvirt/images/a", - "aio": "threads", - "node-name": "node-a-s", - "read-only": false, - "discard": "unmap" - }, + "file": "node-a-s", "backing": "node-b-f" } +{ + "driver": "file", + "filename": "/var/lib/libvirt/images/a", + "aio": "threads", + "node-name": "node-a-s", + "read-only": false, + "discard": "unmap" +} { "node-name": "node-b-f", "read-only": true, "driver": "qed", - "file": { - "driver": "file", - "filename": "/var/lib/libvirt/images/b", - "aio": "threads", - "node-name": "node-b-s", - "read-only": true, - "discard": "unmap" - }, + "file": "node-b-s", "backing": "node-c-f" } +{ + "driver": "file", + "filename": "/var/lib/libvirt/images/b", + "aio": "threads", + "node-name": "node-b-s", + "read-only": true, + "discard": "unmap" +} { "node-name": "node-c-f", "read-only": true, "driver": "vmdk", - "file": { - "driver": "gluster", - "volume": "images", - "path": "c", - "server": [ - { - "type": "inet", - "host": "test.org", - "port": "24007" - } - ], - "node-name": "node-c-s", - "read-only": true, - "discard": "unmap" - }, + "file": "node-c-s", "backing": "node-d-f" } +{ + "driver": "gluster", + "volume": "images", + "path": "c", + "server": [ + { + "type": "inet", + "host": "test.org", + "port": "24007" + } + ], + "node-name": "node-c-s", + "read-only": true, + "discard": "unmap" +} { "node-name": "node-d-f", "read-only": true, "driver": "raw", - "file": { - "driver": "file", - "filename": "/var/lib/libvirt/images/d", - "aio": "threads", - "node-name": "node-d-s", - "read-only": true, - "discard": "unmap" - } + "file": "node-d-s" +} +{ + "driver": "file", + "filename": "/var/lib/libvirt/images/d", + "aio": "threads", + "node-name": "node-d-s", + "read-only": true, + "discard": "unmap" } diff --git a/tests/qemublocktestdata/xml2json/file-backing_basic-cache-directsync.json b/tests/qemublocktestdata/xml2json/file-backing_basic-cache-directsync.json index 023caf013f..18cd183cd8 100644 --- a/tests/qemublocktestdata/xml2json/file-backing_basic-cache-directsync.json +++ b/tests/qemublocktestdata/xml2json/file-backing_basic-cache-directsync.json @@ -6,19 +6,20 @@ "no-flush": false }, "driver": "qcow2", - "file": { - "driver": "file", - "filename": "/var/lib/libvirt/images/a", - "node-name": "node-a-s", - "cache": { - "direct": true, - "no-flush": false - }, - "read-only": false, - "discard": "unmap" - }, + "file": "node-a-s", "backing": "node-b-f" } +{ + "driver": "file", + "filename": "/var/lib/libvirt/images/a", + "node-name": "node-a-s", + "cache": { + "direct": true, + "no-flush": false + }, + "read-only": false, + "discard": "unmap" +} { "node-name": "node-b-f", "read-only": true, @@ -27,19 +28,20 @@ "no-flush": false }, "driver": "qcow2", - "file": { - "driver": "file", - "filename": "/var/lib/libvirt/images/b", - "node-name": "node-b-s", - "cache": { - "direct": true, - "no-flush": false - }, - "read-only": true, - "discard": "unmap" - }, + "file": "node-b-s", "backing": "node-c-f" } +{ + "driver": "file", + "filename": "/var/lib/libvirt/images/b", + "node-name": "node-b-s", + "cache": { + "direct": true, + "no-flush": false + }, + "read-only": true, + "discard": "unmap" +} { "node-name": "node-c-f", "read-only": true, @@ -48,27 +50,28 @@ "no-flush": false }, "driver": "qcow2", - "file": { - "driver": "gluster", - "volume": "images", - "path": "c", - "server": [ - { - "type": "inet", - "host": "test.org", - "port": "24007" - } - ], - "node-name": "node-c-s", - "cache": { - "direct": true, - "no-flush": false - }, - "read-only": true, - "discard": "unmap" - }, + "file": "node-c-s", "backing": "node-d-f" } +{ + "driver": "gluster", + "volume": "images", + "path": "c", + "server": [ + { + "type": "inet", + "host": "test.org", + "port": "24007" + } + ], + "node-name": "node-c-s", + "cache": { + "direct": true, + "no-flush": false + }, + "read-only": true, + "discard": "unmap" +} { "node-name": "node-d-f", "read-only": true, @@ -77,15 +80,16 @@ "no-flush": false }, "driver": "raw", - "file": { - "driver": "file", - "filename": "/var/lib/libvirt/images/d", - "node-name": "node-d-s", - "cache": { - "direct": true, - "no-flush": false - }, - "read-only": true, - "discard": "unmap" - } + "file": "node-d-s" +} +{ + "driver": "file", + "filename": "/var/lib/libvirt/images/d", + "node-name": "node-d-s", + "cache": { + "direct": true, + "no-flush": false + }, + "read-only": true, + "discard": "unmap" } diff --git a/tests/qemublocktestdata/xml2json/file-backing_basic-cache-none.json b/tests/qemublocktestdata/xml2json/file-backing_basic-cache-none.json index 023caf013f..18cd183cd8 100644 --- a/tests/qemublocktestdata/xml2json/file-backing_basic-cache-none.json +++ b/tests/qemublocktestdata/xml2json/file-backing_basic-cache-none.json @@ -6,19 +6,20 @@ "no-flush": false }, "driver": "qcow2", - "file": { - "driver": "file", - "filename": "/var/lib/libvirt/images/a", - "node-name": "node-a-s", - "cache": { - "direct": true, - "no-flush": false - }, - "read-only": false, - "discard": "unmap" - }, + "file": "node-a-s", "backing": "node-b-f" } +{ + "driver": "file", + "filename": "/var/lib/libvirt/images/a", + "node-name": "node-a-s", + "cache": { + "direct": true, + "no-flush": false + }, + "read-only": false, + "discard": "unmap" +} { "node-name": "node-b-f", "read-only": true, @@ -27,19 +28,20 @@ "no-flush": false }, "driver": "qcow2", - "file": { - "driver": "file", - "filename": "/var/lib/libvirt/images/b", - "node-name": "node-b-s", - "cache": { - "direct": true, - "no-flush": false - }, - "read-only": true, - "discard": "unmap" - }, + "file": "node-b-s", "backing": "node-c-f" } +{ + "driver": "file", + "filename": "/var/lib/libvirt/images/b", + "node-name": "node-b-s", + "cache": { + "direct": true, + "no-flush": false + }, + "read-only": true, + "discard": "unmap" +} { "node-name": "node-c-f", "read-only": true, @@ -48,27 +50,28 @@ "no-flush": false }, "driver": "qcow2", - "file": { - "driver": "gluster", - "volume": "images", - "path": "c", - "server": [ - { - "type": "inet", - "host": "test.org", - "port": "24007" - } - ], - "node-name": "node-c-s", - "cache": { - "direct": true, - "no-flush": false - }, - "read-only": true, - "discard": "unmap" - }, + "file": "node-c-s", "backing": "node-d-f" } +{ + "driver": "gluster", + "volume": "images", + "path": "c", + "server": [ + { + "type": "inet", + "host": "test.org", + "port": "24007" + } + ], + "node-name": "node-c-s", + "cache": { + "direct": true, + "no-flush": false + }, + "read-only": true, + "discard": "unmap" +} { "node-name": "node-d-f", "read-only": true, @@ -77,15 +80,16 @@ "no-flush": false }, "driver": "raw", - "file": { - "driver": "file", - "filename": "/var/lib/libvirt/images/d", - "node-name": "node-d-s", - "cache": { - "direct": true, - "no-flush": false - }, - "read-only": true, - "discard": "unmap" - } + "file": "node-d-s" +} +{ + "driver": "file", + "filename": "/var/lib/libvirt/images/d", + "node-name": "node-d-s", + "cache": { + "direct": true, + "no-flush": false + }, + "read-only": true, + "discard": "unmap" } diff --git a/tests/qemublocktestdata/xml2json/file-backing_basic-cache-unsafe.json b/tests/qemublocktestdata/xml2json/file-backing_basic-cache-unsafe.json index 5f6b94a9d5..4e92061c65 100644 --- a/tests/qemublocktestdata/xml2json/file-backing_basic-cache-unsafe.json +++ b/tests/qemublocktestdata/xml2json/file-backing_basic-cache-unsafe.json @@ -6,19 +6,20 @@ "no-flush": true }, "driver": "qcow2", - "file": { - "driver": "file", - "filename": "/var/lib/libvirt/images/a", - "node-name": "node-a-s", - "cache": { - "direct": false, - "no-flush": true - }, - "read-only": false, - "discard": "unmap" - }, + "file": "node-a-s", "backing": "node-b-f" } +{ + "driver": "file", + "filename": "/var/lib/libvirt/images/a", + "node-name": "node-a-s", + "cache": { + "direct": false, + "no-flush": true + }, + "read-only": false, + "discard": "unmap" +} { "node-name": "node-b-f", "read-only": true, @@ -27,19 +28,20 @@ "no-flush": true }, "driver": "qcow2", - "file": { - "driver": "file", - "filename": "/var/lib/libvirt/images/b", - "node-name": "node-b-s", - "cache": { - "direct": false, - "no-flush": true - }, - "read-only": true, - "discard": "unmap" - }, + "file": "node-b-s", "backing": "node-c-f" } +{ + "driver": "file", + "filename": "/var/lib/libvirt/images/b", + "node-name": "node-b-s", + "cache": { + "direct": false, + "no-flush": true + }, + "read-only": true, + "discard": "unmap" +} { "node-name": "node-c-f", "read-only": true, @@ -48,27 +50,28 @@ "no-flush": true }, "driver": "qcow2", - "file": { - "driver": "gluster", - "volume": "images", - "path": "c", - "server": [ - { - "type": "inet", - "host": "test.org", - "port": "24007" - } - ], - "node-name": "node-c-s", - "cache": { - "direct": false, - "no-flush": true - }, - "read-only": true, - "discard": "unmap" - }, + "file": "node-c-s", "backing": "node-d-f" } +{ + "driver": "gluster", + "volume": "images", + "path": "c", + "server": [ + { + "type": "inet", + "host": "test.org", + "port": "24007" + } + ], + "node-name": "node-c-s", + "cache": { + "direct": false, + "no-flush": true + }, + "read-only": true, + "discard": "unmap" +} { "node-name": "node-d-f", "read-only": true, @@ -77,15 +80,16 @@ "no-flush": true }, "driver": "raw", - "file": { - "driver": "file", - "filename": "/var/lib/libvirt/images/d", - "node-name": "node-d-s", - "cache": { - "direct": false, - "no-flush": true - }, - "read-only": true, - "discard": "unmap" - } + "file": "node-d-s" +} +{ + "driver": "file", + "filename": "/var/lib/libvirt/images/d", + "node-name": "node-d-s", + "cache": { + "direct": false, + "no-flush": true + }, + "read-only": true, + "discard": "unmap" } diff --git a/tests/qemublocktestdata/xml2json/file-backing_basic-cache-writeback.json b/tests/qemublocktestdata/xml2json/file-backing_basic-cache-writeback.json index 9dc7d38850..a105b47483 100644 --- a/tests/qemublocktestdata/xml2json/file-backing_basic-cache-writeback.json +++ b/tests/qemublocktestdata/xml2json/file-backing_basic-cache-writeback.json @@ -6,19 +6,20 @@ "no-flush": false }, "driver": "qcow2", - "file": { - "driver": "file", - "filename": "/var/lib/libvirt/images/a", - "node-name": "node-a-s", - "cache": { - "direct": false, - "no-flush": false - }, - "read-only": false, - "discard": "unmap" - }, + "file": "node-a-s", "backing": "node-b-f" } +{ + "driver": "file", + "filename": "/var/lib/libvirt/images/a", + "node-name": "node-a-s", + "cache": { + "direct": false, + "no-flush": false + }, + "read-only": false, + "discard": "unmap" +} { "node-name": "node-b-f", "read-only": true, @@ -27,19 +28,20 @@ "no-flush": false }, "driver": "qcow2", - "file": { - "driver": "file", - "filename": "/var/lib/libvirt/images/b", - "node-name": "node-b-s", - "cache": { - "direct": false, - "no-flush": false - }, - "read-only": true, - "discard": "unmap" - }, + "file": "node-b-s", "backing": "node-c-f" } +{ + "driver": "file", + "filename": "/var/lib/libvirt/images/b", + "node-name": "node-b-s", + "cache": { + "direct": false, + "no-flush": false + }, + "read-only": true, + "discard": "unmap" +} { "node-name": "node-c-f", "read-only": true, @@ -48,27 +50,28 @@ "no-flush": false }, "driver": "qcow2", - "file": { - "driver": "gluster", - "volume": "images", - "path": "c", - "server": [ - { - "type": "inet", - "host": "test.org", - "port": "24007" - } - ], - "node-name": "node-c-s", - "cache": { - "direct": false, - "no-flush": false - }, - "read-only": true, - "discard": "unmap" - }, + "file": "node-c-s", "backing": "node-d-f" } +{ + "driver": "gluster", + "volume": "images", + "path": "c", + "server": [ + { + "type": "inet", + "host": "test.org", + "port": "24007" + } + ], + "node-name": "node-c-s", + "cache": { + "direct": false, + "no-flush": false + }, + "read-only": true, + "discard": "unmap" +} { "node-name": "node-d-f", "read-only": true, @@ -77,15 +80,16 @@ "no-flush": false }, "driver": "raw", - "file": { - "driver": "file", - "filename": "/var/lib/libvirt/images/d", - "node-name": "node-d-s", - "cache": { - "direct": false, - "no-flush": false - }, - "read-only": true, - "discard": "unmap" - } + "file": "node-d-s" +} +{ + "driver": "file", + "filename": "/var/lib/libvirt/images/d", + "node-name": "node-d-s", + "cache": { + "direct": false, + "no-flush": false + }, + "read-only": true, + "discard": "unmap" } diff --git a/tests/qemublocktestdata/xml2json/file-backing_basic-cache-writethrough.json b/tests/qemublocktestdata/xml2json/file-backing_basic-cache-writethrough.json index 9dc7d38850..a105b47483 100644 --- a/tests/qemublocktestdata/xml2json/file-backing_basic-cache-writethrough.json +++ b/tests/qemublocktestdata/xml2json/file-backing_basic-cache-writethrough.json @@ -6,19 +6,20 @@ "no-flush": false }, "driver": "qcow2", - "file": { - "driver": "file", - "filename": "/var/lib/libvirt/images/a", - "node-name": "node-a-s", - "cache": { - "direct": false, - "no-flush": false - }, - "read-only": false, - "discard": "unmap" - }, + "file": "node-a-s", "backing": "node-b-f" } +{ + "driver": "file", + "filename": "/var/lib/libvirt/images/a", + "node-name": "node-a-s", + "cache": { + "direct": false, + "no-flush": false + }, + "read-only": false, + "discard": "unmap" +} { "node-name": "node-b-f", "read-only": true, @@ -27,19 +28,20 @@ "no-flush": false }, "driver": "qcow2", - "file": { - "driver": "file", - "filename": "/var/lib/libvirt/images/b", - "node-name": "node-b-s", - "cache": { - "direct": false, - "no-flush": false - }, - "read-only": true, - "discard": "unmap" - }, + "file": "node-b-s", "backing": "node-c-f" } +{ + "driver": "file", + "filename": "/var/lib/libvirt/images/b", + "node-name": "node-b-s", + "cache": { + "direct": false, + "no-flush": false + }, + "read-only": true, + "discard": "unmap" +} { "node-name": "node-c-f", "read-only": true, @@ -48,27 +50,28 @@ "no-flush": false }, "driver": "qcow2", - "file": { - "driver": "gluster", - "volume": "images", - "path": "c", - "server": [ - { - "type": "inet", - "host": "test.org", - "port": "24007" - } - ], - "node-name": "node-c-s", - "cache": { - "direct": false, - "no-flush": false - }, - "read-only": true, - "discard": "unmap" - }, + "file": "node-c-s", "backing": "node-d-f" } +{ + "driver": "gluster", + "volume": "images", + "path": "c", + "server": [ + { + "type": "inet", + "host": "test.org", + "port": "24007" + } + ], + "node-name": "node-c-s", + "cache": { + "direct": false, + "no-flush": false + }, + "read-only": true, + "discard": "unmap" +} { "node-name": "node-d-f", "read-only": true, @@ -77,15 +80,16 @@ "no-flush": false }, "driver": "raw", - "file": { - "driver": "file", - "filename": "/var/lib/libvirt/images/d", - "node-name": "node-d-s", - "cache": { - "direct": false, - "no-flush": false - }, - "read-only": true, - "discard": "unmap" - } + "file": "node-d-s" +} +{ + "driver": "file", + "filename": "/var/lib/libvirt/images/d", + "node-name": "node-d-s", + "cache": { + "direct": false, + "no-flush": false + }, + "read-only": true, + "discard": "unmap" } diff --git a/tests/qemublocktestdata/xml2json/file-backing_basic-detect.json b/tests/qemublocktestdata/xml2json/file-backing_basic-detect.json index c1e4c40757..44a6e90fcd 100644 --- a/tests/qemublocktestdata/xml2json/file-backing_basic-detect.json +++ b/tests/qemublocktestdata/xml2json/file-backing_basic-detect.json @@ -3,58 +3,62 @@ "read-only": false, "detect-zeroes": "on", "driver": "qcow", - "file": { - "driver": "file", - "filename": "/var/lib/libvirt/images/a", - "node-name": "node-a-s", - "read-only": false, - "discard": "unmap" - }, + "file": "node-a-s", "backing": "node-b-f" } +{ + "driver": "file", + "filename": "/var/lib/libvirt/images/a", + "node-name": "node-a-s", + "read-only": false, + "discard": "unmap" +} { "node-name": "node-b-f", "read-only": true, "driver": "qed", - "file": { - "driver": "file", - "filename": "/var/lib/libvirt/images/b", - "node-name": "node-b-s", - "read-only": true, - "discard": "unmap" - }, + "file": "node-b-s", "backing": "node-c-f" } +{ + "driver": "file", + "filename": "/var/lib/libvirt/images/b", + "node-name": "node-b-s", + "read-only": true, + "discard": "unmap" +} { "node-name": "node-c-f", "read-only": true, "driver": "vmdk", - "file": { - "driver": "gluster", - "volume": "images", - "path": "c", - "server": [ - { - "type": "inet", - "host": "test.org", - "port": "24007" - } - ], - "node-name": "node-c-s", - "read-only": true, - "discard": "unmap" - }, + "file": "node-c-s", "backing": "node-d-f" } +{ + "driver": "gluster", + "volume": "images", + "path": "c", + "server": [ + { + "type": "inet", + "host": "test.org", + "port": "24007" + } + ], + "node-name": "node-c-s", + "read-only": true, + "discard": "unmap" +} { "node-name": "node-d-f", "read-only": true, "driver": "raw", - "file": { - "driver": "file", - "filename": "/var/lib/libvirt/images/d", - "node-name": "node-d-s", - "read-only": true, - "discard": "unmap" - } + "file": "node-d-s" +} +{ + "driver": "file", + "filename": "/var/lib/libvirt/images/d", + "node-name": "node-d-s", + "read-only": true, + "discard": "unmap" } diff --git a/tests/qemublocktestdata/xml2json/file-backing_basic-noopts.json b/tests/qemublocktestdata/xml2json/file-backing_basic-noopts.json index 3285a6ec67..b0fd9b6988 100644 --- a/tests/qemublocktestdata/xml2json/file-backing_basic-noopts.json +++ b/tests/qemublocktestdata/xml2json/file-backing_basic-noopts.json @@ -2,50 +2,54 @@ "node-name": "node-a-f", "read-only": false, "driver": "qed", - "file": { - "driver": "file", - "filename": "/var/lib/libvirt/images/a", - "node-name": "node-a-s", - "read-only": false, - "discard": "unmap" - }, + "file": "node-a-s", "backing": "node-b-f" } +{ + "driver": "file", + "filename": "/var/lib/libvirt/images/a", + "node-name": "node-a-s", + "read-only": false, + "discard": "unmap" +} { "node-name": "node-b-f", "read-only": true, "driver": "qcow", - "file": { - "driver": "file", - "filename": "/var/lib/libvirt/images/b", - "node-name": "node-b-s", - "read-only": true, - "discard": "unmap" - }, + "file": "node-b-s", "backing": "node-c-f" } +{ + "driver": "file", + "filename": "/var/lib/libvirt/images/b", + "node-name": "node-b-s", + "read-only": true, + "discard": "unmap" +} { "node-name": "node-c-f", "read-only": true, "driver": "vmdk", - "file": { - "driver": "file", - "filename": "/var/lib/libvirt/images/c", - "node-name": "node-c-s", - "read-only": true, - "discard": "unmap" - }, + "file": "node-c-s", "backing": "node-d-f" } +{ + "driver": "file", + "filename": "/var/lib/libvirt/images/c", + "node-name": "node-c-s", + "read-only": true, + "discard": "unmap" +} { "node-name": "node-d-f", "read-only": true, "driver": "raw", - "file": { - "driver": "file", - "filename": "/var/lib/libvirt/images/d", - "node-name": "node-d-s", - "read-only": true, - "discard": "unmap" - } + "file": "node-d-s" +} +{ + "driver": "file", + "filename": "/var/lib/libvirt/images/d", + "node-name": "node-d-s", + "read-only": true, + "discard": "unmap" } diff --git a/tests/qemublocktestdata/xml2json/file-backing_basic-unmap-detect.json b/tests/qemublocktestdata/xml2json/file-backing_basic-unmap-detect.json index b00008dd54..6cf4e77090 100644 --- a/tests/qemublocktestdata/xml2json/file-backing_basic-unmap-detect.json +++ b/tests/qemublocktestdata/xml2json/file-backing_basic-unmap-detect.json @@ -4,61 +4,65 @@ "discard": "unmap", "detect-zeroes": "unmap", "driver": "qcow", - "file": { - "driver": "file", - "filename": "/var/lib/libvirt/images/a", - "node-name": "node-a-s", - "read-only": false, - "discard": "unmap" - }, + "file": "node-a-s", "backing": "node-b-f" } +{ + "driver": "file", + "filename": "/var/lib/libvirt/images/a", + "node-name": "node-a-s", + "read-only": false, + "discard": "unmap" +} { "node-name": "node-b-f", "read-only": true, "discard": "unmap", "driver": "qed", - "file": { - "driver": "file", - "filename": "/var/lib/libvirt/images/b", - "node-name": "node-b-s", - "read-only": true, - "discard": "unmap" - }, + "file": "node-b-s", "backing": "node-c-f" } +{ + "driver": "file", + "filename": "/var/lib/libvirt/images/b", + "node-name": "node-b-s", + "read-only": true, + "discard": "unmap" +} { "node-name": "node-c-f", "read-only": true, "discard": "unmap", "driver": "vmdk", - "file": { - "driver": "gluster", - "volume": "images", - "path": "c", - "server": [ - { - "type": "inet", - "host": "test.org", - "port": "24007" - } - ], - "node-name": "node-c-s", - "read-only": true, - "discard": "unmap" - }, + "file": "node-c-s", "backing": "node-d-f" } +{ + "driver": "gluster", + "volume": "images", + "path": "c", + "server": [ + { + "type": "inet", + "host": "test.org", + "port": "24007" + } + ], + "node-name": "node-c-s", + "read-only": true, + "discard": "unmap" +} { "node-name": "node-d-f", "read-only": true, "discard": "unmap", "driver": "raw", - "file": { - "driver": "file", - "filename": "/var/lib/libvirt/images/d", - "node-name": "node-d-s", - "read-only": true, - "discard": "unmap" - } + "file": "node-d-s" +} +{ + "driver": "file", + "filename": "/var/lib/libvirt/images/d", + "node-name": "node-d-s", + "read-only": true, + "discard": "unmap" } diff --git a/tests/qemublocktestdata/xml2json/file-backing_basic-unmap-ignore.json b/tests/qemublocktestdata/xml2json/file-backing_basic-unmap-ignore.json index 5419deafc0..b6e454297f 100644 --- a/tests/qemublocktestdata/xml2json/file-backing_basic-unmap-ignore.json +++ b/tests/qemublocktestdata/xml2json/file-backing_basic-unmap-ignore.json @@ -4,61 +4,65 @@ "discard": "ignore", "detect-zeroes": "on", "driver": "qcow", - "file": { - "driver": "file", - "filename": "/var/lib/libvirt/images/a", - "node-name": "node-a-s", - "read-only": false, - "discard": "unmap" - }, + "file": "node-a-s", "backing": "node-b-f" } +{ + "driver": "file", + "filename": "/var/lib/libvirt/images/a", + "node-name": "node-a-s", + "read-only": false, + "discard": "unmap" +} { "node-name": "node-b-f", "read-only": true, "discard": "ignore", "driver": "qed", - "file": { - "driver": "file", - "filename": "/var/lib/libvirt/images/b", - "node-name": "node-b-s", - "read-only": true, - "discard": "unmap" - }, + "file": "node-b-s", "backing": "node-c-f" } +{ + "driver": "file", + "filename": "/var/lib/libvirt/images/b", + "node-name": "node-b-s", + "read-only": true, + "discard": "unmap" +} { "node-name": "node-c-f", "read-only": true, "discard": "ignore", "driver": "vmdk", - "file": { - "driver": "gluster", - "volume": "images", - "path": "c", - "server": [ - { - "type": "inet", - "host": "test.org", - "port": "24007" - } - ], - "node-name": "node-c-s", - "read-only": true, - "discard": "unmap" - }, + "file": "node-c-s", "backing": "node-d-f" } +{ + "driver": "gluster", + "volume": "images", + "path": "c", + "server": [ + { + "type": "inet", + "host": "test.org", + "port": "24007" + } + ], + "node-name": "node-c-s", + "read-only": true, + "discard": "unmap" +} { "node-name": "node-d-f", "read-only": true, "discard": "ignore", "driver": "raw", - "file": { - "driver": "file", - "filename": "/var/lib/libvirt/images/d", - "node-name": "node-d-s", - "read-only": true, - "discard": "unmap" - } + "file": "node-d-s" +} +{ + "driver": "file", + "filename": "/var/lib/libvirt/images/d", + "node-name": "node-d-s", + "read-only": true, + "discard": "unmap" } diff --git a/tests/qemublocktestdata/xml2json/file-backing_basic-unmap.json b/tests/qemublocktestdata/xml2json/file-backing_basic-unmap.json index 1efc462c06..21a10c8543 100644 --- a/tests/qemublocktestdata/xml2json/file-backing_basic-unmap.json +++ b/tests/qemublocktestdata/xml2json/file-backing_basic-unmap.json @@ -3,61 +3,65 @@ "read-only": false, "discard": "unmap", "driver": "qcow", - "file": { - "driver": "file", - "filename": "/var/lib/libvirt/images/a", - "node-name": "node-a-s", - "read-only": false, - "discard": "unmap" - }, + "file": "node-a-s", "backing": "node-b-f" } +{ + "driver": "file", + "filename": "/var/lib/libvirt/images/a", + "node-name": "node-a-s", + "read-only": false, + "discard": "unmap" +} { "node-name": "node-b-f", "read-only": true, "discard": "unmap", "driver": "qed", - "file": { - "driver": "file", - "filename": "/var/lib/libvirt/images/b", - "node-name": "node-b-s", - "read-only": true, - "discard": "unmap" - }, + "file": "node-b-s", "backing": "node-c-f" } +{ + "driver": "file", + "filename": "/var/lib/libvirt/images/b", + "node-name": "node-b-s", + "read-only": true, + "discard": "unmap" +} { "node-name": "node-c-f", "read-only": true, "discard": "unmap", "driver": "vmdk", - "file": { - "driver": "gluster", - "volume": "images", - "path": "c", - "server": [ - { - "type": "inet", - "host": "test.org", - "port": "24007" - } - ], - "node-name": "node-c-s", - "read-only": true, - "discard": "unmap" - }, + "file": "node-c-s", "backing": "node-d-f" } +{ + "driver": "gluster", + "volume": "images", + "path": "c", + "server": [ + { + "type": "inet", + "host": "test.org", + "port": "24007" + } + ], + "node-name": "node-c-s", + "read-only": true, + "discard": "unmap" +} { "node-name": "node-d-f", "read-only": true, "discard": "unmap", "driver": "raw", - "file": { - "driver": "file", - "filename": "/var/lib/libvirt/images/d", - "node-name": "node-d-s", - "read-only": true, - "discard": "unmap" - } + "file": "node-d-s" +} +{ + "driver": "file", + "filename": "/var/lib/libvirt/images/d", + "node-name": "node-d-s", + "read-only": true, + "discard": "unmap" } diff --git a/tests/qemublocktestdata/xml2json/file-bochs-noopts.json b/tests/qemublocktestdata/xml2json/file-bochs-noopts.json index 22e2560998..6ab43b2a1c 100644 --- a/tests/qemublocktestdata/xml2json/file-bochs-noopts.json +++ b/tests/qemublocktestdata/xml2json/file-bochs-noopts.json @@ -2,11 +2,12 @@ "node-name": "test1", "read-only": false, "driver": "bochs", - "file": { - "driver": "file", - "filename": "/path/to/i.img", - "node-name": "test2", - "read-only": false, - "discard": "unmap" - } + "file": "test2" +} +{ + "driver": "file", + "filename": "/path/to/i.img", + "node-name": "test2", + "read-only": false, + "discard": "unmap" } diff --git a/tests/qemublocktestdata/xml2json/file-cloop-noopts.json b/tests/qemublocktestdata/xml2json/file-cloop-noopts.json index b72bb5df56..f709c3d3bd 100644 --- a/tests/qemublocktestdata/xml2json/file-cloop-noopts.json +++ b/tests/qemublocktestdata/xml2json/file-cloop-noopts.json @@ -2,11 +2,12 @@ "node-name": "test1", "read-only": false, "driver": "cloop", - "file": { - "driver": "file", - "filename": "/path/to/i.img", - "node-name": "test2", - "read-only": false, - "discard": "unmap" - } + "file": "test2" +} +{ + "driver": "file", + "filename": "/path/to/i.img", + "node-name": "test2", + "read-only": false, + "discard": "unmap" } diff --git a/tests/qemublocktestdata/xml2json/file-dmg-noopts.json b/tests/qemublocktestdata/xml2json/file-dmg-noopts.json index 9f2912b8d3..55261de4b2 100644 --- a/tests/qemublocktestdata/xml2json/file-dmg-noopts.json +++ b/tests/qemublocktestdata/xml2json/file-dmg-noopts.json @@ -2,11 +2,12 @@ "node-name": "test1", "read-only": false, "driver": "dmg", - "file": { - "driver": "file", - "filename": "/path/to/i.img", - "node-name": "test2", - "read-only": false, - "discard": "unmap" - } + "file": "test2" +} +{ + "driver": "file", + "filename": "/path/to/i.img", + "node-name": "test2", + "read-only": false, + "discard": "unmap" } diff --git a/tests/qemublocktestdata/xml2json/file-ploop-noopts.json b/tests/qemublocktestdata/xml2json/file-ploop-noopts.json index 64006d28a3..81fa263098 100644 --- a/tests/qemublocktestdata/xml2json/file-ploop-noopts.json +++ b/tests/qemublocktestdata/xml2json/file-ploop-noopts.json @@ -2,11 +2,12 @@ "node-name": "test1", "read-only": false, "driver": "parallels", - "file": { - "driver": "file", - "filename": "/path/to/i.img", - "node-name": "test2", - "read-only": false, - "discard": "unmap" - } + "file": "test2" +} +{ + "driver": "file", + "filename": "/path/to/i.img", + "node-name": "test2", + "read-only": false, + "discard": "unmap" } diff --git a/tests/qemublocktestdata/xml2json/file-qcow2-backing-chain-encryption.json b/tests/qemublocktestdata/xml2json/file-qcow2-backing-chain-encryption.json index 94e2ecd1e2..3469c06654 100644 --- a/tests/qemublocktestdata/xml2json/file-qcow2-backing-chain-encryption.json +++ b/tests/qemublocktestdata/xml2json/file-qcow2-backing-chain-encryption.json @@ -6,15 +6,16 @@ "format": "luks", "key-secret": "node-b-f-encalias" }, - "file": { - "driver": "file", - "filename": "/var/lib/libvirt/images/a", - "node-name": "node-a-s", - "read-only": false, - "discard": "unmap" - }, + "file": "node-a-s", "backing": "node-b-f" } +{ + "driver": "file", + "filename": "/var/lib/libvirt/images/a", + "node-name": "node-a-s", + "read-only": false, + "discard": "unmap" +} { "node-name": "node-b-f", "read-only": true, @@ -23,12 +24,13 @@ "format": "aes", "key-secret": "node-b-f-encalias" }, - "file": { - "driver": "file", - "filename": "/var/lib/libvirt/images/b", - "node-name": "node-b-s", - "read-only": true, - "discard": "unmap" - }, + "file": "node-b-s", "backing": null } +{ + "driver": "file", + "filename": "/var/lib/libvirt/images/b", + "node-name": "node-b-s", + "read-only": true, + "discard": "unmap" +} diff --git a/tests/qemublocktestdata/xml2json/file-qcow2-backing-chain-noopts.json b/tests/qemublocktestdata/xml2json/file-qcow2-backing-chain-noopts.json index 3e7c08f080..6bc6e2fe30 100644 --- a/tests/qemublocktestdata/xml2json/file-qcow2-backing-chain-noopts.json +++ b/tests/qemublocktestdata/xml2json/file-qcow2-backing-chain-noopts.json @@ -2,129 +2,139 @@ "node-name": "#block126", "read-only": false, "driver": "qcow2", - "file": { - "driver": "file", - "filename": "/var/lib/libvirt/images/rhel7.3.1507297895", - "node-name": "#block004", - "read-only": false, - "discard": "unmap" - }, + "file": "#block004", "backing": "#block313" } +{ + "driver": "file", + "filename": "/var/lib/libvirt/images/rhel7.3.1507297895", + "node-name": "#block004", + "read-only": false, + "discard": "unmap" +} { "node-name": "#block313", "read-only": true, "driver": "qcow2", - "file": { - "driver": "file", - "filename": "/var/lib/libvirt/images/rhel7.3.1484071872", - "node-name": "#block256", - "read-only": true, - "discard": "unmap" - }, + "file": "#block256", "backing": "#block556" } +{ + "driver": "file", + "filename": "/var/lib/libvirt/images/rhel7.3.1484071872", + "node-name": "#block256", + "read-only": true, + "discard": "unmap" +} { "node-name": "#block556", "read-only": true, "driver": "qcow2", - "file": { - "driver": "file", - "filename": "/var/lib/libvirt/images/rhel7.3.1483615252", - "node-name": "#block418", - "read-only": true, - "discard": "unmap" - }, + "file": "#block418", "backing": "#block767" } +{ + "driver": "file", + "filename": "/var/lib/libvirt/images/rhel7.3.1483615252", + "node-name": "#block418", + "read-only": true, + "discard": "unmap" +} { "node-name": "#block767", "read-only": true, "driver": "qcow2", - "file": { - "driver": "file", - "filename": "/var/lib/libvirt/images/rhel7.3.1483605924", - "node-name": "#block624", - "read-only": true, - "discard": "unmap" - }, + "file": "#block624", "backing": "#block937" } +{ + "driver": "file", + "filename": "/var/lib/libvirt/images/rhel7.3.1483605924", + "node-name": "#block624", + "read-only": true, + "discard": "unmap" +} { "node-name": "#block937", "read-only": true, "driver": "qcow2", - "file": { - "driver": "file", - "filename": "/var/lib/libvirt/images/rhel7.3.1483605920", - "node-name": "#block869", - "read-only": true, - "discard": "unmap" - }, + "file": "#block869", "backing": "#block1157" } +{ + "driver": "file", + "filename": "/var/lib/libvirt/images/rhel7.3.1483605920", + "node-name": "#block869", + "read-only": true, + "discard": "unmap" +} { "node-name": "#block1157", "read-only": true, "driver": "qcow2", - "file": { - "driver": "file", - "filename": "/var/lib/libvirt/images/rhel7.3.1483546244", - "node-name": "#block1047", - "read-only": true, - "discard": "unmap" - }, + "file": "#block1047", "backing": "#block1392" } +{ + "driver": "file", + "filename": "/var/lib/libvirt/images/rhel7.3.1483546244", + "node-name": "#block1047", + "read-only": true, + "discard": "unmap" +} { "node-name": "#block1392", "read-only": true, "driver": "qcow2", - "file": { - "driver": "file", - "filename": "/var/lib/libvirt/images/rhel7.3.1483545901", - "node-name": "#block1279", - "read-only": true, - "discard": "unmap" - }, + "file": "#block1279", "backing": "#block1523" } +{ + "driver": "file", + "filename": "/var/lib/libvirt/images/rhel7.3.1483545901", + "node-name": "#block1279", + "read-only": true, + "discard": "unmap" +} { "node-name": "#block1523", "read-only": true, "driver": "qcow2", - "file": { - "driver": "file", - "filename": "/var/lib/libvirt/images/rhel7.3.1483545313", - "node-name": "#block1444", - "read-only": true, - "discard": "unmap" - }, + "file": "#block1444", "backing": "#block1742" } +{ + "driver": "file", + "filename": "/var/lib/libvirt/images/rhel7.3.1483545313", + "node-name": "#block1444", + "read-only": true, + "discard": "unmap" +} { "node-name": "#block1742", "read-only": true, "driver": "qcow2", - "file": { - "driver": "file", - "filename": "/var/lib/libvirt/images/rhel7.3.1483536402", - "node-name": "#block1602", - "read-only": true, - "discard": "unmap" - }, + "file": "#block1602", "backing": "#block1909" } +{ + "driver": "file", + "filename": "/var/lib/libvirt/images/rhel7.3.1483536402", + "node-name": "#block1602", + "read-only": true, + "discard": "unmap" +} { "node-name": "#block1909", "read-only": true, "driver": "qcow2", - "file": { - "driver": "file", - "filename": "/var/lib/libvirt/images/rhel7.3.qcow2", - "node-name": "#block1864", - "read-only": true, - "discard": "unmap" - }, + "file": "#block1864", "backing": null } +{ + "driver": "file", + "filename": "/var/lib/libvirt/images/rhel7.3.qcow2", + "node-name": "#block1864", + "read-only": true, + "discard": "unmap" +} diff --git a/tests/qemublocktestdata/xml2json/file-qcow2-backing-chain-unterminated.json b/tests/qemublocktestdata/xml2json/file-qcow2-backing-chain-unterminated.json index 8fcdc48bb0..454c07faec 100644 --- a/tests/qemublocktestdata/xml2json/file-qcow2-backing-chain-unterminated.json +++ b/tests/qemublocktestdata/xml2json/file-qcow2-backing-chain-unterminated.json @@ -2,24 +2,26 @@ "node-name": "#block126", "read-only": false, "driver": "qcow2", - "file": { - "driver": "file", - "filename": "/var/lib/libvirt/images/rhel7.3.1507297895", - "node-name": "#block004", - "read-only": false, - "discard": "unmap" - }, + "file": "#block004", "backing": "#block313" } +{ + "driver": "file", + "filename": "/var/lib/libvirt/images/rhel7.3.1507297895", + "node-name": "#block004", + "read-only": false, + "discard": "unmap" +} { "node-name": "#block313", "read-only": true, "driver": "qcow2", - "file": { - "driver": "file", - "filename": "/var/lib/libvirt/images/rhel7.3.1484071872", - "node-name": "#block256", - "read-only": true, - "discard": "unmap" - } + "file": "#block256" +} +{ + "driver": "file", + "filename": "/var/lib/libvirt/images/rhel7.3.1484071872", + "node-name": "#block256", + "read-only": true, + "discard": "unmap" } diff --git a/tests/qemublocktestdata/xml2json/file-raw-aio_native.json b/tests/qemublocktestdata/xml2json/file-raw-aio_native.json index 2752e0b204..4e63561311 100644 --- a/tests/qemublocktestdata/xml2json/file-raw-aio_native.json +++ b/tests/qemublocktestdata/xml2json/file-raw-aio_native.json @@ -6,16 +6,17 @@ "no-flush": false }, "driver": "raw", - "file": { - "driver": "file", - "filename": "/path/to/i.img", - "aio": "native", - "node-name": "test2", - "cache": { - "direct": true, - "no-flush": false - }, - "read-only": false, - "discard": "unmap" - } + "file": "test2" +} +{ + "driver": "file", + "filename": "/path/to/i.img", + "aio": "native", + "node-name": "test2", + "cache": { + "direct": true, + "no-flush": false + }, + "read-only": false, + "discard": "unmap" } diff --git a/tests/qemublocktestdata/xml2json/file-raw-luks.json b/tests/qemublocktestdata/xml2json/file-raw-luks.json index e3d9c4c26b..c26dd3bba5 100644 --- a/tests/qemublocktestdata/xml2json/file-raw-luks.json +++ b/tests/qemublocktestdata/xml2json/file-raw-luks.json @@ -3,11 +3,12 @@ "read-only": false, "driver": "luks", "key-secret": "test1-encalias", - "file": { - "driver": "file", - "filename": "/path/luks.img", - "node-name": "test2", - "read-only": false, - "discard": "unmap" - } + "file": "test2" +} +{ + "driver": "file", + "filename": "/path/luks.img", + "node-name": "test2", + "read-only": false, + "discard": "unmap" } diff --git a/tests/qemublocktestdata/xml2json/file-raw-noopts.json b/tests/qemublocktestdata/xml2json/file-raw-noopts.json index 25de571428..cace1f6448 100644 --- a/tests/qemublocktestdata/xml2json/file-raw-noopts.json +++ b/tests/qemublocktestdata/xml2json/file-raw-noopts.json @@ -2,11 +2,12 @@ "node-name": "0123456789ABCDEF0123456789ABCDE", "read-only": false, "driver": "raw", - "file": { - "driver": "file", - "filename": "/var/lib/libvirt/images/i.img", - "node-name": "0123456789ABCDEF0123456789ABCDE", - "read-only": false, - "discard": "unmap" - } + "file": "0123456789ABCDEF0123456789ABCDE" +} +{ + "driver": "file", + "filename": "/var/lib/libvirt/images/i.img", + "node-name": "0123456789ABCDEF0123456789ABCDE", + "read-only": false, + "discard": "unmap" } diff --git a/tests/qemublocktestdata/xml2json/file-vdi-noopts.json b/tests/qemublocktestdata/xml2json/file-vdi-noopts.json index ce8e359c91..15f9da2091 100644 --- a/tests/qemublocktestdata/xml2json/file-vdi-noopts.json +++ b/tests/qemublocktestdata/xml2json/file-vdi-noopts.json @@ -2,11 +2,12 @@ "node-name": "test1", "read-only": false, "driver": "vdi", - "file": { - "driver": "file", - "filename": "/path/to/i.img", - "node-name": "test2", - "read-only": false, - "discard": "unmap" - } + "file": "test2" +} +{ + "driver": "file", + "filename": "/path/to/i.img", + "node-name": "test2", + "read-only": false, + "discard": "unmap" } diff --git a/tests/qemublocktestdata/xml2json/file-vhd-noopts.json b/tests/qemublocktestdata/xml2json/file-vhd-noopts.json index d4b8e1f55a..ce96c4be8a 100644 --- a/tests/qemublocktestdata/xml2json/file-vhd-noopts.json +++ b/tests/qemublocktestdata/xml2json/file-vhd-noopts.json @@ -2,11 +2,12 @@ "node-name": "test1", "read-only": false, "driver": "vhdx", - "file": { - "driver": "file", - "filename": "/path/to/i.img", - "node-name": "test2", - "read-only": false, - "discard": "unmap" - } + "file": "test2" +} +{ + "driver": "file", + "filename": "/path/to/i.img", + "node-name": "test2", + "read-only": false, + "discard": "unmap" } diff --git a/tests/qemublocktestdata/xml2json/file-vpc-noopts.json b/tests/qemublocktestdata/xml2json/file-vpc-noopts.json index be1ec795a7..9cba99e567 100644 --- a/tests/qemublocktestdata/xml2json/file-vpc-noopts.json +++ b/tests/qemublocktestdata/xml2json/file-vpc-noopts.json @@ -2,11 +2,12 @@ "node-name": "test1", "read-only": false, "driver": "vpc", - "file": { - "driver": "file", - "filename": "/path/to/i.img", - "node-name": "test2", - "read-only": false, - "discard": "unmap" - } + "file": "test2" +} +{ + "driver": "file", + "filename": "/path/to/i.img", + "node-name": "test2", + "read-only": false, + "discard": "unmap" } diff --git a/tests/qemublocktestdata/xml2json/network-qcow2-backing-chain-cache-unsafe.json b/tests/qemublocktestdata/xml2json/network-qcow2-backing-chain-cache-unsafe.json index 6161f3375d..80a694eee4 100644 --- a/tests/qemublocktestdata/xml2json/network-qcow2-backing-chain-cache-unsafe.json +++ b/tests/qemublocktestdata/xml2json/network-qcow2-backing-chain-cache-unsafe.json @@ -6,30 +6,31 @@ "no-flush": true }, "driver": "qcow2", - "file": { - "driver": "rbd", - "pool": "rbdpool", - "image": "rbdimg", - "server": [ - { - "host": "host1.example.com", - "port": "0" - }, - { - "host": "host2.example.com", - "port": "0" - } - ], - "user": "testuser-rbd", - "node-name": "node-a-s", - "cache": { - "direct": false, - "no-flush": true + "file": "node-a-s", + "backing": "node-b-f" +} +{ + "driver": "rbd", + "pool": "rbdpool", + "image": "rbdimg", + "server": [ + { + "host": "host1.example.com", + "port": "0" }, - "read-only": false, - "discard": "unmap" + { + "host": "host2.example.com", + "port": "0" + } + ], + "user": "testuser-rbd", + "node-name": "node-a-s", + "cache": { + "direct": false, + "no-flush": true }, - "backing": "node-b-f" + "read-only": false, + "discard": "unmap" } { "node-name": "node-b-f", @@ -39,19 +40,20 @@ "no-flush": true }, "driver": "qcow2", - "file": { - "driver": "iscsi", - "portal": "example.org:3260", - "target": "iscsitarget", - "lun": 1, - "transport": "tcp", - "node-name": "node-b-s", - "cache": { - "direct": false, - "no-flush": true - }, - "read-only": true, - "discard": "unmap" - }, + "file": "node-b-s", "backing": null } +{ + "driver": "iscsi", + "portal": "example.org:3260", + "target": "iscsitarget", + "lun": 1, + "transport": "tcp", + "node-name": "node-b-s", + "cache": { + "direct": false, + "no-flush": true + }, + "read-only": true, + "discard": "unmap" +} diff --git a/tests/qemublocktestdata/xml2json/network-qcow2-backing-chain-encryption_auth.json b/tests/qemublocktestdata/xml2json/network-qcow2-backing-chain-encryption_auth.json index 7e7a4e44f7..6e5abbfbdd 100644 --- a/tests/qemublocktestdata/xml2json/network-qcow2-backing-chain-encryption_auth.json +++ b/tests/qemublocktestdata/xml2json/network-qcow2-backing-chain-encryption_auth.json @@ -6,27 +6,28 @@ "format": "luks", "key-secret": "node-b-f-encalias" }, - "file": { - "driver": "rbd", - "pool": "rbdpool", - "image": "rbdimg", - "server": [ - { - "host": "host1.example.com", - "port": "0" - }, - { - "host": "host2.example.com", - "port": "0" - } - ], - "user": "testuser-rbd", - "node-name": "node-a-s", - "read-only": false, - "discard": "unmap" - }, + "file": "node-a-s", "backing": "node-b-f" } +{ + "driver": "rbd", + "pool": "rbdpool", + "image": "rbdimg", + "server": [ + { + "host": "host1.example.com", + "port": "0" + }, + { + "host": "host2.example.com", + "port": "0" + } + ], + "user": "testuser-rbd", + "node-name": "node-a-s", + "read-only": false, + "discard": "unmap" +} { "node-name": "node-b-f", "read-only": true, @@ -35,17 +36,18 @@ "format": "aes", "key-secret": "node-b-f-encalias" }, - "file": { - "driver": "iscsi", - "portal": "example.org:3260", - "target": "iqn.2016-09.com.example:iscsitarget", - "lun": 1, - "transport": "tcp", - "user": "testuser-iscsi", - "password-secret": "node-b-s-secalias", - "node-name": "node-b-s", - "read-only": true, - "discard": "unmap" - }, + "file": "node-b-s", "backing": null } +{ + "driver": "iscsi", + "portal": "example.org:3260", + "target": "iqn.2016-09.com.example:iscsitarget", + "lun": 1, + "transport": "tcp", + "user": "testuser-iscsi", + "password-secret": "node-b-s-secalias", + "node-name": "node-b-s", + "read-only": true, + "discard": "unmap" +} -- 2.16.2

It will be used when parsing the migration private data. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/conf/domain_conf.c | 2 +- src/conf/domain_conf.h | 6 ++++++ src/libvirt_private.syms | 1 + 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 3689ac0a82..b220232f3f 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -8692,7 +8692,7 @@ virDomainDiskSourcePRParse(xmlNodePtr node, } -static int +int virDomainStorageSourceParse(xmlNodePtr node, xmlXPathContextPtr ctxt, virStorageSourcePtr src, diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index a78fdee40c..1daf15d454 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -3446,6 +3446,12 @@ int virDomainStorageSourceFormat(virBufferPtr attrBuf, bool skipSeclabels) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3); +int virDomainStorageSourceParse(xmlNodePtr node, + xmlXPathContextPtr ctxt, + virStorageSourcePtr src, + unsigned int flags) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3); + int virDomainDefGetVcpuPinInfoHelper(virDomainDefPtr def, int maplen, int ncpumaps, diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 3dece252df..a97b7fe223 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -547,6 +547,7 @@ virDomainStateReasonToString; virDomainStateTypeFromString; virDomainStateTypeToString; virDomainStorageSourceFormat; +virDomainStorageSourceParse; virDomainTaintTypeFromString; virDomainTaintTypeToString; virDomainTimerModeTypeFromString; -- 2.16.2

The initiation of a synchronous block job in the NBD storage migration code was placed after entering the monitor thus after the lock on the VM object was unlocked. Thankfully nothing bad could happen in this situation since the migration job prevents any disk detaches or other modifications of the domain object. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_migration.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index f753e42d1b..5fa2b4b56b 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -833,11 +833,12 @@ qemuMigrationSrcDriveMirror(virQEMUDriverPtr driver, hoststr, port, diskAlias) < 0)) goto cleanup; + qemuBlockJobSyncBegin(disk); + if (qemuDomainObjEnterMonitorAsync(driver, vm, QEMU_ASYNC_JOB_MIGRATION_OUT) < 0) goto cleanup; - qemuBlockJobSyncBegin(disk); /* Force "raw" format for NBD export */ mon_ret = qemuMonitorDriveMirror(priv->mon, diskAlias, nbd_dest, "raw", mirror_speed, 0, 0, mirror_flags); -- 2.16.2

The capability also represents that 'blockdev-add' is functional. It's necessary to detect it via presence of 'blockdev-del' since blockdev-add did not have the unsupported 'x-blockdev-add' version previously and thus would be marked as present even if we could not use it. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_capabilities.c | 2 ++ src/qemu/qemu_capabilities.h | 1 + tests/qemucapabilitiesdata/caps_2.10.0.aarch64.xml | 1 + tests/qemucapabilitiesdata/caps_2.10.0.ppc64.xml | 1 + tests/qemucapabilitiesdata/caps_2.10.0.s390x.xml | 1 + tests/qemucapabilitiesdata/caps_2.10.0.x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_2.11.0.s390x.xml | 1 + tests/qemucapabilitiesdata/caps_2.12.0.aarch64.xml | 1 + tests/qemucapabilitiesdata/caps_2.12.0.ppc64.xml | 1 + tests/qemucapabilitiesdata/caps_2.12.0.s390x.xml | 1 + tests/qemucapabilitiesdata/caps_2.12.0.x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_2.9.0.ppc64.xml | 1 + tests/qemucapabilitiesdata/caps_2.9.0.s390x.xml | 1 + tests/qemucapabilitiesdata/caps_2.9.0.x86_64.xml | 1 + 14 files changed, 15 insertions(+) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index bface72de2..b841eba0c9 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -487,6 +487,7 @@ VIR_ENUM_IMPL(virQEMUCaps, QEMU_CAPS_LAST, /* 300 */ "sdl-gl", "screendump_device", + "blockdev-del", ); @@ -996,6 +997,7 @@ struct virQEMUCapsStringFlags virQEMUCapsCommands[] = { { "query-named-block-nodes", QEMU_CAPS_QUERY_NAMED_BLOCK_NODES }, { "query-cpus-fast", QEMU_CAPS_QUERY_CPUS_FAST }, { "qom-list-properties", QEMU_CAPS_QOM_LIST_PROPERTIES }, + { "blockdev-del", QEMU_CAPS_BLOCKDEV_DEL }, }; struct virQEMUCapsStringFlags virQEMUCapsMigration[] = { diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index 6f9953478a..db5773b02f 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -471,6 +471,7 @@ typedef enum { /* virQEMUCapsFlags grouping marker for syntax-check */ /* 300 */ QEMU_CAPS_SDL_GL, /* -sdl gl */ QEMU_CAPS_SCREENDUMP_DEVICE, /* screendump command accepts device & head */ + QEMU_CAPS_BLOCKDEV_DEL, /* blockdev-del is supported */ QEMU_CAPS_LAST /* this must always be the last item */ } virQEMUCapsFlags; diff --git a/tests/qemucapabilitiesdata/caps_2.10.0.aarch64.xml b/tests/qemucapabilitiesdata/caps_2.10.0.aarch64.xml index 5904306848..2206724645 100644 --- a/tests/qemucapabilitiesdata/caps_2.10.0.aarch64.xml +++ b/tests/qemucapabilitiesdata/caps_2.10.0.aarch64.xml @@ -155,6 +155,7 @@ <flag name='disk-write-cache'/> <flag name='nbd-tls'/> <flag name='sdl-gl'/> + <flag name='blockdev-del'/> <version>2010000</version> <kvmVersion>0</kvmVersion> <microcodeVersion>303541</microcodeVersion> diff --git a/tests/qemucapabilitiesdata/caps_2.10.0.ppc64.xml b/tests/qemucapabilitiesdata/caps_2.10.0.ppc64.xml index 2912c8d66b..d2767c1fde 100644 --- a/tests/qemucapabilitiesdata/caps_2.10.0.ppc64.xml +++ b/tests/qemucapabilitiesdata/caps_2.10.0.ppc64.xml @@ -154,6 +154,7 @@ <flag name='disk-write-cache'/> <flag name='nbd-tls'/> <flag name='sdl-gl'/> + <flag name='blockdev-del'/> <version>2010000</version> <kvmVersion>0</kvmVersion> <microcodeVersion>382824</microcodeVersion> diff --git a/tests/qemucapabilitiesdata/caps_2.10.0.s390x.xml b/tests/qemucapabilitiesdata/caps_2.10.0.s390x.xml index 518788ac13..3fa1fa569f 100644 --- a/tests/qemucapabilitiesdata/caps_2.10.0.s390x.xml +++ b/tests/qemucapabilitiesdata/caps_2.10.0.s390x.xml @@ -116,6 +116,7 @@ <flag name='nbd-tls'/> <flag name='virtual-css-bridge'/> <flag name='sdl-gl'/> + <flag name='blockdev-del'/> <version>2010000</version> <kvmVersion>0</kvmVersion> <microcodeVersion>303434</microcodeVersion> diff --git a/tests/qemucapabilitiesdata/caps_2.10.0.x86_64.xml b/tests/qemucapabilitiesdata/caps_2.10.0.x86_64.xml index 77ca3013b5..9f2ee7a4c4 100644 --- a/tests/qemucapabilitiesdata/caps_2.10.0.x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_2.10.0.x86_64.xml @@ -197,6 +197,7 @@ <flag name='disk-write-cache'/> <flag name='nbd-tls'/> <flag name='sdl-gl'/> + <flag name='blockdev-del'/> <version>2010000</version> <kvmVersion>0</kvmVersion> <microcodeVersion>344938</microcodeVersion> diff --git a/tests/qemucapabilitiesdata/caps_2.11.0.s390x.xml b/tests/qemucapabilitiesdata/caps_2.11.0.s390x.xml index 9adca9d46b..012ba109fb 100644 --- a/tests/qemucapabilitiesdata/caps_2.11.0.s390x.xml +++ b/tests/qemucapabilitiesdata/caps_2.11.0.s390x.xml @@ -122,6 +122,7 @@ <flag name='pr-manager-helper'/> <flag name='virtual-css-bridge'/> <flag name='sdl-gl'/> + <flag name='blockdev-del'/> <version>2011000</version> <kvmVersion>0</kvmVersion> <microcodeVersion>342166</microcodeVersion> diff --git a/tests/qemucapabilitiesdata/caps_2.12.0.aarch64.xml b/tests/qemucapabilitiesdata/caps_2.12.0.aarch64.xml index de41d96cd0..6fa01c1a2d 100644 --- a/tests/qemucapabilitiesdata/caps_2.12.0.aarch64.xml +++ b/tests/qemucapabilitiesdata/caps_2.12.0.aarch64.xml @@ -163,6 +163,7 @@ <flag name='memory-backend-file.discard-data'/> <flag name='sdl-gl'/> <flag name='screendump_device'/> + <flag name='blockdev-del'/> <version>2011090</version> <kvmVersion>0</kvmVersion> <microcodeVersion>343099</microcodeVersion> diff --git a/tests/qemucapabilitiesdata/caps_2.12.0.ppc64.xml b/tests/qemucapabilitiesdata/caps_2.12.0.ppc64.xml index fc26f934ee..3fdb38df76 100644 --- a/tests/qemucapabilitiesdata/caps_2.12.0.ppc64.xml +++ b/tests/qemucapabilitiesdata/caps_2.12.0.ppc64.xml @@ -160,6 +160,7 @@ <flag name='memory-backend-file.discard-data'/> <flag name='sdl-gl'/> <flag name='screendump_device'/> + <flag name='blockdev-del'/> <version>2011090</version> <kvmVersion>0</kvmVersion> <microcodeVersion>419968</microcodeVersion> diff --git a/tests/qemucapabilitiesdata/caps_2.12.0.s390x.xml b/tests/qemucapabilitiesdata/caps_2.12.0.s390x.xml index bdfb81c998..cfc85d5849 100644 --- a/tests/qemucapabilitiesdata/caps_2.12.0.s390x.xml +++ b/tests/qemucapabilitiesdata/caps_2.12.0.s390x.xml @@ -128,6 +128,7 @@ <flag name='vfio-ccw'/> <flag name='sdl-gl'/> <flag name='screendump_device'/> + <flag name='blockdev-del'/> <version>2012000</version> <kvmVersion>0</kvmVersion> <microcodeVersion>371055</microcodeVersion> diff --git a/tests/qemucapabilitiesdata/caps_2.12.0.x86_64.xml b/tests/qemucapabilitiesdata/caps_2.12.0.x86_64.xml index 820b3ef759..c8c7e3b8bd 100644 --- a/tests/qemucapabilitiesdata/caps_2.12.0.x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_2.12.0.x86_64.xml @@ -201,6 +201,7 @@ <flag name='memory-backend-file.discard-data'/> <flag name='sdl-gl'/> <flag name='screendump_device'/> + <flag name='blockdev-del'/> <version>2011090</version> <kvmVersion>0</kvmVersion> <microcodeVersion>390813</microcodeVersion> diff --git a/tests/qemucapabilitiesdata/caps_2.9.0.ppc64.xml b/tests/qemucapabilitiesdata/caps_2.9.0.ppc64.xml index cfc9405095..8a15683634 100644 --- a/tests/qemucapabilitiesdata/caps_2.9.0.ppc64.xml +++ b/tests/qemucapabilitiesdata/caps_2.9.0.ppc64.xml @@ -146,6 +146,7 @@ <flag name='disk-write-cache'/> <flag name='nbd-tls'/> <flag name='sdl-gl'/> + <flag name='blockdev-del'/> <version>2009000</version> <kvmVersion>0</kvmVersion> <microcodeVersion>346538</microcodeVersion> diff --git a/tests/qemucapabilitiesdata/caps_2.9.0.s390x.xml b/tests/qemucapabilitiesdata/caps_2.9.0.s390x.xml index 96521efb8a..513aa0b395 100644 --- a/tests/qemucapabilitiesdata/caps_2.9.0.s390x.xml +++ b/tests/qemucapabilitiesdata/caps_2.9.0.s390x.xml @@ -111,6 +111,7 @@ <flag name='nbd-tls'/> <flag name='virtual-css-bridge'/> <flag name='sdl-gl'/> + <flag name='blockdev-del'/> <version>2009000</version> <kvmVersion>0</kvmVersion> <microcodeVersion>265159</microcodeVersion> diff --git a/tests/qemucapabilitiesdata/caps_2.9.0.x86_64.xml b/tests/qemucapabilitiesdata/caps_2.9.0.x86_64.xml index 0701c244f6..d3e7492590 100644 --- a/tests/qemucapabilitiesdata/caps_2.9.0.x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_2.9.0.x86_64.xml @@ -192,6 +192,7 @@ <flag name='disk-write-cache'/> <flag name='nbd-tls'/> <flag name='sdl-gl'/> + <flag name='blockdev-del'/> <version>2009000</version> <kvmVersion>0</kvmVersion> <microcodeVersion>320947</microcodeVersion> -- 2.16.2

Move formatting of the qemu command out of qemuMonitorJSONMakeCommandRaw to qemuMonitorJSONMakeCommandInternal to allow greater reusability and document the function better. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_monitor_json.c | 70 +++++++++++++++++++++++++++++++------------- 1 file changed, 49 insertions(+), 21 deletions(-) diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 6dcded9369..0b0fb7feba 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -464,40 +464,68 @@ qemuMonitorJSONHasError(virJSONValuePtr reply, } -/* Top-level commands and nested transaction list elements share a - * common structure for everything except the dictionary names. */ +/** + * qemuMonitorJSONMakeCommandInternal: + * @cmdname: QMP command name + * @arguments: a JSON object containing command arguments or NULL + * @transaction: format the command as arguments for the 'transaction' command + * + * Create a JSON object used on the QMP monitor to call a command. If + * @transaction is true, the returned object is formatted to be used as a member + * of the 'transaction' command. + * + * Note that @arguments is always consumed and should not be referenced after + * the call to this function. + */ +static virJSONValuePtr +qemuMonitorJSONMakeCommandInternal(const char *cmdname, + virJSONValuePtr arguments, + bool transaction) +{ + virJSONValuePtr cmd = NULL; + virJSONValuePtr ret = NULL; + + if (!transaction) { + if (virJSONValueObjectCreate(&cmd, + "s:execute", cmdname, + "A:arguments", &arguments, NULL) < 0) + goto cleanup; + } else { + if (virJSONValueObjectCreate(&cmd, + "s:type", cmdname, + "A:data", &arguments, NULL) < 0) + goto cleanup; + } + + VIR_STEAL_PTR(ret, cmd); + + cleanup: + virJSONValueFree(arguments); + virJSONValueFree(cmd); + return ret; +} + + static virJSONValuePtr ATTRIBUTE_SENTINEL -qemuMonitorJSONMakeCommandRaw(bool wrap, const char *cmdname, ...) +qemuMonitorJSONMakeCommandRaw(bool transaction, + const char *cmdname, + ...) { - virJSONValuePtr obj; + virJSONValuePtr obj = NULL; virJSONValuePtr jargs = NULL; va_list args; va_start(args, cmdname); - if (!(obj = virJSONValueNewObject())) - goto error; - - if (virJSONValueObjectAppendString(obj, wrap ? "type" : "execute", - cmdname) < 0) - goto error; - if (virJSONValueObjectCreateVArgs(&jargs, args) < 0) - goto error; + goto cleanup; - if (jargs && - virJSONValueObjectAppend(obj, wrap ? "data" : "arguments", jargs) < 0) - goto error; + obj = qemuMonitorJSONMakeCommandInternal(cmdname, jargs, transaction); + cleanup: va_end(args); return obj; - - error: - virJSONValueFree(obj); - virJSONValueFree(jargs); - va_end(args); - return NULL; } #define qemuMonitorJSONMakeCommand(cmdname, ...) \ -- 2.16.2

Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_monitor.c | 37 +++++++++++++++++++++++++++++ src/qemu/qemu_monitor.h | 7 ++++++ src/qemu/qemu_monitor_json.c | 55 ++++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 9 ++++++++ 4 files changed, 108 insertions(+) diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index f21bf7000d..fb9583e405 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -4412,3 +4412,40 @@ qemuMonitorSetWatchdogAction(qemuMonitorPtr mon, return qemuMonitorJSONSetWatchdogAction(mon, action); } + + +/** + * qemuMonitorBlockdevAdd: + * @mon: monitor object + * @props: JSON object describing the blockdev to add + * + * Adds a new block device (BDS) to qemu. Note that @props is always consumed + * by this function and should not be accessed after calling this function. + */ +int +qemuMonitorBlockdevAdd(qemuMonitorPtr mon, + virJSONValuePtr props) +{ + VIR_DEBUG("props=%p (node-name=%s)", props, + NULLSTR(virJSONValueObjectGetString(props, "node-name"))); + + QEMU_CHECK_MONITOR_JSON_GOTO(mon, error); + + return qemuMonitorJSONBlockdevAdd(mon, props); + + error: + virJSONValueFree(props); + return -1; +} + + +int +qemuMonitorBlockdevDel(qemuMonitorPtr mon, + const char *nodename) +{ + VIR_DEBUG("nodename=%s", nodename); + + QEMU_CHECK_MONITOR_JSON(mon); + + return qemuMonitorJSONBlockdevDel(mon, nodename); +} diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index 6cba37c281..52ad843029 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -1142,4 +1142,11 @@ virJSONValuePtr qemuMonitorQueryNamedBlockNodes(qemuMonitorPtr mon); int qemuMonitorSetWatchdogAction(qemuMonitorPtr mon, const char *action); + +int qemuMonitorBlockdevAdd(qemuMonitorPtr mon, + virJSONValuePtr props); + +int qemuMonitorBlockdevDel(qemuMonitorPtr mon, + const char *nodename); + #endif /* QEMU_MONITOR_H */ diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 0b0fb7feba..61554a7ebc 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -7889,3 +7889,58 @@ qemuMonitorJSONSetWatchdogAction(qemuMonitorPtr mon, virJSONValueFree(reply); return ret; } + + +int +qemuMonitorJSONBlockdevAdd(qemuMonitorPtr mon, + virJSONValuePtr props) +{ + virJSONValuePtr cmd; + virJSONValuePtr reply = NULL; + int ret = -1; + + if (!(cmd = qemuMonitorJSONMakeCommandInternal("blockdev-add", + props, false))) + return -1; + + if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0) + goto cleanup; + + if (qemuMonitorJSONCheckError(cmd, reply) < 0) + goto cleanup; + + ret = 0; + + cleanup: + virJSONValueFree(cmd); + virJSONValueFree(reply); + return ret; +} + + +int +qemuMonitorJSONBlockdevDel(qemuMonitorPtr mon, + const char *nodename) +{ + virJSONValuePtr cmd; + virJSONValuePtr reply = NULL; + int ret = -1; + + if (!(cmd = qemuMonitorJSONMakeCommand("blockdev-del", + "s:node-name", nodename, + NULL))) + return -1; + + if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0) + goto cleanup; + + if (qemuMonitorJSONCheckError(cmd, reply) < 0) + goto cleanup; + + ret = 0; + + cleanup: + virJSONValueFree(cmd); + virJSONValueFree(reply); + return ret; +} diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index 8461932cac..22bcc1e8ef 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -537,4 +537,13 @@ virJSONValuePtr qemuMonitorJSONQueryNamedBlockNodes(qemuMonitorPtr mon) int qemuMonitorJSONSetWatchdogAction(qemuMonitorPtr mon, const char *action) ATTRIBUTE_NONNULL(1); + +int qemuMonitorJSONBlockdevAdd(qemuMonitorPtr mon, + virJSONValuePtr props) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); + +int qemuMonitorJSONBlockdevDel(qemuMonitorPtr mon, + const char *nodename) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); + #endif /* QEMU_MONITOR_JSON_H */ -- 2.16.2

drive-mirror allows only file targets. Introduce support for blockdev-mirror that is able to copy to any BDS described by a node name in qemu. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_monitor.c | 22 ++++++++++++++++++++++ src/qemu/qemu_monitor.h | 9 +++++++++ src/qemu/qemu_monitor_json.c | 39 +++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 9 +++++++++ 4 files changed, 79 insertions(+) diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index fb9583e405..315bb460b9 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -3362,6 +3362,28 @@ qemuMonitorDriveMirror(qemuMonitorPtr mon, } +int +qemuMonitorBlockdevMirror(qemuMonitorPtr mon, + const char *jobname, + const char *device, + const char *target, + unsigned long long bandwidth, + unsigned int granularity, + unsigned long long buf_size, + unsigned int flags) +{ + VIR_DEBUG("jobname=%s, device=%s, target=%s, bandwidth=%lld, " + "granularity=%#x, buf_size=%lld, flags=0x%x", + NULLSTR(jobname), device, target, bandwidth, granularity, + buf_size, flags); + + QEMU_CHECK_MONITOR_JSON(mon); + + return qemuMonitorJSONBlockdevMirror(mon, jobname, device, target, bandwidth, + granularity, buf_size, flags); +} + + /* Use the transaction QMP command to run atomic snapshot commands. */ int qemuMonitorTransaction(qemuMonitorPtr mon, virJSONValuePtr *actions) diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index 52ad843029..6acc4edffa 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -860,6 +860,15 @@ int qemuMonitorDriveMirror(qemuMonitorPtr mon, unsigned long long buf_size, unsigned int flags) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3); +int qemuMonitorBlockdevMirror(qemuMonitorPtr mon, + const char *jobname, + const char *device, + const char *target, + unsigned long long bandwidth, + unsigned int granularity, + unsigned long long buf_size, + unsigned int flags) + ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4); int qemuMonitorDrivePivot(qemuMonitorPtr mon, const char *device) ATTRIBUTE_NONNULL(2); diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 61554a7ebc..2a7abf538e 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -4189,6 +4189,45 @@ qemuMonitorJSONDriveMirror(qemuMonitorPtr mon, return ret; } + +int +qemuMonitorJSONBlockdevMirror(qemuMonitorPtr mon, + const char *jobname, + const char *device, + const char *target, + unsigned long long speed, + unsigned int granularity, + unsigned long long buf_size, + unsigned int flags) +{ + int ret = -1; + virJSONValuePtr cmd; + virJSONValuePtr reply = NULL; + bool shallow = (flags & VIR_DOMAIN_BLOCK_REBASE_SHALLOW) != 0; + + cmd = qemuMonitorJSONMakeCommand("blockdev-mirror", + "S:job-id", jobname, + "s:device", device, + "s:target", target, + "Y:speed", speed, + "z:granularity", granularity, + "P:buf-size", buf_size, + "s:sync", shallow ? "top" : "full", + NULL); + if (!cmd) + return -1; + + if ((ret = qemuMonitorJSONCommand(mon, cmd, &reply)) < 0) + goto cleanup; + ret = qemuMonitorJSONCheckError(cmd, reply); + + cleanup: + virJSONValueFree(cmd); + virJSONValueFree(reply); + return ret; +} + + int qemuMonitorJSONTransaction(qemuMonitorPtr mon, virJSONValuePtr *actions) { diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index 22bcc1e8ef..646cfcc8ac 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -264,6 +264,15 @@ int qemuMonitorJSONDriveMirror(qemuMonitorPtr mon, unsigned long long buf_size, unsigned int flags) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3); +int qemuMonitorJSONBlockdevMirror(qemuMonitorPtr mon, + const char *jobname, + const char *device, + const char *target, + unsigned long long speed, + unsigned int granularity, + unsigned long long buf_size, + unsigned int flags) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4); int qemuMonitorJSONDrivePivot(qemuMonitorPtr mon, const char *device) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); -- 2.16.2

These helpers add infrastructure which simplifies adding and rolling back virStorageSources to a running qemu instance. Using of the helper structure and separate functions allows for a much cleaner code in the section dealing with the monitor. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_block.c | 155 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_block.h | 34 +++++++++++ 2 files changed, 189 insertions(+) diff --git a/src/qemu/qemu_block.c b/src/qemu/qemu_block.c index a514e8a055..09437cdb40 100644 --- a/src/qemu/qemu_block.c +++ b/src/qemu/qemu_block.c @@ -1467,3 +1467,158 @@ qemuBlockStorageSourceGetBlockdevProps(virStorageSourcePtr src) virJSONValueFree(props); return ret; } + + +void +qemuBlockStorageSourceAttachDataFree(qemuBlockStorageSourceAttachDataPtr data) +{ + if (!data) + return; + + virJSONValueFree(data->storageProps); + virJSONValueFree(data->formatProps); + VIR_FREE(data); +} + + +/** + * qemuBlockStorageSourceAttachPrepareBlockdev: + * @src: storage source to prepare data from + * + * Creates a qemuBlockStorageSourceAttachData structure containing data to attach + * @src to a VM using the blockdev-add approach. Note that this function only + * creates the data for the storage source itself, any other related + * authentication/encryption/... objects need to be prepared separately. + * + * The changes are then applied using qemuBlockStorageSourceAttachApply. + * + * Returns the filled data structure on success or NULL on error and a libvirt + * error is reported + */ +qemuBlockStorageSourceAttachDataPtr +qemuBlockStorageSourceAttachPrepareBlockdev(virStorageSourcePtr src) +{ + qemuBlockStorageSourceAttachDataPtr data; + qemuBlockStorageSourceAttachDataPtr ret = NULL; + + if (VIR_ALLOC(data) < 0) + return NULL; + + if (!(data->formatProps = qemuBlockStorageSourceGetBlockdevProps(src)) || + !(data->storageProps = qemuBlockStorageSourceGetBackendProps(src, false))) + goto cleanup; + + data->storageNodeName = src->nodestorage; + data->formatNodeName = src->nodeformat; + + VIR_STEAL_PTR(ret, data); + + cleanup: + qemuBlockStorageSourceAttachDataFree(data); + return ret; +} + + +/** + * qemuBlockStorageSourceAttachApply: + * @mon: monitor object + * @data: structure holding data of block device to apply + * + * Attaches a virStorageSource definition converted to + * qemuBlockStorageSourceAttachData to a running VM. This function expects being + * called after the monitor was entered. + * + * Returns 0 on success and -1 on error with a libvirt error reported. If an + * error occured, changes which were already applied need to be rolled back by + * calling qemuBlockStorageSourceAttachRollback. + */ +int +qemuBlockStorageSourceAttachApply(qemuMonitorPtr mon, + qemuBlockStorageSourceAttachDataPtr data) +{ + int rv; + + if (data->storageProps) { + rv = qemuMonitorBlockdevAdd(mon, data->storageProps); + data->storageProps = NULL; + + if (rv < 0) + return -1; + + data->storageAttached = true; + } + + if (data->formatProps) { + rv = qemuMonitorBlockdevAdd(mon, data->formatProps); + data->formatProps = NULL; + + if (rv < 0) + return -1; + + data->formatAttached = true; + } + + return 0; +} + + +/** + * qemuBlockStorageSourceAttachRollback: + * @mon: monitor object + * @data: structure holding data of block device to roll back + * + * Attempts a best effort rollback of changes which were made to a running VM by + * qemuBlockStorageSourceAttachApply. Preserves any existing errors. + * + * This function expects being called after the monitor was entered. + */ +void +qemuBlockStorageSourceAttachRollback(qemuMonitorPtr mon, + qemuBlockStorageSourceAttachDataPtr data) +{ + virErrorPtr orig_err; + + virErrorPreserveLast(&orig_err); + + if (data->formatAttached) + ignore_value(qemuMonitorBlockdevDel(mon, data->formatNodeName)); + + if (data->storageAttached) + ignore_value(qemuMonitorBlockdevDel(mon, data->storageNodeName)); + + virErrorRestore(&orig_err); +} + + +/** + * qemuBlockStorageSourceDetachOneBlockdev: + * @driver: qemu driver object + * @vm: domain object + * @asyncJob: currently running async job + * @src: storage source to detach + * + * Detaches one virStorageSource using blockdev-del. Note that this does not + * detach any authentication/encryption objects. This function enters the + * monitor internally. + */ +int +qemuBlockStorageSourceDetachOneBlockdev(virQEMUDriverPtr driver, + virDomainObjPtr vm, + qemuDomainAsyncJob asyncJob, + virStorageSourcePtr src) +{ + int ret; + + if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0) + return -1; + + ret = qemuMonitorBlockdevDel(qemuDomainGetMonitor(vm), src->nodeformat); + + if (ret == 0) + ret = qemuMonitorBlockdevDel(qemuDomainGetMonitor(vm), src->nodestorage); + + if (qemuDomainObjExitMonitor(driver, vm) < 0) + return -1; + + return ret; +} diff --git a/src/qemu/qemu_block.h b/src/qemu/qemu_block.h index f819c6f907..bbaf9ec0f1 100644 --- a/src/qemu/qemu_block.h +++ b/src/qemu/qemu_block.h @@ -67,4 +67,38 @@ qemuBlockStorageSourceGetURI(virStorageSourcePtr src); virJSONValuePtr qemuBlockStorageSourceGetBlockdevProps(virStorageSourcePtr src); + +typedef struct qemuBlockStorageSourceAttachData qemuBlockStorageSourceAttachData; +typedef qemuBlockStorageSourceAttachData *qemuBlockStorageSourceAttachDataPtr; +struct qemuBlockStorageSourceAttachData { + virJSONValuePtr storageProps; + const char *storageNodeName; + bool storageAttached; + + virJSONValuePtr formatProps; + const char *formatNodeName; + bool formatAttached; +}; + + +void +qemuBlockStorageSourceAttachDataFree(qemuBlockStorageSourceAttachDataPtr data); + +qemuBlockStorageSourceAttachDataPtr +qemuBlockStorageSourceAttachPrepareBlockdev(virStorageSourcePtr src); + +int +qemuBlockStorageSourceAttachApply(qemuMonitorPtr mon, + qemuBlockStorageSourceAttachDataPtr data); + +void +qemuBlockStorageSourceAttachRollback(qemuMonitorPtr mon, + qemuBlockStorageSourceAttachDataPtr data); + +int +qemuBlockStorageSourceDetachOneBlockdev(virQEMUDriverPtr driver, + virDomainObjPtr vm, + qemuDomainAsyncJob asyncJob, + virStorageSourcePtr src); + #endif /* __QEMU_BLOCK_H__ */ -- 2.16.2

We will be adding source data to it so extract it to a separate function. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_domain.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index d3beee5d87..0bca80f3c6 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -2067,6 +2067,23 @@ qemuDomainObjPrivateXMLFormatPR(virBufferPtr buf, } +static void +qemuDomainObjPrivateXMLFormatNBDMigration(virBufferPtr buf, + virDomainObjPtr vm) +{ + size_t i; + virDomainDiskDefPtr disk; + qemuDomainDiskPrivatePtr diskPriv; + + for (i = 0; i < vm->def->ndisks; i++) { + disk = vm->def->disks[i]; + diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk); + virBufferAsprintf(buf, "<disk dev='%s' migrating='%s'/>\n", + disk->dst, diskPriv->migrating ? "yes" : "no"); + } +} + + static int qemuDomainObjPrivateXMLFormatJob(virBufferPtr buf, virDomainObjPtr vm, @@ -2098,18 +2115,8 @@ qemuDomainObjPrivateXMLFormatJob(virBufferPtr buf, if (priv->job.asyncJob != QEMU_ASYNC_JOB_NONE) virBufferAsprintf(&attrBuf, " flags='0x%lx'", priv->job.apiFlags); - if (priv->job.asyncJob == QEMU_ASYNC_JOB_MIGRATION_OUT) { - size_t i; - virDomainDiskDefPtr disk; - qemuDomainDiskPrivatePtr diskPriv; - - for (i = 0; i < vm->def->ndisks; i++) { - disk = vm->def->disks[i]; - diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk); - virBufferAsprintf(&childBuf, "<disk dev='%s' migrating='%s'/>\n", - disk->dst, diskPriv->migrating ? "yes" : "no"); - } - } + if (priv->job.asyncJob == QEMU_ASYNC_JOB_MIGRATION_OUT) + qemuDomainObjPrivateXMLFormatNBDMigration(&childBuf, vm); if (priv->job.migParams) qemuMigrationParamsFormat(&childBuf, priv->job.migParams); -- 2.16.2

Extract the NBD portion of the 'job' status XML element parser into a separate function. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_domain.c | 61 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 39 insertions(+), 22 deletions(-) diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 0bca80f3c6..94a9c5d1bc 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -2367,16 +2367,51 @@ qemuDomainObjPrivateXMLParsePR(xmlXPathContextPtr ctxt, } +static int +qemuDomainObjPrivateXMLParseJobNBD(virDomainObjPtr vm, + qemuDomainObjPrivatePtr priv, + xmlXPathContextPtr ctxt) +{ + xmlNodePtr *nodes = NULL; + size_t i; + int n; + int ret = -1; + + if ((n = virXPathNodeSet("./disk[@migrating='yes']", ctxt, &nodes)) < 0) + goto cleanup; + + if (n > 0) { + if (priv->job.asyncJob != QEMU_ASYNC_JOB_MIGRATION_OUT) { + VIR_WARN("Found disks marked for migration but we were not " + "migrating"); + n = 0; + } + for (i = 0; i < n; i++) { + char *dst = virXMLPropString(nodes[i], "dev"); + virDomainDiskDefPtr disk; + + if (dst && (disk = virDomainDiskByName(vm->def, dst, false))) + QEMU_DOMAIN_DISK_PRIVATE(disk)->migrating = true; + VIR_FREE(dst); + } + } + VIR_FREE(nodes); + + ret = 0; + + cleanup: + VIR_FREE(nodes); + return ret; +} + + static int qemuDomainObjPrivateXMLParseJob(virDomainObjPtr vm, qemuDomainObjPrivatePtr priv, xmlXPathContextPtr ctxt) { - xmlNodePtr *nodes = NULL; xmlNodePtr savedNode = ctxt->node; char *tmp = NULL; - size_t i; - int n; int ret = -1; if (!(ctxt->node = virXPathNode("./job[1]", ctxt))) { @@ -2423,26 +2458,9 @@ qemuDomainObjPrivateXMLParseJob(virDomainObjPtr vm, goto cleanup; } - if ((n = virXPathNodeSet("./disk[@migrating='yes']", ctxt, &nodes)) < 0) + if (qemuDomainObjPrivateXMLParseJobNBD(vm, priv, ctxt) < 0) goto cleanup; - if (n > 0) { - if (priv->job.asyncJob != QEMU_ASYNC_JOB_MIGRATION_OUT) { - VIR_WARN("Found disks marked for migration but we were not " - "migrating"); - n = 0; - } - for (i = 0; i < n; i++) { - char *dst = virXMLPropString(nodes[i], "dev"); - virDomainDiskDefPtr disk; - - if (dst && (disk = virDomainDiskByName(vm->def, dst, false))) - QEMU_DOMAIN_DISK_PRIVATE(disk)->migrating = true; - VIR_FREE(dst); - } - } - VIR_FREE(nodes); - if (qemuMigrationParamsParse(ctxt, &priv->job.migParams) < 0) goto cleanup; @@ -2451,7 +2469,6 @@ qemuDomainObjPrivateXMLParseJob(virDomainObjPtr vm, cleanup: ctxt->node = savedNode; VIR_FREE(tmp); - VIR_FREE(nodes); return ret; } -- 2.16.2

On 05/18/2018 07:29 AM, Peter Krempa wrote:
Extract the NBD portion of the 'job' status XML element parser into a separate function.
Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_domain.c | 61 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 39 insertions(+), 22 deletions(-)
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 0bca80f3c6..94a9c5d1bc 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -2367,16 +2367,51 @@ qemuDomainObjPrivateXMLParsePR(xmlXPathContextPtr ctxt, }
+static int +qemuDomainObjPrivateXMLParseJobNBD(virDomainObjPtr vm, + qemuDomainObjPrivatePtr priv, + xmlXPathContextPtr ctxt) +{ + xmlNodePtr *nodes = NULL; + size_t i; + int n; + int ret = -1; + + if ((n = virXPathNodeSet("./disk[@migrating='yes']", ctxt, &nodes)) < 0) + goto cleanup; + + if (n > 0) { + if (priv->job.asyncJob != QEMU_ASYNC_JOB_MIGRATION_OUT) { + VIR_WARN("Found disks marked for migration but we were not " + "migrating"); + n = 0; + } + for (i = 0; i < n; i++) { + char *dst = virXMLPropString(nodes[i], "dev"); + virDomainDiskDefPtr disk; + + if (dst && (disk = virDomainDiskByName(vm->def, dst, false))) + QEMU_DOMAIN_DISK_PRIVATE(disk)->migrating = true; + VIR_FREE(dst); + } + } + VIR_FREE(nodes);
NIT: This one's unnecessary since its done at cleanup anyway. John
+ + ret = 0; + + cleanup: + VIR_FREE(nodes); + return ret; +} + + static int qemuDomainObjPrivateXMLParseJob(virDomainObjPtr vm, qemuDomainObjPrivatePtr priv, xmlXPathContextPtr ctxt) { - xmlNodePtr *nodes = NULL; xmlNodePtr savedNode = ctxt->node; char *tmp = NULL; - size_t i; - int n; int ret = -1;
if (!(ctxt->node = virXPathNode("./job[1]", ctxt))) { @@ -2423,26 +2458,9 @@ qemuDomainObjPrivateXMLParseJob(virDomainObjPtr vm, goto cleanup; }
- if ((n = virXPathNodeSet("./disk[@migrating='yes']", ctxt, &nodes)) < 0) + if (qemuDomainObjPrivateXMLParseJobNBD(vm, priv, ctxt) < 0) goto cleanup;
- if (n > 0) { - if (priv->job.asyncJob != QEMU_ASYNC_JOB_MIGRATION_OUT) { - VIR_WARN("Found disks marked for migration but we were not " - "migrating"); - n = 0; - } - for (i = 0; i < n; i++) { - char *dst = virXMLPropString(nodes[i], "dev"); - virDomainDiskDefPtr disk; - - if (dst && (disk = virDomainDiskByName(vm->def, dst, false))) - QEMU_DOMAIN_DISK_PRIVATE(disk)->migrating = true; - VIR_FREE(dst); - } - } - VIR_FREE(nodes); - if (qemuMigrationParamsParse(ctxt, &priv->job.migParams) < 0) goto cleanup;
@@ -2451,7 +2469,6 @@ qemuDomainObjPrivateXMLParseJob(virDomainObjPtr vm, cleanup: ctxt->node = savedNode; VIR_FREE(tmp); - VIR_FREE(nodes); return ret; }

Allow saving various aspects necessary to do NBD migration via blockdev by storing a 'virStorageSource' in the disk private data meant to store the NBD target of migration. Along with this add code to parse and format it into the status XML. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_domain.c | 162 ++++++++++++++++++++++++++++++++++++++++++++++--- src/qemu/qemu_domain.h | 1 + 2 files changed, 156 insertions(+), 7 deletions(-) diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 94a9c5d1bc..632c025bef 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -1015,6 +1015,7 @@ qemuDomainDiskPrivateDispose(void *obj) qemuDomainDiskPrivatePtr priv = obj; VIR_FREE(priv->blockJobError); + virStorageSourceFree(priv->migrSource); } static virClassPtr qemuDomainStorageSourcePrivateClass; @@ -2067,20 +2068,82 @@ qemuDomainObjPrivateXMLFormatPR(virBufferPtr buf, } -static void +static int +qemuDomainObjPrivateXMLFormatNBDMigrationSource(virBufferPtr buf, + virStorageSourcePtr src) +{ + virBuffer attrBuf = VIR_BUFFER_INITIALIZER; + virBuffer childBuf = VIR_BUFFER_INITIALIZER; + virBuffer privateDataBuf = VIR_BUFFER_INITIALIZER; + int ret = -1; + + virBufferSetChildIndent(&childBuf, buf); + virBufferSetChildIndent(&privateDataBuf, &childBuf); + + virBufferAsprintf(&attrBuf, " type='%s' format='%s'", + virStorageTypeToString(src->type), + virStorageFileFormatTypeToString(src->format)); + + if (virDomainStorageSourceFormat(&attrBuf, &childBuf, src, + VIR_DOMAIN_DEF_FORMAT_STATUS, false) < 0) + goto cleanup; + + if (qemuStorageSourcePrivateDataFormat(src, &privateDataBuf) < 0) + goto cleanup; + + if (virXMLFormatElement(&childBuf, "privateData", NULL, &privateDataBuf) < 0) + goto cleanup; + + if (virXMLFormatElement(buf, "migrationSource", &attrBuf, &childBuf) < 0) + goto cleanup; + + ret = 0; + + cleanup: + virBufferFreeAndReset(&attrBuf); + virBufferFreeAndReset(&childBuf); + virBufferFreeAndReset(&privateDataBuf); + + return ret; +} + + +static int qemuDomainObjPrivateXMLFormatNBDMigration(virBufferPtr buf, virDomainObjPtr vm) { + virBuffer attrBuf = VIR_BUFFER_INITIALIZER; + virBuffer childBuf = VIR_BUFFER_INITIALIZER; size_t i; virDomainDiskDefPtr disk; qemuDomainDiskPrivatePtr diskPriv; + int ret = -1; for (i = 0; i < vm->def->ndisks; i++) { disk = vm->def->disks[i]; diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk); - virBufferAsprintf(buf, "<disk dev='%s' migrating='%s'/>\n", + + virBufferSetChildIndent(&childBuf, buf); + + virBufferAsprintf(&attrBuf, " dev='%s' migrating='%s'", disk->dst, diskPriv->migrating ? "yes" : "no"); + + if (diskPriv->migrSource && + qemuDomainObjPrivateXMLFormatNBDMigrationSource(&childBuf, + diskPriv->migrSource) < 0) + goto cleanup; + + if (virXMLFormatElement(buf, "disk", &attrBuf, &childBuf) < 0) + goto cleanup; } + + ret = 0; + + cleanup: + virBufferFreeAndReset(&attrBuf); + virBufferFreeAndReset(&childBuf); + + return ret; } @@ -2092,6 +2155,7 @@ qemuDomainObjPrivateXMLFormatJob(virBufferPtr buf, virBuffer attrBuf = VIR_BUFFER_INITIALIZER; virBuffer childBuf = VIR_BUFFER_INITIALIZER; qemuDomainJob job = priv->job.active; + int ret = -1; if (!qemuDomainTrackJob(job)) job = QEMU_JOB_NONE; @@ -2115,13 +2179,23 @@ qemuDomainObjPrivateXMLFormatJob(virBufferPtr buf, if (priv->job.asyncJob != QEMU_ASYNC_JOB_NONE) virBufferAsprintf(&attrBuf, " flags='0x%lx'", priv->job.apiFlags); - if (priv->job.asyncJob == QEMU_ASYNC_JOB_MIGRATION_OUT) - qemuDomainObjPrivateXMLFormatNBDMigration(&childBuf, vm); + if (priv->job.asyncJob == QEMU_ASYNC_JOB_MIGRATION_OUT && + qemuDomainObjPrivateXMLFormatNBDMigration(&childBuf, vm) < 0) + goto cleanup; if (priv->job.migParams) qemuMigrationParamsFormat(&childBuf, priv->job.migParams); - return virXMLFormatElement(buf, "job", &attrBuf, &childBuf); + if (virXMLFormatElement(buf, "job", &attrBuf, &childBuf) < 0) + goto cleanup; + + ret = 0; + + cleanup: + virBufferFreeAndReset(&attrBuf); + virBufferFreeAndReset(&childBuf); + + return ret; } @@ -2367,12 +2441,79 @@ qemuDomainObjPrivateXMLParsePR(xmlXPathContextPtr ctxt, } +static int +qemuDomainObjPrivateXMLParseJobNBDSource(xmlNodePtr node, + xmlXPathContextPtr ctxt, + virDomainDiskDefPtr disk) +{ + xmlNodePtr savedNode = ctxt->node; + qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk); + virStorageSourcePtr migrSource = NULL; + char *format = NULL; + char *type = NULL; + int ret = -1; + + ctxt->node = node; + + if (!(ctxt->node = virXPathNode("./migrationSource", ctxt))) { + ret = 0; + goto cleanup; + } + + if (VIR_ALLOC(migrSource) < 0) + goto cleanup; + + if (!(type = virXMLPropString(ctxt->node, "type"))) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("missing storage source type")); + goto cleanup; + } + + if (!(format = virXMLPropString(ctxt->node, "format"))) { + virReportError(VIR_ERR_XML_ERROR, "%s", + ("missing storage source format")); + goto cleanup; + } + + if ((migrSource->type = virStorageTypeFromString(type)) <= 0) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("unknown storage source type '%s'"), type); + goto cleanup; + } + + if ((migrSource->format = virStorageFileFormatTypeFromString(format)) <= 0) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("unknown storage source format '%s'"), format); + goto cleanup; + } + + if (virDomainStorageSourceParse(ctxt->node, ctxt, migrSource, + VIR_DOMAIN_DEF_PARSE_STATUS) < 0) + goto cleanup; + + if ((ctxt->node = virXPathNode("./privateData", ctxt)) && + qemuStorageSourcePrivateDataParse(ctxt, migrSource) < 0) + goto cleanup; + + VIR_STEAL_PTR(diskPriv->migrSource, migrSource); + ret = 0; + + cleanup: + virStorageSourceFree(migrSource); + VIR_FREE(format); + VIR_FREE(type); + ctxt->node = savedNode; + return ret; +} + + static int qemuDomainObjPrivateXMLParseJobNBD(virDomainObjPtr vm, qemuDomainObjPrivatePtr priv, xmlXPathContextPtr ctxt) { xmlNodePtr *nodes = NULL; + char *dst = NULL; size_t i; int n; int ret = -1; @@ -2387,11 +2528,17 @@ qemuDomainObjPrivateXMLParseJobNBD(virDomainObjPtr vm, n = 0; } for (i = 0; i < n; i++) { - char *dst = virXMLPropString(nodes[i], "dev"); virDomainDiskDefPtr disk; - if (dst && (disk = virDomainDiskByName(vm->def, dst, false))) + if ((dst = virXMLPropString(nodes[i], "dev")) && + (disk = virDomainDiskByName(vm->def, dst, false))) { QEMU_DOMAIN_DISK_PRIVATE(disk)->migrating = true; + + if (qemuDomainObjPrivateXMLParseJobNBDSource(nodes[i], ctxt, + disk) < 0) + goto cleanup; + } + VIR_FREE(dst); } } @@ -2401,6 +2548,7 @@ qemuDomainObjPrivateXMLParseJobNBD(virDomainObjPtr vm, cleanup: VIR_FREE(nodes); + VIR_FREE(dst); return ret; } diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h index 40d1d095a3..000d8fb8d7 100644 --- a/src/qemu/qemu_domain.h +++ b/src/qemu/qemu_domain.h @@ -370,6 +370,7 @@ struct _qemuDomainDiskPrivate { bool blockJobSync; /* the block job needs synchronized termination */ bool migrating; /* the disk is being migrated */ + virStorageSourcePtr migrSource; /* disk source object used for NBD migration */ /* information about the device */ bool tray; /* device has tray */ -- 2.16.2

On 05/18/2018 07:29 AM, Peter Krempa wrote:
Allow saving various aspects necessary to do NBD migration via blockdev by storing a 'virStorageSource' in the disk private data meant to store the NBD target of migration. Along with this add code to parse and format it into the status XML.
Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_domain.c | 162 ++++++++++++++++++++++++++++++++++++++++++++++--- src/qemu/qemu_domain.h | 1 + 2 files changed, 156 insertions(+), 7 deletions(-)
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 94a9c5d1bc..632c025bef 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c
[...]
@@ -2092,6 +2155,7 @@ qemuDomainObjPrivateXMLFormatJob(virBufferPtr buf, virBuffer attrBuf = VIR_BUFFER_INITIALIZER; virBuffer childBuf = VIR_BUFFER_INITIALIZER; qemuDomainJob job = priv->job.active; + int ret = -1;
if (!qemuDomainTrackJob(job)) job = QEMU_JOB_NONE; @@ -2115,13 +2179,23 @@ qemuDomainObjPrivateXMLFormatJob(virBufferPtr buf, if (priv->job.asyncJob != QEMU_ASYNC_JOB_NONE) virBufferAsprintf(&attrBuf, " flags='0x%lx'", priv->job.apiFlags);
- if (priv->job.asyncJob == QEMU_ASYNC_JOB_MIGRATION_OUT) - qemuDomainObjPrivateXMLFormatNBDMigration(&childBuf, vm); + if (priv->job.asyncJob == QEMU_ASYNC_JOB_MIGRATION_OUT && + qemuDomainObjPrivateXMLFormatNBDMigration(&childBuf, vm) < 0) + goto cleanup;
if (priv->job.migParams) qemuMigrationParamsFormat(&childBuf, priv->job.migParams);
- return virXMLFormatElement(buf, "job", &attrBuf, &childBuf); + if (virXMLFormatElement(buf, "job", &attrBuf, &childBuf) < 0) + goto cleanup; + + ret = 0; + + cleanup: + virBufferFreeAndReset(&attrBuf); + virBufferFreeAndReset(&childBuf);
So I assume the lack of FreeAndReset was existing prior to this patch since d8be0f4bc?
+ + return ret; }
@@ -2367,12 +2441,79 @@ qemuDomainObjPrivateXMLParsePR(xmlXPathContextPtr ctxt, }
[...] John

On Tue, May 22, 2018 at 20:26:56 -0400, John Ferlan wrote:
On 05/18/2018 07:29 AM, Peter Krempa wrote:
Allow saving various aspects necessary to do NBD migration via blockdev by storing a 'virStorageSource' in the disk private data meant to store the NBD target of migration. Along with this add code to parse and format it into the status XML.
Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_domain.c | 162 ++++++++++++++++++++++++++++++++++++++++++++++--- src/qemu/qemu_domain.h | 1 + 2 files changed, 156 insertions(+), 7 deletions(-)
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 94a9c5d1bc..632c025bef 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c
[...]
@@ -2092,6 +2155,7 @@ qemuDomainObjPrivateXMLFormatJob(virBufferPtr buf, virBuffer attrBuf = VIR_BUFFER_INITIALIZER; virBuffer childBuf = VIR_BUFFER_INITIALIZER; qemuDomainJob job = priv->job.active; + int ret = -1;
if (!qemuDomainTrackJob(job)) job = QEMU_JOB_NONE; @@ -2115,13 +2179,23 @@ qemuDomainObjPrivateXMLFormatJob(virBufferPtr buf, if (priv->job.asyncJob != QEMU_ASYNC_JOB_NONE) virBufferAsprintf(&attrBuf, " flags='0x%lx'", priv->job.apiFlags);
- if (priv->job.asyncJob == QEMU_ASYNC_JOB_MIGRATION_OUT) - qemuDomainObjPrivateXMLFormatNBDMigration(&childBuf, vm); + if (priv->job.asyncJob == QEMU_ASYNC_JOB_MIGRATION_OUT && + qemuDomainObjPrivateXMLFormatNBDMigration(&childBuf, vm) < 0) + goto cleanup;
if (priv->job.migParams) qemuMigrationParamsFormat(&childBuf, priv->job.migParams);
- return virXMLFormatElement(buf, "job", &attrBuf, &childBuf); + if (virXMLFormatElement(buf, "job", &attrBuf, &childBuf) < 0) + goto cleanup; + + ret = 0; + + cleanup: + virBufferFreeAndReset(&attrBuf); + virBufferFreeAndReset(&childBuf);
So I assume the lack of FreeAndReset was existing prior to this patch since d8be0f4bc?
Yes. I assumed that virXMLFormatElement clears them on error, but it apparently does not, so adding them here actually fixes a possible bug. This chagne would be necessary even with the above assumption being valid as this patch adds a possible error code path.

Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- .../migration-out-nbd-tls-in.xml | 464 +++++++++++++++++++++ .../migration-out-nbd-tls-out.xml | 1 + tests/qemuxml2xmltest.c | 1 + 3 files changed, 466 insertions(+) create mode 100644 tests/qemustatusxml2xmldata/migration-out-nbd-tls-in.xml create mode 120000 tests/qemustatusxml2xmldata/migration-out-nbd-tls-out.xml diff --git a/tests/qemustatusxml2xmldata/migration-out-nbd-tls-in.xml b/tests/qemustatusxml2xmldata/migration-out-nbd-tls-in.xml new file mode 100644 index 0000000000..be1dc7347e --- /dev/null +++ b/tests/qemustatusxml2xmldata/migration-out-nbd-tls-in.xml @@ -0,0 +1,464 @@ +<domstatus state='running' reason='booted' pid='68472'> + <taint flag='high-privileges'/> + <monitor path='/var/lib/libvirt/qemu/domain-3-upstream/monitor.sock' json='1' type='unix'/> + <namespaces> + <mount/> + </namespaces> + <vcpus> + <vcpu id='0' pid='68477'/> + <vcpu id='1' pid='68478'/> + </vcpus> + <qemuCaps> + <flag name='kvm'/> + <flag name='mem-path'/> + <flag name='drive-serial'/> + <flag name='monitor-json'/> + <flag name='sdl'/> + <flag name='netdev'/> + <flag name='rtc'/> + <flag name='vhost-net'/> + <flag name='no-hpet'/> + <flag name='no-kvm-pit'/> + <flag name='nodefconfig'/> + <flag name='boot-menu'/> + <flag name='fsdev'/> + <flag name='name-process'/> + <flag name='smbios-type'/> + <flag name='spice'/> + <flag name='vga-none'/> + <flag name='boot-index'/> + <flag name='hda-duplex'/> + <flag name='drive-aio'/> + <flag name='ccid-emulated'/> + <flag name='ccid-passthru'/> + <flag name='chardev-spicevmc'/> + <flag name='virtio-tx-alg'/> + <flag name='pci-multifunction'/> + <flag name='virtio-blk-pci.ioeventfd'/> + <flag name='sga'/> + <flag name='virtio-blk-pci.event_idx'/> + <flag name='virtio-net-pci.event_idx'/> + <flag name='cache-directsync'/> + <flag name='piix3-usb-uhci'/> + <flag name='piix4-usb-uhci'/> + <flag name='usb-ehci'/> + <flag name='ich9-usb-ehci1'/> + <flag name='vt82c686b-usb-uhci'/> + <flag name='pci-ohci'/> + <flag name='usb-redir'/> + <flag name='usb-hub'/> + <flag name='no-shutdown'/> + <flag name='cache-unsafe'/> + <flag name='ich9-ahci'/> + <flag name='no-acpi'/> + <flag name='fsdev-readonly'/> + <flag name='virtio-blk-pci.scsi'/> + <flag name='drive-copy-on-read'/> + <flag name='fsdev-writeout'/> + <flag name='drive-iotune'/> + <flag name='system_wakeup'/> + <flag name='scsi-disk.channel'/> + <flag name='scsi-block'/> + <flag name='transaction'/> + <flag name='block-job-async'/> + <flag name='scsi-cd'/> + <flag name='ide-cd'/> + <flag name='no-user-config'/> + <flag name='hda-micro'/> + <flag name='dump-guest-memory'/> + <flag name='nec-usb-xhci'/> + <flag name='balloon-event'/> + <flag name='bridge'/> + <flag name='lsi'/> + <flag name='virtio-scsi-pci'/> + <flag name='blockio'/> + <flag name='disable-s3'/> + <flag name='disable-s4'/> + <flag name='usb-redir.filter'/> + <flag name='ide-drive.wwn'/> + <flag name='scsi-disk.wwn'/> + <flag name='seccomp-sandbox'/> + <flag name='reboot-timeout'/> + <flag name='dump-guest-core'/> + <flag name='seamless-migration'/> + <flag name='block-commit'/> + <flag name='vnc'/> + <flag name='drive-mirror'/> + <flag name='usb-redir.bootindex'/> + <flag name='usb-host.bootindex'/> + <flag name='blockdev-snapshot-sync'/> + <flag name='qxl'/> + <flag name='VGA'/> + <flag name='cirrus-vga'/> + <flag name='vmware-svga'/> + <flag name='device-video-primary'/> + <flag name='usb-serial'/> + <flag name='usb-net'/> + <flag name='add-fd'/> + <flag name='nbd-server'/> + <flag name='virtio-rng'/> + <flag name='rng-random'/> + <flag name='rng-egd'/> + <flag name='dtb'/> + <flag name='megasas'/> + <flag name='ipv6-migration'/> + <flag name='machine-opt'/> + <flag name='machine-usb-opt'/> + <flag name='tpm-passthrough'/> + <flag name='tpm-tis'/> + <flag name='pci-bridge'/> + <flag name='vfio-pci'/> + <flag name='vfio-pci.bootindex'/> + <flag name='scsi-generic'/> + <flag name='scsi-generic.bootindex'/> + <flag name='mem-merge'/> + <flag name='vnc-websocket'/> + <flag name='drive-discard'/> + <flag name='mlock'/> + <flag name='vnc-share-policy'/> + <flag name='device-del-event'/> + <flag name='dmi-to-pci-bridge'/> + <flag name='i440fx-pci-hole64-size'/> + <flag name='q35-pci-hole64-size'/> + <flag name='usb-storage'/> + <flag name='usb-storage.removable'/> + <flag name='virtio-mmio'/> + <flag name='ich9-intel-hda'/> + <flag name='kvm-pit-lost-tick-policy'/> + <flag name='boot-strict'/> + <flag name='pvpanic'/> + <flag name='spice-file-xfer-disable'/> + <flag name='spiceport'/> + <flag name='usb-kbd'/> + <flag name='host-pci-multidomain'/> + <flag name='msg-timestamp'/> + <flag name='active-commit'/> + <flag name='change-backing-file'/> + <flag name='memory-backend-ram'/> + <flag name='numa'/> + <flag name='memory-backend-file'/> + <flag name='usb-audio'/> + <flag name='rtc-reset-reinjection'/> + <flag name='splash-timeout'/> + <flag name='iothread'/> + <flag name='migrate-rdma'/> + <flag name='ivshmem'/> + <flag name='drive-iotune-max'/> + <flag name='VGA.vgamem_mb'/> + <flag name='vmware-svga.vgamem_mb'/> + <flag name='qxl.vgamem_mb'/> + <flag name='pc-dimm'/> + <flag name='machine-vmport-opt'/> + <flag name='aes-key-wrap'/> + <flag name='dea-key-wrap'/> + <flag name='pci-serial'/> + <flag name='vhost-user-multiqueue'/> + <flag name='migration-event'/> + <flag name='ioh3420'/> + <flag name='x3130-upstream'/> + <flag name='xio3130-downstream'/> + <flag name='rtl8139'/> + <flag name='e1000'/> + <flag name='virtio-net'/> + <flag name='gic-version'/> + <flag name='incoming-defer'/> + <flag name='virtio-gpu'/> + <flag name='virtio-gpu.virgl'/> + <flag name='virtio-keyboard'/> + <flag name='virtio-mouse'/> + <flag name='virtio-tablet'/> + <flag name='virtio-input-host'/> + <flag name='chardev-file-append'/> + <flag name='ich9-disable-s3'/> + <flag name='ich9-disable-s4'/> + <flag name='vserport-change-event'/> + <flag name='virtio-balloon-pci.deflate-on-oom'/> + <flag name='mptsas1068'/> + <flag name='qxl.vram64_size_mb'/> + <flag name='chardev-logfile'/> + <flag name='debug-threads'/> + <flag name='secret'/> + <flag name='pxb'/> + <flag name='pxb-pcie'/> + <flag name='device-tray-moved-event'/> + <flag name='nec-usb-xhci-ports'/> + <flag name='virtio-scsi-pci.iothread'/> + <flag name='name-guest'/> + <flag name='qxl.max_outputs'/> + <flag name='spice-unix'/> + <flag name='drive-detect-zeroes'/> + <flag name='tls-creds-x509'/> + <flag name='display'/> + <flag name='intel-iommu'/> + <flag name='smm'/> + <flag name='virtio-pci-disable-legacy'/> + <flag name='query-hotpluggable-cpus'/> + <flag name='virtio-net.rx_queue_size'/> + <flag name='virtio-vga'/> + <flag name='drive-iotune-max-length'/> + <flag name='ivshmem-plain'/> + <flag name='ivshmem-doorbell'/> + <flag name='query-qmp-schema'/> + <flag name='gluster.debug_level'/> + <flag name='vhost-scsi'/> + <flag name='drive-iotune-group'/> + <flag name='query-cpu-model-expansion'/> + <flag name='virtio-net.host_mtu'/> + <flag name='nvdimm'/> + <flag name='pcie-root-port'/> + <flag name='query-cpu-definitions'/> + <flag name='block-write-threshold'/> + <flag name='query-named-block-nodes'/> + <flag name='cpu-cache'/> + <flag name='qemu-xhci'/> + <flag name='kernel-irqchip'/> + <flag name='kernel-irqchip.split'/> + <flag name='intel-iommu.intremap'/> + <flag name='intel-iommu.caching-mode'/> + <flag name='intel-iommu.eim'/> + <flag name='intel-iommu.device-iotlb'/> + <flag name='virtio.iommu_platform'/> + <flag name='virtio.ats'/> + <flag name='loadparm'/> + <flag name='vnc-multi-servers'/> + <flag name='virtio-net.tx_queue_size'/> + <flag name='chardev-reconnect'/> + <flag name='virtio-gpu.max_outputs'/> + <flag name='vxhs'/> + <flag name='virtio-blk.num-queues'/> + <flag name='vmcoreinfo'/> + <flag name='numa.dist'/> + <flag name='disk-share-rw'/> + <flag name='iscsi.password-secret'/> + <flag name='isa-serial'/> + <flag name='dump-completed'/> + <flag name='nbd-tls'/> + <flag name='blockdev-del'/> + </qemuCaps> + <job type='none' async='migration out' phase='perform3' flags='0x0'> + <disk dev='vdb' migrating='yes'> + <migrationSource type='network' format='raw' protocol='nbd' name='drive-virtio-disk1' tlsFromConfig='0'> + <host name='andariel.usersys.redhat.com' port='49152'/> + <privateData> + <nodenames> + <nodename type='storage' name='migration-vdb-storage'/> + <nodename type='format' name='migration-vdb-format'/> + </nodenames> + </privateData> + </migrationSource> + </disk> + <disk dev='hda' migrating='no'/> + </job> + <devices> + <device alias='rng0'/> + <device alias='sound0-codec0'/> + <device alias='virtio-disk1'/> + <device alias='virtio-serial0'/> + <device alias='video0'/> + <device alias='serial0'/> + <device alias='sound0'/> + <device alias='balloon0'/> + <device alias='channel1'/> + <device alias='channel0'/> + <device alias='net0'/> + <device alias='input0'/> + <device alias='redir0'/> + <device alias='redir1'/> + <device alias='scsi0'/> + <device alias='usb'/> + <device alias='ide0-0-0'/> + </devices> + <numad nodeset='0' cpuset='0-7'/> + <libDir path='/var/lib/libvirt/qemu/domain-3-upstream'/> + <channelTargetDir path='/var/lib/libvirt/qemu/channel/target/domain-3-upstream'/> + <chardevStdioLogd/> + <allowReboot value='yes'/> + <blockjobs active='no'/> + <domain type='kvm' id='3'> + <name>upstream</name> + <uuid>dcf47dbd-46d1-4d5b-b442-262a806a333a</uuid> + <memory unit='KiB'>1024000</memory> + <currentMemory unit='KiB'>1024000</currentMemory> + <memoryBacking> + <access mode='shared'/> + </memoryBacking> + <vcpu placement='auto' current='2'>8</vcpu> + <numatune> + <memory mode='strict' placement='auto'/> + </numatune> + <resource> + <partition>/machine</partition> + </resource> + <os> + <type arch='x86_64' machine='pc-i440fx-2.9'>hvm</type> + <bootmenu enable='yes'/> + </os> + <features> + <acpi/> + <apic/> + <vmport state='off'/> + </features> + <cpu> + <numa> + <cell id='0' cpus='0,2,4,6' memory='512000' unit='KiB'/> + <cell id='1' cpus='1,3,5,7' memory='512000' unit='KiB'/> + </numa> + </cpu> + <clock offset='utc'> + <timer name='rtc' tickpolicy='catchup'/> + <timer name='pit' tickpolicy='delay'/> + <timer name='hpet' present='no'/> + </clock> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>restart</on_crash> + <pm> + <suspend-to-mem enabled='no'/> + <suspend-to-disk enabled='no'/> + </pm> + <devices> + <emulator>/usr/bin/qemu-system-x86_64</emulator> + <disk type='file' device='disk'> + <driver name='qemu' type='qcow2' discard='unmap' detect_zeroes='on'/> + <source file='/var/lib/libvirt/images/a.qcow2'/> + <backingStore type='file' index='1'> + <format type='qcow2'/> + <source file='/var/lib/libvirt/images/base.qcow2'> + <privateData> + <relPath>base.qcow2</relPath> + </privateData> + </source> + <backingStore/> + </backingStore> + <target dev='vdb' bus='virtio'/> + <alias name='virtio-disk1'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0b' function='0x0'/> + </disk> + <disk type='file' device='cdrom'> + <driver name='qemu' type='raw'/> + <source file='/var/lib/libvirt/images/systemrescuecd-x86-4.9.5.iso'/> + <backingStore/> + <target dev='hda' bus='ide'/> + <readonly/> + <boot order='1'/> + <alias name='ide0-0-0'/> + <address type='drive' controller='0' bus='0' target='0' unit='0'/> + </disk> + <controller type='usb' index='0' model='ich9-ehci1'> + <alias name='usb'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x7'/> + </controller> + <controller type='usb' index='0' model='ich9-uhci1'> + <alias name='usb'/> + <master startport='0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0' multifunction='on'/> + </controller> + <controller type='usb' index='0' model='ich9-uhci2'> + <alias name='usb'/> + <master startport='2'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x1'/> + </controller> + <controller type='usb' index='0' model='ich9-uhci3'> + <alias name='usb'/> + <master startport='4'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x2'/> + </controller> + <controller type='pci' index='0' model='pci-root'> + <alias name='pci.0'/> + </controller> + <controller type='virtio-serial' index='0'> + <alias name='virtio-serial0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/> + </controller> + <controller type='ide' index='0'> + <alias name='ide'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/> + </controller> + <controller type='scsi' index='0' model='lsilogic'> + <alias name='scsi0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x09' function='0x0'/> + </controller> + <controller type='fdc' index='0'> + <alias name='fdc0'/> + </controller> + <interface type='network'> + <mac address='52:54:00:36:bd:3b'/> + <source network='default'/> + <actual type='network'> + <source bridge='virbr0'/> + </actual> + <target dev='vnet0'/> + <model type='virtio'/> + <alias name='net0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> + </interface> + <serial type='pty'> + <source path='/dev/pts/67'/> + <target type='isa-serial' port='0'> + <model name='isa-serial'/> + </target> + <alias name='serial0'/> + </serial> + <console type='pty' tty='/dev/pts/67'> + <source path='/dev/pts/67'/> + <target type='serial' port='0'/> + <alias name='serial0'/> + </console> + <channel type='unix'> + <source mode='bind' path='/var/lib/libvirt/qemu/channel/target/domain-3-upstream/org.qemu.guest_agent.0'/> + <target type='virtio' name='org.qemu.guest_agent.0' state='disconnected'/> + <alias name='channel0'/> + <address type='virtio-serial' controller='0' bus='0' port='1'/> + </channel> + <channel type='spicevmc'> + <target type='virtio' name='com.redhat.spice.0' state='disconnected'/> + <alias name='channel1'/> + <address type='virtio-serial' controller='0' bus='0' port='2'/> + </channel> + <input type='tablet' bus='usb'> + <alias name='input0'/> + <address type='usb' bus='0' port='1'/> + </input> + <input type='mouse' bus='ps2'> + <alias name='input1'/> + </input> + <input type='keyboard' bus='ps2'> + <alias name='input2'/> + </input> + <graphics type='spice' port='5900' autoport='yes' listen='127.0.0.1'> + <listen type='address' address='127.0.0.1' fromConfig='1' autoGenerated='no'/> + <image compression='off'/> + </graphics> + <sound model='ich6'> + <alias name='sound0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/> + </sound> + <video> + <model type='qxl' ram='65536' vram='65536' vgamem='16384' heads='1' primary='yes'/> + <alias name='video0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> + </video> + <redirdev bus='usb' type='spicevmc'> + <alias name='redir0'/> + <address type='usb' bus='0' port='2'/> + </redirdev> + <redirdev bus='usb' type='spicevmc'> + <alias name='redir1'/> + <address type='usb' bus='0' port='3'/> + </redirdev> + <memballoon model='virtio'> + <alias name='balloon0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x08' function='0x0'/> + </memballoon> + <rng model='virtio'> + <backend model='random'>/dev/random</backend> + <alias name='rng0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/> + </rng> + </devices> + <seclabel type='dynamic' model='dac' relabel='yes'> + <label>+0:+0</label> + <imagelabel>+0:+0</imagelabel> + </seclabel> + </domain> +</domstatus> diff --git a/tests/qemustatusxml2xmldata/migration-out-nbd-tls-out.xml b/tests/qemustatusxml2xmldata/migration-out-nbd-tls-out.xml new file mode 120000 index 0000000000..e8cdbdb55e --- /dev/null +++ b/tests/qemustatusxml2xmldata/migration-out-nbd-tls-out.xml @@ -0,0 +1 @@ +migration-out-nbd-tls-in.xml \ No newline at end of file diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index 7cedc2b999..e31d8212fe 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -1208,6 +1208,7 @@ mymain(void) DO_TEST_STATUS("migration-out-nbd"); DO_TEST_STATUS("migration-in-params"); DO_TEST_STATUS("migration-out-params"); + DO_TEST_STATUS("migration-out-nbd-tls"); if (getenv("LIBVIRT_SKIP_CLEANUP") == NULL) virFileDeleteTree(fakerootdir); -- 2.16.2

Drop the mention of 'drive mirror' from the function names and mention NBD. This will help when adding the 'blockdev mirror' migration code which will allow using TLS. Additionally fix some of the function comments to make more sense Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_migration.c | 121 ++++++++++++++++++++++------------------------ 1 file changed, 58 insertions(+), 63 deletions(-) diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index 5fa2b4b56b..fdf71b2c0b 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -463,20 +463,19 @@ qemuMigrationDstStopNBDServer(virQEMUDriverPtr driver, /** - * qemuMigrationSrcDriveMirrorReady: + * qemuMigrationSrcNBDStorageCopyReady: * @vm: domain * - * Check the status of all drive-mirrors started by - * qemuMigrationSrcDriveMirror. Any pending block job events - * for the mirrored disks will be processed. + * Check the status of all drives copied via qemuMigrationSrcNBDStorageCopy. + * Any pending block job events for the mirrored disks will be processed. * * Returns 1 if all mirrors are "ready", * 0 if some mirrors are still performing initial sync, * -1 on error. */ static int -qemuMigrationSrcDriveMirrorReady(virDomainObjPtr vm, - qemuDomainAsyncJob asyncJob) +qemuMigrationSrcNBDStorageCopyReady(virDomainObjPtr vm, + qemuDomainAsyncJob asyncJob) { size_t i; size_t notReady = 0; @@ -530,9 +529,9 @@ qemuMigrationSrcDriveMirrorReady(virDomainObjPtr vm, * -2 all mirrors are gone but some of them failed. */ static int -qemuMigrationDriveMirrorCancelled(virDomainObjPtr vm, - qemuDomainAsyncJob asyncJob, - bool check) +qemuMigrationSrcNBDCopyCancelled(virDomainObjPtr vm, + qemuDomainAsyncJob asyncJob, + bool check) { size_t i; size_t active = 0; @@ -617,11 +616,11 @@ qemuMigrationDriveMirrorCancelled(virDomainObjPtr vm, * -1 on error or when job failed and failNoJob is true. */ static int -qemuMigrationSrcCancelOneDriveMirror(virQEMUDriverPtr driver, - virDomainObjPtr vm, - virDomainDiskDefPtr disk, - bool failNoJob, - qemuDomainAsyncJob asyncJob) +qemuMigrationSrcNBDCopyCancelOne(virQEMUDriverPtr driver, + virDomainObjPtr vm, + virDomainDiskDefPtr disk, + bool failNoJob, + qemuDomainAsyncJob asyncJob) { qemuDomainObjPrivatePtr priv = vm->privateData; char *diskAlias = NULL; @@ -672,23 +671,22 @@ qemuMigrationSrcCancelOneDriveMirror(virQEMUDriverPtr driver, /** - * qemuMigrationSrcCancelDriveMirror: + * qemuMigrationSrcNBDCopyCancel: * @driver: qemu driver * @vm: domain * @check: if true report an error when some of the mirrors fails * - * Cancel all drive-mirrors started by qemuMigrationDriveMirror. - * Any pending block job events for the affected disks will be - * processed. + * Cancel all drive-mirrors started by qemuMigrationSrcNBDStorageCopy. + * Any pending block job events for the affected disks will be processed. * * Returns 0 on success, -1 otherwise. */ static int -qemuMigrationSrcCancelDriveMirror(virQEMUDriverPtr driver, - virDomainObjPtr vm, - bool check, - qemuDomainAsyncJob asyncJob, - virConnectPtr dconn) +qemuMigrationSrcNBDCopyCancel(virQEMUDriverPtr driver, + virDomainObjPtr vm, + bool check, + qemuDomainAsyncJob asyncJob, + virConnectPtr dconn) { virErrorPtr err = NULL; int ret = -1; @@ -705,8 +703,8 @@ qemuMigrationSrcCancelDriveMirror(virQEMUDriverPtr driver, if (!diskPriv->migrating) continue; - rv = qemuMigrationSrcCancelOneDriveMirror(driver, vm, disk, - check, asyncJob); + rv = qemuMigrationSrcNBDCopyCancelOne(driver, vm, disk, + check, asyncJob); if (rv != 0) { if (rv < 0) { if (!err) @@ -718,8 +716,7 @@ qemuMigrationSrcCancelDriveMirror(virQEMUDriverPtr driver, } } - while ((rv = qemuMigrationDriveMirrorCancelled(vm, asyncJob, - check)) != 1) { + while ((rv = qemuMigrationSrcNBDCopyCancelled(vm, asyncJob, check)) != 1) { if (check && !failed && dconn && virConnectIsAlive(dconn) <= 0) { virReportError(VIR_ERR_OPERATION_FAILED, "%s", @@ -752,7 +749,7 @@ qemuMigrationSrcCancelDriveMirror(virQEMUDriverPtr driver, /** - * qemuMigrationDriveMirror: + * qemuMigrationSrcNBDStorageCopy: * @driver: qemu driver * @vm: domain * @mig: migration cookie @@ -760,27 +757,26 @@ qemuMigrationSrcCancelDriveMirror(virQEMUDriverPtr driver, * @speed: bandwidth limit in MiB/s * @migrate_flags: migrate monitor command flags * - * Run drive-mirror to feed NBD server running on dst and wait - * till the process switches into another phase where writes go - * simultaneously to both source and destination. On success, - * update @migrate_flags so we don't tell 'migrate' command + * Migrate non-shared storage using the NBD protocol to the server running + * inside the qemu process on dst and wait until the copy converges. + * On success update @migrate_flags so we don't tell 'migrate' command * to do the very same operation. On failure, the caller is - * expected to call qemuMigrationSrcCancelDriveMirror to stop all - * running mirrors. + * expected to call qemuMigrationSrcNBDCopyCancel to stop all + * running copy operations. * * Returns 0 on success (@migrate_flags updated), * -1 otherwise. */ static int -qemuMigrationSrcDriveMirror(virQEMUDriverPtr driver, - virDomainObjPtr vm, - qemuMigrationCookiePtr mig, - const char *host, - unsigned long speed, - unsigned int *migrate_flags, - size_t nmigrate_disks, - const char **migrate_disks, - virConnectPtr dconn) +qemuMigrationSrcNBDStorageCopy(virQEMUDriverPtr driver, + virDomainObjPtr vm, + qemuMigrationCookiePtr mig, + const char *host, + unsigned long speed, + unsigned int *migrate_flags, + size_t nmigrate_disks, + const char **migrate_disks, + virConnectPtr dconn) { qemuDomainObjPrivatePtr priv = vm->privateData; int ret = -1; @@ -857,8 +853,7 @@ qemuMigrationSrcDriveMirror(virQEMUDriverPtr driver, } } - while ((rv = qemuMigrationSrcDriveMirrorReady(vm, - QEMU_ASYNC_JOB_MIGRATION_OUT)) != 1) { + while ((rv = qemuMigrationSrcNBDStorageCopyReady(vm, QEMU_ASYNC_JOB_MIGRATION_OUT)) != 1) { if (rv < 0) goto cleanup; @@ -1364,7 +1359,7 @@ qemuMigrationAnyCompleted(virQEMUDriverPtr driver, /* This flag should only be set when run on src host */ if (flags & QEMU_MIGRATION_COMPLETED_CHECK_STORAGE && - qemuMigrationSrcDriveMirrorReady(vm, asyncJob) < 0) + qemuMigrationSrcNBDStorageCopyReady(vm, asyncJob) < 0) goto error; if (flags & QEMU_MIGRATION_COMPLETED_ABORT_ON_ERROR && @@ -2852,8 +2847,8 @@ qemuMigrationSrcConfirmPhase(virQEMUDriverPtr driver, int reason; /* cancel any outstanding NBD jobs */ - qemuMigrationSrcCancelDriveMirror(driver, vm, false, - QEMU_ASYNC_JOB_MIGRATION_OUT, NULL); + qemuMigrationSrcNBDCopyCancel(driver, vm, false, + QEMU_ASYNC_JOB_MIGRATION_OUT, NULL); virSetError(orig_err); virFreeError(orig_err); @@ -3357,13 +3352,13 @@ qemuMigrationSrcRun(virQEMUDriverPtr driver, } /* This will update migrate_flags on success */ - if (qemuMigrationSrcDriveMirror(driver, vm, mig, - spec->dest.host.name, - migrate_speed, - &migrate_flags, - nmigrate_disks, - migrate_disks, - dconn) < 0) { + if (qemuMigrationSrcNBDStorageCopy(driver, vm, mig, + spec->dest.host.name, + migrate_speed, + &migrate_flags, + nmigrate_disks, + migrate_disks, + dconn) < 0) { goto error; } } else { @@ -3492,9 +3487,9 @@ qemuMigrationSrcRun(virQEMUDriverPtr driver, } if (mig->nbd && - qemuMigrationSrcCancelDriveMirror(driver, vm, true, - QEMU_ASYNC_JOB_MIGRATION_OUT, - dconn) < 0) + qemuMigrationSrcNBDCopyCancel(driver, vm, true, + QEMU_ASYNC_JOB_MIGRATION_OUT, + dconn) < 0) goto error; /* When migration was paused before serializing device state we need to @@ -3579,9 +3574,9 @@ qemuMigrationSrcRun(virQEMUDriverPtr driver, /* cancel any outstanding NBD jobs */ if (mig && mig->nbd) - qemuMigrationSrcCancelDriveMirror(driver, vm, false, - QEMU_ASYNC_JOB_MIGRATION_OUT, - dconn); + qemuMigrationSrcNBDCopyCancel(driver, vm, false, + QEMU_ASYNC_JOB_MIGRATION_OUT, + dconn); if (priv->job.current->status != QEMU_DOMAIN_JOB_STATUS_CANCELED) priv->job.current->status = QEMU_DOMAIN_JOB_STATUS_FAILED; @@ -5270,8 +5265,8 @@ qemuMigrationSrcCancel(virQEMUDriverPtr driver, } } - if (qemuMigrationSrcCancelDriveMirror(driver, vm, false, - QEMU_ASYNC_JOB_NONE, NULL) < 0) + if (qemuMigrationSrcNBDCopyCancel(driver, vm, false, + QEMU_ASYNC_JOB_NONE, NULL) < 0) goto endsyncjob; ret = 0; -- 2.16.2

Separate the code relevant for this approach so that we can later add a second implementation without making the function messy. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_migration.c | 76 ++++++++++++++++++++++++++++++----------------- 1 file changed, 49 insertions(+), 27 deletions(-) diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index fdf71b2c0b..6617b7aea6 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -748,6 +748,48 @@ qemuMigrationSrcNBDCopyCancel(virQEMUDriverPtr driver, } +static int +qemuMigrationSrcNBDStorageCopyDriveMirror(virQEMUDriverPtr driver, + virDomainObjPtr vm, + const char *diskAlias, + const char *host, + int port, + unsigned long long mirror_speed, + unsigned int mirror_flags) +{ + char *nbd_dest = NULL; + int mon_ret; + int ret = -1; + + if (strchr(host, ':')) { + if (virAsprintf(&nbd_dest, "nbd:[%s]:%d:exportname=%s", + host, port, diskAlias) < 0) + goto cleanup; + } else { + if (virAsprintf(&nbd_dest, "nbd:%s:%d:exportname=%s", + host, port, diskAlias) < 0) + goto cleanup; + } + + if (qemuDomainObjEnterMonitorAsync(driver, vm, + QEMU_ASYNC_JOB_MIGRATION_OUT) < 0) + goto cleanup; + + mon_ret = qemuMonitorDriveMirror(qemuDomainGetMonitor(vm), + diskAlias, nbd_dest, "raw", + mirror_speed, 0, 0, mirror_flags); + + if (qemuDomainObjExitMonitor(driver, vm) < 0 || mon_ret < 0) + goto cleanup; + + ret = 0; + + cleanup: + VIR_FREE(nbd_dest); + return ret; +} + + /** * qemuMigrationSrcNBDStorageCopy: * @driver: qemu driver @@ -783,8 +825,6 @@ qemuMigrationSrcNBDStorageCopy(virQEMUDriverPtr driver, int port; size_t i; char *diskAlias = NULL; - char *nbd_dest = NULL; - char *hoststr = NULL; unsigned long long mirror_speed = speed; unsigned int mirror_flags = VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT; int rv; @@ -804,47 +844,31 @@ qemuMigrationSrcNBDStorageCopy(virQEMUDriverPtr driver, port = mig->nbd->port; mig->nbd->port = 0; - /* escape literal IPv6 address */ - if (strchr(host, ':')) { - if (virAsprintf(&hoststr, "[%s]", host) < 0) - goto cleanup; - } else if (VIR_STRDUP(hoststr, host) < 0) { - goto cleanup; - } - if (*migrate_flags & QEMU_MONITOR_MIGRATE_NON_SHARED_INC) mirror_flags |= VIR_DOMAIN_BLOCK_REBASE_SHALLOW; for (i = 0; i < vm->def->ndisks; i++) { virDomainDiskDefPtr disk = vm->def->disks[i]; qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk); - int mon_ret; /* check whether disk should be migrated */ if (!qemuMigrationAnyCopyDisk(disk, nmigrate_disks, migrate_disks)) continue; - if (!(diskAlias = qemuAliasFromDisk(disk)) || - (virAsprintf(&nbd_dest, "nbd:%s:%d:exportname=%s", - hoststr, port, diskAlias) < 0)) + if (!(diskAlias = qemuAliasFromDisk(disk))) goto cleanup; qemuBlockJobSyncBegin(disk); - if (qemuDomainObjEnterMonitorAsync(driver, vm, - QEMU_ASYNC_JOB_MIGRATION_OUT) < 0) - goto cleanup; - - /* Force "raw" format for NBD export */ - mon_ret = qemuMonitorDriveMirror(priv->mon, diskAlias, nbd_dest, - "raw", mirror_speed, 0, 0, mirror_flags); - VIR_FREE(diskAlias); - VIR_FREE(nbd_dest); - - if (qemuDomainObjExitMonitor(driver, vm) < 0 || mon_ret < 0) { + if (qemuMigrationSrcNBDStorageCopyDriveMirror(driver, vm, diskAlias, + host, port, + mirror_speed, + mirror_flags) < 0) { qemuBlockJobSyncEnd(vm, QEMU_ASYNC_JOB_MIGRATION_OUT, disk); goto cleanup; } + + VIR_FREE(diskAlias); diskPriv->migrating = true; if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, driver->caps) < 0) { @@ -886,8 +910,6 @@ qemuMigrationSrcNBDStorageCopy(virQEMUDriverPtr driver, cleanup: virObjectUnref(cfg); VIR_FREE(diskAlias); - VIR_FREE(nbd_dest); - VIR_FREE(hoststr); return ret; } -- 2.16.2

Implement the secure way to transport non-shared storage data across migrations. The new approach uses blockdev-add to create the NBD client so that the TLS secret object can be specified. https://bugzilla.redhat.com/show_bug.cgi?id=1300772 Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_migration.c | 122 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 115 insertions(+), 7 deletions(-) diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index 6617b7aea6..68663eac47 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -39,6 +39,7 @@ #include "qemu_hotplug.h" #include "qemu_blockjob.h" #include "qemu_security.h" +#include "qemu_block.h" #include "domain_audit.h" #include "virlog.h" @@ -737,6 +738,19 @@ qemuMigrationSrcNBDCopyCancel(virQEMUDriverPtr driver, goto cleanup; } + for (i = 0; i < vm->def->ndisks; i++) { + virDomainDiskDefPtr disk = vm->def->disks[i]; + qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk); + + if (!diskPriv->migrSource) + continue; + + qemuBlockStorageSourceDetachOneBlockdev(driver, vm, asyncJob, + diskPriv->migrSource); + virStorageSourceFree(diskPriv->migrSource); + diskPriv->migrSource = NULL; + } + ret = failed ? -1 : 0; cleanup: @@ -748,6 +762,85 @@ qemuMigrationSrcNBDCopyCancel(virQEMUDriverPtr driver, } +static int +qemuMigrationSrcNBDStorageCopyBlockdev(virQEMUDriverPtr driver, + virDomainObjPtr vm, + virDomainDiskDefPtr disk, + const char *diskAlias, + const char *host, + int port, + unsigned long long mirror_speed, + unsigned int mirror_flags, + const char *tlsAlias) +{ + qemuBlockStorageSourceAttachDataPtr data = NULL; + qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk); + virStorageSourcePtr copysrc = NULL; + int mon_ret = 0; + int ret = -1; + + VIR_DEBUG("starting blockdev mirror for disk=%s to host=%s", diskAlias, host); + + if (VIR_ALLOC(copysrc) < 0) + goto cleanup; + + copysrc->type = VIR_STORAGE_TYPE_NETWORK; + copysrc->protocol = VIR_STORAGE_NET_PROTOCOL_NBD; + copysrc->format = VIR_STORAGE_FILE_RAW; + + if (VIR_ALLOC(copysrc->backingStore) < 0) + goto cleanup; + + if (VIR_STRDUP(copysrc->path, diskAlias) < 0) + goto cleanup; + + if (VIR_ALLOC_N(copysrc->hosts, 1) < 0) + goto cleanup; + + copysrc->nhosts = 1; + copysrc->hosts->transport = VIR_STORAGE_NET_HOST_TRANS_TCP; + copysrc->hosts->port = port; + if (VIR_STRDUP(copysrc->hosts->name, host) < 0) + goto cleanup; + + if (VIR_STRDUP(copysrc->tlsAlias, tlsAlias) < 0) + goto cleanup; + + if (virAsprintf(©src->nodestorage, "migration-%s-storage", disk->dst) < 0 || + virAsprintf(©src->nodeformat, "migration-%s-format", disk->dst) < 0) + goto cleanup; + + if (!(data = qemuBlockStorageSourceAttachPrepareBlockdev(copysrc))) + goto cleanup; + + if (qemuDomainObjEnterMonitorAsync(driver, vm, + QEMU_ASYNC_JOB_MIGRATION_OUT) < 0) + goto cleanup; + + mon_ret = qemuBlockStorageSourceAttachApply(qemuDomainGetMonitor(vm), data); + + if (mon_ret == 0) + mon_ret = qemuMonitorBlockdevMirror(qemuDomainGetMonitor(vm), NULL, + diskAlias, copysrc->nodeformat, + mirror_speed, 0, 0, mirror_flags); + + if (mon_ret != 0) + qemuBlockStorageSourceAttachRollback(qemuDomainGetMonitor(vm), data); + + if (qemuDomainObjExitMonitor(driver, vm) < 0 || mon_ret < 0) + goto cleanup; + + VIR_STEAL_PTR(diskPriv->migrSource, copysrc); + + ret = 0; + + cleanup: + qemuBlockStorageSourceAttachDataFree(data); + virStorageSourceFree(copysrc); + return ret; +} + + static int qemuMigrationSrcNBDStorageCopyDriveMirror(virQEMUDriverPtr driver, virDomainObjPtr vm, @@ -818,7 +911,9 @@ qemuMigrationSrcNBDStorageCopy(virQEMUDriverPtr driver, unsigned int *migrate_flags, size_t nmigrate_disks, const char **migrate_disks, - virConnectPtr dconn) + virConnectPtr dconn, + const char *tlsAlias, + unsigned int flags) { qemuDomainObjPrivatePtr priv = vm->privateData; int ret = -1; @@ -850,6 +945,7 @@ qemuMigrationSrcNBDStorageCopy(virQEMUDriverPtr driver, for (i = 0; i < vm->def->ndisks; i++) { virDomainDiskDefPtr disk = vm->def->disks[i]; qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk); + int rc; /* check whether disk should be migrated */ if (!qemuMigrationAnyCopyDisk(disk, nmigrate_disks, migrate_disks)) @@ -860,10 +956,21 @@ qemuMigrationSrcNBDStorageCopy(virQEMUDriverPtr driver, qemuBlockJobSyncBegin(disk); - if (qemuMigrationSrcNBDStorageCopyDriveMirror(driver, vm, diskAlias, - host, port, - mirror_speed, - mirror_flags) < 0) { + if (flags & VIR_MIGRATE_TLS) { + rc = qemuMigrationSrcNBDStorageCopyBlockdev(driver, vm, + disk, diskAlias, + host, port, + mirror_speed, + mirror_flags, + tlsAlias); + } else { + rc = qemuMigrationSrcNBDStorageCopyDriveMirror(driver, vm, diskAlias, + host, port, + mirror_speed, + mirror_flags); + } + + if (rc < 0) { qemuBlockJobSyncEnd(vm, QEMU_ASYNC_JOB_MIGRATION_OUT, disk); goto cleanup; } @@ -3367,7 +3474,8 @@ qemuMigrationSrcRun(virQEMUDriverPtr driver, * non-shared storage migration with TLS. As we need to honour the * VIR_MIGRATE_TLS flag, we need to reject such migration until * we implement TLS for NBD. */ - if (flags & VIR_MIGRATE_TLS) { + if (flags & VIR_MIGRATE_TLS && + !virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKDEV_DEL)) { virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", _("NBD migration with TLS is not supported")); goto error; @@ -3380,7 +3488,7 @@ qemuMigrationSrcRun(virQEMUDriverPtr driver, &migrate_flags, nmigrate_disks, migrate_disks, - dconn) < 0) { + dconn, tlsAlias, flags) < 0) { goto error; } } else { -- 2.16.2

On 05/18/2018 07:28 AM, Peter Krempa wrote:
Implement the non-shared storage migration when TLS is enabled. This is done by using blockdev-add to add the NBD endpoint with the TLS environment alias configured properly.
Peter Krempa (15): qemu: block: Don't nest storage layer properties into format layer conf: domain: Export virDomainStorageSourceParse qemu: migration: Don't access disk members without lock qemu: caps: Add capability for blockdev-add/blockdev-del qemu: monitor: Factor out and document code to format QMP command qemu: monitor: Add implementation for blockdev-add and blockdev-del qemu: monitor: Introduce support for blockdev-mirror qemu: block: Add helpers for hot-adding virStorageSource via blockdev qemu: domain: Extract NBD disk migration private data formatting qemu: domain: Extract parsing of NBD status XML qemu: domain: Add private data for NBD migration storage source definition test: Add status XML test for NBD tls storage migration qemu: migration: Rename NBD migration functions qemu: migration: Extract code responsible for calling drive-mirror qemu: migration: Add support for transporting NBD over TLS
src/conf/domain_conf.c | 2 +- src/conf/domain_conf.h | 6 + src/libvirt_private.syms | 1 + src/qemu/qemu_block.c | 163 +++++++- src/qemu/qemu_block.h | 34 ++ src/qemu/qemu_capabilities.c | 2 + src/qemu/qemu_capabilities.h | 1 + src/qemu/qemu_domain.c | 242 +++++++++-- src/qemu/qemu_domain.h | 1 + src/qemu/qemu_migration.c | 306 ++++++++++---- src/qemu/qemu_monitor.c | 59 +++ src/qemu/qemu_monitor.h | 16 + src/qemu/qemu_monitor_json.c | 164 +++++++- src/qemu/qemu_monitor_json.h | 18 + tests/qemublocktest.c | 11 +- .../xml2json/block-raw-noopts.json | 15 +- .../qemublocktestdata/xml2json/dir-fat-cache.json | 27 +- .../qemublocktestdata/xml2json/dir-fat-floppy.json | 19 +- .../xml2json/dir-fat-readonly.json | 19 +- .../xml2json/file-backing_basic-aio_threads.json | 82 ++-- .../file-backing_basic-cache-directsync.json | 108 ++--- .../xml2json/file-backing_basic-cache-none.json | 108 ++--- .../xml2json/file-backing_basic-cache-unsafe.json | 108 ++--- .../file-backing_basic-cache-writeback.json | 108 ++--- .../file-backing_basic-cache-writethrough.json | 108 ++--- .../xml2json/file-backing_basic-detect.json | 76 ++-- .../xml2json/file-backing_basic-noopts.json | 60 +-- .../xml2json/file-backing_basic-unmap-detect.json | 76 ++-- .../xml2json/file-backing_basic-unmap-ignore.json | 76 ++-- .../xml2json/file-backing_basic-unmap.json | 76 ++-- .../xml2json/file-bochs-noopts.json | 15 +- .../xml2json/file-cloop-noopts.json | 15 +- .../xml2json/file-dmg-noopts.json | 15 +- .../xml2json/file-ploop-noopts.json | 15 +- .../file-qcow2-backing-chain-encryption.json | 30 +- .../xml2json/file-qcow2-backing-chain-noopts.json | 150 +++---- .../file-qcow2-backing-chain-unterminated.json | 30 +- .../xml2json/file-raw-aio_native.json | 25 +- .../qemublocktestdata/xml2json/file-raw-luks.json | 15 +- .../xml2json/file-raw-noopts.json | 15 +- .../xml2json/file-vdi-noopts.json | 15 +- .../xml2json/file-vhd-noopts.json | 15 +- .../xml2json/file-vpc-noopts.json | 15 +- .../network-qcow2-backing-chain-cache-unsafe.json | 74 ++-- ...etwork-qcow2-backing-chain-encryption_auth.json | 64 +-- tests/qemucapabilitiesdata/caps_2.10.0.aarch64.xml | 1 + tests/qemucapabilitiesdata/caps_2.10.0.ppc64.xml | 1 + tests/qemucapabilitiesdata/caps_2.10.0.s390x.xml | 1 + tests/qemucapabilitiesdata/caps_2.10.0.x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_2.11.0.s390x.xml | 1 + tests/qemucapabilitiesdata/caps_2.12.0.aarch64.xml | 1 + tests/qemucapabilitiesdata/caps_2.12.0.ppc64.xml | 1 + tests/qemucapabilitiesdata/caps_2.12.0.s390x.xml | 1 + tests/qemucapabilitiesdata/caps_2.12.0.x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_2.9.0.ppc64.xml | 1 + tests/qemucapabilitiesdata/caps_2.9.0.s390x.xml | 1 + tests/qemucapabilitiesdata/caps_2.9.0.x86_64.xml | 1 + .../migration-out-nbd-tls-in.xml | 464 +++++++++++++++++++++ .../migration-out-nbd-tls-out.xml | 1 + tests/qemuxml2xmltest.c | 1 + 60 files changed, 2172 insertions(+), 906 deletions(-) create mode 100644 tests/qemustatusxml2xmldata/migration-out-nbd-tls-in.xml create mode 120000 tests/qemustatusxml2xmldata/migration-out-nbd-tls-out.xml
There's a couple things noted, but otherwise looks good to me. Reviewed-by: John Ferlan <jferlan@redhat.com> (series) John I tried running through my Coverity checker, but the license server is down - hopefully by morning it's back.
participants (2)
-
John Ferlan
-
Peter Krempa