The current code for using -drive simply sets the -drive 'index'
parameter. QEMU internally converts this to bus/unit depending
on the type of drive. This does not give us precise control over
the bus/unit assignment though. This change switches over to make
libvirt explicitly calculate the bus/unit number.
In addition bus/unit/index are actually irrelevant for VirtIO
disks, since each virtio disk is a separate PCI device. No disk
controller is involved.
Doing the conversion to bus/unit in libvirt allows us to correctly
attach SCSI controllers when required.
* src/qemu/qemu_conf.c: Specify bus/unit instead of index for
disks
---
src/qemu/qemu_conf.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 79 insertions(+), 1 deletions(-)
diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
index 27faa3f..f4fbe96 100644
--- a/src/qemu/qemu_conf.c
+++ b/src/qemu/qemu_conf.c
@@ -1342,6 +1342,7 @@ qemuBuildDriveStr(virConnectPtr conn,
const char *bus = virDomainDiskQEMUBusTypeToString(disk->bus);
int idx = virDiskNameToIndex(disk->dst);
char *optstr = NULL;
+ int controllerid = -1, busid = -1, unitid = -1;
if (idx < 0) {
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
@@ -1349,6 +1350,80 @@ qemuBuildDriveStr(virConnectPtr conn,
goto error;
}
+ switch (disk->bus) {
+ case VIR_DOMAIN_DISK_BUS_SCSI:
+ case VIR_DOMAIN_DISK_BUS_IDE:
+ case VIR_DOMAIN_DISK_BUS_FDC:
+ if (disk->addr.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE &&
+ disk->addr.mode == VIR_DOMAIN_DEVICE_ADDRESS_MODE_STATIC) {
+ /* The user specified an explicit address, so ignore dev name */
+ controllerid = disk->addr.data.drive.controller;
+ busid = disk->addr.data.drive.bus;
+ unitid = disk->addr.data.drive.unit;
+ } else if (disk->addr.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE ||
+ disk->addr.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE) {
+ /*
+ * We auto-assign contoller/bus/unit based on the drive
+ * index, which was in turn based on dev name eg "sda"
+ */
+ if (disk->bus == VIR_DOMAIN_DISK_BUS_SCSI) {
+ /* Many SCSI controllers, only 1 bus, each with 7 units */
+ controllerid = idx / 7;
+ busid = 0;
+ unitid = idx % 7;
+ } else if (disk->bus == VIR_DOMAIN_DISK_BUS_IDE) {
+ /* One IDE controller, with 2 buses, each 2 units */
+ controllerid = 0;
+ busid = idx / 2;
+ unitid = idx % 2;
+ } else {
+ controllerid = 0;
+ busid = 0;
+ unitid = idx;
+ }
+
+ disk->addr.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE;
+ disk->addr.mode = VIR_DOMAIN_DEVICE_ADDRESS_MODE_DYNAMIC;
+ disk->addr.data.drive.controller = controllerid;
+ disk->addr.data.drive.bus = busid;
+ disk->addr.data.drive.unit = unitid;
+ } else {
+ qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "%s",
+ _("unexpected address type for ide/scsi/fdc
disk"));
+ goto error;
+ }
+ break;
+
+ case VIR_DOMAIN_DISK_BUS_VIRTIO:
+ /* Each virtio drive is a separate PCI device, no unit/busid */
+ break;
+
+ case VIR_DOMAIN_DISK_BUS_XEN:
+ /* Xen has no address type currently, so assign based on index */
+ unitid = idx;
+ break;
+ }
+
+ if (disk->bus == VIR_DOMAIN_DISK_BUS_SCSI) {
+ if (busid != 0) {
+ qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+ _("SCSI controller only supports 1 bus"));
+ goto error;
+ }
+ /* Setting bus= attr for SCSI drives, causes a controller
+ * to be created. Yes this is slightly odd. It is not possible
+ * to have > 1 bus on a SCSI controller (yet). */
+ busid = controllerid;
+ } else if (disk->bus == VIR_DOMAIN_DISK_BUS_IDE ||
+ disk->bus == VIR_DOMAIN_DISK_BUS_FDC) {
+ /* We can only have 1 IDE / Floppy controller (currently) */
+ if (controllerid != 0) {
+ qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+ _("Only 1 %s controller is supported"), bus);
+ goto error;
+ }
+ }
+
if (disk->src) {
if (disk->type == VIR_DOMAIN_DISK_TYPE_DIR) {
/* QEMU only supports magic FAT format for now */
@@ -1375,7 +1450,10 @@ qemuBuildDriveStr(virConnectPtr conn,
virBufferVSprintf(&opt, "if=%s", bus);
if (disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM)
virBufferAddLit(&opt, ",media=cdrom");
- virBufferVSprintf(&opt, ",index=%d", idx);
+ if (busid != -1)
+ virBufferVSprintf(&opt, ",bus=%d", busid);
+ if (unitid != -1)
+ virBufferVSprintf(&opt, ",unit=%d", unitid);
if (bootable &&
disk->device == VIR_DOMAIN_DISK_DEVICE_DISK)
virBufferAddLit(&opt, ",boot=on");
--
1.6.5.2