diff options
Diffstat (limited to 'qga/commands-posix.c')
| -rw-r--r-- | qga/commands-posix.c | 166 |
1 files changed, 118 insertions, 48 deletions
diff --git a/qga/commands-posix.c b/qga/commands-posix.c index 1a62a3a70d..af5a58a9fd 100644 --- a/qga/commands-posix.c +++ b/qga/commands-posix.c @@ -861,28 +861,26 @@ static int build_hosts(char const *syspath, char const *host, bool ata, return i; } -/* Store disk device info specified by @sysfs into @fs */ -static void build_guest_fsinfo_for_real_device(char const *syspath, - GuestFilesystemInfo *fs, - Error **errp) +/* + * Store disk device info for devices on the PCI bus. + * Returns true if information has been stored, or false for failure. + */ +static bool build_guest_fsinfo_for_pci_dev(char const *syspath, + GuestDiskAddress *disk, + Error **errp) { unsigned int pci[4], host, hosts[8], tgt[3]; int i, nhosts = 0, pcilen; - GuestDiskAddress *disk; - GuestPCIAddress *pciaddr; - GuestDiskAddressList *list = NULL; + GuestPCIAddress *pciaddr = disk->pci_controller; bool has_ata = false, has_host = false, has_tgt = false; char *p, *q, *driver = NULL; -#ifdef CONFIG_LIBUDEV - struct udev *udev = NULL; - struct udev_device *udevice = NULL; -#endif + bool ret = false; p = strstr(syspath, "/devices/pci"); if (!p || sscanf(p + 12, "%*x:%*x/%x:%x:%x.%x%n", pci, pci + 1, pci + 2, pci + 3, &pcilen) < 4) { g_debug("only pci device is supported: sysfs path '%s'", syspath); - return; + return false; } p += 12 + pcilen; @@ -903,7 +901,7 @@ static void build_guest_fsinfo_for_real_device(char const *syspath, } g_debug("unsupported driver or sysfs path '%s'", syspath); - return; + return false; } p = strstr(syspath, "/target"); @@ -929,38 +927,11 @@ static void build_guest_fsinfo_for_real_device(char const *syspath, } } - pciaddr = g_malloc0(sizeof(*pciaddr)); pciaddr->domain = pci[0]; pciaddr->bus = pci[1]; pciaddr->slot = pci[2]; pciaddr->function = pci[3]; - disk = g_malloc0(sizeof(*disk)); - disk->pci_controller = pciaddr; - - list = g_malloc0(sizeof(*list)); - list->value = disk; - -#ifdef CONFIG_LIBUDEV - udev = udev_new(); - udevice = udev_device_new_from_syspath(udev, syspath); - if (udev == NULL || udevice == NULL) { - g_debug("failed to query udev"); - } else { - const char *devnode, *serial; - devnode = udev_device_get_devnode(udevice); - if (devnode != NULL) { - disk->dev = g_strdup(devnode); - disk->has_dev = true; - } - serial = udev_device_get_property_value(udevice, "ID_SERIAL"); - if (serial != NULL && *serial != 0) { - disk->serial = g_strdup(serial); - disk->has_serial = true; - } - } -#endif - if (strcmp(driver, "ata_piix") == 0) { /* a host per ide bus, target*:0:<unit>:0 */ if (!has_host || !has_tgt) { @@ -1018,21 +989,111 @@ static void build_guest_fsinfo_for_real_device(char const *syspath, goto cleanup; } - list->next = fs->disk; - fs->disk = list; - goto out; + ret = true; cleanup: - if (list) { - qapi_free_GuestDiskAddressList(list); - } -out: g_free(driver); + return ret; +} + +/* + * Store disk device info for non-PCI virtio devices (for example s390x + * channel I/O devices). Returns true if information has been stored, or + * false for failure. + */ +static bool build_guest_fsinfo_for_nonpci_virtio(char const *syspath, + GuestDiskAddress *disk, + Error **errp) +{ + unsigned int tgt[3]; + char *p; + + if (!strstr(syspath, "/virtio") || !strstr(syspath, "/block")) { + g_debug("Unsupported virtio device '%s'", syspath); + return false; + } + + p = strstr(syspath, "/target"); + if (p && sscanf(p + 7, "%*u:%*u:%*u/%*u:%u:%u:%u", + &tgt[0], &tgt[1], &tgt[2]) == 3) { + /* virtio-scsi: target*:0:<target>:<unit> */ + disk->bus_type = GUEST_DISK_BUS_TYPE_SCSI; + disk->bus = tgt[0]; + disk->target = tgt[1]; + disk->unit = tgt[2]; + } else { + /* virtio-blk: 1 disk per 1 device */ + disk->bus_type = GUEST_DISK_BUS_TYPE_VIRTIO; + } + + return true; +} + +/* Store disk device info specified by @sysfs into @fs */ +static void build_guest_fsinfo_for_real_device(char const *syspath, + GuestFilesystemInfo *fs, + Error **errp) +{ + GuestDiskAddress *disk; + GuestPCIAddress *pciaddr; + GuestDiskAddressList *list = NULL; + bool has_hwinf; +#ifdef CONFIG_LIBUDEV + struct udev *udev = NULL; + struct udev_device *udevice = NULL; +#endif + + pciaddr = g_new0(GuestPCIAddress, 1); + pciaddr->domain = -1; /* -1 means field is invalid */ + pciaddr->bus = -1; + pciaddr->slot = -1; + pciaddr->function = -1; + + disk = g_new0(GuestDiskAddress, 1); + disk->pci_controller = pciaddr; + disk->bus_type = GUEST_DISK_BUS_TYPE_UNKNOWN; + + list = g_new0(GuestDiskAddressList, 1); + list->value = disk; + #ifdef CONFIG_LIBUDEV + udev = udev_new(); + udevice = udev_device_new_from_syspath(udev, syspath); + if (udev == NULL || udevice == NULL) { + g_debug("failed to query udev"); + } else { + const char *devnode, *serial; + devnode = udev_device_get_devnode(udevice); + if (devnode != NULL) { + disk->dev = g_strdup(devnode); + disk->has_dev = true; + } + serial = udev_device_get_property_value(udevice, "ID_SERIAL"); + if (serial != NULL && *serial != 0) { + disk->serial = g_strdup(serial); + disk->has_serial = true; + } + } + udev_unref(udev); udev_device_unref(udevice); #endif - return; + + if (strstr(syspath, "/devices/pci")) { + has_hwinf = build_guest_fsinfo_for_pci_dev(syspath, disk, errp); + } else if (strstr(syspath, "/virtio")) { + has_hwinf = build_guest_fsinfo_for_nonpci_virtio(syspath, disk, errp); + } else { + g_debug("Unsupported device type for '%s'", syspath); + has_hwinf = false; + } + + if (has_hwinf || disk->has_dev || disk->has_serial) { + list->next = fs->disk; + fs->disk = list; + } else { + qapi_free_GuestDiskAddressList(list); + } } static void build_guest_fsinfo_for_device(char const *devpath, @@ -2761,6 +2822,8 @@ GList *ga_command_blacklist_init(GList *blacklist) blacklist = g_list_append(blacklist, g_strdup("guest-fstrim")); #endif + blacklist = g_list_append(blacklist, g_strdup("guest-get-devices")); + return blacklist; } @@ -2981,3 +3044,10 @@ GuestOSInfo *qmp_guest_get_osinfo(Error **errp) return info; } + +GuestDeviceInfoList *qmp_guest_get_devices(Error **errp) +{ + error_setg(errp, QERR_UNSUPPORTED); + + return NULL; +} |