Skip to content

Commit a3d60ae

Browse files
efarmangregkh
authored andcommitted
s390/vfio_ccw: Implement a crw lock
commit 16b0798 upstream. Unlike the channel_program struct, which covers synchronous I/O submissions and asynchronous interrupts, the CRW region relies exclusively on asynchronous events coming from hardware. Implement a lock to manage the list of those payloads, to ensure they are read cohesively. Fixes: 3f02cb2 ("vfio-ccw: Wire up the CRW irq and CRW region") Cc: stable@vger.kernel.org Reviewed-by: Matthew Rosato <mjrosato@linux.ibm.com> Reviewed-by: Farhan Ali <alifm@linux.ibm.com> Signed-off-by: Eric Farman <farman@linux.ibm.com> Signed-off-by: Christian Borntraeger <borntraeger@linux.ibm.com> [farman@linux.ibm.com: resolved merge conflict] Signed-off-by: Eric Farman <farman@linux.ibm.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent f0d189d commit a3d60ae

4 files changed

Lines changed: 30 additions & 10 deletions

File tree

drivers/s390/cio/vfio_ccw_chp.c

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -93,18 +93,13 @@ static ssize_t vfio_ccw_crw_region_read(struct vfio_ccw_private *private,
9393
loff_t pos = *ppos & VFIO_CCW_OFFSET_MASK;
9494
struct ccw_crw_region *region;
9595
struct vfio_ccw_crw *crw;
96+
unsigned long flags;
9697
int ret;
9798

9899
if (pos + count > sizeof(*region))
99100
return -EINVAL;
100101

101102
mutex_lock(&private->io_mutex);
102-
crw = list_first_entry_or_null(&private->crw,
103-
struct vfio_ccw_crw, next);
104-
105-
if (crw)
106-
list_del(&crw->next);
107-
108103
if (i >= private->num_regions) {
109104
ret = -EINVAL;
110105
goto out;
@@ -113,6 +108,16 @@ static ssize_t vfio_ccw_crw_region_read(struct vfio_ccw_private *private,
113108
i = array_index_nospec(i, private->num_regions);
114109
region = private->region[i].data;
115110

111+
spin_lock_irqsave(&private->crw_lock, flags);
112+
crw = list_first_entry_or_null(&private->crw,
113+
struct vfio_ccw_crw, next);
114+
115+
if (crw)
116+
list_del(&crw->next);
117+
118+
/* Drop CRW lock while copying to userspace */
119+
spin_unlock_irqrestore(&private->crw_lock, flags);
120+
116121
if (crw)
117122
memcpy(&region->crw, &crw->crw, sizeof(region->crw));
118123

@@ -122,15 +127,16 @@ static ssize_t vfio_ccw_crw_region_read(struct vfio_ccw_private *private,
122127
ret = count;
123128

124129
region->crw = 0;
125-
126-
out:
127-
mutex_unlock(&private->io_mutex);
128-
129130
kfree(crw);
130131

131132
/* Notify the guest if more CRWs are on our queue */
133+
spin_lock_irqsave(&private->crw_lock, flags);
132134
if (!list_empty(&private->crw) && private->crw_trigger)
133135
eventfd_signal(private->crw_trigger, 1);
136+
spin_unlock_irqrestore(&private->crw_lock, flags);
137+
138+
out:
139+
mutex_unlock(&private->io_mutex);
134140

135141
return ret;
136142
}

drivers/s390/cio/vfio_ccw_drv.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,11 +118,14 @@ void vfio_ccw_sch_io_todo(struct work_struct *work)
118118
void vfio_ccw_crw_todo(struct work_struct *work)
119119
{
120120
struct vfio_ccw_private *private;
121+
unsigned long flags;
121122

122123
private = container_of(work, struct vfio_ccw_private, crw_work);
123124

125+
spin_lock_irqsave(&private->crw_lock, flags);
124126
if (!list_empty(&private->crw) && private->crw_trigger)
125127
eventfd_signal(private->crw_trigger, 1);
128+
spin_unlock_irqrestore(&private->crw_lock, flags);
126129
}
127130

128131
void vfio_ccw_notoper_todo(struct work_struct *work)
@@ -286,6 +289,7 @@ static void vfio_ccw_queue_crw(struct vfio_ccw_private *private,
286289
unsigned int rsid)
287290
{
288291
struct vfio_ccw_crw *crw;
292+
unsigned long flags;
289293

290294
/*
291295
* If unable to allocate a CRW, just drop the event and
@@ -303,7 +307,9 @@ static void vfio_ccw_queue_crw(struct vfio_ccw_private *private,
303307
crw->crw.erc = erc;
304308
crw->crw.rsid = rsid;
305309

310+
spin_lock_irqsave(&private->crw_lock, flags);
306311
list_add_tail(&crw->next, &private->crw);
312+
spin_unlock_irqrestore(&private->crw_lock, flags);
307313
queue_work(vfio_ccw_work_q, &private->crw_work);
308314
}
309315

drivers/s390/cio/vfio_ccw_ops.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ static int vfio_ccw_mdev_init_dev(struct vfio_device *vdev)
5555
INIT_WORK(&private->io_work, vfio_ccw_sch_io_todo);
5656
INIT_WORK(&private->crw_work, vfio_ccw_crw_todo);
5757
INIT_WORK(&private->notoper_work, vfio_ccw_notoper_todo);
58+
spin_lock_init(&private->crw_lock);
5859

5960
private->cp.guest_cp = kcalloc(CCWCHAIN_LEN_MAX, sizeof(struct ccw1),
6061
GFP_KERNEL);
@@ -132,6 +133,7 @@ static void vfio_ccw_mdev_release_dev(struct vfio_device *vdev)
132133
struct vfio_ccw_private *private =
133134
container_of(vdev, struct vfio_ccw_private, vdev);
134135
struct vfio_ccw_crw *crw, *temp;
136+
unsigned long flags;
135137

136138
/*
137139
* Ensure these work items are fully drained, so none can
@@ -147,10 +149,12 @@ static void vfio_ccw_mdev_release_dev(struct vfio_device *vdev)
147149
cancel_work_sync(&private->crw_work);
148150
flush_work(&private->notoper_work);
149151

152+
spin_lock_irqsave(&private->crw_lock, flags);
150153
list_for_each_entry_safe(crw, temp, &private->crw, next) {
151154
list_del(&crw->next);
152155
kfree(crw);
153156
}
157+
spin_unlock_irqrestore(&private->crw_lock, flags);
154158

155159
kmem_cache_free(vfio_ccw_crw_region, private->crw_region);
156160
kmem_cache_free(vfio_ccw_schib_region, private->schib_region);

drivers/s390/cio/vfio_ccw_private.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@ struct vfio_ccw_parent {
9898
* @cp: channel program for the current I/O operation
9999
* @irb: irb info received from interrupt
100100
* @scsw: scsw info
101+
* @crw_lock: serialization of CRW list information
102+
* @crw: list of Channel Report Word elements
101103
* @io_trigger: eventfd ctx for signaling userspace I/O results
102104
* @crw_trigger: eventfd ctx for signaling userspace CRW information
103105
* @req_trigger: eventfd ctx for signaling userspace to return device
@@ -120,6 +122,8 @@ struct vfio_ccw_private {
120122
struct channel_program cp;
121123
struct irb irb;
122124
union scsw scsw;
125+
126+
spinlock_t crw_lock;
123127
struct list_head crw;
124128

125129
struct eventfd_ctx *io_trigger;

0 commit comments

Comments
 (0)