]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob
11a2a5d05d703814bd8439bb8e138a0ba5864ced
[thirdparty/kernel/stable-queue.git] /
1 From ef3bbb2d3a2ef48c5d4280b619a63bf796d613f7 Mon Sep 17 00:00:00 2001
2 From: Sasha Levin <sashal@kernel.org>
3 Date: Mon, 2 Nov 2020 15:02:00 -0700
4 Subject: vfio/pci: Implement ioeventfd thread handler for contended memory
5 lock
6
7 From: Alex Williamson <alex.williamson@redhat.com>
8
9 [ Upstream commit 38565c93c8a1306dc5f245572a545fbea908ac41 ]
10
11 The ioeventfd is called under spinlock with interrupts disabled,
12 therefore if the memory lock is contended defer code that might
13 sleep to a thread context.
14
15 Fixes: bc93b9ae0151 ("vfio-pci: Avoid recursive read-lock usage")
16 Link: https://bugzilla.kernel.org/show_bug.cgi?id=209253#c1
17 Reported-by: Ian Pilcher <arequipeno@gmail.com>
18 Tested-by: Ian Pilcher <arequipeno@gmail.com>
19 Tested-by: Justin Gatzen <justin.gatzen@gmail.com>
20 Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
21 Signed-off-by: Sasha Levin <sashal@kernel.org>
22 ---
23 drivers/vfio/pci/vfio_pci_rdwr.c | 43 ++++++++++++++++++++++++++------
24 1 file changed, 35 insertions(+), 8 deletions(-)
25
26 diff --git a/drivers/vfio/pci/vfio_pci_rdwr.c b/drivers/vfio/pci/vfio_pci_rdwr.c
27 index 9e353c484ace2..a0b5fc8e46f4d 100644
28 --- a/drivers/vfio/pci/vfio_pci_rdwr.c
29 +++ b/drivers/vfio/pci/vfio_pci_rdwr.c
30 @@ -356,34 +356,60 @@ ssize_t vfio_pci_vga_rw(struct vfio_pci_device *vdev, char __user *buf,
31 return done;
32 }
33
34 -static int vfio_pci_ioeventfd_handler(void *opaque, void *unused)
35 +static void vfio_pci_ioeventfd_do_write(struct vfio_pci_ioeventfd *ioeventfd,
36 + bool test_mem)
37 {
38 - struct vfio_pci_ioeventfd *ioeventfd = opaque;
39 -
40 switch (ioeventfd->count) {
41 case 1:
42 - vfio_pci_iowrite8(ioeventfd->vdev, ioeventfd->test_mem,
43 + vfio_pci_iowrite8(ioeventfd->vdev, test_mem,
44 ioeventfd->data, ioeventfd->addr);
45 break;
46 case 2:
47 - vfio_pci_iowrite16(ioeventfd->vdev, ioeventfd->test_mem,
48 + vfio_pci_iowrite16(ioeventfd->vdev, test_mem,
49 ioeventfd->data, ioeventfd->addr);
50 break;
51 case 4:
52 - vfio_pci_iowrite32(ioeventfd->vdev, ioeventfd->test_mem,
53 + vfio_pci_iowrite32(ioeventfd->vdev, test_mem,
54 ioeventfd->data, ioeventfd->addr);
55 break;
56 #ifdef iowrite64
57 case 8:
58 - vfio_pci_iowrite64(ioeventfd->vdev, ioeventfd->test_mem,
59 + vfio_pci_iowrite64(ioeventfd->vdev, test_mem,
60 ioeventfd->data, ioeventfd->addr);
61 break;
62 #endif
63 }
64 +}
65 +
66 +static int vfio_pci_ioeventfd_handler(void *opaque, void *unused)
67 +{
68 + struct vfio_pci_ioeventfd *ioeventfd = opaque;
69 + struct vfio_pci_device *vdev = ioeventfd->vdev;
70 +
71 + if (ioeventfd->test_mem) {
72 + if (!down_read_trylock(&vdev->memory_lock))
73 + return 1; /* Lock contended, use thread */
74 + if (!__vfio_pci_memory_enabled(vdev)) {
75 + up_read(&vdev->memory_lock);
76 + return 0;
77 + }
78 + }
79 +
80 + vfio_pci_ioeventfd_do_write(ioeventfd, false);
81 +
82 + if (ioeventfd->test_mem)
83 + up_read(&vdev->memory_lock);
84
85 return 0;
86 }
87
88 +static void vfio_pci_ioeventfd_thread(void *opaque, void *unused)
89 +{
90 + struct vfio_pci_ioeventfd *ioeventfd = opaque;
91 +
92 + vfio_pci_ioeventfd_do_write(ioeventfd, ioeventfd->test_mem);
93 +}
94 +
95 long vfio_pci_ioeventfd(struct vfio_pci_device *vdev, loff_t offset,
96 uint64_t data, int count, int fd)
97 {
98 @@ -457,7 +483,8 @@ long vfio_pci_ioeventfd(struct vfio_pci_device *vdev, loff_t offset,
99 ioeventfd->test_mem = vdev->pdev->resource[bar].flags & IORESOURCE_MEM;
100
101 ret = vfio_virqfd_enable(ioeventfd, vfio_pci_ioeventfd_handler,
102 - NULL, NULL, &ioeventfd->virqfd, fd);
103 + vfio_pci_ioeventfd_thread, NULL,
104 + &ioeventfd->virqfd, fd);
105 if (ret) {
106 kfree(ioeventfd);
107 goto out_unlock;
108 --
109 2.27.0
110