[libvirt] [PATCHv3 0/6] Allocate virtio-serial addresses

Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1076708 https://bugzilla.redhat.com/show_bug.cgi?id=890606 New in v3: * preserve the behavior of honoring the controller if a partial address is specified: <address type='virtio-serial' controller='2'/> * automatically add a controller if we're out of free ports and add a test for it Ján Tomko (6): Add test for virtio serial port assignment Add functions to track virtio-serial addresses Allocate virtio-serial addresses when starting a domain Expand the address set when attaching a virtio-serial controller Assign an address when hotplugging a virtio-serial device Auto add virtio-serial controllers src/conf/domain_addr.c | 435 +++++++++++++++++++++ src/conf/domain_addr.h | 61 +++ src/conf/domain_conf.c | 48 +-- src/conf/domain_conf.h | 1 + src/libvirt_private.syms | 11 + src/qemu/qemu_command.c | 63 +++ src/qemu/qemu_domain.c | 1 + src/qemu/qemu_domain.h | 1 + src/qemu/qemu_hotplug.c | 32 +- src/qemu/qemu_process.c | 2 + tests/qemuhotplugtest.c | 2 +- .../qemuxml2argv-channel-virtio-auto.args | 2 +- .../qemuxml2argv-channel-virtio-autoadd.args | 33 ++ .../qemuxml2argv-channel-virtio-autoadd.xml | 45 +++ .../qemuxml2argv-channel-virtio-autoassign.args | 20 + .../qemuxml2argv-channel-virtio-autoassign.xml | 50 +++ tests/qemuxml2argvtest.c | 4 + .../qemuxml2xmlout-channel-virtio-auto.xml | 9 +- 18 files changed, 777 insertions(+), 43 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-channel-virtio-autoadd.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-channel-virtio-autoadd.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-channel-virtio-autoassign.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-channel-virtio-autoassign.xml -- 2.0.5

Add a test to demonstrate the effect of automatic virtio-serial address assignment. --- .../qemuxml2argv-channel-virtio-autoassign.args | 20 +++++++++ .../qemuxml2argv-channel-virtio-autoassign.xml | 50 ++++++++++++++++++++++ tests/qemuxml2argvtest.c | 2 + 3 files changed, 72 insertions(+) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-channel-virtio-autoassign.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-channel-virtio-autoassign.xml diff --git a/tests/qemuxml2argvdata/qemuxml2argv-channel-virtio-autoassign.args b/tests/qemuxml2argvdata/qemuxml2argv-channel-virtio-autoassign.args new file mode 100644 index 0000000..f7f7b8d --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-channel-virtio-autoassign.args @@ -0,0 +1,20 @@ +LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test QEMU_AUDIO_DRV=none \ +/usr/bin/qemu -S -M pc -m 214 -smp 1 -nographic -nodefconfig -nodefaults \ +-chardev socket,id=charmonitor,path=/tmp/test-monitor,server,nowait \ +-mon chardev=charmonitor,id=monitor,mode=readline -no-acpi -boot c \ +-device virtio-serial-pci,id=virtio-serial0,max_ports=4,vectors=4,bus=pci.0\ +,addr=0x3 -device virtio-serial-pci,id=virtio-serial1,bus=pci.0,addr=0xa \ +-usb -hda /dev/HostVG/QEMUGuest1 \ +-chardev pty,id=charchannel0 -device virtserialport,bus=virtio-serial0.0,nr=1,\ +chardev=charchannel0,id=channel0,name=org.linux-kvm.port.0 \ +-chardev pty,id=charchannel1 -device virtserialport,bus=virtio-serial0.2,nr=1,\ +chardev=charchannel1,id=channel1,name=org.linux-kvm.port.foo \ +-chardev pty,id=charchannel2 -device virtserialport,bus=virtio-serial0.0,nr=1,\ +chardev=charchannel2,id=channel2,name=org.linux-kvm.port.bar \ +-chardev pty,id=charchannel3 -device virtserialport,bus=virtio-serial0.0,nr=2,\ +chardev=charchannel3,id=channel3,name=org.linux-kvm.port.wizz \ +-chardev pty,id=charchannel4 -device virtserialport,bus=virtio-serial0.0,nr=3,\ +chardev=charchannel4,id=channel4,name=org.linux-kvm.port.ooh \ +-chardev pty,id=charchannel5 -device virtserialport,bus=virtio-serial0.0,nr=4,\ +chardev=charchannel5,id=channel5,name=org.linux-kvm.port.lla \ +-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x4 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-channel-virtio-autoassign.xml b/tests/qemuxml2argvdata/qemuxml2argv-channel-virtio-autoassign.xml new file mode 100644 index 0000000..5592c8f --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-channel-virtio-autoassign.xml @@ -0,0 +1,50 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>219100</memory> + <currentMemory unit='KiB'>219100</currentMemory> + <vcpu placement='static' cpuset='1-4,8-20,525'>1</vcpu> + <os> + <type arch='i686' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu</emulator> + <disk type='block' device='disk'> + <source dev='/dev/HostVG/QEMUGuest1'/> + <target dev='hda' bus='ide'/> + <address type='drive' controller='0' bus='0' target='0' unit='0'/> + </disk> + <controller type='usb' index='0'/> + <controller type='ide' index='0'/> + <controller type='virtio-serial' index='0' ports='4' vectors='4'/> + <controller type='virtio-serial' index='1'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0a' function='0x0'/> + </controller> + <channel type='pty'> + <target type='virtio' name='org.linux-kvm.port.0'/> + </channel> + <channel type='pty'> + <target type='virtio' name='org.linux-kvm.port.foo'/> + <address type='virtio-serial' controller='0' bus='2'/> + </channel> + <channel type='pty'> + <target type='virtio' name='org.linux-kvm.port.bar'/> + <address type='virtio-serial' controller='0' port='1'/> + </channel> + <channel type='pty'> + <target type='virtio' name='org.linux-kvm.port.wizz'/> + </channel> + <channel type='pty'> + <target type='virtio' name='org.linux-kvm.port.ooh'/> + </channel> + <channel type='pty'> + <target type='virtio' name='org.linux-kvm.port.lla'/> + </channel> + <memballoon model='virtio'/> + </devices> +</domain> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 08f374e..00e608c 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -1070,6 +1070,8 @@ mymain(void) QEMU_CAPS_DEVICE, QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG); DO_TEST("channel-virtio-auto", QEMU_CAPS_DEVICE, QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG); + DO_TEST("channel-virtio-autoassign", + QEMU_CAPS_DEVICE, QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG); DO_TEST("console-virtio", QEMU_CAPS_DEVICE, QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG); DO_TEST("console-virtio-many", -- 2.0.5

Create a sorted array of virtio-serial controllers. Each of the elements contains the controller index and a bitmap of available ports. Buses are not tracked, because they aren't supported by QEMU. --- src/conf/domain_addr.c | 398 +++++++++++++++++++++++++++++++++++++++++++++++ src/conf/domain_addr.h | 59 +++++++ src/libvirt_private.syms | 10 ++ 3 files changed, 467 insertions(+) diff --git a/src/conf/domain_addr.c b/src/conf/domain_addr.c index fb4a76f..49d28be 100644 --- a/src/conf/domain_addr.c +++ b/src/conf/domain_addr.c @@ -718,3 +718,401 @@ virDomainCCWAddressSetCreate(void) virDomainCCWAddressSetFree(addrs); return NULL; } + + +#define VIR_DOMAIN_DEFAULT_VIRTIO_SERIAL_PORTS 31 + + +/* virDomainVirtioSerialAddrSetCreate + * + * Allocates an address set for virtio serial addresses + */ +virDomainVirtioSerialAddrSetPtr +virDomainVirtioSerialAddrSetCreate(void) +{ + virDomainVirtioSerialAddrSetPtr ret = NULL; + + if (VIR_ALLOC(ret) < 0) + return NULL; + + return ret; +} + +static void +virDomainVirtioSerialControllerFree(virDomainVirtioSerialControllerPtr cont) +{ + if (cont) { + virBitmapFree(cont->ports); + VIR_FREE(cont); + } +} + +static ssize_t +virDomainVirtioSerialAddrPlaceController(virDomainVirtioSerialAddrSetPtr addrs, + virDomainVirtioSerialControllerPtr cont) +{ + size_t i; + + for (i = 0; i < addrs->ncontrollers; i++) { + if (addrs->controllers[i]->idx == cont->idx) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("virtio serial controller with index %u already exists" + " in the address set"), + cont->idx); + return -2; + } + if (addrs->controllers[i]->idx > cont->idx) + return i; + } + return -1; +} + +static ssize_t +virDomainVirtioSerialAddrFindController(virDomainVirtioSerialAddrSetPtr addrs, + unsigned int idx) +{ + size_t i; + + for (i = 0; i < addrs->ncontrollers; i++) { + if (addrs->controllers[i]->idx == idx) + return i; + } + return -1; +} + +/* virDomainVirtioSerialAddrSetAddController + * + * Adds virtio serial ports of the existing controller + * to the address set. + */ +int +virDomainVirtioSerialAddrSetAddController(virDomainVirtioSerialAddrSetPtr addrs, + virDomainControllerDefPtr cont) +{ + int ret = -1; + int ports; + virDomainVirtioSerialControllerPtr cnt = NULL; + ssize_t insertAt; + + if (cont->type != VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL) + return 0; + + ports = cont->opts.vioserial.ports; + if (ports == -1) + ports = VIR_DOMAIN_DEFAULT_VIRTIO_SERIAL_PORTS; + + VIR_DEBUG("Adding virtio serial controller index %u with %d" + " ports to the address set", cont->idx, ports); + + if (VIR_ALLOC(cnt) < 0) + goto cleanup; + + if (!(cnt->ports = virBitmapNew(ports))) + goto cleanup; + cnt->idx = cont->idx; + + if ((insertAt = virDomainVirtioSerialAddrPlaceController(addrs, cnt)) < -1) + goto cleanup; + if (VIR_INSERT_ELEMENT(addrs->controllers, insertAt, + addrs->ncontrollers, cnt) < 0) + goto cleanup; + + ret = 0; + + cleanup: + virDomainVirtioSerialControllerFree(cnt); + return ret; +} + +/* virDomainVirtioSerialAddrSetAddControllers + * + * Adds virtio serial ports of controllers present in the domain definition + * to the address set. + */ +int +virDomainVirtioSerialAddrSetAddControllers(virDomainVirtioSerialAddrSetPtr addrs, + virDomainDefPtr def) +{ + size_t i; + + for (i = 0; i < def->ncontrollers; i++) { + if (virDomainVirtioSerialAddrSetAddController(addrs, + def->controllers[i]) < 0) + return -1; + } + + return 0; +} + +/* virDomainVirtioSerialAddrSetRemoveController + * + * Removes a virtio serial controller from the address set. + */ +void +virDomainVirtioSerialAddrSetRemoveController(virDomainVirtioSerialAddrSetPtr addrs, + virDomainControllerDefPtr cont) +{ + ssize_t pos; + + if (cont->type != VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL) + return; + + VIR_DEBUG("Removing virtio serial controller index %u " + "from the address set", cont->idx); + + pos = virDomainVirtioSerialAddrFindController(addrs, cont->idx); + + if (pos >= 0) + VIR_DELETE_ELEMENT(addrs->controllers, pos, addrs->ncontrollers); +} + +void +virDomainVirtioSerialAddrSetFree(virDomainVirtioSerialAddrSetPtr addrs) +{ + size_t i; + if (addrs) { + for (i = 0; i < addrs->ncontrollers; i++) + virDomainVirtioSerialControllerFree(addrs->controllers[i]); + VIR_FREE(addrs); + } +} + +static int +virDomainVirtioSerialAddrNext(virDomainVirtioSerialAddrSetPtr addrs, + virDomainDeviceVirtioSerialAddress *addr, + bool allowZero) +{ + int ret = -1; + ssize_t port, startPort = 0; + ssize_t i; + unsigned int controller; + + /* port number 0 is reserved for virtconsoles */ + if (allowZero) + startPort = -1; + + if (addrs->ncontrollers == 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("no virtio-serial controllers are available")); + goto cleanup; + } + + for (i = 0; i < addrs->ncontrollers; i++) { + virBitmapPtr map = addrs->controllers[i]->ports; + if ((port = virBitmapNextClearBit(map, startPort)) >= 0) { + controller = addrs->controllers[i]->idx; + goto success; + } + } + + virReportError(VIR_ERR_XML_ERROR, "%s", + _("Unable to find a free virtio-serial port")); + + cleanup: + return ret; + + success: + addr->bus = 0; + addr->port = port; + addr->controller = controller; + VIR_DEBUG("Found free virtio serial controller %u port %u", addr->controller, + addr->port); + ret = 0; + goto cleanup; +} + +static int +virDomainVirtioSerialAddrNextFromController(virDomainVirtioSerialAddrSetPtr addrs, + virDomainDeviceVirtioSerialAddress *addr) +{ + ssize_t port; + ssize_t i; + virBitmapPtr map; + + i = virDomainVirtioSerialAddrFindController(addrs, addr->controller); + if (i < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("virtio-serial controller %u not available"), + addr->controller); + return -1; + } + + map = addrs->controllers[i]->ports; + if ((port = virBitmapNextClearBit(map, 0)) <= 0) { + virReportError(VIR_ERR_XML_ERROR, + _("Unable to find a free port on virtio-serial controller %u"), + addr->controller); + return -1; + } + + addr->bus = 0; + addr->port = port; + VIR_DEBUG("Found free virtio serial controller %u port %u", addr->controller, + addr->port); + return 0; +} + +/* virDomainVirtioSerialAddrAutoAssign + * + * reserve a virtio serial address of the device (if it has one) + * or assign a virtio serial address to the device + */ +int +virDomainVirtioSerialAddrAutoAssign(virDomainVirtioSerialAddrSetPtr addrs, + virDomainDeviceInfoPtr info, + bool allowZero) +{ + bool portOnly = info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL; + if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL && + info->addr.vioserial.port) + return virDomainVirtioSerialAddrReserve(NULL, NULL, info, addrs); + else + return virDomainVirtioSerialAddrAssign(addrs, info, allowZero, portOnly); +} + + +int +virDomainVirtioSerialAddrAssign(virDomainVirtioSerialAddrSetPtr addrs, + virDomainDeviceInfoPtr info, + bool allowZero, + bool portOnly) +{ + int ret = -1; + virDomainDeviceInfo nfo = { NULL }; + virDomainDeviceInfoPtr ptr = allowZero ? &nfo : info; + + ptr->type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL; + + if (portOnly) { + if (virDomainVirtioSerialAddrNextFromController(addrs, + &ptr->addr.vioserial) < 0) + goto cleanup; + } else { + if (virDomainVirtioSerialAddrNext(addrs, &ptr->addr.vioserial, + allowZero) < 0) + goto cleanup; + } + + if (virDomainVirtioSerialAddrReserve(NULL, NULL, ptr, addrs) < 0) + goto cleanup; + + ret = 0; + + cleanup: + return ret; +} + +/* virDomainVirtioSerialAddrIsComplete + * + * Check if the address is complete, or it needs auto-assignment + */ +bool +virDomainVirtioSerialAddrIsComplete(virDomainDeviceInfoPtr info) +{ + return info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL && + info->addr.vioserial.port != 0; +} + +/* virDomainVirtioSerialAddrReserve + * + * Reserve the virtio serial address of the device + * + * For use with virDomainDeviceInfoIterate, + * opaque should be the address set + */ +int +virDomainVirtioSerialAddrReserve(virDomainDefPtr def ATTRIBUTE_UNUSED, + virDomainDeviceDefPtr dev ATTRIBUTE_UNUSED, + virDomainDeviceInfoPtr info, + void *data) +{ + virDomainVirtioSerialAddrSetPtr addrs = data; + char *str = NULL; + int ret = -1; + virBitmapPtr map = NULL; + bool b; + ssize_t i; + + if (!virDomainVirtioSerialAddrIsComplete(info)) + return 0; + + VIR_DEBUG("Reserving virtio serial %u %u", info->addr.vioserial.controller, + info->addr.vioserial.port); + + i = virDomainVirtioSerialAddrFindController(addrs, info->addr.vioserial.controller); + if (i < 0) { + virReportError(VIR_ERR_XML_ERROR, + _("virtio serial controller %u is missing"), + info->addr.vioserial.controller); + goto cleanup; + } + + map = addrs->controllers[i]->ports; + if (virBitmapGetBit(map, info->addr.vioserial.port, &b) < 0) { + virReportError(VIR_ERR_XML_ERROR, + _("virtio serial controller %u does not have port %u"), + info->addr.vioserial.controller, + info->addr.vioserial.port); + goto cleanup; + } + + if (b) { + virReportError(VIR_ERR_XML_ERROR, + _("virtio serial port %u on controller %u is already occupied"), + info->addr.vioserial.port, + info->addr.vioserial.controller); + goto cleanup; + } + + ignore_value(virBitmapSetBit(map, info->addr.vioserial.port)); + + ret = 0; + + cleanup: + VIR_FREE(str); + return ret; +} + +/* virDomainVirtioSerialAddrRelease + * + * Release the virtio serial address of the device + */ +int +virDomainVirtioSerialAddrRelease(virDomainVirtioSerialAddrSetPtr addrs, + virDomainDeviceInfoPtr info) +{ + virBitmapPtr map; + char *str = NULL; + int ret = -1; + ssize_t i; + + if (info->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL || + info->addr.vioserial.port == 0) + return 0; + + VIR_DEBUG("Releasing virtio serial %u %u", info->addr.vioserial.controller, + info->addr.vioserial.port); + + i = virDomainVirtioSerialAddrFindController(addrs, info->addr.vioserial.controller); + if (i < 0) { + virReportError(VIR_ERR_XML_ERROR, + _("virtio serial controller %u is missing"), + info->addr.vioserial.controller); + goto cleanup; + } + + map = addrs->controllers[i]->ports; + if (virBitmapClearBit(map, info->addr.vioserial.port) < 0) { + virReportError(VIR_ERR_XML_ERROR, + _("virtio serial controller %u does not have port %u"), + info->addr.vioserial.controller, + info->addr.vioserial.port); + goto cleanup; + } + + ret = 0; + + cleanup: + VIR_FREE(str); + return ret; +} diff --git a/src/conf/domain_addr.h b/src/conf/domain_addr.h index 2c3468e..14ffd17 100644 --- a/src/conf/domain_addr.h +++ b/src/conf/domain_addr.h @@ -173,4 +173,63 @@ int virDomainCCWAddressReleaseAddr(virDomainCCWAddressSetPtr addrs, virDomainDeviceInfoPtr dev) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); virDomainCCWAddressSetPtr virDomainCCWAddressSetCreate(void); + +struct _virDomainVirtioSerialController { + unsigned int idx; + virBitmapPtr ports; +}; + +typedef struct _virDomainVirtioSerialController virDomainVirtioSerialController; +typedef virDomainVirtioSerialController *virDomainVirtioSerialControllerPtr; + +struct _virDomainVirtioSerialAddrSet { + virDomainVirtioSerialControllerPtr *controllers; + size_t ncontrollers; +}; +typedef struct _virDomainVirtioSerialAddrSet virDomainVirtioSerialAddrSet; +typedef virDomainVirtioSerialAddrSet *virDomainVirtioSerialAddrSetPtr; + +virDomainVirtioSerialAddrSetPtr +virDomainVirtioSerialAddrSetCreate(void); +int +virDomainVirtioSerialAddrSetAddController(virDomainVirtioSerialAddrSetPtr addrs, + virDomainControllerDefPtr cont) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); +void +virDomainVirtioSerialAddrSetRemoveController(virDomainVirtioSerialAddrSetPtr addrs, + virDomainControllerDefPtr cont) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); +int +virDomainVirtioSerialAddrSetAddControllers(virDomainVirtioSerialAddrSetPtr addrs, + virDomainDefPtr def) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); +void +virDomainVirtioSerialAddrSetFree(virDomainVirtioSerialAddrSetPtr addrs); +bool +virDomainVirtioSerialAddrIsComplete(virDomainDeviceInfoPtr info); +int +virDomainVirtioSerialAddrAutoAssign(virDomainVirtioSerialAddrSetPtr addrs, + virDomainDeviceInfoPtr info, + bool allowZero) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); + +int +virDomainVirtioSerialAddrAssign(virDomainVirtioSerialAddrSetPtr addrs, + virDomainDeviceInfoPtr info, + bool allowZero, + bool portOnly) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); + +int +virDomainVirtioSerialAddrReserve(virDomainDefPtr def, + virDomainDeviceDefPtr dev, + virDomainDeviceInfoPtr info, + void *data) + ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4); + +int +virDomainVirtioSerialAddrRelease(virDomainVirtioSerialAddrSetPtr addrs, + virDomainDeviceInfoPtr info) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); + #endif /* __DOMAIN_ADDR_H__ */ diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 33222f0..fe8aee3 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -108,6 +108,16 @@ virDomainPCIAddressSetFree; virDomainPCIAddressSetGrow; virDomainPCIAddressSlotInUse; virDomainPCIAddressValidate; +virDomainVirtioSerialAddrAssign; +virDomainVirtioSerialAddrAutoAssign; +virDomainVirtioSerialAddrIsComplete; +virDomainVirtioSerialAddrRelease; +virDomainVirtioSerialAddrReserve; +virDomainVirtioSerialAddrSetAddController; +virDomainVirtioSerialAddrSetAddControllers; +virDomainVirtioSerialAddrSetCreate; +virDomainVirtioSerialAddrSetFree; +virDomainVirtioSerialAddrSetRemoveController; # conf/domain_audit.h -- 2.0.5

Instead of always using controller 0 and incrementing port number, respect the maximum port numbers of controllers and use all of them. Ports for virtio consoles are quietly reserved, but not formatted (neither in XML nor on QEMU command line). Also rejects duplicate virtio-serial addresses. https://bugzilla.redhat.com/show_bug.cgi?id=890606 https://bugzilla.redhat.com/show_bug.cgi?id=1076708 Test changes: * virtio-auto.args Filling out the port when just the controller is specified. switched from using maxport + 1 to: first free port on the controller * virtio-autoassign.args Filling out the address when no <address> is specified. Started using all the controllers instead of 0, also discards the bus value. * xml -> xml output of virtio-auto The port assignment is no longer done as a part of XML parsing, so the unspecified values stay 0. --- src/conf/domain_conf.c | 48 +++++------------ src/conf/domain_conf.h | 1 + src/libvirt_private.syms | 1 + src/qemu/qemu_command.c | 63 ++++++++++++++++++++++ src/qemu/qemu_domain.c | 1 + src/qemu/qemu_domain.h | 1 + src/qemu/qemu_process.c | 2 + .../qemuxml2argv-channel-virtio-auto.args | 2 +- .../qemuxml2argv-channel-virtio-autoassign.args | 10 ++-- .../qemuxml2xmlout-channel-virtio-auto.xml | 9 ++-- 10 files changed, 93 insertions(+), 45 deletions(-) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index d633f93..e777f5f 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -3498,21 +3498,6 @@ virDomainDeviceDefPostParseInternal(virDomainDeviceDefPtr dev, chr->target.port = maxport + 1; } - - if (chr->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL && - chr->info.addr.vioserial.port == 0) { - int maxport = 0; - - for (i = 0; i < cnt; i++) { - const virDomainChrDef *thischr = arrPtr[i]; - if (thischr->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL && - thischr->info.addr.vioserial.controller == chr->info.addr.vioserial.controller && - thischr->info.addr.vioserial.bus == chr->info.addr.vioserial.bus && - (int)thischr->info.addr.vioserial.port > maxport) - maxport = thischr->info.addr.vioserial.port; - } - chr->info.addr.vioserial.port = maxport + 1; - } } /* set default path for virtio-rng "random" backend to /dev/random */ @@ -12471,6 +12456,20 @@ virDomainControllerFind(virDomainDefPtr def, } int +virDomainControllerFindByType(virDomainDefPtr def, + int type) +{ + size_t i; + + for (i = 0; i < def->ncontrollers; i++) { + if (def->controllers[i]->type == type) + return i; + } + + return -1; +} + +int virDomainControllerFindByPCIAddress(virDomainDefPtr def, virDevicePCIAddressPtr addr) { @@ -14906,25 +14905,6 @@ virDomainDefParseXML(xmlDocPtr xml, goto error; def->channels[def->nchannels++] = chr; - - if (chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CHANNEL && - chr->targetType == VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_VIRTIO && - chr->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) - chr->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL; - - if (chr->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL && - chr->info.addr.vioserial.port == 0) { - int maxport = 0; - for (j = 0; j < i; j++) { - virDomainChrDefPtr thischr = def->channels[j]; - if (thischr->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL && - thischr->info.addr.vioserial.controller == chr->info.addr.vioserial.controller && - thischr->info.addr.vioserial.bus == chr->info.addr.vioserial.bus && - (int)thischr->info.addr.vioserial.port > maxport) - maxport = thischr->info.addr.vioserial.port; - } - chr->info.addr.vioserial.port = maxport + 1; - } } VIR_FREE(nodes); diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index bceb2d7..b756b40 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -2701,6 +2701,7 @@ int virDomainControllerInsert(virDomainDefPtr def, void virDomainControllerInsertPreAlloced(virDomainDefPtr def, virDomainControllerDefPtr controller); int virDomainControllerFind(virDomainDefPtr def, int type, int idx); +int virDomainControllerFindByType(virDomainDefPtr def, int type); int virDomainControllerFindByPCIAddress(virDomainDefPtr def, virDevicePCIAddressPtr addr); virDomainControllerDefPtr virDomainControllerRemove(virDomainDefPtr def, size_t i); diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index fe8aee3..e6e5da2 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -184,6 +184,7 @@ virDomainClockOffsetTypeToString; virDomainConfigFile; virDomainControllerDefFree; virDomainControllerFind; +virDomainControllerFindByType; virDomainControllerInsert; virDomainControllerInsertPreAlloced; virDomainControllerModelPCITypeToString; diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 7e6b95c..2af5dbf 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -1403,6 +1403,65 @@ qemuAssignSpaprVIOAddress(virDomainDefPtr def, virDomainDeviceInfoPtr info, return 0; } + +static int +qemuDomainAssignVirtioSerialAddresses(virDomainDefPtr def, + virDomainObjPtr obj) +{ + int ret = -1; + size_t i; + virDomainVirtioSerialAddrSetPtr addrs = NULL; + qemuDomainObjPrivatePtr priv = NULL; + + if (virDomainControllerFindByType(def, VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL) == -1) + return 0; + + if (!(addrs = virDomainVirtioSerialAddrSetCreate())) + goto cleanup; + + if (virDomainVirtioSerialAddrSetAddControllers(addrs, def) < 0) + goto cleanup; + + if (virDomainDeviceInfoIterate(def, virDomainVirtioSerialAddrReserve, + addrs) < 0) + goto cleanup; + + VIR_DEBUG("Finished reserving existing ports"); + + for (i = 0; i < def->nconsoles; i++) { + virDomainChrDefPtr chr = def->consoles[i]; + if (chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE && + chr->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_VIRTIO && + !virDomainVirtioSerialAddrIsComplete(&chr->info) && + virDomainVirtioSerialAddrAutoAssign(addrs, &chr->info, true) < 0) + goto cleanup; + } + + for (i = 0; i < def->nchannels; i++) { + virDomainChrDefPtr chr = def->channels[i]; + if (chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CHANNEL && + chr->targetType == VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_VIRTIO && + !virDomainVirtioSerialAddrIsComplete(&chr->info) && + virDomainVirtioSerialAddrAutoAssign(addrs, &chr->info, false) < 0) + goto cleanup; + } + + if (obj && obj->privateData) { + priv = obj->privateData; + /* if this is the live domain object, we persist the addresses */ + virDomainVirtioSerialAddrSetFree(priv->vioserialaddrs); + priv->persistentAddrs = 1; + priv->vioserialaddrs = addrs; + addrs = NULL; + } + ret = 0; + + cleanup: + virDomainVirtioSerialAddrSetFree(addrs); + return ret; +} + + int qemuDomainAssignSpaprVIOAddresses(virDomainDefPtr def, virQEMUCapsPtr qemuCaps) { @@ -1649,6 +1708,10 @@ int qemuDomainAssignAddresses(virDomainDefPtr def, { int rc; + rc = qemuDomainAssignVirtioSerialAddresses(def, obj); + if (rc) + return rc; + rc = qemuDomainAssignSpaprVIOAddresses(def, qemuCaps); if (rc) return rc; diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 655afb9..7879afc 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -431,6 +431,7 @@ qemuDomainObjPrivateFree(void *data) virCgroupFree(&priv->cgroup); virDomainPCIAddressSetFree(priv->pciaddrs); virDomainCCWAddressSetFree(priv->ccwaddrs); + virDomainVirtioSerialAddrSetFree(priv->vioserialaddrs); virDomainChrSourceDefFree(priv->monConfig); qemuDomainObjFreeJob(priv); VIR_FREE(priv->vcpupids); diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h index 28eefac..08279e0 100644 --- a/src/qemu/qemu_domain.h +++ b/src/qemu/qemu_domain.h @@ -159,6 +159,7 @@ struct _qemuDomainObjPrivate { virDomainPCIAddressSetPtr pciaddrs; virDomainCCWAddressSetPtr ccwaddrs; + virDomainVirtioSerialAddrSetPtr vioserialaddrs; int persistentAddrs; virQEMUCapsPtr qemuCaps; diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 59eae1c..45f1bcd 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -5217,6 +5217,8 @@ void qemuProcessStop(virQEMUDriverPtr driver, virDomainDefClearCCWAddresses(vm->def); virDomainCCWAddressSetFree(priv->ccwaddrs); priv->ccwaddrs = NULL; + virDomainVirtioSerialAddrSetFree(priv->vioserialaddrs); + priv->vioserialaddrs = NULL; } qemuDomainReAttachHostDevices(driver, vm->def); diff --git a/tests/qemuxml2argvdata/qemuxml2argv-channel-virtio-auto.args b/tests/qemuxml2argvdata/qemuxml2argv-channel-virtio-auto.args index f7d7409..1806b20 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-channel-virtio-auto.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-channel-virtio-auto.args @@ -15,7 +15,7 @@ virtserialport,bus=virtio-serial1.0,nr=3,chardev=charchannel2,id=channel2,\ name=org.linux-kvm.port.bar -chardev pty,id=charchannel3 -device \ virtserialport,bus=virtio-serial0.0,nr=2,chardev=charchannel3,id=channel3,\ name=org.linux-kvm.port.wizz -chardev pty,id=charchannel4 -device \ -virtserialport,bus=virtio-serial1.0,nr=4,chardev=charchannel4,id=channel4,\ +virtserialport,bus=virtio-serial1.0,nr=2,chardev=charchannel4,id=channel4,\ name=org.linux-kvm.port.ooh -chardev pty,id=charchannel5 -device \ virtserialport,bus=virtio-serial2.0,nr=1,chardev=charchannel5,id=channel5,\ name=org.linux-kvm.port.lla -device virtio-balloon-pci,id=balloon0,\ diff --git a/tests/qemuxml2argvdata/qemuxml2argv-channel-virtio-autoassign.args b/tests/qemuxml2argvdata/qemuxml2argv-channel-virtio-autoassign.args index f7f7b8d..f11039d 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-channel-virtio-autoassign.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-channel-virtio-autoassign.args @@ -5,16 +5,16 @@ LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test QEMU_AUDIO_DRV=none \ -device virtio-serial-pci,id=virtio-serial0,max_ports=4,vectors=4,bus=pci.0\ ,addr=0x3 -device virtio-serial-pci,id=virtio-serial1,bus=pci.0,addr=0xa \ -usb -hda /dev/HostVG/QEMUGuest1 \ --chardev pty,id=charchannel0 -device virtserialport,bus=virtio-serial0.0,nr=1,\ +-chardev pty,id=charchannel0 -device virtserialport,bus=virtio-serial0.0,nr=2,\ chardev=charchannel0,id=channel0,name=org.linux-kvm.port.0 \ --chardev pty,id=charchannel1 -device virtserialport,bus=virtio-serial0.2,nr=1,\ +-chardev pty,id=charchannel1 -device virtserialport,bus=virtio-serial0.0,nr=3,\ chardev=charchannel1,id=channel1,name=org.linux-kvm.port.foo \ -chardev pty,id=charchannel2 -device virtserialport,bus=virtio-serial0.0,nr=1,\ chardev=charchannel2,id=channel2,name=org.linux-kvm.port.bar \ --chardev pty,id=charchannel3 -device virtserialport,bus=virtio-serial0.0,nr=2,\ +-chardev pty,id=charchannel3 -device virtserialport,bus=virtio-serial1.0,nr=1,\ chardev=charchannel3,id=channel3,name=org.linux-kvm.port.wizz \ --chardev pty,id=charchannel4 -device virtserialport,bus=virtio-serial0.0,nr=3,\ +-chardev pty,id=charchannel4 -device virtserialport,bus=virtio-serial1.0,nr=2,\ chardev=charchannel4,id=channel4,name=org.linux-kvm.port.ooh \ --chardev pty,id=charchannel5 -device virtserialport,bus=virtio-serial0.0,nr=4,\ +-chardev pty,id=charchannel5 -device virtserialport,bus=virtio-serial1.0,nr=3,\ chardev=charchannel5,id=channel5,name=org.linux-kvm.port.lla \ -device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x4 diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-channel-virtio-auto.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-channel-virtio-auto.xml index fd6b852..7a608a8 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-channel-virtio-auto.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-channel-virtio-auto.xml @@ -29,11 +29,10 @@ <controller type='virtio-serial' index='2'/> <channel type='pty'> <target type='virtio' name='org.linux-kvm.port.0'/> - <address type='virtio-serial' controller='0' bus='0' port='1'/> </channel> <channel type='pty'> <target type='virtio' name='org.linux-kvm.port.foo'/> - <address type='virtio-serial' controller='1' bus='0' port='1'/> + <address type='virtio-serial' controller='1' bus='0' port='0'/> </channel> <channel type='pty'> <target type='virtio' name='org.linux-kvm.port.bar'/> @@ -41,15 +40,15 @@ </channel> <channel type='pty'> <target type='virtio' name='org.linux-kvm.port.wizz'/> - <address type='virtio-serial' controller='0' bus='0' port='2'/> + <address type='virtio-serial' controller='0' bus='0' port='0'/> </channel> <channel type='pty'> <target type='virtio' name='org.linux-kvm.port.ooh'/> - <address type='virtio-serial' controller='1' bus='0' port='4'/> + <address type='virtio-serial' controller='1' bus='0' port='0'/> </channel> <channel type='pty'> <target type='virtio' name='org.linux-kvm.port.lla'/> - <address type='virtio-serial' controller='2' bus='0' port='1'/> + <address type='virtio-serial' controller='2' bus='0' port='0'/> </channel> <memballoon model='virtio'/> </devices> -- 2.0.5

--- src/qemu/qemu_hotplug.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 9b8d11b..ef2f9b0 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -437,6 +437,7 @@ int qemuDomainAttachControllerDevice(virQEMUDriverPtr driver, char *devstr = NULL; qemuDomainObjPrivatePtr priv = vm->privateData; bool releaseaddr = false; + bool addedToAddrSet = false; if (virDomainControllerFind(vm->def, controller->type, controller->idx) >= 0) { virReportError(VIR_ERR_OPERATION_FAILED, @@ -475,6 +476,12 @@ int qemuDomainAttachControllerDevice(virQEMUDriverPtr driver, goto cleanup; } + if (controller->type == VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL && + virDomainVirtioSerialAddrSetAddController(priv->vioserialaddrs, + controller) < 0) + goto cleanup; + addedToAddrSet = true; + if (!(devstr = qemuBuildControllerDevStr(vm->def, controller, priv->qemuCaps, NULL))) goto cleanup; } @@ -503,6 +510,9 @@ int qemuDomainAttachControllerDevice(virQEMUDriverPtr driver, } cleanup: + if (ret != 0 && addedToAddrSet) + virDomainVirtioSerialAddrSetRemoveController(priv->vioserialaddrs, + controller); if (ret != 0 && releaseaddr) qemuDomainReleaseDeviceAddress(vm, &controller->info, NULL); -- 2.0.5

--- src/qemu/qemu_hotplug.c | 21 +++++++++++++++++++-- tests/qemuhotplugtest.c | 2 +- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index ef2f9b0..560a164 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -1541,6 +1541,8 @@ int qemuDomainAttachChrDevice(virQEMUDriverPtr driver, virDomainDefPtr vmdef = vm->def; char *devstr = NULL; char *charAlias = NULL; + bool need_release = false; + bool allowZero = false; if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) { virReportError(VIR_ERR_OPERATION_INVALID, "%s", @@ -1551,6 +1553,16 @@ int qemuDomainAttachChrDevice(virQEMUDriverPtr driver, if (qemuAssignDeviceChrAlias(vmdef, chr, -1) < 0) goto cleanup; + if (chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE && + chr->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_VIRTIO) + allowZero = true; + + if (virDomainVirtioSerialAddrAutoAssign(priv->vioserialaddrs, + &chr->info, + allowZero) < 0) + goto cleanup; + need_release = true; + if (qemuBuildChrDeviceStr(&devstr, vm->def, chr, priv->qemuCaps) < 0) goto cleanup; @@ -1582,6 +1594,8 @@ int qemuDomainAttachChrDevice(virQEMUDriverPtr driver, cleanup: if (ret < 0 && virDomainObjIsActive(vm)) qemuDomainChrInsertPreAllocCleanup(vm->def, chr); + if (ret < 0 && need_release) + virDomainVirtioSerialAddrRelease(priv->vioserialaddrs, &chr->info); VIR_FREE(charAlias); VIR_FREE(devstr); return ret; @@ -4120,10 +4134,13 @@ int qemuDomainDetachChrDevice(virQEMUDriverPtr driver, goto cleanup; rc = qemuDomainWaitForDeviceRemoval(vm); - if (rc == 0 || rc == 1) + if (rc == 0 || rc == 1) { + virDomainVirtioSerialAddrRelease(priv->vioserialaddrs, &tmpChr->info); ret = qemuDomainRemoveChrDevice(driver, vm, tmpChr); - else + } else { ret = 0; + } + cleanup: qemuDomainResetDeviceRemoval(vm); diff --git a/tests/qemuhotplugtest.c b/tests/qemuhotplugtest.c index 12a7f71..ea2cf77 100644 --- a/tests/qemuhotplugtest.c +++ b/tests/qemuhotplugtest.c @@ -86,7 +86,7 @@ qemuHotplugCreateObjects(virDomainXMLOptionPtr xmlopt, if (event) virQEMUCapsSet(priv->qemuCaps, QEMU_CAPS_DEVICE_DEL_EVENT); - if (qemuDomainAssignPCIAddresses((*vm)->def, priv->qemuCaps, *vm) < 0) + if (qemuDomainAssignAddresses((*vm)->def, priv->qemuCaps, *vm) < 0) goto cleanup; if (qemuAssignDeviceAliases((*vm)->def, priv->qemuCaps) < 0) -- 2.0.5

In virDomainVirtioSerialAddrNext, add another controller if we've exhausted all ports of the existing controllers. https://bugzilla.redhat.com/show_bug.cgi?id=1076708 --- src/conf/domain_addr.c | 47 +++++++++++++++++++--- src/conf/domain_addr.h | 10 +++-- src/qemu/qemu_command.c | 4 +- src/qemu/qemu_hotplug.c | 3 +- .../qemuxml2argv-channel-virtio-autoadd.args | 33 +++++++++++++++ .../qemuxml2argv-channel-virtio-autoadd.xml | 45 +++++++++++++++++++++ tests/qemuxml2argvtest.c | 2 + 7 files changed, 132 insertions(+), 12 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-channel-virtio-autoadd.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-channel-virtio-autoadd.xml diff --git a/src/conf/domain_addr.c b/src/conf/domain_addr.c index 49d28be..27a237d 100644 --- a/src/conf/domain_addr.c +++ b/src/conf/domain_addr.c @@ -878,7 +878,28 @@ virDomainVirtioSerialAddrSetFree(virDomainVirtioSerialAddrSetPtr addrs) } static int -virDomainVirtioSerialAddrNext(virDomainVirtioSerialAddrSetPtr addrs, +virDomainVirtioSerialAddrSetAutoaddController(virDomainDefPtr def, + virDomainVirtioSerialAddrSetPtr addrs, + unsigned int idx) +{ + int contidx; + + if (virDomainDefMaybeAddController(def, + VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL, + idx, -1) < 0) + return -1; + + contidx = virDomainControllerFind(def, VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL, idx); + + if (virDomainVirtioSerialAddrSetAddController(addrs, def->controllers[contidx]) < 0) + return -1; + + return 0; +} + +static int +virDomainVirtioSerialAddrNext(virDomainDefPtr def, + virDomainVirtioSerialAddrSetPtr addrs, virDomainDeviceVirtioSerialAddress *addr, bool allowZero) { @@ -905,6 +926,20 @@ virDomainVirtioSerialAddrNext(virDomainVirtioSerialAddrSetPtr addrs, } } + if (def) { + for (i = 0; i < INT_MAX; i++) { + int idx = virDomainControllerFind(def, VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL, i); + + if (idx == -1) { + if (virDomainVirtioSerialAddrSetAutoaddController(def, addrs, i) < 0) + goto cleanup; + controller = i; + port = startPort + 1; + goto success; + } + } + } + virReportError(VIR_ERR_XML_ERROR, "%s", _("Unable to find a free virtio-serial port")); @@ -958,7 +993,8 @@ virDomainVirtioSerialAddrNextFromController(virDomainVirtioSerialAddrSetPtr addr * or assign a virtio serial address to the device */ int -virDomainVirtioSerialAddrAutoAssign(virDomainVirtioSerialAddrSetPtr addrs, +virDomainVirtioSerialAddrAutoAssign(virDomainDefPtr def, + virDomainVirtioSerialAddrSetPtr addrs, virDomainDeviceInfoPtr info, bool allowZero) { @@ -967,12 +1003,13 @@ virDomainVirtioSerialAddrAutoAssign(virDomainVirtioSerialAddrSetPtr addrs, info->addr.vioserial.port) return virDomainVirtioSerialAddrReserve(NULL, NULL, info, addrs); else - return virDomainVirtioSerialAddrAssign(addrs, info, allowZero, portOnly); + return virDomainVirtioSerialAddrAssign(def, addrs, info, allowZero, portOnly); } int -virDomainVirtioSerialAddrAssign(virDomainVirtioSerialAddrSetPtr addrs, +virDomainVirtioSerialAddrAssign(virDomainDefPtr def, + virDomainVirtioSerialAddrSetPtr addrs, virDomainDeviceInfoPtr info, bool allowZero, bool portOnly) @@ -988,7 +1025,7 @@ virDomainVirtioSerialAddrAssign(virDomainVirtioSerialAddrSetPtr addrs, &ptr->addr.vioserial) < 0) goto cleanup; } else { - if (virDomainVirtioSerialAddrNext(addrs, &ptr->addr.vioserial, + if (virDomainVirtioSerialAddrNext(def, addrs, &ptr->addr.vioserial, allowZero) < 0) goto cleanup; } diff --git a/src/conf/domain_addr.h b/src/conf/domain_addr.h index 14ffd17..c18e130 100644 --- a/src/conf/domain_addr.h +++ b/src/conf/domain_addr.h @@ -208,17 +208,19 @@ virDomainVirtioSerialAddrSetFree(virDomainVirtioSerialAddrSetPtr addrs); bool virDomainVirtioSerialAddrIsComplete(virDomainDeviceInfoPtr info); int -virDomainVirtioSerialAddrAutoAssign(virDomainVirtioSerialAddrSetPtr addrs, +virDomainVirtioSerialAddrAutoAssign(virDomainDefPtr def, + virDomainVirtioSerialAddrSetPtr addrs, virDomainDeviceInfoPtr info, bool allowZero) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); + ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3); int -virDomainVirtioSerialAddrAssign(virDomainVirtioSerialAddrSetPtr addrs, +virDomainVirtioSerialAddrAssign(virDomainDefPtr def, + virDomainVirtioSerialAddrSetPtr addrs, virDomainDeviceInfoPtr info, bool allowZero, bool portOnly) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); + ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3); int virDomainVirtioSerialAddrReserve(virDomainDefPtr def, diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 2af5dbf..c339088 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -1433,7 +1433,7 @@ qemuDomainAssignVirtioSerialAddresses(virDomainDefPtr def, if (chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE && chr->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_VIRTIO && !virDomainVirtioSerialAddrIsComplete(&chr->info) && - virDomainVirtioSerialAddrAutoAssign(addrs, &chr->info, true) < 0) + virDomainVirtioSerialAddrAutoAssign(def, addrs, &chr->info, true) < 0) goto cleanup; } @@ -1442,7 +1442,7 @@ qemuDomainAssignVirtioSerialAddresses(virDomainDefPtr def, if (chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CHANNEL && chr->targetType == VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_VIRTIO && !virDomainVirtioSerialAddrIsComplete(&chr->info) && - virDomainVirtioSerialAddrAutoAssign(addrs, &chr->info, false) < 0) + virDomainVirtioSerialAddrAutoAssign(def, addrs, &chr->info, false) < 0) goto cleanup; } diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 560a164..2f0549e 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -1557,7 +1557,8 @@ int qemuDomainAttachChrDevice(virQEMUDriverPtr driver, chr->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_VIRTIO) allowZero = true; - if (virDomainVirtioSerialAddrAutoAssign(priv->vioserialaddrs, + if (virDomainVirtioSerialAddrAutoAssign(NULL, + priv->vioserialaddrs, &chr->info, allowZero) < 0) goto cleanup; diff --git a/tests/qemuxml2argvdata/qemuxml2argv-channel-virtio-autoadd.args b/tests/qemuxml2argvdata/qemuxml2argv-channel-virtio-autoadd.args new file mode 100644 index 0000000..9aae58a --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-channel-virtio-autoadd.args @@ -0,0 +1,33 @@ +LC_ALL=C \ +PATH=/bin \ +HOME=/home/test \ +USER=test \ +LOGNAME=test \ +QEMU_AUDIO_DRV=none \ +/usr/bin/qemu -S -M pc -m 214 -smp 1 \ +-nographic -nodefconfig -nodefaults \ +-chardev socket,id=charmonitor,path=/tmp/test-monitor,server,nowait \ +-mon chardev=charmonitor,id=monitor,mode=readline \ +-no-acpi -boot c \ +-device virtio-serial-pci,id=virtio-serial0,max_ports=4,vectors=4,bus=pci.0,addr=0x3 \ +-device virtio-serial-pci,id=virtio-serial1,bus=pci.0,addr=0x4 \ +-usb -hda /dev/HostVG/QEMUGuest1 \ +-chardev pty,id=charchannel0 \ +-device virtserialport,bus=virtio-serial0.0,nr=1,chardev=charchannel0,\ +id=channel0,name=org.linux-kvm.port.0 \ +-chardev pty,id=charchannel1 \ +-device virtserialport,bus=virtio-serial0.0,nr=2,chardev=charchannel1,\ +id=channel1,name=org.linux-kvm.port.foo \ +-chardev pty,id=charchannel2 \ +-device virtserialport,bus=virtio-serial0.0,nr=3,chardev=charchannel2,\ +id=channel2,name=org.linux-kvm.port.bar \ +-chardev pty,id=charchannel3 \ +-device virtserialport,bus=virtio-serial1.0,nr=1,chardev=charchannel3,\ +id=channel3,name=org.linux-kvm.port.wizz \ +-chardev pty,id=charchannel4 \ +-device virtserialport,bus=virtio-serial1.0,nr=2,chardev=charchannel4,\ +id=channel4,name=org.linux-kvm.port.ooh \ +-chardev pty,id=charchannel5 \ +-device virtserialport,bus=virtio-serial1.0,nr=3,chardev=charchannel5,\ +id=channel5,name=org.linux-kvm.port.lla \ +-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x5 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-channel-virtio-autoadd.xml b/tests/qemuxml2argvdata/qemuxml2argv-channel-virtio-autoadd.xml new file mode 100644 index 0000000..0da2492 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-channel-virtio-autoadd.xml @@ -0,0 +1,45 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>219100</memory> + <currentMemory unit='KiB'>219100</currentMemory> + <vcpu placement='static' cpuset='1-4,8-20,525'>1</vcpu> + <os> + <type arch='i686' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu</emulator> + <disk type='block' device='disk'> + <source dev='/dev/HostVG/QEMUGuest1'/> + <target dev='hda' bus='ide'/> + <address type='drive' controller='0' bus='0' target='0' unit='0'/> + </disk> + <controller type='usb' index='0'/> + <controller type='ide' index='0'/> + <controller type='virtio-serial' index='0' ports='4' vectors='4'/> + <channel type='pty'> + <target type='virtio' name='org.linux-kvm.port.0'/> + </channel> + <channel type='pty'> + <target type='virtio' name='org.linux-kvm.port.foo'/> + </channel> + <channel type='pty'> + <target type='virtio' name='org.linux-kvm.port.bar'/> + </channel> + <channel type='pty'> + <target type='virtio' name='org.linux-kvm.port.wizz'/> + </channel> + <channel type='pty'> + <target type='virtio' name='org.linux-kvm.port.ooh'/> + </channel> + <channel type='pty'> + <target type='virtio' name='org.linux-kvm.port.lla'/> + </channel> + <memballoon model='virtio'/> + </devices> +</domain> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 00e608c..ff8b37a 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -1072,6 +1072,8 @@ mymain(void) QEMU_CAPS_DEVICE, QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG); DO_TEST("channel-virtio-autoassign", QEMU_CAPS_DEVICE, QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG); + DO_TEST("channel-virtio-autoadd", + QEMU_CAPS_DEVICE, QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG); DO_TEST("console-virtio", QEMU_CAPS_DEVICE, QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG); DO_TEST("console-virtio-many", -- 2.0.5

On 03/24/2015 01:15 PM, Ján Tomko wrote:
Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1076708 https://bugzilla.redhat.com/show_bug.cgi?id=890606
New in v3: * preserve the behavior of honoring the controller if a partial address is specified: <address type='virtio-serial' controller='2'/> * automatically add a controller if we're out of free ports and add a test for it
Ján Tomko (6): Add test for virtio serial port assignment Add functions to track virtio-serial addresses Allocate virtio-serial addresses when starting a domain Expand the address set when attaching a virtio-serial controller Assign an address when hotplugging a virtio-serial device Auto add virtio-serial controllers
src/conf/domain_addr.c | 435 +++++++++++++++++++++ src/conf/domain_addr.h | 61 +++ src/conf/domain_conf.c | 48 +-- src/conf/domain_conf.h | 1 + src/libvirt_private.syms | 11 + src/qemu/qemu_command.c | 63 +++ src/qemu/qemu_domain.c | 1 + src/qemu/qemu_domain.h | 1 + src/qemu/qemu_hotplug.c | 32 +- src/qemu/qemu_process.c | 2 + tests/qemuhotplugtest.c | 2 +- .../qemuxml2argv-channel-virtio-auto.args | 2 +- .../qemuxml2argv-channel-virtio-autoadd.args | 33 ++ .../qemuxml2argv-channel-virtio-autoadd.xml | 45 +++ .../qemuxml2argv-channel-virtio-autoassign.args | 20 + .../qemuxml2argv-channel-virtio-autoassign.xml | 50 +++ tests/qemuxml2argvtest.c | 4 + .../qemuxml2xmlout-channel-virtio-auto.xml | 9 +- 18 files changed, 777 insertions(+), 43 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-channel-virtio-autoadd.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-channel-virtio-autoadd.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-channel-virtio-autoassign.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-channel-virtio-autoassign.xml
ACK series John

On Thu, Apr 02, 2015 at 07:58:32AM -0400, John Ferlan wrote:
On 03/24/2015 01:15 PM, Ján Tomko wrote:
Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1076708 https://bugzilla.redhat.com/show_bug.cgi?id=890606
New in v3: * preserve the behavior of honoring the controller if a partial address is specified: <address type='virtio-serial' controller='2'/> * automatically add a controller if we're out of free ports and add a test for it
Ján Tomko (6): Add test for virtio serial port assignment Add functions to track virtio-serial addresses Allocate virtio-serial addresses when starting a domain Expand the address set when attaching a virtio-serial controller Assign an address when hotplugging a virtio-serial device Auto add virtio-serial controllers
...
ACK series
Pushed now, thanks for the review. Jan
participants (2)
-
John Ferlan
-
Ján Tomko