Compare commits
272 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 54d3da1da5 | |||
| faf5df2081 | |||
| e5075407b1 | |||
| 8c3f1e830e | |||
| 58083f4418 | |||
| 55a13fd521 | |||
| 262bbf08f2 | |||
| 0fe69a9b44 | |||
| 04cb28c315 | |||
| a74ea318d1 | |||
| 98ed6b4e36 | |||
| 2c49d1fd11 | |||
| 6e7bca6631 | |||
| 2fe145bb02 | |||
| 10b7d235e3 | |||
| 232e2e7de2 | |||
| fb1e4b061e | |||
| 0b1a013081 | |||
| a972457f43 | |||
| 67cfa34a05 | |||
| fc2ebb7646 | |||
| e92b461b4f | |||
| b1ac7b5791 | |||
| 88424efe85 | |||
| 4e2aab98a2 | |||
| f4bc1a2fe2 | |||
| a4bf2768b8 | |||
| 47cd44e9da | |||
| 731c6b90ff | |||
| 47ca46905d | |||
| 860ffc5b13 | |||
| 611b2ee520 | |||
| edcb926f9d | |||
| caebff8304 | |||
| 8fa41135ca | |||
| 0debbff964 | |||
| d6cc78be66 | |||
| 8d9645735e | |||
| 4c65f08330 | |||
| 2427f8f078 | |||
| d168e4f934 | |||
| 4dd365589f | |||
| 50e253df29 | |||
| cb71801a2b | |||
| 4a9c74e91d | |||
| 281508ec99 | |||
| feb92626e1 | |||
| 93cadb0880 | |||
| dd6b57aa60 | |||
| b8cb754e9d | |||
| dbe61507bd | |||
| ce7b23d9d0 | |||
| 8ded6ff93e | |||
| 1ef96f3488 | |||
| ee3bf37900 | |||
| 7452a06938 | |||
| fe8f9ed9c4 | |||
| 1b64f74c82 | |||
| c81949046d | |||
| 19dcb913e6 | |||
| e4b5ba1a9d | |||
| 5f1a422d83 | |||
| c5b0b3ef9d | |||
| c0a04cb876 | |||
| 3cc7cdf12f | |||
| 6b531d9967 | |||
| 4d05ac021c | |||
| d29aa84b17 | |||
| a075adc818 | |||
| 4d0e63f99c | |||
| 9e11936ec5 | |||
| a4075ec632 | |||
| dadb59c95f | |||
| e73cc6a9d8 | |||
| 10cd84e37f | |||
| e63e2040cd | |||
| 91063332d7 | |||
| 503330ba5d | |||
| 0a64085f47 | |||
| 1073e2447a | |||
| 5b1a906ace | |||
| aff97e0146 | |||
| a4b41a378b | |||
| 3ec523d168 | |||
| 622cf0d642 | |||
| a540751e83 | |||
| 11b596669a | |||
| fefbae879b | |||
| 695b281409 | |||
| 9f9eae34c1 | |||
| ae37ed3500 | |||
| f7f509999b | |||
| 419bcc4b2f | |||
| 7b59d4f7eb | |||
| 03326e9c04 | |||
| f40b464d1e | |||
| 810ca6c207 | |||
| 8df3aef6aa | |||
| 0223d5a656 | |||
| aad810a204 | |||
| 1b8b7567b1 | |||
| 442040caac | |||
| 65efaafca2 | |||
| e87c8ab0c7 | |||
| be6bda45b4 | |||
| 8c9e40d383 | |||
| 0f6f9b973a | |||
| 3db6039b2b | |||
| 4051217c8b | |||
| c5c28baba1 | |||
| 43618df1d4 | |||
| a2951dccb5 | |||
| b884323c03 | |||
| adeaf839fd | |||
| 40d99010e1 | |||
| 11755d8663 | |||
| 2daa92daf9 | |||
| db2858c661 | |||
| 53adb9aaba | |||
| 168df8b606 | |||
| f9085f2538 | |||
| b159bbdc98 | |||
| a5af3cf105 | |||
| 27ca069db7 | |||
| 000a3274d2 | |||
| 19c7799c31 | |||
| 198ff818c6 | |||
| e80c83ad06 | |||
| 660e0112c6 | |||
| 45c1cabef6 | |||
| 56be2c5e38 | |||
| 4aa9c4f1a3 | |||
| 7be420ad22 | |||
| 40b00623a4 | |||
| ce09ec66c7 | |||
| 97d7c80e2e | |||
| b856ae03bf | |||
| 803b3b891a | |||
| 350081d1a9 | |||
| 1b71b68bb9 | |||
| 4084288dd5 | |||
| d1cd1b7ceb | |||
| 5ed69704b9 | |||
| be6e136cb1 | |||
| d3109abfa4 | |||
| f5ff4a2393 | |||
| 8cc50838dc | |||
| 2c2e71c0ce | |||
| 96b1b18b42 | |||
| f7763bfd17 | |||
| 404e58cb18 | |||
| cd3767e3b9 | |||
| f1867a5ecc | |||
| b5548f62cb | |||
| 52f3bedee7 | |||
| f87237919c | |||
| e8969fb913 | |||
| 74d46bc7dd | |||
| 4b6ea94306 | |||
| 963754bc8c | |||
| 7b5483236c | |||
| 438006407c | |||
| 76c8282ee2 | |||
| f463598b24 | |||
| f4e752a385 | |||
| c37cb21dea | |||
| e0bfc1f8aa | |||
| 544ad4a787 | |||
| 8f163760ed | |||
| 565427cf89 | |||
| e10da2f6d4 | |||
| aa386576d5 | |||
| c73c129b48 | |||
| afe729ac3c | |||
| b6038bae4f | |||
| e6d9787587 | |||
| 44699dc495 | |||
| 991d719dde | |||
| 96a520b555 | |||
| e31df5e9de | |||
| 6763b267b9 | |||
| 24e91208a4 | |||
| 15dec999e7 | |||
| d6b0635d3d | |||
| 336a93264e | |||
| 6398d1cff5 | |||
| 6926ed26ea | |||
| 6253f97a2d | |||
| 37ddbd0eac | |||
| 95fe7c8df2 | |||
| 79ae809020 | |||
| f19e302ba9 | |||
| e9c1d3f4b0 | |||
| 0f577d932b | |||
| 21a02c2e90 | |||
| 4e460d5f09 | |||
| f9de2f6bc6 | |||
| 2daa1b7814 | |||
| f99eeb8567 | |||
| 7069f75cb8 | |||
| 2cac7dac46 | |||
| 913c3c6554 | |||
| a5a4c0c89b | |||
| 8c8aca2fab | |||
| daf8e124ca | |||
| 38c4b724fe | |||
| 4d00487275 | |||
| a6831c26c1 | |||
| c363c7ebdb | |||
| 18ee6daf8a | |||
| 459eb426c3 | |||
| a0d670d2bf | |||
| d7b41212c1 | |||
| 2e1539eba4 | |||
| ee9521d87c | |||
| 8d8fc08bac | |||
| e79d304c79 | |||
| db03f03fd9 | |||
| 957403ebec | |||
| 6c32e1aaeb | |||
| 362e335c0b | |||
| ed6c49f874 | |||
| 47fcec5405 | |||
| d7239a45b6 | |||
| f13fb18c58 | |||
| d29644418d | |||
| ed9e426b26 | |||
| 659febf9ff | |||
| fca1fccfad | |||
| f713d63bab | |||
| 5a45e466cf | |||
| 742b24eb23 | |||
| 03369d2383 | |||
| 2605d662e0 | |||
| e8394ab5b5 | |||
| 8ad156a5c2 | |||
| f2d6fb6239 | |||
| e3a592c38d | |||
| 7e99819dda | |||
| a160d7f98d | |||
| 36cab842e8 | |||
| 7b7b86e327 | |||
| f4bfe638b6 | |||
| 0e9d242f05 | |||
| e24467a8c2 | |||
| b39c370a76 | |||
| 62e4e7cde2 | |||
| f822179f97 | |||
| 47e7e1e548 | |||
| e73b75314b | |||
| 8193a55b4a | |||
| 6036708fa2 | |||
| 4717aa0b6d | |||
| 97ae25ea7d | |||
| 6470ed033b | |||
| b550f9c1d5 | |||
| ee0273ffc3 | |||
| 50fce74b00 | |||
| e29f71d1c9 | |||
| 427ed20801 | |||
| d23e6c285b | |||
| 2c139b45d8 | |||
| 762435e3b7 | |||
| 6383d6b056 | |||
| 3712441ea6 | |||
| 9d0bc882fa | |||
| 90dddf3d3d | |||
| 86abd54d02 | |||
| 4ab5ad5425 | |||
| f9c1b758c3 | |||
| 38cf1bd5ba | |||
| aeda455930 |
+1
-1
@@ -2,4 +2,4 @@
|
||||
*.rpm
|
||||
i686
|
||||
x86_64
|
||||
libvirt-*.tar.gz
|
||||
libvirt-*.tar.xz
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
From: Andrea Bolognani <abologna@redhat.com>
|
||||
Date: Fri, 12 May 2017 14:05:55 +0200
|
||||
Subject: [PATCH] tests: Check default GIC version for aarch64/virt TCG guests
|
||||
|
||||
Signed-off-by: Andrea Bolognani <abologna@redhat.com>
|
||||
(cherry picked from commit b24eaf6210ebaf5dc8d29621063873c8419c517e)
|
||||
---
|
||||
.../qemuxml2argv-aarch64-gic-none-tcg.args | 19 ++++++++++++++++
|
||||
.../qemuxml2argv-aarch64-gic-none-tcg.xml | 17 +++++++++++++++
|
||||
tests/qemuxml2argvtest.c | 3 +++
|
||||
.../qemuxml2xmlout-aarch64-gic-none-tcg.xml | 25 ++++++++++++++++++++++
|
||||
tests/qemuxml2xmltest.c | 1 +
|
||||
5 files changed, 65 insertions(+)
|
||||
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-aarch64-gic-none-tcg.args
|
||||
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-aarch64-gic-none-tcg.xml
|
||||
create mode 100644 tests/qemuxml2xmloutdata/qemuxml2xmlout-aarch64-gic-none-tcg.xml
|
||||
|
||||
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-aarch64-gic-none-tcg.args b/tests/qemuxml2argvdata/qemuxml2argv-aarch64-gic-none-tcg.args
|
||||
new file mode 100644
|
||||
index 000000000..975a01481
|
||||
--- /dev/null
|
||||
+++ b/tests/qemuxml2argvdata/qemuxml2argv-aarch64-gic-none-tcg.args
|
||||
@@ -0,0 +1,19 @@
|
||||
+LC_ALL=C \
|
||||
+PATH=/bin \
|
||||
+HOME=/home/test \
|
||||
+USER=test \
|
||||
+LOGNAME=test \
|
||||
+QEMU_AUDIO_DRV=none \
|
||||
+/usr/bin/qemu-system-aarch64 \
|
||||
+-name guest \
|
||||
+-S \
|
||||
+-machine virt,accel=tcg,gic-version=3 \
|
||||
+-cpu cortex-a57 \
|
||||
+-m 1024 \
|
||||
+-smp 1,sockets=1,cores=1,threads=1 \
|
||||
+-uuid 6ba410c5-1e5c-4d57-bee7-2228e7ffa32f \
|
||||
+-nographic \
|
||||
+-nodefaults \
|
||||
+-monitor unix:/tmp/lib/domain--1-guest/monitor.sock,server,nowait \
|
||||
+-no-acpi \
|
||||
+-boot c
|
||||
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-aarch64-gic-none-tcg.xml b/tests/qemuxml2argvdata/qemuxml2argv-aarch64-gic-none-tcg.xml
|
||||
new file mode 100644
|
||||
index 000000000..0aa33dbec
|
||||
--- /dev/null
|
||||
+++ b/tests/qemuxml2argvdata/qemuxml2argv-aarch64-gic-none-tcg.xml
|
||||
@@ -0,0 +1,17 @@
|
||||
+<domain type='qemu'>
|
||||
+ <name>guest</name>
|
||||
+ <uuid>6ba410c5-1e5c-4d57-bee7-2228e7ffa32f</uuid>
|
||||
+ <memory unit='KiB'>1048576</memory>
|
||||
+ <vcpu placement='static'>1</vcpu>
|
||||
+ <os>
|
||||
+ <type arch='aarch64' machine='virt'>hvm</type>
|
||||
+ <boot dev='hd'/>
|
||||
+ </os>
|
||||
+ <cpu mode='custom'>
|
||||
+ <model>cortex-a57</model>
|
||||
+ </cpu>
|
||||
+ <devices>
|
||||
+ <emulator>/usr/bin/qemu-system-aarch64</emulator>
|
||||
+ <memballoon model='none'/>
|
||||
+ </devices>
|
||||
+</domain>
|
||||
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
|
||||
index cc4fb91cd..362b140ac 100644
|
||||
--- a/tests/qemuxml2argvtest.c
|
||||
+++ b/tests/qemuxml2argvtest.c
|
||||
@@ -2250,6 +2250,9 @@ mymain(void)
|
||||
DO_TEST_GIC("aarch64-gic-none-both", GIC_BOTH,
|
||||
QEMU_CAPS_KVM, QEMU_CAPS_MACHINE_OPT,
|
||||
QEMU_CAPS_MACH_VIRT_GIC_VERSION);
|
||||
+ DO_TEST_GIC("aarch64-gic-none-tcg", GIC_BOTH,
|
||||
+ QEMU_CAPS_MACHINE_OPT,
|
||||
+ QEMU_CAPS_MACH_VIRT_GIC_VERSION);
|
||||
DO_TEST_GIC("aarch64-gic-default", GIC_NONE,
|
||||
QEMU_CAPS_KVM, QEMU_CAPS_MACHINE_OPT);
|
||||
DO_TEST_GIC("aarch64-gic-default", GIC_NONE,
|
||||
diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-aarch64-gic-none-tcg.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-aarch64-gic-none-tcg.xml
|
||||
new file mode 100644
|
||||
index 000000000..69510e281
|
||||
--- /dev/null
|
||||
+++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-aarch64-gic-none-tcg.xml
|
||||
@@ -0,0 +1,25 @@
|
||||
+<domain type='qemu'>
|
||||
+ <name>guest</name>
|
||||
+ <uuid>6ba410c5-1e5c-4d57-bee7-2228e7ffa32f</uuid>
|
||||
+ <memory unit='KiB'>1048576</memory>
|
||||
+ <currentMemory unit='KiB'>1048576</currentMemory>
|
||||
+ <vcpu placement='static'>1</vcpu>
|
||||
+ <os>
|
||||
+ <type arch='aarch64' machine='virt'>hvm</type>
|
||||
+ <boot dev='hd'/>
|
||||
+ </os>
|
||||
+ <features>
|
||||
+ <gic version='3'/>
|
||||
+ </features>
|
||||
+ <cpu mode='custom' match='exact' check='none'>
|
||||
+ <model fallback='allow'>cortex-a57</model>
|
||||
+ </cpu>
|
||||
+ <clock offset='utc'/>
|
||||
+ <on_poweroff>destroy</on_poweroff>
|
||||
+ <on_reboot>restart</on_reboot>
|
||||
+ <on_crash>destroy</on_crash>
|
||||
+ <devices>
|
||||
+ <emulator>/usr/bin/qemu-system-aarch64</emulator>
|
||||
+ <memballoon model='none'/>
|
||||
+ </devices>
|
||||
+</domain>
|
||||
diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c
|
||||
index eae999dd6..aae632afe 100644
|
||||
--- a/tests/qemuxml2xmltest.c
|
||||
+++ b/tests/qemuxml2xmltest.c
|
||||
@@ -1073,6 +1073,7 @@ mymain(void)
|
||||
DO_TEST_FULL("aarch64-gic-none-v2", WHEN_BOTH, GIC_V2, NONE);
|
||||
DO_TEST_FULL("aarch64-gic-none-v3", WHEN_BOTH, GIC_V3, NONE);
|
||||
DO_TEST_FULL("aarch64-gic-none-both", WHEN_BOTH, GIC_BOTH, NONE);
|
||||
+ DO_TEST_FULL("aarch64-gic-none-tcg", WHEN_BOTH, GIC_BOTH, NONE);
|
||||
DO_TEST_FULL("aarch64-gic-default", WHEN_BOTH, GIC_NONE, NONE);
|
||||
DO_TEST_FULL("aarch64-gic-default", WHEN_BOTH, GIC_V2, NONE);
|
||||
DO_TEST_FULL("aarch64-gic-default", WHEN_BOTH, GIC_V3, NONE);
|
||||
@@ -0,0 +1,85 @@
|
||||
From: Andrea Bolognani <abologna@redhat.com>
|
||||
Date: Fri, 12 May 2017 13:29:57 +0200
|
||||
Subject: [PATCH] qemu: Use GICv2 for aarch64/virt TCG guests
|
||||
|
||||
There are currently some limitations in the emulated GICv3
|
||||
that make it unsuitable as a default. Use GICv2 instead.
|
||||
|
||||
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1450433
|
||||
|
||||
Signed-off-by: Andrea Bolognani <abologna@redhat.com>
|
||||
(cherry picked from commit bc07101a7c2cd2ce07ad1ca28c47e0a7cde5625d)
|
||||
---
|
||||
src/qemu/qemu_domain.c | 23 +++++++++++++++++++++-
|
||||
.../qemuxml2argv-aarch64-gic-none-tcg.args | 2 +-
|
||||
.../qemuxml2xmlout-aarch64-gic-none-tcg.xml | 2 +-
|
||||
3 files changed, 24 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
|
||||
index 589eb1889..891f8258a 100644
|
||||
--- a/src/qemu/qemu_domain.c
|
||||
+++ b/src/qemu/qemu_domain.c
|
||||
@@ -2527,6 +2527,24 @@ qemuDomainDefEnableDefaultFeatures(virDomainDefPtr def,
|
||||
for (version = VIR_GIC_VERSION_LAST - 1;
|
||||
version > VIR_GIC_VERSION_NONE;
|
||||
version--) {
|
||||
+
|
||||
+ /* We want to use the highest available GIC version for guests;
|
||||
+ * however, the emulated GICv3 is currently lacking a MSI controller,
|
||||
+ * making it unsuitable for the pure PCIe topology we aim for.
|
||||
+ *
|
||||
+ * For that reason, we skip this step entirely for TCG guests,
|
||||
+ * and rely on the code below to pick the default version, GICv2,
|
||||
+ * which supports all the features we need.
|
||||
+ *
|
||||
+ * We'll want to revisit this once MSI support for GICv3 has been
|
||||
+ * implemented in QEMU.
|
||||
+ *
|
||||
+ * See https://bugzilla.redhat.com/show_bug.cgi?id=1414081 */
|
||||
+ if (version == VIR_GIC_VERSION_3 &&
|
||||
+ def->virtType == VIR_DOMAIN_VIRT_QEMU) {
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
if (virQEMUCapsSupportsGICVersion(qemuCaps,
|
||||
def->virtType,
|
||||
version)) {
|
||||
@@ -2544,8 +2562,11 @@ qemuDomainDefEnableDefaultFeatures(virDomainDefPtr def,
|
||||
|
||||
/* Use the default GIC version if no version was specified */
|
||||
if (def->features[VIR_DOMAIN_FEATURE_GIC] == VIR_TRISTATE_SWITCH_ON &&
|
||||
- def->gic_version == VIR_GIC_VERSION_NONE)
|
||||
+ def->gic_version == VIR_GIC_VERSION_NONE) {
|
||||
+ VIR_DEBUG("Using GIC version %s (default)",
|
||||
+ virGICVersionTypeToString(VIR_GIC_VERSION_DEFAULT));
|
||||
def->gic_version = VIR_GIC_VERSION_DEFAULT;
|
||||
+ }
|
||||
}
|
||||
|
||||
|
||||
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-aarch64-gic-none-tcg.args b/tests/qemuxml2argvdata/qemuxml2argv-aarch64-gic-none-tcg.args
|
||||
index 975a01481..52b699696 100644
|
||||
--- a/tests/qemuxml2argvdata/qemuxml2argv-aarch64-gic-none-tcg.args
|
||||
+++ b/tests/qemuxml2argvdata/qemuxml2argv-aarch64-gic-none-tcg.args
|
||||
@@ -7,7 +7,7 @@ QEMU_AUDIO_DRV=none \
|
||||
/usr/bin/qemu-system-aarch64 \
|
||||
-name guest \
|
||||
-S \
|
||||
--machine virt,accel=tcg,gic-version=3 \
|
||||
+-machine virt,accel=tcg \
|
||||
-cpu cortex-a57 \
|
||||
-m 1024 \
|
||||
-smp 1,sockets=1,cores=1,threads=1 \
|
||||
diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-aarch64-gic-none-tcg.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-aarch64-gic-none-tcg.xml
|
||||
index 69510e281..a0cd0b768 100644
|
||||
--- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-aarch64-gic-none-tcg.xml
|
||||
+++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-aarch64-gic-none-tcg.xml
|
||||
@@ -9,7 +9,7 @@
|
||||
<boot dev='hd'/>
|
||||
</os>
|
||||
<features>
|
||||
- <gic version='3'/>
|
||||
+ <gic version='2'/>
|
||||
</features>
|
||||
<cpu mode='custom' match='exact' check='none'>
|
||||
<model fallback='allow'>cortex-a57</model>
|
||||
@@ -0,0 +1,67 @@
|
||||
From: Andrea Bolognani <abologna@redhat.com>
|
||||
Date: Fri, 12 May 2017 14:38:08 +0200
|
||||
Subject: [PATCH] gic: Remove VIR_GIC_VERSION_DEFAULT
|
||||
|
||||
The QEMU default is GICv2, and some of the code in libvirt
|
||||
relies on the exact value. Stop pretending that's not the
|
||||
case and use GICv2 explicitly where needed.
|
||||
|
||||
Signed-off-by: Andrea Bolognani <abologna@redhat.com>
|
||||
(cherry picked from commit 5645badd1fe04fee7237c2f95e7710e978e40770)
|
||||
---
|
||||
src/qemu/qemu_command.c | 6 +++---
|
||||
src/qemu/qemu_domain.c | 7 +++----
|
||||
src/util/virgic.h | 3 ---
|
||||
3 files changed, 6 insertions(+), 10 deletions(-)
|
||||
|
||||
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
|
||||
index 2d1328cf9..5feddc523 100644
|
||||
--- a/src/qemu/qemu_command.c
|
||||
+++ b/src/qemu/qemu_command.c
|
||||
@@ -7321,9 +7321,9 @@ qemuBuildMachineCommandLine(virCommandPtr cmd,
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
- /* The default GIC version should not be specified on the
|
||||
- * QEMU commandline for backwards compatibility reasons */
|
||||
- if (def->gic_version != VIR_GIC_VERSION_DEFAULT) {
|
||||
+ /* The default GIC version (GICv2) should not be specified on
|
||||
+ * the QEMU commandline for backwards compatibility reasons */
|
||||
+ if (def->gic_version != VIR_GIC_VERSION_2) {
|
||||
if (!virQEMUCapsGet(qemuCaps,
|
||||
QEMU_CAPS_MACH_VIRT_GIC_VERSION)) {
|
||||
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
||||
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
|
||||
index 891f8258a..4a127cedf 100644
|
||||
--- a/src/qemu/qemu_domain.c
|
||||
+++ b/src/qemu/qemu_domain.c
|
||||
@@ -2560,12 +2560,11 @@ qemuDomainDefEnableDefaultFeatures(virDomainDefPtr def,
|
||||
def->features[VIR_DOMAIN_FEATURE_GIC] = VIR_TRISTATE_SWITCH_ON;
|
||||
}
|
||||
|
||||
- /* Use the default GIC version if no version was specified */
|
||||
+ /* Use the default GIC version (GICv2) if no version was specified */
|
||||
if (def->features[VIR_DOMAIN_FEATURE_GIC] == VIR_TRISTATE_SWITCH_ON &&
|
||||
def->gic_version == VIR_GIC_VERSION_NONE) {
|
||||
- VIR_DEBUG("Using GIC version %s (default)",
|
||||
- virGICVersionTypeToString(VIR_GIC_VERSION_DEFAULT));
|
||||
- def->gic_version = VIR_GIC_VERSION_DEFAULT;
|
||||
+ VIR_DEBUG("Using GIC version 2 (default)");
|
||||
+ def->gic_version = VIR_GIC_VERSION_2;
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/src/util/virgic.h b/src/util/virgic.h
|
||||
index 1c9efd60f..2d77fdd45 100644
|
||||
--- a/src/util/virgic.h
|
||||
+++ b/src/util/virgic.h
|
||||
@@ -35,9 +35,6 @@ typedef enum {
|
||||
|
||||
VIR_ENUM_DECL(virGICVersion);
|
||||
|
||||
-/* Consider GIC v2 the default */
|
||||
-# define VIR_GIC_VERSION_DEFAULT VIR_GIC_VERSION_2
|
||||
-
|
||||
typedef enum {
|
||||
VIR_GIC_IMPLEMENTATION_NONE = 0,
|
||||
VIR_GIC_IMPLEMENTATION_KERNEL = (1 << 1),
|
||||
@@ -0,0 +1,198 @@
|
||||
From: Laine Stump <laine@laine.org>
|
||||
Date: Thu, 18 May 2017 14:16:27 -0400
|
||||
Subject: [PATCH] Revert "qemu: propagate bridge MTU into qemu "host_mtu"
|
||||
option"
|
||||
|
||||
This reverts commit 2841e675.
|
||||
|
||||
It turns out that adding the host_mtu field to the PCI capabilities in
|
||||
the guest bumps the length of PCI capabilities beyond the 32 byte
|
||||
boundary, so the virtio-net device gets 64 bytes of ioport space
|
||||
instead of 32, which offsets the address of all the other following
|
||||
devices. Migration doesn't work very well when the location and length
|
||||
of PCI capabilities of devices is changed between source and
|
||||
destination.
|
||||
|
||||
This means that we need to make sure that the absence/presence of
|
||||
host_mtu on the qemu commandline always matches between source and
|
||||
destination, which means that we need to make setting of host_mtu an
|
||||
opt-in thing (it can't happen automatically when the bridge being used
|
||||
has a non-default MTU, which is what commit 2841e675 implemented).
|
||||
|
||||
I do want to re-implement this feature with an <mtu auto='on'/>
|
||||
setting, but probably won't backport that to any stable branches, so
|
||||
I'm first reverting the original commit, and that revert can be pushed
|
||||
to the few releases that have been made since the original (3.1.0 -
|
||||
3.3.0)
|
||||
|
||||
Resolves: https://bugzilla.redhat.com/1449346
|
||||
(cherry picked from commit 77780a29edace958a1f931d3281b962be4f5290e)
|
||||
(cherry picked from commit a2f5e87dceb1725c16cd4df17a4b7381ecf65901)
|
||||
---
|
||||
src/qemu/qemu_command.c | 32 ++++++++++----------------------
|
||||
src/qemu/qemu_command.h | 3 +--
|
||||
src/qemu/qemu_hotplug.c | 5 ++---
|
||||
src/qemu/qemu_interface.c | 5 ++---
|
||||
src/qemu/qemu_interface.h | 3 +--
|
||||
5 files changed, 16 insertions(+), 32 deletions(-)
|
||||
|
||||
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
|
||||
index 5feddc523..3abfe7b55 100644
|
||||
--- a/src/qemu/qemu_command.c
|
||||
+++ b/src/qemu/qemu_command.c
|
||||
@@ -3629,8 +3629,7 @@ qemuBuildNicDevStr(virDomainDefPtr def,
|
||||
int vlan,
|
||||
unsigned int bootindex,
|
||||
size_t vhostfdSize,
|
||||
- virQEMUCapsPtr qemuCaps,
|
||||
- unsigned int mtu)
|
||||
+ virQEMUCapsPtr qemuCaps)
|
||||
{
|
||||
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
||||
const char *nic = net->model;
|
||||
@@ -3754,23 +3753,13 @@ qemuBuildNicDevStr(virDomainDefPtr def,
|
||||
virBufferAsprintf(&buf, ",rx_queue_size=%u", net->driver.virtio.rx_queue_size);
|
||||
}
|
||||
|
||||
- if (usingVirtio && mtu) {
|
||||
- if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_NET_HOST_MTU)) {
|
||||
-
|
||||
- virBufferAsprintf(&buf, ",host_mtu=%u", mtu);
|
||||
-
|
||||
- } else {
|
||||
- /* log an error if mtu was requested specifically for this
|
||||
- * interface, otherwise, if it's just what was reported by
|
||||
- * the attached network, ignore it.
|
||||
- */
|
||||
- if (net->mtu) {
|
||||
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
||||
- _("setting MTU is not supported with "
|
||||
- "this QEMU binary"));
|
||||
- goto error;
|
||||
- }
|
||||
+ if (usingVirtio && net->mtu) {
|
||||
+ if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_NET_HOST_MTU)) {
|
||||
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
||||
+ _("setting MTU is not supported with this QEMU binary"));
|
||||
+ goto error;
|
||||
}
|
||||
+ virBufferAsprintf(&buf, ",host_mtu=%u", net->mtu);
|
||||
}
|
||||
|
||||
if (vlan == -1)
|
||||
@@ -8213,7 +8202,7 @@ qemuBuildVhostuserCommandLine(virQEMUDriverPtr driver,
|
||||
VIR_FREE(netdev);
|
||||
|
||||
if (!(nic = qemuBuildNicDevStr(def, net, -1, bootindex,
|
||||
- queues, qemuCaps, net->mtu))) {
|
||||
+ queues, qemuCaps))) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
"%s", _("Error generating NIC -device string"));
|
||||
goto error;
|
||||
@@ -8259,7 +8248,6 @@ qemuBuildInterfaceCommandLine(virQEMUDriverPtr driver,
|
||||
virDomainNetType actualType = virDomainNetGetActualType(net);
|
||||
virNetDevBandwidthPtr actualBandwidth;
|
||||
size_t i;
|
||||
- unsigned int mtu = net->mtu;
|
||||
|
||||
|
||||
if (!bootindex)
|
||||
@@ -8314,7 +8302,7 @@ qemuBuildInterfaceCommandLine(virQEMUDriverPtr driver,
|
||||
memset(tapfd, -1, tapfdSize * sizeof(tapfd[0]));
|
||||
|
||||
if (qemuInterfaceBridgeConnect(def, driver, net,
|
||||
- tapfd, &tapfdSize, &mtu) < 0)
|
||||
+ tapfd, &tapfdSize) < 0)
|
||||
goto cleanup;
|
||||
break;
|
||||
|
||||
@@ -8494,7 +8482,7 @@ qemuBuildInterfaceCommandLine(virQEMUDriverPtr driver,
|
||||
}
|
||||
if (qemuDomainSupportsNicdev(def, net)) {
|
||||
if (!(nic = qemuBuildNicDevStr(def, net, vlan, bootindex,
|
||||
- vhostfdSize, qemuCaps, mtu)))
|
||||
+ vhostfdSize, qemuCaps)))
|
||||
goto cleanup;
|
||||
virCommandAddArgList(cmd, "-device", nic, NULL);
|
||||
} else {
|
||||
diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h
|
||||
index 7da92c8c9..09cb00ee9 100644
|
||||
--- a/src/qemu/qemu_command.h
|
||||
+++ b/src/qemu/qemu_command.h
|
||||
@@ -101,8 +101,7 @@ char *qemuBuildNicDevStr(virDomainDefPtr def,
|
||||
int vlan,
|
||||
unsigned int bootindex,
|
||||
size_t vhostfdSize,
|
||||
- virQEMUCapsPtr qemuCaps,
|
||||
- unsigned int mtu);
|
||||
+ virQEMUCapsPtr qemuCaps);
|
||||
|
||||
char *qemuDeviceDriveHostAlias(virDomainDiskDefPtr disk);
|
||||
|
||||
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
|
||||
index f133d04a8..2a4159560 100644
|
||||
--- a/src/qemu/qemu_hotplug.c
|
||||
+++ b/src/qemu/qemu_hotplug.c
|
||||
@@ -968,7 +968,6 @@ qemuDomainAttachNetDevice(virQEMUDriverPtr driver,
|
||||
bool charDevPlugged = false;
|
||||
bool netdevPlugged = false;
|
||||
bool hostPlugged = false;
|
||||
- unsigned int mtu = net->mtu;
|
||||
|
||||
/* preallocate new slot for device */
|
||||
if (VIR_REALLOC_N(vm->def->nets, vm->def->nnets + 1) < 0)
|
||||
@@ -1025,7 +1024,7 @@ qemuDomainAttachNetDevice(virQEMUDriverPtr driver,
|
||||
goto cleanup;
|
||||
memset(vhostfd, -1, sizeof(*vhostfd) * vhostfdSize);
|
||||
if (qemuInterfaceBridgeConnect(vm->def, driver, net,
|
||||
- tapfd, &tapfdSize, &mtu) < 0)
|
||||
+ tapfd, &tapfdSize) < 0)
|
||||
goto cleanup;
|
||||
iface_connected = true;
|
||||
if (qemuInterfaceOpenVhostNet(vm->def, net, priv->qemuCaps,
|
||||
@@ -1239,7 +1238,7 @@ qemuDomainAttachNetDevice(virQEMUDriverPtr driver,
|
||||
VIR_FORCE_CLOSE(vhostfd[i]);
|
||||
|
||||
if (!(nicstr = qemuBuildNicDevStr(vm->def, net, vlan, 0,
|
||||
- queueSize, priv->qemuCaps, mtu)))
|
||||
+ queueSize, priv->qemuCaps)))
|
||||
goto try_remove;
|
||||
|
||||
qemuDomainObjEnterMonitor(driver, vm);
|
||||
diff --git a/src/qemu/qemu_interface.c b/src/qemu/qemu_interface.c
|
||||
index c5dca60f1..ce448d243 100644
|
||||
--- a/src/qemu/qemu_interface.c
|
||||
+++ b/src/qemu/qemu_interface.c
|
||||
@@ -503,8 +503,7 @@ qemuInterfaceBridgeConnect(virDomainDefPtr def,
|
||||
virQEMUDriverPtr driver,
|
||||
virDomainNetDefPtr net,
|
||||
int *tapfd,
|
||||
- size_t *tapfdSize,
|
||||
- unsigned int *mtu)
|
||||
+ size_t *tapfdSize)
|
||||
{
|
||||
const char *brname;
|
||||
int ret = -1;
|
||||
@@ -545,7 +544,7 @@ qemuInterfaceBridgeConnect(virDomainDefPtr def,
|
||||
def->uuid, tunpath, tapfd, *tapfdSize,
|
||||
virDomainNetGetActualVirtPortProfile(net),
|
||||
virDomainNetGetActualVlan(net),
|
||||
- net->mtu, mtu,
|
||||
+ 0, NULL,
|
||||
tap_create_flags) < 0) {
|
||||
virDomainAuditNetDevice(def, net, tunpath, false);
|
||||
goto cleanup;
|
||||
diff --git a/src/qemu/qemu_interface.h b/src/qemu/qemu_interface.h
|
||||
index ba74ac2cf..a7faa0b3d 100644
|
||||
--- a/src/qemu/qemu_interface.h
|
||||
+++ b/src/qemu/qemu_interface.h
|
||||
@@ -51,8 +51,7 @@ int qemuInterfaceBridgeConnect(virDomainDefPtr def,
|
||||
virQEMUDriverPtr driver,
|
||||
virDomainNetDefPtr net,
|
||||
int *tapfd,
|
||||
- size_t *tapfdSize,
|
||||
- unsigned int *mtu)
|
||||
+ size_t *tapfdSize)
|
||||
ATTRIBUTE_NONNULL(2);
|
||||
|
||||
int qemuInterfaceOpenVhostNet(virDomainDefPtr def,
|
||||
@@ -0,0 +1,145 @@
|
||||
From: Jiri Denemark <jdenemar@redhat.com>
|
||||
Date: Wed, 29 Mar 2017 14:45:44 +0200
|
||||
Subject: [PATCH] cpu: Introduce virCPUCopyMigratable
|
||||
|
||||
This new internal API makes a copy of virCPUDef while removing all
|
||||
features which would block migration. It uses cpu_map.xml as a database
|
||||
of such features, which should only be used as a fallback when we cannot
|
||||
get the data from a hypervisor. The main goal of this API is to decouple
|
||||
this filtering from virCPUUpdate so that the hypervisor driver can
|
||||
filter the features according to the hypervisor.
|
||||
|
||||
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
|
||||
(cherry picked from commit 05e91c79f19e0be96526098d58a3498dac3f8529)
|
||||
---
|
||||
src/cpu/cpu.c | 31 +++++++++++++++++++++++++++++++
|
||||
src/cpu/cpu.h | 8 ++++++++
|
||||
src/cpu/cpu_x86.c | 25 +++++++++++++++++++++++++
|
||||
src/libvirt_private.syms | 1 +
|
||||
4 files changed, 65 insertions(+)
|
||||
|
||||
diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c
|
||||
index 93647a2ed..8a407ac18 100644
|
||||
--- a/src/cpu/cpu.c
|
||||
+++ b/src/cpu/cpu.c
|
||||
@@ -1130,3 +1130,34 @@ virCPUExpandFeatures(virArch arch,
|
||||
VIR_DEBUG("nfeatures=%zu", cpu->nfeatures);
|
||||
return 0;
|
||||
}
|
||||
+
|
||||
+
|
||||
+/**
|
||||
+ * virCPUCopyMigratable:
|
||||
+ *
|
||||
+ * @arch: CPU architecture
|
||||
+ * @cpu: CPU definition to be copied
|
||||
+ *
|
||||
+ * Makes a copy of @cpu with all features which would block migration removed.
|
||||
+ * If this doesn't make sense for a given architecture, the function returns a
|
||||
+ * plain copy of @cpu (i.e., a copy with no features removed).
|
||||
+ *
|
||||
+ * Returns the copy of the CPU or NULL on error.
|
||||
+ */
|
||||
+virCPUDefPtr
|
||||
+virCPUCopyMigratable(virArch arch,
|
||||
+ virCPUDefPtr cpu)
|
||||
+{
|
||||
+ struct cpuArchDriver *driver;
|
||||
+
|
||||
+ VIR_DEBUG("arch=%s, cpu=%p, model=%s",
|
||||
+ virArchToString(arch), cpu, NULLSTR(cpu->model));
|
||||
+
|
||||
+ if (!(driver = cpuGetSubDriver(arch)))
|
||||
+ return NULL;
|
||||
+
|
||||
+ if (driver->copyMigratable)
|
||||
+ return driver->copyMigratable(cpu);
|
||||
+ else
|
||||
+ return virCPUDefCopy(cpu);
|
||||
+}
|
||||
diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h
|
||||
index 8c238ad55..352445c40 100644
|
||||
--- a/src/cpu/cpu.h
|
||||
+++ b/src/cpu/cpu.h
|
||||
@@ -118,6 +118,9 @@ typedef int
|
||||
typedef int
|
||||
(*virCPUArchExpandFeatures)(virCPUDefPtr cpu);
|
||||
|
||||
+typedef virCPUDefPtr
|
||||
+(*virCPUArchCopyMigratable)(virCPUDefPtr cpu);
|
||||
+
|
||||
struct cpuArchDriver {
|
||||
const char *name;
|
||||
const virArch *arch;
|
||||
@@ -138,6 +141,7 @@ struct cpuArchDriver {
|
||||
virCPUArchTranslate translate;
|
||||
virCPUArchConvertLegacy convertLegacy;
|
||||
virCPUArchExpandFeatures expandFeatures;
|
||||
+ virCPUArchCopyMigratable copyMigratable;
|
||||
};
|
||||
|
||||
|
||||
@@ -254,6 +258,10 @@ int
|
||||
virCPUExpandFeatures(virArch arch,
|
||||
virCPUDefPtr cpu);
|
||||
|
||||
+virCPUDefPtr
|
||||
+virCPUCopyMigratable(virArch arch,
|
||||
+ virCPUDefPtr cpu);
|
||||
+
|
||||
/* virCPUDataFormat and virCPUDataParse are implemented for unit tests only and
|
||||
* have no real-life usage
|
||||
*/
|
||||
diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c
|
||||
index 48648a7f4..a771b251e 100644
|
||||
--- a/src/cpu/cpu_x86.c
|
||||
+++ b/src/cpu/cpu_x86.c
|
||||
@@ -2903,6 +2903,30 @@ virCPUx86ExpandFeatures(virCPUDefPtr cpu)
|
||||
}
|
||||
|
||||
|
||||
+static virCPUDefPtr
|
||||
+virCPUx86CopyMigratable(virCPUDefPtr cpu)
|
||||
+{
|
||||
+ virCPUDefPtr copy;
|
||||
+ virCPUx86MapPtr map;
|
||||
+
|
||||
+ if (!(map = virCPUx86GetMap()))
|
||||
+ return NULL;
|
||||
+
|
||||
+ if (!(copy = virCPUDefCopyWithoutModel(cpu)))
|
||||
+ return NULL;
|
||||
+
|
||||
+ if (virCPUDefCopyModelFilter(copy, cpu, false,
|
||||
+ x86FeatureIsMigratable, map) < 0)
|
||||
+ goto error;
|
||||
+
|
||||
+ return copy;
|
||||
+
|
||||
+ error:
|
||||
+ virCPUDefFree(copy);
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+
|
||||
int
|
||||
virCPUx86DataAddCPUID(virCPUDataPtr cpuData,
|
||||
const virCPUx86CPUID *cpuid)
|
||||
@@ -2978,4 +3002,5 @@ struct cpuArchDriver cpuDriverX86 = {
|
||||
.getModels = virCPUx86GetModels,
|
||||
.translate = virCPUx86Translate,
|
||||
.expandFeatures = virCPUx86ExpandFeatures,
|
||||
+ .copyMigratable = virCPUx86CopyMigratable,
|
||||
};
|
||||
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
|
||||
index b551cb86a..dc6db3b28 100644
|
||||
--- a/src/libvirt_private.syms
|
||||
+++ b/src/libvirt_private.syms
|
||||
@@ -1016,6 +1016,7 @@ virCPUCheckFeature;
|
||||
virCPUCompare;
|
||||
virCPUCompareXML;
|
||||
virCPUConvertLegacy;
|
||||
+virCPUCopyMigratable;
|
||||
virCPUDataCheckFeature;
|
||||
virCPUDataFormat;
|
||||
virCPUDataFree;
|
||||
@@ -0,0 +1,78 @@
|
||||
From: Jiri Denemark <jdenemar@redhat.com>
|
||||
Date: Thu, 30 Mar 2017 13:50:44 +0200
|
||||
Subject: [PATCH] qemu: Move common code in virQEMUCapsInitCPUModel one layer
|
||||
up
|
||||
|
||||
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
|
||||
(cherry picked from commit d84b93fad51b190238e18b1daac82ea6e28869e9)
|
||||
---
|
||||
src/qemu/qemu_capabilities.c | 25 ++++++++++---------------
|
||||
1 file changed, 10 insertions(+), 15 deletions(-)
|
||||
|
||||
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
|
||||
index b1245ad5d..1a15750a3 100644
|
||||
--- a/src/qemu/qemu_capabilities.c
|
||||
+++ b/src/qemu/qemu_capabilities.c
|
||||
@@ -3111,17 +3111,11 @@ virQEMUCapsCPUFilterFeatures(const char *name,
|
||||
*/
|
||||
static int
|
||||
virQEMUCapsInitCPUModelS390(virQEMUCapsPtr qemuCaps,
|
||||
- virDomainVirtType type,
|
||||
+ qemuMonitorCPUModelInfoPtr modelInfo,
|
||||
virCPUDefPtr cpu)
|
||||
{
|
||||
- qemuMonitorCPUModelInfoPtr modelInfo;
|
||||
size_t i;
|
||||
|
||||
- if (type == VIR_DOMAIN_VIRT_KVM)
|
||||
- modelInfo = qemuCaps->kvmCPUModelInfo;
|
||||
- else
|
||||
- modelInfo = qemuCaps->tcgCPUModelInfo;
|
||||
-
|
||||
if (!modelInfo) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("missing host CPU model info from QEMU capabilities "
|
||||
@@ -3163,9 +3157,9 @@ virQEMUCapsInitCPUModelS390(virQEMUCapsPtr qemuCaps,
|
||||
static int
|
||||
virQEMUCapsInitCPUModelX86(virQEMUCapsPtr qemuCaps,
|
||||
virDomainVirtType type,
|
||||
+ qemuMonitorCPUModelInfoPtr model,
|
||||
virCPUDefPtr cpu)
|
||||
{
|
||||
- qemuMonitorCPUModelInfoPtr model;
|
||||
virCPUDataPtr data = NULL;
|
||||
unsigned long long sigFamily = 0;
|
||||
unsigned long long sigModel = 0;
|
||||
@@ -3174,11 +3168,6 @@ virQEMUCapsInitCPUModelX86(virQEMUCapsPtr qemuCaps,
|
||||
int ret = -1;
|
||||
size_t i;
|
||||
|
||||
- if (type == VIR_DOMAIN_VIRT_KVM)
|
||||
- model = qemuCaps->kvmCPUModelInfo;
|
||||
- else
|
||||
- model = qemuCaps->tcgCPUModelInfo;
|
||||
-
|
||||
if (!model)
|
||||
return 1;
|
||||
|
||||
@@ -3239,12 +3228,18 @@ virQEMUCapsInitCPUModel(virQEMUCapsPtr qemuCaps,
|
||||
virDomainVirtType type,
|
||||
virCPUDefPtr cpu)
|
||||
{
|
||||
+ qemuMonitorCPUModelInfoPtr model;
|
||||
int ret = 1;
|
||||
|
||||
+ if (type == VIR_DOMAIN_VIRT_KVM)
|
||||
+ model = qemuCaps->kvmCPUModelInfo;
|
||||
+ else
|
||||
+ model = qemuCaps->tcgCPUModelInfo;
|
||||
+
|
||||
if (ARCH_IS_S390(qemuCaps->arch))
|
||||
- ret = virQEMUCapsInitCPUModelS390(qemuCaps, type, cpu);
|
||||
+ ret = virQEMUCapsInitCPUModelS390(qemuCaps, model, cpu);
|
||||
else if (ARCH_IS_X86(qemuCaps->arch))
|
||||
- ret = virQEMUCapsInitCPUModelX86(qemuCaps, type, cpu);
|
||||
+ ret = virQEMUCapsInitCPUModelX86(qemuCaps, type, model, cpu);
|
||||
|
||||
if (ret == 0)
|
||||
cpu->fallback = VIR_CPU_FALLBACK_FORBID;
|
||||
@@ -0,0 +1,139 @@
|
||||
From: Jiri Denemark <jdenemar@redhat.com>
|
||||
Date: Wed, 29 Mar 2017 13:33:50 +0200
|
||||
Subject: [PATCH] qemu: Add migratable parameter to virQEMUCapsInitCPUModel
|
||||
|
||||
The caller can ask for a migratable CPU model by passing true for the
|
||||
new parameter.
|
||||
|
||||
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
|
||||
(cherry picked from commit 00e0cbcb567a57c7b5a145d7fd3fb662779f6bec)
|
||||
---
|
||||
src/qemu/qemu_capabilities.c | 36 +++++++++++++++++++++++++-----------
|
||||
src/qemu/qemu_capspriv.h | 3 ++-
|
||||
tests/cputest.c | 2 +-
|
||||
3 files changed, 28 insertions(+), 13 deletions(-)
|
||||
|
||||
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
|
||||
index 1a15750a3..b8e4e47b6 100644
|
||||
--- a/src/qemu/qemu_capabilities.c
|
||||
+++ b/src/qemu/qemu_capabilities.c
|
||||
@@ -3112,7 +3112,8 @@ virQEMUCapsCPUFilterFeatures(const char *name,
|
||||
static int
|
||||
virQEMUCapsInitCPUModelS390(virQEMUCapsPtr qemuCaps,
|
||||
qemuMonitorCPUModelInfoPtr modelInfo,
|
||||
- virCPUDefPtr cpu)
|
||||
+ virCPUDefPtr cpu,
|
||||
+ bool migratable)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
@@ -3140,8 +3141,12 @@ virQEMUCapsInitCPUModelS390(virQEMUCapsPtr qemuCaps,
|
||||
|
||||
if (VIR_STRDUP(feature->name, prop->name) < 0)
|
||||
return -1;
|
||||
- feature->policy = prop->value.boolean ? VIR_CPU_FEATURE_REQUIRE
|
||||
- : VIR_CPU_FEATURE_DISABLE;
|
||||
+
|
||||
+ if (!prop->value.boolean ||
|
||||
+ (migratable && prop->migratable == VIR_TRISTATE_BOOL_NO))
|
||||
+ feature->policy = VIR_CPU_FEATURE_DISABLE;
|
||||
+ else
|
||||
+ feature->policy = VIR_CPU_FEATURE_REQUIRE;
|
||||
cpu->nfeatures++;
|
||||
}
|
||||
|
||||
@@ -3158,7 +3163,8 @@ static int
|
||||
virQEMUCapsInitCPUModelX86(virQEMUCapsPtr qemuCaps,
|
||||
virDomainVirtType type,
|
||||
qemuMonitorCPUModelInfoPtr model,
|
||||
- virCPUDefPtr cpu)
|
||||
+ virCPUDefPtr cpu,
|
||||
+ bool migratable)
|
||||
{
|
||||
virCPUDataPtr data = NULL;
|
||||
unsigned long long sigFamily = 0;
|
||||
@@ -3179,9 +3185,13 @@ virQEMUCapsInitCPUModelX86(virQEMUCapsPtr qemuCaps,
|
||||
|
||||
switch (prop->type) {
|
||||
case QEMU_MONITOR_CPU_PROPERTY_BOOLEAN:
|
||||
- if (prop->value.boolean &&
|
||||
- virCPUx86DataAddFeature(data, prop->name) < 0)
|
||||
+ if (!prop->value.boolean ||
|
||||
+ (migratable && prop->migratable == VIR_TRISTATE_BOOL_NO))
|
||||
+ continue;
|
||||
+
|
||||
+ if (virCPUx86DataAddFeature(data, prop->name) < 0)
|
||||
goto cleanup;
|
||||
+
|
||||
break;
|
||||
|
||||
case QEMU_MONITOR_CPU_PROPERTY_STRING:
|
||||
@@ -3220,13 +3230,14 @@ virQEMUCapsInitCPUModelX86(virQEMUCapsPtr qemuCaps,
|
||||
|
||||
/**
|
||||
* Returns 0 when host CPU model provided by QEMU was filled in qemuCaps,
|
||||
- * 1 when the caller should fall back to using virCapsPtr->host.cpu,
|
||||
+ * 1 when the caller should fall back to other methods
|
||||
* -1 on error.
|
||||
*/
|
||||
int
|
||||
virQEMUCapsInitCPUModel(virQEMUCapsPtr qemuCaps,
|
||||
virDomainVirtType type,
|
||||
- virCPUDefPtr cpu)
|
||||
+ virCPUDefPtr cpu,
|
||||
+ bool migratable)
|
||||
{
|
||||
qemuMonitorCPUModelInfoPtr model;
|
||||
int ret = 1;
|
||||
@@ -3236,10 +3247,13 @@ virQEMUCapsInitCPUModel(virQEMUCapsPtr qemuCaps,
|
||||
else
|
||||
model = qemuCaps->tcgCPUModelInfo;
|
||||
|
||||
+ if (migratable && model && !model->migratability)
|
||||
+ return 1;
|
||||
+
|
||||
if (ARCH_IS_S390(qemuCaps->arch))
|
||||
- ret = virQEMUCapsInitCPUModelS390(qemuCaps, model, cpu);
|
||||
+ ret = virQEMUCapsInitCPUModelS390(qemuCaps, model, cpu, migratable);
|
||||
else if (ARCH_IS_X86(qemuCaps->arch))
|
||||
- ret = virQEMUCapsInitCPUModelX86(qemuCaps, type, model, cpu);
|
||||
+ ret = virQEMUCapsInitCPUModelX86(qemuCaps, type, model, cpu, migratable);
|
||||
|
||||
if (ret == 0)
|
||||
cpu->fallback = VIR_CPU_FALLBACK_FORBID;
|
||||
@@ -3268,7 +3282,7 @@ virQEMUCapsInitHostCPUModel(virQEMUCapsPtr qemuCaps,
|
||||
cpu->match = VIR_CPU_MATCH_EXACT;
|
||||
cpu->fallback = VIR_CPU_FALLBACK_ALLOW;
|
||||
|
||||
- if ((rc = virQEMUCapsInitCPUModel(qemuCaps, type, cpu)) < 0) {
|
||||
+ if ((rc = virQEMUCapsInitCPUModel(qemuCaps, type, cpu, false)) < 0) {
|
||||
goto error;
|
||||
} else if (rc == 1) {
|
||||
VIR_DEBUG("No host CPU model info from QEMU; probing host CPU directly");
|
||||
diff --git a/src/qemu/qemu_capspriv.h b/src/qemu/qemu_capspriv.h
|
||||
index 61ccd4517..1baaaf334 100644
|
||||
--- a/src/qemu/qemu_capspriv.h
|
||||
+++ b/src/qemu/qemu_capspriv.h
|
||||
@@ -81,7 +81,8 @@ virQEMUCapsInitHostCPUModel(virQEMUCapsPtr qemuCaps,
|
||||
int
|
||||
virQEMUCapsInitCPUModel(virQEMUCapsPtr qemuCaps,
|
||||
virDomainVirtType type,
|
||||
- virCPUDefPtr cpu);
|
||||
+ virCPUDefPtr cpu,
|
||||
+ bool migratable);
|
||||
|
||||
void
|
||||
virQEMUCapsSetCPUModelInfo(virQEMUCapsPtr qemuCaps,
|
||||
diff --git a/tests/cputest.c b/tests/cputest.c
|
||||
index 3d3e43f16..8c07cf4f6 100644
|
||||
--- a/tests/cputest.c
|
||||
+++ b/tests/cputest.c
|
||||
@@ -709,7 +709,7 @@ cpuTestJSONCPUID(const void *arg)
|
||||
cpu->match = VIR_CPU_MATCH_EXACT;
|
||||
cpu->fallback = VIR_CPU_FALLBACK_FORBID;
|
||||
|
||||
- if (virQEMUCapsInitCPUModel(qemuCaps, VIR_DOMAIN_VIRT_KVM, cpu) != 0)
|
||||
+ if (virQEMUCapsInitCPUModel(qemuCaps, VIR_DOMAIN_VIRT_KVM, cpu, false) != 0)
|
||||
goto cleanup;
|
||||
|
||||
ret = cpuTestCompareXML(data->arch, cpu, result, false);
|
||||
@@ -0,0 +1,47 @@
|
||||
From: Jiri Denemark <jdenemar@redhat.com>
|
||||
Date: Fri, 7 Apr 2017 17:03:38 +0200
|
||||
Subject: [PATCH] qemu: Introduce virQEMUCapsSetHostModel
|
||||
|
||||
A simple helper as a complement to virQEMUCapsGetHostModel.
|
||||
|
||||
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
|
||||
(cherry picked from commit bffc3b9fe501ff122ad81ddf42ecdb69f70ff70a)
|
||||
---
|
||||
src/qemu/qemu_capabilities.c | 17 +++++++++++++----
|
||||
1 file changed, 13 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
|
||||
index b8e4e47b6..f6020b86d 100644
|
||||
--- a/src/qemu/qemu_capabilities.c
|
||||
+++ b/src/qemu/qemu_capabilities.c
|
||||
@@ -2419,6 +2419,18 @@ virQEMUCapsGetHostModel(virQEMUCapsPtr qemuCaps,
|
||||
}
|
||||
|
||||
|
||||
+static void
|
||||
+virQEMUCapsSetHostModel(virQEMUCapsPtr qemuCaps,
|
||||
+ virDomainVirtType type,
|
||||
+ virCPUDefPtr cpu)
|
||||
+{
|
||||
+ if (type == VIR_DOMAIN_VIRT_KVM)
|
||||
+ qemuCaps->kvmCPUModel = cpu;
|
||||
+ else
|
||||
+ qemuCaps->tcgCPUModel = cpu;
|
||||
+}
|
||||
+
|
||||
+
|
||||
bool
|
||||
virQEMUCapsIsCPUModeSupported(virQEMUCapsPtr qemuCaps,
|
||||
virCapsPtr caps,
|
||||
@@ -3295,10 +3307,7 @@ virQEMUCapsInitHostCPUModel(virQEMUCapsPtr qemuCaps,
|
||||
goto error;
|
||||
}
|
||||
|
||||
- if (type == VIR_DOMAIN_VIRT_KVM)
|
||||
- qemuCaps->kvmCPUModel = cpu;
|
||||
- else
|
||||
- qemuCaps->tcgCPUModel = cpu;
|
||||
+ virQEMUCapsSetHostModel(qemuCaps, type, cpu);
|
||||
|
||||
cleanup:
|
||||
virCPUDefFree(hostCPU);
|
||||
@@ -0,0 +1,70 @@
|
||||
From: Jiri Denemark <jdenemar@redhat.com>
|
||||
Date: Fri, 7 Apr 2017 17:40:31 +0200
|
||||
Subject: [PATCH] qemu: Move qemuCaps CPU data copying into a separate function
|
||||
|
||||
This introduces virQEMUCapsHostCPUDataCopy which will later be
|
||||
refactored a bit and called twice from virQEMUCapsNewCopy.
|
||||
|
||||
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
|
||||
(cherry picked from commit 8be4346ca5ae4b568b3e8ce3de9cf46f2e94b416)
|
||||
---
|
||||
src/qemu/qemu_capabilities.c | 39 +++++++++++++++++++++++++--------------
|
||||
1 file changed, 25 insertions(+), 14 deletions(-)
|
||||
|
||||
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
|
||||
index f6020b86d..d17e0e8b8 100644
|
||||
--- a/src/qemu/qemu_capabilities.c
|
||||
+++ b/src/qemu/qemu_capabilities.c
|
||||
@@ -2082,6 +2082,30 @@ virQEMUCapsNew(void)
|
||||
}
|
||||
|
||||
|
||||
+static int
|
||||
+virQEMUCapsHostCPUDataCopy(virQEMUCapsPtr dst,
|
||||
+ virQEMUCapsPtr src)
|
||||
+{
|
||||
+ if (src->kvmCPUModel &&
|
||||
+ !(dst->kvmCPUModel = virCPUDefCopy(src->kvmCPUModel)))
|
||||
+ return -1;
|
||||
+
|
||||
+ if (src->tcgCPUModel &&
|
||||
+ !(dst->tcgCPUModel = virCPUDefCopy(src->tcgCPUModel)))
|
||||
+ return -1;
|
||||
+
|
||||
+ if (src->kvmCPUModelInfo &&
|
||||
+ !(dst->kvmCPUModelInfo = qemuMonitorCPUModelInfoCopy(src->kvmCPUModelInfo)))
|
||||
+ return -1;
|
||||
+
|
||||
+ if (src->tcgCPUModelInfo &&
|
||||
+ !(dst->tcgCPUModelInfo = qemuMonitorCPUModelInfoCopy(src->tcgCPUModelInfo)))
|
||||
+ return -1;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+
|
||||
virQEMUCapsPtr virQEMUCapsNewCopy(virQEMUCapsPtr qemuCaps)
|
||||
{
|
||||
virQEMUCapsPtr ret = virQEMUCapsNew();
|
||||
@@ -2119,20 +2143,7 @@ virQEMUCapsPtr virQEMUCapsNewCopy(virQEMUCapsPtr qemuCaps)
|
||||
goto error;
|
||||
}
|
||||
|
||||
- if (qemuCaps->kvmCPUModel &&
|
||||
- !(ret->kvmCPUModel = virCPUDefCopy(qemuCaps->kvmCPUModel)))
|
||||
- goto error;
|
||||
-
|
||||
- if (qemuCaps->tcgCPUModel &&
|
||||
- !(ret->tcgCPUModel = virCPUDefCopy(qemuCaps->tcgCPUModel)))
|
||||
- goto error;
|
||||
-
|
||||
- if (qemuCaps->kvmCPUModelInfo &&
|
||||
- !(ret->kvmCPUModelInfo = qemuMonitorCPUModelInfoCopy(qemuCaps->kvmCPUModelInfo)))
|
||||
- goto error;
|
||||
-
|
||||
- if (qemuCaps->tcgCPUModelInfo &&
|
||||
- !(ret->tcgCPUModelInfo = qemuMonitorCPUModelInfoCopy(qemuCaps->tcgCPUModelInfo)))
|
||||
+ if (virQEMUCapsHostCPUDataCopy(ret, qemuCaps) < 0)
|
||||
goto error;
|
||||
|
||||
if (VIR_ALLOC_N(ret->machineTypes, qemuCaps->nmachineTypes) < 0)
|
||||
@@ -0,0 +1,67 @@
|
||||
From: Jiri Denemark <jdenemar@redhat.com>
|
||||
Date: Fri, 7 Apr 2017 17:43:59 +0200
|
||||
Subject: [PATCH] qemu: Introduce virQEMUCapsHostCPUDataClear
|
||||
|
||||
To keep freeing of host CPU data in one place.
|
||||
|
||||
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
|
||||
(cherry picked from commit b0605e848724c5dc478382398b734398abff674c)
|
||||
---
|
||||
src/qemu/qemu_capabilities.c | 30 +++++++++++++++++-------------
|
||||
1 file changed, 17 insertions(+), 13 deletions(-)
|
||||
|
||||
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
|
||||
index d17e0e8b8..2da53a60b 100644
|
||||
--- a/src/qemu/qemu_capabilities.c
|
||||
+++ b/src/qemu/qemu_capabilities.c
|
||||
@@ -2106,6 +2106,21 @@ virQEMUCapsHostCPUDataCopy(virQEMUCapsPtr dst,
|
||||
}
|
||||
|
||||
|
||||
+static void
|
||||
+virQEMUCapsHostCPUDataClear(virQEMUCapsPtr qemuCaps)
|
||||
+{
|
||||
+ qemuMonitorCPUModelInfoFree(qemuCaps->kvmCPUModelInfo);
|
||||
+ qemuMonitorCPUModelInfoFree(qemuCaps->tcgCPUModelInfo);
|
||||
+ qemuCaps->kvmCPUModelInfo = NULL;
|
||||
+ qemuCaps->tcgCPUModelInfo = NULL;
|
||||
+
|
||||
+ virCPUDefFree(qemuCaps->kvmCPUModel);
|
||||
+ virCPUDefFree(qemuCaps->tcgCPUModel);
|
||||
+ qemuCaps->kvmCPUModel = NULL;
|
||||
+ qemuCaps->tcgCPUModel = NULL;
|
||||
+}
|
||||
+
|
||||
+
|
||||
virQEMUCapsPtr virQEMUCapsNewCopy(virQEMUCapsPtr qemuCaps)
|
||||
{
|
||||
virQEMUCapsPtr ret = virQEMUCapsNew();
|
||||
@@ -2192,10 +2207,7 @@ void virQEMUCapsDispose(void *obj)
|
||||
|
||||
VIR_FREE(qemuCaps->gicCapabilities);
|
||||
|
||||
- qemuMonitorCPUModelInfoFree(qemuCaps->kvmCPUModelInfo);
|
||||
- qemuMonitorCPUModelInfoFree(qemuCaps->tcgCPUModelInfo);
|
||||
- virCPUDefFree(qemuCaps->kvmCPUModel);
|
||||
- virCPUDefFree(qemuCaps->tcgCPUModel);
|
||||
+ virQEMUCapsHostCPUDataClear(qemuCaps);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -4068,15 +4080,7 @@ virQEMUCapsReset(virQEMUCapsPtr qemuCaps)
|
||||
VIR_FREE(qemuCaps->gicCapabilities);
|
||||
qemuCaps->ngicCapabilities = 0;
|
||||
|
||||
- qemuMonitorCPUModelInfoFree(qemuCaps->kvmCPUModelInfo);
|
||||
- qemuMonitorCPUModelInfoFree(qemuCaps->tcgCPUModelInfo);
|
||||
- qemuCaps->kvmCPUModelInfo = NULL;
|
||||
- qemuCaps->tcgCPUModelInfo = NULL;
|
||||
-
|
||||
- virCPUDefFree(qemuCaps->kvmCPUModel);
|
||||
- virCPUDefFree(qemuCaps->tcgCPUModel);
|
||||
- qemuCaps->kvmCPUModel = NULL;
|
||||
- qemuCaps->tcgCPUModel = NULL;
|
||||
+ virQEMUCapsHostCPUDataClear(qemuCaps);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,342 @@
|
||||
From: Jiri Denemark <jdenemar@redhat.com>
|
||||
Date: Fri, 7 Apr 2017 18:15:26 +0200
|
||||
Subject: [PATCH] qemu: Move qemuCaps host CPU data in a struct
|
||||
|
||||
We need to store several CPU related data structure for both KVM and
|
||||
TCG. So instead of keeping two different copies of everything let's
|
||||
make a virQEMUCapsHostCPUData struct and use it twice.
|
||||
|
||||
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
|
||||
(cherry picked from commit b0a84ffb7f38f990120c231cfb74956a0ed10d95)
|
||||
---
|
||||
src/qemu/qemu_capabilities.c | 168 +++++++++++++++++++++----------------------
|
||||
1 file changed, 82 insertions(+), 86 deletions(-)
|
||||
|
||||
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
|
||||
index 2da53a60b..bbb234538 100644
|
||||
--- a/src/qemu/qemu_capabilities.c
|
||||
+++ b/src/qemu/qemu_capabilities.c
|
||||
@@ -373,6 +373,19 @@ struct virQEMUCapsMachineType {
|
||||
unsigned int maxCpus;
|
||||
bool hotplugCpus;
|
||||
};
|
||||
+
|
||||
+typedef struct _virQEMUCapsHostCPUData virQEMUCapsHostCPUData;
|
||||
+typedef virQEMUCapsHostCPUData *virQEMUCapsHostCPUDataPtr;
|
||||
+struct _virQEMUCapsHostCPUData {
|
||||
+ /* Only the "info" part is stored in the capabilities cache, the rest is
|
||||
+ * re-computed from other fields and external data sources everytime we
|
||||
+ * probe QEMU or load the cache.
|
||||
+ */
|
||||
+ qemuMonitorCPUModelInfoPtr info;
|
||||
+ /* Host CPU definition reported in domain capabilities. */
|
||||
+ virCPUDefPtr reported;
|
||||
+};
|
||||
+
|
||||
/*
|
||||
* Update the XML parser/formatter when adding more
|
||||
* information to this struct so that it gets cached
|
||||
@@ -407,15 +420,8 @@ struct _virQEMUCaps {
|
||||
size_t ngicCapabilities;
|
||||
virGICCapability *gicCapabilities;
|
||||
|
||||
- qemuMonitorCPUModelInfoPtr kvmCPUModelInfo;
|
||||
- qemuMonitorCPUModelInfoPtr tcgCPUModelInfo;
|
||||
-
|
||||
- /* Anything below is not stored in the cache since the values are
|
||||
- * re-computed from the other fields or external data sources every
|
||||
- * time we probe QEMU or load the results from the cache.
|
||||
- */
|
||||
- virCPUDefPtr kvmCPUModel;
|
||||
- virCPUDefPtr tcgCPUModel;
|
||||
+ virQEMUCapsHostCPUData kvmCPU;
|
||||
+ virQEMUCapsHostCPUData tcgCPU;
|
||||
};
|
||||
|
||||
struct virQEMUCapsSearchData {
|
||||
@@ -2083,23 +2089,15 @@ virQEMUCapsNew(void)
|
||||
|
||||
|
||||
static int
|
||||
-virQEMUCapsHostCPUDataCopy(virQEMUCapsPtr dst,
|
||||
- virQEMUCapsPtr src)
|
||||
+virQEMUCapsHostCPUDataCopy(virQEMUCapsHostCPUDataPtr dst,
|
||||
+ virQEMUCapsHostCPUDataPtr src)
|
||||
{
|
||||
- if (src->kvmCPUModel &&
|
||||
- !(dst->kvmCPUModel = virCPUDefCopy(src->kvmCPUModel)))
|
||||
+ if (src->info &&
|
||||
+ !(dst->info = qemuMonitorCPUModelInfoCopy(src->info)))
|
||||
return -1;
|
||||
|
||||
- if (src->tcgCPUModel &&
|
||||
- !(dst->tcgCPUModel = virCPUDefCopy(src->tcgCPUModel)))
|
||||
- return -1;
|
||||
-
|
||||
- if (src->kvmCPUModelInfo &&
|
||||
- !(dst->kvmCPUModelInfo = qemuMonitorCPUModelInfoCopy(src->kvmCPUModelInfo)))
|
||||
- return -1;
|
||||
-
|
||||
- if (src->tcgCPUModelInfo &&
|
||||
- !(dst->tcgCPUModelInfo = qemuMonitorCPUModelInfoCopy(src->tcgCPUModelInfo)))
|
||||
+ if (src->reported &&
|
||||
+ !(dst->reported = virCPUDefCopy(src->reported)))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
@@ -2107,17 +2105,12 @@ virQEMUCapsHostCPUDataCopy(virQEMUCapsPtr dst,
|
||||
|
||||
|
||||
static void
|
||||
-virQEMUCapsHostCPUDataClear(virQEMUCapsPtr qemuCaps)
|
||||
+virQEMUCapsHostCPUDataClear(virQEMUCapsHostCPUDataPtr cpuData)
|
||||
{
|
||||
- qemuMonitorCPUModelInfoFree(qemuCaps->kvmCPUModelInfo);
|
||||
- qemuMonitorCPUModelInfoFree(qemuCaps->tcgCPUModelInfo);
|
||||
- qemuCaps->kvmCPUModelInfo = NULL;
|
||||
- qemuCaps->tcgCPUModelInfo = NULL;
|
||||
-
|
||||
- virCPUDefFree(qemuCaps->kvmCPUModel);
|
||||
- virCPUDefFree(qemuCaps->tcgCPUModel);
|
||||
- qemuCaps->kvmCPUModel = NULL;
|
||||
- qemuCaps->tcgCPUModel = NULL;
|
||||
+ qemuMonitorCPUModelInfoFree(cpuData->info);
|
||||
+ virCPUDefFree(cpuData->reported);
|
||||
+
|
||||
+ memset(cpuData, 0, sizeof(*cpuData));
|
||||
}
|
||||
|
||||
|
||||
@@ -2158,7 +2151,8 @@ virQEMUCapsPtr virQEMUCapsNewCopy(virQEMUCapsPtr qemuCaps)
|
||||
goto error;
|
||||
}
|
||||
|
||||
- if (virQEMUCapsHostCPUDataCopy(ret, qemuCaps) < 0)
|
||||
+ if (virQEMUCapsHostCPUDataCopy(&ret->kvmCPU, &qemuCaps->kvmCPU) < 0 ||
|
||||
+ virQEMUCapsHostCPUDataCopy(&ret->tcgCPU, &qemuCaps->tcgCPU) < 0)
|
||||
goto error;
|
||||
|
||||
if (VIR_ALLOC_N(ret->machineTypes, qemuCaps->nmachineTypes) < 0)
|
||||
@@ -2207,7 +2201,8 @@ void virQEMUCapsDispose(void *obj)
|
||||
|
||||
VIR_FREE(qemuCaps->gicCapabilities);
|
||||
|
||||
- virQEMUCapsHostCPUDataClear(qemuCaps);
|
||||
+ virQEMUCapsHostCPUDataClear(&qemuCaps->kvmCPU);
|
||||
+ virQEMUCapsHostCPUDataClear(&qemuCaps->tcgCPU);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -2431,14 +2426,24 @@ virQEMUCapsGetCPUDefinitions(virQEMUCapsPtr qemuCaps,
|
||||
}
|
||||
|
||||
|
||||
+static virQEMUCapsHostCPUDataPtr
|
||||
+virQEMUCapsGetHostCPUData(virQEMUCapsPtr qemuCaps,
|
||||
+ virDomainVirtType type)
|
||||
+{
|
||||
+ if (type == VIR_DOMAIN_VIRT_KVM)
|
||||
+ return &qemuCaps->kvmCPU;
|
||||
+ else
|
||||
+ return &qemuCaps->tcgCPU;
|
||||
+}
|
||||
+
|
||||
+
|
||||
virCPUDefPtr
|
||||
virQEMUCapsGetHostModel(virQEMUCapsPtr qemuCaps,
|
||||
virDomainVirtType type)
|
||||
{
|
||||
- if (type == VIR_DOMAIN_VIRT_KVM)
|
||||
- return qemuCaps->kvmCPUModel;
|
||||
- else
|
||||
- return qemuCaps->tcgCPUModel;
|
||||
+ virQEMUCapsHostCPUDataPtr cpuData = virQEMUCapsGetHostCPUData(qemuCaps, type);
|
||||
+
|
||||
+ return cpuData->reported;
|
||||
}
|
||||
|
||||
|
||||
@@ -2447,10 +2452,9 @@ virQEMUCapsSetHostModel(virQEMUCapsPtr qemuCaps,
|
||||
virDomainVirtType type,
|
||||
virCPUDefPtr cpu)
|
||||
{
|
||||
- if (type == VIR_DOMAIN_VIRT_KVM)
|
||||
- qemuCaps->kvmCPUModel = cpu;
|
||||
- else
|
||||
- qemuCaps->tcgCPUModel = cpu;
|
||||
+ virQEMUCapsHostCPUDataPtr cpuData = virQEMUCapsGetHostCPUData(qemuCaps, type);
|
||||
+
|
||||
+ cpuData->reported = cpu;
|
||||
}
|
||||
|
||||
|
||||
@@ -2841,24 +2845,28 @@ virQEMUCapsProbeQMPHostCPU(virQEMUCapsPtr qemuCaps,
|
||||
qemuMonitorPtr mon,
|
||||
bool tcg)
|
||||
{
|
||||
- qemuMonitorCPUModelInfoPtr *modelInfo;
|
||||
+ qemuMonitorCPUModelInfoPtr modelInfo = NULL;
|
||||
qemuMonitorCPUModelInfoPtr nonMigratable = NULL;
|
||||
virHashTablePtr hash = NULL;
|
||||
const char *model;
|
||||
qemuMonitorCPUModelExpansionType type;
|
||||
+ virDomainVirtType virtType;
|
||||
+ virQEMUCapsHostCPUDataPtr cpuData;
|
||||
int ret = -1;
|
||||
|
||||
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_QUERY_CPU_MODEL_EXPANSION))
|
||||
return 0;
|
||||
|
||||
if (tcg || !virQEMUCapsGet(qemuCaps, QEMU_CAPS_KVM)) {
|
||||
- modelInfo = &qemuCaps->tcgCPUModelInfo;
|
||||
+ virtType = VIR_DOMAIN_VIRT_QEMU;
|
||||
model = "max";
|
||||
} else {
|
||||
- modelInfo = &qemuCaps->kvmCPUModelInfo;
|
||||
+ virtType = VIR_DOMAIN_VIRT_KVM;
|
||||
model = "host";
|
||||
}
|
||||
|
||||
+ cpuData = virQEMUCapsGetHostCPUData(qemuCaps, virtType);
|
||||
+
|
||||
/* Some x86_64 features defined in cpu_map.xml use spelling which differ
|
||||
* from the one preferred by QEMU. Static expansion would give us only the
|
||||
* preferred spelling, thus we need to do a full expansion on the result of
|
||||
@@ -2869,14 +2877,14 @@ virQEMUCapsProbeQMPHostCPU(virQEMUCapsPtr qemuCaps,
|
||||
else
|
||||
type = QEMU_MONITOR_CPU_MODEL_EXPANSION_STATIC;
|
||||
|
||||
- if (qemuMonitorGetCPUModelExpansion(mon, type, model, true, modelInfo) < 0)
|
||||
- return -1;
|
||||
+ if (qemuMonitorGetCPUModelExpansion(mon, type, model, true, &modelInfo) < 0)
|
||||
+ goto cleanup;
|
||||
|
||||
/* Try to check migratability of each feature. */
|
||||
- if (*modelInfo &&
|
||||
+ if (modelInfo &&
|
||||
qemuMonitorGetCPUModelExpansion(mon, type, model, false,
|
||||
&nonMigratable) < 0)
|
||||
- goto error;
|
||||
+ goto cleanup;
|
||||
|
||||
if (nonMigratable) {
|
||||
qemuMonitorCPUPropertyPtr prop;
|
||||
@@ -2884,12 +2892,12 @@ virQEMUCapsProbeQMPHostCPU(virQEMUCapsPtr qemuCaps,
|
||||
size_t i;
|
||||
|
||||
if (!(hash = virHashCreate(0, NULL)))
|
||||
- goto error;
|
||||
+ goto cleanup;
|
||||
|
||||
- for (i = 0; i < (*modelInfo)->nprops; i++) {
|
||||
- prop = (*modelInfo)->props + i;
|
||||
+ for (i = 0; i < modelInfo->nprops; i++) {
|
||||
+ prop = modelInfo->props + i;
|
||||
if (virHashAddEntry(hash, prop->name, prop) < 0)
|
||||
- goto error;
|
||||
+ goto cleanup;
|
||||
}
|
||||
|
||||
for (i = 0; i < nonMigratable->nprops; i++) {
|
||||
@@ -2907,21 +2915,18 @@ virQEMUCapsProbeQMPHostCPU(virQEMUCapsPtr qemuCaps,
|
||||
}
|
||||
}
|
||||
|
||||
- (*modelInfo)->migratability = true;
|
||||
+ modelInfo->migratability = true;
|
||||
}
|
||||
|
||||
+ VIR_STEAL_PTR(cpuData->info, modelInfo);
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
virHashFree(hash);
|
||||
qemuMonitorCPUModelInfoFree(nonMigratable);
|
||||
+ qemuMonitorCPUModelInfoFree(modelInfo);
|
||||
|
||||
return ret;
|
||||
-
|
||||
- error:
|
||||
- qemuMonitorCPUModelInfoFree(*modelInfo);
|
||||
- *modelInfo = NULL;
|
||||
- goto cleanup;
|
||||
}
|
||||
|
||||
struct tpmTypeToCaps {
|
||||
@@ -3274,21 +3279,19 @@ virQEMUCapsInitCPUModel(virQEMUCapsPtr qemuCaps,
|
||||
virCPUDefPtr cpu,
|
||||
bool migratable)
|
||||
{
|
||||
- qemuMonitorCPUModelInfoPtr model;
|
||||
+ virQEMUCapsHostCPUDataPtr cpuData = virQEMUCapsGetHostCPUData(qemuCaps, type);
|
||||
int ret = 1;
|
||||
|
||||
- if (type == VIR_DOMAIN_VIRT_KVM)
|
||||
- model = qemuCaps->kvmCPUModelInfo;
|
||||
- else
|
||||
- model = qemuCaps->tcgCPUModelInfo;
|
||||
-
|
||||
- if (migratable && model && !model->migratability)
|
||||
+ if (migratable && cpuData->info && !cpuData->info->migratability)
|
||||
return 1;
|
||||
|
||||
- if (ARCH_IS_S390(qemuCaps->arch))
|
||||
- ret = virQEMUCapsInitCPUModelS390(qemuCaps, model, cpu, migratable);
|
||||
- else if (ARCH_IS_X86(qemuCaps->arch))
|
||||
- ret = virQEMUCapsInitCPUModelX86(qemuCaps, type, model, cpu, migratable);
|
||||
+ if (ARCH_IS_S390(qemuCaps->arch)) {
|
||||
+ ret = virQEMUCapsInitCPUModelS390(qemuCaps, cpuData->info,
|
||||
+ cpu, migratable);
|
||||
+ } else if (ARCH_IS_X86(qemuCaps->arch)) {
|
||||
+ ret = virQEMUCapsInitCPUModelX86(qemuCaps, type, cpuData->info,
|
||||
+ cpu, migratable);
|
||||
+ }
|
||||
|
||||
if (ret == 0)
|
||||
cpu->fallback = VIR_CPU_FALLBACK_FORBID;
|
||||
@@ -3348,10 +3351,9 @@ virQEMUCapsSetCPUModelInfo(virQEMUCapsPtr qemuCaps,
|
||||
virDomainVirtType type,
|
||||
qemuMonitorCPUModelInfoPtr modelInfo)
|
||||
{
|
||||
- if (type == VIR_DOMAIN_VIRT_KVM)
|
||||
- qemuCaps->kvmCPUModelInfo = modelInfo;
|
||||
- else
|
||||
- qemuCaps->tcgCPUModelInfo = modelInfo;
|
||||
+ virQEMUCapsHostCPUDataPtr cpuData = virQEMUCapsGetHostCPUData(qemuCaps, type);
|
||||
+
|
||||
+ cpuData->info = modelInfo;
|
||||
}
|
||||
|
||||
|
||||
@@ -3810,18 +3812,11 @@ virQEMUCapsFormatHostCPUModelInfo(virQEMUCapsPtr qemuCaps,
|
||||
virBufferPtr buf,
|
||||
virDomainVirtType type)
|
||||
{
|
||||
- qemuMonitorCPUModelInfoPtr model;
|
||||
- const char *typeStr;
|
||||
+ virQEMUCapsHostCPUDataPtr cpuData = virQEMUCapsGetHostCPUData(qemuCaps, type);
|
||||
+ qemuMonitorCPUModelInfoPtr model = cpuData->info;
|
||||
+ const char *typeStr = type == VIR_DOMAIN_VIRT_KVM ? "kvm" : "tcg";
|
||||
size_t i;
|
||||
|
||||
- if (type == VIR_DOMAIN_VIRT_KVM) {
|
||||
- typeStr = "kvm";
|
||||
- model = qemuCaps->kvmCPUModelInfo;
|
||||
- } else {
|
||||
- typeStr = "tcg";
|
||||
- model = qemuCaps->tcgCPUModelInfo;
|
||||
- }
|
||||
-
|
||||
if (!model)
|
||||
return;
|
||||
|
||||
@@ -4080,7 +4075,8 @@ virQEMUCapsReset(virQEMUCapsPtr qemuCaps)
|
||||
VIR_FREE(qemuCaps->gicCapabilities);
|
||||
qemuCaps->ngicCapabilities = 0;
|
||||
|
||||
- virQEMUCapsHostCPUDataClear(qemuCaps);
|
||||
+ virQEMUCapsHostCPUDataClear(&qemuCaps->kvmCPU);
|
||||
+ virQEMUCapsHostCPUDataClear(&qemuCaps->tcgCPU);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
From: Jiri Denemark <jdenemar@redhat.com>
|
||||
Date: Tue, 11 Apr 2017 11:14:30 +0200
|
||||
Subject: [PATCH] qemu: Prepare qemuCaps for multiple host CPU defs
|
||||
|
||||
Soon we will need to store multiple host CPU definitions in
|
||||
virQEMUCapsHostCPUData and qemuCaps users will want to request the one
|
||||
they need. This patch introduces virQEMUCapsHostCPUType enum which will
|
||||
be used for specifying the requested CPU definition.
|
||||
|
||||
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
|
||||
(cherry picked from commit 1fe517c68df92eb7f379fa87cb0d29d566aad6f4)
|
||||
---
|
||||
src/qemu/qemu_capabilities.c | 16 ++++++++++++----
|
||||
src/qemu/qemu_capabilities.h | 10 +++++++++-
|
||||
src/qemu/qemu_command.c | 3 ++-
|
||||
src/qemu/qemu_process.c | 6 ++++--
|
||||
4 files changed, 27 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
|
||||
index bbb234538..a6324a398 100644
|
||||
--- a/src/qemu/qemu_capabilities.c
|
||||
+++ b/src/qemu/qemu_capabilities.c
|
||||
@@ -2439,11 +2439,17 @@ virQEMUCapsGetHostCPUData(virQEMUCapsPtr qemuCaps,
|
||||
|
||||
virCPUDefPtr
|
||||
virQEMUCapsGetHostModel(virQEMUCapsPtr qemuCaps,
|
||||
- virDomainVirtType type)
|
||||
+ virDomainVirtType type,
|
||||
+ virQEMUCapsHostCPUType cpuType)
|
||||
{
|
||||
virQEMUCapsHostCPUDataPtr cpuData = virQEMUCapsGetHostCPUData(qemuCaps, type);
|
||||
|
||||
- return cpuData->reported;
|
||||
+ switch (cpuType) {
|
||||
+ case VIR_QEMU_CAPS_HOST_CPU_REPORTED:
|
||||
+ return cpuData->reported;
|
||||
+ }
|
||||
+
|
||||
+ return NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -2472,7 +2478,8 @@ virQEMUCapsIsCPUModeSupported(virQEMUCapsPtr qemuCaps,
|
||||
virQEMUCapsGuestIsNative(caps->host.arch, qemuCaps->arch);
|
||||
|
||||
case VIR_CPU_MODE_HOST_MODEL:
|
||||
- return !!virQEMUCapsGetHostModel(qemuCaps, type);
|
||||
+ return !!virQEMUCapsGetHostModel(qemuCaps, type,
|
||||
+ VIR_QEMU_CAPS_HOST_CPU_REPORTED);
|
||||
|
||||
case VIR_CPU_MODE_CUSTOM:
|
||||
if (type == VIR_DOMAIN_VIRT_KVM)
|
||||
@@ -5456,7 +5463,8 @@ virQEMUCapsFillDomainCPUCaps(virCapsPtr caps,
|
||||
|
||||
if (virQEMUCapsIsCPUModeSupported(qemuCaps, caps, domCaps->virttype,
|
||||
VIR_CPU_MODE_HOST_MODEL)) {
|
||||
- virCPUDefPtr cpu = virQEMUCapsGetHostModel(qemuCaps, domCaps->virttype);
|
||||
+ virCPUDefPtr cpu = virQEMUCapsGetHostModel(qemuCaps, domCaps->virttype,
|
||||
+ VIR_QEMU_CAPS_HOST_CPU_REPORTED);
|
||||
domCaps->cpu.hostModel = virCPUDefCopy(cpu);
|
||||
}
|
||||
|
||||
diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h
|
||||
index d44682f2a..88e27855b 100644
|
||||
--- a/src/qemu/qemu_capabilities.h
|
||||
+++ b/src/qemu/qemu_capabilities.h
|
||||
@@ -449,8 +449,16 @@ int virQEMUCapsGetCPUDefinitions(virQEMUCapsPtr qemuCaps,
|
||||
virDomainVirtType type,
|
||||
char ***names,
|
||||
size_t *count);
|
||||
+
|
||||
+typedef enum {
|
||||
+ /* Host CPU definition reported in domain capabilities. */
|
||||
+ VIR_QEMU_CAPS_HOST_CPU_REPORTED,
|
||||
+} virQEMUCapsHostCPUType;
|
||||
+
|
||||
virCPUDefPtr virQEMUCapsGetHostModel(virQEMUCapsPtr qemuCaps,
|
||||
- virDomainVirtType type);
|
||||
+ virDomainVirtType type,
|
||||
+ virQEMUCapsHostCPUType cpuType);
|
||||
+
|
||||
bool virQEMUCapsIsCPUModeSupported(virQEMUCapsPtr qemuCaps,
|
||||
virCapsPtr caps,
|
||||
virDomainVirtType type,
|
||||
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
|
||||
index 3abfe7b55..311edd13e 100644
|
||||
--- a/src/qemu/qemu_command.c
|
||||
+++ b/src/qemu/qemu_command.c
|
||||
@@ -6879,7 +6879,8 @@ qemuBuildCpuCommandLine(virCommandPtr cmd,
|
||||
if (def->cpu->mode == VIR_CPU_MODE_CUSTOM)
|
||||
cpuDef = def->cpu;
|
||||
else if (def->cpu->mode == VIR_CPU_MODE_HOST_PASSTHROUGH)
|
||||
- cpuDef = virQEMUCapsGetHostModel(qemuCaps, def->virtType);
|
||||
+ cpuDef = virQEMUCapsGetHostModel(qemuCaps, def->virtType,
|
||||
+ VIR_QEMU_CAPS_HOST_CPU_REPORTED);
|
||||
|
||||
if (cpuDef) {
|
||||
int svm = virCPUCheckFeature(def->os.arch, cpuDef, "svm");
|
||||
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
|
||||
index 26a668d27..07a88a3a7 100644
|
||||
--- a/src/qemu/qemu_process.c
|
||||
+++ b/src/qemu/qemu_process.c
|
||||
@@ -5299,12 +5299,14 @@ qemuProcessUpdateGuestCPU(virDomainDefPtr def,
|
||||
|
||||
if (def->cpu->check == VIR_CPU_CHECK_PARTIAL &&
|
||||
virCPUCompare(caps->host.arch,
|
||||
- virQEMUCapsGetHostModel(qemuCaps, def->virtType),
|
||||
+ virQEMUCapsGetHostModel(qemuCaps, def->virtType,
|
||||
+ VIR_QEMU_CAPS_HOST_CPU_REPORTED),
|
||||
def->cpu, true) < 0)
|
||||
return -1;
|
||||
|
||||
if (virCPUUpdate(def->os.arch, def->cpu,
|
||||
- virQEMUCapsGetHostModel(qemuCaps, def->virtType)) < 0)
|
||||
+ virQEMUCapsGetHostModel(qemuCaps, def->virtType,
|
||||
+ VIR_QEMU_CAPS_HOST_CPU_REPORTED)) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (virQEMUCapsGetCPUDefinitions(qemuCaps, def->virtType,
|
||||
@@ -0,0 +1,210 @@
|
||||
From: Jiri Denemark <jdenemar@redhat.com>
|
||||
Date: Wed, 29 Mar 2017 15:31:17 +0200
|
||||
Subject: [PATCH] qemu: Pass migratable host CPU model to virCPUUpdate
|
||||
|
||||
We already know from QEMU which CPU features will block migration. Let's
|
||||
use this information to make a migratable copy of the host CPU model and
|
||||
use it for updating guest CPU specification. This will allow us to drop
|
||||
feature filtering from virCPUUpdate where it was just a hack.
|
||||
|
||||
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
|
||||
(cherry picked from commit 56bd7edcb5dc878beffb80d4e6a9cfb812378ded)
|
||||
---
|
||||
src/qemu/qemu_capabilities.c | 57 +++++++++++++++++++++++++++++++++++++-------
|
||||
src/qemu/qemu_capabilities.h | 2 ++
|
||||
src/qemu/qemu_process.c | 2 +-
|
||||
tests/cputest.c | 7 +++++-
|
||||
4 files changed, 57 insertions(+), 11 deletions(-)
|
||||
|
||||
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
|
||||
index a6324a398..7fc577546 100644
|
||||
--- a/src/qemu/qemu_capabilities.c
|
||||
+++ b/src/qemu/qemu_capabilities.c
|
||||
@@ -384,6 +384,8 @@ struct _virQEMUCapsHostCPUData {
|
||||
qemuMonitorCPUModelInfoPtr info;
|
||||
/* Host CPU definition reported in domain capabilities. */
|
||||
virCPUDefPtr reported;
|
||||
+ /* Migratable host CPU definition used for updating guest CPU. */
|
||||
+ virCPUDefPtr migratable;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -2100,6 +2102,10 @@ virQEMUCapsHostCPUDataCopy(virQEMUCapsHostCPUDataPtr dst,
|
||||
!(dst->reported = virCPUDefCopy(src->reported)))
|
||||
return -1;
|
||||
|
||||
+ if (src->migratable &&
|
||||
+ !(dst->migratable = virCPUDefCopy(src->migratable)))
|
||||
+ return -1;
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2109,6 +2115,7 @@ virQEMUCapsHostCPUDataClear(virQEMUCapsHostCPUDataPtr cpuData)
|
||||
{
|
||||
qemuMonitorCPUModelInfoFree(cpuData->info);
|
||||
virCPUDefFree(cpuData->reported);
|
||||
+ virCPUDefFree(cpuData->migratable);
|
||||
|
||||
memset(cpuData, 0, sizeof(*cpuData));
|
||||
}
|
||||
@@ -2447,6 +2454,9 @@ virQEMUCapsGetHostModel(virQEMUCapsPtr qemuCaps,
|
||||
switch (cpuType) {
|
||||
case VIR_QEMU_CAPS_HOST_CPU_REPORTED:
|
||||
return cpuData->reported;
|
||||
+
|
||||
+ case VIR_QEMU_CAPS_HOST_CPU_MIGRATABLE:
|
||||
+ return cpuData->migratable;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
@@ -2456,11 +2466,13 @@ virQEMUCapsGetHostModel(virQEMUCapsPtr qemuCaps,
|
||||
static void
|
||||
virQEMUCapsSetHostModel(virQEMUCapsPtr qemuCaps,
|
||||
virDomainVirtType type,
|
||||
- virCPUDefPtr cpu)
|
||||
+ virCPUDefPtr reported,
|
||||
+ virCPUDefPtr migratable)
|
||||
{
|
||||
virQEMUCapsHostCPUDataPtr cpuData = virQEMUCapsGetHostCPUData(qemuCaps, type);
|
||||
|
||||
- cpuData->reported = cpu;
|
||||
+ cpuData->reported = reported;
|
||||
+ cpuData->migratable = migratable;
|
||||
}
|
||||
|
||||
|
||||
@@ -3307,26 +3319,39 @@ virQEMUCapsInitCPUModel(virQEMUCapsPtr qemuCaps,
|
||||
}
|
||||
|
||||
|
||||
+static virCPUDefPtr
|
||||
+virQEMUCapsNewHostCPUModel(void)
|
||||
+{
|
||||
+ virCPUDefPtr cpu;
|
||||
+
|
||||
+ if (VIR_ALLOC(cpu) < 0)
|
||||
+ return NULL;
|
||||
+
|
||||
+ cpu->type = VIR_CPU_TYPE_GUEST;
|
||||
+ cpu->mode = VIR_CPU_MODE_CUSTOM;
|
||||
+ cpu->match = VIR_CPU_MATCH_EXACT;
|
||||
+ cpu->fallback = VIR_CPU_FALLBACK_ALLOW;
|
||||
+
|
||||
+ return cpu;
|
||||
+}
|
||||
+
|
||||
+
|
||||
void
|
||||
virQEMUCapsInitHostCPUModel(virQEMUCapsPtr qemuCaps,
|
||||
virCapsPtr caps,
|
||||
virDomainVirtType type)
|
||||
{
|
||||
virCPUDefPtr cpu = NULL;
|
||||
+ virCPUDefPtr migCPU = NULL;
|
||||
virCPUDefPtr hostCPU = NULL;
|
||||
int rc;
|
||||
|
||||
if (!caps || !virQEMUCapsGuestIsNative(caps->host.arch, qemuCaps->arch))
|
||||
return;
|
||||
|
||||
- if (VIR_ALLOC(cpu) < 0)
|
||||
+ if (!(cpu = virQEMUCapsNewHostCPUModel()))
|
||||
goto error;
|
||||
|
||||
- cpu->type = VIR_CPU_TYPE_GUEST;
|
||||
- cpu->mode = VIR_CPU_MODE_CUSTOM;
|
||||
- cpu->match = VIR_CPU_MATCH_EXACT;
|
||||
- cpu->fallback = VIR_CPU_FALLBACK_ALLOW;
|
||||
-
|
||||
if ((rc = virQEMUCapsInitCPUModel(qemuCaps, type, cpu, false)) < 0) {
|
||||
goto error;
|
||||
} else if (rc == 1) {
|
||||
@@ -3340,7 +3365,20 @@ virQEMUCapsInitHostCPUModel(virQEMUCapsPtr qemuCaps,
|
||||
goto error;
|
||||
}
|
||||
|
||||
- virQEMUCapsSetHostModel(qemuCaps, type, cpu);
|
||||
+ if (!(migCPU = virQEMUCapsNewHostCPUModel()))
|
||||
+ goto error;
|
||||
+
|
||||
+ if ((rc = virQEMUCapsInitCPUModel(qemuCaps, type, migCPU, true)) < 0) {
|
||||
+ goto error;
|
||||
+ } else if (rc == 1) {
|
||||
+ VIR_DEBUG("CPU migratability not provided by QEMU");
|
||||
+
|
||||
+ virCPUDefFree(migCPU);
|
||||
+ if (!(migCPU = virCPUCopyMigratable(qemuCaps->arch, cpu)))
|
||||
+ goto error;
|
||||
+ }
|
||||
+
|
||||
+ virQEMUCapsSetHostModel(qemuCaps, type, cpu, migCPU);
|
||||
|
||||
cleanup:
|
||||
virCPUDefFree(hostCPU);
|
||||
@@ -3348,6 +3386,7 @@ virQEMUCapsInitHostCPUModel(virQEMUCapsPtr qemuCaps,
|
||||
|
||||
error:
|
||||
virCPUDefFree(cpu);
|
||||
+ virCPUDefFree(migCPU);
|
||||
virResetLastError();
|
||||
goto cleanup;
|
||||
}
|
||||
diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h
|
||||
index 88e27855b..31818c940 100644
|
||||
--- a/src/qemu/qemu_capabilities.h
|
||||
+++ b/src/qemu/qemu_capabilities.h
|
||||
@@ -453,6 +453,8 @@ int virQEMUCapsGetCPUDefinitions(virQEMUCapsPtr qemuCaps,
|
||||
typedef enum {
|
||||
/* Host CPU definition reported in domain capabilities. */
|
||||
VIR_QEMU_CAPS_HOST_CPU_REPORTED,
|
||||
+ /* Migratable host CPU definition used for updating guest CPU. */
|
||||
+ VIR_QEMU_CAPS_HOST_CPU_MIGRATABLE,
|
||||
} virQEMUCapsHostCPUType;
|
||||
|
||||
virCPUDefPtr virQEMUCapsGetHostModel(virQEMUCapsPtr qemuCaps,
|
||||
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
|
||||
index 07a88a3a7..e67736638 100644
|
||||
--- a/src/qemu/qemu_process.c
|
||||
+++ b/src/qemu/qemu_process.c
|
||||
@@ -5306,7 +5306,7 @@ qemuProcessUpdateGuestCPU(virDomainDefPtr def,
|
||||
|
||||
if (virCPUUpdate(def->os.arch, def->cpu,
|
||||
virQEMUCapsGetHostModel(qemuCaps, def->virtType,
|
||||
- VIR_QEMU_CAPS_HOST_CPU_REPORTED)) < 0)
|
||||
+ VIR_QEMU_CAPS_HOST_CPU_MIGRATABLE)) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (virQEMUCapsGetCPUDefinitions(qemuCaps, def->virtType,
|
||||
diff --git a/tests/cputest.c b/tests/cputest.c
|
||||
index 8c07cf4f6..efa891dc1 100644
|
||||
--- a/tests/cputest.c
|
||||
+++ b/tests/cputest.c
|
||||
@@ -393,6 +393,7 @@ cpuTestUpdate(const void *arg)
|
||||
const struct data *data = arg;
|
||||
int ret = -1;
|
||||
virCPUDefPtr host = NULL;
|
||||
+ virCPUDefPtr migHost = NULL;
|
||||
virCPUDefPtr cpu = NULL;
|
||||
char *result = NULL;
|
||||
|
||||
@@ -400,7 +401,10 @@ cpuTestUpdate(const void *arg)
|
||||
!(cpu = cpuTestLoadXML(data->arch, data->name)))
|
||||
goto cleanup;
|
||||
|
||||
- if (virCPUUpdate(host->arch, cpu, host) < 0)
|
||||
+ if (!(migHost = virCPUCopyMigratable(data->arch, host)))
|
||||
+ goto cleanup;
|
||||
+
|
||||
+ if (virCPUUpdate(host->arch, cpu, migHost) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (virAsprintf(&result, "%s+%s", data->host, data->name) < 0)
|
||||
@@ -411,6 +415,7 @@ cpuTestUpdate(const void *arg)
|
||||
cleanup:
|
||||
virCPUDefFree(host);
|
||||
virCPUDefFree(cpu);
|
||||
+ virCPUDefFree(migHost);
|
||||
VIR_FREE(result);
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
From: Jiri Denemark <jdenemar@redhat.com>
|
||||
Date: Wed, 29 Mar 2017 15:00:21 +0200
|
||||
Subject: [PATCH] cpu: Drop feature filtering from virCPUUpdate
|
||||
|
||||
Because of the changes done in the previous commit, @host is already a
|
||||
migratable CPU and there's no need to do any additional filtering.
|
||||
|
||||
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
|
||||
(cherry picked from commit 232d87c7dd081d126a079fb45178e0be096cc680)
|
||||
---
|
||||
src/cpu/cpu_x86.c | 9 +++------
|
||||
1 file changed, 3 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c
|
||||
index a771b251e..53359ff9b 100644
|
||||
--- a/src/cpu/cpu_x86.c
|
||||
+++ b/src/cpu/cpu_x86.c
|
||||
@@ -2549,8 +2549,7 @@ x86Baseline(virCPUDefPtr *cpus,
|
||||
|
||||
static int
|
||||
x86UpdateHostModel(virCPUDefPtr guest,
|
||||
- const virCPUDef *host,
|
||||
- virCPUx86MapPtr map)
|
||||
+ const virCPUDef *host)
|
||||
{
|
||||
virCPUDefPtr updated = NULL;
|
||||
size_t i;
|
||||
@@ -2559,11 +2558,9 @@ x86UpdateHostModel(virCPUDefPtr guest,
|
||||
if (!(updated = virCPUDefCopyWithoutModel(host)))
|
||||
goto cleanup;
|
||||
|
||||
- /* Remove non-migratable features by default */
|
||||
updated->type = VIR_CPU_TYPE_GUEST;
|
||||
updated->mode = VIR_CPU_MODE_CUSTOM;
|
||||
- if (virCPUDefCopyModelFilter(updated, host, true,
|
||||
- x86FeatureIsMigratable, map) < 0)
|
||||
+ if (virCPUDefCopyModel(updated, host, true) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (guest->vendor_id) {
|
||||
@@ -2627,7 +2624,7 @@ virCPUx86Update(virCPUDefPtr guest,
|
||||
|
||||
if (guest->mode == VIR_CPU_MODE_HOST_MODEL ||
|
||||
guest->match == VIR_CPU_MATCH_MINIMUM)
|
||||
- ret = x86UpdateHostModel(guest, host, map);
|
||||
+ ret = x86UpdateHostModel(guest, host);
|
||||
else
|
||||
ret = 0;
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
From: Jiri Denemark <jdenemar@redhat.com>
|
||||
Date: Tue, 11 Apr 2017 20:45:07 +0200
|
||||
Subject: [PATCH] cpu: Introduce virCPUGetHostIsSupported
|
||||
|
||||
Sometimes we want to call virCPUGetHost only when it is implemented for
|
||||
a given architecture to avoid logging expected and possibly misleading
|
||||
errors. The new virCPUGetHostIsSupported API may be used to guard such
|
||||
calls to virCPUGetHost.
|
||||
|
||||
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
|
||||
(cherry picked from commit bf1a881715c905c67f7d38dcd5bd6c2afbff1f9b)
|
||||
---
|
||||
src/cpu/cpu.c | 20 ++++++++++++++++++++
|
||||
src/cpu/cpu.h | 3 +++
|
||||
src/libvirt_private.syms | 1 +
|
||||
3 files changed, 24 insertions(+)
|
||||
|
||||
diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c
|
||||
index 8a407ac18..702b14dbb 100644
|
||||
--- a/src/cpu/cpu.c
|
||||
+++ b/src/cpu/cpu.c
|
||||
@@ -357,6 +357,26 @@ virCPUDataFree(virCPUDataPtr data)
|
||||
}
|
||||
|
||||
|
||||
+/**
|
||||
+ * virCPUGetHostIsSupported:
|
||||
+ *
|
||||
+ * @arch: CPU architecture
|
||||
+ *
|
||||
+ * Check whether virCPUGetHost is supported for @arch.
|
||||
+ *
|
||||
+ * Returns true if virCPUGetHost is supported, false otherwise.
|
||||
+ */
|
||||
+bool
|
||||
+virCPUGetHostIsSupported(virArch arch)
|
||||
+{
|
||||
+ struct cpuArchDriver *driver;
|
||||
+
|
||||
+ VIR_DEBUG("arch=%s", virArchToString(arch));
|
||||
+
|
||||
+ return (driver = cpuGetSubDriver(arch)) && driver->getHost;
|
||||
+}
|
||||
+
|
||||
+
|
||||
/**
|
||||
* virCPUGetHost:
|
||||
*
|
||||
diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h
|
||||
index 352445c40..c6ca111e9 100644
|
||||
--- a/src/cpu/cpu.h
|
||||
+++ b/src/cpu/cpu.h
|
||||
@@ -183,6 +183,9 @@ virCPUDataNew(virArch arch);
|
||||
void
|
||||
virCPUDataFree(virCPUDataPtr data);
|
||||
|
||||
+bool
|
||||
+virCPUGetHostIsSupported(virArch arch);
|
||||
+
|
||||
virCPUDefPtr
|
||||
virCPUGetHost(virArch arch,
|
||||
virCPUType type,
|
||||
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
|
||||
index dc6db3b28..2d8a9ddec 100644
|
||||
--- a/src/libvirt_private.syms
|
||||
+++ b/src/libvirt_private.syms
|
||||
@@ -1024,6 +1024,7 @@ virCPUDataNew;
|
||||
virCPUDataParse;
|
||||
virCPUExpandFeatures;
|
||||
virCPUGetHost;
|
||||
+virCPUGetHostIsSupported;
|
||||
virCPUGetModels;
|
||||
virCPUProbeHost;
|
||||
virCPUTranslate;
|
||||
@@ -0,0 +1,164 @@
|
||||
From: Jiri Denemark <jdenemar@redhat.com>
|
||||
Date: Tue, 11 Apr 2017 20:46:05 +0200
|
||||
Subject: [PATCH] qemu: Use more data for comparing CPUs
|
||||
|
||||
With QEMU older than 2.9.0 libvirt uses CPUID instruction to determine
|
||||
what CPU features are supported on the host. This was later used when
|
||||
checking compatibility of guest CPUs. Since QEMU 2.9.0 we ask QEMU for
|
||||
the host CPU data. But the two methods we use usually provide disjoint
|
||||
sets of CPU features because QEMU/KVM does not support all features
|
||||
provided by the host CPU and on the other hand it can enable some
|
||||
feature even if the host CPU does not support them.
|
||||
|
||||
So if there is a domain which requires a CPU features disabled by
|
||||
QEMU/KVM, libvirt will refuse to start it with QEMU > 2.9.0 as its guest
|
||||
CPU is incompatible with the host CPU data we got from QEMU. But such
|
||||
domain would happily start on older QEMU (of course, the features would
|
||||
be missing the guest CPU). To fix this regression, we need to combine
|
||||
both CPU feature sets when checking guest CPU compatibility.
|
||||
|
||||
https://bugzilla.redhat.com/show_bug.cgi?id=1439933
|
||||
|
||||
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
|
||||
(cherry picked from commit 5b4a6adb5ca24a6cb91cdc55c31506fb278d3a91)
|
||||
---
|
||||
src/qemu/qemu_capabilities.c | 35 +++++++++++++++++++++++++++++++++--
|
||||
src/qemu/qemu_capabilities.h | 4 ++++
|
||||
src/qemu/qemu_process.c | 2 +-
|
||||
3 files changed, 38 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
|
||||
index 7fc577546..01bd4750c 100644
|
||||
--- a/src/qemu/qemu_capabilities.c
|
||||
+++ b/src/qemu/qemu_capabilities.c
|
||||
@@ -386,6 +386,10 @@ struct _virQEMUCapsHostCPUData {
|
||||
virCPUDefPtr reported;
|
||||
/* Migratable host CPU definition used for updating guest CPU. */
|
||||
virCPUDefPtr migratable;
|
||||
+ /* CPU definition with features detected by libvirt using virCPUGetHost
|
||||
+ * combined with features reported by QEMU. This is used for backward
|
||||
+ * compatible comparison between a guest CPU and a host CPU. */
|
||||
+ virCPUDefPtr full;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -2106,6 +2110,10 @@ virQEMUCapsHostCPUDataCopy(virQEMUCapsHostCPUDataPtr dst,
|
||||
!(dst->migratable = virCPUDefCopy(src->migratable)))
|
||||
return -1;
|
||||
|
||||
+ if (src->full &&
|
||||
+ !(dst->full = virCPUDefCopy(src->full)))
|
||||
+ return -1;
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2116,6 +2124,7 @@ virQEMUCapsHostCPUDataClear(virQEMUCapsHostCPUDataPtr cpuData)
|
||||
qemuMonitorCPUModelInfoFree(cpuData->info);
|
||||
virCPUDefFree(cpuData->reported);
|
||||
virCPUDefFree(cpuData->migratable);
|
||||
+ virCPUDefFree(cpuData->full);
|
||||
|
||||
memset(cpuData, 0, sizeof(*cpuData));
|
||||
}
|
||||
@@ -2457,6 +2466,11 @@ virQEMUCapsGetHostModel(virQEMUCapsPtr qemuCaps,
|
||||
|
||||
case VIR_QEMU_CAPS_HOST_CPU_MIGRATABLE:
|
||||
return cpuData->migratable;
|
||||
+
|
||||
+ case VIR_QEMU_CAPS_HOST_CPU_FULL:
|
||||
+ /* 'full' is non-NULL only if we have data from both QEMU and
|
||||
+ * virCPUGetHost */
|
||||
+ return cpuData->full ? cpuData->full : cpuData->reported;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
@@ -2467,12 +2481,14 @@ static void
|
||||
virQEMUCapsSetHostModel(virQEMUCapsPtr qemuCaps,
|
||||
virDomainVirtType type,
|
||||
virCPUDefPtr reported,
|
||||
- virCPUDefPtr migratable)
|
||||
+ virCPUDefPtr migratable,
|
||||
+ virCPUDefPtr full)
|
||||
{
|
||||
virQEMUCapsHostCPUDataPtr cpuData = virQEMUCapsGetHostCPUData(qemuCaps, type);
|
||||
|
||||
cpuData->reported = reported;
|
||||
cpuData->migratable = migratable;
|
||||
+ cpuData->full = full;
|
||||
}
|
||||
|
||||
|
||||
@@ -3344,6 +3360,8 @@ virQEMUCapsInitHostCPUModel(virQEMUCapsPtr qemuCaps,
|
||||
virCPUDefPtr cpu = NULL;
|
||||
virCPUDefPtr migCPU = NULL;
|
||||
virCPUDefPtr hostCPU = NULL;
|
||||
+ virCPUDefPtr fullCPU = NULL;
|
||||
+ size_t i;
|
||||
int rc;
|
||||
|
||||
if (!caps || !virQEMUCapsGuestIsNative(caps->host.arch, qemuCaps->arch))
|
||||
@@ -3363,6 +3381,18 @@ virQEMUCapsInitHostCPUModel(virQEMUCapsPtr qemuCaps,
|
||||
virQEMUCapsCPUFilterFeatures,
|
||||
qemuCaps) < 0)
|
||||
goto error;
|
||||
+ } else if (type == VIR_DOMAIN_VIRT_KVM &&
|
||||
+ virCPUGetHostIsSupported(qemuCaps->arch)) {
|
||||
+ if (!(fullCPU = virCPUGetHost(qemuCaps->arch, VIR_CPU_TYPE_GUEST,
|
||||
+ NULL, NULL, 0)))
|
||||
+ goto error;
|
||||
+
|
||||
+ for (i = 0; i < cpu->nfeatures; i++) {
|
||||
+ if (cpu->features[i].policy == VIR_CPU_FEATURE_REQUIRE &&
|
||||
+ virCPUDefUpdateFeature(fullCPU, cpu->features[i].name,
|
||||
+ VIR_CPU_FEATURE_REQUIRE) < 0)
|
||||
+ goto error;
|
||||
+ }
|
||||
}
|
||||
|
||||
if (!(migCPU = virQEMUCapsNewHostCPUModel()))
|
||||
@@ -3378,7 +3408,7 @@ virQEMUCapsInitHostCPUModel(virQEMUCapsPtr qemuCaps,
|
||||
goto error;
|
||||
}
|
||||
|
||||
- virQEMUCapsSetHostModel(qemuCaps, type, cpu, migCPU);
|
||||
+ virQEMUCapsSetHostModel(qemuCaps, type, cpu, migCPU, fullCPU);
|
||||
|
||||
cleanup:
|
||||
virCPUDefFree(hostCPU);
|
||||
@@ -3387,6 +3417,7 @@ virQEMUCapsInitHostCPUModel(virQEMUCapsPtr qemuCaps,
|
||||
error:
|
||||
virCPUDefFree(cpu);
|
||||
virCPUDefFree(migCPU);
|
||||
+ virCPUDefFree(fullCPU);
|
||||
virResetLastError();
|
||||
goto cleanup;
|
||||
}
|
||||
diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h
|
||||
index 31818c940..4e9561c0a 100644
|
||||
--- a/src/qemu/qemu_capabilities.h
|
||||
+++ b/src/qemu/qemu_capabilities.h
|
||||
@@ -455,6 +455,10 @@ typedef enum {
|
||||
VIR_QEMU_CAPS_HOST_CPU_REPORTED,
|
||||
/* Migratable host CPU definition used for updating guest CPU. */
|
||||
VIR_QEMU_CAPS_HOST_CPU_MIGRATABLE,
|
||||
+ /* CPU definition with features detected by libvirt using virCPUGetHost
|
||||
+ * combined with features reported by QEMU. This is used for backward
|
||||
+ * compatible comparison between a guest CPU and a host CPU. */
|
||||
+ VIR_QEMU_CAPS_HOST_CPU_FULL,
|
||||
} virQEMUCapsHostCPUType;
|
||||
|
||||
virCPUDefPtr virQEMUCapsGetHostModel(virQEMUCapsPtr qemuCaps,
|
||||
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
|
||||
index e67736638..992a7174b 100644
|
||||
--- a/src/qemu/qemu_process.c
|
||||
+++ b/src/qemu/qemu_process.c
|
||||
@@ -5300,7 +5300,7 @@ qemuProcessUpdateGuestCPU(virDomainDefPtr def,
|
||||
if (def->cpu->check == VIR_CPU_CHECK_PARTIAL &&
|
||||
virCPUCompare(caps->host.arch,
|
||||
virQEMUCapsGetHostModel(qemuCaps, def->virtType,
|
||||
- VIR_QEMU_CAPS_HOST_CPU_REPORTED),
|
||||
+ VIR_QEMU_CAPS_HOST_CPU_FULL),
|
||||
def->cpu, true) < 0)
|
||||
return -1;
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
From: Neal Gompa <ngompa13@gmail.com>
|
||||
Date: Mon, 17 Jul 2017 11:32:46 -0400
|
||||
Subject: [PATCH] spec: Add support for building the zfs storage driver
|
||||
|
||||
Where it can be supported in Fedora, the driver is built and made
|
||||
available as a subpackage.
|
||||
|
||||
Signed-off-by: Neal Gompa <ngompa13@gmail.com>
|
||||
(cherry picked from commit 9af764e86aef7dfb0191a9561bf1d1abf941da05)
|
||||
---
|
||||
libvirt.spec.in | 50 +++++++++++++++++++++++++++++++++++++++++++++++++-
|
||||
1 file changed, 49 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/libvirt.spec.in b/libvirt.spec.in
|
||||
index 079b5f386..46a3e97d1 100644
|
||||
--- a/libvirt.spec.in
|
||||
+++ b/libvirt.spec.in
|
||||
@@ -71,6 +71,13 @@
|
||||
%define with_storage_gluster 0%{!?_without_storage_gluster:1}
|
||||
%define with_numactl 0%{!?_without_numactl:1}
|
||||
|
||||
+# F25+ has zfs-fuse
|
||||
+%if 0%{?fedora} >= 25
|
||||
+ %define with_storage_zfs 0%{!?_without_storage_zfs:1}
|
||||
+%else
|
||||
+ %define with_storage_zfs 0
|
||||
+%endif
|
||||
+
|
||||
# A few optional bits off by default, we enable later
|
||||
%define with_fuse 0%{!?_without_fuse:0}
|
||||
%define with_cgconfig 0%{!?_without_cgconfig:0}
|
||||
@@ -115,6 +122,12 @@
|
||||
%endif
|
||||
%endif
|
||||
|
||||
+# zfs-fuse is not available on some architectures
|
||||
+%ifarch s390 s390x aarch64
|
||||
+ %define with_storage_zfs 0
|
||||
+%endif
|
||||
+
|
||||
+
|
||||
# RHEL doesn't ship OpenVZ, VBox, UML, PowerHypervisor,
|
||||
# VMware, libxenserver (xenapi), libxenlight (Xen 4.1 and newer),
|
||||
# or HyperV.
|
||||
@@ -373,6 +386,12 @@ BuildRequires: glusterfs-devel >= 3.4.1
|
||||
%if %{with_storage_sheepdog}
|
||||
BuildRequires: sheepdog
|
||||
%endif
|
||||
+%if %{with_storage_zfs}
|
||||
+# Support any conforming implementation of zfs. On stock Fedora
|
||||
+# this is zfs-fuse, but could be zfsonlinux upstream RPMs
|
||||
+BuildRequires: /sbin/zfs
|
||||
+BuildRequires: /sbin/zpool
|
||||
+%endif
|
||||
%if %{with_numactl}
|
||||
# For QEMU/LXC numa info
|
||||
BuildRequires: numactl-devel
|
||||
@@ -705,6 +724,21 @@ sheepdog volumes using.
|
||||
%endif
|
||||
|
||||
|
||||
+%if %{with_storage_zfs}
|
||||
+%package daemon-driver-storage-zfs
|
||||
+Summary: Storage driver plugin for ZFS
|
||||
+Group: Development/Libraries
|
||||
+Requires: libvirt-daemon-driver-storage-core = %{version}-%{release}
|
||||
+# Support any conforming implementation of zfs
|
||||
+Requires: /sbin/zfs
|
||||
+Requires: /sbin/zpool
|
||||
+
|
||||
+%description daemon-driver-storage-zfs
|
||||
+The storage driver backend adding implementation of the storage APIs for
|
||||
+ZFS volumes.
|
||||
+%endif
|
||||
+
|
||||
+
|
||||
%package daemon-driver-storage
|
||||
Summary: Storage driver plugin including all backends for the libvirtd daemon
|
||||
Group: Development/Libraries
|
||||
@@ -723,6 +757,9 @@ Requires: libvirt-daemon-driver-storage-rbd = %{version}-%{release}
|
||||
%if %{with_storage_sheepdog}
|
||||
Requires: libvirt-daemon-driver-storage-sheepdog = %{version}-%{release}
|
||||
%endif
|
||||
+%if %{with_storage_zfs}
|
||||
+Requires: libvirt-daemon-driver-storage-zfs = %{version}-%{release}
|
||||
+%endif
|
||||
|
||||
%description daemon-driver-storage
|
||||
The storage driver plugin for the libvirtd daemon, providing
|
||||
@@ -1180,6 +1217,12 @@ rm -rf .git
|
||||
%define arg_storage_gluster --without-storage-gluster
|
||||
%endif
|
||||
|
||||
+%if %{with_storage_zfs}
|
||||
+ %define arg_storage_zfs --with-storage-zfs
|
||||
+%else
|
||||
+ %define arg_storage_zfs --without-storage-zfs
|
||||
+%endif
|
||||
+
|
||||
%if %{with_numactl}
|
||||
%define arg_numactl --with-numactl
|
||||
%else
|
||||
@@ -1288,7 +1331,7 @@ rm -f po/stamp-po
|
||||
%{?arg_storage_rbd} \
|
||||
%{?arg_storage_sheepdog} \
|
||||
%{?arg_storage_gluster} \
|
||||
- --without-storage-zfs \
|
||||
+ %{?arg_storage_zfs} \
|
||||
--without-storage-vstorage \
|
||||
%{?arg_numactl} \
|
||||
%{?arg_numad} \
|
||||
@@ -1850,6 +1893,11 @@ exit 0
|
||||
%{_libdir}/%{name}/storage-backend/libvirt_storage_backend_sheepdog.so
|
||||
%endif
|
||||
|
||||
+%if %{with_storage_zfs}
|
||||
+%files daemon-driver-storage-zfs
|
||||
+%{_libdir}/%{name}/storage-backend/libvirt_storage_backend_zfs.so
|
||||
+%endif
|
||||
+
|
||||
%if %{with_qemu}
|
||||
%files daemon-driver-qemu
|
||||
%dir %attr(0700, root, root) %{_sysconfdir}/libvirt/qemu/
|
||||
@@ -0,0 +1,150 @@
|
||||
From: Juan Hernandez <jhernand@redhat.com>
|
||||
Date: Thu, 6 Jul 2017 17:03:31 +0200
|
||||
Subject: [PATCH] Avoid hidden cgroup mount points
|
||||
|
||||
Currently the scan of the /proc/mounts file used to find cgroup mount
|
||||
points doesn't take into account that mount points may hidden by other
|
||||
mount points. For, example in certain Kubernetes environments the
|
||||
/proc/mounts contains the following lines:
|
||||
|
||||
cgroup /sys/fs/cgroup/net_prio,net_cls cgroup ...
|
||||
tmpfs /sys/fs/cgroup tmpfs ...
|
||||
cgroup /sys/fs/cgroup/net_cls,net_prio cgroup ...
|
||||
|
||||
In this particular environment the first mount point is hidden by the
|
||||
second one. The correct mount point is the third one, but libvirt will
|
||||
never process it because it only checks the first mount point for each
|
||||
controller (net_cls in this case). So libvirt will try to use the first
|
||||
mount point, which doesn't actually exist, and the complete detection
|
||||
process will fail.
|
||||
|
||||
To avoid that issue this patch changes the virCgroupDetectMountsFromFile
|
||||
function so that when there are duplicates it takes the information from
|
||||
the last line in /proc/mounts. This requires removing the previous
|
||||
explicit condition to skip duplicates, and adding code to free the
|
||||
memory used by the processing of duplicated lines.
|
||||
|
||||
Related-To: https://bugzilla.redhat.com/1468214
|
||||
Related-To: https://github.com/kubevirt/libvirt/issues/4
|
||||
Signed-off-by: Juan Hernandez <jhernand@redhat.com>
|
||||
(cherry picked from commit dacd160d7479e0ec2d8a63f102145fd30636a1c8)
|
||||
---
|
||||
src/util/vircgroup.c | 23 ++++++++++++++---------
|
||||
tests/vircgroupdata/kubevirt.mounts | 25 +++++++++++++++++++++++++
|
||||
tests/vircgroupdata/kubevirt.parsed | 10 ++++++++++
|
||||
tests/vircgrouptest.c | 1 +
|
||||
4 files changed, 50 insertions(+), 9 deletions(-)
|
||||
create mode 100644 tests/vircgroupdata/kubevirt.mounts
|
||||
create mode 100644 tests/vircgroupdata/kubevirt.parsed
|
||||
|
||||
diff --git a/src/util/vircgroup.c b/src/util/vircgroup.c
|
||||
index 5aa1db5b1..a53908fc9 100644
|
||||
--- a/src/util/vircgroup.c
|
||||
+++ b/src/util/vircgroup.c
|
||||
@@ -397,6 +397,7 @@ virCgroupDetectMountsFromFile(virCgroupPtr group,
|
||||
const char *typestr = virCgroupControllerTypeToString(i);
|
||||
int typelen = strlen(typestr);
|
||||
char *tmp = entry.mnt_opts;
|
||||
+ struct virCgroupController *controller = &group->controllers[i];
|
||||
while (tmp) {
|
||||
char *next = strchr(tmp, ',');
|
||||
int len;
|
||||
@@ -406,18 +407,22 @@ virCgroupDetectMountsFromFile(virCgroupPtr group,
|
||||
} else {
|
||||
len = strlen(tmp);
|
||||
}
|
||||
- /* NB, the same controller can appear >1 time in mount list
|
||||
- * due to bind mounts from one location to another. Pick the
|
||||
- * first entry only
|
||||
- */
|
||||
- if (typelen == len && STREQLEN(typestr, tmp, len) &&
|
||||
- !group->controllers[i].mountPoint) {
|
||||
+
|
||||
+ if (typelen == len && STREQLEN(typestr, tmp, len)) {
|
||||
char *linksrc;
|
||||
struct stat sb;
|
||||
char *tmp2;
|
||||
|
||||
- if (VIR_STRDUP(group->controllers[i].mountPoint,
|
||||
- entry.mnt_dir) < 0)
|
||||
+ /* Note that the lines in /proc/mounts have the same
|
||||
+ * order than the mount operations, and that there may
|
||||
+ * be duplicates due to bind mounts. This means
|
||||
+ * that the same mount point may be processed more than
|
||||
+ * once. We need to save the results of the last one,
|
||||
+ * and we need to be careful to release the memory used
|
||||
+ * by previous processing. */
|
||||
+ VIR_FREE(controller->mountPoint);
|
||||
+ VIR_FREE(controller->linkPoint);
|
||||
+ if (VIR_STRDUP(controller->mountPoint, entry.mnt_dir) < 0)
|
||||
goto error;
|
||||
|
||||
tmp2 = strrchr(entry.mnt_dir, '/');
|
||||
@@ -453,7 +458,7 @@ virCgroupDetectMountsFromFile(virCgroupPtr group,
|
||||
VIR_WARN("Expecting a symlink at %s for controller %s",
|
||||
linksrc, typestr);
|
||||
} else {
|
||||
- group->controllers[i].linkPoint = linksrc;
|
||||
+ controller->linkPoint = linksrc;
|
||||
}
|
||||
}
|
||||
}
|
||||
diff --git a/tests/vircgroupdata/kubevirt.mounts b/tests/vircgroupdata/kubevirt.mounts
|
||||
new file mode 100644
|
||||
index 000000000..ca036196b
|
||||
--- /dev/null
|
||||
+++ b/tests/vircgroupdata/kubevirt.mounts
|
||||
@@ -0,0 +1,25 @@
|
||||
+rootfs / rootfs rw 0 0
|
||||
+proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0
|
||||
+udev /dev devtmpfs rw,nosuid,relatime,size=10240k,nr_inodes=1006404,mode=755 0 0
|
||||
+devpts /dev/pts devpts rw,relatime,gid=5,mode=620,ptmxmode=000 0 0
|
||||
+sysfs /sys sysfs rw,nosuid,nodev,noexec,relatime 0 0
|
||||
+/dev/sda1 / ext4 rw,noatime,data=ordered 0 0
|
||||
+tmpfs /run tmpfs rw,nodev,relatime,size=812296k,mode=755 0 0
|
||||
+mqueue /dev/mqueue mqueue rw,nosuid,nodev,noexec,relatime 0 0
|
||||
+shm /dev/shm tmpfs rw,nosuid,nodev,noexec,relatime 0 0
|
||||
+debugfs /sys/kernel/debug debugfs rw,nosuid,nodev,noexec,relatime 0 0
|
||||
+cgroup_root /sys/fs/cgroup tmpfs rw,nosuid,nodev,noexec,relatime,size=10240k,mode=755 0 0
|
||||
+openrc /sys/fs/cgroup/openrc cgroup rw,nosuid,nodev,noexec,relatime,release_agent=/lib64/rc/sh/cgroup-release-agent.sh,name=openrc 0 0
|
||||
+cpuset /some/random/location/cpuset cgroup rw,nosuid,nodev,noexec,relatime,cpuset 0 0
|
||||
+cpuset /sys/fs/cgroup/cpuset cgroup rw,nosuid,nodev,noexec,relatime,cpuset 0 0
|
||||
+cpu /sys/fs/cgroup/cpu cgroup rw,nosuid,nodev,noexec,relatime,cpu 0 0
|
||||
+cpuacct /some/random/location/cpuset cgroup rw,nosuid,nodev,noexec,relatime,cpuacct 0 0
|
||||
+cpuacct /sys/fs/cgroup/cpuacct cgroup rw,nosuid,nodev,noexec,relatime,cpuacct 0 0
|
||||
+memory /sys/fs/cgroup/memory cgroup rw,nosuid,nodev,noexec,relatime,memory 0 0
|
||||
+devices /sys/fs/cgroup/devices cgroup rw,nosuid,nodev,noexec,relatime,devices 0 0
|
||||
+freezer /sys/fs/cgroup/freezer cgroup rw,nosuid,nodev,noexec,relatime,freezer 0 0
|
||||
+blkio /sys/fs/cgroup/blkio cgroup rw,nosuid,nodev,noexec,relatime,blkio 0 0
|
||||
+perf_event /sys/fs/cgroup/perf_event cgroup rw,nosuid,nodev,noexec,relatime,perf_event 0 0
|
||||
+hugetlb /sys/fs/cgroup/hugetlb cgroup rw,nosuid,nodev,noexec,relatime,hugetlb 0 0
|
||||
+binfmt_misc /proc/sys/fs/binfmt_misc binfmt_misc rw,nosuid,nodev,noexec,relatime 0 0
|
||||
+freezer /some/random/location/freezer cgroup rw,nosuid,nodev,noexec,relatime,freezer 0 0
|
||||
diff --git a/tests/vircgroupdata/kubevirt.parsed b/tests/vircgroupdata/kubevirt.parsed
|
||||
new file mode 100644
|
||||
index 000000000..694870723
|
||||
--- /dev/null
|
||||
+++ b/tests/vircgroupdata/kubevirt.parsed
|
||||
@@ -0,0 +1,10 @@
|
||||
+cpu /sys/fs/cgroup/cpu
|
||||
+cpuacct /sys/fs/cgroup/cpuacct
|
||||
+cpuset /sys/fs/cgroup/cpuset
|
||||
+memory /sys/fs/cgroup/memory
|
||||
+devices /sys/fs/cgroup/devices
|
||||
+freezer /some/random/location/freezer
|
||||
+blkio /sys/fs/cgroup/blkio
|
||||
+net_cls <null>
|
||||
+perf_event /sys/fs/cgroup/perf_event
|
||||
+name=systemd <null>
|
||||
diff --git a/tests/vircgrouptest.c b/tests/vircgrouptest.c
|
||||
index f55ef74a1..cf0315f16 100644
|
||||
--- a/tests/vircgrouptest.c
|
||||
+++ b/tests/vircgrouptest.c
|
||||
@@ -885,6 +885,7 @@ mymain(void)
|
||||
DETECT_MOUNTS("cgroups3");
|
||||
DETECT_MOUNTS("all-in-one");
|
||||
DETECT_MOUNTS("no-cgroups");
|
||||
+ DETECT_MOUNTS("kubevirt");
|
||||
|
||||
if (virTestRun("New cgroup for self", testCgroupNewForSelf, NULL) < 0)
|
||||
ret = -1;
|
||||
@@ -0,0 +1,53 @@
|
||||
From: Jim Fehlig <jfehlig@suse.com>
|
||||
Date: Tue, 18 Jul 2017 10:20:35 -0600
|
||||
Subject: [PATCH] docs: schema: make disk driver name attribute optional
|
||||
|
||||
/domain/devices/disk/driver/@name is not a required or mandatory
|
||||
attribute according to formatdomain, and indeed it was agreed on
|
||||
IRC that the attribute is "optional for input, recommended (but
|
||||
not required) for output". Currently the schema requires the
|
||||
attribute, causing virt-xml-validate to fail on disk config where
|
||||
the driver name is not explicitly specified. E.g.
|
||||
|
||||
# cat test.xml | grep -A 5 cdrom
|
||||
<disk type='file' device='cdrom'>
|
||||
<driver type='raw'/>
|
||||
<target dev='hdb' bus='ide'/>
|
||||
<readonly/>
|
||||
<address type='drive' controller='0' bus='0' target='0' unit='1'/>
|
||||
</disk>
|
||||
|
||||
# virt-xml-validate test.xml
|
||||
Relax-NG validity error : Extra element devices in interleave
|
||||
test.xml:21: element devices: Relax-NG validity error : Element domain failed to validate content
|
||||
test.xml fails to validate
|
||||
|
||||
Relaxing the name attribute to be optional fixes the validation
|
||||
|
||||
# virt-xml-validate test.xml
|
||||
test.xml validates
|
||||
|
||||
(cherry picked from commit b494e09d058f09b48d0fd8855edd557101294671)
|
||||
---
|
||||
docs/schemas/domaincommon.rng | 8 +++++---
|
||||
1 file changed, 5 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
|
||||
index edc225fe5..dfc7e2470 100644
|
||||
--- a/docs/schemas/domaincommon.rng
|
||||
+++ b/docs/schemas/domaincommon.rng
|
||||
@@ -1720,9 +1720,11 @@
|
||||
</element>
|
||||
</define>
|
||||
<define name="driverFormat">
|
||||
- <attribute name="name">
|
||||
- <ref name="genericName"/>
|
||||
- </attribute>
|
||||
+ <optional>
|
||||
+ <attribute name="name">
|
||||
+ <ref name="genericName"/>
|
||||
+ </attribute>
|
||||
+ </optional>
|
||||
<optional>
|
||||
<attribute name='type'>
|
||||
<choice>
|
||||
@@ -0,0 +1,34 @@
|
||||
From: Stefan Berger <stefanb@linux.vnet.ibm.com>
|
||||
Date: Thu, 29 Jun 2017 14:01:11 -0400
|
||||
Subject: [PATCH] tpm: Use /dev/null for cancel path if none was found
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
TPM 2 does not implement sysfs files for cancellation of commands.
|
||||
We therefore use /dev/null for the cancel path passed to QEMU.
|
||||
|
||||
Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
|
||||
Tested-by: Javier Martinez Canillas <javierm@redhat.com>
|
||||
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
|
||||
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
|
||||
(cherry picked from commit dfbb15b75433e520fb1b905c1c3e28753e53e4a5)
|
||||
---
|
||||
src/util/virtpm.c | 4 +---
|
||||
1 file changed, 1 insertion(+), 3 deletions(-)
|
||||
|
||||
diff --git a/src/util/virtpm.c b/src/util/virtpm.c
|
||||
index 6d9b0657a..d5c10da38 100644
|
||||
--- a/src/util/virtpm.c
|
||||
+++ b/src/util/virtpm.c
|
||||
@@ -61,9 +61,7 @@ virTPMCreateCancelPath(const char *devpath)
|
||||
VIR_FREE(path);
|
||||
}
|
||||
if (!path)
|
||||
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||
- _("No usable sysfs TPM cancel file could be "
|
||||
- "found"));
|
||||
+ ignore_value(VIR_STRDUP(path, "/dev/null"));
|
||||
} else {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("TPM device path %s is invalid"), devpath);
|
||||
@@ -0,0 +1,108 @@
|
||||
From: Cole Robinson <crobinso@redhat.com>
|
||||
Date: Sun, 27 Aug 2017 11:23:47 -0400
|
||||
Subject: [PATCH] security: add MANAGER_MOUNT_NAMESPACE flag
|
||||
|
||||
The VIR_SECURITY_MANAGER_MOUNT_NAMESPACE flag informs the DAC driver
|
||||
if mount namespaces are in use for the VM. Will be used for future
|
||||
changes.
|
||||
|
||||
Wire it up in the qemu driver
|
||||
|
||||
(cherry picked from commit 321031e482425dfeae0f125cdac6df870f079efd)
|
||||
---
|
||||
src/qemu/qemu_driver.c | 2 ++
|
||||
src/security/security_dac.c | 10 ++++++++++
|
||||
src/security/security_dac.h | 3 +++
|
||||
src/security/security_manager.c | 4 +++-
|
||||
src/security/security_manager.h | 1 +
|
||||
5 files changed, 19 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
|
||||
index ce844bb04..555a1009b 100644
|
||||
--- a/src/qemu/qemu_driver.c
|
||||
+++ b/src/qemu/qemu_driver.c
|
||||
@@ -417,6 +417,8 @@ qemuSecurityInit(virQEMUDriverPtr driver)
|
||||
if (virQEMUDriverIsPrivileged(driver)) {
|
||||
if (cfg->dynamicOwnership)
|
||||
flags |= VIR_SECURITY_MANAGER_DYNAMIC_OWNERSHIP;
|
||||
+ if (virBitmapIsBitSet(cfg->namespaces, QEMU_DOMAIN_NS_MOUNT))
|
||||
+ flags |= VIR_SECURITY_MANAGER_MOUNT_NAMESPACE;
|
||||
if (!(mgr = qemuSecurityNewDAC(QEMU_DRIVER_NAME,
|
||||
cfg->user,
|
||||
cfg->group,
|
||||
diff --git a/src/security/security_dac.c b/src/security/security_dac.c
|
||||
index 922e48494..1f8d279bf 100644
|
||||
--- a/src/security/security_dac.c
|
||||
+++ b/src/security/security_dac.c
|
||||
@@ -57,6 +57,7 @@ struct _virSecurityDACData {
|
||||
gid_t *groups;
|
||||
int ngroups;
|
||||
bool dynamicOwnership;
|
||||
+ bool mountNamespace;
|
||||
char *baselabel;
|
||||
virSecurityManagerDACChownCallback chownCallback;
|
||||
};
|
||||
@@ -237,6 +238,15 @@ virSecurityDACSetDynamicOwnership(virSecurityManagerPtr mgr,
|
||||
priv->dynamicOwnership = dynamicOwnership;
|
||||
}
|
||||
|
||||
+void
|
||||
+virSecurityDACSetMountNamespace(virSecurityManagerPtr mgr,
|
||||
+ bool mountNamespace)
|
||||
+{
|
||||
+ virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
|
||||
+ priv->mountNamespace = mountNamespace;
|
||||
+}
|
||||
+
|
||||
+
|
||||
void
|
||||
virSecurityDACSetChownCallback(virSecurityManagerPtr mgr,
|
||||
virSecurityManagerDACChownCallback chownCallback)
|
||||
diff --git a/src/security/security_dac.h b/src/security/security_dac.h
|
||||
index 846cefbb5..97681c961 100644
|
||||
--- a/src/security/security_dac.h
|
||||
+++ b/src/security/security_dac.h
|
||||
@@ -32,6 +32,9 @@ int virSecurityDACSetUserAndGroup(virSecurityManagerPtr mgr,
|
||||
void virSecurityDACSetDynamicOwnership(virSecurityManagerPtr mgr,
|
||||
bool dynamic);
|
||||
|
||||
+void virSecurityDACSetMountNamespace(virSecurityManagerPtr mgr,
|
||||
+ bool mountNamespace);
|
||||
+
|
||||
void virSecurityDACSetChownCallback(virSecurityManagerPtr mgr,
|
||||
virSecurityManagerDACChownCallback chownCallback);
|
||||
|
||||
diff --git a/src/security/security_manager.c b/src/security/security_manager.c
|
||||
index 6c777db1e..b2d04d4b9 100644
|
||||
--- a/src/security/security_manager.c
|
||||
+++ b/src/security/security_manager.c
|
||||
@@ -146,7 +146,8 @@ virSecurityManagerNewDAC(const char *virtDriver,
|
||||
virSecurityManagerPtr mgr;
|
||||
|
||||
virCheckFlags(VIR_SECURITY_MANAGER_NEW_MASK |
|
||||
- VIR_SECURITY_MANAGER_DYNAMIC_OWNERSHIP, NULL);
|
||||
+ VIR_SECURITY_MANAGER_DYNAMIC_OWNERSHIP |
|
||||
+ VIR_SECURITY_MANAGER_MOUNT_NAMESPACE, NULL);
|
||||
|
||||
mgr = virSecurityManagerNewDriver(&virSecurityDriverDAC,
|
||||
virtDriver,
|
||||
@@ -161,6 +162,7 @@ virSecurityManagerNewDAC(const char *virtDriver,
|
||||
}
|
||||
|
||||
virSecurityDACSetDynamicOwnership(mgr, flags & VIR_SECURITY_MANAGER_DYNAMIC_OWNERSHIP);
|
||||
+ virSecurityDACSetMountNamespace(mgr, flags & VIR_SECURITY_MANAGER_MOUNT_NAMESPACE);
|
||||
virSecurityDACSetChownCallback(mgr, chownCallback);
|
||||
|
||||
return mgr;
|
||||
diff --git a/src/security/security_manager.h b/src/security/security_manager.h
|
||||
index 238e66cd0..96937a892 100644
|
||||
--- a/src/security/security_manager.h
|
||||
+++ b/src/security/security_manager.h
|
||||
@@ -36,6 +36,7 @@ typedef enum {
|
||||
VIR_SECURITY_MANAGER_REQUIRE_CONFINED = 1 << 2,
|
||||
VIR_SECURITY_MANAGER_PRIVILEGED = 1 << 3,
|
||||
VIR_SECURITY_MANAGER_DYNAMIC_OWNERSHIP = 1 << 4,
|
||||
+ VIR_SECURITY_MANAGER_MOUNT_NAMESPACE = 1 << 5,
|
||||
} virSecurityManagerNewFlags;
|
||||
|
||||
# define VIR_SECURITY_MANAGER_NEW_MASK \
|
||||
@@ -0,0 +1,101 @@
|
||||
From: Cole Robinson <crobinso@redhat.com>
|
||||
Date: Mon, 17 Jul 2017 08:57:57 -0400
|
||||
Subject: [PATCH] security: dac: relabel spice rendernode
|
||||
|
||||
For a logged in user this a path like /dev/dri/renderD128 will have
|
||||
default ownership root:video which won't work for the qemu:qemu user,
|
||||
so we need to chown it.
|
||||
|
||||
We only do this when mount namespaces are enabled in the qemu driver,
|
||||
so the chown'ing doesn't interfere with other users of the shared
|
||||
render node path
|
||||
|
||||
https://bugzilla.redhat.com/show_bug.cgi?id=1460804
|
||||
(cherry picked from commit 98931187eefdec6f2dea5cb82ab6d23a3ffa6634)
|
||||
---
|
||||
src/security/security_dac.c | 58 +++++++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 58 insertions(+)
|
||||
|
||||
diff --git a/src/security/security_dac.c b/src/security/security_dac.c
|
||||
index 1f8d279bf..5f13bcee8 100644
|
||||
--- a/src/security/security_dac.c
|
||||
+++ b/src/security/security_dac.c
|
||||
@@ -1379,6 +1379,54 @@ virSecurityDACRestoreTPMFileLabel(virSecurityManagerPtr mgr,
|
||||
}
|
||||
|
||||
|
||||
+static int
|
||||
+virSecurityDACSetGraphicsLabel(virSecurityManagerPtr mgr,
|
||||
+ virDomainDefPtr def,
|
||||
+ virDomainGraphicsDefPtr gfx)
|
||||
+
|
||||
+{
|
||||
+ virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
|
||||
+ virSecurityLabelDefPtr seclabel;
|
||||
+ uid_t user;
|
||||
+ gid_t group;
|
||||
+
|
||||
+ /* Skip chowning the shared render file if namespaces are disabled */
|
||||
+ if (!priv->mountNamespace)
|
||||
+ return 0;
|
||||
+
|
||||
+ seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_DAC_NAME);
|
||||
+ if (seclabel && !seclabel->relabel)
|
||||
+ return 0;
|
||||
+
|
||||
+ if (virSecurityDACGetIds(seclabel, priv, &user, &group, NULL, NULL) < 0)
|
||||
+ return -1;
|
||||
+
|
||||
+ if (gfx->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE &&
|
||||
+ gfx->data.spice.gl == VIR_TRISTATE_BOOL_YES &&
|
||||
+ gfx->data.spice.rendernode) {
|
||||
+ if (virSecurityDACSetOwnership(priv, NULL,
|
||||
+ gfx->data.spice.rendernode,
|
||||
+ user, group) < 0)
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static int
|
||||
+virSecurityDACRestoreGraphicsLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
|
||||
+ virDomainDefPtr def ATTRIBUTE_UNUSED,
|
||||
+ virDomainGraphicsDefPtr gfx ATTRIBUTE_UNUSED)
|
||||
+
|
||||
+{
|
||||
+ /* The only graphics labelling we do is dependent on mountNamespaces,
|
||||
+ in which case 'restoring' the label doesn't actually accomplish
|
||||
+ anything, so there's nothing to do here */
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+
|
||||
static int
|
||||
virSecurityDACSetInputLabel(virSecurityManagerPtr mgr,
|
||||
virDomainDefPtr def,
|
||||
@@ -1489,6 +1537,11 @@ virSecurityDACRestoreAllLabel(virSecurityManagerPtr mgr,
|
||||
rc = -1;
|
||||
}
|
||||
|
||||
+ for (i = 0; i < def->ngraphics; i++) {
|
||||
+ if (virSecurityDACRestoreGraphicsLabel(mgr, def, def->graphics[i]) < 0)
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
for (i = 0; i < def->ninputs; i++) {
|
||||
if (virSecurityDACRestoreInputLabel(mgr, def, def->inputs[i]) < 0)
|
||||
rc = -1;
|
||||
@@ -1602,6 +1655,11 @@ virSecurityDACSetAllLabel(virSecurityManagerPtr mgr,
|
||||
return -1;
|
||||
}
|
||||
|
||||
+ for (i = 0; i < def->ngraphics; i++) {
|
||||
+ if (virSecurityDACSetGraphicsLabel(mgr, def, def->graphics[i]) < 0)
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
for (i = 0; i < def->ninputs; i++) {
|
||||
if (virSecurityDACSetInputLabel(mgr, def, def->inputs[i]) < 0)
|
||||
return -1;
|
||||
@@ -0,0 +1,63 @@
|
||||
From: Michal Privoznik <mprivozn@redhat.com>
|
||||
Date: Mon, 31 Jul 2017 16:55:58 +0200
|
||||
Subject: [PATCH] qemu: Honour <on_reboot/>
|
||||
|
||||
https://bugzilla.redhat.com/show_bug.cgi?id=1476866
|
||||
|
||||
For some reason, we completely ignore <on_reboot/> setting for
|
||||
domains. The implementation is simply not there. It never was.
|
||||
|
||||
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
|
||||
(cherry picked from commit 3ee9bdbe351c0b80d4c469571ef31df3f1b148ea)
|
||||
---
|
||||
src/qemu/qemu_process.c | 27 ++++++++++++++++++++++++---
|
||||
1 file changed, 24 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
|
||||
index 992a7174b..7588212ba 100644
|
||||
--- a/src/qemu/qemu_process.c
|
||||
+++ b/src/qemu/qemu_process.c
|
||||
@@ -487,6 +487,7 @@ qemuProcessHandleReset(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
|
||||
virObjectEventPtr event;
|
||||
qemuDomainObjPrivatePtr priv;
|
||||
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
|
||||
+ int ret = -1;
|
||||
|
||||
virObjectLock(vm);
|
||||
|
||||
@@ -498,12 +499,32 @@ qemuProcessHandleReset(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
|
||||
if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, driver->caps) < 0)
|
||||
VIR_WARN("Failed to save status on vm %s", vm->def->name);
|
||||
|
||||
- virObjectUnlock(vm);
|
||||
+ if (vm->def->onReboot == VIR_DOMAIN_LIFECYCLE_DESTROY ||
|
||||
+ vm->def->onReboot == VIR_DOMAIN_LIFECYCLE_PRESERVE) {
|
||||
|
||||
- qemuDomainEventQueue(driver, event);
|
||||
+ if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
|
||||
+ goto cleanup;
|
||||
+
|
||||
+ if (!virDomainObjIsActive(vm)) {
|
||||
+ VIR_DEBUG("Ignoring RESET event from inactive domain %s",
|
||||
+ vm->def->name);
|
||||
+ goto endjob;
|
||||
+ }
|
||||
+
|
||||
+ qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_DESTROYED,
|
||||
+ QEMU_ASYNC_JOB_NONE, 0);
|
||||
+ virDomainAuditStop(vm, "destroyed");
|
||||
+ qemuDomainRemoveInactive(driver, vm);
|
||||
+ endjob:
|
||||
+ qemuDomainObjEndJob(driver, vm);
|
||||
+ }
|
||||
|
||||
+ ret = 0;
|
||||
+ cleanup:
|
||||
+ virObjectUnlock(vm);
|
||||
+ qemuDomainEventQueue(driver, event);
|
||||
virObjectUnref(cfg);
|
||||
- return 0;
|
||||
+ return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
From: Michal Privoznik <mprivozn@redhat.com>
|
||||
Date: Thu, 27 Apr 2017 16:29:21 +0200
|
||||
Subject: [PATCH] qemuDomainBuildNamespace: Move /dev/* mountpoints later
|
||||
|
||||
When setting up mount namespace for a qemu domain the following
|
||||
steps are executed:
|
||||
|
||||
1) get list of mountpoints under /dev/
|
||||
2) move them to /var/run/libvirt/qemu/$domName.ext
|
||||
3) start constructing new device tree under /var/run/libvirt/qemu/$domName.dev
|
||||
4) move the mountpoint of the new device tree to /dev
|
||||
5) restore original mountpoints from step 2)
|
||||
|
||||
Note the problem with this approach is that if some device in step
|
||||
3) requires access to a mountpoint from step 2) it will fail as
|
||||
the mountpoint is not there anymore. For instance consider the
|
||||
following domain disk configuration:
|
||||
|
||||
<disk type='file' device='disk'>
|
||||
<driver name='qemu' type='raw'/>
|
||||
<source file='/dev/shm/vhostmd0'/>
|
||||
<target dev='vdb' bus='virtio'/>
|
||||
<address type='pci' domain='0x0000' bus='0x00' slot='0x0a' function='0x0'/>
|
||||
</disk>
|
||||
|
||||
In this case operation fails as we are unable to create vhostmd0
|
||||
in the new device tree because after step 2) there is no /dev/shm
|
||||
anymore. Leave aside fact that we shouldn't try to create devices
|
||||
living in other mountpoints. That's a separate bug that will be
|
||||
addressed later.
|
||||
|
||||
Currently, the order described above is rearranged to:
|
||||
|
||||
1) get list of mountpoints under /dev/
|
||||
2) start constructing new device tree under /var/run/libvirt/qemu/$domName.dev
|
||||
3) move them to /var/run/libvirt/qemu/$domName.ext
|
||||
4) move the mountpoint of the new device tree to /dev
|
||||
5) restore original mountpoints from step 3)
|
||||
|
||||
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
|
||||
Reviewed-by: Cedric Bosdonnat <cbosdonnat@suse.com>
|
||||
(cherry picked from commit a7cc039dc796f541793955598377807af48341fb)
|
||||
(cherry picked from commit 469bf7cb7a44a0798c63e4b5e4682d8e38bce66e)
|
||||
---
|
||||
src/qemu/qemu_domain.c | 48 ++++++++++++++++++++++++------------------------
|
||||
1 file changed, 24 insertions(+), 24 deletions(-)
|
||||
|
||||
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
|
||||
index 4a127cedf..64f18f493 100644
|
||||
--- a/src/qemu/qemu_domain.c
|
||||
+++ b/src/qemu/qemu_domain.c
|
||||
@@ -7854,6 +7854,30 @@ qemuDomainBuildNamespace(virQEMUDriverConfigPtr cfg,
|
||||
if (qemuDomainSetupDev(cfg, mgr, vm, devPath) < 0)
|
||||
goto cleanup;
|
||||
|
||||
+ if (qemuDomainSetupAllDisks(cfg, vm, devPath) < 0)
|
||||
+ goto cleanup;
|
||||
+
|
||||
+ if (qemuDomainSetupAllHostdevs(cfg, vm, devPath) < 0)
|
||||
+ goto cleanup;
|
||||
+
|
||||
+ if (qemuDomainSetupAllMemories(cfg, vm, devPath) < 0)
|
||||
+ goto cleanup;
|
||||
+
|
||||
+ if (qemuDomainSetupAllChardevs(cfg, vm, devPath) < 0)
|
||||
+ goto cleanup;
|
||||
+
|
||||
+ if (qemuDomainSetupTPM(cfg, vm, devPath) < 0)
|
||||
+ goto cleanup;
|
||||
+
|
||||
+ if (qemuDomainSetupAllGraphics(cfg, vm, devPath) < 0)
|
||||
+ goto cleanup;
|
||||
+
|
||||
+ if (qemuDomainSetupAllInputs(cfg, vm, devPath) < 0)
|
||||
+ goto cleanup;
|
||||
+
|
||||
+ if (qemuDomainSetupAllRNGs(cfg, vm, devPath) < 0)
|
||||
+ goto cleanup;
|
||||
+
|
||||
/* Save some mount points because we want to share them with the host */
|
||||
for (i = 0; i < ndevMountsPath; i++) {
|
||||
struct stat sb;
|
||||
@@ -7881,30 +7905,6 @@ qemuDomainBuildNamespace(virQEMUDriverConfigPtr cfg,
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
- if (qemuDomainSetupAllDisks(cfg, vm, devPath) < 0)
|
||||
- goto cleanup;
|
||||
-
|
||||
- if (qemuDomainSetupAllHostdevs(cfg, vm, devPath) < 0)
|
||||
- goto cleanup;
|
||||
-
|
||||
- if (qemuDomainSetupAllMemories(cfg, vm, devPath) < 0)
|
||||
- goto cleanup;
|
||||
-
|
||||
- if (qemuDomainSetupAllChardevs(cfg, vm, devPath) < 0)
|
||||
- goto cleanup;
|
||||
-
|
||||
- if (qemuDomainSetupTPM(cfg, vm, devPath) < 0)
|
||||
- goto cleanup;
|
||||
-
|
||||
- if (qemuDomainSetupAllGraphics(cfg, vm, devPath) < 0)
|
||||
- goto cleanup;
|
||||
-
|
||||
- if (qemuDomainSetupAllInputs(cfg, vm, devPath) < 0)
|
||||
- goto cleanup;
|
||||
-
|
||||
- if (qemuDomainSetupAllRNGs(cfg, vm, devPath) < 0)
|
||||
- goto cleanup;
|
||||
-
|
||||
if (virFileMoveMount(devPath, "/dev") < 0)
|
||||
goto cleanup;
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
From: "Daniel P. Berrange" <berrange@redhat.com>
|
||||
Date: Thu, 5 Oct 2017 17:54:28 +0100
|
||||
Subject: [PATCH] qemu: ensure TLS clients always verify the server certificate
|
||||
|
||||
The default_tls_x509_verify (and related) parameters in qemu.conf
|
||||
control whether the QEMU TLS servers request & verify certificates
|
||||
from clients. This works as a simple access control system for
|
||||
servers by requiring the CA to issue certs to permitted clients.
|
||||
This use of client certificates is disabled by default, since it
|
||||
requires extra work to issue client certificates.
|
||||
|
||||
Unfortunately the code was using this configuration parameter when
|
||||
setting up both TLS clients and servers in QEMU. The result was that
|
||||
TLS clients for character devices and disk devices had verification
|
||||
turned off, meaning they would ignore errors while validating the
|
||||
server certificate.
|
||||
|
||||
This allows for trivial MITM attacks between client and server,
|
||||
as any certificate returned by the attacker will be accepted by
|
||||
the client.
|
||||
|
||||
This is assigned CVE-2017-1000256 / LSN-2017-0002
|
||||
|
||||
Reviewed-by: Eric Blake <eblake@redhat.com>
|
||||
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
|
||||
(cherry picked from commit 441d3eb6d1be940a67ce45a286602a967601b157)
|
||||
---
|
||||
src/qemu/qemu_command.c | 2 +-
|
||||
tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev.args | 2 +-
|
||||
.../qemuxml2argv-serial-tcp-tlsx509-secret-chardev.args | 2 +-
|
||||
3 files changed, 3 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
|
||||
index 311edd13e..141831635 100644
|
||||
--- a/src/qemu/qemu_command.c
|
||||
+++ b/src/qemu/qemu_command.c
|
||||
@@ -727,7 +727,7 @@ qemuBuildTLSx509BackendProps(const char *tlspath,
|
||||
if (virJSONValueObjectCreate(propsret,
|
||||
"s:dir", path,
|
||||
"s:endpoint", (isListen ? "server": "client"),
|
||||
- "b:verify-peer", verifypeer,
|
||||
+ "b:verify-peer", (isListen ? verifypeer : true),
|
||||
NULL) < 0)
|
||||
goto cleanup;
|
||||
|
||||
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev.args b/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev.args
|
||||
index b456cce30..003d11de7 100644
|
||||
--- a/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev.args
|
||||
+++ b/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev.args
|
||||
@@ -26,7 +26,7 @@ server,nowait \
|
||||
localport=1111 \
|
||||
-device isa-serial,chardev=charserial0,id=serial0 \
|
||||
-object tls-creds-x509,id=objcharserial1_tls0,dir=/etc/pki/libvirt-chardev,\
|
||||
-endpoint=client,verify-peer=no \
|
||||
+endpoint=client,verify-peer=yes \
|
||||
-chardev socket,id=charserial1,host=127.0.0.1,port=5555,\
|
||||
tls-creds=objcharserial1_tls0 \
|
||||
-device isa-serial,chardev=charserial1,id=serial1 \
|
||||
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-secret-chardev.args b/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-secret-chardev.args
|
||||
index 7f9fedb6c..a020ff006 100644
|
||||
--- a/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-secret-chardev.args
|
||||
+++ b/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-secret-chardev.args
|
||||
@@ -31,7 +31,7 @@ localport=1111 \
|
||||
data=9eao5F8qtkGt+seB1HYivWIxbtwUu6MQtg1zpj/oDtUsPr1q8wBYM91uEHCn6j/1,\
|
||||
keyid=masterKey0,iv=AAECAwQFBgcICQoLDA0ODw==,format=base64 \
|
||||
-object tls-creds-x509,id=objcharserial1_tls0,dir=/etc/pki/libvirt-chardev,\
|
||||
-endpoint=client,verify-peer=no,passwordid=charserial1-secret0 \
|
||||
+endpoint=client,verify-peer=yes,passwordid=charserial1-secret0 \
|
||||
-chardev socket,id=charserial1,host=127.0.0.1,port=5555,\
|
||||
tls-creds=objcharserial1_tls0 \
|
||||
-device isa-serial,chardev=charserial1,id=serial1 \
|
||||
@@ -1,356 +0,0 @@
|
||||
From 953440bd12608a20007ee5da5ab69fbbe910bd28 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel P. Berrange <berrange@redhat.com>
|
||||
Date: Mon, 14 Jun 2010 15:53:59 +0100
|
||||
Subject: [PATCH 01/11] Extract the backing store format as well as name, if available
|
||||
|
||||
When QEMU opens a backing store for a QCow2 file, it will
|
||||
normally auto-probe for the format of the backing store,
|
||||
rather than assuming it has the same format as the referencing
|
||||
file. There is a QCow2 extension that allows an explicit format
|
||||
for the backing store to be embedded in the referencing file.
|
||||
This closes the auto-probing security hole in QEMU.
|
||||
|
||||
This backing store format can be useful for libvirt users
|
||||
of virStorageFileGetMetadata, so extract this data and report
|
||||
it.
|
||||
|
||||
QEMU does not require disk image backing store files to be in
|
||||
the same format the file linkee. It will auto-probe the disk
|
||||
format for the backing store when opening it. If the backing
|
||||
store was intended to be a raw file this could be a security
|
||||
hole, because a guest may have written data into its disk that
|
||||
then makes the backing store look like a qcow2 file. If it can
|
||||
trick QEMU into thinking the raw file is a qcow2 file, it can
|
||||
access arbitrary files on the host by adding further backing
|
||||
store links.
|
||||
|
||||
To address this, callers of virStorageFileGetMeta need to be
|
||||
told of the backing store format. If no format is declared,
|
||||
they can make a decision whether to allow format probing or
|
||||
not.
|
||||
---
|
||||
src/util/storage_file.c | 206 +++++++++++++++++++++++++++++++++++++++++------
|
||||
src/util/storage_file.h | 2 +
|
||||
2 files changed, 183 insertions(+), 25 deletions(-)
|
||||
|
||||
diff --git a/src/util/storage_file.c b/src/util/storage_file.c
|
||||
index 0adea40..80f743e 100644
|
||||
--- a/src/util/storage_file.c
|
||||
+++ b/src/util/storage_file.c
|
||||
@@ -78,12 +78,33 @@ struct FileTypeInfo {
|
||||
int qcowCryptOffset; /* Byte offset from start of file
|
||||
* where to find encryption mode,
|
||||
* -1 if encryption is not used */
|
||||
- int (*getBackingStore)(char **res, const unsigned char *buf, size_t buf_size);
|
||||
+ int (*getBackingStore)(char **res, int *format,
|
||||
+ const unsigned char *buf, size_t buf_size);
|
||||
};
|
||||
|
||||
-static int cowGetBackingStore(char **, const unsigned char *, size_t);
|
||||
-static int qcowXGetBackingStore(char **, const unsigned char *, size_t);
|
||||
-static int vmdk4GetBackingStore(char **, const unsigned char *, size_t);
|
||||
+static int cowGetBackingStore(char **, int *,
|
||||
+ const unsigned char *, size_t);
|
||||
+static int qcow1GetBackingStore(char **, int *,
|
||||
+ const unsigned char *, size_t);
|
||||
+static int qcow2GetBackingStore(char **, int *,
|
||||
+ const unsigned char *, size_t);
|
||||
+static int vmdk4GetBackingStore(char **, int *,
|
||||
+ const unsigned char *, size_t);
|
||||
+
|
||||
+#define QCOWX_HDR_VERSION (4)
|
||||
+#define QCOWX_HDR_BACKING_FILE_OFFSET (QCOWX_HDR_VERSION+4)
|
||||
+#define QCOWX_HDR_BACKING_FILE_SIZE (QCOWX_HDR_BACKING_FILE_OFFSET+8)
|
||||
+#define QCOWX_HDR_IMAGE_SIZE (QCOWX_HDR_BACKING_FILE_SIZE+4+4)
|
||||
+
|
||||
+#define QCOW1_HDR_CRYPT (QCOWX_HDR_IMAGE_SIZE+8+1+1)
|
||||
+#define QCOW2_HDR_CRYPT (QCOWX_HDR_IMAGE_SIZE+8)
|
||||
+
|
||||
+#define QCOW1_HDR_TOTAL_SIZE (QCOW1_HDR_CRYPT+4+8)
|
||||
+#define QCOW2_HDR_TOTAL_SIZE (QCOW2_HDR_CRYPT+4+4+8+8+4+4+8)
|
||||
+
|
||||
+#define QCOW2_HDR_EXTENSION_END 0
|
||||
+#define QCOW2_HDR_EXTENSION_BACKING_FORMAT 0xE2792ACA
|
||||
+
|
||||
|
||||
|
||||
static struct FileTypeInfo const fileTypeInfo[] = {
|
||||
@@ -119,11 +140,11 @@ static struct FileTypeInfo const fileTypeInfo[] = {
|
||||
/* QCow */
|
||||
{ VIR_STORAGE_FILE_QCOW, "QFI", NULL,
|
||||
LV_BIG_ENDIAN, 4, 1,
|
||||
- 4+4+8+4+4, 8, 1, 4+4+8+4+4+8+1+1+2, qcowXGetBackingStore },
|
||||
+ QCOWX_HDR_IMAGE_SIZE, 8, 1, QCOW1_HDR_CRYPT, qcow1GetBackingStore },
|
||||
/* QCow 2 */
|
||||
{ VIR_STORAGE_FILE_QCOW2, "QFI", NULL,
|
||||
LV_BIG_ENDIAN, 4, 2,
|
||||
- 4+4+8+4+4, 8, 1, 4+4+8+4+4+8, qcowXGetBackingStore },
|
||||
+ QCOWX_HDR_IMAGE_SIZE, 8, 1, QCOW2_HDR_CRYPT, qcow2GetBackingStore },
|
||||
/* VMDK 3 */
|
||||
/* XXX Untested
|
||||
{ VIR_STORAGE_FILE_VMDK, "COWD", NULL,
|
||||
@@ -142,11 +163,14 @@ static struct FileTypeInfo const fileTypeInfo[] = {
|
||||
|
||||
static int
|
||||
cowGetBackingStore(char **res,
|
||||
+ int *format,
|
||||
const unsigned char *buf,
|
||||
size_t buf_size)
|
||||
{
|
||||
#define COW_FILENAME_MAXLEN 1024
|
||||
*res = NULL;
|
||||
+ *format = VIR_STORAGE_FILE_AUTO;
|
||||
+
|
||||
if (buf_size < 4+4+ COW_FILENAME_MAXLEN)
|
||||
return BACKING_STORE_INVALID;
|
||||
if (buf[4+4] == '\0') /* cow_header_v2.backing_file[0] */
|
||||
@@ -160,31 +184,98 @@ cowGetBackingStore(char **res,
|
||||
return BACKING_STORE_OK;
|
||||
}
|
||||
|
||||
+
|
||||
+static int
|
||||
+qcow2GetBackingStoreFormat(int *format,
|
||||
+ const unsigned char *buf,
|
||||
+ size_t buf_size,
|
||||
+ size_t extension_start,
|
||||
+ size_t extension_end)
|
||||
+{
|
||||
+ size_t offset = extension_start;
|
||||
+
|
||||
+ /*
|
||||
+ * The extensions take format of
|
||||
+ *
|
||||
+ * int32: magic
|
||||
+ * int32: length
|
||||
+ * byte[length]: payload
|
||||
+ *
|
||||
+ * Unknown extensions can be ignored by skipping
|
||||
+ * over "length" bytes in the data stream.
|
||||
+ */
|
||||
+ while (offset < (buf_size-8) &&
|
||||
+ offset < (extension_end-8)) {
|
||||
+ unsigned int magic =
|
||||
+ (buf[offset] << 24) +
|
||||
+ (buf[offset+1] << 16) +
|
||||
+ (buf[offset+2] << 8) +
|
||||
+ (buf[offset+3]);
|
||||
+ unsigned int len =
|
||||
+ (buf[offset+4] << 24) +
|
||||
+ (buf[offset+5] << 16) +
|
||||
+ (buf[offset+6] << 8) +
|
||||
+ (buf[offset+7]);
|
||||
+
|
||||
+ offset += 8;
|
||||
+
|
||||
+ if ((offset + len) < offset)
|
||||
+ break;
|
||||
+
|
||||
+ if ((offset + len) > buf_size)
|
||||
+ break;
|
||||
+
|
||||
+ switch (magic) {
|
||||
+ case QCOW2_HDR_EXTENSION_END:
|
||||
+ goto done;
|
||||
+
|
||||
+ case QCOW2_HDR_EXTENSION_BACKING_FORMAT:
|
||||
+ if (buf[offset+len] != '\0')
|
||||
+ break;
|
||||
+ *format = virStorageFileFormatTypeFromString(
|
||||
+ ((const char *)buf)+offset);
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ offset += len;
|
||||
+ }
|
||||
+
|
||||
+done:
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+
|
||||
static int
|
||||
qcowXGetBackingStore(char **res,
|
||||
+ int *format,
|
||||
const unsigned char *buf,
|
||||
- size_t buf_size)
|
||||
+ size_t buf_size,
|
||||
+ bool isQCow2)
|
||||
{
|
||||
unsigned long long offset;
|
||||
unsigned long size;
|
||||
|
||||
*res = NULL;
|
||||
- if (buf_size < 4+4+8+4)
|
||||
+ if (format)
|
||||
+ *format = VIR_STORAGE_FILE_AUTO;
|
||||
+
|
||||
+ if (buf_size < QCOWX_HDR_BACKING_FILE_OFFSET+8+4)
|
||||
return BACKING_STORE_INVALID;
|
||||
- offset = (((unsigned long long)buf[4+4] << 56)
|
||||
- | ((unsigned long long)buf[4+4+1] << 48)
|
||||
- | ((unsigned long long)buf[4+4+2] << 40)
|
||||
- | ((unsigned long long)buf[4+4+3] << 32)
|
||||
- | ((unsigned long long)buf[4+4+4] << 24)
|
||||
- | ((unsigned long long)buf[4+4+5] << 16)
|
||||
- | ((unsigned long long)buf[4+4+6] << 8)
|
||||
- | buf[4+4+7]); /* QCowHeader.backing_file_offset */
|
||||
+ offset = (((unsigned long long)buf[QCOWX_HDR_BACKING_FILE_OFFSET] << 56)
|
||||
+ | ((unsigned long long)buf[QCOWX_HDR_BACKING_FILE_OFFSET+1] << 48)
|
||||
+ | ((unsigned long long)buf[QCOWX_HDR_BACKING_FILE_OFFSET+2] << 40)
|
||||
+ | ((unsigned long long)buf[QCOWX_HDR_BACKING_FILE_OFFSET+3] << 32)
|
||||
+ | ((unsigned long long)buf[QCOWX_HDR_BACKING_FILE_OFFSET+4] << 24)
|
||||
+ | ((unsigned long long)buf[QCOWX_HDR_BACKING_FILE_OFFSET+5] << 16)
|
||||
+ | ((unsigned long long)buf[QCOWX_HDR_BACKING_FILE_OFFSET+6] << 8)
|
||||
+ | buf[QCOWX_HDR_BACKING_FILE_OFFSET+7]); /* QCowHeader.backing_file_offset */
|
||||
if (offset > buf_size)
|
||||
return BACKING_STORE_INVALID;
|
||||
- size = ((buf[4+4+8] << 24)
|
||||
- | (buf[4+4+8+1] << 16)
|
||||
- | (buf[4+4+8+2] << 8)
|
||||
- | buf[4+4+8+3]); /* QCowHeader.backing_file_size */
|
||||
+ size = ((buf[QCOWX_HDR_BACKING_FILE_SIZE] << 24)
|
||||
+ | (buf[QCOWX_HDR_BACKING_FILE_SIZE+1] << 16)
|
||||
+ | (buf[QCOWX_HDR_BACKING_FILE_SIZE+2] << 8)
|
||||
+ | buf[QCOWX_HDR_BACKING_FILE_SIZE+3]); /* QCowHeader.backing_file_size */
|
||||
if (size == 0)
|
||||
return BACKING_STORE_OK;
|
||||
if (offset + size > buf_size || offset + size < offset)
|
||||
@@ -197,12 +288,63 @@ qcowXGetBackingStore(char **res,
|
||||
}
|
||||
memcpy(*res, buf + offset, size);
|
||||
(*res)[size] = '\0';
|
||||
+
|
||||
+ /*
|
||||
+ * Traditionally QCow2 files had a layout of
|
||||
+ *
|
||||
+ * [header]
|
||||
+ * [backingStoreName]
|
||||
+ *
|
||||
+ * Although the backingStoreName typically followed
|
||||
+ * the header immediately, this was not required by
|
||||
+ * the format. By specifying a higher byte offset for
|
||||
+ * the backing file offset in the header, it was
|
||||
+ * possible to leave space between the header and
|
||||
+ * start of backingStore.
|
||||
+ *
|
||||
+ * This hack is now used to store extensions to the
|
||||
+ * qcow2 format:
|
||||
+ *
|
||||
+ * [header]
|
||||
+ * [extensions]
|
||||
+ * [backingStoreName]
|
||||
+ *
|
||||
+ * Thus the file region to search for extensions is
|
||||
+ * between the end of the header (QCOW2_HDR_TOTAL_SIZE)
|
||||
+ * and the start of the backingStoreName (offset)
|
||||
+ */
|
||||
+ if (isQCow2)
|
||||
+ qcow2GetBackingStoreFormat(format, buf, buf_size, QCOW2_HDR_TOTAL_SIZE, offset);
|
||||
+
|
||||
return BACKING_STORE_OK;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
+qcow1GetBackingStore(char **res,
|
||||
+ int *format,
|
||||
+ const unsigned char *buf,
|
||||
+ size_t buf_size)
|
||||
+{
|
||||
+ /* QCow1 doesn't have the extensions capability
|
||||
+ * used to store backing format */
|
||||
+ *format = VIR_STORAGE_FILE_AUTO;
|
||||
+ return qcowXGetBackingStore(res, NULL, buf, buf_size, false);
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+qcow2GetBackingStore(char **res,
|
||||
+ int *format,
|
||||
+ const unsigned char *buf,
|
||||
+ size_t buf_size)
|
||||
+{
|
||||
+ return qcowXGetBackingStore(res, format, buf, buf_size, true);
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static int
|
||||
vmdk4GetBackingStore(char **res,
|
||||
+ int *format,
|
||||
const unsigned char *buf,
|
||||
size_t buf_size)
|
||||
{
|
||||
@@ -212,6 +354,14 @@ vmdk4GetBackingStore(char **res,
|
||||
size_t len;
|
||||
|
||||
*res = NULL;
|
||||
+ /*
|
||||
+ * Technically this should have been VMDK, since
|
||||
+ * VMDK spec / VMWare impl only support VMDK backed
|
||||
+ * by VMDK. QEMU isn't following this though and
|
||||
+ * does probing on VMDK backing files, hence we set
|
||||
+ * AUTO
|
||||
+ */
|
||||
+ *format = VIR_STORAGE_FILE_AUTO;
|
||||
|
||||
if (buf_size <= 0x200)
|
||||
return BACKING_STORE_INVALID;
|
||||
@@ -358,9 +508,12 @@ virStorageFileGetMetadataFromFD(const char *path,
|
||||
/* Validation passed, we know the file format now */
|
||||
meta->format = fileTypeInfo[i].type;
|
||||
if (fileTypeInfo[i].getBackingStore != NULL) {
|
||||
- char *base;
|
||||
+ char *backing;
|
||||
+ int backingFormat;
|
||||
|
||||
- switch (fileTypeInfo[i].getBackingStore(&base, head, len)) {
|
||||
+ switch (fileTypeInfo[i].getBackingStore(&backing,
|
||||
+ &backingFormat,
|
||||
+ head, len)) {
|
||||
case BACKING_STORE_OK:
|
||||
break;
|
||||
|
||||
@@ -370,13 +523,16 @@ virStorageFileGetMetadataFromFD(const char *path,
|
||||
case BACKING_STORE_ERROR:
|
||||
return -1;
|
||||
}
|
||||
- if (base != NULL) {
|
||||
- meta->backingStore = absolutePathFromBaseFile(path, base);
|
||||
- VIR_FREE(base);
|
||||
+ if (backing != NULL) {
|
||||
+ meta->backingStore = absolutePathFromBaseFile(path, backing);
|
||||
+ VIR_FREE(backing);
|
||||
if (meta->backingStore == NULL) {
|
||||
virReportOOMError();
|
||||
return -1;
|
||||
}
|
||||
+ meta->backingStoreFormat = backingFormat;
|
||||
+ } else {
|
||||
+ meta->backingStoreFormat = VIR_STORAGE_FILE_AUTO;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
diff --git a/src/util/storage_file.h b/src/util/storage_file.h
|
||||
index 58533ee..6328ba7 100644
|
||||
--- a/src/util/storage_file.h
|
||||
+++ b/src/util/storage_file.h
|
||||
@@ -28,6 +28,7 @@
|
||||
# include <stdbool.h>
|
||||
|
||||
enum virStorageFileFormat {
|
||||
+ VIR_STORAGE_FILE_AUTO = -1,
|
||||
VIR_STORAGE_FILE_RAW = 0,
|
||||
VIR_STORAGE_FILE_DIR,
|
||||
VIR_STORAGE_FILE_BOCHS,
|
||||
@@ -47,6 +48,7 @@ VIR_ENUM_DECL(virStorageFileFormat);
|
||||
typedef struct _virStorageFileMetadata {
|
||||
int format;
|
||||
char *backingStore;
|
||||
+ int backingStoreFormat;
|
||||
unsigned long long capacity;
|
||||
bool encrypted;
|
||||
} virStorageFileMetadata;
|
||||
--
|
||||
1.7.1.1
|
||||
|
||||
@@ -1,159 +0,0 @@
|
||||
From cab428b1d4d432965cee6f5afb67265557706715 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel P. Berrange <berrange@redhat.com>
|
||||
Date: Mon, 14 Jun 2010 16:39:32 +0100
|
||||
Subject: [PATCH 02/11] Remove 'type' field from FileTypeInfo struct
|
||||
|
||||
Instead of including a field in FileTypeInfo struct for the
|
||||
disk format, rely on the array index matching the format.
|
||||
Use verify() to assert the correct number of elements in the
|
||||
array.
|
||||
|
||||
* src/util/storage_file.c: remove type field from FileTypeInfo
|
||||
---
|
||||
src/util/storage_file.c | 108 +++++++++++++++++++++++-----------------------
|
||||
1 files changed, 54 insertions(+), 54 deletions(-)
|
||||
|
||||
diff --git a/src/util/storage_file.c b/src/util/storage_file.c
|
||||
index 80f743e..df0e3a1 100644
|
||||
--- a/src/util/storage_file.c
|
||||
+++ b/src/util/storage_file.c
|
||||
@@ -58,7 +58,6 @@ enum {
|
||||
|
||||
/* Either 'magic' or 'extension' *must* be provided */
|
||||
struct FileTypeInfo {
|
||||
- int type; /* One of the constants above */
|
||||
const char *magic; /* Optional string of file magic
|
||||
* to check at head of file */
|
||||
const char *extension; /* Optional file extension to check */
|
||||
@@ -108,58 +107,59 @@ static int vmdk4GetBackingStore(char **, int *,
|
||||
|
||||
|
||||
static struct FileTypeInfo const fileTypeInfo[] = {
|
||||
- /* Bochs */
|
||||
- /* XXX Untested
|
||||
- { VIR_STORAGE_FILE_BOCHS, "Bochs Virtual HD Image", NULL,
|
||||
- LV_LITTLE_ENDIAN, 64, 0x20000,
|
||||
- 32+16+16+4+4+4+4+4, 8, 1, -1, NULL },*/
|
||||
- /* CLoop */
|
||||
- /* XXX Untested
|
||||
- { VIR_STORAGE_VOL_CLOOP, "#!/bin/sh\n#V2.0 Format\nmodprobe cloop file=$0 && mount -r -t iso9660 /dev/cloop $1\n", NULL,
|
||||
- LV_LITTLE_ENDIAN, -1, 0,
|
||||
- -1, 0, 0, -1, NULL }, */
|
||||
- /* Cow */
|
||||
- { VIR_STORAGE_FILE_COW, "OOOM", NULL,
|
||||
- LV_BIG_ENDIAN, 4, 2,
|
||||
- 4+4+1024+4, 8, 1, -1, cowGetBackingStore },
|
||||
- /* DMG */
|
||||
- /* XXX QEMU says there's no magic for dmg, but we should check... */
|
||||
- { VIR_STORAGE_FILE_DMG, NULL, ".dmg",
|
||||
- 0, -1, 0,
|
||||
- -1, 0, 0, -1, NULL },
|
||||
- /* XXX there's probably some magic for iso we can validate too... */
|
||||
- { VIR_STORAGE_FILE_ISO, NULL, ".iso",
|
||||
- 0, -1, 0,
|
||||
- -1, 0, 0, -1, NULL },
|
||||
- /* Parallels */
|
||||
- /* XXX Untested
|
||||
- { VIR_STORAGE_FILE_PARALLELS, "WithoutFreeSpace", NULL,
|
||||
- LV_LITTLE_ENDIAN, 16, 2,
|
||||
- 16+4+4+4+4, 4, 512, -1, NULL },
|
||||
- */
|
||||
- /* QCow */
|
||||
- { VIR_STORAGE_FILE_QCOW, "QFI", NULL,
|
||||
- LV_BIG_ENDIAN, 4, 1,
|
||||
- QCOWX_HDR_IMAGE_SIZE, 8, 1, QCOW1_HDR_CRYPT, qcow1GetBackingStore },
|
||||
- /* QCow 2 */
|
||||
- { VIR_STORAGE_FILE_QCOW2, "QFI", NULL,
|
||||
- LV_BIG_ENDIAN, 4, 2,
|
||||
- QCOWX_HDR_IMAGE_SIZE, 8, 1, QCOW2_HDR_CRYPT, qcow2GetBackingStore },
|
||||
- /* VMDK 3 */
|
||||
- /* XXX Untested
|
||||
- { VIR_STORAGE_FILE_VMDK, "COWD", NULL,
|
||||
- LV_LITTLE_ENDIAN, 4, 1,
|
||||
- 4+4+4, 4, 512, -1, NULL },
|
||||
- */
|
||||
- /* VMDK 4 */
|
||||
- { VIR_STORAGE_FILE_VMDK, "KDMV", NULL,
|
||||
- LV_LITTLE_ENDIAN, 4, 1,
|
||||
- 4+4+4, 8, 512, -1, vmdk4GetBackingStore },
|
||||
- /* Connectix / VirtualPC */
|
||||
- { VIR_STORAGE_FILE_VPC, "conectix", NULL,
|
||||
- LV_BIG_ENDIAN, 12, 0x10000,
|
||||
- 8 + 4 + 4 + 8 + 4 + 4 + 2 + 2 + 4, 8, 1, -1, NULL},
|
||||
+ [VIR_STORAGE_FILE_RAW] = { NULL, NULL, LV_LITTLE_ENDIAN, -1, 0, 0, 0, 0, 0, NULL },
|
||||
+ [VIR_STORAGE_FILE_DIR] = { NULL, NULL, LV_LITTLE_ENDIAN, -1, 0, 0, 0, 0, 0, NULL },
|
||||
+ [VIR_STORAGE_FILE_BOCHS] = {
|
||||
+ /*"Bochs Virtual HD Image", */ /* Untested */ NULL,
|
||||
+ NULL,
|
||||
+ LV_LITTLE_ENDIAN, 64, 0x20000,
|
||||
+ 32+16+16+4+4+4+4+4, 8, 1, -1, NULL
|
||||
+ },
|
||||
+ [VIR_STORAGE_FILE_CLOOP] = {
|
||||
+ /*"#!/bin/sh\n#V2.0 Format\nmodprobe cloop file=$0 && mount -r -t iso9660 /dev/cloop $1\n", */ /* Untested */ NULL,
|
||||
+ NULL,
|
||||
+ LV_LITTLE_ENDIAN, -1, 0,
|
||||
+ -1, 0, 0, -1, NULL
|
||||
+ },
|
||||
+ [VIR_STORAGE_FILE_COW] = {
|
||||
+ "OOOM", NULL,
|
||||
+ LV_BIG_ENDIAN, 4, 2,
|
||||
+ 4+4+1024+4, 8, 1, -1, cowGetBackingStore
|
||||
+ },
|
||||
+ [VIR_STORAGE_FILE_DMG] = {
|
||||
+ NULL, /* XXX QEMU says there's no magic for dmg, but we should check... */
|
||||
+ ".dmg",
|
||||
+ 0, -1, 0,
|
||||
+ -1, 0, 0, -1, NULL
|
||||
+ },
|
||||
+ [VIR_STORAGE_FILE_ISO] = {
|
||||
+ NULL, /* XXX there's probably some magic for iso we can validate too... */
|
||||
+ ".iso",
|
||||
+ 0, -1, 0,
|
||||
+ -1, 0, 0, -1, NULL
|
||||
+ },
|
||||
+ [VIR_STORAGE_FILE_QCOW] = {
|
||||
+ "QFI", NULL,
|
||||
+ LV_BIG_ENDIAN, 4, 1,
|
||||
+ QCOWX_HDR_IMAGE_SIZE, 8, 1, QCOW1_HDR_CRYPT, qcow1GetBackingStore,
|
||||
+ },
|
||||
+ [VIR_STORAGE_FILE_QCOW2] = {
|
||||
+ "QFI", NULL,
|
||||
+ LV_BIG_ENDIAN, 4, 2,
|
||||
+ QCOWX_HDR_IMAGE_SIZE, 8, 1, QCOW2_HDR_CRYPT, qcow2GetBackingStore,
|
||||
+ },
|
||||
+ [VIR_STORAGE_FILE_VMDK] = {
|
||||
+ "KDMV", NULL,
|
||||
+ LV_LITTLE_ENDIAN, 4, 1,
|
||||
+ 4+4+4, 8, 512, -1, vmdk4GetBackingStore
|
||||
+ },
|
||||
+ [VIR_STORAGE_FILE_VPC] = {
|
||||
+ "conectix", NULL,
|
||||
+ LV_BIG_ENDIAN, 12, 0x10000,
|
||||
+ 8 + 4 + 4 + 8 + 4 + 4 + 2 + 2 + 4, 8, 1, -1, NULL
|
||||
+ },
|
||||
};
|
||||
+verify(ARRAY_CARDINALITY(fileTypeInfo) == VIR_STORAGE_FILE_LAST);
|
||||
|
||||
static int
|
||||
cowGetBackingStore(char **res,
|
||||
@@ -506,7 +506,7 @@ virStorageFileGetMetadataFromFD(const char *path,
|
||||
}
|
||||
|
||||
/* Validation passed, we know the file format now */
|
||||
- meta->format = fileTypeInfo[i].type;
|
||||
+ meta->format = i;
|
||||
if (fileTypeInfo[i].getBackingStore != NULL) {
|
||||
char *backing;
|
||||
int backingFormat;
|
||||
@@ -546,7 +546,7 @@ virStorageFileGetMetadataFromFD(const char *path,
|
||||
if (!virFileHasSuffix(path, fileTypeInfo[i].extension))
|
||||
continue;
|
||||
|
||||
- meta->format = fileTypeInfo[i].type;
|
||||
+ meta->format = i;
|
||||
return 0;
|
||||
}
|
||||
|
||||
--
|
||||
1.7.1.1
|
||||
|
||||
@@ -1,585 +0,0 @@
|
||||
From 57482ca0be29e9e92e242c9acb577e0b770c01d1 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel P. Berrange <berrange@redhat.com>
|
||||
Date: Tue, 15 Jun 2010 14:58:10 +0100
|
||||
Subject: [PATCH 03/11] Refactor virStorageFileGetMetadataFromFD to separate functionality
|
||||
|
||||
The virStorageFileGetMetadataFromFD did two jobs in one. First
|
||||
it probed for storage type, then it extracted metadata for the
|
||||
type. It is desirable to be able to separate these jobs, allowing
|
||||
probing without querying metadata, and querying metadata without
|
||||
probing.
|
||||
|
||||
To prepare for this, split out probing code into a new pair of
|
||||
methods
|
||||
|
||||
virStorageFileProbeFormatFromFD
|
||||
virStorageFileProbeFormat
|
||||
|
||||
* src/util/storage_file.c, src/util/storage_file.h,
|
||||
src/libvirt_private.syms: Introduce virStorageFileProbeFormat
|
||||
and virStorageFileProbeFormatFromFD
|
||||
---
|
||||
src/libvirt_private.syms | 2 +
|
||||
src/util/storage_file.c | 460 +++++++++++++++++++++++++++++++++-------------
|
||||
src/util/storage_file.h | 4 +
|
||||
3 files changed, 335 insertions(+), 131 deletions(-)
|
||||
|
||||
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
|
||||
index 778ceb1..4607f49 100644
|
||||
--- a/src/libvirt_private.syms
|
||||
+++ b/src/libvirt_private.syms
|
||||
@@ -628,6 +628,8 @@ virStorageGenerateQcowPassphrase;
|
||||
# storage_file.h
|
||||
virStorageFileFormatTypeToString;
|
||||
virStorageFileFormatTypeFromString;
|
||||
+virStorageFileProbeFormat;
|
||||
+virStorageFileProbeFormatFromFD;
|
||||
virStorageFileGetMetadata;
|
||||
virStorageFileGetMetadataFromFD;
|
||||
virStorageFileIsSharedFS;
|
||||
diff --git a/src/util/storage_file.c b/src/util/storage_file.c
|
||||
index df0e3a1..221268b 100644
|
||||
--- a/src/util/storage_file.c
|
||||
+++ b/src/util/storage_file.c
|
||||
@@ -104,6 +104,9 @@ static int vmdk4GetBackingStore(char **, int *,
|
||||
#define QCOW2_HDR_EXTENSION_END 0
|
||||
#define QCOW2_HDR_EXTENSION_BACKING_FORMAT 0xE2792ACA
|
||||
|
||||
+/* VMDK needs at least this to find backing store,
|
||||
+ * other formats are less */
|
||||
+#define STORAGE_MAX_HEAD (20*512)
|
||||
|
||||
|
||||
static struct FileTypeInfo const fileTypeInfo[] = {
|
||||
@@ -349,9 +352,14 @@ vmdk4GetBackingStore(char **res,
|
||||
size_t buf_size)
|
||||
{
|
||||
static const char prefix[] = "parentFileNameHint=\"";
|
||||
-
|
||||
- char desc[20*512 + 1], *start, *end;
|
||||
+ char *desc, *start, *end;
|
||||
size_t len;
|
||||
+ int ret = BACKING_STORE_ERROR;
|
||||
+
|
||||
+ if (VIR_ALLOC_N(desc, STORAGE_MAX_HEAD + 1) < 0) {
|
||||
+ virReportOOMError();
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
|
||||
*res = NULL;
|
||||
/*
|
||||
@@ -363,29 +371,42 @@ vmdk4GetBackingStore(char **res,
|
||||
*/
|
||||
*format = VIR_STORAGE_FILE_AUTO;
|
||||
|
||||
- if (buf_size <= 0x200)
|
||||
- return BACKING_STORE_INVALID;
|
||||
+ if (buf_size <= 0x200) {
|
||||
+ ret = BACKING_STORE_INVALID;
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
len = buf_size - 0x200;
|
||||
- if (len > sizeof(desc) - 1)
|
||||
- len = sizeof(desc) - 1;
|
||||
+ if (len > STORAGE_MAX_HEAD)
|
||||
+ len = STORAGE_MAX_HEAD;
|
||||
memcpy(desc, buf + 0x200, len);
|
||||
desc[len] = '\0';
|
||||
start = strstr(desc, prefix);
|
||||
- if (start == NULL)
|
||||
- return BACKING_STORE_OK;
|
||||
+ if (start == NULL) {
|
||||
+ ret = BACKING_STORE_OK;
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
start += strlen(prefix);
|
||||
end = strchr(start, '"');
|
||||
- if (end == NULL)
|
||||
- return BACKING_STORE_INVALID;
|
||||
- if (end == start)
|
||||
- return BACKING_STORE_OK;
|
||||
+ if (end == NULL) {
|
||||
+ ret = BACKING_STORE_INVALID;
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+ if (end == start) {
|
||||
+ ret = BACKING_STORE_OK;
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
*end = '\0';
|
||||
*res = strdup(start);
|
||||
if (*res == NULL) {
|
||||
virReportOOMError();
|
||||
- return BACKING_STORE_ERROR;
|
||||
+ goto cleanup;
|
||||
}
|
||||
- return BACKING_STORE_OK;
|
||||
+
|
||||
+ ret = BACKING_STORE_OK;
|
||||
+
|
||||
+cleanup:
|
||||
+ VIR_FREE(desc);
|
||||
+ return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -411,148 +432,325 @@ absolutePathFromBaseFile(const char *base_file, const char *path)
|
||||
return res;
|
||||
}
|
||||
|
||||
-/**
|
||||
- * Probe the header of a file to determine what type of disk image
|
||||
- * it is, and info about its capacity if available.
|
||||
- */
|
||||
-int
|
||||
-virStorageFileGetMetadataFromFD(const char *path,
|
||||
- int fd,
|
||||
- virStorageFileMetadata *meta)
|
||||
+
|
||||
+static bool
|
||||
+virStorageFileMatchesMagic(int format,
|
||||
+ unsigned char *buf,
|
||||
+ size_t buflen)
|
||||
{
|
||||
- unsigned char head[20*512]; /* vmdk4GetBackingStore needs this much. */
|
||||
- int len, i;
|
||||
+ int mlen;
|
||||
|
||||
- memset(meta, 0, sizeof (*meta));
|
||||
+ if (fileTypeInfo[format].magic == NULL)
|
||||
+ return false;
|
||||
|
||||
- /* If all else fails, call it a raw file */
|
||||
- meta->format = VIR_STORAGE_FILE_RAW;
|
||||
+ /* Validate magic data */
|
||||
+ mlen = strlen(fileTypeInfo[format].magic);
|
||||
+ if (mlen > buflen)
|
||||
+ return false;
|
||||
|
||||
- if ((len = read(fd, head, sizeof(head))) < 0) {
|
||||
- virReportSystemError(errno, _("cannot read header '%s'"), path);
|
||||
- return -1;
|
||||
+ if (memcmp(buf, fileTypeInfo[format].magic, mlen) != 0)
|
||||
+ return false;
|
||||
+
|
||||
+ return true;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static bool
|
||||
+virStorageFileMatchesExtension(int format,
|
||||
+ const char *path)
|
||||
+{
|
||||
+ if (fileTypeInfo[format].extension == NULL)
|
||||
+ return false;
|
||||
+
|
||||
+ if (virFileHasSuffix(path, fileTypeInfo[format].extension))
|
||||
+ return true;
|
||||
+
|
||||
+ return false;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static bool
|
||||
+virStorageFileMatchesVersion(int format,
|
||||
+ unsigned char *buf,
|
||||
+ size_t buflen)
|
||||
+{
|
||||
+ int version;
|
||||
+
|
||||
+ /* Validate version number info */
|
||||
+ if (fileTypeInfo[format].versionOffset == -1)
|
||||
+ return false;
|
||||
+
|
||||
+ if ((fileTypeInfo[format].versionOffset + 4) > buflen)
|
||||
+ return false;
|
||||
+
|
||||
+ if (fileTypeInfo[format].endian == LV_LITTLE_ENDIAN) {
|
||||
+ version =
|
||||
+ (buf[fileTypeInfo[format].versionOffset+3] << 24) |
|
||||
+ (buf[fileTypeInfo[format].versionOffset+2] << 16) |
|
||||
+ (buf[fileTypeInfo[format].versionOffset+1] << 8) |
|
||||
+ (buf[fileTypeInfo[format].versionOffset]);
|
||||
+ } else {
|
||||
+ version =
|
||||
+ (buf[fileTypeInfo[format].versionOffset] << 24) |
|
||||
+ (buf[fileTypeInfo[format].versionOffset+1] << 16) |
|
||||
+ (buf[fileTypeInfo[format].versionOffset+2] << 8) |
|
||||
+ (buf[fileTypeInfo[format].versionOffset+3]);
|
||||
}
|
||||
+ if (version != fileTypeInfo[format].versionNumber)
|
||||
+ return false;
|
||||
|
||||
- /* First check file magic */
|
||||
- for (i = 0 ; i < ARRAY_CARDINALITY(fileTypeInfo) ; i++) {
|
||||
- int mlen;
|
||||
-
|
||||
- if (fileTypeInfo[i].magic == NULL)
|
||||
- continue;
|
||||
-
|
||||
- /* Validate magic data */
|
||||
- mlen = strlen(fileTypeInfo[i].magic);
|
||||
- if (mlen > len)
|
||||
- continue;
|
||||
- if (memcmp(head, fileTypeInfo[i].magic, mlen) != 0)
|
||||
- continue;
|
||||
-
|
||||
- /* Validate version number info */
|
||||
- if (fileTypeInfo[i].versionNumber != -1) {
|
||||
- int version;
|
||||
-
|
||||
- if (fileTypeInfo[i].endian == LV_LITTLE_ENDIAN) {
|
||||
- version = (head[fileTypeInfo[i].versionOffset+3] << 24) |
|
||||
- (head[fileTypeInfo[i].versionOffset+2] << 16) |
|
||||
- (head[fileTypeInfo[i].versionOffset+1] << 8) |
|
||||
- head[fileTypeInfo[i].versionOffset];
|
||||
- } else {
|
||||
- version = (head[fileTypeInfo[i].versionOffset] << 24) |
|
||||
- (head[fileTypeInfo[i].versionOffset+1] << 16) |
|
||||
- (head[fileTypeInfo[i].versionOffset+2] << 8) |
|
||||
- head[fileTypeInfo[i].versionOffset+3];
|
||||
- }
|
||||
- if (version != fileTypeInfo[i].versionNumber)
|
||||
- continue;
|
||||
- }
|
||||
+ return true;
|
||||
+}
|
||||
|
||||
- /* Optionally extract capacity from file */
|
||||
- if (fileTypeInfo[i].sizeOffset != -1) {
|
||||
- if (fileTypeInfo[i].endian == LV_LITTLE_ENDIAN) {
|
||||
- meta->capacity =
|
||||
- ((unsigned long long)head[fileTypeInfo[i].sizeOffset+7] << 56) |
|
||||
- ((unsigned long long)head[fileTypeInfo[i].sizeOffset+6] << 48) |
|
||||
- ((unsigned long long)head[fileTypeInfo[i].sizeOffset+5] << 40) |
|
||||
- ((unsigned long long)head[fileTypeInfo[i].sizeOffset+4] << 32) |
|
||||
- ((unsigned long long)head[fileTypeInfo[i].sizeOffset+3] << 24) |
|
||||
- ((unsigned long long)head[fileTypeInfo[i].sizeOffset+2] << 16) |
|
||||
- ((unsigned long long)head[fileTypeInfo[i].sizeOffset+1] << 8) |
|
||||
- ((unsigned long long)head[fileTypeInfo[i].sizeOffset]);
|
||||
- } else {
|
||||
- meta->capacity =
|
||||
- ((unsigned long long)head[fileTypeInfo[i].sizeOffset] << 56) |
|
||||
- ((unsigned long long)head[fileTypeInfo[i].sizeOffset+1] << 48) |
|
||||
- ((unsigned long long)head[fileTypeInfo[i].sizeOffset+2] << 40) |
|
||||
- ((unsigned long long)head[fileTypeInfo[i].sizeOffset+3] << 32) |
|
||||
- ((unsigned long long)head[fileTypeInfo[i].sizeOffset+4] << 24) |
|
||||
- ((unsigned long long)head[fileTypeInfo[i].sizeOffset+5] << 16) |
|
||||
- ((unsigned long long)head[fileTypeInfo[i].sizeOffset+6] << 8) |
|
||||
- ((unsigned long long)head[fileTypeInfo[i].sizeOffset+7]);
|
||||
- }
|
||||
- /* Avoid unlikely, but theoretically possible overflow */
|
||||
- if (meta->capacity > (ULLONG_MAX / fileTypeInfo[i].sizeMultiplier))
|
||||
- continue;
|
||||
- meta->capacity *= fileTypeInfo[i].sizeMultiplier;
|
||||
- }
|
||||
|
||||
- if (fileTypeInfo[i].qcowCryptOffset != -1) {
|
||||
- int crypt_format;
|
||||
+static int
|
||||
+virStorageFileGetMetadataFromBuf(int format,
|
||||
+ const char *path,
|
||||
+ unsigned char *buf,
|
||||
+ size_t buflen,
|
||||
+ virStorageFileMetadata *meta)
|
||||
+{
|
||||
+ /* XXX we should consider moving virStorageBackendUpdateVolInfo
|
||||
+ * code into this method, for non-magic files
|
||||
+ */
|
||||
+ if (!fileTypeInfo[format].magic) {
|
||||
+ return 0;
|
||||
+ }
|
||||
|
||||
- crypt_format = (head[fileTypeInfo[i].qcowCryptOffset] << 24) |
|
||||
- (head[fileTypeInfo[i].qcowCryptOffset+1] << 16) |
|
||||
- (head[fileTypeInfo[i].qcowCryptOffset+2] << 8) |
|
||||
- head[fileTypeInfo[i].qcowCryptOffset+3];
|
||||
- meta->encrypted = crypt_format != 0;
|
||||
+ /* Optionally extract capacity from file */
|
||||
+ if (fileTypeInfo[format].sizeOffset != -1) {
|
||||
+ if ((fileTypeInfo[format].sizeOffset + 8) > buflen)
|
||||
+ return 1;
|
||||
+
|
||||
+ if (fileTypeInfo[format].endian == LV_LITTLE_ENDIAN) {
|
||||
+ meta->capacity =
|
||||
+ ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+7] << 56) |
|
||||
+ ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+6] << 48) |
|
||||
+ ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+5] << 40) |
|
||||
+ ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+4] << 32) |
|
||||
+ ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+3] << 24) |
|
||||
+ ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+2] << 16) |
|
||||
+ ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+1] << 8) |
|
||||
+ ((unsigned long long)buf[fileTypeInfo[format].sizeOffset]);
|
||||
+ } else {
|
||||
+ meta->capacity =
|
||||
+ ((unsigned long long)buf[fileTypeInfo[format].sizeOffset] << 56) |
|
||||
+ ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+1] << 48) |
|
||||
+ ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+2] << 40) |
|
||||
+ ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+3] << 32) |
|
||||
+ ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+4] << 24) |
|
||||
+ ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+5] << 16) |
|
||||
+ ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+6] << 8) |
|
||||
+ ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+7]);
|
||||
}
|
||||
+ /* Avoid unlikely, but theoretically possible overflow */
|
||||
+ if (meta->capacity > (ULLONG_MAX / fileTypeInfo[format].sizeMultiplier))
|
||||
+ return 1;
|
||||
+ meta->capacity *= fileTypeInfo[format].sizeMultiplier;
|
||||
+ }
|
||||
|
||||
- /* Validation passed, we know the file format now */
|
||||
- meta->format = i;
|
||||
- if (fileTypeInfo[i].getBackingStore != NULL) {
|
||||
- char *backing;
|
||||
- int backingFormat;
|
||||
+ if (fileTypeInfo[format].qcowCryptOffset != -1) {
|
||||
+ int crypt_format;
|
||||
|
||||
- switch (fileTypeInfo[i].getBackingStore(&backing,
|
||||
- &backingFormat,
|
||||
- head, len)) {
|
||||
- case BACKING_STORE_OK:
|
||||
- break;
|
||||
+ crypt_format =
|
||||
+ (buf[fileTypeInfo[format].qcowCryptOffset] << 24) |
|
||||
+ (buf[fileTypeInfo[format].qcowCryptOffset+1] << 16) |
|
||||
+ (buf[fileTypeInfo[format].qcowCryptOffset+2] << 8) |
|
||||
+ (buf[fileTypeInfo[format].qcowCryptOffset+3]);
|
||||
+ meta->encrypted = crypt_format != 0;
|
||||
+ }
|
||||
|
||||
- case BACKING_STORE_INVALID:
|
||||
- continue;
|
||||
+ if (fileTypeInfo[format].getBackingStore != NULL) {
|
||||
+ char *backing;
|
||||
+ int backingFormat;
|
||||
+ int ret = fileTypeInfo[format].getBackingStore(&backing,
|
||||
+ &backingFormat,
|
||||
+ buf, buflen);
|
||||
+ if (ret == BACKING_STORE_INVALID)
|
||||
+ return 1;
|
||||
+
|
||||
+ if (ret == BACKING_STORE_ERROR)
|
||||
+ return -1;
|
||||
|
||||
- case BACKING_STORE_ERROR:
|
||||
+ if (backing != NULL) {
|
||||
+ meta->backingStore = absolutePathFromBaseFile(path, backing);
|
||||
+ VIR_FREE(backing);
|
||||
+ if (meta->backingStore == NULL) {
|
||||
+ virReportOOMError();
|
||||
return -1;
|
||||
}
|
||||
- if (backing != NULL) {
|
||||
- meta->backingStore = absolutePathFromBaseFile(path, backing);
|
||||
- VIR_FREE(backing);
|
||||
- if (meta->backingStore == NULL) {
|
||||
- virReportOOMError();
|
||||
- return -1;
|
||||
- }
|
||||
- meta->backingStoreFormat = backingFormat;
|
||||
- } else {
|
||||
- meta->backingStoreFormat = VIR_STORAGE_FILE_AUTO;
|
||||
- }
|
||||
+ meta->backingStoreFormat = backingFormat;
|
||||
+ } else {
|
||||
+ meta->backingStore = NULL;
|
||||
+ meta->backingStoreFormat = VIR_STORAGE_FILE_AUTO;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static int
|
||||
+virStorageFileProbeFormatFromBuf(const char *path,
|
||||
+ unsigned char *buf,
|
||||
+ size_t buflen)
|
||||
+{
|
||||
+ int format = VIR_STORAGE_FILE_RAW;
|
||||
+ int i;
|
||||
+
|
||||
+ /* First check file magic */
|
||||
+ for (i = 0 ; i < VIR_STORAGE_FILE_LAST ; i++) {
|
||||
+ if (virStorageFileMatchesMagic(i, buf, buflen) &&
|
||||
+ virStorageFileMatchesVersion(i, buf, buflen)) {
|
||||
+ format = i;
|
||||
+ goto cleanup;
|
||||
}
|
||||
- return 0;
|
||||
}
|
||||
|
||||
/* No magic, so check file extension */
|
||||
- for (i = 0 ; i < ARRAY_CARDINALITY(fileTypeInfo) ; i++) {
|
||||
- if (fileTypeInfo[i].extension == NULL)
|
||||
- continue;
|
||||
+ for (i = 0 ; i < VIR_STORAGE_FILE_LAST ; i++) {
|
||||
+ if (virStorageFileMatchesExtension(i, path)) {
|
||||
+ format = i;
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+ }
|
||||
|
||||
- if (!virFileHasSuffix(path, fileTypeInfo[i].extension))
|
||||
- continue;
|
||||
+cleanup:
|
||||
+ return format;
|
||||
+}
|
||||
|
||||
- meta->format = i;
|
||||
- return 0;
|
||||
+
|
||||
+/**
|
||||
+ * virStorageFileProbeFormatFromFD:
|
||||
+ *
|
||||
+ * Probe for the format of 'fd' (which is an open file descriptor
|
||||
+ * pointing to 'path'), returning the detected disk format.
|
||||
+ *
|
||||
+ * Callers are advised never to trust the returned 'format'
|
||||
+ * unless it is listed as VIR_STORAGE_FILE_RAW, since a
|
||||
+ * malicious guest can turn a file into any other non-raw
|
||||
+ * format at will.
|
||||
+ *
|
||||
+ * Best option: Don't use this function
|
||||
+ */
|
||||
+int
|
||||
+virStorageFileProbeFormatFromFD(const char *path, int fd)
|
||||
+{
|
||||
+ unsigned char *head;
|
||||
+ ssize_t len = STORAGE_MAX_HEAD;
|
||||
+ int ret = -1;
|
||||
+
|
||||
+ if (VIR_ALLOC_N(head, len) < 0) {
|
||||
+ virReportOOMError();
|
||||
+ return -1;
|
||||
}
|
||||
|
||||
- return 0;
|
||||
+ if (lseek(fd, 0, SEEK_SET) == (off_t)-1) {
|
||||
+ virReportSystemError(errno, _("cannot set to start of '%s'"), path);
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+
|
||||
+ if ((len = read(fd, head, len)) < 0) {
|
||||
+ virReportSystemError(errno, _("cannot read header '%s'"), path);
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+
|
||||
+ ret = virStorageFileProbeFormatFromBuf(path, head, len);
|
||||
+
|
||||
+cleanup:
|
||||
+ VIR_FREE(head);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+/**
|
||||
+ * virStorageFileProbeFormat:
|
||||
+ *
|
||||
+ * Probe for the format of 'path', returning the detected
|
||||
+ * disk format.
|
||||
+ *
|
||||
+ * Callers are advised never to trust the returned 'format'
|
||||
+ * unless it is listed as VIR_STORAGE_FILE_RAW, since a
|
||||
+ * malicious guest can turn a raw file into any other non-raw
|
||||
+ * format at will.
|
||||
+ *
|
||||
+ * Best option: Don't use this function
|
||||
+ */
|
||||
+int
|
||||
+virStorageFileProbeFormat(const char *path)
|
||||
+{
|
||||
+ int fd, ret;
|
||||
+
|
||||
+ if ((fd = open(path, O_RDONLY)) < 0) {
|
||||
+ virReportSystemError(errno, _("cannot open file '%s'"), path);
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ ret = virStorageFileProbeFormatFromFD(path, fd);
|
||||
+
|
||||
+ close(fd);
|
||||
+
|
||||
+ return ret;
|
||||
}
|
||||
|
||||
+/**
|
||||
+ * virStorageFileGetMetadataFromFD:
|
||||
+ *
|
||||
+ * Probe for the format of 'fd' (which is an open file descriptor
|
||||
+ * for the file 'path'), filling 'meta' with the detected
|
||||
+ * format and other associated metadata.
|
||||
+ *
|
||||
+ * Callers are advised never to trust the returned 'meta->format'
|
||||
+ * unless it is listed as VIR_STORAGE_FILE_RAW, since a
|
||||
+ * malicious guest can turn a raw file into any other non-raw
|
||||
+ * format at will.
|
||||
+ */
|
||||
+int
|
||||
+virStorageFileGetMetadataFromFD(const char *path,
|
||||
+ int fd,
|
||||
+ virStorageFileMetadata *meta)
|
||||
+{
|
||||
+ unsigned char *head;
|
||||
+ ssize_t len = STORAGE_MAX_HEAD;
|
||||
+ int ret = -1;
|
||||
+
|
||||
+ if (VIR_ALLOC_N(head, len) < 0) {
|
||||
+ virReportOOMError();
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ memset(meta, 0, sizeof (*meta));
|
||||
+
|
||||
+ if (lseek(fd, 0, SEEK_SET) == (off_t)-1) {
|
||||
+ virReportSystemError(errno, _("cannot set to start of '%s'"), path);
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+
|
||||
+ if ((len = read(fd, head, len)) < 0) {
|
||||
+ virReportSystemError(errno, _("cannot read header '%s'"), path);
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+
|
||||
+ meta->format = virStorageFileProbeFormatFromBuf(path, head, len);
|
||||
+
|
||||
+ ret = virStorageFileGetMetadataFromBuf(meta->format, path, head, len, meta);
|
||||
+
|
||||
+cleanup:
|
||||
+ VIR_FREE(head);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * virStorageFileGetMetadata:
|
||||
+ *
|
||||
+ * Probe for the format of 'path', filling 'meta' with the detected
|
||||
+ * format and other associated metadata.
|
||||
+ *
|
||||
+ * Callers are advised never to trust the returned 'meta->format'
|
||||
+ * unless it is listed as VIR_STORAGE_FILE_RAW, since a
|
||||
+ * malicious guest can turn a raw file into any other non-raw
|
||||
+ * format at will.
|
||||
+ */
|
||||
int
|
||||
virStorageFileGetMetadata(const char *path,
|
||||
virStorageFileMetadata *meta)
|
||||
diff --git a/src/util/storage_file.h b/src/util/storage_file.h
|
||||
index 6328ba7..3420d44 100644
|
||||
--- a/src/util/storage_file.h
|
||||
+++ b/src/util/storage_file.h
|
||||
@@ -57,6 +57,10 @@ typedef struct _virStorageFileMetadata {
|
||||
# define DEV_BSIZE 512
|
||||
# endif
|
||||
|
||||
+int virStorageFileProbeFormat(const char *path);
|
||||
+int virStorageFileProbeFormatFromFD(const char *path,
|
||||
+ int fd);
|
||||
+
|
||||
int virStorageFileGetMetadata(const char *path,
|
||||
virStorageFileMetadata *meta);
|
||||
int virStorageFileGetMetadataFromFD(const char *path,
|
||||
--
|
||||
1.7.1.1
|
||||
|
||||
@@ -1,285 +0,0 @@
|
||||
From 726a63a437efd96510ce316bf30d16f213d4db27 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel P. Berrange <berrange@redhat.com>
|
||||
Date: Tue, 15 Jun 2010 16:15:51 +0100
|
||||
Subject: [PATCH 04/11] Require format to be passed into virStorageFileGetMetadata
|
||||
|
||||
Require the disk image to be passed into virStorageFileGetMetadata.
|
||||
If this is set to VIR_STORAGE_FILE_AUTO, then the format will be
|
||||
resolved using probing. This makes it easier to control when
|
||||
probing will be used
|
||||
|
||||
* src/qemu/qemu_driver.c, src/qemu/qemu_security_dac.c,
|
||||
src/security/security_selinux.c, src/security/virt-aa-helper.c:
|
||||
Set VIR_STORAGE_FILE_AUTO when calling virStorageFileGetMetadata.
|
||||
* src/storage/storage_backend_fs.c: Probe for disk format before
|
||||
calling virStorageFileGetMetadata.
|
||||
* src/util/storage_file.h, src/util/storage_file.c: Remove format
|
||||
from virStorageFileMeta struct & require it to be passed into
|
||||
method.
|
||||
---
|
||||
src/qemu/qemu_driver.c | 27 +++++++++++++++++---
|
||||
src/qemu/qemu_security_dac.c | 4 ++-
|
||||
src/security/security_selinux.c | 4 ++-
|
||||
src/security/virt-aa-helper.c | 4 ++-
|
||||
src/storage/storage_backend_fs.c | 11 ++++++--
|
||||
src/util/storage_file.c | 50 +++++++++++++++++++++++++------------
|
||||
src/util/storage_file.h | 3 +-
|
||||
7 files changed, 76 insertions(+), 27 deletions(-)
|
||||
|
||||
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
|
||||
index 487bfa3..97f2990 100644
|
||||
--- a/src/qemu/qemu_driver.c
|
||||
+++ b/src/qemu/qemu_driver.c
|
||||
@@ -3069,7 +3069,9 @@ static int qemuSetupDiskCgroup(virCgroupPtr cgroup,
|
||||
}
|
||||
}
|
||||
|
||||
- rc = virStorageFileGetMetadata(path, &meta);
|
||||
+ rc = virStorageFileGetMetadata(path,
|
||||
+ VIR_STORAGE_FILE_AUTO,
|
||||
+ &meta);
|
||||
if (rc < 0)
|
||||
VIR_WARN("Unable to lookup parent image for %s", path);
|
||||
|
||||
@@ -3119,7 +3121,9 @@ static int qemuTeardownDiskCgroup(virCgroupPtr cgroup,
|
||||
}
|
||||
}
|
||||
|
||||
- rc = virStorageFileGetMetadata(path, &meta);
|
||||
+ rc = virStorageFileGetMetadata(path,
|
||||
+ VIR_STORAGE_FILE_AUTO,
|
||||
+ &meta);
|
||||
if (rc < 0)
|
||||
VIR_WARN("Unable to lookup parent image for %s", path);
|
||||
|
||||
@@ -9614,6 +9618,7 @@ static int qemuDomainGetBlockInfo(virDomainPtr dom,
|
||||
virDomainDiskDefPtr disk = NULL;
|
||||
struct stat sb;
|
||||
int i;
|
||||
+ int format;
|
||||
|
||||
virCheckFlags(0, -1);
|
||||
|
||||
@@ -9658,7 +9663,21 @@ static int qemuDomainGetBlockInfo(virDomainPtr dom,
|
||||
}
|
||||
|
||||
/* Probe for magic formats */
|
||||
- if (virStorageFileGetMetadataFromFD(path, fd, &meta) < 0)
|
||||
+ if (disk->driverType) {
|
||||
+ if ((format = virStorageFileFormatTypeFromString(disk->driverType)) < 0) {
|
||||
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
+ _("unknown disk format %s for %s"),
|
||||
+ disk->driverType, disk->src);
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+ } else {
|
||||
+ if ((format = virStorageFileProbeFormat(disk->src)) < 0)
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+
|
||||
+ if (virStorageFileGetMetadataFromFD(path, fd,
|
||||
+ format,
|
||||
+ &meta) < 0)
|
||||
goto cleanup;
|
||||
|
||||
/* Get info for normal formats */
|
||||
@@ -9706,7 +9725,7 @@ static int qemuDomainGetBlockInfo(virDomainPtr dom,
|
||||
highest allocated extent from QEMU */
|
||||
if (virDomainObjIsActive(vm) &&
|
||||
disk->type == VIR_DOMAIN_DISK_TYPE_BLOCK &&
|
||||
- meta.format != VIR_STORAGE_FILE_RAW &&
|
||||
+ format != VIR_STORAGE_FILE_RAW &&
|
||||
S_ISBLK(sb.st_mode)) {
|
||||
qemuDomainObjPrivatePtr priv = vm->privateData;
|
||||
if (qemuDomainObjBeginJob(vm) < 0)
|
||||
diff --git a/src/qemu/qemu_security_dac.c b/src/qemu/qemu_security_dac.c
|
||||
index 95015b0..acfe48e 100644
|
||||
--- a/src/qemu/qemu_security_dac.c
|
||||
+++ b/src/qemu/qemu_security_dac.c
|
||||
@@ -115,7 +115,9 @@ qemuSecurityDACSetSecurityImageLabel(virDomainObjPtr vm ATTRIBUTE_UNUSED,
|
||||
virStorageFileMetadata meta;
|
||||
int ret;
|
||||
|
||||
- ret = virStorageFileGetMetadata(path, &meta);
|
||||
+ ret = virStorageFileGetMetadata(path,
|
||||
+ VIR_STORAGE_FILE_AUTO,
|
||||
+ &meta);
|
||||
|
||||
if (path != disk->src)
|
||||
VIR_FREE(path);
|
||||
diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c
|
||||
index e5eef19..5c0f002 100644
|
||||
--- a/src/security/security_selinux.c
|
||||
+++ b/src/security/security_selinux.c
|
||||
@@ -457,7 +457,9 @@ SELinuxSetSecurityImageLabel(virDomainObjPtr vm,
|
||||
virStorageFileMetadata meta;
|
||||
int ret;
|
||||
|
||||
- ret = virStorageFileGetMetadata(path, &meta);
|
||||
+ ret = virStorageFileGetMetadata(path,
|
||||
+ VIR_STORAGE_FILE_AUTO,
|
||||
+ &meta);
|
||||
|
||||
if (path != disk->src)
|
||||
VIR_FREE(path);
|
||||
diff --git a/src/security/virt-aa-helper.c b/src/security/virt-aa-helper.c
|
||||
index c66f107..2c045e6 100644
|
||||
--- a/src/security/virt-aa-helper.c
|
||||
+++ b/src/security/virt-aa-helper.c
|
||||
@@ -830,7 +830,9 @@ get_files(vahControl * ctl)
|
||||
do {
|
||||
virStorageFileMetadata meta;
|
||||
|
||||
- ret = virStorageFileGetMetadata(path, &meta);
|
||||
+ ret = virStorageFileGetMetadata(path,
|
||||
+ VIR_STORAGE_FILE_AUTO,
|
||||
+ &meta);
|
||||
|
||||
if (path != ctl->def->disks[i]->src)
|
||||
VIR_FREE(path);
|
||||
diff --git a/src/storage/storage_backend_fs.c b/src/storage/storage_backend_fs.c
|
||||
index f0cd770..d3ac0fe 100644
|
||||
--- a/src/storage/storage_backend_fs.c
|
||||
+++ b/src/storage/storage_backend_fs.c
|
||||
@@ -75,14 +75,19 @@ virStorageBackendProbeTarget(virStorageVolTargetPtr target,
|
||||
|
||||
memset(&meta, 0, sizeof(meta));
|
||||
|
||||
- if (virStorageFileGetMetadataFromFD(target->path, fd, &meta) < 0) {
|
||||
+ if ((target->format = virStorageFileProbeFormatFromFD(target->path, fd)) < 0) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
- close(fd);
|
||||
+ if (virStorageFileGetMetadataFromFD(target->path, fd,
|
||||
+ target->format,
|
||||
+ &meta) < 0) {
|
||||
+ close(fd);
|
||||
+ return -1;
|
||||
+ }
|
||||
|
||||
- target->format = meta.format;
|
||||
+ close(fd);
|
||||
|
||||
if (backingStore) {
|
||||
*backingStore = meta.backingStore;
|
||||
diff --git a/src/util/storage_file.c b/src/util/storage_file.c
|
||||
index 221268b..9712d92 100644
|
||||
--- a/src/util/storage_file.c
|
||||
+++ b/src/util/storage_file.c
|
||||
@@ -696,18 +696,23 @@ virStorageFileProbeFormat(const char *path)
|
||||
/**
|
||||
* virStorageFileGetMetadataFromFD:
|
||||
*
|
||||
- * Probe for the format of 'fd' (which is an open file descriptor
|
||||
- * for the file 'path'), filling 'meta' with the detected
|
||||
- * format and other associated metadata.
|
||||
+ * Extract metadata about the storage volume with the specified
|
||||
+ * image format. If image format is VIR_STORAGE_FILE_AUTO, it
|
||||
+ * will probe to automatically identify the format.
|
||||
*
|
||||
- * Callers are advised never to trust the returned 'meta->format'
|
||||
- * unless it is listed as VIR_STORAGE_FILE_RAW, since a
|
||||
- * malicious guest can turn a raw file into any other non-raw
|
||||
- * format at will.
|
||||
+ * Callers are advised never to use VIR_STORAGE_FILE_AUTO as a
|
||||
+ * format, since a malicious guest can turn a raw file into any
|
||||
+ * other non-raw format at will.
|
||||
+ *
|
||||
+ * If the returned meta.backingStoreFormat is VIR_STORAGE_FILE_AUTO
|
||||
+ * it indicates the image didn't specify an explicit format for its
|
||||
+ * backing store. Callers are advised against probing for the
|
||||
+ * backing store format in this case.
|
||||
*/
|
||||
int
|
||||
virStorageFileGetMetadataFromFD(const char *path,
|
||||
int fd,
|
||||
+ int format,
|
||||
virStorageFileMetadata *meta)
|
||||
{
|
||||
unsigned char *head;
|
||||
@@ -731,9 +736,16 @@ virStorageFileGetMetadataFromFD(const char *path,
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
- meta->format = virStorageFileProbeFormatFromBuf(path, head, len);
|
||||
+ if (format == VIR_STORAGE_FILE_AUTO)
|
||||
+ format = virStorageFileProbeFormatFromBuf(path, head, len);
|
||||
+
|
||||
+ if (format < 0 ||
|
||||
+ format >= VIR_STORAGE_FILE_LAST) {
|
||||
+ virReportSystemError(EINVAL, _("unknown storage file format %d"), format);
|
||||
+ return -1;
|
||||
+ }
|
||||
|
||||
- ret = virStorageFileGetMetadataFromBuf(meta->format, path, head, len, meta);
|
||||
+ ret = virStorageFileGetMetadataFromBuf(format, path, head, len, meta);
|
||||
|
||||
cleanup:
|
||||
VIR_FREE(head);
|
||||
@@ -743,16 +755,22 @@ cleanup:
|
||||
/**
|
||||
* virStorageFileGetMetadata:
|
||||
*
|
||||
- * Probe for the format of 'path', filling 'meta' with the detected
|
||||
- * format and other associated metadata.
|
||||
+ * Extract metadata about the storage volume with the specified
|
||||
+ * image format. If image format is VIR_STORAGE_FILE_AUTO, it
|
||||
+ * will probe to automatically identify the format.
|
||||
*
|
||||
- * Callers are advised never to trust the returned 'meta->format'
|
||||
- * unless it is listed as VIR_STORAGE_FILE_RAW, since a
|
||||
- * malicious guest can turn a raw file into any other non-raw
|
||||
- * format at will.
|
||||
+ * Callers are advised never to use VIR_STORAGE_FILE_AUTO as a
|
||||
+ * format, since a malicious guest can turn a raw file into any
|
||||
+ * other non-raw format at will.
|
||||
+ *
|
||||
+ * If the returned meta.backingStoreFormat is VIR_STORAGE_FILE_AUTO
|
||||
+ * it indicates the image didn't specify an explicit format for its
|
||||
+ * backing store. Callers are advised against probing for the
|
||||
+ * backing store format in this case.
|
||||
*/
|
||||
int
|
||||
virStorageFileGetMetadata(const char *path,
|
||||
+ int format,
|
||||
virStorageFileMetadata *meta)
|
||||
{
|
||||
int fd, ret;
|
||||
@@ -762,7 +780,7 @@ virStorageFileGetMetadata(const char *path,
|
||||
return -1;
|
||||
}
|
||||
|
||||
- ret = virStorageFileGetMetadataFromFD(path, fd, meta);
|
||||
+ ret = virStorageFileGetMetadataFromFD(path, fd, format, meta);
|
||||
|
||||
close(fd);
|
||||
|
||||
diff --git a/src/util/storage_file.h b/src/util/storage_file.h
|
||||
index 3420d44..6853182 100644
|
||||
--- a/src/util/storage_file.h
|
||||
+++ b/src/util/storage_file.h
|
||||
@@ -46,7 +46,6 @@ enum virStorageFileFormat {
|
||||
VIR_ENUM_DECL(virStorageFileFormat);
|
||||
|
||||
typedef struct _virStorageFileMetadata {
|
||||
- int format;
|
||||
char *backingStore;
|
||||
int backingStoreFormat;
|
||||
unsigned long long capacity;
|
||||
@@ -62,9 +61,11 @@ int virStorageFileProbeFormatFromFD(const char *path,
|
||||
int fd);
|
||||
|
||||
int virStorageFileGetMetadata(const char *path,
|
||||
+ int format,
|
||||
virStorageFileMetadata *meta);
|
||||
int virStorageFileGetMetadataFromFD(const char *path,
|
||||
int fd,
|
||||
+ int format,
|
||||
virStorageFileMetadata *meta);
|
||||
|
||||
int virStorageFileIsSharedFS(const char *path);
|
||||
--
|
||||
1.7.1.1
|
||||
|
||||
@@ -1,170 +0,0 @@
|
||||
From ac5067f1e2e98181ee0e9230f756697f50d853eb Mon Sep 17 00:00:00 2001
|
||||
From: Daniel P. Berrange <berrange@redhat.com>
|
||||
Date: Mon, 14 Jun 2010 18:09:15 +0100
|
||||
Subject: [PATCH 05/11] Add an API for iterating over disk paths
|
||||
|
||||
There is duplicated code which iterates over disk backing stores
|
||||
performing some action. Provide a convenient helper for doing
|
||||
this to eliminate duplication & risk of mistakes with disk format
|
||||
probing
|
||||
|
||||
* src/conf/domain_conf.c, src/conf/domain_conf.h,
|
||||
src/libvirt_private.syms: Add virDomainDiskDefForeachPath()
|
||||
---
|
||||
src/conf/domain_conf.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++
|
||||
src/conf/domain_conf.h | 11 +++++
|
||||
src/libvirt_private.syms | 1 +
|
||||
3 files changed, 111 insertions(+), 0 deletions(-)
|
||||
|
||||
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
|
||||
index 378c06e..b20ca97 100644
|
||||
--- a/src/conf/domain_conf.c
|
||||
+++ b/src/conf/domain_conf.c
|
||||
@@ -45,6 +45,7 @@
|
||||
#include "macvtap.h"
|
||||
#include "nwfilter_conf.h"
|
||||
#include "ignore-value.h"
|
||||
+#include "storage_file.h"
|
||||
|
||||
#define VIR_FROM_THIS VIR_FROM_DOMAIN
|
||||
|
||||
@@ -7273,4 +7274,102 @@ done:
|
||||
}
|
||||
|
||||
|
||||
+int virDomainDiskDefForeachPath(virDomainDiskDefPtr disk,
|
||||
+ bool allowProbing,
|
||||
+ bool ignoreOpenFailure,
|
||||
+ virDomainDiskDefPathIterator iter,
|
||||
+ void *opaque)
|
||||
+{
|
||||
+ virHashTablePtr paths;
|
||||
+ int format;
|
||||
+ int ret = -1;
|
||||
+ size_t depth = 0;
|
||||
+ char *nextpath = NULL;
|
||||
+
|
||||
+ if (!disk->src)
|
||||
+ return 0;
|
||||
+
|
||||
+ if (disk->driverType) {
|
||||
+ const char *formatStr = disk->driverType;
|
||||
+ if (STREQ(formatStr, "aio"))
|
||||
+ formatStr = "raw"; /* Xen compat */
|
||||
+
|
||||
+ if ((format = virStorageFileFormatTypeFromString(formatStr)) < 0) {
|
||||
+ virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
+ _("unknown disk format '%s' for %s"),
|
||||
+ disk->driverType, disk->src);
|
||||
+ return -1;
|
||||
+ }
|
||||
+ } else {
|
||||
+ if (allowProbing) {
|
||||
+ format = VIR_STORAGE_FILE_AUTO;
|
||||
+ } else {
|
||||
+ virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
+ _("no disk format for %s and probing is disabled"),
|
||||
+ disk->src);
|
||||
+ return -1;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ paths = virHashCreate(5);
|
||||
+
|
||||
+ do {
|
||||
+ virStorageFileMetadata meta;
|
||||
+ const char *path = nextpath ? nextpath : disk->src;
|
||||
+ int fd;
|
||||
+
|
||||
+ if (iter(disk, path, depth, opaque) < 0)
|
||||
+ goto cleanup;
|
||||
+
|
||||
+ if (virHashLookup(paths, path)) {
|
||||
+ virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
+ _("backing store for %s is self-referential"),
|
||||
+ disk->src);
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+
|
||||
+ if ((fd = open(path, O_RDONLY)) < 0) {
|
||||
+ if (ignoreOpenFailure) {
|
||||
+ char ebuf[1024];
|
||||
+ VIR_WARN("Ignoring open failure on %s: %s", path,
|
||||
+ virStrerror(errno, ebuf, sizeof(ebuf)));
|
||||
+ break;
|
||||
+ } else {
|
||||
+ virReportSystemError(errno,
|
||||
+ _("unable to open disk path %s"),
|
||||
+ path);
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (virStorageFileGetMetadataFromFD(path, fd, format, &meta) < 0) {
|
||||
+ close(fd);
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+ close(fd);
|
||||
+
|
||||
+ if (virHashAddEntry(paths, path, (void*)0x1) < 0) {
|
||||
+ virReportOOMError();
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+
|
||||
+ depth++;
|
||||
+ nextpath = meta.backingStore;
|
||||
+
|
||||
+ format = meta.backingStoreFormat;
|
||||
+
|
||||
+ if (format == VIR_STORAGE_FILE_AUTO &&
|
||||
+ !allowProbing)
|
||||
+ format = VIR_STORAGE_FILE_RAW; /* Stops further recursion */
|
||||
+ } while (nextpath);
|
||||
+
|
||||
+ ret = 0;
|
||||
+
|
||||
+cleanup:
|
||||
+ virHashFree(paths, NULL);
|
||||
+ VIR_FREE(nextpath);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
#endif /* ! PROXY */
|
||||
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
|
||||
index 01da17e..d46869e 100644
|
||||
--- a/src/conf/domain_conf.h
|
||||
+++ b/src/conf/domain_conf.h
|
||||
@@ -1079,6 +1079,17 @@ int virDomainChrDefForeach(virDomainDefPtr def,
|
||||
void *opaque);
|
||||
|
||||
|
||||
+typedef int (*virDomainDiskDefPathIterator)(virDomainDiskDefPtr disk,
|
||||
+ const char *path,
|
||||
+ size_t depth,
|
||||
+ void *opaque);
|
||||
+
|
||||
+int virDomainDiskDefForeachPath(virDomainDiskDefPtr disk,
|
||||
+ bool allowProbing,
|
||||
+ bool ignoreOpenFailure,
|
||||
+ virDomainDiskDefPathIterator iter,
|
||||
+ void *opaque);
|
||||
+
|
||||
VIR_ENUM_DECL(virDomainVirt)
|
||||
VIR_ENUM_DECL(virDomainBoot)
|
||||
VIR_ENUM_DECL(virDomainFeature)
|
||||
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
|
||||
index 4607f49..b5f3695 100644
|
||||
--- a/src/libvirt_private.syms
|
||||
+++ b/src/libvirt_private.syms
|
||||
@@ -225,6 +225,7 @@ virDomainSnapshotDefFormat;
|
||||
virDomainSnapshotAssignDef;
|
||||
virDomainObjAssignDef;
|
||||
virDomainChrDefForeach;
|
||||
+virDomainDiskDefForeachPath;
|
||||
|
||||
|
||||
# domain_event.h
|
||||
--
|
||||
1.7.1.1
|
||||
|
||||
@@ -1,506 +0,0 @@
|
||||
From 54c1bb731d2b19a46a594cf9682c022f1e1114d2 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel P. Berrange <berrange@redhat.com>
|
||||
Date: Tue, 15 Jun 2010 16:40:47 +0100
|
||||
Subject: [PATCH 06/11] Convert all disk backing store loops to shared helper API
|
||||
|
||||
Update the QEMU cgroups code, QEMU DAC security driver, SELinux
|
||||
and AppArmour security drivers over to use the shared helper API
|
||||
virDomainDiskDefForeachPath().
|
||||
|
||||
* src/qemu/qemu_driver.c, src/qemu/qemu_security_dac.c,
|
||||
src/security/security_selinux.c, src/security/virt-aa-helper.c:
|
||||
Convert over to use virDomainDiskDefForeachPath()
|
||||
---
|
||||
src/qemu/qemu_driver.c | 161 ++++++++++++++++----------------------
|
||||
src/qemu/qemu_security_dac.c | 47 ++++--------
|
||||
src/security/security_selinux.c | 67 +++++++----------
|
||||
src/security/virt-aa-helper.c | 71 ++++++++----------
|
||||
4 files changed, 142 insertions(+), 204 deletions(-)
|
||||
|
||||
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
|
||||
index 97f2990..99aeffa 100644
|
||||
--- a/src/qemu/qemu_driver.c
|
||||
+++ b/src/qemu/qemu_driver.c
|
||||
@@ -3040,107 +3040,82 @@ static const char *const defaultDeviceACL[] = {
|
||||
#define DEVICE_PTY_MAJOR 136
|
||||
#define DEVICE_SND_MAJOR 116
|
||||
|
||||
-static int qemuSetupDiskCgroup(virCgroupPtr cgroup,
|
||||
- virDomainObjPtr vm,
|
||||
- virDomainDiskDefPtr disk)
|
||||
-{
|
||||
- char *path = disk->src;
|
||||
- int ret = -1;
|
||||
|
||||
- while (path != NULL) {
|
||||
- virStorageFileMetadata meta;
|
||||
- int rc;
|
||||
+static int qemuSetupDiskPathAllow(virDomainDiskDefPtr disk ATTRIBUTE_UNUSED,
|
||||
+ const char *path,
|
||||
+ size_t depth ATTRIBUTE_UNUSED,
|
||||
+ void *opaque)
|
||||
+{
|
||||
+ virCgroupPtr cgroup = opaque;
|
||||
+ int rc;
|
||||
|
||||
- VIR_DEBUG("Process path '%s' for disk", path);
|
||||
- rc = virCgroupAllowDevicePath(cgroup, path);
|
||||
- if (rc != 0) {
|
||||
- /* Get this for non-block devices */
|
||||
- if (rc == -EINVAL) {
|
||||
- VIR_DEBUG("Ignoring EINVAL for %s", path);
|
||||
- } else if (rc == -EACCES) { /* Get this for root squash NFS */
|
||||
- VIR_DEBUG("Ignoring EACCES for %s", path);
|
||||
- } else {
|
||||
- virReportSystemError(-rc,
|
||||
- _("Unable to allow device %s for %s"),
|
||||
- path, vm->def->name);
|
||||
- if (path != disk->src)
|
||||
- VIR_FREE(path);
|
||||
- goto cleanup;
|
||||
- }
|
||||
+ VIR_DEBUG("Process path %s for disk", path);
|
||||
+ /* XXX RO vs RW */
|
||||
+ rc = virCgroupAllowDevicePath(cgroup, path);
|
||||
+ if (rc != 0) {
|
||||
+ /* Get this for non-block devices */
|
||||
+ if (rc == -EINVAL) {
|
||||
+ VIR_DEBUG("Ignoring EINVAL for %s", path);
|
||||
+ } else if (rc == -EACCES) { /* Get this for root squash NFS */
|
||||
+ VIR_DEBUG("Ignoring EACCES for %s", path);
|
||||
+ } else {
|
||||
+ virReportSystemError(-rc,
|
||||
+ _("Unable to allow access for disk path %s"),
|
||||
+ path);
|
||||
+ return -1;
|
||||
}
|
||||
-
|
||||
- rc = virStorageFileGetMetadata(path,
|
||||
- VIR_STORAGE_FILE_AUTO,
|
||||
- &meta);
|
||||
- if (rc < 0)
|
||||
- VIR_WARN("Unable to lookup parent image for %s", path);
|
||||
-
|
||||
- if (path != disk->src)
|
||||
- VIR_FREE(path);
|
||||
- path = NULL;
|
||||
-
|
||||
- if (rc < 0)
|
||||
- break; /* Treating as non fatal */
|
||||
-
|
||||
- path = meta.backingStore;
|
||||
}
|
||||
+ return 0;
|
||||
+}
|
||||
|
||||
- ret = 0;
|
||||
|
||||
-cleanup:
|
||||
- return ret;
|
||||
+static int qemuSetupDiskCgroup(virCgroupPtr cgroup,
|
||||
+ virDomainDiskDefPtr disk)
|
||||
+{
|
||||
+ return virDomainDiskDefForeachPath(disk,
|
||||
+ true,
|
||||
+ true,
|
||||
+ qemuSetupDiskPathAllow,
|
||||
+ cgroup);
|
||||
}
|
||||
|
||||
|
||||
-static int qemuTeardownDiskCgroup(virCgroupPtr cgroup,
|
||||
- virDomainObjPtr vm,
|
||||
- virDomainDiskDefPtr disk)
|
||||
+static int qemuTeardownDiskPathDeny(virDomainDiskDefPtr disk ATTRIBUTE_UNUSED,
|
||||
+ const char *path,
|
||||
+ size_t depth ATTRIBUTE_UNUSED,
|
||||
+ void *opaque)
|
||||
{
|
||||
- char *path = disk->src;
|
||||
- int ret = -1;
|
||||
-
|
||||
- while (path != NULL) {
|
||||
- virStorageFileMetadata meta;
|
||||
- int rc;
|
||||
+ virCgroupPtr cgroup = opaque;
|
||||
+ int rc;
|
||||
|
||||
- VIR_DEBUG("Process path '%s' for disk", path);
|
||||
- rc = virCgroupDenyDevicePath(cgroup, path);
|
||||
- if (rc != 0) {
|
||||
- /* Get this for non-block devices */
|
||||
- if (rc == -EINVAL) {
|
||||
- VIR_DEBUG("Ignoring EINVAL for %s", path);
|
||||
- } else if (rc == -EACCES) { /* Get this for root squash NFS */
|
||||
- VIR_DEBUG("Ignoring EACCES for %s", path);
|
||||
- } else {
|
||||
- virReportSystemError(-rc,
|
||||
- _("Unable to deny device %s for %s"),
|
||||
- path, vm->def->name);
|
||||
- if (path != disk->src)
|
||||
- VIR_FREE(path);
|
||||
- goto cleanup;
|
||||
- }
|
||||
+ VIR_DEBUG("Process path %s for disk", path);
|
||||
+ /* XXX RO vs RW */
|
||||
+ rc = virCgroupDenyDevicePath(cgroup, path);
|
||||
+ if (rc != 0) {
|
||||
+ /* Get this for non-block devices */
|
||||
+ if (rc == -EINVAL) {
|
||||
+ VIR_DEBUG("Ignoring EINVAL for %s", path);
|
||||
+ } else if (rc == -EACCES) { /* Get this for root squash NFS */
|
||||
+ VIR_DEBUG("Ignoring EACCES for %s", path);
|
||||
+ } else {
|
||||
+ virReportSystemError(-rc,
|
||||
+ _("Unable to allow access for disk path %s"),
|
||||
+ path);
|
||||
+ return -1;
|
||||
}
|
||||
-
|
||||
- rc = virStorageFileGetMetadata(path,
|
||||
- VIR_STORAGE_FILE_AUTO,
|
||||
- &meta);
|
||||
- if (rc < 0)
|
||||
- VIR_WARN("Unable to lookup parent image for %s", path);
|
||||
-
|
||||
- if (path != disk->src)
|
||||
- VIR_FREE(path);
|
||||
- path = NULL;
|
||||
-
|
||||
- if (rc < 0)
|
||||
- break; /* Treating as non fatal */
|
||||
-
|
||||
- path = meta.backingStore;
|
||||
}
|
||||
+ return 0;
|
||||
+}
|
||||
|
||||
- ret = 0;
|
||||
|
||||
-cleanup:
|
||||
- return ret;
|
||||
+static int qemuTeardownDiskCgroup(virCgroupPtr cgroup,
|
||||
+ virDomainDiskDefPtr disk)
|
||||
+{
|
||||
+ return virDomainDiskDefForeachPath(disk,
|
||||
+ true,
|
||||
+ true,
|
||||
+ qemuTeardownDiskPathDeny,
|
||||
+ cgroup);
|
||||
}
|
||||
|
||||
|
||||
@@ -3204,7 +3179,7 @@ static int qemuSetupCgroup(struct qemud_driver *driver,
|
||||
}
|
||||
|
||||
for (i = 0; i < vm->def->ndisks ; i++) {
|
||||
- if (qemuSetupDiskCgroup(cgroup, vm, vm->def->disks[i]) < 0)
|
||||
+ if (qemuSetupDiskCgroup(cgroup, vm->def->disks[i]) < 0)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
@@ -8035,7 +8010,7 @@ static int qemudDomainAttachDevice(virDomainPtr dom,
|
||||
vm->def->name);
|
||||
goto endjob;
|
||||
}
|
||||
- if (qemuSetupDiskCgroup(cgroup, vm, dev->data.disk) < 0)
|
||||
+ if (qemuSetupDiskCgroup(cgroup, dev->data.disk) < 0)
|
||||
goto endjob;
|
||||
}
|
||||
|
||||
@@ -8080,7 +8055,7 @@ static int qemudDomainAttachDevice(virDomainPtr dom,
|
||||
/* Fallthrough */
|
||||
}
|
||||
if (ret != 0 && cgroup) {
|
||||
- if (qemuTeardownDiskCgroup(cgroup, vm, dev->data.disk) < 0)
|
||||
+ if (qemuTeardownDiskCgroup(cgroup, dev->data.disk) < 0)
|
||||
VIR_WARN("Failed to teardown cgroup for disk path %s",
|
||||
NULLSTR(dev->data.disk->src));
|
||||
}
|
||||
@@ -8280,7 +8255,7 @@ static int qemuDomainUpdateDeviceFlags(virDomainPtr dom,
|
||||
vm->def->name);
|
||||
goto endjob;
|
||||
}
|
||||
- if (qemuSetupDiskCgroup(cgroup, vm, dev->data.disk) < 0)
|
||||
+ if (qemuSetupDiskCgroup(cgroup, dev->data.disk) < 0)
|
||||
goto endjob;
|
||||
}
|
||||
|
||||
@@ -8303,7 +8278,7 @@ static int qemuDomainUpdateDeviceFlags(virDomainPtr dom,
|
||||
}
|
||||
|
||||
if (ret != 0 && cgroup) {
|
||||
- if (qemuTeardownDiskCgroup(cgroup, vm, dev->data.disk) < 0)
|
||||
+ if (qemuTeardownDiskCgroup(cgroup, dev->data.disk) < 0)
|
||||
VIR_WARN("Failed to teardown cgroup for disk path %s",
|
||||
NULLSTR(dev->data.disk->src));
|
||||
}
|
||||
@@ -8430,7 +8405,7 @@ static int qemudDomainDetachPciDiskDevice(struct qemud_driver *driver,
|
||||
VIR_WARN("Unable to restore security label on %s", dev->data.disk->src);
|
||||
|
||||
if (cgroup != NULL) {
|
||||
- if (qemuTeardownDiskCgroup(cgroup, vm, dev->data.disk) < 0)
|
||||
+ if (qemuTeardownDiskCgroup(cgroup, dev->data.disk) < 0)
|
||||
VIR_WARN("Failed to teardown cgroup for disk path %s",
|
||||
NULLSTR(dev->data.disk->src));
|
||||
}
|
||||
@@ -8493,7 +8468,7 @@ static int qemudDomainDetachSCSIDiskDevice(struct qemud_driver *driver,
|
||||
VIR_WARN("Unable to restore security label on %s", dev->data.disk->src);
|
||||
|
||||
if (cgroup != NULL) {
|
||||
- if (qemuTeardownDiskCgroup(cgroup, vm, dev->data.disk) < 0)
|
||||
+ if (qemuTeardownDiskCgroup(cgroup, dev->data.disk) < 0)
|
||||
VIR_WARN("Failed to teardown cgroup for disk path %s",
|
||||
NULLSTR(dev->data.disk->src));
|
||||
}
|
||||
diff --git a/src/qemu/qemu_security_dac.c b/src/qemu/qemu_security_dac.c
|
||||
index acfe48e..770010d 100644
|
||||
--- a/src/qemu/qemu_security_dac.c
|
||||
+++ b/src/qemu/qemu_security_dac.c
|
||||
@@ -98,45 +98,28 @@ err:
|
||||
|
||||
|
||||
static int
|
||||
+qemuSecurityDACSetSecurityFileLabel(virDomainDiskDefPtr disk ATTRIBUTE_UNUSED,
|
||||
+ const char *path,
|
||||
+ size_t depth ATTRIBUTE_UNUSED,
|
||||
+ void *opaque ATTRIBUTE_UNUSED)
|
||||
+{
|
||||
+ return qemuSecurityDACSetOwnership(path, driver->user, driver->group);
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static int
|
||||
qemuSecurityDACSetSecurityImageLabel(virDomainObjPtr vm ATTRIBUTE_UNUSED,
|
||||
virDomainDiskDefPtr disk)
|
||||
|
||||
{
|
||||
- const char *path;
|
||||
-
|
||||
if (!driver->privileged || !driver->dynamicOwnership)
|
||||
return 0;
|
||||
|
||||
- if (!disk->src)
|
||||
- return 0;
|
||||
-
|
||||
- path = disk->src;
|
||||
- do {
|
||||
- virStorageFileMetadata meta;
|
||||
- int ret;
|
||||
-
|
||||
- ret = virStorageFileGetMetadata(path,
|
||||
- VIR_STORAGE_FILE_AUTO,
|
||||
- &meta);
|
||||
-
|
||||
- if (path != disk->src)
|
||||
- VIR_FREE(path);
|
||||
- path = NULL;
|
||||
-
|
||||
- if (ret < 0)
|
||||
- return -1;
|
||||
-
|
||||
- if (meta.backingStore != NULL &&
|
||||
- qemuSecurityDACSetOwnership(meta.backingStore,
|
||||
- driver->user, driver->group) < 0) {
|
||||
- VIR_FREE(meta.backingStore);
|
||||
- return -1;
|
||||
- }
|
||||
-
|
||||
- path = meta.backingStore;
|
||||
- } while (path != NULL);
|
||||
-
|
||||
- return qemuSecurityDACSetOwnership(disk->src, driver->user, driver->group);
|
||||
+ return virDomainDiskDefForeachPath(disk,
|
||||
+ true,
|
||||
+ false,
|
||||
+ qemuSecurityDACSetSecurityFileLabel,
|
||||
+ NULL);
|
||||
}
|
||||
|
||||
|
||||
diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c
|
||||
index 5c0f002..d191118 100644
|
||||
--- a/src/security/security_selinux.c
|
||||
+++ b/src/security/security_selinux.c
|
||||
@@ -439,54 +439,43 @@ SELinuxRestoreSecurityImageLabel(virDomainObjPtr vm,
|
||||
|
||||
|
||||
static int
|
||||
+SELinuxSetSecurityFileLabel(virDomainDiskDefPtr disk,
|
||||
+ const char *path,
|
||||
+ size_t depth,
|
||||
+ void *opaque)
|
||||
+{
|
||||
+ const virSecurityLabelDefPtr secdef = opaque;
|
||||
+
|
||||
+ if (depth == 0) {
|
||||
+ if (disk->shared) {
|
||||
+ return SELinuxSetFilecon(path, default_image_context);
|
||||
+ } else if (disk->readonly) {
|
||||
+ return SELinuxSetFilecon(path, default_content_context);
|
||||
+ } else if (secdef->imagelabel) {
|
||||
+ return SELinuxSetFilecon(path, secdef->imagelabel);
|
||||
+ } else {
|
||||
+ return 0;
|
||||
+ }
|
||||
+ } else {
|
||||
+ return SELinuxSetFilecon(path, default_content_context);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
SELinuxSetSecurityImageLabel(virDomainObjPtr vm,
|
||||
virDomainDiskDefPtr disk)
|
||||
|
||||
{
|
||||
const virSecurityLabelDefPtr secdef = &vm->def->seclabel;
|
||||
- const char *path;
|
||||
|
||||
if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC)
|
||||
return 0;
|
||||
|
||||
- if (!disk->src)
|
||||
- return 0;
|
||||
-
|
||||
- path = disk->src;
|
||||
- do {
|
||||
- virStorageFileMetadata meta;
|
||||
- int ret;
|
||||
-
|
||||
- ret = virStorageFileGetMetadata(path,
|
||||
- VIR_STORAGE_FILE_AUTO,
|
||||
- &meta);
|
||||
-
|
||||
- if (path != disk->src)
|
||||
- VIR_FREE(path);
|
||||
- path = NULL;
|
||||
-
|
||||
- if (ret < 0)
|
||||
- break;
|
||||
-
|
||||
- if (meta.backingStore != NULL &&
|
||||
- SELinuxSetFilecon(meta.backingStore,
|
||||
- default_content_context) < 0) {
|
||||
- VIR_FREE(meta.backingStore);
|
||||
- return -1;
|
||||
- }
|
||||
-
|
||||
- path = meta.backingStore;
|
||||
- } while (path != NULL);
|
||||
-
|
||||
- if (disk->shared) {
|
||||
- return SELinuxSetFilecon(disk->src, default_image_context);
|
||||
- } else if (disk->readonly) {
|
||||
- return SELinuxSetFilecon(disk->src, default_content_context);
|
||||
- } else if (secdef->imagelabel) {
|
||||
- return SELinuxSetFilecon(disk->src, secdef->imagelabel);
|
||||
- }
|
||||
-
|
||||
- return 0;
|
||||
+ return virDomainDiskDefForeachPath(disk,
|
||||
+ true,
|
||||
+ false,
|
||||
+ SELinuxSetSecurityFileLabel,
|
||||
+ secdef);
|
||||
}
|
||||
|
||||
|
||||
diff --git a/src/security/virt-aa-helper.c b/src/security/virt-aa-helper.c
|
||||
index 2c045e6..9ed0cd3 100644
|
||||
--- a/src/security/virt-aa-helper.c
|
||||
+++ b/src/security/virt-aa-helper.c
|
||||
@@ -36,7 +36,6 @@
|
||||
#include "uuid.h"
|
||||
#include "hostusb.h"
|
||||
#include "pci.h"
|
||||
-#include "storage_file.h"
|
||||
|
||||
static char *progname;
|
||||
|
||||
@@ -801,6 +800,28 @@ file_iterate_pci_cb(pciDevice *dev ATTRIBUTE_UNUSED,
|
||||
}
|
||||
|
||||
static int
|
||||
+add_file_path(virDomainDiskDefPtr disk,
|
||||
+ const char *path,
|
||||
+ size_t depth,
|
||||
+ void *opaque)
|
||||
+{
|
||||
+ virBufferPtr buf = opaque;
|
||||
+ int ret;
|
||||
+
|
||||
+ if (depth == 0) {
|
||||
+ if (disk->readonly)
|
||||
+ ret = vah_add_file(buf, path, "r");
|
||||
+ else
|
||||
+ ret = vah_add_file(buf, path, "rw");
|
||||
+ } else {
|
||||
+ ret = vah_add_file(buf, path, "r");
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static int
|
||||
get_files(vahControl * ctl)
|
||||
{
|
||||
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
||||
@@ -821,45 +842,15 @@ get_files(vahControl * ctl)
|
||||
goto clean;
|
||||
}
|
||||
|
||||
- for (i = 0; i < ctl->def->ndisks; i++)
|
||||
- if (ctl->def->disks[i] && ctl->def->disks[i]->src) {
|
||||
- int ret;
|
||||
- const char *path;
|
||||
-
|
||||
- path = ctl->def->disks[i]->src;
|
||||
- do {
|
||||
- virStorageFileMetadata meta;
|
||||
-
|
||||
- ret = virStorageFileGetMetadata(path,
|
||||
- VIR_STORAGE_FILE_AUTO,
|
||||
- &meta);
|
||||
-
|
||||
- if (path != ctl->def->disks[i]->src)
|
||||
- VIR_FREE(path);
|
||||
- path = NULL;
|
||||
-
|
||||
- if (ret < 0) {
|
||||
- vah_warning("could not open path, skipping");
|
||||
- continue;
|
||||
- }
|
||||
-
|
||||
- if (meta.backingStore != NULL &&
|
||||
- (ret = vah_add_file(&buf, meta.backingStore, "rw")) != 0) {
|
||||
- VIR_FREE(meta.backingStore);
|
||||
- goto clean;
|
||||
- }
|
||||
-
|
||||
- path = meta.backingStore;
|
||||
- } while (path != NULL);
|
||||
-
|
||||
- if (ctl->def->disks[i]->readonly)
|
||||
- ret = vah_add_file(&buf, ctl->def->disks[i]->src, "r");
|
||||
- else
|
||||
- ret = vah_add_file(&buf, ctl->def->disks[i]->src, "rw");
|
||||
-
|
||||
- if (ret != 0)
|
||||
- goto clean;
|
||||
- }
|
||||
+ for (i = 0; i < ctl->def->ndisks; i++) {
|
||||
+ int ret = virDomainDiskDefForeachPath(ctl->def->disks[i],
|
||||
+ true,
|
||||
+ false,
|
||||
+ add_file_path,
|
||||
+ &buf);
|
||||
+ if (ret != 0)
|
||||
+ goto clean;
|
||||
+ }
|
||||
|
||||
for (i = 0; i < ctl->def->nserials; i++)
|
||||
if (ctl->def->serials[i] && ctl->def->serials[i]->data.file.path)
|
||||
--
|
||||
1.7.1.1
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,468 +0,0 @@
|
||||
From dac2b936e77f6c76c11f162e4b175492e4803acb Mon Sep 17 00:00:00 2001
|
||||
From: Daniel P. Berrange <berrange@redhat.com>
|
||||
Date: Tue, 15 Jun 2010 17:58:58 +0100
|
||||
Subject: [PATCH 08/11] Disable all disk probing in QEMU driver & add config option to re-enable
|
||||
|
||||
Disk format probing is now disabled by default. A new config
|
||||
option in /etc/qemu/qemu.conf will re-enable it for existing
|
||||
deployments where this causes trouble
|
||||
---
|
||||
src/qemu/libvirtd_qemu.aug | 1 +
|
||||
src/qemu/qemu.conf | 12 ++++++++++++
|
||||
src/qemu/qemu_conf.c | 4 ++++
|
||||
src/qemu/qemu_conf.h | 1 +
|
||||
src/qemu/qemu_driver.c | 36 +++++++++++++++++++++++-------------
|
||||
src/qemu/qemu_security_dac.c | 2 +-
|
||||
src/qemu/test_libvirtd_qemu.aug | 4 ++++
|
||||
src/security/security_apparmor.c | 12 ++++++++----
|
||||
src/security/security_driver.c | 16 ++++++++++++++--
|
||||
src/security/security_driver.h | 10 ++++++++--
|
||||
src/security/security_selinux.c | 9 ++++++---
|
||||
src/security/virt-aa-helper.c | 10 +++++++++-
|
||||
tests/seclabeltest.c | 2 +-
|
||||
13 files changed, 92 insertions(+), 27 deletions(-)
|
||||
|
||||
diff --git a/src/qemu/libvirtd_qemu.aug b/src/qemu/libvirtd_qemu.aug
|
||||
index 7c9f271..47d0525 100644
|
||||
--- a/src/qemu/libvirtd_qemu.aug
|
||||
+++ b/src/qemu/libvirtd_qemu.aug
|
||||
@@ -40,6 +40,7 @@ module Libvirtd_qemu =
|
||||
| bool_entry "relaxed_acs_check"
|
||||
| bool_entry "vnc_allow_host_audio"
|
||||
| bool_entry "clear_emulator_capabilities"
|
||||
+ | bool_entry "allow_disk_format_probing"
|
||||
|
||||
(* Each enty in the config is one of the following three ... *)
|
||||
let entry = vnc_entry
|
||||
diff --git a/src/qemu/qemu.conf b/src/qemu/qemu.conf
|
||||
index 93934f3..dc8eb83 100644
|
||||
--- a/src/qemu/qemu.conf
|
||||
+++ b/src/qemu/qemu.conf
|
||||
@@ -187,3 +187,15 @@
|
||||
# exploit the privileges and possibly do damage to the host.
|
||||
#
|
||||
# clear_emulator_capabilities = 1
|
||||
+
|
||||
+
|
||||
+
|
||||
+# If allow_disk_format_probing is enabled, libvirt will probe disk
|
||||
+# images to attempt to identify their format, when not otherwise
|
||||
+# specified in the XML. This is disabled by default.
|
||||
+#
|
||||
+# WARNING: Enabling probing is a security hole in almost all
|
||||
+# deployments. It is strongly recommended that users update their
|
||||
+# guest XML <disk> elements to include <driver type='XXXX'/>
|
||||
+# elements instead of enabling this option.
|
||||
+# allow_disk_format_probing = 1
|
||||
diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
|
||||
index 988220b..3ba48bf 100644
|
||||
--- a/src/qemu/qemu_conf.c
|
||||
+++ b/src/qemu/qemu_conf.c
|
||||
@@ -365,6 +365,10 @@ int qemudLoadDriverConfig(struct qemud_driver *driver,
|
||||
CHECK_TYPE ("clear_emulator_capabilities", VIR_CONF_LONG);
|
||||
if (p) driver->clearEmulatorCapabilities = p->l;
|
||||
|
||||
+ p = virConfGetValue (conf, "allow_disk_format_probing");
|
||||
+ CHECK_TYPE ("allow_disk_format_probing", VIR_CONF_LONG);
|
||||
+ if (p) driver->allowDiskFormatProbing = p->l;
|
||||
+
|
||||
virConfFree (conf);
|
||||
return 0;
|
||||
}
|
||||
diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h
|
||||
index ab5f158..30e9f20 100644
|
||||
--- a/src/qemu/qemu_conf.h
|
||||
+++ b/src/qemu/qemu_conf.h
|
||||
@@ -141,6 +141,7 @@ struct qemud_driver {
|
||||
unsigned int relaxedACS : 1;
|
||||
unsigned int vncAllowHostAudio : 1;
|
||||
unsigned int clearEmulatorCapabilities : 1;
|
||||
+ unsigned int allowDiskFormatProbing : 1;
|
||||
|
||||
virCapsPtr caps;
|
||||
|
||||
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
|
||||
index 616547c..3c479c5 100644
|
||||
--- a/src/qemu/qemu_driver.c
|
||||
+++ b/src/qemu/qemu_driver.c
|
||||
@@ -1322,7 +1322,8 @@ qemudSecurityInit(struct qemud_driver *qemud_drv)
|
||||
qemuSecurityDACSetDriver(qemud_drv);
|
||||
|
||||
ret = virSecurityDriverStartup(&security_drv,
|
||||
- qemud_drv->securityDriverName);
|
||||
+ qemud_drv->securityDriverName,
|
||||
+ qemud_drv->allowDiskFormatProbing);
|
||||
if (ret == -1) {
|
||||
VIR_ERROR0(_("Failed to start security driver"));
|
||||
return -1;
|
||||
@@ -3070,11 +3071,12 @@ static int qemuSetupDiskPathAllow(virDomainDiskDefPtr disk ATTRIBUTE_UNUSED,
|
||||
}
|
||||
|
||||
|
||||
-static int qemuSetupDiskCgroup(virCgroupPtr cgroup,
|
||||
+static int qemuSetupDiskCgroup(struct qemud_driver *driver,
|
||||
+ virCgroupPtr cgroup,
|
||||
virDomainDiskDefPtr disk)
|
||||
{
|
||||
return virDomainDiskDefForeachPath(disk,
|
||||
- true,
|
||||
+ driver->allowDiskFormatProbing,
|
||||
true,
|
||||
qemuSetupDiskPathAllow,
|
||||
cgroup);
|
||||
@@ -3109,11 +3111,12 @@ static int qemuTeardownDiskPathDeny(virDomainDiskDefPtr disk ATTRIBUTE_UNUSED,
|
||||
}
|
||||
|
||||
|
||||
-static int qemuTeardownDiskCgroup(virCgroupPtr cgroup,
|
||||
+static int qemuTeardownDiskCgroup(struct qemud_driver *driver,
|
||||
+ virCgroupPtr cgroup,
|
||||
virDomainDiskDefPtr disk)
|
||||
{
|
||||
return virDomainDiskDefForeachPath(disk,
|
||||
- true,
|
||||
+ driver->allowDiskFormatProbing,
|
||||
true,
|
||||
qemuTeardownDiskPathDeny,
|
||||
cgroup);
|
||||
@@ -3180,7 +3183,7 @@ static int qemuSetupCgroup(struct qemud_driver *driver,
|
||||
}
|
||||
|
||||
for (i = 0; i < vm->def->ndisks ; i++) {
|
||||
- if (qemuSetupDiskCgroup(cgroup, vm->def->disks[i]) < 0)
|
||||
+ if (qemuSetupDiskCgroup(driver, cgroup, vm->def->disks[i]) < 0)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
@@ -8033,7 +8036,7 @@ static int qemudDomainAttachDevice(virDomainPtr dom,
|
||||
vm->def->name);
|
||||
goto endjob;
|
||||
}
|
||||
- if (qemuSetupDiskCgroup(cgroup, dev->data.disk) < 0)
|
||||
+ if (qemuSetupDiskCgroup(driver, cgroup, dev->data.disk) < 0)
|
||||
goto endjob;
|
||||
}
|
||||
|
||||
@@ -8078,7 +8081,7 @@ static int qemudDomainAttachDevice(virDomainPtr dom,
|
||||
/* Fallthrough */
|
||||
}
|
||||
if (ret != 0 && cgroup) {
|
||||
- if (qemuTeardownDiskCgroup(cgroup, dev->data.disk) < 0)
|
||||
+ if (qemuTeardownDiskCgroup(driver, cgroup, dev->data.disk) < 0)
|
||||
VIR_WARN("Failed to teardown cgroup for disk path %s",
|
||||
NULLSTR(dev->data.disk->src));
|
||||
}
|
||||
@@ -8278,7 +8281,7 @@ static int qemuDomainUpdateDeviceFlags(virDomainPtr dom,
|
||||
vm->def->name);
|
||||
goto endjob;
|
||||
}
|
||||
- if (qemuSetupDiskCgroup(cgroup, dev->data.disk) < 0)
|
||||
+ if (qemuSetupDiskCgroup(driver, cgroup, dev->data.disk) < 0)
|
||||
goto endjob;
|
||||
}
|
||||
|
||||
@@ -8301,7 +8304,7 @@ static int qemuDomainUpdateDeviceFlags(virDomainPtr dom,
|
||||
}
|
||||
|
||||
if (ret != 0 && cgroup) {
|
||||
- if (qemuTeardownDiskCgroup(cgroup, dev->data.disk) < 0)
|
||||
+ if (qemuTeardownDiskCgroup(driver, cgroup, dev->data.disk) < 0)
|
||||
VIR_WARN("Failed to teardown cgroup for disk path %s",
|
||||
NULLSTR(dev->data.disk->src));
|
||||
}
|
||||
@@ -8429,7 +8432,7 @@ static int qemudDomainDetachPciDiskDevice(struct qemud_driver *driver,
|
||||
VIR_WARN("Unable to restore security label on %s", dev->data.disk->src);
|
||||
|
||||
if (cgroup != NULL) {
|
||||
- if (qemuTeardownDiskCgroup(cgroup, dev->data.disk) < 0)
|
||||
+ if (qemuTeardownDiskCgroup(driver, cgroup, dev->data.disk) < 0)
|
||||
VIR_WARN("Failed to teardown cgroup for disk path %s",
|
||||
NULLSTR(dev->data.disk->src));
|
||||
}
|
||||
@@ -8493,7 +8496,7 @@ static int qemudDomainDetachSCSIDiskDevice(struct qemud_driver *driver,
|
||||
VIR_WARN("Unable to restore security label on %s", dev->data.disk->src);
|
||||
|
||||
if (cgroup != NULL) {
|
||||
- if (qemuTeardownDiskCgroup(cgroup, dev->data.disk) < 0)
|
||||
+ if (qemuTeardownDiskCgroup(driver, cgroup, dev->data.disk) < 0)
|
||||
VIR_WARN("Failed to teardown cgroup for disk path %s",
|
||||
NULLSTR(dev->data.disk->src));
|
||||
}
|
||||
@@ -9672,8 +9675,15 @@ static int qemuDomainGetBlockInfo(virDomainPtr dom,
|
||||
goto cleanup;
|
||||
}
|
||||
} else {
|
||||
- if ((format = virStorageFileProbeFormat(disk->src)) < 0)
|
||||
+ if (driver->allowDiskFormatProbing) {
|
||||
+ if ((format = virStorageFileProbeFormat(disk->src)) < 0)
|
||||
+ goto cleanup;
|
||||
+ } else {
|
||||
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
+ _("no disk format for %s and probing is disabled"),
|
||||
+ disk->src);
|
||||
goto cleanup;
|
||||
+ }
|
||||
}
|
||||
|
||||
if (virStorageFileGetMetadataFromFD(path, fd,
|
||||
diff --git a/src/qemu/qemu_security_dac.c b/src/qemu/qemu_security_dac.c
|
||||
index 0bbcf69..55dc0c6 100644
|
||||
--- a/src/qemu/qemu_security_dac.c
|
||||
+++ b/src/qemu/qemu_security_dac.c
|
||||
@@ -117,7 +117,7 @@ qemuSecurityDACSetSecurityImageLabel(virSecurityDriverPtr drv ATTRIBUTE_UNUSED,
|
||||
return 0;
|
||||
|
||||
return virDomainDiskDefForeachPath(disk,
|
||||
- true,
|
||||
+ driver->allowDiskFormatProbing,
|
||||
false,
|
||||
qemuSecurityDACSetSecurityFileLabel,
|
||||
NULL);
|
||||
diff --git a/src/qemu/test_libvirtd_qemu.aug b/src/qemu/test_libvirtd_qemu.aug
|
||||
index 3326cc5..f0c4a0d 100644
|
||||
--- a/src/qemu/test_libvirtd_qemu.aug
|
||||
+++ b/src/qemu/test_libvirtd_qemu.aug
|
||||
@@ -101,6 +101,8 @@ relaxed_acs_check = 1
|
||||
vnc_allow_host_audio = 1
|
||||
|
||||
clear_emulator_capabilities = 0
|
||||
+
|
||||
+allow_disk_format_probing = 1
|
||||
"
|
||||
|
||||
test Libvirtd_qemu.lns get conf =
|
||||
@@ -212,3 +214,5 @@ clear_emulator_capabilities = 0
|
||||
{ "vnc_allow_host_audio" = "1" }
|
||||
{ "#empty" }
|
||||
{ "clear_emulator_capabilities" = "0" }
|
||||
+{ "#empty" }
|
||||
+{ "allow_disk_format_probing" = "1" }
|
||||
diff --git a/src/security/security_apparmor.c b/src/security/security_apparmor.c
|
||||
index cb5c739..c5f9829 100644
|
||||
--- a/src/security/security_apparmor.c
|
||||
+++ b/src/security/security_apparmor.c
|
||||
@@ -157,6 +157,8 @@ load_profile(virSecurityDriverPtr drv,
|
||||
char *xml = NULL;
|
||||
int pipefd[2];
|
||||
pid_t child;
|
||||
+ const char *probe = virSecurityDriverGetAllowDiskFormatProbing(drv)
|
||||
+ ? "1" : "0";
|
||||
|
||||
if (pipe(pipefd) < -1) {
|
||||
virReportSystemError(errno, "%s", _("unable to create pipe"));
|
||||
@@ -172,19 +174,19 @@ load_profile(virSecurityDriverPtr drv,
|
||||
|
||||
if (create) {
|
||||
const char *const argv[] = {
|
||||
- VIRT_AA_HELPER, "-c", "-u", profile, NULL
|
||||
+ VIRT_AA_HELPER, "-p", probe, "-c", "-u", profile, NULL
|
||||
};
|
||||
ret = virExec(argv, NULL, NULL, &child,
|
||||
pipefd[0], NULL, NULL, VIR_EXEC_NONE);
|
||||
} else if (fn) {
|
||||
const char *const argv[] = {
|
||||
- VIRT_AA_HELPER, "-r", "-u", profile, "-f", fn, NULL
|
||||
+ VIRT_AA_HELPER, "-p", probe, "-r", "-u", profile, "-f", fn, NULL
|
||||
};
|
||||
ret = virExec(argv, NULL, NULL, &child,
|
||||
pipefd[0], NULL, NULL, VIR_EXEC_NONE);
|
||||
} else {
|
||||
const char *const argv[] = {
|
||||
- VIRT_AA_HELPER, "-r", "-u", profile, NULL
|
||||
+ VIRT_AA_HELPER, "-p", probe, "-r", "-u", profile, NULL
|
||||
};
|
||||
ret = virExec(argv, NULL, NULL, &child,
|
||||
pipefd[0], NULL, NULL, VIR_EXEC_NONE);
|
||||
@@ -347,9 +349,11 @@ AppArmorSecurityDriverProbe(void)
|
||||
* currently not used.
|
||||
*/
|
||||
static int
|
||||
-AppArmorSecurityDriverOpen(virSecurityDriverPtr drv)
|
||||
+AppArmorSecurityDriverOpen(virSecurityDriverPtr drv,
|
||||
+ bool allowDiskFormatProbing)
|
||||
{
|
||||
virSecurityDriverSetDOI(drv, SECURITY_APPARMOR_VOID_DOI);
|
||||
+ virSecurityDriverSetAllowDiskFormatProbing(drv, allowDiskFormatProbing);
|
||||
return 0;
|
||||
}
|
||||
|
||||
diff --git a/src/security/security_driver.c b/src/security/security_driver.c
|
||||
index aac9f78..9e32fa4 100644
|
||||
--- a/src/security/security_driver.c
|
||||
+++ b/src/security/security_driver.c
|
||||
@@ -56,7 +56,8 @@ virSecurityDriverVerify(virDomainDefPtr def)
|
||||
|
||||
int
|
||||
virSecurityDriverStartup(virSecurityDriverPtr *drv,
|
||||
- const char *name)
|
||||
+ const char *name,
|
||||
+ bool allowDiskFormatProbing)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
@@ -72,7 +73,7 @@ virSecurityDriverStartup(virSecurityDriverPtr *drv,
|
||||
switch (tmp->probe()) {
|
||||
case SECURITY_DRIVER_ENABLE:
|
||||
virSecurityDriverInit(tmp);
|
||||
- if (tmp->open(tmp) == -1) {
|
||||
+ if (tmp->open(tmp, allowDiskFormatProbing) == -1) {
|
||||
return -1;
|
||||
} else {
|
||||
*drv = tmp;
|
||||
@@ -125,3 +126,14 @@ virSecurityDriverGetModel(virSecurityDriverPtr drv)
|
||||
{
|
||||
return drv->name;
|
||||
}
|
||||
+
|
||||
+void virSecurityDriverSetAllowDiskFormatProbing(virSecurityDriverPtr drv,
|
||||
+ bool allowDiskFormatProbing)
|
||||
+{
|
||||
+ drv->_private.allowDiskFormatProbing = allowDiskFormatProbing;
|
||||
+}
|
||||
+
|
||||
+bool virSecurityDriverGetAllowDiskFormatProbing(virSecurityDriverPtr drv)
|
||||
+{
|
||||
+ return drv->_private.allowDiskFormatProbing;
|
||||
+}
|
||||
diff --git a/src/security/security_driver.h b/src/security/security_driver.h
|
||||
index 61c9eb0..d768f32 100644
|
||||
--- a/src/security/security_driver.h
|
||||
+++ b/src/security/security_driver.h
|
||||
@@ -33,7 +33,8 @@ typedef struct _virSecurityDriverState virSecurityDriverState;
|
||||
typedef virSecurityDriverState *virSecurityDriverStatePtr;
|
||||
|
||||
typedef virSecurityDriverStatus (*virSecurityDriverProbe) (void);
|
||||
-typedef int (*virSecurityDriverOpen) (virSecurityDriverPtr drv);
|
||||
+typedef int (*virSecurityDriverOpen) (virSecurityDriverPtr drv,
|
||||
+ bool allowDiskFormatProbing);
|
||||
typedef int (*virSecurityDomainRestoreImageLabel) (virSecurityDriverPtr drv,
|
||||
virDomainObjPtr vm,
|
||||
virDomainDiskDefPtr disk);
|
||||
@@ -102,12 +103,14 @@ struct _virSecurityDriver {
|
||||
*/
|
||||
struct {
|
||||
char doi[VIR_SECURITY_DOI_BUFLEN];
|
||||
+ bool allowDiskFormatProbing;
|
||||
} _private;
|
||||
};
|
||||
|
||||
/* Global methods */
|
||||
int virSecurityDriverStartup(virSecurityDriverPtr *drv,
|
||||
- const char *name);
|
||||
+ const char *name,
|
||||
+ bool allowDiskFormatProbing);
|
||||
|
||||
int
|
||||
virSecurityDriverVerify(virDomainDefPtr def);
|
||||
@@ -120,7 +123,10 @@ virSecurityDriverVerify(virDomainDefPtr def);
|
||||
void virSecurityDriverInit(virSecurityDriverPtr drv);
|
||||
int virSecurityDriverSetDOI(virSecurityDriverPtr drv,
|
||||
const char *doi);
|
||||
+void virSecurityDriverSetAllowDiskFormatProbing(virSecurityDriverPtr drv,
|
||||
+ bool allowDiskFormatProbing);
|
||||
const char *virSecurityDriverGetDOI(virSecurityDriverPtr drv);
|
||||
const char *virSecurityDriverGetModel(virSecurityDriverPtr drv);
|
||||
+bool virSecurityDriverGetAllowDiskFormatProbing(virSecurityDriverPtr drv);
|
||||
|
||||
#endif /* __VIR_SECURITY_H__ */
|
||||
diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c
|
||||
index cc3812b..a9dd836 100644
|
||||
--- a/src/security/security_selinux.c
|
||||
+++ b/src/security/security_selinux.c
|
||||
@@ -266,13 +266,15 @@ SELinuxSecurityDriverProbe(void)
|
||||
}
|
||||
|
||||
static int
|
||||
-SELinuxSecurityDriverOpen(virSecurityDriverPtr drv)
|
||||
+SELinuxSecurityDriverOpen(virSecurityDriverPtr drv,
|
||||
+ bool allowDiskFormatProbing)
|
||||
{
|
||||
/*
|
||||
* Where will the DOI come from? SELinux configuration, or qemu
|
||||
* configuration? For the moment, we'll just set it to "0".
|
||||
*/
|
||||
virSecurityDriverSetDOI(drv, SECURITY_SELINUX_VOID_DOI);
|
||||
+ virSecurityDriverSetAllowDiskFormatProbing(drv, allowDiskFormatProbing);
|
||||
return SELinuxInitialize();
|
||||
}
|
||||
|
||||
@@ -467,18 +469,19 @@ SELinuxSetSecurityFileLabel(virDomainDiskDefPtr disk,
|
||||
}
|
||||
|
||||
static int
|
||||
-SELinuxSetSecurityImageLabel(virSecurityDriverPtr drv ATTRIBUTE_UNUSED,
|
||||
+SELinuxSetSecurityImageLabel(virSecurityDriverPtr drv,
|
||||
virDomainObjPtr vm,
|
||||
virDomainDiskDefPtr disk)
|
||||
|
||||
{
|
||||
const virSecurityLabelDefPtr secdef = &vm->def->seclabel;
|
||||
+ bool allowDiskFormatProbing = virSecurityDriverGetAllowDiskFormatProbing(drv);
|
||||
|
||||
if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC)
|
||||
return 0;
|
||||
|
||||
return virDomainDiskDefForeachPath(disk,
|
||||
- true,
|
||||
+ allowDiskFormatProbing,
|
||||
false,
|
||||
SELinuxSetSecurityFileLabel,
|
||||
secdef);
|
||||
diff --git a/src/security/virt-aa-helper.c b/src/security/virt-aa-helper.c
|
||||
index 9ed0cd3..521545d 100644
|
||||
--- a/src/security/virt-aa-helper.c
|
||||
+++ b/src/security/virt-aa-helper.c
|
||||
@@ -40,6 +40,7 @@
|
||||
static char *progname;
|
||||
|
||||
typedef struct {
|
||||
+ bool allowDiskFormatProbing;
|
||||
char uuid[PROFILE_NAME_SIZE]; /* UUID of vm */
|
||||
bool dryrun; /* dry run */
|
||||
char cmd; /* 'c' create
|
||||
@@ -844,7 +845,7 @@ get_files(vahControl * ctl)
|
||||
|
||||
for (i = 0; i < ctl->def->ndisks; i++) {
|
||||
int ret = virDomainDiskDefForeachPath(ctl->def->disks[i],
|
||||
- true,
|
||||
+ ctl->allowDiskFormatProbing,
|
||||
false,
|
||||
add_file_path,
|
||||
&buf);
|
||||
@@ -943,6 +944,7 @@ vahParseArgv(vahControl * ctl, int argc, char **argv)
|
||||
{
|
||||
int arg, idx = 0;
|
||||
struct option opt[] = {
|
||||
+ {"probing", 1, 0, 'p' },
|
||||
{"add", 0, 0, 'a'},
|
||||
{"create", 0, 0, 'c'},
|
||||
{"dryrun", 0, 0, 'd'},
|
||||
@@ -991,6 +993,12 @@ vahParseArgv(vahControl * ctl, int argc, char **argv)
|
||||
PROFILE_NAME_SIZE) == NULL)
|
||||
vah_error(ctl, 1, "error copying UUID");
|
||||
break;
|
||||
+ case 'p':
|
||||
+ if (STREQ(optarg, "1"))
|
||||
+ ctl->allowDiskFormatProbing = true;
|
||||
+ else
|
||||
+ ctl->allowDiskFormatProbing = false;
|
||||
+ break;
|
||||
default:
|
||||
vah_error(ctl, 1, "unsupported option");
|
||||
break;
|
||||
diff --git a/tests/seclabeltest.c b/tests/seclabeltest.c
|
||||
index 26d1f86..ef3f026 100644
|
||||
--- a/tests/seclabeltest.c
|
||||
+++ b/tests/seclabeltest.c
|
||||
@@ -15,7 +15,7 @@ main (int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
|
||||
const char *doi, *model;
|
||||
virSecurityDriverPtr security_drv;
|
||||
|
||||
- ret = virSecurityDriverStartup (&security_drv, "selinux");
|
||||
+ ret = virSecurityDriverStartup (&security_drv, "selinux", false);
|
||||
if (ret == -1)
|
||||
{
|
||||
fprintf (stderr, "Failed to start security driver");
|
||||
--
|
||||
1.7.1.1
|
||||
|
||||
@@ -1,94 +0,0 @@
|
||||
From 3534cd47a57ee9cf7041472511444784f14d6939 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel P. Berrange <berrange@redhat.com>
|
||||
Date: Mon, 14 Jun 2010 16:08:55 +0100
|
||||
Subject: [PATCH 09/11] Add ability to set a default driver name/type when parsing disks
|
||||
|
||||
Record a default driver name/type in capabilities struct. Use this
|
||||
when parsing disks if value is not set in XML config.
|
||||
|
||||
* src/conf/capabilities.h: Record default driver name/type for disks
|
||||
* src/conf/domain_conf.c: Fallback to default driver name/type
|
||||
when parsing disks
|
||||
* src/qemu/qemu_driver.c: Set default driver name/type to raw
|
||||
---
|
||||
src/conf/capabilities.h | 2 ++
|
||||
src/conf/domain_conf.c | 16 +++++++++++++++-
|
||||
src/qemu/qemu_driver.c | 8 ++++++++
|
||||
3 files changed, 25 insertions(+), 1 deletions(-)
|
||||
|
||||
diff --git a/src/conf/capabilities.h b/src/conf/capabilities.h
|
||||
index 9290c82..f676eb8 100644
|
||||
--- a/src/conf/capabilities.h
|
||||
+++ b/src/conf/capabilities.h
|
||||
@@ -123,6 +123,8 @@ struct _virCaps {
|
||||
virCapsGuestPtr *guests;
|
||||
unsigned char macPrefix[VIR_MAC_PREFIX_BUFLEN];
|
||||
unsigned int emulatorRequired : 1;
|
||||
+ const char *defaultDiskDriverName;
|
||||
+ const char *defaultDiskDriverType;
|
||||
void *(*privateDataAllocFunc)(void);
|
||||
void (*privateDataFreeFunc)(void *);
|
||||
int (*privateDataXMLFormat)(virBufferPtr, void *);
|
||||
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
|
||||
index b20ca97..f3b8cfa 100644
|
||||
--- a/src/conf/domain_conf.c
|
||||
+++ b/src/conf/domain_conf.c
|
||||
@@ -1639,6 +1639,16 @@ virDomainDiskDefParseXML(virCapsPtr caps,
|
||||
def->serial = serial;
|
||||
serial = NULL;
|
||||
|
||||
+ if (!def->driverType &&
|
||||
+ caps->defaultDiskDriverType &&
|
||||
+ !(def->driverType = strdup(caps->defaultDiskDriverType)))
|
||||
+ goto no_memory;
|
||||
+
|
||||
+ if (!def->driverName &&
|
||||
+ caps->defaultDiskDriverName &&
|
||||
+ !(def->driverName = strdup(caps->defaultDiskDriverName)))
|
||||
+ goto no_memory;
|
||||
+
|
||||
if (def->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE
|
||||
&& virDomainDiskDefAssignAddress(caps, def) < 0)
|
||||
goto error;
|
||||
@@ -1659,6 +1669,9 @@ cleanup:
|
||||
|
||||
return def;
|
||||
|
||||
+no_memory:
|
||||
+ virReportOOMError();
|
||||
+
|
||||
error:
|
||||
virDomainDiskDefFree(def);
|
||||
def = NULL;
|
||||
@@ -4275,7 +4288,8 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps,
|
||||
if (n && VIR_ALLOC_N(def->disks, n) < 0)
|
||||
goto no_memory;
|
||||
for (i = 0 ; i < n ; i++) {
|
||||
- virDomainDiskDefPtr disk = virDomainDiskDefParseXML(caps, nodes[i],
|
||||
+ virDomainDiskDefPtr disk = virDomainDiskDefParseXML(caps,
|
||||
+ nodes[i],
|
||||
flags);
|
||||
if (!disk)
|
||||
goto error;
|
||||
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
|
||||
index 3c479c5..14b790e 100644
|
||||
--- a/src/qemu/qemu_driver.c
|
||||
+++ b/src/qemu/qemu_driver.c
|
||||
@@ -1357,6 +1357,14 @@ qemuCreateCapabilities(virCapsPtr oldcaps,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
+ if (driver->allowDiskFormatProbing) {
|
||||
+ caps->defaultDiskDriverName = NULL;
|
||||
+ caps->defaultDiskDriverType = NULL;
|
||||
+ } else {
|
||||
+ caps->defaultDiskDriverName = "qemu";
|
||||
+ caps->defaultDiskDriverType = "raw";
|
||||
+ }
|
||||
+
|
||||
/* Domain XML parser hooks */
|
||||
caps->privateDataAllocFunc = qemuDomainObjPrivateAlloc;
|
||||
caps->privateDataFreeFunc = qemuDomainObjPrivateFree;
|
||||
--
|
||||
1.7.1.1
|
||||
|
||||
@@ -1,291 +0,0 @@
|
||||
From 2ba8625d6d148fa489586efabdfaf2ef20903762 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel P. Berrange <berrange@redhat.com>
|
||||
Date: Wed, 16 Jun 2010 14:14:05 +0100
|
||||
Subject: [PATCH 10/11] Rewrite qemu-img backing store format handling
|
||||
|
||||
When creating qcow2 files with a backing store, it is important
|
||||
to set an explicit format to prevent QEMU probing. The storage
|
||||
backend was only doing this if it found a 'kvm-img' binary. This
|
||||
is wrong because plenty of kvm-img binaries don't support an
|
||||
explicit format, and plenty of 'qemu-img' binaries do support
|
||||
a format. The result was that most qcow2 files were not getting
|
||||
a backing store format.
|
||||
|
||||
This patch runs 'qemu-img -h' to check for the two support
|
||||
argument formats
|
||||
|
||||
'-o backing_format=raw'
|
||||
'-F raw'
|
||||
|
||||
and use whichever option it finds
|
||||
|
||||
* src/storage/storage_backend.c: Query binary to determine
|
||||
how to set the backing store format
|
||||
---
|
||||
src/storage/storage_backend.c | 214 +++++++++++++++++++++++++++++------------
|
||||
1 files changed, 152 insertions(+), 62 deletions(-)
|
||||
|
||||
diff --git a/src/storage/storage_backend.c b/src/storage/storage_backend.c
|
||||
index aba8937..c185693 100644
|
||||
--- a/src/storage/storage_backend.c
|
||||
+++ b/src/storage/storage_backend.c
|
||||
@@ -561,6 +561,69 @@ static int virStorageBackendCreateExecCommand(virStoragePoolObjPtr pool,
|
||||
return 0;
|
||||
}
|
||||
|
||||
+enum {
|
||||
+ QEMU_IMG_BACKING_FORMAT_NONE = 0,
|
||||
+ QEMU_IMG_BACKING_FORMAT_FLAG,
|
||||
+ QEMU_IMG_BACKING_FORMAT_OPTIONS,
|
||||
+};
|
||||
+
|
||||
+static int virStorageBackendQEMUImgBackingFormat(const char *qemuimg)
|
||||
+{
|
||||
+ const char *const qemuarg[] = { qemuimg, "-h", NULL };
|
||||
+ const char *const qemuenv[] = { "LC_ALL=C", NULL };
|
||||
+ pid_t child = 0;
|
||||
+ int status;
|
||||
+ int newstdout = -1;
|
||||
+ char *help = NULL;
|
||||
+ enum { MAX_HELP_OUTPUT_SIZE = 1024*8 };
|
||||
+ int len;
|
||||
+ char *start;
|
||||
+ char *end;
|
||||
+ char *tmp;
|
||||
+ int ret = -1;
|
||||
+
|
||||
+ if (virExec(qemuarg, qemuenv, NULL,
|
||||
+ &child, -1, &newstdout, NULL, VIR_EXEC_CLEAR_CAPS) < 0)
|
||||
+ goto cleanup;
|
||||
+
|
||||
+ if ((len = virFileReadLimFD(newstdout, MAX_HELP_OUTPUT_SIZE, &help)) < 0) {
|
||||
+ virReportSystemError(errno,
|
||||
+ _("Unable to read '%s -h' output"),
|
||||
+ qemuimg);
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+
|
||||
+ start = strstr(help, " create ");
|
||||
+ end = strstr(start, "\n");
|
||||
+ if ((tmp = strstr(start, "-F fmt")) && tmp < end)
|
||||
+ ret = QEMU_IMG_BACKING_FORMAT_FLAG;
|
||||
+ else if ((tmp = strstr(start, "[-o options]")) && tmp < end)
|
||||
+ ret = QEMU_IMG_BACKING_FORMAT_OPTIONS;
|
||||
+ else
|
||||
+ ret = QEMU_IMG_BACKING_FORMAT_NONE;
|
||||
+
|
||||
+cleanup:
|
||||
+ VIR_FREE(help);
|
||||
+ close(newstdout);
|
||||
+rewait:
|
||||
+ if (child) {
|
||||
+ if (waitpid(child, &status, 0) != child) {
|
||||
+ if (errno == EINTR)
|
||||
+ goto rewait;
|
||||
+
|
||||
+ VIR_ERROR(_("Unexpected exit status from qemu %d pid %lu"),
|
||||
+ WEXITSTATUS(status), (unsigned long)child);
|
||||
+ }
|
||||
+ if (WEXITSTATUS(status) != 0) {
|
||||
+ VIR_WARN("Unexpected exit status '%d', qemu probably failed",
|
||||
+ WEXITSTATUS(status));
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+
|
||||
static int
|
||||
virStorageBackendCreateQemuImg(virConnectPtr conn,
|
||||
virStoragePoolObjPtr pool,
|
||||
@@ -568,10 +631,9 @@ virStorageBackendCreateQemuImg(virConnectPtr conn,
|
||||
virStorageVolDefPtr inputvol,
|
||||
unsigned int flags ATTRIBUTE_UNUSED)
|
||||
{
|
||||
- int ret;
|
||||
+ int ret = -1;
|
||||
char size[100];
|
||||
char *create_tool;
|
||||
- short use_kvmimg;
|
||||
|
||||
const char *type = virStorageFileFormatTypeToString(vol->target.format);
|
||||
const char *backingType = vol->backingStore.path ?
|
||||
@@ -582,41 +644,10 @@ virStorageBackendCreateQemuImg(virConnectPtr conn,
|
||||
const char *inputPath = inputvol ? inputvol->target.path : NULL;
|
||||
/* Treat input block devices as 'raw' format */
|
||||
const char *inputType = inputPath ?
|
||||
- virStorageFileFormatTypeToString(inputvol->type == VIR_STORAGE_VOL_BLOCK ? VIR_STORAGE_FILE_RAW : inputvol->target.format) :
|
||||
- NULL;
|
||||
-
|
||||
- const char **imgargv;
|
||||
- /* The extra NULL field is for indicating encryption (-e). */
|
||||
- const char *imgargvnormal[] = {
|
||||
- NULL, "create",
|
||||
- "-f", type,
|
||||
- vol->target.path,
|
||||
- size,
|
||||
- NULL,
|
||||
- NULL
|
||||
- };
|
||||
- /* Extra NULL fields are for including "backingType" when using
|
||||
- * kvm-img (-F backingType), and for indicating encryption (-e).
|
||||
- */
|
||||
- const char *imgargvbacking[] = {
|
||||
- NULL, "create",
|
||||
- "-f", type,
|
||||
- "-b", vol->backingStore.path,
|
||||
- vol->target.path,
|
||||
- size,
|
||||
- NULL,
|
||||
- NULL,
|
||||
- NULL,
|
||||
- NULL
|
||||
- };
|
||||
- const char *convargv[] = {
|
||||
- NULL, "convert",
|
||||
- "-f", inputType,
|
||||
- "-O", type,
|
||||
- inputPath,
|
||||
- vol->target.path,
|
||||
- NULL,
|
||||
- };
|
||||
+ virStorageFileFormatTypeToString(inputvol->type == VIR_STORAGE_VOL_BLOCK ?
|
||||
+ VIR_STORAGE_FILE_RAW :
|
||||
+ inputvol->target.format) :
|
||||
+ NULL;
|
||||
|
||||
if (type == NULL) {
|
||||
virStorageReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
@@ -690,44 +721,103 @@ virStorageBackendCreateQemuImg(virConnectPtr conn,
|
||||
}
|
||||
}
|
||||
|
||||
- if ((create_tool = virFindFileInPath("kvm-img")) != NULL)
|
||||
- use_kvmimg = 1;
|
||||
- else if ((create_tool = virFindFileInPath("qemu-img")) != NULL)
|
||||
- use_kvmimg = 0;
|
||||
- else {
|
||||
+ /* Size in KB */
|
||||
+ snprintf(size, sizeof(size), "%lluK", vol->capacity/1024);
|
||||
+
|
||||
+ /* KVM is usually ahead of qemu on features, so try that first */
|
||||
+ create_tool = virFindFileInPath("kvm-img");
|
||||
+ if (!create_tool)
|
||||
+ create_tool = virFindFileInPath("qemu-img");
|
||||
+
|
||||
+ if (!create_tool) {
|
||||
virStorageReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
"%s", _("unable to find kvm-img or qemu-img"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (inputvol) {
|
||||
- convargv[0] = create_tool;
|
||||
- imgargv = convargv;
|
||||
+ const char *imgargv[] = {
|
||||
+ create_tool,
|
||||
+ "convert",
|
||||
+ "-f", inputType,
|
||||
+ "-O", type,
|
||||
+ inputPath,
|
||||
+ vol->target.path,
|
||||
+ NULL,
|
||||
+ };
|
||||
+
|
||||
+ ret = virStorageBackendCreateExecCommand(pool, vol, imgargv);
|
||||
} else if (vol->backingStore.path) {
|
||||
- imgargvbacking[0] = create_tool;
|
||||
- if (use_kvmimg) {
|
||||
- imgargvbacking[6] = "-F";
|
||||
- imgargvbacking[7] = backingType;
|
||||
- imgargvbacking[8] = vol->target.path;
|
||||
- imgargvbacking[9] = size;
|
||||
+ const char *imgargv[] = {
|
||||
+ create_tool,
|
||||
+ "create",
|
||||
+ "-f", type,
|
||||
+ "-b", vol->backingStore.path,
|
||||
+ NULL,
|
||||
+ NULL,
|
||||
+ NULL,
|
||||
+ NULL,
|
||||
+ NULL,
|
||||
+ NULL
|
||||
+ };
|
||||
+ int imgformat = virStorageBackendQEMUImgBackingFormat(create_tool);
|
||||
+ char *optflag = NULL;
|
||||
+ if (imgformat < 0)
|
||||
+ goto cleanup;
|
||||
+
|
||||
+ switch (imgformat) {
|
||||
+ case QEMU_IMG_BACKING_FORMAT_FLAG:
|
||||
+ imgargv[6] = "-F";
|
||||
+ imgargv[7] = backingType;
|
||||
+ imgargv[8] = vol->target.path;
|
||||
+ imgargv[9] = size;
|
||||
+ if (vol->target.encryption != NULL)
|
||||
+ imgargv[10] = "-e";
|
||||
+ break;
|
||||
+
|
||||
+ case QEMU_IMG_BACKING_FORMAT_OPTIONS:
|
||||
+ if (virAsprintf(&optflag, "backing_fmt=%s", backingType) < 0) {
|
||||
+ virReportOOMError();
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+ imgargv[6] = "-o";
|
||||
+ imgargv[7] = optflag;
|
||||
+ imgargv[8] = vol->target.path;
|
||||
+ imgargv[9] = size;
|
||||
if (vol->target.encryption != NULL)
|
||||
- imgargvbacking[10] = "-e";
|
||||
- } else if (vol->target.encryption != NULL)
|
||||
- imgargvbacking[8] = "-e";
|
||||
- imgargv = imgargvbacking;
|
||||
+ imgargv[10] = "-e";
|
||||
+ break;
|
||||
+
|
||||
+ default:
|
||||
+ VIR_INFO("Unable to set backing store format for %s with %s",
|
||||
+ vol->target.path, create_tool);
|
||||
+ imgargv[6] = vol->target.path;
|
||||
+ imgargv[7] = size;
|
||||
+ if (vol->target.encryption != NULL)
|
||||
+ imgargv[8] = "-e";
|
||||
+ }
|
||||
+
|
||||
+ ret = virStorageBackendCreateExecCommand(pool, vol, imgargv);
|
||||
+ VIR_FREE(optflag);
|
||||
} else {
|
||||
- imgargvnormal[0] = create_tool;
|
||||
- imgargv = imgargvnormal;
|
||||
+ /* The extra NULL field is for indicating encryption (-e). */
|
||||
+ const char *imgargv[] = {
|
||||
+ create_tool,
|
||||
+ "create",
|
||||
+ "-f", type,
|
||||
+ vol->target.path,
|
||||
+ size,
|
||||
+ NULL,
|
||||
+ NULL
|
||||
+ };
|
||||
if (vol->target.encryption != NULL)
|
||||
imgargv[6] = "-e";
|
||||
- }
|
||||
|
||||
+ ret = virStorageBackendCreateExecCommand(pool, vol, imgargv);
|
||||
+ }
|
||||
|
||||
- /* Size in KB */
|
||||
- snprintf(size, sizeof(size), "%lluK", vol->capacity/1024);
|
||||
-
|
||||
- ret = virStorageBackendCreateExecCommand(pool, vol, imgargv);
|
||||
- VIR_FREE(imgargv[0]);
|
||||
+ cleanup:
|
||||
+ VIR_FREE(create_tool);
|
||||
|
||||
return ret;
|
||||
}
|
||||
--
|
||||
1.7.1.1
|
||||
|
||||
@@ -1,165 +0,0 @@
|
||||
From d33f44c2e74de28c89b64cdc2c0a6564662e075c Mon Sep 17 00:00:00 2001
|
||||
From: Daniel P. Berrange <berrange@redhat.com>
|
||||
Date: Fri, 9 Jul 2010 11:28:40 +0100
|
||||
Subject: [PATCH 11/11] Use the extract backing store format in storage volume lookup
|
||||
|
||||
The storage volume lookup code was probing for the backing store
|
||||
format, instead of using the format extracted from the file
|
||||
itself. This meant it could report in accurate information. If
|
||||
a format is included in the file, then use that in preference,
|
||||
with probing as a fallback.
|
||||
|
||||
* src/storage/storage_backend_fs.c: Use extracted backing store
|
||||
format
|
||||
---
|
||||
src/storage/storage_backend_fs.c | 80 +++++++++++++++++---------------------
|
||||
1 files changed, 36 insertions(+), 44 deletions(-)
|
||||
|
||||
diff --git a/src/storage/storage_backend_fs.c b/src/storage/storage_backend_fs.c
|
||||
index d3ac0fe..ffb0071 100644
|
||||
--- a/src/storage/storage_backend_fs.c
|
||||
+++ b/src/storage/storage_backend_fs.c
|
||||
@@ -51,6 +51,7 @@
|
||||
static int
|
||||
virStorageBackendProbeTarget(virStorageVolTargetPtr target,
|
||||
char **backingStore,
|
||||
+ int *backingStoreFormat,
|
||||
unsigned long long *allocation,
|
||||
unsigned long long *capacity,
|
||||
virStorageEncryptionPtr *encryption)
|
||||
@@ -58,6 +59,10 @@ virStorageBackendProbeTarget(virStorageVolTargetPtr target,
|
||||
int fd, ret;
|
||||
virStorageFileMetadata meta;
|
||||
|
||||
+ if (backingStore)
|
||||
+ *backingStore = NULL;
|
||||
+ if (backingStoreFormat)
|
||||
+ *backingStoreFormat = VIR_STORAGE_FILE_AUTO;
|
||||
if (encryption)
|
||||
*encryption = NULL;
|
||||
|
||||
@@ -89,22 +94,30 @@ virStorageBackendProbeTarget(virStorageVolTargetPtr target,
|
||||
|
||||
close(fd);
|
||||
|
||||
- if (backingStore) {
|
||||
- *backingStore = meta.backingStore;
|
||||
- meta.backingStore = NULL;
|
||||
+ if (meta.backingStore) {
|
||||
+ if (backingStore) {
|
||||
+ *backingStore = meta.backingStore;
|
||||
+ meta.backingStore = NULL;
|
||||
+ if (meta.backingStoreFormat == VIR_STORAGE_FILE_AUTO) {
|
||||
+ if ((*backingStoreFormat = virStorageFileProbeFormat(*backingStore)) < 0) {
|
||||
+ close(fd);
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+ } else {
|
||||
+ *backingStoreFormat = meta.backingStoreFormat;
|
||||
+ }
|
||||
+ } else {
|
||||
+ VIR_FREE(meta.backingStore);
|
||||
+ }
|
||||
}
|
||||
|
||||
- VIR_FREE(meta.backingStore);
|
||||
-
|
||||
if (capacity && meta.capacity)
|
||||
*capacity = meta.capacity;
|
||||
|
||||
if (encryption != NULL && meta.encrypted) {
|
||||
if (VIR_ALLOC(*encryption) < 0) {
|
||||
virReportOOMError();
|
||||
- if (backingStore)
|
||||
- VIR_FREE(*backingStore);
|
||||
- return -1;
|
||||
+ goto cleanup;
|
||||
}
|
||||
|
||||
switch (target->format) {
|
||||
@@ -124,6 +137,11 @@ virStorageBackendProbeTarget(virStorageVolTargetPtr target,
|
||||
}
|
||||
|
||||
return 0;
|
||||
+
|
||||
+cleanup:
|
||||
+ if (backingStore)
|
||||
+ VIR_FREE(*backingStore);
|
||||
+ return -1;
|
||||
}
|
||||
|
||||
#if WITH_STORAGE_FS
|
||||
@@ -585,6 +603,7 @@ virStorageBackendFileSystemRefresh(virConnectPtr conn ATTRIBUTE_UNUSED,
|
||||
while ((ent = readdir(dir)) != NULL) {
|
||||
int ret;
|
||||
char *backingStore;
|
||||
+ int backingStoreFormat;
|
||||
|
||||
if (VIR_ALLOC(vol) < 0)
|
||||
goto no_memory;
|
||||
@@ -604,6 +623,7 @@ virStorageBackendFileSystemRefresh(virConnectPtr conn ATTRIBUTE_UNUSED,
|
||||
|
||||
if ((ret = virStorageBackendProbeTarget(&vol->target,
|
||||
&backingStore,
|
||||
+ &backingStoreFormat,
|
||||
&vol->allocation,
|
||||
&vol->capacity,
|
||||
&vol->target.encryption)) < 0) {
|
||||
@@ -619,46 +639,18 @@ virStorageBackendFileSystemRefresh(virConnectPtr conn ATTRIBUTE_UNUSED,
|
||||
}
|
||||
|
||||
if (backingStore != NULL) {
|
||||
- if (vol->target.format == VIR_STORAGE_FILE_QCOW2 &&
|
||||
- STRPREFIX("fmt:", backingStore)) {
|
||||
- char *fmtstr = backingStore + 4;
|
||||
- char *path = strchr(fmtstr, ':');
|
||||
- if (!path) {
|
||||
- VIR_FREE(backingStore);
|
||||
- } else {
|
||||
- *path = '\0';
|
||||
- if ((vol->backingStore.format =
|
||||
- virStorageFileFormatTypeFromString(fmtstr)) < 0) {
|
||||
- VIR_FREE(backingStore);
|
||||
- } else {
|
||||
- memmove(backingStore, path, strlen(path) + 1);
|
||||
- vol->backingStore.path = backingStore;
|
||||
-
|
||||
- if (virStorageBackendUpdateVolTargetInfo(&vol->backingStore,
|
||||
- NULL,
|
||||
- NULL) < 0)
|
||||
- VIR_FREE(vol->backingStore);
|
||||
- }
|
||||
- }
|
||||
- } else {
|
||||
- vol->backingStore.path = backingStore;
|
||||
-
|
||||
- if ((ret = virStorageBackendProbeTarget(&vol->backingStore,
|
||||
- NULL, NULL, NULL,
|
||||
- NULL)) < 0) {
|
||||
- if (ret == -1)
|
||||
- goto cleanup;
|
||||
- else {
|
||||
- /* Silently ignore non-regular files,
|
||||
- * eg '.' '..', 'lost+found' */
|
||||
- VIR_FREE(vol->backingStore);
|
||||
- }
|
||||
- }
|
||||
+ vol->backingStore.path = backingStore;
|
||||
+ vol->backingStore.format = backingStoreFormat;
|
||||
+
|
||||
+ if (virStorageBackendUpdateVolTargetInfo(&vol->backingStore,
|
||||
+ NULL,
|
||||
+ NULL) < 0) {
|
||||
+ VIR_FREE(vol->backingStore.path);
|
||||
+ goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
-
|
||||
if (VIR_REALLOC_N(pool->volumes.objs,
|
||||
pool->volumes.count+1) < 0)
|
||||
goto no_memory;
|
||||
--
|
||||
1.7.1.1
|
||||
|
||||
@@ -1,265 +0,0 @@
|
||||
From 112a309bc7839e95c558b535143f855ce89cca8c Mon Sep 17 00:00:00 2001
|
||||
From: Daniel P. Berrange <berrange@redhat.com>
|
||||
Date: Thu, 10 Jun 2010 12:50:38 -0400
|
||||
Subject: [PATCH] CVE-2010-2242 Apply a source port mapping to virtual network masquerading
|
||||
|
||||
IPtables will seek to preserve the source port unchanged when
|
||||
doing masquerading, if possible. NFS has a pseudo-security
|
||||
option where it checks for the source port <= 1023 before
|
||||
allowing a mount request. If an admin has used this to make the
|
||||
host OS trusted for mounts, the default iptables behaviour will
|
||||
potentially allow NAT'd guests access too. This needs to be
|
||||
stopped.
|
||||
|
||||
With this change, the iptables -t nat -L -n -v rules for the
|
||||
default network will be
|
||||
|
||||
Chain POSTROUTING (policy ACCEPT 95 packets, 9163 bytes)
|
||||
pkts bytes target prot opt in out source destination
|
||||
14 840 MASQUERADE tcp -- * * 192.168.122.0/24 !192.168.122.0/24 masq ports: 1024-65535
|
||||
75 5752 MASQUERADE udp -- * * 192.168.122.0/24 !192.168.122.0/24 masq ports: 1024-65535
|
||||
0 0 MASQUERADE all -- * * 192.168.122.0/24 !192.168.122.0/24
|
||||
|
||||
* src/network/bridge_driver.c: Add masquerade rules for TCP
|
||||
and UDP protocols
|
||||
* src/util/iptables.c, src/util/iptables.c: Add source port
|
||||
mappings for TCP & UDP protocols when masquerading.
|
||||
---
|
||||
src/network/bridge_driver.c | 73 ++++++++++++++++++++++++++++++++++++++++--
|
||||
src/util/iptables.c | 70 +++++++++++++++++++++++++++++------------
|
||||
src/util/iptables.h | 6 ++-
|
||||
3 files changed, 122 insertions(+), 27 deletions(-)
|
||||
|
||||
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
|
||||
index 72255c1..80ed57a 100644
|
||||
--- a/src/network/bridge_driver.c
|
||||
+++ b/src/network/bridge_driver.c
|
||||
@@ -638,18 +638,74 @@ networkAddMasqueradingIptablesRules(struct network_driver *driver,
|
||||
goto masqerr2;
|
||||
}
|
||||
|
||||
- /* enable masquerading */
|
||||
+ /*
|
||||
+ * Enable masquerading.
|
||||
+ *
|
||||
+ * We need to end up with 3 rules in the table in this order
|
||||
+ *
|
||||
+ * 1. protocol=tcp with sport mapping restricton
|
||||
+ * 2. protocol=udp with sport mapping restricton
|
||||
+ * 3. generic any protocol
|
||||
+ *
|
||||
+ * The sport mappings are required, because default IPtables
|
||||
+ * MASQUERADE is maintain port number unchanged where possible.
|
||||
+ *
|
||||
+ * NFS can be configured to only "trust" port numbers < 1023.
|
||||
+ *
|
||||
+ * Guests using NAT thus need to be prevented from having port
|
||||
+ * numbers < 1023, otherwise they can bypass the NFS "security"
|
||||
+ * check on the source port number.
|
||||
+ *
|
||||
+ * Since we use '--insert' to add rules to the header of the
|
||||
+ * chain, we actually need to add them in the reverse of the
|
||||
+ * order just mentioned !
|
||||
+ */
|
||||
+
|
||||
+ /* First the generic masquerade rule for other protocols */
|
||||
if ((err = iptablesAddForwardMasquerade(driver->iptables,
|
||||
network->def->network,
|
||||
- network->def->forwardDev))) {
|
||||
+ network->def->forwardDev,
|
||||
+ NULL))) {
|
||||
virReportSystemError(err,
|
||||
_("failed to add iptables rule to enable masquerading to '%s'"),
|
||||
network->def->forwardDev ? network->def->forwardDev : NULL);
|
||||
goto masqerr3;
|
||||
}
|
||||
|
||||
+ /* UDP with a source port restriction */
|
||||
+ if ((err = iptablesAddForwardMasquerade(driver->iptables,
|
||||
+ network->def->network,
|
||||
+ network->def->forwardDev,
|
||||
+ "udp"))) {
|
||||
+ virReportSystemError(err,
|
||||
+ _("failed to add iptables rule to enable UDP masquerading to '%s'"),
|
||||
+ network->def->forwardDev ? network->def->forwardDev : NULL);
|
||||
+ goto masqerr4;
|
||||
+ }
|
||||
+
|
||||
+ /* TCP with a source port restriction */
|
||||
+ if ((err = iptablesAddForwardMasquerade(driver->iptables,
|
||||
+ network->def->network,
|
||||
+ network->def->forwardDev,
|
||||
+ "tcp"))) {
|
||||
+ virReportSystemError(err,
|
||||
+ _("failed to add iptables rule to enable TCP masquerading to '%s'"),
|
||||
+ network->def->forwardDev ? network->def->forwardDev : NULL);
|
||||
+ goto masqerr5;
|
||||
+ }
|
||||
+
|
||||
return 1;
|
||||
|
||||
+ masqerr5:
|
||||
+ iptablesRemoveForwardMasquerade(driver->iptables,
|
||||
+ network->def->network,
|
||||
+ network->def->forwardDev,
|
||||
+ "udp");
|
||||
+ masqerr4:
|
||||
+ iptablesRemoveForwardMasquerade(driver->iptables,
|
||||
+ network->def->network,
|
||||
+ network->def->forwardDev,
|
||||
+ NULL);
|
||||
masqerr3:
|
||||
iptablesRemoveForwardAllowRelatedIn(driver->iptables,
|
||||
network->def->network,
|
||||
@@ -814,8 +870,17 @@ networkRemoveIptablesRules(struct network_driver *driver,
|
||||
if (network->def->forwardType != VIR_NETWORK_FORWARD_NONE) {
|
||||
if (network->def->forwardType == VIR_NETWORK_FORWARD_NAT) {
|
||||
iptablesRemoveForwardMasquerade(driver->iptables,
|
||||
- network->def->network,
|
||||
- network->def->forwardDev);
|
||||
+ network->def->network,
|
||||
+ network->def->forwardDev,
|
||||
+ "tcp");
|
||||
+ iptablesRemoveForwardMasquerade(driver->iptables,
|
||||
+ network->def->network,
|
||||
+ network->def->forwardDev,
|
||||
+ "udp");
|
||||
+ iptablesRemoveForwardMasquerade(driver->iptables,
|
||||
+ network->def->network,
|
||||
+ network->def->forwardDev,
|
||||
+ NULL);
|
||||
iptablesRemoveForwardAllowRelatedIn(driver->iptables,
|
||||
network->def->network,
|
||||
network->def->bridge,
|
||||
diff --git a/src/util/iptables.c b/src/util/iptables.c
|
||||
index d06b857..f63e8c6 100644
|
||||
--- a/src/util/iptables.c
|
||||
+++ b/src/util/iptables.c
|
||||
@@ -692,25 +692,49 @@ iptablesRemoveForwardRejectIn(iptablesContext *ctx,
|
||||
*/
|
||||
static int
|
||||
iptablesForwardMasquerade(iptablesContext *ctx,
|
||||
- const char *network,
|
||||
- const char *physdev,
|
||||
- int action)
|
||||
+ const char *network,
|
||||
+ const char *physdev,
|
||||
+ const char *protocol,
|
||||
+ int action)
|
||||
{
|
||||
- if (physdev && physdev[0]) {
|
||||
- return iptablesAddRemoveRule(ctx->nat_postrouting,
|
||||
- action,
|
||||
- "--source", network,
|
||||
- "!", "--destination", network,
|
||||
- "--out-interface", physdev,
|
||||
- "--jump", "MASQUERADE",
|
||||
- NULL);
|
||||
+ if (protocol && protocol[0]) {
|
||||
+ if (physdev && physdev[0]) {
|
||||
+ return iptablesAddRemoveRule(ctx->nat_postrouting,
|
||||
+ action,
|
||||
+ "--source", network,
|
||||
+ "-p", protocol,
|
||||
+ "!", "--destination", network,
|
||||
+ "--out-interface", physdev,
|
||||
+ "--jump", "MASQUERADE",
|
||||
+ "--to-ports", "1024-65535",
|
||||
+ NULL);
|
||||
+ } else {
|
||||
+ return iptablesAddRemoveRule(ctx->nat_postrouting,
|
||||
+ action,
|
||||
+ "--source", network,
|
||||
+ "-p", protocol,
|
||||
+ "!", "--destination", network,
|
||||
+ "--jump", "MASQUERADE",
|
||||
+ "--to-ports", "1024-65535",
|
||||
+ NULL);
|
||||
+ }
|
||||
} else {
|
||||
- return iptablesAddRemoveRule(ctx->nat_postrouting,
|
||||
- action,
|
||||
- "--source", network,
|
||||
- "!", "--destination", network,
|
||||
- "--jump", "MASQUERADE",
|
||||
- NULL);
|
||||
+ if (physdev && physdev[0]) {
|
||||
+ return iptablesAddRemoveRule(ctx->nat_postrouting,
|
||||
+ action,
|
||||
+ "--source", network,
|
||||
+ "!", "--destination", network,
|
||||
+ "--out-interface", physdev,
|
||||
+ "--jump", "MASQUERADE",
|
||||
+ NULL);
|
||||
+ } else {
|
||||
+ return iptablesAddRemoveRule(ctx->nat_postrouting,
|
||||
+ action,
|
||||
+ "--source", network,
|
||||
+ "!", "--destination", network,
|
||||
+ "--jump", "MASQUERADE",
|
||||
+ NULL);
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -719,6 +743,7 @@ iptablesForwardMasquerade(iptablesContext *ctx,
|
||||
* @ctx: pointer to the IP table context
|
||||
* @network: the source network name
|
||||
* @physdev: the physical input device or NULL
|
||||
+ * @protocol: the network protocol or NULL
|
||||
*
|
||||
* Add rules to the IP table context to allow masquerading
|
||||
* network @network on @physdev. This allow the bridge to
|
||||
@@ -729,9 +754,10 @@ iptablesForwardMasquerade(iptablesContext *ctx,
|
||||
int
|
||||
iptablesAddForwardMasquerade(iptablesContext *ctx,
|
||||
const char *network,
|
||||
- const char *physdev)
|
||||
+ const char *physdev,
|
||||
+ const char *protocol)
|
||||
{
|
||||
- return iptablesForwardMasquerade(ctx, network, physdev, ADD);
|
||||
+ return iptablesForwardMasquerade(ctx, network, physdev, protocol, ADD);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -739,6 +765,7 @@ iptablesAddForwardMasquerade(iptablesContext *ctx,
|
||||
* @ctx: pointer to the IP table context
|
||||
* @network: the source network name
|
||||
* @physdev: the physical input device or NULL
|
||||
+ * @protocol: the network protocol or NULL
|
||||
*
|
||||
* Remove rules from the IP table context to stop masquerading
|
||||
* network @network on @physdev. This stops the bridge from
|
||||
@@ -749,7 +776,8 @@ iptablesAddForwardMasquerade(iptablesContext *ctx,
|
||||
int
|
||||
iptablesRemoveForwardMasquerade(iptablesContext *ctx,
|
||||
const char *network,
|
||||
- const char *physdev)
|
||||
+ const char *physdev,
|
||||
+ const char *protocol)
|
||||
{
|
||||
- return iptablesForwardMasquerade(ctx, network, physdev, REMOVE);
|
||||
+ return iptablesForwardMasquerade(ctx, network, physdev, protocol, REMOVE);
|
||||
}
|
||||
diff --git a/src/util/iptables.h b/src/util/iptables.h
|
||||
index 7d55a6d..b47d854 100644
|
||||
--- a/src/util/iptables.h
|
||||
+++ b/src/util/iptables.h
|
||||
@@ -85,9 +85,11 @@ int iptablesRemoveForwardRejectIn (iptablesContext *ctx,
|
||||
|
||||
int iptablesAddForwardMasquerade (iptablesContext *ctx,
|
||||
const char *network,
|
||||
- const char *physdev);
|
||||
+ const char *physdev,
|
||||
+ const char *protocol);
|
||||
int iptablesRemoveForwardMasquerade (iptablesContext *ctx,
|
||||
const char *network,
|
||||
- const char *physdev);
|
||||
+ const char *physdev,
|
||||
+ const char *protocol);
|
||||
|
||||
#endif /* __QEMUD_IPTABLES_H__ */
|
||||
--
|
||||
1.6.6.1
|
||||
|
||||
+2043
-1056
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user