1 From stable+bounces-35128-greg=kroah.com@vger.kernel.org Mon Apr 1 18:54:07 2024
2 From: Alex Williamson <alex.williamson@redhat.com>
3 Date: Mon, 1 Apr 2024 10:52:59 -0600
4 Subject: vfio/platform: Create persistent IRQ handlers
5 To: stable@vger.kernel.org
6 Cc: Alex Williamson <alex.williamson@redhat.com>, sashal@kernel.org, gregkh@linuxfoundation.org, eric.auger@redhat.com, Kevin Tian <kevin.tian@intel.com>
7 Message-ID: <20240401165302.3699643-6-alex.williamson@redhat.com>
9 From: Alex Williamson <alex.williamson@redhat.com>
11 [ Upstream commit 675daf435e9f8e5a5eab140a9864dfad6668b375 ]
13 The vfio-platform SET_IRQS ioctl currently allows loopback triggering of
14 an interrupt before a signaling eventfd has been configured by the user,
15 which thereby allows a NULL pointer dereference.
17 Rather than register the IRQ relative to a valid trigger, register all
18 IRQs in a disabled state in the device open path. This allows mask
19 operations on the IRQ to nest within the overall enable state governed
20 by a valid eventfd signal. This decouples @masked, protected by the
21 @locked spinlock from @trigger, protected via the @igate mutex.
23 In doing so, it's guaranteed that changes to @trigger cannot race the
24 IRQ handlers because the IRQ handler is synchronously disabled before
25 modifying the trigger, and loopback triggering of the IRQ via ioctl is
26 safe due to serialization with trigger changes via igate.
28 For compatibility, request_irq() failures are maintained to be local to
29 the SET_IRQS ioctl rather than a fatal error in the open device path.
30 This allows, for example, a userspace driver with polling mode support
31 to continue to work regardless of moving the request_irq() call site.
32 This necessarily blocks all SET_IRQS access to the failed index.
34 Cc: Eric Auger <eric.auger@redhat.com>
35 Cc: <stable@vger.kernel.org>
36 Fixes: 57f972e2b341 ("vfio/platform: trigger an interrupt via eventfd")
37 Reviewed-by: Kevin Tian <kevin.tian@intel.com>
38 Reviewed-by: Eric Auger <eric.auger@redhat.com>
39 Link: https://lore.kernel.org/r/20240308230557.805580-7-alex.williamson@redhat.com
40 Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
41 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
43 drivers/vfio/platform/vfio_platform_irq.c | 101 ++++++++++++++++++++----------
44 1 file changed, 68 insertions(+), 33 deletions(-)
46 --- a/drivers/vfio/platform/vfio_platform_irq.c
47 +++ b/drivers/vfio/platform/vfio_platform_irq.c
48 @@ -136,6 +136,16 @@ static int vfio_platform_set_irq_unmask(
53 + * The trigger eventfd is guaranteed valid in the interrupt path
54 + * and protected by the igate mutex when triggered via ioctl.
56 +static void vfio_send_eventfd(struct vfio_platform_irq *irq_ctx)
58 + if (likely(irq_ctx->trigger))
59 + eventfd_signal(irq_ctx->trigger, 1);
62 static irqreturn_t vfio_automasked_irq_handler(int irq, void *dev_id)
64 struct vfio_platform_irq *irq_ctx = dev_id;
65 @@ -155,7 +165,7 @@ static irqreturn_t vfio_automasked_irq_h
66 spin_unlock_irqrestore(&irq_ctx->lock, flags);
68 if (ret == IRQ_HANDLED)
69 - eventfd_signal(irq_ctx->trigger, 1);
70 + vfio_send_eventfd(irq_ctx);
74 @@ -164,22 +174,19 @@ static irqreturn_t vfio_irq_handler(int
76 struct vfio_platform_irq *irq_ctx = dev_id;
78 - eventfd_signal(irq_ctx->trigger, 1);
79 + vfio_send_eventfd(irq_ctx);
84 static int vfio_set_trigger(struct vfio_platform_device *vdev, int index,
85 - int fd, irq_handler_t handler)
88 struct vfio_platform_irq *irq = &vdev->irqs[index];
89 struct eventfd_ctx *trigger;
93 - irq_clear_status_flags(irq->hwirq, IRQ_NOAUTOEN);
94 - free_irq(irq->hwirq, irq);
96 + disable_irq(irq->hwirq);
97 eventfd_ctx_put(irq->trigger);
100 @@ -187,30 +194,20 @@ static int vfio_set_trigger(struct vfio_
101 if (fd < 0) /* Disable only */
104 - irq->name = kasprintf(GFP_KERNEL, "vfio-irq[%d](%s)",
105 - irq->hwirq, vdev->name);
109 trigger = eventfd_ctx_fdget(fd);
110 - if (IS_ERR(trigger)) {
112 + if (IS_ERR(trigger))
113 return PTR_ERR(trigger);
116 irq->trigger = trigger;
118 - irq_set_status_flags(irq->hwirq, IRQ_NOAUTOEN);
119 - ret = request_irq(irq->hwirq, handler, 0, irq->name, irq);
122 - eventfd_ctx_put(trigger);
123 - irq->trigger = NULL;
128 - enable_irq(irq->hwirq);
130 + * irq->masked effectively provides nested disables within the overall
131 + * enable relative to trigger. Specifically request_irq() is called
132 + * with NO_AUTOEN, therefore the IRQ is initially disabled. The user
133 + * may only further disable the IRQ with a MASK operations because
134 + * irq->masked is initially false.
136 + enable_irq(irq->hwirq);
140 @@ -229,7 +226,7 @@ static int vfio_platform_set_irq_trigger
141 handler = vfio_irq_handler;
143 if (!count && (flags & VFIO_IRQ_SET_DATA_NONE))
144 - return vfio_set_trigger(vdev, index, -1, handler);
145 + return vfio_set_trigger(vdev, index, -1);
147 if (start != 0 || count != 1)
149 @@ -237,7 +234,7 @@ static int vfio_platform_set_irq_trigger
150 if (flags & VFIO_IRQ_SET_DATA_EVENTFD) {
151 int32_t fd = *(int32_t *)data;
153 - return vfio_set_trigger(vdev, index, fd, handler);
154 + return vfio_set_trigger(vdev, index, fd);
157 if (flags & VFIO_IRQ_SET_DATA_NONE) {
158 @@ -261,6 +258,14 @@ int vfio_platform_set_irqs_ioctl(struct
159 unsigned start, unsigned count, uint32_t flags,
163 + * For compatibility, errors from request_irq() are local to the
164 + * SET_IRQS path and reflected in the name pointer. This allows,
165 + * for example, polling mode fallback for an exclusive IRQ failure.
167 + if (IS_ERR(vdev->irqs[index].name))
168 + return PTR_ERR(vdev->irqs[index].name);
170 switch (flags & VFIO_IRQ_SET_ACTION_TYPE_MASK) {
171 case VFIO_IRQ_SET_ACTION_MASK:
172 func = vfio_platform_set_irq_mask;
173 @@ -281,7 +286,7 @@ int vfio_platform_set_irqs_ioctl(struct
175 int vfio_platform_irq_init(struct vfio_platform_device *vdev)
178 + int cnt = 0, i, ret = 0;
180 while (vdev->get_irq(vdev, cnt) >= 0)
182 @@ -292,29 +297,54 @@ int vfio_platform_irq_init(struct vfio_p
184 for (i = 0; i < cnt; i++) {
185 int hwirq = vdev->get_irq(vdev, i);
186 + irq_handler_t handler = vfio_irq_handler;
194 spin_lock_init(&vdev->irqs[i].lock);
196 vdev->irqs[i].flags = VFIO_IRQ_INFO_EVENTFD;
198 - if (irq_get_trigger_type(hwirq) & IRQ_TYPE_LEVEL_MASK)
199 + if (irq_get_trigger_type(hwirq) & IRQ_TYPE_LEVEL_MASK) {
200 vdev->irqs[i].flags |= VFIO_IRQ_INFO_MASKABLE
201 | VFIO_IRQ_INFO_AUTOMASKED;
202 + handler = vfio_automasked_irq_handler;
205 vdev->irqs[i].count = 1;
206 vdev->irqs[i].hwirq = hwirq;
207 vdev->irqs[i].masked = false;
208 + vdev->irqs[i].name = kasprintf(GFP_KERNEL,
209 + "vfio-irq[%d](%s)", hwirq,
211 + if (!vdev->irqs[i].name) {
216 + ret = request_irq(hwirq, handler, IRQF_NO_AUTOEN,
217 + vdev->irqs[i].name, &vdev->irqs[i]);
219 + kfree(vdev->irqs[i].name);
220 + vdev->irqs[i].name = ERR_PTR(ret);
224 vdev->num_irqs = cnt;
228 + for (--i; i >= 0; i--) {
229 + if (!IS_ERR(vdev->irqs[i].name)) {
230 + free_irq(vdev->irqs[i].hwirq, &vdev->irqs[i]);
231 + kfree(vdev->irqs[i].name);
239 void vfio_platform_irq_cleanup(struct vfio_platform_device *vdev)
240 @@ -324,7 +354,12 @@ void vfio_platform_irq_cleanup(struct vf
241 for (i = 0; i < vdev->num_irqs; i++) {
242 vfio_virqfd_disable(&vdev->irqs[i].mask);
243 vfio_virqfd_disable(&vdev->irqs[i].unmask);
244 - vfio_set_trigger(vdev, i, -1, NULL);
245 + if (!IS_ERR(vdev->irqs[i].name)) {
246 + free_irq(vdev->irqs[i].hwirq, &vdev->irqs[i]);
247 + if (vdev->irqs[i].trigger)
248 + eventfd_ctx_put(vdev->irqs[i].trigger);
249 + kfree(vdev->irqs[i].name);