On Thu, 22 Nov 2018 17:54:32 +0100 Cornelia Huck <cohuck@xxxxxxxxxx> wrote: > Add a region to the vfio-ccw device that can be used to submit > asynchronous I/O instructions. ssch continues to be handled by the > existing I/O region; the new region handles hsch and csch. > > Interrupt status continues to be reported through the same channels > as for ssch. > > Signed-off-by: Cornelia Huck <cohuck@xxxxxxxxxx> > --- > drivers/s390/cio/Makefile | 3 +- > drivers/s390/cio/vfio_ccw_async.c | 88 ++++++++++++++++ > drivers/s390/cio/vfio_ccw_drv.c | 48 ++++++--- > drivers/s390/cio/vfio_ccw_fsm.c | 158 +++++++++++++++++++++++++++- > drivers/s390/cio/vfio_ccw_ops.c | 13 ++- > drivers/s390/cio/vfio_ccw_private.h | 6 ++ > include/uapi/linux/vfio.h | 4 + > include/uapi/linux/vfio_ccw.h | 12 +++ > 8 files changed, 313 insertions(+), 19 deletions(-) > create mode 100644 drivers/s390/cio/vfio_ccw_async.c > > diff --git a/drivers/s390/cio/Makefile b/drivers/s390/cio/Makefile > index f230516abb96..f6a8db04177c 100644 > --- a/drivers/s390/cio/Makefile > +++ b/drivers/s390/cio/Makefile > @@ -20,5 +20,6 @@ obj-$(CONFIG_CCWGROUP) += ccwgroup.o > qdio-objs := qdio_main.o qdio_thinint.o qdio_debug.o qdio_setup.o > obj-$(CONFIG_QDIO) += qdio.o > > -vfio_ccw-objs += vfio_ccw_drv.o vfio_ccw_cp.o vfio_ccw_ops.o vfio_ccw_fsm.o > +vfio_ccw-objs += vfio_ccw_drv.o vfio_ccw_cp.o vfio_ccw_ops.o vfio_ccw_fsm.o \ > + vfio_ccw_async.o > obj-$(CONFIG_VFIO_CCW) += vfio_ccw.o > diff --git a/drivers/s390/cio/vfio_ccw_async.c b/drivers/s390/cio/vfio_ccw_async.c > new file mode 100644 > index 000000000000..8c7f51d17d70 > --- /dev/null > +++ b/drivers/s390/cio/vfio_ccw_async.c > @@ -0,0 +1,88 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Async I/O region for vfio_ccw > + * > + * Copyright Red Hat, Inc. 2018 > + * > + * Author(s): Cornelia Huck <cohuck@xxxxxxxxxx> > + */ > + > +#include <linux/vfio.h> > +#include <linux/mdev.h> > + > +#include "vfio_ccw_private.h" > + > +static size_t vfio_ccw_async_region_read(struct vfio_ccw_private *private, > + char __user *buf, size_t count, > + loff_t *ppos) > +{ > + unsigned int i = VFIO_CCW_OFFSET_TO_INDEX(*ppos) - VFIO_CCW_NUM_REGIONS; > + loff_t pos = *ppos & VFIO_CCW_OFFSET_MASK; > + struct ccw_cmd_region *region; > + > + if (pos + count > sizeof(*region)) > + return -EINVAL; > + > + region = private->region[i].data; > + if (copy_to_user(buf, (void *)region + pos, count)) > + return -EFAULT; > + > + return count; > + > +} > + > +static size_t vfio_ccw_async_region_write(struct vfio_ccw_private *private, > + const char __user *buf, size_t count, > + loff_t *ppos) > +{ > + unsigned int i = VFIO_CCW_OFFSET_TO_INDEX(*ppos) - VFIO_CCW_NUM_REGIONS; > + loff_t pos = *ppos & VFIO_CCW_OFFSET_MASK; > + struct ccw_cmd_region *region; > + > + if (pos + count > sizeof(*region)) > + return -EINVAL; > + > + if (private->state == VFIO_CCW_STATE_NOT_OPER || > + private->state == VFIO_CCW_STATE_STANDBY) > + return -EACCES; > + > + region = private->region[i].data; > + if (copy_from_user((void *)region + pos, buf, count)) > + return -EFAULT; I guess vfio_ccw_async_region_write() is supposed to be reentrant in a sense that there may be more that one 'instances' of the function executing at the same time, or am I wrong? If it is reenarant, I wonder what protects private->region[i].data from corruption or simply being changed 'while at it'? Regards, Halil > + > + switch (region->command) { > + case VFIO_CCW_ASYNC_CMD_HSCH: > + vfio_ccw_fsm_event(private, VFIO_CCW_EVENT_HALT_REQ); > + break; > + case VFIO_CCW_ASYNC_CMD_CSCH: > + vfio_ccw_fsm_event(private, VFIO_CCW_EVENT_CLEAR_REQ); > + break; > + default: > + return -EINVAL; > + } > + > + return region->ret_code ? region->ret_code : count; > +} > +