Przeglądaj źródła

drm/i915/gvt/kvmgt: prevent double-release of vgpu

The release action might be triggered from either user's closing
mdev or the detaching event of kvm and vfio_group, so this patch
introduces an atomic to prevent double-release.

Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
Jike Song 8 lat temu
rodzic
commit
364fb6b789

+ 1 - 0
drivers/gpu/drm/i915/gvt/gvt.h

@@ -175,6 +175,7 @@ struct intel_vgpu {
 		struct notifier_block group_notifier;
 		struct notifier_block group_notifier;
 		struct kvm *kvm;
 		struct kvm *kvm;
 		struct work_struct release_work;
 		struct work_struct release_work;
+		atomic_t released;
 	} vdev;
 	} vdev;
 #endif
 #endif
 };
 };

+ 21 - 3
drivers/gpu/drm/i915/gvt/kvmgt.c

@@ -500,7 +500,16 @@ static int intel_vgpu_open(struct mdev_device *mdev)
 		goto undo_iommu;
 		goto undo_iommu;
 	}
 	}
 
 
-	return kvmgt_guest_init(mdev);
+	ret = kvmgt_guest_init(mdev);
+	if (ret)
+		goto undo_group;
+
+	atomic_set(&vgpu->vdev.released, 0);
+	return ret;
+
+undo_group:
+	vfio_unregister_notifier(&mdev->dev, VFIO_GROUP_NOTIFY,
+					&vgpu->vdev.group_notifier);
 
 
 undo_iommu:
 undo_iommu:
 	vfio_unregister_notifier(&mdev->dev, VFIO_IOMMU_NOTIFY,
 	vfio_unregister_notifier(&mdev->dev, VFIO_IOMMU_NOTIFY,
@@ -512,17 +521,26 @@ out:
 static void __intel_vgpu_release(struct intel_vgpu *vgpu)
 static void __intel_vgpu_release(struct intel_vgpu *vgpu)
 {
 {
 	struct kvmgt_guest_info *info;
 	struct kvmgt_guest_info *info;
+	int ret;
 
 
 	if (!handle_valid(vgpu->handle))
 	if (!handle_valid(vgpu->handle))
 		return;
 		return;
 
 
-	vfio_unregister_notifier(&vgpu->vdev.mdev->dev, VFIO_IOMMU_NOTIFY,
+	if (atomic_cmpxchg(&vgpu->vdev.released, 0, 1))
+		return;
+
+	ret = vfio_unregister_notifier(&vgpu->vdev.mdev->dev, VFIO_IOMMU_NOTIFY,
 					&vgpu->vdev.iommu_notifier);
 					&vgpu->vdev.iommu_notifier);
-	vfio_unregister_notifier(&vgpu->vdev.mdev->dev, VFIO_GROUP_NOTIFY,
+	WARN(ret, "vfio_unregister_notifier for iommu failed: %d\n", ret);
+
+	ret = vfio_unregister_notifier(&vgpu->vdev.mdev->dev, VFIO_GROUP_NOTIFY,
 					&vgpu->vdev.group_notifier);
 					&vgpu->vdev.group_notifier);
+	WARN(ret, "vfio_unregister_notifier for group failed: %d\n", ret);
 
 
 	info = (struct kvmgt_guest_info *)vgpu->handle;
 	info = (struct kvmgt_guest_info *)vgpu->handle;
 	kvmgt_guest_exit(info);
 	kvmgt_guest_exit(info);
+
+	vgpu->vdev.kvm = NULL;
 	vgpu->handle = 0;
 	vgpu->handle = 0;
 }
 }