Skip to content

Commit 866c4b8

Browse files
committed
Merge tag 's390-5.13-3' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
Pull s390 fixes from Vasily Gorbik: "Fix races in vfio-ccw request handling" * tag 's390-5.13-3' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: vfio-ccw: Serialize FSM IDLE state with I/O completion vfio-ccw: Reset FSM state to IDLE inside FSM vfio-ccw: Check initialized flag in cp_init()
2 parents 6799d4f + ffa99c4 commit 866c4b8

File tree

4 files changed

+15
-4
lines changed

4 files changed

+15
-4
lines changed

drivers/s390/cio/vfio_ccw_cp.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -638,6 +638,10 @@ int cp_init(struct channel_program *cp, struct device *mdev, union orb *orb)
638638
static DEFINE_RATELIMIT_STATE(ratelimit_state, 5 * HZ, 1);
639639
int ret;
640640

641+
/* this is an error in the caller */
642+
if (cp->initialized)
643+
return -EBUSY;
644+
641645
/*
642646
* We only support prefetching the channel program. We assume all channel
643647
* programs executed by supported guests likewise support prefetching.

drivers/s390/cio/vfio_ccw_drv.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ static void vfio_ccw_sch_io_todo(struct work_struct *work)
8686
struct vfio_ccw_private *private;
8787
struct irb *irb;
8888
bool is_final;
89+
bool cp_is_finished = false;
8990

9091
private = container_of(work, struct vfio_ccw_private, io_work);
9192
irb = &private->irb;
@@ -94,14 +95,21 @@ static void vfio_ccw_sch_io_todo(struct work_struct *work)
9495
(SCSW_ACTL_DEVACT | SCSW_ACTL_SCHACT));
9596
if (scsw_is_solicited(&irb->scsw)) {
9697
cp_update_scsw(&private->cp, &irb->scsw);
97-
if (is_final && private->state == VFIO_CCW_STATE_CP_PENDING)
98+
if (is_final && private->state == VFIO_CCW_STATE_CP_PENDING) {
9899
cp_free(&private->cp);
100+
cp_is_finished = true;
101+
}
99102
}
100103
mutex_lock(&private->io_mutex);
101104
memcpy(private->io_region->irb_area, irb, sizeof(*irb));
102105
mutex_unlock(&private->io_mutex);
103106

104-
if (private->mdev && is_final)
107+
/*
108+
* Reset to IDLE only if processing of a channel program
109+
* has finished. Do not overwrite a possible processing
110+
* state if the final interrupt was for HSCH or CSCH.
111+
*/
112+
if (private->mdev && cp_is_finished)
105113
private->state = VFIO_CCW_STATE_IDLE;
106114

107115
if (private->io_trigger)

drivers/s390/cio/vfio_ccw_fsm.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,7 @@ static void fsm_io_request(struct vfio_ccw_private *private,
318318
}
319319

320320
err_out:
321+
private->state = VFIO_CCW_STATE_IDLE;
321322
trace_vfio_ccw_fsm_io_request(scsw->cmd.fctl, schid,
322323
io_region->ret_code, errstr);
323324
}

drivers/s390/cio/vfio_ccw_ops.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -279,8 +279,6 @@ static ssize_t vfio_ccw_mdev_write_io_region(struct vfio_ccw_private *private,
279279
}
280280

281281
vfio_ccw_fsm_event(private, VFIO_CCW_EVENT_IO_REQ);
282-
if (region->ret_code != 0)
283-
private->state = VFIO_CCW_STATE_IDLE;
284282
ret = (region->ret_code != 0) ? region->ret_code : count;
285283

286284
out_unlock:

0 commit comments

Comments
 (0)