From: Ian Jackson Date: Fri, 1 Aug 2008 16:15:24 +0000 (+0100) Subject: Fix medium change device lookup. X-Git-Tag: xen-3.3.0-rc3~5 X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=a6425a1734615e60371dd8ea92107f53f1e8df63;p=qemu-xen-4.0-testing.git Fix medium change device lookup. Previously, medium change notifications would be handled with respect to the wrong emulated disk drive. This would make many configurations (particularly ones with CDs and many hard disks) break. (A medium change notification occurs at the start for every removeable device.) Thanks to Haicheng Li at Intel for the report, http://bugzilla.xensource.com/bugzilla/show_bug.cgi?id=1314 --- diff --git a/xenstore.c b/xenstore.c index 6c9d4b55..c0fe95a5 100644 --- a/xenstore.c +++ b/xenstore.c @@ -92,6 +92,59 @@ static void waitForDevice(char *fn) return; } +static int any_hdN; + +static int parse_drive_name(const char *dev, DriveInfo *out) { + /* alway sleaves out->bdrv unchanged */ + /* on success, returns 0 and fills in out->type, ->bus, ->unit */ + /* if drive name not understood, returns -1 and *out may be garbage */ + int ch, max, per_bus; + + /* Change xvdN to look like hdN */ + if (!any_hdN && !strncmp(dev, "xvd", 3) && strlen(dev) == 4) { + ch = dev[3]; + fprintf(logfile, "Using %s for guest's hd%c\n", dev, ch); + out->type = IF_IDE; + } else if (!strncmp(dev, "hd", 2) && strlen(dev) == 3) { + ch = dev[2]; + out->type = IF_IDE; + } else if (!strncmp(dev, "sd", 2) && strlen(dev) == 3) { + ch = dev[2]; + out->type = IF_SCSI; + } else { + fprintf(stderr, "qemu: ignoring not-understood drive `%s'\n", dev); + return -1; + } + + if (out->type == IF_SCSI) { + max = MAX_SCSI_DEVS; + per_bus = max; + } else { + max = 4; + per_bus = 2; + } + + ch = ch - 'a'; + if (ch >= max) { + fprintf(stderr, "qemu: drive `%s' out of range\n", dev); + return -1; + } + + out->bus = ch / per_bus; + out->unit = ch % per_bus; + + return 0; +} + +static int drive_name_to_index(const char *name) { + DriveInfo tmp; + int ret; + + ret = parse_drive_name(name, &tmp); if (ret) return -1; + ret = drive_get_index(tmp.type, tmp.bus, tmp.unit); + return ret; +} + #define DIRECT_PCI_STR_LEN 160 char direct_pci_str[DIRECT_PCI_STR_LEN]; void xenstore_parse_domain_config(int hvm_domid) @@ -100,7 +153,7 @@ void xenstore_parse_domain_config(int hvm_domid) char *buf = NULL, *path; char *fpath = NULL, *bpath = NULL, *dev = NULL, *params = NULL, *type = NULL, *drv = NULL; - int i, is_scsi, is_hdN = 0; + int i, any_hdN = 0, ret; unsigned int len, num, hd_index, pci_devid = 0; BlockDriverState *bs; BlockDriver *format; @@ -143,7 +196,7 @@ void xenstore_parse_domain_config(int hvm_domid) if (dev == NULL) continue; if (!strncmp(dev, "hd", 2)) { - is_hdN = 1; + any_hdN = 1; break; } } @@ -165,26 +218,13 @@ void xenstore_parse_domain_config(int hvm_domid) dev = xs_read(xsh, XBT_NULL, buf, &len); if (dev == NULL) continue; - /* Change xvdN to look like hdN */ - if (!is_hdN && !strncmp(dev, "xvd", 3)) { - fprintf(logfile, "Change xvd%c to look like hd%c\n", - dev[3], dev[3]); - memmove(dev, dev+1, strlen(dev)); - dev[0] = 'h'; - dev[1] = 'd'; - } - is_scsi = !strncmp(dev, "sd", 2); - if ((strncmp(dev, "hd", 2) && !is_scsi) || strlen(dev) != 3 ) - continue; - hd_index = dev[2] - 'a'; if (nb_drives >= MAX_DRIVES) { - fprintf(stderr, "qemu: too many drives\n"); + fprintf(stderr, "qemu: too many drives, skipping `%s'\n", dev); continue; } - if (hd_index >= (is_scsi ? MAX_SCSI_DEVS : 4)) { - fprintf(stderr, "qemu: drives %s out of range\n", dev); + ret = parse_drive_name(dev, &drives_table[nb_drives]); + if (ret) continue; - } /* read the type of the device */ if (pasprintf(&buf, "%s/device/vbd/%s/device-type", path, e[i]) == -1) continue; @@ -294,16 +334,6 @@ void xenstore_parse_domain_config(int hvm_domid) fprintf(stderr, "qemu: could not open vbd '%s' or hard disk image '%s' (drv '%s' format '%s')\n", buf, params, drv ? drv : "?", format ? format->format_name : "0"); } - assert(nb_drives"); + if (image == NULL) goto out; /* gone */