Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

vfio/type1: handle case where IOMMU does not support PAGE_SIZE size

Current vfio_pgsize_bitmap code hides the supported IOMMU page
sizes smaller than PAGE_SIZE. As a result, in case the IOMMU
does not support PAGE_SIZE page, the alignment check on map/unmap
is done with larger page sizes, if any. This can fail although
mapping could be done with pages smaller than PAGE_SIZE.

This patch modifies vfio_pgsize_bitmap implementation so that,
in case the IOMMU supports page sizes smaller than PAGE_SIZE
we pretend PAGE_SIZE is supported and hide sub-PAGE_SIZE sizes.
That way the user will be able to map/unmap buffers whose size/
start address is aligned with PAGE_SIZE. Pinning code uses that
granularity while iommu driver can use the sub-PAGE_SIZE size
to map the buffer.

Signed-off-by: Eric Auger <eric.auger@linaro.org>
Acked-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>

authored by

Eric Auger and committed by
Alex Williamson
4644321f 1276ece3

+14 -1
+14 -1
drivers/vfio/vfio_iommu_type1.c
··· 403 403 static unsigned long vfio_pgsize_bitmap(struct vfio_iommu *iommu) 404 404 { 405 405 struct vfio_domain *domain; 406 - unsigned long bitmap = PAGE_MASK; 406 + unsigned long bitmap = ULONG_MAX; 407 407 408 408 mutex_lock(&iommu->lock); 409 409 list_for_each_entry(domain, &iommu->domain_list, next) 410 410 bitmap &= domain->domain->ops->pgsize_bitmap; 411 411 mutex_unlock(&iommu->lock); 412 + 413 + /* 414 + * In case the IOMMU supports page sizes smaller than PAGE_SIZE 415 + * we pretend PAGE_SIZE is supported and hide sub-PAGE_SIZE sizes. 416 + * That way the user will be able to map/unmap buffers whose size/ 417 + * start address is aligned with PAGE_SIZE. Pinning code uses that 418 + * granularity while iommu driver can use the sub-PAGE_SIZE size 419 + * to map the buffer. 420 + */ 421 + if (bitmap & ~PAGE_MASK) { 422 + bitmap &= PAGE_MASK; 423 + bitmap |= PAGE_SIZE; 424 + } 412 425 413 426 return bitmap; 414 427 }