History

Merge tag 'media/v4.3-2' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media

Pull media updates from Mauro Carvalho Chehab: "A series of patches that move part of the code used to allocate memory from the media subsystem to the mm subsystem" [ The mm parts have been acked by VM people, and the series was apparently in -mm for a while - Linus ] * tag 'media/v4.3-2' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: [media] drm/exynos: Convert g2d_userptr_get_dma_addr() to use get_vaddr_frames() [media] media: vb2: Remove unused functions [media] media: vb2: Convert vb2_dc_get_userptr() to use frame vector [media] media: vb2: Convert vb2_vmalloc_get_userptr() to use frame vector [media] media: vb2: Convert vb2_dma_sg_get_userptr() to use frame vector [media] vb2: Provide helpers for mapping virtual addresses [media] media: omap_vout: Convert omap_vout_uservirt_to_phys() to use get_vaddr_pfns() [media] mm: Provide new get_vaddr_frames() helper [media] vb2: Push mmap_sem down to memops

Linus Torvalds committed 11 years ago

Commit 06a660a2 parents d9b44fe 63540f016 files · +477 −608Browse files

Unified · Split

16 files
  1. drivers/gpu/drm/exynos/Kconfig +1 −0
  2. drivers/gpu/drm/exynos/exynos_drm_g2d.c +29 −60
  3. drivers/gpu/drm/exynos/exynos_drm_gem.c +0 −97
  4. drivers/media/platform/omap/Kconfig +1 −0
  5. drivers/media/platform/omap/omap_vout.c +31 −38
  6. drivers/media/v4l2-core/Kconfig +1 −0
  7. drivers/media/v4l2-core/videobuf2-core.c +0 −2
  8. drivers/media/v4l2-core/videobuf2-dma-contig.c +34 −173
  9. drivers/media/v4l2-core/videobuf2-dma-sg.c +15 −76
  10. drivers/media/v4l2-core/videobuf2-memops.c +46 −102
  11. drivers/media/v4l2-core/videobuf2-vmalloc.c +36 −54
  12. include/linux/mm.h +44 −0
  13. include/media/videobuf2-memops.h +5 −6
  14. mm/Kconfig +3 −0
  15. mm/Makefile +1 −0
  16. mm/frame_vector.c +230 −0
drivers/gpu/drm/exynos/Kconfig+1−0
@@ -77,6 +77,7 @@ config DRM_EXYNOS_VIDI · 76 unmodified lines
7777 config DRM_EXYNOS_G2D
7878 bool "Exynos DRM G2D"
7979 depends on DRM_EXYNOS && !VIDEO_SAMSUNG_S5P_G2D
80+ select FRAME_VECTOR
8081 help
8182 Choose this option if you want to use Exynos G2D for DRM.
8283
drivers/gpu/drm/exynos/exynos_drm_g2d.c+29−60
@@ -194,10 +194,8 @@ struct g2d_cmdlist_userptr { · 193 unmodified lines
194194 dma_addr_t dma_addr;
195195 unsigned long userptr;
196196 unsigned long size;
197− struct page **pages;
198− unsigned int npages;
197+ struct frame_vector *vec;
199198 struct sg_table *sgt;
200− struct vm_area_struct *vma;
201199 atomic_t refcount;
202200 bool in_pool;
203201 bool out_of_list;
@@ -367,6 +365,7 @@ static void g2d_userptr_put_dma_addr(struct drm_device *drm_dev, · 163 unmodified lines
367365 {
368366 struct g2d_cmdlist_userptr *g2d_userptr =
369367 (struct g2d_cmdlist_userptr *)obj;
368+ struct page **pages;
370369
371370 if (!obj)
372371 return;
@@ -386,19 +385,21 @@ out: · 13 unmodified lines
386385 exynos_gem_unmap_sgt_from_dma(drm_dev, g2d_userptr->sgt,
387386 DMA_BIDIRECTIONAL);
388387
389− exynos_gem_put_pages_to_userptr(g2d_userptr->pages,
390− g2d_userptr->npages,
391− g2d_userptr->vma);
388+ pages = frame_vector_pages(g2d_userptr->vec);
389+ if (!IS_ERR(pages)) {
390+ int i;
392391
393− exynos_gem_put_vma(g2d_userptr->vma);
392+ for (i = 0; i < frame_vector_count(g2d_userptr->vec); i++)
393+ set_page_dirty_lock(pages[i]);
394+ }
395+ put_vaddr_frames(g2d_userptr->vec);
396+ frame_vector_destroy(g2d_userptr->vec);
394397
395398 if (!g2d_userptr->out_of_list)
396399 list_del_init(&g2d_userptr->list);
397400
398401 sg_free_table(g2d_userptr->sgt);
399402 kfree(g2d_userptr->sgt);
400−
401− drm_free_large(g2d_userptr->pages);
402403 kfree(g2d_userptr);
403404 }
404405
@@ -412,9 +413,7 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct drm_device *drm_dev, · 7 unmodified lines
412413 struct exynos_drm_g2d_private *g2d_priv = file_priv->g2d_priv;
413414 struct g2d_cmdlist_userptr *g2d_userptr;
414415 struct g2d_data *g2d;
415− struct page **pages;
416416 struct sg_table *sgt;
417− struct vm_area_struct *vma;
418417 unsigned long start, end;
419418 unsigned int npages, offset;
420419 int ret;
@@ -460,65 +459,40 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct drm_device *drm_dev, · 39 unmodified lines
460459 return ERR_PTR(-ENOMEM);
461460
462461 atomic_set(&g2d_userptr->refcount, 1);
462+ g2d_userptr->size = size;
463463
464464 start = userptr & PAGE_MASK;
465465 offset = userptr & ~PAGE_MASK;
466466 end = PAGE_ALIGN(userptr + size);
467467 npages = (end - start) >> PAGE_SHIFT;
468− g2d_userptr->npages = npages;
469−
470− pages = drm_calloc_large(npages, sizeof(struct page *));
471− if (!pages) {
472− DRM_ERROR("failed to allocate pages.\n");
468+ g2d_userptr->vec = frame_vector_create(npages);
469+ if (!g2d_userptr->vec) {
473470 ret = -ENOMEM;
474471 goto err_free;
475472 }
476473
477− down_read(&current->mm->mmap_sem);
478− vma = find_vma(current->mm, userptr);
479− if (!vma) {
480− up_read(&current->mm->mmap_sem);
481− DRM_ERROR("failed to get vm region.\n");
474+ ret = get_vaddr_frames(start, npages, true, true, g2d_userptr->vec);
475+ if (ret != npages) {
476+ DRM_ERROR("failed to get user pages from userptr.\n");
477+ if (ret < 0)
478+ goto err_destroy_framevec;
482479 ret = -EFAULT;
483− goto err_free_pages;
480+ goto err_put_framevec;
484481 }
485−
486− if (vma->vm_end < userptr + size) {
487− up_read(&current->mm->mmap_sem);
488− DRM_ERROR("vma is too small.\n");
482+ if (frame_vector_to_pages(g2d_userptr->vec) < 0) {
489483 ret = -EFAULT;
490− goto err_free_pages;
491− }
492−
493− g2d_userptr->vma = exynos_gem_get_vma(vma);
494− if (!g2d_userptr->vma) {
495− up_read(&current->mm->mmap_sem);
496− DRM_ERROR("failed to copy vma.\n");
497− ret = -ENOMEM;
498− goto err_free_pages;
499− }
500−
501− g2d_userptr->size = size;
502−
503− ret = exynos_gem_get_pages_from_userptr(start & PAGE_MASK,
504− npages, pages, vma);
505− if (ret < 0) {
506− up_read(&current->mm->mmap_sem);
507− DRM_ERROR("failed to get user pages from userptr.\n");
508− goto err_put_vma;
484+ goto err_put_framevec;
509485 }
510486
511− up_read(&current->mm->mmap_sem);
512− g2d_userptr->pages = pages;
513−
514487 sgt = kzalloc(sizeof(*sgt), GFP_KERNEL);
515488 if (!sgt) {
516489 ret = -ENOMEM;
517− goto err_free_userptr;
490+ goto err_put_framevec;
518491 }
519492
520− ret = sg_alloc_table_from_pages(sgt, pages, npages, offset,
521− size, GFP_KERNEL);
493+ ret = sg_alloc_table_from_pages(sgt,
494+ frame_vector_pages(g2d_userptr->vec),
495+ npages, offset, size, GFP_KERNEL);
522496 if (ret < 0) {
523497 DRM_ERROR("failed to get sgt from pages.\n");
524498 goto err_free_sgt;
@@ -553,16 +527,11 @@ err_sg_free_table: · 28 unmodified lines
553527 err_free_sgt:
554528 kfree(sgt);
555529
556−err_free_userptr:
557− exynos_gem_put_pages_to_userptr(g2d_userptr->pages,
558− g2d_userptr->npages,
559− g2d_userptr->vma);
560−
561−err_put_vma:
562− exynos_gem_put_vma(g2d_userptr->vma);
530+err_put_framevec:
531+ put_vaddr_frames(g2d_userptr->vec);
563532
564−err_free_pages:
565− drm_free_large(pages);
533+err_destroy_framevec:
534+ frame_vector_destroy(g2d_userptr->vec);
566535
567536 err_free:
568537 kfree(g2d_userptr);
drivers/gpu/drm/exynos/exynos_drm_gem.c+0−97
@@ -366,103 +366,6 @@ int exynos_drm_gem_get_ioctl(struct drm_device *dev, void *data, · 365 unmodified lines
366366 return 0;
367367 }
368368
369−struct vm_area_struct *exynos_gem_get_vma(struct vm_area_struct *vma)
370−{
371− struct vm_area_struct *vma_copy;
372−
373− vma_copy = kmalloc(sizeof(*vma_copy), GFP_KERNEL);
374− if (!vma_copy)
375− return NULL;
376−
377− if (vma->vm_ops && vma->vm_ops->open)
378− vma->vm_ops->open(vma);
379−
380− if (vma->vm_file)
381− get_file(vma->vm_file);
382−
383− memcpy(vma_copy, vma, sizeof(*vma));
384−
385− vma_copy->vm_mm = NULL;
386− vma_copy->vm_next = NULL;
387− vma_copy->vm_prev = NULL;
388−
389− return vma_copy;
390−}
391−
392−void exynos_gem_put_vma(struct vm_area_struct *vma)
393−{
394− if (!vma)
395− return;
396−
397− if (vma->vm_ops && vma->vm_ops->close)
398− vma->vm_ops->close(vma);
399−
400− if (vma->vm_file)
401− fput(vma->vm_file);
402−
403− kfree(vma);
404−}
405−
406−int exynos_gem_get_pages_from_userptr(unsigned long start,
407− unsigned int npages,
408− struct page **pages,
409− struct vm_area_struct *vma)
410−{
411− int get_npages;
412−
413− /* the memory region mmaped with VM_PFNMAP. */
414− if (vma_is_io(vma)) {
415− unsigned int i;
416−
417− for (i = 0; i < npages; ++i, start += PAGE_SIZE) {
418− unsigned long pfn;
419− int ret = follow_pfn(vma, start, &pfn);
420− if (ret)
421− return ret;
422−
423− pages[i] = pfn_to_page(pfn);
424− }
425−
426− if (i != npages) {
427− DRM_ERROR("failed to get user_pages.\n");
428− return -EINVAL;
429− }
430−
431− return 0;
432− }
433−
434− get_npages = get_user_pages(current, current->mm, start,
435− npages, 1, 1, pages, NULL);
436− get_npages = max(get_npages, 0);
437− if (get_npages != npages) {
438− DRM_ERROR("failed to get user_pages.\n");
439− while (get_npages)
440− put_page(pages[--get_npages]);
441− return -EFAULT;
442− }
443−
444− return 0;
445−}
446−
447−void exynos_gem_put_pages_to_userptr(struct page **pages,
448− unsigned int npages,
449− struct vm_area_struct *vma)
450−{
451− if (!vma_is_io(vma)) {
452− unsigned int i;
453−
454− for (i = 0; i < npages; i++) {
455− set_page_dirty_lock(pages[i]);
456−
457− /*
458− * undo the reference we took when populating
459− * the table.
460− */
461− put_page(pages[i]);
462− }
463− }
464−}
465−
466369 int exynos_gem_map_sgt_with_dma(struct drm_device *drm_dev,
467370 struct sg_table *sgt,
468371 enum dma_data_direction dir)
drivers/media/platform/omap/Kconfig+1−0
@@ -10,6 +10,7 @@ config VIDEO_OMAP2_VOUT · 9 unmodified lines
1010 select OMAP2_DSS if HAS_IOMEM && ARCH_OMAP2PLUS
1111 select OMAP2_VRFB if ARCH_OMAP2 || ARCH_OMAP3
1212 select VIDEO_OMAP2_VOUT_VRFB if VIDEO_OMAP2_VOUT && OMAP2_VRFB
13+ select FRAME_VECTOR
1314 default n
1415 ---help---
1516 V4L2 Display driver support for OMAP2/3 based boards.
drivers/media/platform/omap/omap_vout.c+31−38
@@ -195,46 +195,34 @@ static int omap_vout_try_format(struct v4l2_pix_format *pix) · 194 unmodified lines
195195 }
196196
197197 /*
198− * omap_vout_uservirt_to_phys: This inline function is used to convert user
199− * space virtual address to physical address.
198+ * omap_vout_get_userptr: Convert user space virtual address to physical
199+ * address.
200200 */
201−static unsigned long omap_vout_uservirt_to_phys(unsigned long virtp)
201+static int omap_vout_get_userptr(struct videobuf_buffer *vb, u32 virtp,
202+ u32 *physp)
202203 {
203− unsigned long physp = 0;
204− struct vm_area_struct *vma;
205− struct mm_struct *mm = current->mm;
204+ struct frame_vector *vec;
205+ int ret;
206206
207207 /* For kernel direct-mapped memory, take the easy way */
208− if (virtp >= PAGE_OFFSET)
209− return virt_to_phys((void *) virtp);
210−
211− down_read(&current->mm->mmap_sem);
212− vma = find_vma(mm, virtp);
213− if (vma && (vma->vm_flags & VM_IO) && vma->vm_pgoff) {
214− /* this will catch, kernel-allocated, mmaped-to-usermode
215− addresses */
216− physp = (vma->vm_pgoff << PAGE_SHIFT) + (virtp - vma->vm_start);
217− up_read(&current->mm->mmap_sem);
218− } else {
219− /* otherwise, use get_user_pages() for general userland pages */
220− int res, nr_pages = 1;
221− struct page *pages;
208+ if (virtp >= PAGE_OFFSET) {
209+ *physp = virt_to_phys((void *)virtp);
210+ return 0;
211+ }
222212
223− res = get_user_pages(current, current->mm, virtp, nr_pages, 1,
224− 0, &pages, NULL);
225− up_read(&current->mm->mmap_sem);
213+ vec = frame_vector_create(1);
214+ if (!vec)
215+ return -ENOMEM;
226216
227− if (res == nr_pages) {
228− physp = __pa(page_address(&pages[0]) +
229− (virtp & ~PAGE_MASK));
230− } else {
231− printk(KERN_WARNING VOUT_NAME
232− "get_user_pages failed\n");
233− return 0;
234− }
217+ ret = get_vaddr_frames(virtp, 1, true, false, vec);
218+ if (ret != 1) {
219+ frame_vector_destroy(vec);
220+ return -EINVAL;
235221 }
222+ *physp = __pfn_to_phys(frame_vector_pfns(vec)[0]);
223+ vb->priv = vec;
236224
237− return physp;
225+ return 0;
238226 }
239227
240228 /*
@@ -784,11 +772,15 @@ static int omap_vout_buffer_prepare(struct videobuf_queue *q, · 543 unmodified lines
784772 * address of the buffer
785773 */
786774 if (V4L2_MEMORY_USERPTR == vb->memory) {
775+ int ret;
776+
787777 if (0 == vb->baddr)
788778 return -EINVAL;
789779 /* Physical address */
790− vout->queued_buf_addr[vb->i] = (u8 *)
791− omap_vout_uservirt_to_phys(vb->baddr);
780+ ret = omap_vout_get_userptr(vb, vb->baddr,
781+ (u32 *)&vout->queued_buf_addr[vb->i]);
782+ if (ret < 0)
783+ return ret;
792784 } else {
793785 unsigned long addr, dma_addr;
794786 unsigned long size;
@@ -834,12 +826,13 @@ static void omap_vout_buffer_queue(struct videobuf_queue *q, · 39 unmodified lines
834826 static void omap_vout_buffer_release(struct videobuf_queue *q,
835827 struct videobuf_buffer *vb)
836828 {
837− struct omap_vout_device *vout = q->priv_data;
838−
839829 vb->state = VIDEOBUF_NEEDS_INIT;
830+ if (vb->memory == V4L2_MEMORY_USERPTR && vb->priv) {
831+ struct frame_vector *vec = vb->priv;
840832
841− if (V4L2_MEMORY_MMAP != vout->memory)
842− return;
833+ put_vaddr_frames(vec);
834+ frame_vector_destroy(vec);
835+ }
843836 }
844837
845838 /*
drivers/media/v4l2-core/Kconfig+1−0
@@ -84,6 +84,7 @@ config VIDEOBUF2_CORE · 83 unmodified lines
8484
8585 config VIDEOBUF2_MEMOPS
8686 tristate
87+ select FRAME_VECTOR
8788
8889 config VIDEOBUF2_DMA_CONTIG
8990 tristate
drivers/media/v4l2-core/videobuf2-core.c+0−2
@@ -1691,9 +1691,7 @@ static int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b) · 1690 unmodified lines
16911691 ret = __qbuf_mmap(vb, b);
16921692 break;
16931693 case V4L2_MEMORY_USERPTR:
1694− down_read(&current->mm->mmap_sem);
16951694 ret = __qbuf_userptr(vb, b);
1696− up_read(&current->mm->mmap_sem);
16971695 break;
16981696 case V4L2_MEMORY_DMABUF:
16991697 ret = __qbuf_dmabuf(vb, b);
drivers/media/v4l2-core/videobuf2-dma-contig.c+34−173
@@ -32,15 +32,13 @@ struct vb2_dc_buf { · 31 unmodified lines
3232 dma_addr_t dma_addr;
3333 enum dma_data_direction dma_dir;
3434 struct sg_table *dma_sgt;
35+ struct frame_vector *vec;
3536
3637 /* MMAP related */
3738 struct vb2_vmarea_handler handler;
3839 atomic_t refcount;
3940 struct sg_table *sgt_base;
4041
41− /* USERPTR related */
42− struct vm_area_struct *vma;
43−
4442 /* DMABUF related */
4543 struct dma_buf_attachment *db_attach;
4644 };
@@ -49,24 +47,6 @@ struct vb2_dc_buf { · 2 unmodified lines
4947 /* scatterlist table functions */
5048 /*********************************************/
5149
52−
53−static void vb2_dc_sgt_foreach_page(struct sg_table *sgt,
54− void (*cb)(struct page *pg))
55−{
56− struct scatterlist *s;
57− unsigned int i;
58−
59− for_each_sg(sgt->sgl, s, sgt->orig_nents, i) {
60− struct page *page = sg_page(s);
61− unsigned int n_pages = PAGE_ALIGN(s->offset + s->length)
62− >> PAGE_SHIFT;
63− unsigned int j;
64−
65− for (j = 0; j < n_pages; ++j, ++page)
66− cb(page);
67− }
68−}
69−
7050 static unsigned long vb2_dc_get_contiguous_size(struct sg_table *sgt)
7151 {
7252 struct scatterlist *s;
@@ -429,92 +409,12 @@ static struct dma_buf *vb2_dc_get_dmabuf(void *buf_priv, unsigned long flags) · 356 unmodified lines
429409 /* callbacks for USERPTR buffers */
430410 /*********************************************/
431411
432−static inline int vma_is_io(struct vm_area_struct *vma)
433−{
434− return !!(vma->vm_flags & (VM_IO | VM_PFNMAP));
435−}
436−
437−static int vb2_dc_get_user_pfn(unsigned long start, int n_pages,
438− struct vm_area_struct *vma, unsigned long *res)
439−{
440− unsigned long pfn, start_pfn, prev_pfn;
441− unsigned int i;
442− int ret;
443−
444− if (!vma_is_io(vma))
445− return -EFAULT;
446−
447− ret = follow_pfn(vma, start, &pfn);
448− if (ret)
449− return ret;
450−
451− start_pfn = pfn;
452− start += PAGE_SIZE;
453−
454− for (i = 1; i < n_pages; ++i, start += PAGE_SIZE) {
455− prev_pfn = pfn;
456− ret = follow_pfn(vma, start, &pfn);
457−
458− if (ret) {
459− pr_err("no page for address %lu\n", start);
460− return ret;
461− }
462− if (pfn != prev_pfn + 1)
463− return -EINVAL;
464− }
465−
466− *res = start_pfn;
467− return 0;
468−}
469−
470−static int vb2_dc_get_user_pages(unsigned long start, struct page **pages,
471− int n_pages, struct vm_area_struct *vma,
472− enum dma_data_direction dma_dir)
473−{
474− if (vma_is_io(vma)) {
475− unsigned int i;
476−
477− for (i = 0; i < n_pages; ++i, start += PAGE_SIZE) {
478− unsigned long pfn;
479− int ret = follow_pfn(vma, start, &pfn);
480−
481− if (!pfn_valid(pfn))
482− return -EINVAL;
483−
484− if (ret) {
485− pr_err("no page for address %lu\n", start);
486− return ret;
487− }
488− pages[i] = pfn_to_page(pfn);
489− }
490− } else {
491− int n;
492−
493− n = get_user_pages(current, current->mm, start & PAGE_MASK,
494− n_pages, dma_dir == DMA_FROM_DEVICE, 1, pages, NULL);
495− /* negative error means that no page was pinned */
496− n = max(n, 0);
497− if (n != n_pages) {
498− pr_err("got only %d of %d user pages\n", n, n_pages);
499− while (n)
500− put_page(pages[--n]);
501− return -EFAULT;
502− }
503− }
504−
505− return 0;
506−}
507−
508−static void vb2_dc_put_dirty_page(struct page *page)
509−{
510− set_page_dirty_lock(page);
511− put_page(page);
512−}
513−
514412 static void vb2_dc_put_userptr(void *buf_priv)
515413 {
516414 struct vb2_dc_buf *buf = buf_priv;
517415 struct sg_table *sgt = buf->dma_sgt;
416+ int i;
417+ struct page **pages;
518418
519419 if (sgt) {
520420 DEFINE_DMA_ATTRS(attrs);
@@ -526,13 +426,15 @@ static void vb2_dc_put_userptr(void *buf_priv) · 5 unmodified lines
526426 */
527427 dma_unmap_sg_attrs(buf->dev, sgt->sgl, sgt->orig_nents,
528428 buf->dma_dir, &attrs);
529− if (!vma_is_io(buf->vma))
530− vb2_dc_sgt_foreach_page(sgt, vb2_dc_put_dirty_page);
531−
429+ pages = frame_vector_pages(buf->vec);
430+ /* sgt should exist only if vector contains pages... */
431+ BUG_ON(IS_ERR(pages));
432+ for (i = 0; i < frame_vector_count(buf->vec); i++)
433+ set_page_dirty_lock(pages[i]);
532434 sg_free_table(sgt);
533435 kfree(sgt);
534436 }
535− vb2_put_vma(buf->vma);
437+ vb2_destroy_framevec(buf->vec);
536438 kfree(buf);
537439 }
538440
@@ -572,13 +474,10 @@ static void *vb2_dc_get_userptr(void *alloc_ctx, unsigned long vaddr, · 33 unmodified lines
572474 {
573475 struct vb2_dc_conf *conf = alloc_ctx;
574476 struct vb2_dc_buf *buf;
575− unsigned long start;
576− unsigned long end;
477+ struct frame_vector *vec;
577478 unsigned long offset;
578− struct page **pages;
579− int n_pages;
479+ int n_pages, i;
580480 int ret = 0;
581− struct vm_area_struct *vma;
582481 struct sg_table *sgt;
583482 unsigned long contig_size;
584483 unsigned long dma_align = dma_get_cache_alignment();
@@ -604,72 +503,43 @@ static void *vb2_dc_get_userptr(void *alloc_ctx, unsigned long vaddr, · 19 unmodified lines
604503 buf->dev = conf->dev;
605504 buf->dma_dir = dma_dir;
606505
607− start = vaddr & PAGE_MASK;
608506 offset = vaddr & ~PAGE_MASK;
609− end = PAGE_ALIGN(vaddr + size);
610− n_pages = (end - start) >> PAGE_SHIFT;
611−
612− pages = kmalloc(n_pages * sizeof(pages[0]), GFP_KERNEL);
613− if (!pages) {
614− ret = -ENOMEM;
615− pr_err("failed to allocate pages table\n");
507+ vec = vb2_create_framevec(vaddr, size, dma_dir == DMA_FROM_DEVICE);
508+ if (IS_ERR(vec)) {
509+ ret = PTR_ERR(vec);
616510 goto fail_buf;
617511 }
512+ buf->vec = vec;
513+ n_pages = frame_vector_count(vec);
514+ ret = frame_vector_to_pages(vec);
515+ if (ret < 0) {
516+ unsigned long *nums = frame_vector_pfns(vec);
618517
619− /* current->mm->mmap_sem is taken by videobuf2 core */
620− vma = find_vma(current->mm, vaddr);
621− if (!vma) {
622− pr_err("no vma for address %lu\n", vaddr);
623− ret = -EFAULT;
624− goto fail_pages;
625− }
626−
627− if (vma->vm_end < vaddr + size) {
628− pr_err("vma at %lu is too small for %lu bytes\n", vaddr, size);
629− ret = -EFAULT;
630− goto fail_pages;
631− }
632−
633− buf->vma = vb2_get_vma(vma);
634− if (!buf->vma) {
635− pr_err("failed to copy vma\n");
636− ret = -ENOMEM;
637− goto fail_pages;
638− }
639−
640− /* extract page list from userspace mapping */
641− ret = vb2_dc_get_user_pages(start, pages, n_pages, vma, dma_dir);
642− if (ret) {
643− unsigned long pfn;
644− if (vb2_dc_get_user_pfn(start, n_pages, vma, &pfn) == 0) {
645− buf->dma_addr = vb2_dc_pfn_to_dma(buf->dev, pfn);
646− buf->size = size;
647− kfree(pages);
648− return buf;
649− }
650−
651− pr_err("failed to get user pages\n");
652− goto fail_vma;
518+ /*
519+ * Failed to convert to pages... Check the memory is physically
520+ * contiguous and use direct mapping
521+ */
522+ for (i = 1; i < n_pages; i++)
523+ if (nums[i-1] + 1 != nums[i])
524+ goto fail_pfnvec;
525+ buf->dma_addr = vb2_dc_pfn_to_dma(buf->dev, nums[0]);
526+ goto out;
653527 }
654528
655529 sgt = kzalloc(sizeof(*sgt), GFP_KERNEL);
656530 if (!sgt) {
657531 pr_err("failed to allocate sg table\n");
658532 ret = -ENOMEM;
659− goto fail_get_user_pages;
533+ goto fail_pfnvec;
660534 }
661535
662− ret = sg_alloc_table_from_pages(sgt, pages, n_pages,
536+ ret = sg_alloc_table_from_pages(sgt, frame_vector_pages(vec), n_pages,
663537 offset, size, GFP_KERNEL);
664538 if (ret) {
665539 pr_err("failed to initialize sg table\n");
666540 goto fail_sgt;
667541 }
668542
669− /* pages are no longer needed */
670− kfree(pages);
671− pages = NULL;
672−
673543 /*
674544 * No need to sync to the device, this will happen later when the
675545 * prepare() memop is called.
@@ -691,8 +561,9 @@ static void *vb2_dc_get_userptr(void *alloc_ctx, unsigned long vaddr, · 15 unmodified lines
691561 }
692562
693563 buf->dma_addr = sg_dma_address(sgt->sgl);
694− buf->size = size;
695564 buf->dma_sgt = sgt;
565+out:
566+ buf->size = size;
696567
697568 return buf;
698569
@@ -701,23 +572,13 @@ fail_map_sg: · 2 unmodified lines
701572 buf->dma_dir, &attrs);
702573
703574 fail_sgt_init:
704− if (!vma_is_io(buf->vma))
705− vb2_dc_sgt_foreach_page(sgt, put_page);
706575 sg_free_table(sgt);
707576
708577 fail_sgt:
709578 kfree(sgt);
710579
711−fail_get_user_pages:
712− if (pages && !vma_is_io(buf->vma))
713− while (n_pages)
714− put_page(pages[--n_pages]);
715−
716−fail_vma:
717− vb2_put_vma(buf->vma);
718−
719−fail_pages:
720− kfree(pages); /* kfree is NULL-proof */
580+fail_pfnvec:
581+ vb2_destroy_framevec(vec);
721582
722583 fail_buf:
723584 kfree(buf);
drivers/media/v4l2-core/videobuf2-dma-sg.c+15−76
@@ -38,6 +38,7 @@ struct vb2_dma_sg_buf { · 37 unmodified lines
3838 struct device *dev;
3939 void *vaddr;
4040 struct page **pages;
41+ struct frame_vector *vec;
4142 int offset;
4243 enum dma_data_direction dma_dir;
4344 struct sg_table sg_table;
@@ -51,7 +52,6 @@ struct vb2_dma_sg_buf { · 7 unmodified lines
5152 unsigned int num_pages;
5253 atomic_t refcount;
5354 struct vb2_vmarea_handler handler;
54− struct vm_area_struct *vma;
5555
5656 struct dma_buf_attachment *db_attach;
5757 };
@@ -225,25 +225,17 @@ static void vb2_dma_sg_finish(void *buf_priv) · 167 unmodified lines
225225 dma_sync_sg_for_cpu(buf->dev, sgt->sgl, sgt->nents, buf->dma_dir);
226226 }
227227
228−static inline int vma_is_io(struct vm_area_struct *vma)
229−{
230− return !!(vma->vm_flags & (VM_IO | VM_PFNMAP));
231−}
232−
233228 static void *vb2_dma_sg_get_userptr(void *alloc_ctx, unsigned long vaddr,
234229 unsigned long size,
235230 enum dma_data_direction dma_dir)
236231 {
237232 struct vb2_dma_sg_conf *conf = alloc_ctx;
238233 struct vb2_dma_sg_buf *buf;
239− unsigned long first, last;
240− int num_pages_from_user;
241− struct vm_area_struct *vma;
242234 struct sg_table *sgt;
243235 DEFINE_DMA_ATTRS(attrs);
236+ struct frame_vector *vec;
244237
245238 dma_set_attr(DMA_ATTR_SKIP_CPU_SYNC, &attrs);
246−
247239 buf = kzalloc(sizeof *buf, GFP_KERNEL);
248240 if (!buf)
249241 return NULL;
@@ -254,61 +246,19 @@ static void *vb2_dma_sg_get_userptr(void *alloc_ctx, unsigned long vaddr, · 4 unmodified lines
254246 buf->offset = vaddr & ~PAGE_MASK;
255247 buf->size = size;
256248 buf->dma_sgt = &buf->sg_table;
249+ vec = vb2_create_framevec(vaddr, size, buf->dma_dir == DMA_FROM_DEVICE);
250+ if (IS_ERR(vec))
251+ goto userptr_fail_pfnvec;
252+ buf->vec = vec;
257253
258− first = (vaddr & PAGE_MASK) >> PAGE_SHIFT;
259− last = ((vaddr + size - 1) & PAGE_MASK) >> PAGE_SHIFT;
260− buf->num_pages = last - first + 1;
261−
262− buf->pages = kzalloc(buf->num_pages * sizeof(struct page *),
263− GFP_KERNEL);
264− if (!buf->pages)
265− goto userptr_fail_alloc_pages;
266−
267− vma = find_vma(current->mm, vaddr);
268− if (!vma) {
269− dprintk(1, "no vma for address %lu\n", vaddr);
270− goto userptr_fail_find_vma;
271− }
272−
273− if (vma->vm_end < vaddr + size) {
274− dprintk(1, "vma at %lu is too small for %lu bytes\n",
275− vaddr, size);
276− goto userptr_fail_find_vma;
277− }
278−
279− buf->vma = vb2_get_vma(vma);
280− if (!buf->vma) {
281− dprintk(1, "failed to copy vma\n");
282− goto userptr_fail_find_vma;
283− }
284−
285− if (vma_is_io(buf->vma)) {
286− for (num_pages_from_user = 0;
287− num_pages_from_user < buf->num_pages;
288− ++num_pages_from_user, vaddr += PAGE_SIZE) {
289− unsigned long pfn;
290−
291− if (follow_pfn(vma, vaddr, &pfn)) {
292− dprintk(1, "no page for address %lu\n", vaddr);
293− break;
294− }
295− buf->pages[num_pages_from_user] = pfn_to_page(pfn);
296− }
297− } else
298− num_pages_from_user = get_user_pages(current, current->mm,
299− vaddr & PAGE_MASK,
300− buf->num_pages,
301− buf->dma_dir == DMA_FROM_DEVICE,
302− 1, /* force */
303− buf->pages,
304− NULL);
305−
306− if (num_pages_from_user != buf->num_pages)
307− goto userptr_fail_get_user_pages;
254+ buf->pages = frame_vector_pages(vec);
255+ if (IS_ERR(buf->pages))
256+ goto userptr_fail_sgtable;
257+ buf->num_pages = frame_vector_count(vec);
308258
309259 if (sg_alloc_table_from_pages(buf->dma_sgt, buf->pages,
310260 buf->num_pages, buf->offset, size, 0))
311− goto userptr_fail_alloc_table_from_pages;
261+ goto userptr_fail_sgtable;
312262
313263 sgt = &buf->sg_table;
314264 /*
@@ -324,17 +274,9 @@ static void *vb2_dma_sg_get_userptr(void *alloc_ctx, unsigned long vaddr, · 9 unmodified lines
324274
325275 userptr_fail_map:
326276 sg_free_table(&buf->sg_table);
327−userptr_fail_alloc_table_from_pages:
328−userptr_fail_get_user_pages:
329− dprintk(1, "get_user_pages requested/got: %d/%d]\n",
330− buf->num_pages, num_pages_from_user);
331− if (!vma_is_io(buf->vma))
332− while (--num_pages_from_user >= 0)
333− put_page(buf->pages[num_pages_from_user]);
334− vb2_put_vma(buf->vma);
335−userptr_fail_find_vma:
336− kfree(buf->pages);
337−userptr_fail_alloc_pages:
277+userptr_fail_sgtable:
278+ vb2_destroy_framevec(vec);
279+userptr_fail_pfnvec:
338280 kfree(buf);
339281 return NULL;
340282 }
@@ -362,11 +304,8 @@ static void vb2_dma_sg_put_userptr(void *buf_priv) · 21 unmodified lines
362304 while (--i >= 0) {
363305 if (buf->dma_dir == DMA_FROM_DEVICE)
364306 set_page_dirty_lock(buf->pages[i]);
365− if (!vma_is_io(buf->vma))
366− put_page(buf->pages[i]);
367307 }
368− kfree(buf->pages);
369− vb2_put_vma(buf->vma);
308+ vb2_destroy_framevec(buf->vec);
370309 kfree(buf);
371310 }
372311
drivers/media/v4l2-core/videobuf2-memops.c+46−102
@@ -23,118 +23,62 @@ · 22 unmodified lines
2323 #include <media/videobuf2-memops.h>
2424
2525 /**
26− * vb2_get_vma() - acquire and lock the virtual memory area
27− * @vma: given virtual memory area
26+ * vb2_create_framevec() - map virtual addresses to pfns
27+ * @start: Virtual user address where we start mapping
28+ * @length: Length of a range to map
29+ * @write: Should we map for writing into the area
2830 *
29− * This function attempts to acquire an area mapped in the userspace for
30− * the duration of a hardware operation. The area is "locked" by performing
31− * the same set of operation that are done when process calls fork() and
32− * memory areas are duplicated.
33− *
34− * Returns a copy of a virtual memory region on success or NULL.
35− */
36−struct vm_area_struct *vb2_get_vma(struct vm_area_struct *vma)
37−{
38− struct vm_area_struct *vma_copy;
39−
40− vma_copy = kmalloc(sizeof(*vma_copy), GFP_KERNEL);
41− if (vma_copy == NULL)
42− return NULL;
43−
44− if (vma->vm_ops && vma->vm_ops->open)
45− vma->vm_ops->open(vma);
46−
47− if (vma->vm_file)
48− get_file(vma->vm_file);
49−
50− memcpy(vma_copy, vma, sizeof(*vma));
51−
52− vma_copy->vm_mm = NULL;
53− vma_copy->vm_next = NULL;
54− vma_copy->vm_prev = NULL;
55−
56− return vma_copy;
57−}
58−EXPORT_SYMBOL_GPL(vb2_get_vma);
59−
60−/**
61− * vb2_put_userptr() - release a userspace virtual memory area
62− * @vma: virtual memory region associated with the area to be released
63− *
64− * This function releases the previously acquired memory area after a hardware
65− * operation.
31+ * This function allocates and fills in a vector with pfns corresponding to
32+ * virtual address range passed in arguments. If pfns have corresponding pages,
33+ * page references are also grabbed to pin pages in memory. The function
34+ * returns pointer to the vector on success and error pointer in case of
35+ * failure. Returned vector needs to be freed via vb2_destroy_pfnvec().
6636 */
67−void vb2_put_vma(struct vm_area_struct *vma)
37+struct frame_vector *vb2_create_framevec(unsigned long start,
38+ unsigned long length,
39+ bool write)
6840 {
69− if (!vma)
70− return;
71−
72− if (vma->vm_ops && vma->vm_ops->close)
73− vma->vm_ops->close(vma);
74−
75− if (vma->vm_file)
76− fput(vma->vm_file);
77−
78− kfree(vma);
41+ int ret;
42+ unsigned long first, last;
43+ unsigned long nr;
44+ struct frame_vector *vec;
45+
46+ first = start >> PAGE_SHIFT;
47+ last = (start + length - 1) >> PAGE_SHIFT;
48+ nr = last - first + 1;
49+ vec = frame_vector_create(nr);
50+ if (!vec)
51+ return ERR_PTR(-ENOMEM);
52+ ret = get_vaddr_frames(start, nr, write, 1, vec);
53+ if (ret < 0)
54+ goto out_destroy;
55+ /* We accept only complete set of PFNs */
56+ if (ret != nr) {
57+ ret = -EFAULT;
58+ goto out_release;
59+ }
60+ return vec;
61+out_release:
62+ put_vaddr_frames(vec);
63+out_destroy:
64+ frame_vector_destroy(vec);
65+ return ERR_PTR(ret);
7966 }
80−EXPORT_SYMBOL_GPL(vb2_put_vma);
67+EXPORT_SYMBOL(vb2_create_framevec);
8168
8269 /**
83− * vb2_get_contig_userptr() - lock physically contiguous userspace mapped memory
84− * @vaddr: starting virtual address of the area to be verified
85− * @size: size of the area
86− * @res_paddr: will return physical address for the given vaddr
87− * @res_vma: will return locked copy of struct vm_area for the given area
88− *
89− * This function will go through memory area of size @size mapped at @vaddr and
90− * verify that the underlying physical pages are contiguous. If they are
91− * contiguous the virtual memory area is locked and a @res_vma is filled with
92− * the copy and @res_pa set to the physical address of the buffer.
70+ * vb2_destroy_framevec() - release vector of mapped pfns
71+ * @vec: vector of pfns / pages to release
9372 *
94− * Returns 0 on success.
73+ * This releases references to all pages in the vector @vec (if corresponding
74+ * pfns are backed by pages) and frees the passed vector.
9575 */
96−int vb2_get_contig_userptr(unsigned long vaddr, unsigned long size,
97− struct vm_area_struct **res_vma, dma_addr_t *res_pa)
76+void vb2_destroy_framevec(struct frame_vector *vec)
9877 {
99− struct mm_struct *mm = current->mm;
100− struct vm_area_struct *vma;
101− unsigned long offset, start, end;
102− unsigned long this_pfn, prev_pfn;
103− dma_addr_t pa = 0;
104−
105− start = vaddr;
106− offset = start & ~PAGE_MASK;
107− end = start + size;
108−
109− vma = find_vma(mm, start);
110−
111− if (vma == NULL || vma->vm_end < end)
112− return -EFAULT;
113−
114− for (prev_pfn = 0; start < end; start += PAGE_SIZE) {
115− int ret = follow_pfn(vma, start, &this_pfn);
116− if (ret)
117− return ret;
118−
119− if (prev_pfn == 0)
120− pa = this_pfn << PAGE_SHIFT;
121− else if (this_pfn != prev_pfn + 1)
122− return -EFAULT;
123−
124− prev_pfn = this_pfn;
125− }
126−
127− /*
128− * Memory is contiguous, lock vma and return to the caller
129− */
130− *res_vma = vb2_get_vma(vma);
131− if (*res_vma == NULL)
132− return -ENOMEM;
133−
134− *res_pa = pa + offset;
135− return 0;
78+ put_vaddr_frames(vec);
79+ frame_vector_destroy(vec);
13680 }
137−EXPORT_SYMBOL_GPL(vb2_get_contig_userptr);
81+EXPORT_SYMBOL(vb2_destroy_framevec);
13882
13983 /**
14084 * vb2_common_vm_open() - increase refcount of the vma
drivers/media/v4l2-core/videobuf2-vmalloc.c+36−54
@@ -23,11 +23,9 @@ · 22 unmodified lines
2323
2424 struct vb2_vmalloc_buf {
2525 void *vaddr;
26− struct page **pages;
27− struct vm_area_struct *vma;
26+ struct frame_vector *vec;
2827 enum dma_data_direction dma_dir;
2928 unsigned long size;
30− unsigned int n_pages;
3129 atomic_t refcount;
3230 struct vb2_vmarea_handler handler;
3331 struct dma_buf *dbuf;
@@ -76,10 +74,8 @@ static void *vb2_vmalloc_get_userptr(void *alloc_ctx, unsigned long vaddr, · 42 unmodified lines
7674 enum dma_data_direction dma_dir)
7775 {
7876 struct vb2_vmalloc_buf *buf;
79− unsigned long first, last;
80− int n_pages, offset;
81− struct vm_area_struct *vma;
82− dma_addr_t physp;
77+ struct frame_vector *vec;
78+ int n_pages, offset, i;
8379
8480 buf = kzalloc(sizeof(*buf), GFP_KERNEL);
8581 if (!buf)
@@ -88,51 +84,36 @@ static void *vb2_vmalloc_get_userptr(void *alloc_ctx, unsigned long vaddr, · 2 unmodified lines
8884 buf->dma_dir = dma_dir;
8985 offset = vaddr & ~PAGE_MASK;
9086 buf->size = size;
91−
92−
93− vma = find_vma(current->mm, vaddr);
94− if (vma && (vma->vm_flags & VM_PFNMAP) && (vma->vm_pgoff)) {
95− if (vb2_get_contig_userptr(vaddr, size, &vma, &physp))
96− goto fail_pages_array_alloc;
97− buf->vma = vma;
98− buf->vaddr = (__force void *)ioremap_nocache(physp, size);
99− if (!buf->vaddr)
100− goto fail_pages_array_alloc;
87+ vec = vb2_create_framevec(vaddr, size, dma_dir == DMA_FROM_DEVICE);
88+ if (IS_ERR(vec))
89+ goto fail_pfnvec_create;
90+ buf->vec = vec;
91+ n_pages = frame_vector_count(vec);
92+ if (frame_vector_to_pages(vec) < 0) {
93+ unsigned long *nums = frame_vector_pfns(vec);
94+
95+ /*
96+ * We cannot get page pointers for these pfns. Check memory is
97+ * physically contiguous and use direct mapping.
98+ */
99+ for (i = 1; i < n_pages; i++)
100+ if (nums[i-1] + 1 != nums[i])
101+ goto fail_map;
102+ buf->vaddr = (__force void *)
103+ ioremap_nocache(nums[0] << PAGE_SHIFT, size);
101104 } else {
102− first = vaddr >> PAGE_SHIFT;
103− last = (vaddr + size - 1) >> PAGE_SHIFT;
104− buf->n_pages = last - first + 1;
105− buf->pages = kzalloc(buf->n_pages * sizeof(struct page *),
106− GFP_KERNEL);
107− if (!buf->pages)
108− goto fail_pages_array_alloc;
109−
110− /* current->mm->mmap_sem is taken by videobuf2 core */
111− n_pages = get_user_pages(current, current->mm,
112− vaddr & PAGE_MASK, buf->n_pages,
113− dma_dir == DMA_FROM_DEVICE,
114− 1, /* force */
115− buf->pages, NULL);
116− if (n_pages != buf->n_pages)
117− goto fail_get_user_pages;
118−
119− buf->vaddr = vm_map_ram(buf->pages, buf->n_pages, -1,
105+ buf->vaddr = vm_map_ram(frame_vector_pages(vec), n_pages, -1,
120106 PAGE_KERNEL);
121− if (!buf->vaddr)
122− goto fail_get_user_pages;
123107 }
124108
109+ if (!buf->vaddr)
110+ goto fail_map;
125111 buf->vaddr += offset;
126112 return buf;
127113
128−fail_get_user_pages:
129− pr_debug("get_user_pages requested/got: %d/%d]\n", n_pages,
130− buf->n_pages);
131− while (--n_pages >= 0)
132− put_page(buf->pages[n_pages]);
133− kfree(buf->pages);
134−
135−fail_pages_array_alloc:
114+fail_map:
115+ vb2_destroy_framevec(vec);
116+fail_pfnvec_create:
136117 kfree(buf);
137118
138119 return NULL;
@@ -143,20 +124,21 @@ static void vb2_vmalloc_put_userptr(void *buf_priv) · 4 unmodified lines
143124 struct vb2_vmalloc_buf *buf = buf_priv;
144125 unsigned long vaddr = (unsigned long)buf->vaddr & PAGE_MASK;
145126 unsigned int i;
127+ struct page **pages;
128+ unsigned int n_pages;
146129
147− if (buf->pages) {
130+ if (!buf->vec->is_pfns) {
131+ n_pages = frame_vector_count(buf->vec);
132+ pages = frame_vector_pages(buf->vec);
148133 if (vaddr)
149− vm_unmap_ram((void *)vaddr, buf->n_pages);
150− for (i = 0; i < buf->n_pages; ++i) {
151− if (buf->dma_dir == DMA_FROM_DEVICE)
152− set_page_dirty_lock(buf->pages[i]);
153− put_page(buf->pages[i]);
154− }
155− kfree(buf->pages);
134+ vm_unmap_ram((void *)vaddr, n_pages);
135+ if (buf->dma_dir == DMA_FROM_DEVICE)
136+ for (i = 0; i < n_pages; i++)
137+ set_page_dirty_lock(pages[i]);
156138 } else {
157− vb2_put_vma(buf->vma);
158139 iounmap((__force void __iomem *)buf->vaddr);
159140 }
141+ vb2_destroy_framevec(buf->vec);
160142 kfree(buf);
161143 }
162144
include/linux/mm.h+44−0
@@ -20,6 +20,7 @@ · 19 unmodified lines
2020 #include <linux/shrinker.h>
2121 #include <linux/resource.h>
2222 #include <linux/page_ext.h>
23+#include <linux/err.h>
2324
2425 struct mempolicy;
2526 struct anon_vma;
@@ -1214,6 +1215,49 @@ long get_user_pages_unlocked(struct task_struct *tsk, struct mm_struct *mm, · 1188 unmodified lines
12141215 int write, int force, struct page **pages);
12151216 int get_user_pages_fast(unsigned long start, int nr_pages, int write,
12161217 struct page **pages);
1218+
1219+/* Container for pinned pfns / pages */
1220+struct frame_vector {
1221+ unsigned int nr_allocated; /* Number of frames we have space for */
1222+ unsigned int nr_frames; /* Number of frames stored in ptrs array */
1223+ bool got_ref; /* Did we pin pages by getting page ref? */
1224+ bool is_pfns; /* Does array contain pages or pfns? */
1225+ void *ptrs[0]; /* Array of pinned pfns / pages. Use
1226+ * pfns_vector_pages() or pfns_vector_pfns()
1227+ * for access */
1228+};
1229+
1230+struct frame_vector *frame_vector_create(unsigned int nr_frames);
1231+void frame_vector_destroy(struct frame_vector *vec);
1232+int get_vaddr_frames(unsigned long start, unsigned int nr_pfns,
1233+ bool write, bool force, struct frame_vector *vec);
1234+void put_vaddr_frames(struct frame_vector *vec);
1235+int frame_vector_to_pages(struct frame_vector *vec);
1236+void frame_vector_to_pfns(struct frame_vector *vec);
1237+
1238+static inline unsigned int frame_vector_count(struct frame_vector *vec)
1239+{
1240+ return vec->nr_frames;
1241+}
1242+
1243+static inline struct page **frame_vector_pages(struct frame_vector *vec)
1244+{
1245+ if (vec->is_pfns) {
1246+ int err = frame_vector_to_pages(vec);
1247+
1248+ if (err)
1249+ return ERR_PTR(err);
1250+ }
1251+ return (struct page **)(vec->ptrs);
1252+}
1253+
1254+static inline unsigned long *frame_vector_pfns(struct frame_vector *vec)
1255+{
1256+ if (!vec->is_pfns)
1257+ frame_vector_to_pfns(vec);
1258+ return (unsigned long *)(vec->ptrs);
1259+}
1260+
12171261 struct kvec;
12181262 int get_kernel_pages(const struct kvec *iov, int nr_pages, int write,
12191263 struct page **pages);
include/media/videobuf2-memops.h+5−6
@@ -15,6 +15,7 @@ · 14 unmodified lines
1515 #define _MEDIA_VIDEOBUF2_MEMOPS_H
1616
1717 #include <media/videobuf2-core.h>
18+#include <linux/mm.h>
1819
1920 /**
2021 * struct vb2_vmarea_handler - common vma refcount tracking handler
@@ -31,11 +32,9 @@ struct vb2_vmarea_handler { · 10 unmodified lines
3132
3233 extern const struct vm_operations_struct vb2_common_vm_ops;
3334
34−int vb2_get_contig_userptr(unsigned long vaddr, unsigned long size,
35− struct vm_area_struct **res_vma, dma_addr_t *res_pa);
36−
37−struct vm_area_struct *vb2_get_vma(struct vm_area_struct *vma);
38−void vb2_put_vma(struct vm_area_struct *vma);
39−
35+struct frame_vector *vb2_create_framevec(unsigned long start,
36+ unsigned long length,
37+ bool write);
38+void vb2_destroy_framevec(struct frame_vector *vec);
4039
4140 #endif
mm/Kconfig+3−0
@@ -677,3 +677,6 @@ config ZONE_DEVICE · 676 unmodified lines
677677 mapping in an O_DIRECT operation, among other things.
678678
679679 If FS_DAX is enabled, then say Y.
680+
681+config FRAME_VECTOR
682+ bool
mm/Makefile+1−0
@@ -80,3 +80,4 @@ obj-$(CONFIG_PAGE_EXTENSION) += page_ext.o · 79 unmodified lines
8080 obj-$(CONFIG_CMA_DEBUGFS) += cma_debug.o
8181 obj-$(CONFIG_USERFAULTFD) += userfaultfd.o
8282 obj-$(CONFIG_IDLE_PAGE_TRACKING) += page_idle.o
83+obj-$(CONFIG_FRAME_VECTOR) += frame_vector.o
mm/frame_vector.c+230−0
@@ -0,0 +1,230 @@
1+#include <linux/kernel.h>
2+#include <linux/errno.h>
3+#include <linux/err.h>
4+#include <linux/mm.h>
5+#include <linux/slab.h>
6+#include <linux/vmalloc.h>
7+#include <linux/pagemap.h>
8+#include <linux/sched.h>
9+
10+/*
11+ * get_vaddr_frames() - map virtual addresses to pfns
12+ * @start: starting user address
13+ * @nr_frames: number of pages / pfns from start to map
14+ * @write: whether pages will be written to by the caller
15+ * @force: whether to force write access even if user mapping is
16+ * readonly. See description of the same argument of
17+ get_user_pages().
18+ * @vec: structure which receives pages / pfns of the addresses mapped.
19+ * It should have space for at least nr_frames entries.
20+ *
21+ * This function maps virtual addresses from @start and fills @vec structure
22+ * with page frame numbers or page pointers to corresponding pages (choice
23+ * depends on the type of the vma underlying the virtual address). If @start
24+ * belongs to a normal vma, the function grabs reference to each of the pages
25+ * to pin them in memory. If @start belongs to VM_IO | VM_PFNMAP vma, we don't
26+ * touch page structures and the caller must make sure pfns aren't reused for
27+ * anything else while he is using them.
28+ *
29+ * The function returns number of pages mapped which may be less than
30+ * @nr_frames. In particular we stop mapping if there are more vmas of
31+ * different type underlying the specified range of virtual addresses.
32+ * When the function isn't able to map a single page, it returns error.
33+ *
34+ * This function takes care of grabbing mmap_sem as necessary.
35+ */
36+int get_vaddr_frames(unsigned long start, unsigned int nr_frames,
37+ bool write, bool force, struct frame_vector *vec)
38+{
39+ struct mm_struct *mm = current->mm;
40+ struct vm_area_struct *vma;
41+ int ret = 0;
42+ int err;
43+ int locked;
44+
45+ if (nr_frames == 0)
46+ return 0;
47+
48+ if (WARN_ON_ONCE(nr_frames > vec->nr_allocated))
49+ nr_frames = vec->nr_allocated;
50+
51+ down_read(&mm->mmap_sem);
52+ locked = 1;
53+ vma = find_vma_intersection(mm, start, start + 1);
54+ if (!vma) {
55+ ret = -EFAULT;
56+ goto out;
57+ }
58+ if (!(vma->vm_flags & (VM_IO | VM_PFNMAP))) {
59+ vec->got_ref = true;
60+ vec->is_pfns = false;
61+ ret = get_user_pages_locked(current, mm, start, nr_frames,
62+ write, force, (struct page **)(vec->ptrs), &locked);
63+ goto out;
64+ }
65+
66+ vec->got_ref = false;
67+ vec->is_pfns = true;
68+ do {
69+ unsigned long *nums = frame_vector_pfns(vec);
70+
71+ while (ret < nr_frames && start + PAGE_SIZE <= vma->vm_end) {
72+ err = follow_pfn(vma, start, &nums[ret]);
73+ if (err) {
74+ if (ret == 0)
75+ ret = err;
76+ goto out;
77+ }
78+ start += PAGE_SIZE;
79+ ret++;
80+ }
81+ /*
82+ * We stop if we have enough pages or if VMA doesn't completely
83+ * cover the tail page.
84+ */
85+ if (ret >= nr_frames || start < vma->vm_end)
86+ break;
87+ vma = find_vma_intersection(mm, start, start + 1);
88+ } while (vma && vma->vm_flags & (VM_IO | VM_PFNMAP));
89+out:
90+ if (locked)
91+ up_read(&mm->mmap_sem);
92+ if (!ret)
93+ ret = -EFAULT;
94+ if (ret > 0)
95+ vec->nr_frames = ret;
96+ return ret;
97+}
98+EXPORT_SYMBOL(get_vaddr_frames);
99+
100+/**
101+ * put_vaddr_frames() - drop references to pages if get_vaddr_frames() acquired
102+ * them
103+ * @vec: frame vector to put
104+ *
105+ * Drop references to pages if get_vaddr_frames() acquired them. We also
106+ * invalidate the frame vector so that it is prepared for the next call into
107+ * get_vaddr_frames().
108+ */
109+void put_vaddr_frames(struct frame_vector *vec)
110+{
111+ int i;
112+ struct page **pages;
113+
114+ if (!vec->got_ref)
115+ goto out;
116+ pages = frame_vector_pages(vec);
117+ /*
118+ * frame_vector_pages() might needed to do a conversion when
119+ * get_vaddr_frames() got pages but vec was later converted to pfns.
120+ * But it shouldn't really fail to convert pfns back...
121+ */
122+ if (WARN_ON(IS_ERR(pages)))
123+ goto out;
124+ for (i = 0; i < vec->nr_frames; i++)
125+ put_page(pages[i]);
126+ vec->got_ref = false;
127+out:
128+ vec->nr_frames = 0;
129+}
130+EXPORT_SYMBOL(put_vaddr_frames);
131+
132+/**
133+ * frame_vector_to_pages - convert frame vector to contain page pointers
134+ * @vec: frame vector to convert
135+ *
136+ * Convert @vec to contain array of page pointers. If the conversion is
137+ * successful, return 0. Otherwise return an error. Note that we do not grab
138+ * page references for the page structures.
139+ */
140+int frame_vector_to_pages(struct frame_vector *vec)
141+{
142+ int i;
143+ unsigned long *nums;
144+ struct page **pages;
145+
146+ if (!vec->is_pfns)
147+ return 0;
148+ nums = frame_vector_pfns(vec);
149+ for (i = 0; i < vec->nr_frames; i++)
150+ if (!pfn_valid(nums[i]))
151+ return -EINVAL;
152+ pages = (struct page **)nums;
153+ for (i = 0; i < vec->nr_frames; i++)
154+ pages[i] = pfn_to_page(nums[i]);
155+ vec->is_pfns = false;
156+ return 0;
157+}
158+EXPORT_SYMBOL(frame_vector_to_pages);
159+
160+/**
161+ * frame_vector_to_pfns - convert frame vector to contain pfns
162+ * @vec: frame vector to convert
163+ *
164+ * Convert @vec to contain array of pfns.
165+ */
166+void frame_vector_to_pfns(struct frame_vector *vec)
167+{
168+ int i;
169+ unsigned long *nums;
170+ struct page **pages;
171+
172+ if (vec->is_pfns)
173+ return;
174+ pages = (struct page **)(vec->ptrs);
175+ nums = (unsigned long *)pages;
176+ for (i = 0; i < vec->nr_frames; i++)
177+ nums[i] = page_to_pfn(pages[i]);
178+ vec->is_pfns = true;
179+}
180+EXPORT_SYMBOL(frame_vector_to_pfns);
181+
182+/**
183+ * frame_vector_create() - allocate & initialize structure for pinned pfns
184+ * @nr_frames: number of pfns slots we should reserve
185+ *
186+ * Allocate and initialize struct pinned_pfns to be able to hold @nr_pfns
187+ * pfns.
188+ */
189+struct frame_vector *frame_vector_create(unsigned int nr_frames)
190+{
191+ struct frame_vector *vec;
192+ int size = sizeof(struct frame_vector) + sizeof(void *) * nr_frames;
193+
194+ if (WARN_ON_ONCE(nr_frames == 0))
195+ return NULL;
196+ /*
197+ * This is absurdly high. It's here just to avoid strange effects when
198+ * arithmetics overflows.
199+ */
200+ if (WARN_ON_ONCE(nr_frames > INT_MAX / sizeof(void *) / 2))
201+ return NULL;
202+ /*
203+ * Avoid higher order allocations, use vmalloc instead. It should
204+ * be rare anyway.
205+ */
206+ if (size <= PAGE_SIZE)
207+ vec = kmalloc(size, GFP_KERNEL);
208+ else
209+ vec = vmalloc(size);
210+ if (!vec)
211+ return NULL;
212+ vec->nr_allocated = nr_frames;
213+ vec->nr_frames = 0;
214+ return vec;
215+}
216+EXPORT_SYMBOL(frame_vector_create);
217+
218+/**
219+ * frame_vector_destroy() - free memory allocated to carry frame vector
220+ * @vec: Frame vector to free
221+ *
222+ * Free structure allocated by frame_vector_create() to carry frames.
223+ */
224+void frame_vector_destroy(struct frame_vector *vec)
225+{
226+ /* Make sure put_vaddr_frames() got called properly... */
227+ VM_BUG_ON(vec->nr_frames > 0);
228+ kvfree(vec);
229+}
230+EXPORT_SYMBOL(frame_vector_destroy);