Change console handling to a proper device list, as done for other
character devices. Even though certain drivers can actually handle multiple
consoles, for now just maintain existing behavior where possible.
Signed-off-by: Cole Robinson <crobinso(a)redhat.com>
---
src/conf/domain_conf.c | 72 ++++++++++++-------
src/conf/domain_conf.h | 5 +-
src/lxc/lxc_driver.c | 8 +-
src/uml/uml_conf.c | 4 +-
src/uml/uml_driver.c | 6 +-
src/xen/xend_internal.c | 12 +++-
src/xen/xm_internal.c | 15 ++++-
.../xml2sexprdata/xml2sexpr-pv-multi-console.sexpr | 1 +
tests/xml2sexprdata/xml2sexpr-pv-multi-console.xml | 24 +++++++
tests/xml2sexprtest.c | 1 +
10 files changed, 106 insertions(+), 42 deletions(-)
create mode 100644 tests/xml2sexprdata/xml2sexpr-pv-multi-console.sexpr
create mode 100644 tests/xml2sexprdata/xml2sexpr-pv-multi-console.xml
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index e4d52ff..0793ac0 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -703,7 +703,9 @@ void virDomainDefFree(virDomainDefPtr def)
virDomainChrDefFree(def->channels[i]);
VIR_FREE(def->channels);
- virDomainChrDefFree(def->console);
+ for (i = 0 ; i < def->nconsoles ; i++)
+ virDomainChrDefFree(def->consoles[i]);
+ VIR_FREE(def->consoles);
for (i = 0 ; i < def->nsounds ; i++)
virDomainSoundDefFree(def->sounds[i]);
@@ -995,6 +997,9 @@ int virDomainDeviceInfoIterate(virDomainDefPtr def,
for (i = 0; i < def->nchannels ; i++)
if (cb(def, &def->channels[i]->info, opaque) < 0)
return -1;
+ for (i = 0; i < def->nconsoles ; i++)
+ if (cb(def, &def->consoles[i]->info, opaque) < 0)
+ return -1;
for (i = 0; i < def->ninputs ; i++)
if (cb(def, &def->inputs[i]->info, opaque) < 0)
return -1;
@@ -1004,9 +1009,6 @@ int virDomainDeviceInfoIterate(virDomainDefPtr def,
if (def->watchdog)
if (cb(def, &def->watchdog->info, opaque) < 0)
return -1;
- if (def->console)
- if (cb(def, &def->console->info, opaque) < 0)
- return -1;
return 0;
}
@@ -4384,31 +4386,45 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps,
}
VIR_FREE(nodes);
- if ((node = virXPathNode("./devices/console[1]", ctxt)) != NULL) {
- virDomainChrDefPtr chr = virDomainChrDefParseXML(node,
+ if ((n = virXPathNodeSet("./devices/console", ctxt, &nodes)) < 0) {
+ virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("cannot extract console
devices"));
+ goto error;
+ }
+ if (n && VIR_ALLOC_N(def->consoles, n) < 0)
+ goto no_memory;
+
+ for (i = 0; i < n ; i++) {
+ virDomainChrDefPtr chr = virDomainChrDefParseXML(nodes[i],
flags);
if (!chr)
goto error;
- chr->target.port = 0;
- /*
- * For HVM console actually created a serial device
- * while for non-HVM it was a parvirt console
- */
- if (STREQ(def->os.type, "hvm")) {
- if (def->nserials != 0) {
- virDomainChrDefFree(chr);
- } else {
- if (VIR_ALLOC_N(def->serials, 1) < 0) {
+ chr->target.port = i;
+
+ /* Back compat handling for the first console device */
+ if (i == 0) {
+ /*
+ * For HVM console actually created a serial device
+ * while for non-HVM it was a parvirt console
+ */
+ if (STREQ(def->os.type, "hvm")) {
+ if (def->nserials != 0) {
virDomainChrDefFree(chr);
- goto no_memory;
+ } else {
+ if (VIR_ALLOC_N(def->serials, 1) < 0) {
+ virDomainChrDefFree(chr);
+ goto no_memory;
+ }
+ def->nserials = 1;
+ def->serials[0] = chr;
+ chr->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL;
}
- def->nserials = 1;
- def->serials[0] = chr;
- chr->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL;
+ } else {
+ def->consoles[def->nconsoles++] = chr;
}
} else {
- def->console = chr;
+ def->consoles[def->nconsoles++] = chr;
}
}
@@ -5496,9 +5512,10 @@ virDomainChrDefFormat(virBufferPtr buf,
return -1;
}
- /* Compat with legacy <console tty='/dev/pts/5'/> syntax */
virBufferVSprintf(buf, " <%s type='%s'",
elementName, type);
+
+ /* Compat with legacy <console tty='/dev/pts/5'/> syntax */
if (def->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE &&
def->type == VIR_DOMAIN_CHR_TYPE_PTY &&
!(flags & VIR_DOMAIN_XML_INACTIVE) &&
@@ -6213,9 +6230,10 @@ char *virDomainDefFormat(virDomainDefPtr def,
goto cleanup;
/* If there's a PV console that's preferred.. */
- if (def->console) {
- if (virDomainChrDefFormat(&buf, def->console, flags) < 0)
- goto cleanup;
+ if (def->nconsoles) {
+ for (n = 0 ; n < def->nconsoles ; n++)
+ if (virDomainChrDefFormat(&buf, def->consoles[n], flags) < 0)
+ goto cleanup;
} else if (def->nserials != 0) {
/* ..else for legacy compat duplicate the first serial device as a
* console */
@@ -7260,9 +7278,9 @@ int virDomainChrDefForeach(virDomainDefPtr def,
if (abortOnError && rc != 0)
goto done;
}
- if (def->console) {
+ for (i = 0 ; i < def->nconsoles ; i++) {
if ((iter)(def,
- def->console,
+ def->consoles[i],
opaque) < 0)
rc = -1;
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 75dc29a..1361d38 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -875,8 +875,9 @@ struct _virDomainDef {
int nchannels;
virDomainChrDefPtr *channels;
- /* Only 1 */
- virDomainChrDefPtr console;
+ int nconsoles;
+ virDomainChrDefPtr *consoles;
+
virSecurityLabelDef seclabel;
virDomainWatchdogDefPtr watchdog;
virCPUDefPtr cpu;
diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c
index 462bc9c..9b0969e 100644
--- a/src/lxc/lxc_driver.c
+++ b/src/lxc/lxc_driver.c
@@ -1273,10 +1273,10 @@ static int lxcVmStart(virConnectPtr conn,
_("Failed to allocate tty"));
goto cleanup;
}
- if (vm->def->console &&
- vm->def->console->type == VIR_DOMAIN_CHR_TYPE_PTY) {
- VIR_FREE(vm->def->console->data.file.path);
- vm->def->console->data.file.path = parentTtyPath;
+ if (vm->def->nconsoles > 0 &&
+ vm->def->consoles[0]->type == VIR_DOMAIN_CHR_TYPE_PTY) {
+ VIR_FREE(vm->def->consoles[0]->data.file.path);
+ vm->def->consoles[0]->data.file.path = parentTtyPath;
} else {
VIR_FREE(parentTtyPath);
}
diff --git a/src/uml/uml_conf.c b/src/uml/uml_conf.c
index 785d627..6715a94 100644
--- a/src/uml/uml_conf.c
+++ b/src/uml/uml_conf.c
@@ -500,8 +500,8 @@ int umlBuildCommandLine(virConnectPtr conn,
for (i = 0 ; i < UML_MAX_CHAR_DEVICE ; i++) {
char *ret;
- if (i == 0 && vm->def->console)
- ret = umlBuildCommandLineChr(vm->def->console, "con");
+ if (i == 0 && vm->def->nconsoles > 0)
+ ret = umlBuildCommandLineChr(vm->def->consoles[0], "con");
else
if (virAsprintf(&ret, "con%d=none", i) < 0)
goto no_memory;
diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c
index 110179e..aa8cbef 100644
--- a/src/uml/uml_driver.c
+++ b/src/uml/uml_driver.c
@@ -231,10 +231,10 @@ umlIdentifyChrPTY(struct uml_driver *driver,
{
int i;
- if (dom->def->console &&
- dom->def->console->type == VIR_DOMAIN_CHR_TYPE_PTY)
+ if (dom->def->nconsoles > 0 &&
+ dom->def->consoles[0]->type == VIR_DOMAIN_CHR_TYPE_PTY)
if (umlIdentifyOneChrPTY(driver, dom,
- dom->def->console, "con") < 0)
+ dom->def->consoles[0], "con") < 0)
return -1;
for (i = 0 ; i < dom->def->nserials; i++)
diff --git a/src/xen/xend_internal.c b/src/xen/xend_internal.c
index a492231..02383ca 100644
--- a/src/xen/xend_internal.c
+++ b/src/xen/xend_internal.c
@@ -2364,9 +2364,17 @@ xenDaemonParseSxpr(virConnectPtr conn,
}
} else {
/* Fake a paravirt console, since that's not in the sexpr */
- if (!(def->console = xenDaemonParseSxprChar("pty", tty)))
+ virDomainChrDefPtr chr;
+
+ if ((chr = xenDaemonParseSxprChar("pty", tty)) == NULL)
goto error;
- def->console->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE;
+ if (VIR_REALLOC_N(def->consoles, def->nconsoles+1) < 0) {
+ virDomainChrDefFree(chr);
+ goto no_memory;
+ }
+
+ chr->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE;
+ def->consoles[def->nconsoles++] = chr;
}
VIR_FREE(tty);
diff --git a/src/xen/xm_internal.c b/src/xen/xm_internal.c
index 4230504..7756662 100644
--- a/src/xen/xm_internal.c
+++ b/src/xen/xm_internal.c
@@ -1438,9 +1438,20 @@ xenXMDomainConfigParse(virConnectPtr conn, virConfPtr conf) {
def->nserials++;
}
} else {
- if (!(def->console = xenDaemonParseSxprChar("pty", NULL)))
+ virDomainChrDefPtr chr;
+
+ if ((chr = xenDaemonParseSxprChar("pty", NULL)) == NULL)
goto cleanup;
- def->console->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE;
+
+ if (chr) {
+ if (VIR_ALLOC_N(def->consoles, 1) < 0) {
+ virDomainChrDefFree(chr);
+ goto no_memory;
+ }
+ chr->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE;
+ def->consoles[0] = chr;
+ def->nconsoles++;
+ }
}
if (hvm) {
diff --git a/tests/xml2sexprdata/xml2sexpr-pv-multi-console.sexpr
b/tests/xml2sexprdata/xml2sexpr-pv-multi-console.sexpr
new file mode 100644
index 0000000..60db610
--- /dev/null
+++ b/tests/xml2sexprdata/xml2sexpr-pv-multi-console.sexpr
@@ -0,0 +1 @@
+(vm (name 'pvtest')(memory 420)(maxmem 420)(vcpus 2)(uuid
'596a5d21-71f4-8fb2-e068-e2386a5c413e')(on_poweroff 'destroy')(on_reboot
'destroy')(on_crash 'destroy')(image (linux (kernel
'/var/lib/xen/vmlinuz.2Dn2YT')(ramdisk
'/var/lib/xen/initrd.img.0u-Vhq')(args '
method=http://download.fedora.devel.redhat.com/pub/fedora/linux/core/test...
')))(device (vbd (dev 'xvda')(uname 'file:/root/some.img')(mode
'w'))))
\ No newline at end of file
diff --git a/tests/xml2sexprdata/xml2sexpr-pv-multi-console.xml
b/tests/xml2sexprdata/xml2sexpr-pv-multi-console.xml
new file mode 100644
index 0000000..4f9c869
--- /dev/null
+++ b/tests/xml2sexprdata/xml2sexpr-pv-multi-console.xml
@@ -0,0 +1,24 @@
+<domain type='xen' id='15'>
+ <name>pvtest</name>
+ <uuid>596a5d2171f48fb2e068e2386a5c413e</uuid>
+ <os>
+ <type>linux</type>
+ <kernel>/var/lib/xen/vmlinuz.2Dn2YT</kernel>
+ <initrd>/var/lib/xen/initrd.img.0u-Vhq</initrd>
+ <cmdline>
method=http://download.fedora.devel.redhat.com/pub/fedora/linux/core/test...
</cmdline>
+ </os>
+ <memory>430080</memory>
+ <vcpu>2</vcpu>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>destroy</on_reboot>
+ <on_crash>destroy</on_crash>
+ <devices>
+ <disk type='file' device='disk'>
+ <source file='/root/some.img'/>
+ <target dev='xvda'/>
+ </disk>
+ <console tty='/dev/pts/4'/>
+ <console tty='/dev/pts/5'/>
+ <console tty='/dev/pts/6'/>
+ </devices>
+</domain>
diff --git a/tests/xml2sexprtest.c b/tests/xml2sexprtest.c
index 0455dc4..920ee29 100644
--- a/tests/xml2sexprtest.c
+++ b/tests/xml2sexprtest.c
@@ -113,6 +113,7 @@ mymain(int argc, char **argv)
DO_TEST("pv-vfb-new", "pv-vfb-new", "pvtest", 3);
DO_TEST("pv-vfb-new-auto", "pv-vfb-new-auto", "pvtest",
3);
DO_TEST("pv-bootloader", "pv-bootloader", "pvtest",
1);
+ DO_TEST("pv-multi-console", "pv-multi-console",
"pvtest", 2);
DO_TEST("disk-file", "disk-file", "pvtest", 2);
DO_TEST("disk-block", "disk-block", "pvtest", 2);
--
1.6.6.1