drm/i915/gvt: Dereference msi eventfd_ctx when it isn't used anymore
authorXiong Zhang <xiong.y.zhang@intel.com>
Fri, 13 Apr 2018 02:26:16 +0000 (10:26 +0800)
committerZhenyu Wang <zhenyuw@linux.intel.com>
Mon, 16 Apr 2018 09:24:04 +0000 (17:24 +0800)
kvmgt get msi eventfd_ctx at qemu vfio set irq eventfd, then
msi eventfd_ctx should be put at some point.
The first point is kvmgt handle qemu vfio_disable_irqindex()
call which has DATA_NONE and ACTION_TRIGGER in flags.
If qemu doesn't call vfio_disable_irqindex(), the second point
is vgpu release function.

v2: Don't inject msi interrupt into guest if eventfd_ctx is dereferenced

Signed-off-by: Xiong Zhang <xiong.y.zhang@intel.com>
Reviewed-by: Zhenyu Wang <zhenyuw@linux.intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
drivers/gpu/drm/i915/gvt/kvmgt.c

index 021f722..a7487f4 100644 (file)
@@ -566,6 +566,17 @@ out:
        return ret;
 }
 
+static void intel_vgpu_release_msi_eventfd_ctx(struct intel_vgpu *vgpu)
+{
+       struct eventfd_ctx *trigger;
+
+       trigger = vgpu->vdev.msi_trigger;
+       if (trigger) {
+               eventfd_ctx_put(trigger);
+               vgpu->vdev.msi_trigger = NULL;
+       }
+}
+
 static void __intel_vgpu_release(struct intel_vgpu *vgpu)
 {
        struct kvmgt_guest_info *info;
@@ -590,6 +601,8 @@ static void __intel_vgpu_release(struct intel_vgpu *vgpu)
        info = (struct kvmgt_guest_info *)vgpu->handle;
        kvmgt_guest_exit(info);
 
+       intel_vgpu_release_msi_eventfd_ctx(vgpu);
+
        vgpu->vdev.kvm = NULL;
        vgpu->handle = 0;
 }
@@ -970,7 +983,8 @@ static int intel_vgpu_set_msi_trigger(struct intel_vgpu *vgpu,
                        return PTR_ERR(trigger);
                }
                vgpu->vdev.msi_trigger = trigger;
-       }
+       } else if ((flags & VFIO_IRQ_SET_DATA_NONE) && !count)
+               intel_vgpu_release_msi_eventfd_ctx(vgpu);
 
        return 0;
 }
@@ -1566,6 +1580,18 @@ static int kvmgt_inject_msi(unsigned long handle, u32 addr, u16 data)
        info = (struct kvmgt_guest_info *)handle;
        vgpu = info->vgpu;
 
+       /*
+        * When guest is poweroff, msi_trigger is set to NULL, but vgpu's
+        * config and mmio register isn't restored to default during guest
+        * poweroff. If this vgpu is still used in next vm, this vgpu's pipe
+        * may be enabled, then once this vgpu is active, it will get inject
+        * vblank interrupt request. But msi_trigger is null until msi is
+        * enabled by guest. so if msi_trigger is null, success is still
+        * returned and don't inject interrupt into guest.
+        */
+       if (vgpu->vdev.msi_trigger == NULL)
+               return 0;
+
        if (eventfd_signal(vgpu->vdev.msi_trigger, 1) == 1)
                return 0;