Skip to content

Commit 810cd4b

Browse files
committed
vfio/pci: Lock external INTx masking ops
Mask operations through config space changes to DisINTx may race INTx configuration changes via ioctl. Create wrappers that add locking for paths outside of the core interrupt code. In particular, irq_type is updated holding igate, therefore testing is_intx() requires holding igate. For example clearing DisINTx from config space can otherwise race changes of the interrupt configuration. This aligns interfaces which may trigger the INTx eventfd into two camps, one side serialized by igate and the other only enabled while INTx is configured. A subsequent patch introduces synchronization for the latter flows. Cc: <stable@vger.kernel.org> Fixes: 89e1f7d ("vfio: Add PCI device driver") Reported-by: Reinette Chatre <reinette.chatre@intel.com> Reviewed-by: Kevin Tian <kevin.tian@intel.com> Reviewed-by: Reinette Chatre <reinette.chatre@intel.com> Reviewed-by: Eric Auger <eric.auger@redhat.com> Link: https://lore.kernel.org/r/20240308230557.805580-3-alex.williamson@redhat.com Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
1 parent fe9a708 commit 810cd4b

File tree

1 file changed

+28
-6
lines changed

1 file changed

+28
-6
lines changed

drivers/vfio/pci/vfio_pci_intrs.c

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -99,13 +99,15 @@ static void vfio_send_intx_eventfd(void *opaque, void *unused)
9999
}
100100

101101
/* Returns true if the INTx vfio_pci_irq_ctx.masked value is changed. */
102-
bool vfio_pci_intx_mask(struct vfio_pci_core_device *vdev)
102+
static bool __vfio_pci_intx_mask(struct vfio_pci_core_device *vdev)
103103
{
104104
struct pci_dev *pdev = vdev->pdev;
105105
struct vfio_pci_irq_ctx *ctx;
106106
unsigned long flags;
107107
bool masked_changed = false;
108108

109+
lockdep_assert_held(&vdev->igate);
110+
109111
spin_lock_irqsave(&vdev->irqlock, flags);
110112

111113
/*
@@ -143,6 +145,17 @@ bool vfio_pci_intx_mask(struct vfio_pci_core_device *vdev)
143145
return masked_changed;
144146
}
145147

148+
bool vfio_pci_intx_mask(struct vfio_pci_core_device *vdev)
149+
{
150+
bool mask_changed;
151+
152+
mutex_lock(&vdev->igate);
153+
mask_changed = __vfio_pci_intx_mask(vdev);
154+
mutex_unlock(&vdev->igate);
155+
156+
return mask_changed;
157+
}
158+
146159
/*
147160
* If this is triggered by an eventfd, we can't call eventfd_signal
148161
* or else we'll deadlock on the eventfd wait queue. Return >0 when
@@ -194,12 +207,21 @@ static int vfio_pci_intx_unmask_handler(void *opaque, void *unused)
194207
return ret;
195208
}
196209

197-
void vfio_pci_intx_unmask(struct vfio_pci_core_device *vdev)
210+
static void __vfio_pci_intx_unmask(struct vfio_pci_core_device *vdev)
198211
{
212+
lockdep_assert_held(&vdev->igate);
213+
199214
if (vfio_pci_intx_unmask_handler(vdev, NULL) > 0)
200215
vfio_send_intx_eventfd(vdev, NULL);
201216
}
202217

218+
void vfio_pci_intx_unmask(struct vfio_pci_core_device *vdev)
219+
{
220+
mutex_lock(&vdev->igate);
221+
__vfio_pci_intx_unmask(vdev);
222+
mutex_unlock(&vdev->igate);
223+
}
224+
203225
static irqreturn_t vfio_intx_handler(int irq, void *dev_id)
204226
{
205227
struct vfio_pci_core_device *vdev = dev_id;
@@ -563,11 +585,11 @@ static int vfio_pci_set_intx_unmask(struct vfio_pci_core_device *vdev,
563585
return -EINVAL;
564586

565587
if (flags & VFIO_IRQ_SET_DATA_NONE) {
566-
vfio_pci_intx_unmask(vdev);
588+
__vfio_pci_intx_unmask(vdev);
567589
} else if (flags & VFIO_IRQ_SET_DATA_BOOL) {
568590
uint8_t unmask = *(uint8_t *)data;
569591
if (unmask)
570-
vfio_pci_intx_unmask(vdev);
592+
__vfio_pci_intx_unmask(vdev);
571593
} else if (flags & VFIO_IRQ_SET_DATA_EVENTFD) {
572594
struct vfio_pci_irq_ctx *ctx = vfio_irq_ctx_get(vdev, 0);
573595
int32_t fd = *(int32_t *)data;
@@ -594,11 +616,11 @@ static int vfio_pci_set_intx_mask(struct vfio_pci_core_device *vdev,
594616
return -EINVAL;
595617

596618
if (flags & VFIO_IRQ_SET_DATA_NONE) {
597-
vfio_pci_intx_mask(vdev);
619+
__vfio_pci_intx_mask(vdev);
598620
} else if (flags & VFIO_IRQ_SET_DATA_BOOL) {
599621
uint8_t mask = *(uint8_t *)data;
600622
if (mask)
601-
vfio_pci_intx_mask(vdev);
623+
__vfio_pci_intx_mask(vdev);
602624
} else if (flags & VFIO_IRQ_SET_DATA_EVENTFD) {
603625
return -ENOTTY; /* XXX implement me */
604626
}

0 commit comments

Comments
 (0)