diff options
Diffstat (limited to 'drivers/s390/cio/vfio_ccw_chp.c')
-rw-r--r-- | drivers/s390/cio/vfio_ccw_chp.c | 17 |
1 files changed, 17 insertions, 0 deletions
diff --git a/drivers/s390/cio/vfio_ccw_chp.c b/drivers/s390/cio/vfio_ccw_chp.c index 37ea344a4d72..876f6ade51cc 100644 --- a/drivers/s390/cio/vfio_ccw_chp.c +++ b/drivers/s390/cio/vfio_ccw_chp.c @@ -82,14 +82,24 @@ static ssize_t vfio_ccw_crw_region_read(struct vfio_ccw_private *private, unsigned int i = VFIO_CCW_OFFSET_TO_INDEX(*ppos) - VFIO_CCW_NUM_REGIONS; loff_t pos = *ppos & VFIO_CCW_OFFSET_MASK; struct ccw_crw_region *region; + struct vfio_ccw_crw *crw; int ret; if (pos + count > sizeof(*region)) return -EINVAL; + crw = list_first_entry_or_null(&private->crw, + struct vfio_ccw_crw, next); + + if (crw) + list_del(&crw->next); + mutex_lock(&private->io_mutex); region = private->region[i].data; + if (crw) + memcpy(®ion->crw, &crw->crw, sizeof(region->crw)); + if (copy_to_user(buf, (void *)region + pos, count)) ret = -EFAULT; else @@ -98,6 +108,13 @@ static ssize_t vfio_ccw_crw_region_read(struct vfio_ccw_private *private, region->crw = 0; mutex_unlock(&private->io_mutex); + + kfree(crw); + + /* Notify the guest if more CRWs are on our queue */ + if (!list_empty(&private->crw) && private->crw_trigger) + eventfd_signal(private->crw_trigger, 1); + return ret; } |