Re: [RFC PATCH v3 4/8] vfio/type1: Pre-map more pages than requested in the IOPF handling

2021-05-21 Thread Shenming Lu
On 2021/5/19 2:58, Alex Williamson wrote:
> On Fri, 9 Apr 2021 11:44:16 +0800
> Shenming Lu  wrote:
> 
>> To optimize for fewer page fault handlings, we can pre-map more pages
>> than requested at once.
>>
>> Note that IOPF_PREMAP_LEN is just an arbitrary value for now, which we
>> could try further tuning.
> 
> I'd prefer that the series introduced full end-to-end functionality
> before trying to improve performance.  The pre-map value seems
> arbitrary here and as noted in the previous patch, the IOMMU API does
> not guarantee unmaps of ranges smaller than the original mapping.  This
> would need to map with single page granularity in order to guarantee
> page granularity at the mmu notifier when the IOMMU supports
> superpages.  Thanks,

Yeah, I will drop this patch in the current stage.

Thanks,
Shenming

> 
> Alex
> 
> .
> 
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [RFC PATCH v3 4/8] vfio/type1: Pre-map more pages than requested in the IOPF handling

2021-05-18 Thread Alex Williamson
On Fri, 9 Apr 2021 11:44:16 +0800
Shenming Lu  wrote:

> To optimize for fewer page fault handlings, we can pre-map more pages
> than requested at once.
> 
> Note that IOPF_PREMAP_LEN is just an arbitrary value for now, which we
> could try further tuning.

I'd prefer that the series introduced full end-to-end functionality
before trying to improve performance.  The pre-map value seems
arbitrary here and as noted in the previous patch, the IOMMU API does
not guarantee unmaps of ranges smaller than the original mapping.  This
would need to map with single page granularity in order to guarantee
page granularity at the mmu notifier when the IOMMU supports
superpages.  Thanks,

Alex

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[RFC PATCH v3 4/8] vfio/type1: Pre-map more pages than requested in the IOPF handling

2021-04-08 Thread Shenming Lu
To optimize for fewer page fault handlings, we can pre-map more pages
than requested at once.

Note that IOPF_PREMAP_LEN is just an arbitrary value for now, which we
could try further tuning.

Signed-off-by: Shenming Lu 
---
 drivers/vfio/vfio_iommu_type1.c | 131 ++--
 1 file changed, 123 insertions(+), 8 deletions(-)

diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
index 1cb9d1f2717b..01e296c6dc9e 100644
--- a/drivers/vfio/vfio_iommu_type1.c
+++ b/drivers/vfio/vfio_iommu_type1.c
@@ -3217,6 +3217,91 @@ static int vfio_iommu_type1_dirty_pages(struct 
vfio_iommu *iommu,
return -EINVAL;
 }
 
+/*
+ * To optimize for fewer page fault handlings, try to
+ * pre-map more pages than requested.
+ */
+#define IOPF_PREMAP_LEN512
+
+/*
+ * Return 0 on success or a negative error code, the
+ * number of pages contiguously pinned is in @pinned.
+ */
+static int pin_pages_iopf(struct vfio_dma *dma, unsigned long vaddr,
+ unsigned long npages, unsigned long *pfn_base,
+ unsigned long *pinned, struct vfio_batch *batch)
+{
+   struct mm_struct *mm;
+   unsigned long pfn;
+   int ret = 0;
+   *pinned = 0;
+
+   mm = get_task_mm(dma->task);
+   if (!mm)
+   return -ENODEV;
+
+   if (batch->size) {
+   *pfn_base = page_to_pfn(batch->pages[batch->offset]);
+   pfn = *pfn_base;
+   } else {
+   *pfn_base = 0;
+   }
+
+   while (npages) {
+   if (!batch->size) {
+   unsigned long req_pages = min_t(unsigned long, npages,
+   batch->capacity);
+
+   ret = vaddr_get_pfns(mm, vaddr, req_pages, dma->prot,
+, batch->pages);
+   if (ret < 0)
+   goto out;
+
+   batch->size = ret;
+   batch->offset = 0;
+   ret = 0;
+
+   if (!*pfn_base)
+   *pfn_base = pfn;
+   }
+
+   while (true) {
+   if (pfn != *pfn_base + *pinned)
+   goto out;
+
+   (*pinned)++;
+   npages--;
+   vaddr += PAGE_SIZE;
+   batch->offset++;
+   batch->size--;
+
+   if (!batch->size)
+   break;
+
+   pfn = page_to_pfn(batch->pages[batch->offset]);
+   }
+
+   if (unlikely(disable_hugepages))
+   break;
+   }
+
+out:
+   if (batch->size == 1 && !batch->offset) {
+   put_pfn(pfn, dma->prot);
+   batch->size = 0;
+   }
+
+   mmput(mm);
+   return ret;
+}
+
+static void unpin_pages_iopf(struct vfio_dma *dma,
+unsigned long pfn, unsigned long npages)
+{
+   while (npages--)
+   put_pfn(pfn++, dma->prot);
+}
+
 /* VFIO I/O Page Fault handler */
 static int vfio_iommu_type1_dma_map_iopf(struct iommu_fault *fault, void *data)
 {
@@ -3225,9 +3310,11 @@ static int vfio_iommu_type1_dma_map_iopf(struct 
iommu_fault *fault, void *data)
struct vfio_iopf_group *iopf_group;
struct vfio_iommu *iommu;
struct vfio_dma *dma;
+   struct vfio_batch batch;
dma_addr_t iova = ALIGN_DOWN(fault->prm.addr, PAGE_SIZE);
int access_flags = 0;
-   unsigned long bit_offset, vaddr, pfn;
+   size_t premap_len, map_len, mapped_len = 0;
+   unsigned long bit_offset, vaddr, pfn, i, npages;
int ret;
enum iommu_page_response_code status = IOMMU_PAGE_RESP_INVALID;
struct iommu_page_response resp = {0};
@@ -3263,19 +3350,47 @@ static int vfio_iommu_type1_dma_map_iopf(struct 
iommu_fault *fault, void *data)
if (IOPF_MAPPED_BITMAP_GET(dma, bit_offset))
goto out_success;
 
+   premap_len = IOPF_PREMAP_LEN << PAGE_SHIFT;
+   npages = dma->size >> PAGE_SHIFT;
+   map_len = PAGE_SIZE;
+   for (i = bit_offset + 1; i < npages; i++) {
+   if (map_len >= premap_len || IOPF_MAPPED_BITMAP_GET(dma, i))
+   break;
+   map_len += PAGE_SIZE;
+   }
vaddr = iova - dma->iova + dma->vaddr;
+   vfio_batch_init();
 
-   if (vfio_pin_page_external(dma, vaddr, , false))
-   goto out_invalid;
+   while (map_len) {
+   ret = pin_pages_iopf(dma, vaddr + mapped_len,
+map_len >> PAGE_SHIFT, ,
+, );
+   if (!npages)
+   break;
 
-   if (vfio_iommu_map(iommu, iova, pfn, 1, dma->prot)) {
-   put_pfn(pfn, dma->prot);
-   goto