[RFC v2 18/20] vfio: VFIO_IOMMU_GET_FAULT_EVENTS

From: Eric Auger
Date: Tue Sep 18 2018 - 10:27:04 EST


Introduce an IOTCL that allows the userspace to consume fault
events that may have occurred. The userspace buffer gets filled
by pending faults, if any. The number of filled faults is
reported to the userspace. Read faults are removed from the kfifo.
the kernel does not expect any response from the userspace.

Signed-off-by: Lan Tianyu <tianyu.lan@xxxxxxxxx>
Signed-off-by: Eric Auger <eric.auger@xxxxxxxxxx>

---

the fault_lock may not be needed as kfifo documentation says:
"Note that with only one concurrent reader and one concurrent
writer, you don't need extra locking to use these macro."
---
drivers/vfio/vfio_iommu_type1.c | 33 ++++++++++++++++++++++++++++++++-
include/uapi/linux/vfio.h | 10 ++++++++++
2 files changed, 42 insertions(+), 1 deletion(-)

diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
index e52cbeb479c3..917bb8f9c9ae 100644
--- a/drivers/vfio/vfio_iommu_type1.c
+++ b/drivers/vfio/vfio_iommu_type1.c
@@ -1769,7 +1769,7 @@ vfio_iommu_fault_handler(struct iommu_fault_event *event, void *data)
eventfd_signal(iommu->fault_ctx, 1);
out:
mutex_unlock(&iommu->fault_lock);
- return 0;
+ return ret;
}

static inline int
@@ -1981,6 +1981,37 @@ static long vfio_iommu_type1_ioctl(void *iommu_data,
return -EINVAL;

return vfio_iommu_set_fault_eventfd(iommu, &ustruct);
+ } else if (cmd == VFIO_IOMMU_GET_FAULT_EVENTS) {
+ struct vfio_iommu_type1_get_fault_events ustruct;
+ size_t buf_size, len, elem_size;
+ int copied, max_events, ret;
+
+ minsz = offsetofend(struct vfio_iommu_type1_get_fault_events,
+ reserved);
+
+ if (copy_from_user(&ustruct, (void __user *)arg, minsz))
+ return -EFAULT;
+
+ if (ustruct.argsz < minsz || ustruct.flags)
+ return -EINVAL;
+
+ elem_size = sizeof(struct iommu_fault);
+ buf_size = ustruct.argsz - minsz;
+ max_events = buf_size / elem_size;
+ len = max_events * elem_size;
+
+ mutex_lock(&iommu->fault_lock);
+
+ ret = kfifo_to_user(&iommu->fault_fifo,
+ (void __user *)(arg + minsz), len, &copied);
+
+ mutex_unlock(&iommu->fault_lock);
+ if (ret)
+ return ret;
+
+ ustruct.count = copied / elem_size;
+
+ return copy_to_user((void __user *)arg, &ustruct, minsz);
}

return -ENOTTY;
diff --git a/include/uapi/linux/vfio.h b/include/uapi/linux/vfio.h
index 0d62598c818a..5b9165b7db8d 100644
--- a/include/uapi/linux/vfio.h
+++ b/include/uapi/linux/vfio.h
@@ -703,6 +703,16 @@ struct vfio_iommu_type1_set_fault_eventfd {
};
#define VFIO_IOMMU_SET_FAULT_EVENTFD _IO(VFIO_TYPE, VFIO_BASE + 25)

+struct vfio_iommu_type1_get_fault_events {
+ __u32 argsz;
+ __u32 flags;
+ __u32 count; /* number of faults returned */
+ __u32 reserved;
+ struct iommu_fault events[];
+};
+
+#define VFIO_IOMMU_GET_FAULT_EVENTS _IO(VFIO_TYPE, VFIO_BASE + 26)
+
/* -------- Additional API for SPAPR TCE (Server POWERPC) IOMMU -------- */

/*
--
2.17.1