Skip to content

Commit

Permalink
vfio/ccw/pci: Allow devices to opt-in for ballooning
Browse files Browse the repository at this point in the history
If a vfio assigned device makes use of a physical IOMMU, then memory
ballooning is necessarily inhibited due to the page pinning, lack of
page level granularity at the IOMMU, and sufficient notifiers to both
remove the page on balloon inflation and add it back on deflation.
However, not all devices are backed by a physical IOMMU.  In the case
of mediated devices, if a vendor driver is well synchronized with the
guest driver, such that only pages actively used by the guest driver
are pinned by the host mdev vendor driver, then there should be no
overlap between pages available for the balloon driver and pages
actively in use by the device.  Under these conditions, ballooning
should be safe.

vfio-ccw devices are always mediated devices and always operate under
the constraints above.  Therefore we can consider all vfio-ccw devices
as balloon compatible.

The situation is far from straightforward with vfio-pci.  These
devices can be physical devices with physical IOMMU backing or
mediated devices where it is unknown whether a physical IOMMU is in
use or whether the vendor driver is well synchronized to the working
set of the guest driver.  The safest approach is therefore to assume
all vfio-pci devices are incompatible with ballooning, but allow user
opt-in should they have further insight into mediated devices.

Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
  • Loading branch information
awilliam committed Aug 17, 2018
1 parent c65ee43 commit 238e917
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 2 deletions.
9 changes: 9 additions & 0 deletions hw/vfio/ccw.c
Expand Up @@ -349,6 +349,15 @@ static void vfio_ccw_get_device(VFIOGroup *group, VFIOCCWDevice *vcdev,
}
}

/*
* All vfio-ccw devices are believed to operate in a way compatible with
* memory ballooning, ie. pages pinned in the host are in the current
* working set of the guest driver and therefore never overlap with pages
* available to the guest balloon driver. This needs to be set before
* vfio_get_device() for vfio common to handle the balloon inhibitor.
*/
vcdev->vdev.balloon_allowed = true;

if (vfio_get_device(group, vcdev->cdev.mdevid, &vcdev->vdev, errp)) {
goto out_err;
}
Expand Down
23 changes: 22 additions & 1 deletion hw/vfio/common.c
Expand Up @@ -1381,7 +1381,9 @@ void vfio_put_group(VFIOGroup *group)
return;
}

qemu_balloon_inhibit(false);
if (!group->balloon_allowed) {
qemu_balloon_inhibit(false);
}
vfio_kvm_device_del_group(group);
vfio_disconnect_container(group);
QLIST_REMOVE(group, next);
Expand Down Expand Up @@ -1417,6 +1419,25 @@ int vfio_get_device(VFIOGroup *group, const char *name,
return ret;
}

/*
* Clear the balloon inhibitor for this group if the driver knows the
* device operates compatibly with ballooning. Setting must be consistent
* per group, but since compatibility is really only possible with mdev
* currently, we expect singleton groups.
*/
if (vbasedev->balloon_allowed != group->balloon_allowed) {
if (!QLIST_EMPTY(&group->device_list)) {
error_setg(errp,
"Inconsistent device balloon setting within group");
return -1;
}

if (!group->balloon_allowed) {
group->balloon_allowed = true;
qemu_balloon_inhibit(false);
}
}

vbasedev->fd = fd;
vbasedev->group = group;
QLIST_INSERT_HEAD(&group->device_list, vbasedev, next);
Expand Down
26 changes: 25 additions & 1 deletion hw/vfio/pci.c
Expand Up @@ -2804,12 +2804,13 @@ static void vfio_realize(PCIDevice *pdev, Error **errp)
VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev);
VFIODevice *vbasedev_iter;
VFIOGroup *group;
char *tmp, group_path[PATH_MAX], *group_name;
char *tmp, *subsys, group_path[PATH_MAX], *group_name;
Error *err = NULL;
ssize_t len;
struct stat st;
int groupid;
int i, ret;
bool is_mdev;

if (!vdev->vbasedev.sysfsdev) {
if (!(~vdev->host.domain || ~vdev->host.bus ||
Expand Down Expand Up @@ -2869,6 +2870,27 @@ static void vfio_realize(PCIDevice *pdev, Error **errp)
}
}

/*
* Mediated devices *might* operate compatibly with memory ballooning, but
* we cannot know for certain, it depends on whether the mdev vendor driver
* stays in sync with the active working set of the guest driver. Prevent
* the x-balloon-allowed option unless this is minimally an mdev device.
*/
tmp = g_strdup_printf("%s/subsystem", vdev->vbasedev.sysfsdev);
subsys = realpath(tmp, NULL);
g_free(tmp);
is_mdev = (strcmp(subsys, "/sys/bus/mdev") == 0);
free(subsys);

trace_vfio_mdev(vdev->vbasedev.name, is_mdev);

if (vdev->vbasedev.balloon_allowed && !is_mdev) {
error_setg(errp, "x-balloon-allowed only potentially compatible "
"with mdev devices");
vfio_put_group(group);
goto error;
}

ret = vfio_get_device(group, vdev->vbasedev.name, &vdev->vbasedev, errp);
if (ret) {
vfio_put_group(group);
Expand Down Expand Up @@ -3170,6 +3192,8 @@ static Property vfio_pci_dev_properties[] = {
DEFINE_PROP_BIT("x-igd-opregion", VFIOPCIDevice, features,
VFIO_FEATURE_ENABLE_IGD_OPREGION_BIT, false),
DEFINE_PROP_BOOL("x-no-mmap", VFIOPCIDevice, vbasedev.no_mmap, false),
DEFINE_PROP_BOOL("x-balloon-allowed", VFIOPCIDevice,
vbasedev.balloon_allowed, false),
DEFINE_PROP_BOOL("x-no-kvm-intx", VFIOPCIDevice, no_kvm_intx, false),
DEFINE_PROP_BOOL("x-no-kvm-msi", VFIOPCIDevice, no_kvm_msi, false),
DEFINE_PROP_BOOL("x-no-kvm-msix", VFIOPCIDevice, no_kvm_msix, false),
Expand Down
1 change: 1 addition & 0 deletions hw/vfio/trace-events
Expand Up @@ -39,6 +39,7 @@ vfio_pci_hot_reset_result(const char *name, const char *result) "%s hot reset: %
vfio_populate_device_config(const char *name, unsigned long size, unsigned long offset, unsigned long flags) "Device %s config:\n size: 0x%lx, offset: 0x%lx, flags: 0x%lx"
vfio_populate_device_get_irq_info_failure(void) "VFIO_DEVICE_GET_IRQ_INFO failure: %m"
vfio_realize(const char *name, int group_id) " (%s) group %d"
vfio_mdev(const char *name, bool is_mdev) " (%s) is_mdev %d"
vfio_add_ext_cap_dropped(const char *name, uint16_t cap, uint16_t offset) "%s 0x%x@0x%x"
vfio_pci_reset(const char *name) " (%s)"
vfio_pci_reset_flr(const char *name) "%s FLR/VFIO_DEVICE_RESET"
Expand Down
2 changes: 2 additions & 0 deletions include/hw/vfio/vfio-common.h
Expand Up @@ -112,6 +112,7 @@ typedef struct VFIODevice {
bool reset_works;
bool needs_reset;
bool no_mmap;
bool balloon_allowed;
VFIODeviceOps *ops;
unsigned int num_irqs;
unsigned int num_regions;
Expand All @@ -131,6 +132,7 @@ typedef struct VFIOGroup {
QLIST_HEAD(, VFIODevice) device_list;
QLIST_ENTRY(VFIOGroup) next;
QLIST_ENTRY(VFIOGroup) container_next;
bool balloon_allowed;
} VFIOGroup;

typedef struct VFIODMABuf {
Expand Down

0 comments on commit 238e917

Please sign in to comment.