[libvirt] [PATCHv2 4/7] qemu: fix handling of default/implicit devices for q35

Doug Goldstein cardoe at gentoo.org
Mon Aug 5 13:40:42 UTC 2013


On Mon, Aug 5, 2013 at 3:37 AM, Laine Stump <laine at laine.org> wrote:
> On 08/04/2013 07:53 PM, Doug Goldstein wrote:
>> On Sat, Aug 3, 2013 at 9:01 PM, Laine Stump <laine at laine.org> wrote:
>>> This patch adds in special handling for a few devices that need to be
>>> treated differently for q35 domains:
>>>
>>> usb - there is no implicit/default usb controller for the q35
>>> machinetype. This is done because normally the default usb controller
>>> is added to a domain by just adding "-usb" to the qemu commandline,
>>> and it's assumed that this will add a single piix3 usb1 controller at
>>> slot 1 function 2. That's not what happens when the machinetype is
>>> q35, though. Instead, adding -usb to the commandline adds 3 usb
>>> (version 2) controllers to the domain at slot 0x1D.{1,2,7}. Rather
>>> than having
>>>
>>>   <controller type='usb' index='0'/>
>>>
>>> translate into 3 separate devices on the PCI bus, it's cleaner to not
>>> automatically add a default usb device; one can always be added
>>> explicitly if desired. Or we may decide that on q35 machines, 3 usb
>>> controllers will be automatically added when none is given. But for
>>> this initial commit, at least we aren't locking ourselves into
>>> something we later won't want.
>>>
>>> video - for pc machine types, the primary video device is always in
>>> slot 2, and that slot is reserved even when no video device has been
>>> specified. On q35, when you specify "-vga qxl" on the qemu
>>> commandline, the vga device is put in slot 1, not 2. Assuming that
>>> this was done for a reason, this patch always puts the primary video
>>> for q35 machines in slot 1, and reserves slot 1 even if there is no
>>> video.
>> Might be worth updating the comments here to say that QEMU will assign
>> it in the first available slot, which with q35 is slot 1 and i440fx
>> (pc) is slot 2 (due to the always present IDE controller).
>
>
> I see you caught my question (and the later discussion) on qemu-devel
> :-) yeah, I think it would be reasonable to change this comment, now
> that I understand better what is happening.
>
>
>>
>>> sata - a q35 machine always has a sata controller implicitly added at
>>> slot 0x1F, function 2. There is no way to avoid this controller, so we
>>> always add it. Note that the xml2xml tests for the pcie-root and q35
>>> cases were changed to use DO_TEST_DIFFERENT() so that we can check for
>>> the sata controller being automatically added. This is especially
>>> important because we can't check for it in the xml2argv output (it has
>>> no effect on that output since it's an implicit device).
>> The note about pcie-root switching to DO_TEST_DIFFERENT should go into
>> the earlier patch.
>
> Done.
>
>>
>>> ide - q35 has no ide controllers.
>>>
>>> isa and smbus controllers - these two are always present in a q35 (at
>>> slot 0x1F functions 0 and 3) but we have no way of modelling them in
>>> our config. We do need to reserve those functions so that the user
>>> doesn't attempt to put anything else there though.
>>> ---
>>>
>>> +    if (def->nvideos > 0) {
>>> +        /* NB: unlike the pc machinetypes, q35 machinetypes put the primary VGA
>>> +         * at slot 1 for some reason.
>>> +         */
>>> +        virDomainVideoDefPtr primaryVideo = def->videos[0];
>>> +        if (primaryVideo->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
>>> +            primaryVideo->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
>>> +            primaryVideo->info.addr.pci.domain = 0;
>>> +            primaryVideo->info.addr.pci.bus = 0;
>>> +            primaryVideo->info.addr.pci.slot = 1;
>>> +            primaryVideo->info.addr.pci.function = 0;
>>> +            addrptr = &primaryVideo->info.addr.pci;
>>> +
>>> +            if (!qemuDomainPCIAddressValidate(addrs, addrptr, flags))
>>> +                goto error;
>>> +
>>> +            if (qemuDomainPCIAddressSlotInUse(addrs, addrptr)) {
>>> +                if (qemuDeviceVideoUsable) {
>>> +                    virResetLastError();
>>> +                    if (qemuDomainPCIAddressReserveNextSlot(addrs,
>>> +                                                            &primaryVideo->info,
>>> +                                                            flags) < 0)
>>> +                        goto error;
>>> +                } else {
>>> +                    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
>>> +                                   _("PCI address 0:0:1.0 is in use, "
>>> +                                     "QEMU needs it for primary video"));
>>> +                    goto error;
>>> +                }
>>> +            } else if (qemuDomainPCIAddressReserveSlot(addrs, addrptr, flags) < 0) {
>>> +                goto error;
>>> +            }
>>> +        } else if (!qemuDeviceVideoUsable) {
>>> +            if (primaryVideo->info.addr.pci.domain != 0 ||
>>> +                primaryVideo->info.addr.pci.bus != 0 ||
>>> +                primaryVideo->info.addr.pci.slot != 1 ||
>>> +                primaryVideo->info.addr.pci.function != 0) {
>>> +                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
>>> +                               _("Primary video card must have PCI address 0:0:1.0"));
>>> +                goto error;
>>> +            }
>>> +            /* If TYPE==PCI, then qemuCollectPCIAddress() function
>>> +             * has already reserved the address, so we must skip */
>>> +        }
>>> +    } else if (addrs->nbuses && !qemuDeviceVideoUsable) {
>>> +        memset(&tmp_addr, 0, sizeof(tmp_addr));
>>> +        tmp_addr.slot = 1;
>>> +
>>> +        if (qemuDomainPCIAddressSlotInUse(addrs, &tmp_addr)) {
>>> +            VIR_DEBUG("PCI address 0:0:1.0 in use, future addition of a video"
>>> +                      " device will not be possible without manual"
>>> +                      " intervention");
>>> +            virResetLastError();
>>> +        } else if (qemuDomainPCIAddressReserveSlot(addrs, &tmp_addr, flags) < 0) {
>>> +            goto error;
>>> +        }
>>> +    }
>> Is this really necessary/correct? From the qemu-devel thread it really
>> seems like the VGA controller will just take the first available slot
>> but is it not possible for us to stick this somewhere other than slot
>> 1? I know with current libvirt and qemu we limit ourselves to -vga qxl
>> rather than -device qxl-vga due to a bug in QEMU but I think with QEMU
>> 1.6, that limitation goes away so that might free us up to move it
>> around.
>
> Unfortunately, I think that if we want to avoid surprises with the
> location of the video device then we have to do this. The problem is
> that not everybody has qemu 1.6+ (actually at this point *almost nobody*
> does). If we don't reserve "the first" slot (be it 1 or 2) for the video
> adapter when the domain is created, and continue to watch out for it as
> long as no video is added, another device would probably go in that
> place, and when the user finally did get around to adding a device, it
> would go in "some other" indeterminate place (well, we could figure it
> out, but it would be much more inconvenient that simply reserving slot 1
> or 2 on every domain for video)
>
> I may be taking this too seriously though - does anyone else want to
> chime in one way or another?

I think you're probably right and we want to keep this check in.
Obviously we want libvirt to do the right thing for users and not give
them a bunch of bits that they need to sort themselves so this check
helps users along the right path and helps get a consistent
environment for different QEMU binaries so keep it.


>
>
>>
>>
>>> +    return 0;
>>> +
>>> +error:
>>> +    return -1;
>>> +}
>>> +
>>> +
>>>  /*
>>>   * This assigns static PCI slots to all configured devices.
>>>   * The ordering here is chosen to match the ordering used
>>> @@ -2365,6 +2504,11 @@ qemuAssignDevicePCISlots(virDomainDefPtr def,
>>>          goto error;
>>>      }
>>>
>>> +    if (qemuDomainMachineIsQ35(def) &&
>>> +        qemuDomainValidateDevicePCISlotsQ35(def, qemuCaps, addrs) < 0) {
>>> +        goto error;
>>> +    }
>>> +
>>>      /* PCI controllers */
>>>      for (i = 0; i < def->ncontrollers; i++) {
>>>          if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI) {
>>> @@ -7676,6 +7820,9 @@ qemuBuildCommandLine(virConnectPtr conn,
>>>                                         _("SATA is not supported with this "
>>>                                           "QEMU binary"));
>>>                          goto error;
>>> +                    } else if (cont->idx == 0 && qemuDomainMachineIsQ35(def)) {
>>> +                        /* first SATA controller on Q35 machines is implicit */
>>> +                        continue;
>>>                      } else {
>>>                          char *devstr;
>>>
>>> @@ -7689,6 +7836,7 @@ qemuBuildCommandLine(virConnectPtr conn,
>>>                      }
>>>                  } else if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_USB &&
>>>                             cont->model == -1 &&
>>> +                           !qemuDomainMachineIsQ35(def) &&
>>>                             (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_PIIX3_USB_UHCI) ||
>>>                              def->os.arch == VIR_ARCH_PPC64)) {
>>>                      if (usblegacy) {
>>> @@ -7713,7 +7861,7 @@ qemuBuildCommandLine(virConnectPtr conn,
>>>          }
>>>      }
>>>
>>> -    if (usbcontroller == 0)
>>> +    if (usbcontroller == 0 && !qemuDomainMachineIsQ35(def))
>>>          virCommandAddArg(cmd, "-usb");
>>>
>>>      for (i = 0; i < def->nhubs; i++) {
>>> diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
>>> index f5030cd..75be591 100644
>>> --- a/src/qemu/qemu_domain.c
>>> +++ b/src/qemu/qemu_domain.c
>>> @@ -700,6 +700,7 @@ qemuDomainDefPostParse(virDomainDefPtr def,
>>>                         void *opaque ATTRIBUTE_UNUSED)
>>>  {
>>>      bool addDefaultUSB = true;
>>> +    bool addImplicitSATA = false;
>>>      bool addPCIRoot = false;
>>>      bool addPCIeRoot = false;
>>>
>>> @@ -722,6 +723,7 @@ qemuDomainDefPostParse(virDomainDefPtr def,
>>>              STREQ(def->os.machine, "q35")) {
>>>             addPCIeRoot = true;
>>>             addDefaultUSB = false;
>>> +           addImplicitSATA = true;
>>>             break;
>>>          }
>>>          if (!STRPREFIX(def->os.machine, "pc-0.") &&
>>> @@ -754,6 +756,11 @@ qemuDomainDefPostParse(virDomainDefPtr def,
>>>              def, VIR_DOMAIN_CONTROLLER_TYPE_USB, 0, -1) < 0)
>>>          return -1;
>>>
>>> +    if (addImplicitSATA &&
>>> +        virDomainDefMaybeAddController(
>>> +            def, VIR_DOMAIN_CONTROLLER_TYPE_SATA, 0, -1) < 0)
>>> +        return -1;
>>> +
>>>      if (addPCIRoot &&
>>>          virDomainDefMaybeAddController(
>>>              def, VIR_DOMAIN_CONTROLLER_TYPE_PCI, 0,
>>> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-pcie-root.args b/tests/qemuxml2argvdata/qemuxml2argv-pcie-root.args
>>> index 23db85c..cecef7b 100644
>>> --- a/tests/qemuxml2argvdata/qemuxml2argv-pcie-root.args
>>> +++ b/tests/qemuxml2argvdata/qemuxml2argv-pcie-root.args
>>> @@ -1,5 +1,5 @@
>>>  LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/libexec/qemu-kvm \
>>>  -S -M q35 -m 2048 -smp 2 -nographic -nodefaults \
>>>  -monitor unix:/tmp/test-monitor,server,nowait -no-acpi -boot c \
>>> --device i82801b11-bridge,id=pci.1,bus=pci.0,addr=0x1 \
>>> --device pci-bridge,chassis_nr=2,id=pci.2,bus=pci.1,addr=0x1 -usb
>>> +-device i82801b11-bridge,id=pci.1,bus=pci.0,addr=0x2 \
>>> +-device pci-bridge,chassis_nr=2,id=pci.2,bus=pci.1,addr=0x1
>>> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-pcie-root.xml b/tests/qemuxml2argvdata/qemuxml2argv-pcie-root.xml
>>> index 1aa5455..d7fb90c 100644
>>> --- a/tests/qemuxml2argvdata/qemuxml2argv-pcie-root.xml
>>> +++ b/tests/qemuxml2argvdata/qemuxml2argv-pcie-root.xml
>>> @@ -15,7 +15,6 @@
>>>    <devices>
>>>      <emulator>/usr/libexec/qemu-kvm</emulator>
>>>      <controller type='pci' index='0' model='pcie-root'/>
>>> -    <controller type='usb' index='0'/>
>>>      <memballoon model='none'/>
>>>    </devices>
>>>  </domain>
>>> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-q35.args b/tests/qemuxml2argvdata/qemuxml2argv-q35.args
>>> index ddff6f0..6c24407 100644
>>> --- a/tests/qemuxml2argvdata/qemuxml2argv-q35.args
>>> +++ b/tests/qemuxml2argvdata/qemuxml2argv-q35.args
>>> @@ -1,7 +1,6 @@
>>>  LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test \
>>>  /usr/libexec/qemu-kvm -S -M q35 -m 2048 -smp 2 -nographic -nodefaults \
>>>  -monitor unix:/tmp/test-monitor,server,nowait -no-acpi -boot c \
>>> --device i82801b11-bridge,id=pci.1,bus=pci.0,addr=0x1 \
>>> +-device i82801b11-bridge,id=pci.1,bus=pci.0,addr=0x2 \
>>>  -device pci-bridge,chassis_nr=2,id=pci.2,bus=pci.1,addr=0x1 \
>>> --usb \
>>>  -vga qxl -global qxl.ram_size=67108864 -global qxl.vram_size=18874368
>>> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
>>> index aba0f88..0068d27 100644
>>> --- a/tests/qemuxml2argvtest.c
>>> +++ b/tests/qemuxml2argvtest.c
>>> @@ -995,11 +995,13 @@ mymain(void)
>>>      DO_TEST("pci-bridge-many-disks",
>>>              QEMU_CAPS_DEVICE, QEMU_CAPS_DRIVE, QEMU_CAPS_DEVICE_PCI_BRIDGE);
>>>      DO_TEST("pcie-root",
>>> +            QEMU_CAPS_ICH9_AHCI,
>>>              QEMU_CAPS_DEVICE, QEMU_CAPS_DEVICE_PCI_BRIDGE,
>>>              QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE);
>>>      DO_TEST("q35",
>>>              QEMU_CAPS_DEVICE, QEMU_CAPS_DEVICE_PCI_BRIDGE,
>>>              QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE,
>>> +            QEMU_CAPS_ICH9_AHCI,
>>>              QEMU_CAPS_VGA, QEMU_CAPS_DEVICE_VIDEO_PRIMARY,
>>>              QEMU_CAPS_VGA, QEMU_CAPS_VGA_QXL, QEMU_CAPS_DEVICE_QXL);
>>>
>>> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pcie-root.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pcie-root.xml
>>> index 25c77f1..f10e85b 100644
>>> --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pcie-root.xml
>>> +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pcie-root.xml
>>> @@ -15,7 +15,7 @@
>>>    <devices>
>>>      <emulator>/usr/libexec/qemu-kvm</emulator>
>>>      <controller type='pci' index='0' model='pcie-root'/>
>>> -    <controller type='usb' index='0'/>
>>> +    <controller type='sata' index='0'/>
>>>      <controller type='pci' index='1' model='dmi-to-pci-bridge'/>
>>>      <controller type='pci' index='2' model='pci-bridge'/>
>>>      <memballoon model='none'/>
>>> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35.xml
>>> new file mode 100644
>>> index 0000000..2a86e61
>>> --- /dev/null
>>> +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35.xml
>>> @@ -0,0 +1,26 @@
>>> +<domain type='qemu'>
>>> +  <name>q35-test</name>
>>> +  <uuid>11dbdcdd-4c3b-482b-8903-9bdb8c0a2774</uuid>
>>> +  <memory unit='KiB'>2097152</memory>
>>> +  <currentMemory unit='KiB'>2097152</currentMemory>
>>> +  <vcpu placement='static' cpuset='0-1'>2</vcpu>
>>> +  <os>
>>> +    <type arch='x86_64' machine='q35'>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/libexec/qemu-kvm</emulator>
>>> +    <controller type='pci' index='0' model='pcie-root'/>
>>> +    <controller type='pci' index='1' model='dmi-to-pci-bridge'/>
>>> +    <controller type='pci' index='2' model='pci-bridge'/>
>>> +    <controller type='sata' index='0'/>
>>> +    <video>
>>> +      <model type='qxl' ram='65536' vram='18432' heads='1'/>
>>> +    </video>
>>> +    <memballoon model='none'/>
>>> +  </devices>
>>> +</domain>
>>> diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c
>>> index 8b4590a..5c6730d 100644
>>> --- a/tests/qemuxml2xmltest.c
>>> +++ b/tests/qemuxml2xmltest.c
>>> @@ -295,7 +295,7 @@ mymain(void)
>>>      DO_TEST_DIFFERENT("pci-autoadd-addr");
>>>      DO_TEST_DIFFERENT("pci-autoadd-idx");
>>>      DO_TEST_DIFFERENT("pcie-root");
>>> -    DO_TEST("q35");
>>> +    DO_TEST_DIFFERENT("q35");
>>>
>>>      DO_TEST("hostdev-scsi-lsi");
>>>      DO_TEST("hostdev-scsi-virtio-scsi");
>>> --
>>> 1.7.11.7
>>>
>>> --
>>> libvir-list mailing list
>>> libvir-list at redhat.com
>>> https://www.redhat.com/mailman/listinfo/libvir-list
>> I'm going to hold off on saying ACK here due to my question above, but
>> we might not even need a code change if my understanding is wrong.
>>
>



-- 
Doug Goldstein




More information about the libvir-list mailing list