aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Williamson <alex.williamson@redhat.com>2013-06-21 11:38:02 -0400
committerAlex Williamson <alex.williamson@redhat.com>2013-06-21 11:38:02 -0400
commit166fd7d94afdac040b28c473e45241820ca522a2 (patch)
tree044cd4540cb2a949ed8a55949cc39471b05a73b3
parentcd9b22685e4ccd728550d51fbe108c473f89df4f (diff)
vfio: hugepage support for vfio_iommu_type1
We currently send all mappings to the iommu in PAGE_SIZE chunks, which prevents the iommu from enabling support for larger page sizes. We still need to pin pages, which means we step through them in PAGE_SIZE chunks, but we can batch up contiguous physical memory chunks to allow the iommu the opportunity to use larger pages. The approach here is a bit different that the one currently used for legacy KVM device assignment. Rather than looking at the vma page size and using that as the maximum size to pass to the iommu, we instead simply look at whether the next page is physically contiguous. This means we might ask the iommu to map a 4MB region, while legacy KVM might limit itself to a maximum of 2MB. Splitting our mapping path also allows us to be smarter about locked memory because we can more easily unwind if the user attempts to exceed the limit. Therefore, rather than assuming that a mapping will result in locked memory, we test each page as it is pinned to determine whether it locks RAM vs an mmap'd MMIO region. This should result in better locking granularity and less locked page fudge factors in userspace. The unmap path uses the same algorithm as legacy KVM. We don't want to track the pfn for each mapping ourselves, but we need the pfn in order to unpin pages. We therefore ask the iommu for the iova to physical address translation, ask it to unpin a page, and see how many pages were actually unpinned. iommus supporting large pages will often return something bigger than a page here, which we know will be physically contiguous and we can unpin a batch of pfns. iommus not supporting large mappings won't see an improvement in batching here as they only unmap a page at a time. With this change, we also make a clarification to the API for mapping and unmapping DMA. We can only guarantee unmaps at the same granularity as used for the original mapping. In other words, unmapping a subregion of a previous mapping is not guaranteed and may result in a larger or smaller unmapping than requested. The size field in the unmapping structure is updated to reflect this. Previously this was unmodified on mapping, always returning the the requested unmap size. This is now updated to return the actual unmap size on success, allowing userspace to appropriately track mappings. Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
-rw-r--r--drivers/vfio/vfio_iommu_type1.c523
-rw-r--r--include/uapi/linux/vfio.h8
2 files changed, 344 insertions, 187 deletions
diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
index 0e863b3ddcab..6654a7eb42d3 100644
--- a/drivers/vfio/vfio_iommu_type1.c
+++ b/drivers/vfio/vfio_iommu_type1.c
@@ -60,7 +60,7 @@ struct vfio_dma {
60 struct rb_node node; 60 struct rb_node node;
61 dma_addr_t iova; /* Device address */ 61 dma_addr_t iova; /* Device address */
62 unsigned long vaddr; /* Process virtual addr */ 62 unsigned long vaddr; /* Process virtual addr */
63 long npage; /* Number of pages */ 63 size_t size; /* Map size (bytes) */
64 int prot; /* IOMMU_READ/WRITE */ 64 int prot; /* IOMMU_READ/WRITE */
65}; 65};
66 66
@@ -74,8 +74,6 @@ struct vfio_group {
74 * into DMA'ble space using the IOMMU 74 * into DMA'ble space using the IOMMU
75 */ 75 */
76 76
77#define NPAGE_TO_SIZE(npage) ((size_t)(npage) << PAGE_SHIFT)
78
79static struct vfio_dma *vfio_find_dma(struct vfio_iommu *iommu, 77static struct vfio_dma *vfio_find_dma(struct vfio_iommu *iommu,
80 dma_addr_t start, size_t size) 78 dma_addr_t start, size_t size)
81{ 79{
@@ -86,7 +84,7 @@ static struct vfio_dma *vfio_find_dma(struct vfio_iommu *iommu,
86 84
87 if (start + size <= dma->iova) 85 if (start + size <= dma->iova)
88 node = node->rb_left; 86 node = node->rb_left;
89 else if (start >= dma->iova + NPAGE_TO_SIZE(dma->npage)) 87 else if (start >= dma->iova + dma->size)
90 node = node->rb_right; 88 node = node->rb_right;
91 else 89 else
92 return dma; 90 return dma;
@@ -104,7 +102,7 @@ static void vfio_insert_dma(struct vfio_iommu *iommu, struct vfio_dma *new)
104 parent = *link; 102 parent = *link;
105 dma = rb_entry(parent, struct vfio_dma, node); 103 dma = rb_entry(parent, struct vfio_dma, node);
106 104
107 if (new->iova + NPAGE_TO_SIZE(new->npage) <= dma->iova) 105 if (new->iova + new->size <= dma->iova)
108 link = &(*link)->rb_left; 106 link = &(*link)->rb_left;
109 else 107 else
110 link = &(*link)->rb_right; 108 link = &(*link)->rb_right;
@@ -144,8 +142,8 @@ static void vfio_lock_acct(long npage)
144 struct vwork *vwork; 142 struct vwork *vwork;
145 struct mm_struct *mm; 143 struct mm_struct *mm;
146 144
147 if (!current->mm) 145 if (!current->mm || !npage)
148 return; /* process exited */ 146 return; /* process exited or nothing to do */
149 147
150 if (down_write_trylock(&current->mm->mmap_sem)) { 148 if (down_write_trylock(&current->mm->mmap_sem)) {
151 current->mm->locked_vm += npage; 149 current->mm->locked_vm += npage;
@@ -217,33 +215,6 @@ static int put_pfn(unsigned long pfn, int prot)
217 return 0; 215 return 0;
218} 216}
219 217
220/* Unmap DMA region */
221static long __vfio_dma_do_unmap(struct vfio_iommu *iommu, dma_addr_t iova,
222 long npage, int prot)
223{
224 long i, unlocked = 0;
225
226 for (i = 0; i < npage; i++, iova += PAGE_SIZE) {
227 unsigned long pfn;
228
229 pfn = iommu_iova_to_phys(iommu->domain, iova) >> PAGE_SHIFT;
230 if (pfn) {
231 iommu_unmap(iommu->domain, iova, PAGE_SIZE);
232 unlocked += put_pfn(pfn, prot);
233 }
234 }
235 return unlocked;
236}
237
238static void vfio_dma_unmap(struct vfio_iommu *iommu, dma_addr_t iova,
239 long npage, int prot)
240{
241 long unlocked;
242
243 unlocked = __vfio_dma_do_unmap(iommu, iova, npage, prot);
244 vfio_lock_acct(-unlocked);
245}
246
247static int vaddr_get_pfn(unsigned long vaddr, int prot, unsigned long *pfn) 218static int vaddr_get_pfn(unsigned long vaddr, int prot, unsigned long *pfn)
248{ 219{
249 struct page *page[1]; 220 struct page *page[1];
@@ -270,79 +241,142 @@ static int vaddr_get_pfn(unsigned long vaddr, int prot, unsigned long *pfn)
270 return ret; 241 return ret;
271} 242}
272 243
273/* Map DMA region */ 244/*
274static int __vfio_dma_map(struct vfio_iommu *iommu, dma_addr_t iova, 245 * Attempt to pin pages. We really don't want to track all the pfns and
275 unsigned long vaddr, long npage, int prot) 246 * the iommu can only map chunks of consecutive pfns anyway, so get the
247 * first page and all consecutive pages with the same locking.
248 */
249static long vfio_pin_pages(unsigned long vaddr, long npage,
250 int prot, unsigned long *pfn_base)
276{ 251{
277 dma_addr_t start = iova; 252 unsigned long limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
278 long i, locked = 0; 253 bool lock_cap = capable(CAP_IPC_LOCK);
279 int ret; 254 long ret, i;
280 255
281 /* Verify that pages are not already mapped */ 256 if (!current->mm)
282 for (i = 0; i < npage; i++, iova += PAGE_SIZE) 257 return -ENODEV;
283 if (iommu_iova_to_phys(iommu->domain, iova))
284 return -EBUSY;
285 258
286 iova = start; 259 ret = vaddr_get_pfn(vaddr, prot, pfn_base);
260 if (ret)
261 return ret;
287 262
288 if (iommu->cache) 263 if (is_invalid_reserved_pfn(*pfn_base))
289 prot |= IOMMU_CACHE; 264 return 1;
290 265
291 /* 266 if (!lock_cap && current->mm->locked_vm + 1 > limit) {
292 * XXX We break mappings into pages and use get_user_pages_fast to 267 put_pfn(*pfn_base, prot);
293 * pin the pages in memory. It's been suggested that mlock might 268 pr_warn("%s: RLIMIT_MEMLOCK (%ld) exceeded\n", __func__,
294 * provide a more efficient mechanism, but nothing prevents the 269 limit << PAGE_SHIFT);
295 * user from munlocking the pages, which could then allow the user 270 return -ENOMEM;
296 * access to random host memory. We also have no guarantee from the 271 }
297 * IOMMU API that the iommu driver can unmap sub-pages of previous 272
298 * mappings. This means we might lose an entire range if a single 273 /* Lock all the consecutive pages from pfn_base */
299 * page within it is unmapped. Single page mappings are inefficient, 274 for (i = 1, vaddr += PAGE_SIZE; i < npage; i++, vaddr += PAGE_SIZE) {
300 * but provide the most flexibility for now.
301 */
302 for (i = 0; i < npage; i++, iova += PAGE_SIZE, vaddr += PAGE_SIZE) {
303 unsigned long pfn = 0; 275 unsigned long pfn = 0;
304 276
305 ret = vaddr_get_pfn(vaddr, prot, &pfn); 277 ret = vaddr_get_pfn(vaddr, prot, &pfn);
306 if (ret) { 278 if (ret)
307 __vfio_dma_do_unmap(iommu, start, i, prot); 279 break;
308 return ret; 280
281 if (pfn != *pfn_base + i || is_invalid_reserved_pfn(pfn)) {
282 put_pfn(pfn, prot);
283 break;
309 } 284 }
310 285
286 if (!lock_cap && current->mm->locked_vm + i + 1 > limit) {
287 put_pfn(pfn, prot);
288 pr_warn("%s: RLIMIT_MEMLOCK (%ld) exceeded\n",
289 __func__, limit << PAGE_SHIFT);
290 break;
291 }
292 }
293