[libvirt] [PATCH] Fix ejecting cdroms with latest qemu syntax

Daniel P. Berrange berrange at redhat.com
Thu Aug 28 09:17:34 UTC 2008


On Wed, Aug 27, 2008 at 05:32:21PM -0400, Cole Robinson wrote:
> Daniel P. Berrange wrote:
> > 
> > I think this block could be re-factored a little into one or more helper
> > methods, because I think we'll need to re-use this for hot-unplug of
> > disks. I'd suggest a helper to turn the plain integer index into the
> > (bus,device) index pair
> > 
> >      virDiskNameToBusDeviceIndex(virDomainDiskDefPtr disk, 
> >                                  int *busIdx, 
> >                                  int *devIdx);
> > 
> > And then a QEMU specific function
> > 
> >     char *virQEMUDeviceName(virDomainDiskDefPtr disk);
> > 
> > and have this call virDiskNameToBusDeviceIndex() and return the 'ide1-2'
> > type string.
> > 
> 
> Okay, second cut attached. I followed your recommendations:
> 
> virDiskNameToBusDeviceIndex added to domain_conf.c
> qemudDiskDeviceName added to qemu_driver.c
> 
> I also hopefully solved the back compatibility issue. Seems
> -drive was added to qemu in Dec 07 (qemu commit 3759) and the
> device naming scheme was updated at the end of that month (qemu
> commit 3846), so checking for -drive should be a sufficient 
> indicator that we need to use the new device name format. So
> if drive was detected (using the already present qemu_conf
> flag), we revert to the old style cdrom/fda naming style.

Excellant - that intermediate month can be argued as a bug
because people could add multiple CDROMs and the monitor
provided no way to select between them. So this check for 
-drive is sufficient.


> +/* Translates a device name of the form (regex) "[fhv]d[a-z]+" into
> + * the corresponding bus,index combination (e.g. sda => (0,0), sdi (1,1),
> + *                                               hdd => (1,1), vdaa => (0,27))
> + * @param disk The disk device
> + * @param busIdx parsed bus number
> + * @param devIdx parsed device number
> + * @return 0 on success, -1 on failure
> + */
> +int virDiskNameToBusDeviceIndex(virDomainDiskDefPtr disk,
> +                                int *busIdx,
> +                                int *devIdx) {
> +
> +    int idx = virDiskNameToIndex(disk->dst);

Minor bug here

       if (idx < 0)
          return -1;

> +
> +    switch (disk->bus) {
> +        case VIR_DOMAIN_DISK_BUS_IDE:
> +            *busIdx = ((idx - (idx % 2)) / 2);
> +            *devIdx = (idx % 2);
> +            break;
> +        case VIR_DOMAIN_DISK_BUS_SCSI:
> +            *busIdx = ((idx - (idx % 7)) / 7);
> +            *devIdx = (idx % 7);
> +            break;
> +        case VIR_DOMAIN_DISK_BUS_FDC:
> +        case VIR_DOMAIN_DISK_BUS_VIRTIO:

Could also add 

      case VIR_DOMAIN_DISK_BUS_USB:
      case VIR_DOMAIN_DISK_BUS_XEN:

> +        default:
> +            *busIdx = 0;
> +            *devIdx = idx;
> +            break;
> +    }
> +
> +    return 0;
> +}


> +/* Return the disks name for use in monitor commands */
> +static char *qemudDiskDeviceName(virDomainPtr dom,
> +                                 virDomainDiskDefPtr disk) {
> +
> +    int busid, devid;
> +    int ret;
> +    char *devname;
> +
> +    virDiskNameToBusDeviceIndex(disk, &busid, &devid);

     if (virDiskNameToBusDeviceIndex(disk, &busid, &devid) < 0)
           qemudReportError(dom->conn, dom, NULL, VIR_ERR_INTERNAL_ERROR,
                            _("cannot convertor disk name to bus/device index"));
           return NULL;
     }

> +
> +    switch (disk->bus) {
> +        case VIR_DOMAIN_DISK_BUS_IDE:
> +            ret = asprintf(&devname, "ide%d-cd%d", busid, devid);
> +            break;
> +        case VIR_DOMAIN_DISK_BUS_SCSI:
> +            ret = asprintf(&devname, "scsi%d-cd%d", busid, devid);
> +            break;
> +        case VIR_DOMAIN_DISK_BUS_FDC:
> +            ret = asprintf(&devname, "floppy%d", devid);
> +            break;
> +        case VIR_DOMAIN_DISK_BUS_VIRTIO:
> +            ret = asprintf(&devname, "virtio%d", devid);
> +            break;
> +        default:
> +            qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
> +                             _("Unknown disk name mapping for bus '%s'"),
> +                             virDomainDiskBusTypeToString(disk->bus));

s/Unknown/Unsupported/  because we know about Xen / USB, merely don't
support them. 

> +            return NULL;
> +    }
> +
> +    if (ret == -1) {
> +        qemudReportError(dom->conn, NULL, NULL, VIR_ERR_NO_MEMORY, NULL);
> +        return NULL;
> +    }
> +
> +    return devname;
> +}
> +
> +static int qemudDomainChangeEjectableMedia(virDomainPtr dom,
> +                                           virDomainDeviceDefPtr dev)
> +{
>      struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData;
> +    virDomainObjPtr vm = virDomainFindByUUID(driver->domains, dom->uuid);
> +    virDomainDiskDefPtr origdisk, newdisk;
>      char *cmd, *reply, *safe_path;
> +    char *devname = NULL;
> +    int qemuCmdFlags;
> +
> +    if (!vm) {
> +        qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN,
> +                         "%s", _("no domain with matching uuid"));
> +        return -1;
> +    }
> +
> +    newdisk = dev->data.disk;
> +    origdisk = vm->def->disks;
> +    while (origdisk) {
> +        if (origdisk->bus == newdisk->bus &&
> +            STREQ(origdisk->dst, newdisk->dst))
> +            break;
> +        origdisk = origdisk->next;
> +    }
> +
> +    if (!origdisk) {
> +        qemudReportError(dom->conn, dom, NULL, VIR_ERR_INTERNAL_ERROR,
> +                         _("No device with bus '%s' and target '%s'"),
> +                         virDomainDiskBusTypeToString(newdisk->bus),
> +                         newdisk->dst);
> +        return -1;
> +    }
> +
> +    if (qemudExtractVersionInfo(vm->def->emulator,
> +                                NULL,
> +                                &qemuCmdFlags) < 0) {
> +        qemudReportError(dom->conn, dom, NULL, VIR_ERR_INTERNAL_ERROR,
> +                         _("Cannot determine QEMU argv syntax %s"),
> +                         vm->def->emulator);
> +        return -1;
> +    }
> +
> +    if (qemuCmdFlags & QEMUD_CMD_FLAG_DRIVE) {
> +        devname = qemudDiskDeviceName(dom, newdisk);
> +    } else {
> +        /* Back compat for no -drive option */
> +        if (newdisk->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY)
> +            devname = strdup(newdisk->dst);
> +        else if (newdisk->device == VIR_DOMAIN_DISK_DEVICE_CDROM &&
> +                 STREQ(newdisk->dst, "hdc"))
> +            devname = strdup("cdrom");
> +        else {
> +            qemudReportError(dom->conn, dom, NULL, VIR_ERR_INTERNAL_ERROR,
> +                             _("Emulator version does not support removable "
> +                               "media for device '%s' and target '%s'"),
> +                               virDomainDiskDeviceTypeToString(newdisk->device),
> +                               newdisk->dst);
> +            return -1;
> +        }
> +    }
> +
> +    if (!devname) {
> +        qemudReportError(dom->conn, NULL, NULL, VIR_ERR_NO_MEMORY, NULL);

You don't want to call qemudReportError here, because qemudDiskDeviceName()
will already have raised an error. You need to push this particular error
raise up into the 'else { ... }'  clause above.

> +        return -1;
> +    }
>  
>      if (newdisk->src) {
>          safe_path = qemudEscapeMonitorArg(newdisk->src);
>          if (!safe_path) {
>              qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
>                               "%s", _("out of memory"));
> +            VIR_FREE(devname);
>              return -1;
>          }
> -        if (asprintf (&cmd, "change %s \"%s\"",
> -                      /* XXX qemu may support multiple CDROM in future */
> -                      /* olddisk->dst */ "cdrom",
> -                      safe_path) == -1) {
> +        if (asprintf (&cmd, "change %s \"%s\"", devname, safe_path) == -1) {
>              qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
>                               "%s", _("out of memory"));

I know this was here already, but we should change it to the OOM error code

              qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_MEMORY...

>              VIR_FREE(safe_path);
> +            VIR_FREE(devname);
>              return -1;
>          }
>          VIR_FREE(safe_path);
>  
> -    } else if (asprintf(&cmd, "eject cdrom") == -1) {
> +    } else if (asprintf(&cmd, "eject %s", devname) == -1) {
>          qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
>                           "%s", _("out of memory"));

Likewise here..

> +        VIR_FREE(devname);
>          return -1;
>      }
> +    VIR_FREE(devname);
>  
>      if (qemudMonitorCommand(driver, vm, cmd, &reply) < 0) {
>          qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
> @@ -2984,7 +3082,7 @@ static int qemudDomainChangeCDROM(virDomainPtr dom,


> @@ -3186,10 +3251,11 @@ static int qemudDomainAttachDevice(virDomainPtr dom,
>      }
>  
>      if (dev->type == VIR_DOMAIN_DEVICE_DISK &&
> -        dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
> -                ret = qemudDomainAttachCdromDevice(dom, dev);
> +        (dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM ||
> +         dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY)) {
> +                ret = qemudDomainChangeEjectableMedia(dom, dev);
>      } else if (dev->type == VIR_DOMAIN_DEVICE_DISK &&
> -        dev->data.disk->device == VIR_DOMAIN_DEVICE_DISK &&
> +        dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_DISK &&

OOpps, nice catch for that typo !

>          dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_USB) {
>                  ret = qemudDomainAttachUsbMassstorageDevice(dom, dev);
>      } else if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV &&

Daniel
-- 
|: Red Hat, Engineering, London   -o-   http://people.redhat.com/berrange/ :|
|: http://libvirt.org  -o-  http://virt-manager.org  -o-  http://ovirt.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505  -o-  F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|




More information about the libvir-list mailing list