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 :|