Re: [PATCH] MAINTAINERS & files: Canonize the e-mails I use at files

2018-05-09 Thread Jan Kara
On Fri 04-05-18 08:33:55, Mauro Carvalho Chehab wrote:
> Em Fri, 04 May 2018 13:58:39 +0300
> Jani Nikula <jani.nik...@linux.intel.com> escreveu:
> 
> > On Fri, 04 May 2018, Mauro Carvalho Chehab <mchehab+sams...@kernel.org> 
> > wrote:
> > > From now on, I'll start using my @kernel.org as my development e-mail.
> > >
> > > As such, let's remove the entries that point to the old
> > > mche...@s-opensource.com at MAINTAINERS file.
> > >
> > > For the files written with a copyright with mchehab@s-opensource,
> > > let's keep Samsung on their names, using mchehab+sams...@kernel.org,
> > > in order to keep pointing to my employer, with sponsors the work.
> > >
> > > For the files written before I join Samsung (on July, 4 2013),
> > > let's just use mche...@kernel.org.
> > >
> > > For bug reports, we can simply point to just kernel.org, as
> > > this will reach my mchehab+samsung inbox anyway.  
> > 
> > I suppose this begs the question, why do we insist on adding our email
> > addresses all over the place? On a quick grep, there are at least 40k+
> > email addresses in the sources. Do we expect them all to be up-to-date
> > too?
> 
> That's a good question.
> 
> The usual use case is that the e-mail allows people to contact developers
> if needed. Such contact could simply due to something like handling SPDX
> or other license-related issues or for troubleshooting.
> 
> There's also another reason (with IMHO, is more relevant): just the name
> may not be enough to uniquely identify the author of some code. While
> that might happen on occidental Countries, this is a way more relevant
> for Asian Countries. For example, there are very few surnames on
> some Countries there[1], and common names are usually... common. So, it
> is not hard to find several people with exactly the same name working at
> the same company. I've seen e-mails from those people that are things like
> john.doe51@some.company, john.doe69@some.company, ...
> 
> [1] For example: https://en.wikipedia.org/wiki/List_of_Korean_surnames.
> 
> The e-mail is a way to uniquely identify a person. If we remove it,
> then we may need to add another thing instead (like parents names,
> security number or whatever), with would be weird, IMO. 
> 
> As we all use e-mails to uniquely identify contributors submissions,
> IMHO, the best is to keep using e-mails. The side effect is that
> we should keep those emails updated.

Understood but e-mails in code get stale eventually as people rarely update
those. So I think having a contact email in MAINTAINERS and git logs is
enough for practical purposes.

Honza
-- 
Jan Kara <j...@suse.com>
SUSE Labs, CR


Re: [PATCH v2 3/4] [media] v4l2: disable filesystem-dax mapping support

2017-11-27 Thread Jan Kara
On Tue 14-11-17 11:56:45, Dan Williams wrote:
> V4L2 memory registrations are incompatible with filesystem-dax that
> needs the ability to revoke dma access to a mapping at will, or
> otherwise allow the kernel to wait for completion of DMA. The
> filesystem-dax implementation breaks the traditional solution of
> truncate of active file backed mappings since there is no page-cache
> page we can orphan to sustain ongoing DMA.
> 
> If v4l2 wants to support long lived DMA mappings it needs to arrange to
> hold a file lease or use some other mechanism so that the kernel can
> coordinate revoking DMA access when the filesystem needs to truncate
> mappings.
> 
> Reported-by: Jan Kara <j...@suse.cz>
> Cc: Mauro Carvalho Chehab <mche...@kernel.org>
> Cc: linux-media@vger.kernel.org
> Cc: <sta...@vger.kernel.org>
> Fixes: 3565fce3a659 ("mm, x86: get_user_pages() for dax mappings")
> Signed-off-by: Dan Williams <dan.j.willi...@intel.com>

Looks good to me. You can add:

Reviewed-by: Jan Kara <j...@suse.cz>

Honza

> ---
>  drivers/media/v4l2-core/videobuf-dma-sg.c |5 +++--
>  1 file changed, 3 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/media/v4l2-core/videobuf-dma-sg.c 
> b/drivers/media/v4l2-core/videobuf-dma-sg.c
> index 0b5c43f7e020..f412429cf5ba 100644
> --- a/drivers/media/v4l2-core/videobuf-dma-sg.c
> +++ b/drivers/media/v4l2-core/videobuf-dma-sg.c
> @@ -185,12 +185,13 @@ static int videobuf_dma_init_user_locked(struct 
> videobuf_dmabuf *dma,
>   dprintk(1, "init user [0x%lx+0x%lx => %d pages]\n",
>   data, size, dma->nr_pages);
>  
> - err = get_user_pages(data & PAGE_MASK, dma->nr_pages,
> + err = get_user_pages_longterm(data & PAGE_MASK, dma->nr_pages,
>flags, dma->pages, NULL);
>  
>   if (err != dma->nr_pages) {
>   dma->nr_pages = (err >= 0) ? err : 0;
> - dprintk(1, "get_user_pages: err=%d [%d]\n", err, dma->nr_pages);
> + dprintk(1, "get_user_pages_longterm: err=%d [%d]\n", err,
> + dma->nr_pages);
>   return err < 0 ? err : -EINVAL;
>   }
>   return 0;
> 
-- 
Jan Kara <j...@suse.com>
SUSE Labs, CR


Re: [PATCH v2 2/4] mm: fail get_vaddr_frames() for filesystem-dax mappings

2017-11-27 Thread Jan Kara
On Tue 14-11-17 11:56:39, Dan Williams wrote:
> Until there is a solution to the dma-to-dax vs truncate problem it is
> not safe to allow V4L2, Exynos, and other frame vector users to create
> long standing / irrevocable memory registrations against filesytem-dax
> vmas.
> 
> Cc: Inki Dae <inki@samsung.com>
> Cc: Seung-Woo Kim <sw0312@samsung.com>
> Cc: Joonyoung Shim <jy0922.s...@samsung.com>
> Cc: Kyungmin Park <kyungmin.p...@samsung.com>
> Cc: Mauro Carvalho Chehab <mche...@kernel.org>
> Cc: linux-media@vger.kernel.org
> Cc: Jan Kara <j...@suse.cz>
> Cc: Mel Gorman <mgor...@suse.de>
> Cc: Vlastimil Babka <vba...@suse.cz>
> Cc: Andrew Morton <a...@linux-foundation.org>
> Cc: <sta...@vger.kernel.org>
> Fixes: 3565fce3a659 ("mm, x86: get_user_pages() for dax mappings")
> Signed-off-by: Dan Williams <dan.j.willi...@intel.com>

Makes sense. I'd just note that in principle get_vaddr_frames() is no more
long-term than get_user_pages(). It is just so that all the users of
get_vaddr_frames() currently want a long-term reference. Maybe could you
add here also a comment that the vma_is_fsdax() check is there because all
users of this function want a long term page reference? With that you can
add:

Reviewed-by: Jan Kara <j...@suse.cz>

Honza

> ---
>  mm/frame_vector.c |4 
>  1 file changed, 4 insertions(+)
> 
> diff --git a/mm/frame_vector.c b/mm/frame_vector.c
> index 72ebec18629c..d2fdbeaadc8b 100644
> --- a/mm/frame_vector.c
> +++ b/mm/frame_vector.c
> @@ -52,6 +52,10 @@ int get_vaddr_frames(unsigned long start, unsigned int 
> nr_frames,
>   ret = -EFAULT;
>   goto out;
>   }
> +
> + if (vma_is_fsdax(vma))
> + return -EOPNOTSUPP;
> +
>   if (!(vma->vm_flags & (VM_IO | VM_PFNMAP))) {
>   vec->got_ref = true;
>   vec->is_pfns = false;
> 
-- 
Jan Kara <j...@suse.com>
SUSE Labs, CR


Re: [PATCH 05/10] mm: replace get_vaddr_frames() write/force parameters with gup_flags

2016-10-19 Thread Jan Kara
On Thu 13-10-16 01:20:15, Lorenzo Stoakes wrote:
> This patch removes the write and force parameters from get_vaddr_frames() and
> replaces them with a gup_flags parameter to make the use of FOLL_FORCE 
> explicit
> in callers as use of this flag can result in surprising behaviour (and hence
> bugs) within the mm subsystem.
> 
> Signed-off-by: Lorenzo Stoakes <lstoa...@gmail.com>

Looks good. You can add:

Reviewed-by: Jan Kara <j...@suse.cz>

Honza

> ---
>  drivers/gpu/drm/exynos/exynos_drm_g2d.c|  3 ++-
>  drivers/media/platform/omap/omap_vout.c|  2 +-
>  drivers/media/v4l2-core/videobuf2-memops.c |  6 +-
>  include/linux/mm.h |  2 +-
>  mm/frame_vector.c  | 13 ++---
>  5 files changed, 11 insertions(+), 15 deletions(-)
> 
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c 
> b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
> index aa92dec..fbd13fa 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
> @@ -488,7 +488,8 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct 
> drm_device *drm_dev,
>   goto err_free;
>   }
>  
> - ret = get_vaddr_frames(start, npages, true, true, g2d_userptr->vec);
> + ret = get_vaddr_frames(start, npages, FOLL_FORCE | FOLL_WRITE,
> + g2d_userptr->vec);
>   if (ret != npages) {
>   DRM_ERROR("failed to get user pages from userptr.\n");
>   if (ret < 0)
> diff --git a/drivers/media/platform/omap/omap_vout.c 
> b/drivers/media/platform/omap/omap_vout.c
> index e668dde..a31b95c 100644
> --- a/drivers/media/platform/omap/omap_vout.c
> +++ b/drivers/media/platform/omap/omap_vout.c
> @@ -214,7 +214,7 @@ static int omap_vout_get_userptr(struct videobuf_buffer 
> *vb, u32 virtp,
>   if (!vec)
>   return -ENOMEM;
>  
> - ret = get_vaddr_frames(virtp, 1, true, false, vec);
> + ret = get_vaddr_frames(virtp, 1, FOLL_WRITE, vec);
>   if (ret != 1) {
>   frame_vector_destroy(vec);
>   return -EINVAL;
> diff --git a/drivers/media/v4l2-core/videobuf2-memops.c 
> b/drivers/media/v4l2-core/videobuf2-memops.c
> index 3c3b517..1cd322e 100644
> --- a/drivers/media/v4l2-core/videobuf2-memops.c
> +++ b/drivers/media/v4l2-core/videobuf2-memops.c
> @@ -42,6 +42,10 @@ struct frame_vector *vb2_create_framevec(unsigned long 
> start,
>   unsigned long first, last;
>   unsigned long nr;
>   struct frame_vector *vec;
> + unsigned int flags = FOLL_FORCE;
> +
> + if (write)
> + flags |= FOLL_WRITE;
>  
>   first = start >> PAGE_SHIFT;
>   last = (start + length - 1) >> PAGE_SHIFT;
> @@ -49,7 +53,7 @@ struct frame_vector *vb2_create_framevec(unsigned long 
> start,
>   vec = frame_vector_create(nr);
>   if (!vec)
>   return ERR_PTR(-ENOMEM);
> - ret = get_vaddr_frames(start & PAGE_MASK, nr, write, true, vec);
> + ret = get_vaddr_frames(start & PAGE_MASK, nr, flags, vec);
>   if (ret < 0)
>   goto out_destroy;
>   /* We accept only complete set of PFNs */
> diff --git a/include/linux/mm.h b/include/linux/mm.h
> index 27ab538..5ff084f6 100644
> --- a/include/linux/mm.h
> +++ b/include/linux/mm.h
> @@ -1305,7 +1305,7 @@ struct frame_vector {
>  struct frame_vector *frame_vector_create(unsigned int nr_frames);
>  void frame_vector_destroy(struct frame_vector *vec);
>  int get_vaddr_frames(unsigned long start, unsigned int nr_pfns,
> -  bool write, bool force, struct frame_vector *vec);
> +  unsigned int gup_flags, struct frame_vector *vec);
>  void put_vaddr_frames(struct frame_vector *vec);
>  int frame_vector_to_pages(struct frame_vector *vec);
>  void frame_vector_to_pfns(struct frame_vector *vec);
> diff --git a/mm/frame_vector.c b/mm/frame_vector.c
> index 81b6749..db77dcb 100644
> --- a/mm/frame_vector.c
> +++ b/mm/frame_vector.c
> @@ -11,10 +11,7 @@
>   * get_vaddr_frames() - map virtual addresses to pfns
>   * @start:   starting user address
>   * @nr_frames:   number of pages / pfns from start to map
> - * @write:   whether pages will be written to by the caller
> - * @force:   whether to force write access even if user mapping is
> - *   readonly. See description of the same argument of
> - get_user_pages().
> + * @gup_flags:   flags modifying lookup behaviour
>   * @vec: structure which receives pages / pfns of the addresses mapped.
>   *   It should have space for at least nr_frames entries.
&g

Re: [PATCH 04/10] mm: replace get_user_pages_locked() write/force parameters with gup_flags

2016-10-19 Thread Jan Kara
On Thu 13-10-16 01:20:14, Lorenzo Stoakes wrote:
> This patch removes the write and force parameters from get_user_pages_locked()
> and replaces them with a gup_flags parameter to make the use of FOLL_FORCE
> explicit in callers as use of this flag can result in surprising behaviour 
> (and
> hence bugs) within the mm subsystem.
> 
> Signed-off-by: Lorenzo Stoakes <lstoa...@gmail.com>

After our discussion the patch looks good to me. You can add:

Reviewed-by: Jan Kara <j...@suse.cz>

        Honza
-- 
Jan Kara <j...@suse.com>
SUSE Labs, CR
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 08/10] mm: replace __access_remote_vm() write parameter with gup_flags

2016-10-19 Thread Jan Kara
On Thu 13-10-16 01:20:18, Lorenzo Stoakes wrote:
> This patch removes the write parameter from __access_remote_vm() and replaces 
> it
> with a gup_flags parameter as use of this function previously _implied_
> FOLL_FORCE, whereas after this patch callers explicitly pass this flag.
> 
> We make this explicit as use of FOLL_FORCE can result in surprising behaviour
> (and hence bugs) within the mm subsystem.
> 
> Signed-off-by: Lorenzo Stoakes <lstoa...@gmail.com>

So I'm not convinced this (and the following two patches) is actually
helping much. By grepping for FOLL_FORCE we will easily see that any caller
of access_remote_vm() gets that semantics and can thus continue search
accordingly (it is much simpler than searching for all get_user_pages()
users and extracting from parameter lists what they actually pass as
'force' argument). Sure it makes somewhat more visible to callers of
access_remote_vm() that they get FOLL_FORCE semantics but OTOH it also
opens a space for issues where a caller of access_remote_vm() actually
wants FOLL_FORCE (and currently all of them want it) and just mistakenly
does not set it. All in all I'd prefer to keep access_remote_vm() and
friends as is...

Honza

> ---
>  mm/memory.c | 23 +++
>  mm/nommu.c  |  9 ++---
>  2 files changed, 21 insertions(+), 11 deletions(-)
> 
> diff --git a/mm/memory.c b/mm/memory.c
> index 20a9adb..79ebed3 100644
> --- a/mm/memory.c
> +++ b/mm/memory.c
> @@ -3869,14 +3869,11 @@ EXPORT_SYMBOL_GPL(generic_access_phys);
>   * given task for page fault accounting.
>   */
>  static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm,
> - unsigned long addr, void *buf, int len, int write)
> + unsigned long addr, void *buf, int len, unsigned int gup_flags)
>  {
>   struct vm_area_struct *vma;
>   void *old_buf = buf;
> - unsigned int flags = FOLL_FORCE;
> -
> - if (write)
> - flags |= FOLL_WRITE;
> + int write = gup_flags & FOLL_WRITE;
>  
>   down_read(>mmap_sem);
>   /* ignore errors, just check how much was successfully transferred */
> @@ -3886,7 +3883,7 @@ static int __access_remote_vm(struct task_struct *tsk, 
> struct mm_struct *mm,
>   struct page *page = NULL;
>  
>   ret = get_user_pages_remote(tsk, mm, addr, 1,
> - flags, , );
> + gup_flags, , );
>   if (ret <= 0) {
>  #ifndef CONFIG_HAVE_IOREMAP_PROT
>   break;
> @@ -3945,7 +3942,12 @@ static int __access_remote_vm(struct task_struct *tsk, 
> struct mm_struct *mm,
>  int access_remote_vm(struct mm_struct *mm, unsigned long addr,
>   void *buf, int len, int write)
>  {
> - return __access_remote_vm(NULL, mm, addr, buf, len, write);
> + unsigned int flags = FOLL_FORCE;
> +
> + if (write)
> + flags |= FOLL_WRITE;
> +
> + return __access_remote_vm(NULL, mm, addr, buf, len, flags);
>  }
>  
>  /*
> @@ -3958,12 +3960,17 @@ int access_process_vm(struct task_struct *tsk, 
> unsigned long addr,
>  {
>   struct mm_struct *mm;
>   int ret;
> + unsigned int flags = FOLL_FORCE;
>  
>   mm = get_task_mm(tsk);
>   if (!mm)
>   return 0;
>  
> - ret = __access_remote_vm(tsk, mm, addr, buf, len, write);
> + if (write)
> + flags |= FOLL_WRITE;
> +
> + ret = __access_remote_vm(tsk, mm, addr, buf, len, flags);
> +
>   mmput(mm);
>  
>   return ret;
> diff --git a/mm/nommu.c b/mm/nommu.c
> index 70cb844..bde7df3 100644
> --- a/mm/nommu.c
> +++ b/mm/nommu.c
> @@ -1809,9 +1809,10 @@ void filemap_map_pages(struct fault_env *fe,
>  EXPORT_SYMBOL(filemap_map_pages);
>  
>  static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm,
> - unsigned long addr, void *buf, int len, int write)
> + unsigned long addr, void *buf, int len, unsigned int gup_flags)
>  {
>   struct vm_area_struct *vma;
> + int write = gup_flags & FOLL_WRITE;
>  
>   down_read(>mmap_sem);
>  
> @@ -1853,7 +1854,8 @@ static int __access_remote_vm(struct task_struct *tsk, 
> struct mm_struct *mm,
>  int access_remote_vm(struct mm_struct *mm, unsigned long addr,
>   void *buf, int len, int write)
>  {
> - return __access_remote_vm(NULL, mm, addr, buf, len, write);
> + return __access_remote_vm(NULL, mm, addr, buf, len,
> + write ? FOLL_WRITE : 0);
>  }
>  
>  /*
> @@ -1871,7 +1873,8 @@ int access_process_vm(struct task_struct *tsk, unsigned 
>

Re: [PATCH 06/10] mm: replace get_user_pages() write/force parameters with gup_flags

2016-10-19 Thread Jan Kara
On Thu 13-10-16 01:20:16, Lorenzo Stoakes wrote:
> This patch removes the write and force parameters from get_user_pages() and
> replaces them with a gup_flags parameter to make the use of FOLL_FORCE 
> explicit
> in callers as use of this flag can result in surprising behaviour (and hence
> bugs) within the mm subsystem.
> 
> Signed-off-by: Lorenzo Stoakes <lstoa...@gmail.com>

The patch looks good. You can add:

Reviewed-by: Jan Kara <j...@suse.cz>

Honza

> ---
>  arch/cris/arch-v32/drivers/cryptocop.c |  4 +---
>  arch/ia64/kernel/err_inject.c  |  2 +-
>  arch/x86/mm/mpx.c  |  5 ++---
>  drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c|  7 +--
>  drivers/gpu/drm/radeon/radeon_ttm.c|  3 ++-
>  drivers/gpu/drm/via/via_dmablit.c  |  4 ++--
>  drivers/infiniband/core/umem.c |  6 +-
>  drivers/infiniband/hw/mthca/mthca_memfree.c|  2 +-
>  drivers/infiniband/hw/qib/qib_user_pages.c |  3 ++-
>  drivers/infiniband/hw/usnic/usnic_uiom.c   |  5 -
>  drivers/media/v4l2-core/videobuf-dma-sg.c  |  7 +--
>  drivers/misc/mic/scif/scif_rma.c   |  3 +--
>  drivers/misc/sgi-gru/grufault.c|  2 +-
>  drivers/platform/goldfish/goldfish_pipe.c  |  3 ++-
>  drivers/rapidio/devices/rio_mport_cdev.c   |  3 ++-
>  .../vc04_services/interface/vchiq_arm/vchiq_2835_arm.c |  3 +--
>  .../vc04_services/interface/vchiq_arm/vchiq_arm.c  |  3 +--
>  drivers/virt/fsl_hypervisor.c  |  4 ++--
>  include/linux/mm.h |  2 +-
>  mm/gup.c   | 12 +++-
>  mm/mempolicy.c |  2 +-
>  mm/nommu.c | 18 
> --
>  22 files changed, 49 insertions(+), 54 deletions(-)
> 
> diff --git a/arch/cris/arch-v32/drivers/cryptocop.c 
> b/arch/cris/arch-v32/drivers/cryptocop.c
> index b5698c8..099e170 100644
> --- a/arch/cris/arch-v32/drivers/cryptocop.c
> +++ b/arch/cris/arch-v32/drivers/cryptocop.c
> @@ -2722,7 +2722,6 @@ static int cryptocop_ioctl_process(struct inode *inode, 
> struct file *filp, unsig
>   err = get_user_pages((unsigned long int)(oper.indata + prev_ix),
>noinpages,
>0,  /* read access only for in data */
> -  0, /* no force */
>inpages,
>NULL);
>  
> @@ -2736,8 +2735,7 @@ static int cryptocop_ioctl_process(struct inode *inode, 
> struct file *filp, unsig
>   if (oper.do_cipher){
>   err = get_user_pages((unsigned long int)oper.cipher_outdata,
>nooutpages,
> -  1, /* write access for out data */
> -  0, /* no force */
> +  FOLL_WRITE, /* write access for out data */
>outpages,
>NULL);
>   up_read(>mm->mmap_sem);
> diff --git a/arch/ia64/kernel/err_inject.c b/arch/ia64/kernel/err_inject.c
> index 09f8457..5ed0ea9 100644
> --- a/arch/ia64/kernel/err_inject.c
> +++ b/arch/ia64/kernel/err_inject.c
> @@ -142,7 +142,7 @@ store_virtual_to_phys(struct device *dev, struct 
> device_attribute *attr,
>   u64 virt_addr=simple_strtoull(buf, NULL, 16);
>   int ret;
>  
> - ret = get_user_pages(virt_addr, 1, VM_READ, 0, NULL, NULL);
> + ret = get_user_pages(virt_addr, 1, FOLL_WRITE, NULL, NULL);
>   if (ret<=0) {
>  #ifdef ERR_INJ_DEBUG
>   printk("Virtual address %lx is not existing.\n",virt_addr);
> diff --git a/arch/x86/mm/mpx.c b/arch/x86/mm/mpx.c
> index 8047687..e4f8009 100644
> --- a/arch/x86/mm/mpx.c
> +++ b/arch/x86/mm/mpx.c
> @@ -544,10 +544,9 @@ static int mpx_resolve_fault(long __user *addr, int 
> write)
>  {
>   long gup_ret;
>   int nr_pages = 1;
> - int force = 0;
>  
> - gup_ret = get_user_pages((unsigned long)addr, nr_pages, write,
> - force, NULL, NULL);
> + gup_ret = get_user_pages((unsigned long)addr, nr_pages,
> + write ? FOLL_WRITE : 0, NULL, NULL);
>   /*
>* get_user_pages() returns number of pages gotten.
>* 0 means we failed to fault in and get anything,
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdg

Re: [PATCH 07/10] mm: replace get_user_pages_remote() write/force parameters with gup_flags

2016-10-19 Thread Jan Kara
On Thu 13-10-16 01:20:17, Lorenzo Stoakes wrote:
> This patch removes the write and force parameters from get_user_pages_remote()
> and replaces them with a gup_flags parameter to make the use of FOLL_FORCE
> explicit in callers as use of this flag can result in surprising behaviour 
> (and
> hence bugs) within the mm subsystem.
> 
> Signed-off-by: Lorenzo Stoakes <lstoa...@gmail.com>

Looks good. You can add:

Reviewed-by: Jan Kara <j...@suse.cz>

Honza

> ---
>  drivers/gpu/drm/etnaviv/etnaviv_gem.c   |  7 +--
>  drivers/gpu/drm/i915/i915_gem_userptr.c |  6 +-
>  drivers/infiniband/core/umem_odp.c  |  7 +--
>  fs/exec.c   |  9 +++--
>  include/linux/mm.h  |  2 +-
>  kernel/events/uprobes.c |  6 --
>  mm/gup.c| 22 +++---
>  mm/memory.c |  6 +-
>  security/tomoyo/domain.c|  2 +-
>  9 files changed, 40 insertions(+), 27 deletions(-)
> 
> diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.c 
> b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
> index 5ce3603..0370b84 100644
> --- a/drivers/gpu/drm/etnaviv/etnaviv_gem.c
> +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
> @@ -748,19 +748,22 @@ static struct page **etnaviv_gem_userptr_do_get_pages(
>   int ret = 0, pinned, npages = etnaviv_obj->base.size >> PAGE_SHIFT;
>   struct page **pvec;
>   uintptr_t ptr;
> + unsigned int flags = 0;
>  
>   pvec = drm_malloc_ab(npages, sizeof(struct page *));
>   if (!pvec)
>   return ERR_PTR(-ENOMEM);
>  
> + if (!etnaviv_obj->userptr.ro)
> + flags |= FOLL_WRITE;
> +
>   pinned = 0;
>   ptr = etnaviv_obj->userptr.ptr;
>  
>   down_read(>mmap_sem);
>   while (pinned < npages) {
>   ret = get_user_pages_remote(task, mm, ptr, npages - pinned,
> - !etnaviv_obj->userptr.ro, 0,
> - pvec + pinned, NULL);
> + flags, pvec + pinned, NULL);
>   if (ret < 0)
>   break;
>  
> diff --git a/drivers/gpu/drm/i915/i915_gem_userptr.c 
> b/drivers/gpu/drm/i915/i915_gem_userptr.c
> index e537930..c6f780f 100644
> --- a/drivers/gpu/drm/i915/i915_gem_userptr.c
> +++ b/drivers/gpu/drm/i915/i915_gem_userptr.c
> @@ -508,6 +508,10 @@ __i915_gem_userptr_get_pages_worker(struct work_struct 
> *_work)
>   pvec = drm_malloc_gfp(npages, sizeof(struct page *), GFP_TEMPORARY);
>   if (pvec != NULL) {
>   struct mm_struct *mm = obj->userptr.mm->mm;
> + unsigned int flags = 0;
> +
> + if (!obj->userptr.read_only)
> + flags |= FOLL_WRITE;
>  
>   ret = -EFAULT;
>   if (atomic_inc_not_zero(>mm_users)) {
> @@ -517,7 +521,7 @@ __i915_gem_userptr_get_pages_worker(struct work_struct 
> *_work)
>   (work->task, mm,
>obj->userptr.ptr + pinned * PAGE_SIZE,
>npages - pinned,
> -  !obj->userptr.read_only, 0,
> +  flags,
>pvec + pinned, NULL);
>   if (ret < 0)
>   break;
> diff --git a/drivers/infiniband/core/umem_odp.c 
> b/drivers/infiniband/core/umem_odp.c
> index 75077a0..1f0fe32 100644
> --- a/drivers/infiniband/core/umem_odp.c
> +++ b/drivers/infiniband/core/umem_odp.c
> @@ -527,6 +527,7 @@ int ib_umem_odp_map_dma_pages(struct ib_umem *umem, u64 
> user_virt, u64 bcnt,
>   u64 off;
>   int j, k, ret = 0, start_idx, npages = 0;
>   u64 base_virt_addr;
> + unsigned int flags = 0;
>  
>   if (access_mask == 0)
>   return -EINVAL;
> @@ -556,6 +557,9 @@ int ib_umem_odp_map_dma_pages(struct ib_umem *umem, u64 
> user_virt, u64 bcnt,
>   goto out_put_task;
>   }
>  
> + if (access_mask & ODP_WRITE_ALLOWED_BIT)
> + flags |= FOLL_WRITE;
> +
>   start_idx = (user_virt - ib_umem_start(umem)) >> PAGE_SHIFT;
>   k = start_idx;
>  
> @@ -574,8 +578,7 @@ int ib_umem_odp_map_dma_pages(struct ib_umem *umem, u64 
> user_virt, u64 bcnt,
>*/
>   npages = get_user_pages_remote(owning_process, owning_mm,
>   user_virt, gup_num_pages,
> -   

Re: [PATCH 04/10] mm: replace get_user_pages_locked() write/force parameters with gup_flags

2016-10-19 Thread Jan Kara
On Tue 18-10-16 14:56:09, Lorenzo Stoakes wrote:
> On Tue, Oct 18, 2016 at 02:54:25PM +0200, Jan Kara wrote:
> > > @@ -1282,7 +1282,7 @@ long get_user_pages(unsigned long start, unsigned 
> > > long nr_pages,
> > >   int write, int force, struct page **pages,
> > >   struct vm_area_struct **vmas);
> > >  long get_user_pages_locked(unsigned long start, unsigned long nr_pages,
> > > - int write, int force, struct page **pages, int *locked);
> > > + unsigned int gup_flags, struct page **pages, int *locked);
> >
> > Hum, the prototype is inconsistent with e.g. __get_user_pages_unlocked()
> > where gup_flags come after **pages argument. Actually it makes more sense
> > to have it before **pages so that input arguments come first and output
> > arguments second but I don't care that much. But it definitely should be
> > consistent...
> 
> It was difficult to decide quite how to arrange parameters as there was
> inconsitency with regards to parameter ordering already - for example
> __get_user_pages() places its flags argument before pages whereas, as you 
> note,
> __get_user_pages_unlocked() puts them afterwards.
> 
> I ended up compromising by trying to match the existing ordering of the 
> function
> as much as I could by replacing write, force pairs with gup_flags in the same
> location (with the exception of get_user_pages_unlocked() which I felt should
> match __get_user_pages_unlocked() in signature) or if there was already a
> gup_flags parameter as in the case of __get_user_pages_unlocked() I simply
> removed the write, force pair and left the flags as the last parameter.
> 
> I am happy to rearrange parameters as needed, however I am not sure if it'd be
> worthwhile for me to do so (I am keen to try to avoid adding too much noise 
> here
> :)
> 
> If we were to rearrange parameters for consistency I'd suggest adjusting
> __get_user_pages_unlocked() to put gup_flags before pages and do the same with
> get_user_pages_unlocked(), let me know what you think.

Yeah, ok. If the inconsistency is already there, just leave it for now.

Honza
-- 
Jan Kara <j...@suse.com>
SUSE Labs, CR
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 04/10] mm: replace get_user_pages_locked() write/force parameters with gup_flags

2016-10-18 Thread Jan Kara
On Thu 13-10-16 01:20:14, Lorenzo Stoakes wrote:
> This patch removes the write and force parameters from get_user_pages_locked()
> and replaces them with a gup_flags parameter to make the use of FOLL_FORCE
> explicit in callers as use of this flag can result in surprising behaviour 
> (and
> hence bugs) within the mm subsystem.
> 
> Signed-off-by: Lorenzo Stoakes <lstoa...@gmail.com>
> ---
>  include/linux/mm.h |  2 +-
>  mm/frame_vector.c  |  8 +++-
>  mm/gup.c   | 12 +++-
>  mm/nommu.c |  5 -
>  4 files changed, 15 insertions(+), 12 deletions(-)
> 
> diff --git a/include/linux/mm.h b/include/linux/mm.h
> index 6adc4bc..27ab538 100644
> --- a/include/linux/mm.h
> +++ b/include/linux/mm.h
> @@ -1282,7 +1282,7 @@ long get_user_pages(unsigned long start, unsigned long 
> nr_pages,
>   int write, int force, struct page **pages,
>   struct vm_area_struct **vmas);
>  long get_user_pages_locked(unsigned long start, unsigned long nr_pages,
> - int write, int force, struct page **pages, int *locked);
> + unsigned int gup_flags, struct page **pages, int *locked);

Hum, the prototype is inconsistent with e.g. __get_user_pages_unlocked()
where gup_flags come after **pages argument. Actually it makes more sense
to have it before **pages so that input arguments come first and output
arguments second but I don't care that much. But it definitely should be
consistent...

    Honza
-- 
Jan Kara <j...@suse.com>
SUSE Labs, CR
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 03/10] mm: replace get_user_pages_unlocked() write/force parameters with gup_flags

2016-10-18 Thread Jan Kara
On Thu 13-10-16 01:20:13, Lorenzo Stoakes wrote:
> This patch removes the write and force parameters from 
> get_user_pages_unlocked()
> and replaces them with a gup_flags parameter to make the use of FOLL_FORCE
> explicit in callers as use of this flag can result in surprising behaviour 
> (and
> hence bugs) within the mm subsystem.
> 
> Signed-off-by: Lorenzo Stoakes <lstoa...@gmail.com>

Looks good. You can add:

Reviewed-by: Jan Kara <j...@suse.cz>

        Honza
-- 
Jan Kara <j...@suse.com>
SUSE Labs, CR
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 02/10] mm: remove write/force parameters from __get_user_pages_unlocked()

2016-10-18 Thread Jan Kara
On Thu 13-10-16 01:20:12, Lorenzo Stoakes wrote:
> This patch removes the write and force parameters from
> __get_user_pages_unlocked() to make the use of FOLL_FORCE explicit in callers 
> as
> use of this flag can result in surprising behaviour (and hence bugs) within 
> the
> mm subsystem.
> 
> Signed-off-by: Lorenzo Stoakes <lstoa...@gmail.com>

The patch looks good. You can add:

Reviewed-by: Jan Kara <j...@suse.cz>

        Honza
-- 
Jan Kara <j...@suse.com>
SUSE Labs, CR
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 01/10] mm: remove write/force parameters from __get_user_pages_locked()

2016-10-18 Thread Jan Kara
On Thu 13-10-16 01:20:11, Lorenzo Stoakes wrote:
> This patch removes the write and force parameters from 
> __get_user_pages_locked()
> to make the use of FOLL_FORCE explicit in callers as use of this flag can 
> result
> in surprising behaviour (and hence bugs) within the mm subsystem.
> 
> Signed-off-by: Lorenzo Stoakes <lstoa...@gmail.com>

Looks good. You can add:

Reviewed-by: Jan Kara <j...@suse.cz>

        Honza
-- 
Jan Kara <j...@suse.com>
SUSE Labs, CR
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 1/2] [media] vb2-memops: Fix over allocation of frame vectors

2016-03-04 Thread Jan Kara
On Thu 03-03-16 20:12:48, Ricardo Ribalda Delgado wrote:
> On page unaligned frames, create_framevec forces get_vaddr_frames to
> allocate an extra page at the end of the buffer. Under some
> circumstances, this leads to -EINVAL on VIDIOC_QBUF.
> 
> E.g:
> We have vm_a that vm_area that goes from 0x1000 to 0x3000. And a
> frame that goes from 0x1800 to 0x2800, i.e. 2 pages.
> 
> frame_vector_create will be called with the following params:
> 
> get_vaddr_frames(0x1800 , 2, write, 1, vec);
> 
> get_vaddr will allocate the first page after checking that the memory
> 0x1800-0x27ff is valid, but it will not allocate the second page because
> the range 0x2800-0x37ff is out of the vm_a range. This results in
> create_framevec returning -EFAULT
> 
> Error Trace:
> [ 9083.793015] video0: VIDIOC_QBUF: 00:00:00. index=1,
> type=vid-cap, flags=0x2002, field=any, sequence=0,
> memory=userptr, bytesused=0, offset/userptr=0x7ff2b023ca80, length=5765760
> [ 9083.793028] timecode=00:00:00 type=0, flags=0x,
> frames=0, userbits=0x
> [ 9083.793117] video0: VIDIOC_QBUF: error -22: 00:00:00.
> index=2, type=vid-cap, flags=0x, field=any, sequence=0,
> memory=userptr, bytesused=0, offset/userptr=0x7ff2b07bc500, length=5765760
> 
> Fixes: 21fb0cb7ec65 ("[media] vb2: Provide helpers for mapping virtual 
> addresses")
> Reported-by: Albert Antony <alb...@newtec.dk>
> Signed-off-by: Ricardo Ribalda Delgado <ricardo.riba...@gmail.com>

The patch looks good. Thanks for fixing this! You can add:

Reviewed-by: Jan Kara <j...@suse.cz>

Honza
> ---
> 
> Maybe we should cc stable.
> 
> This error has not pop-out yet because userptr is usually called with memory
> on the heap and malloc usually overallocate. This error has been a pain to 
> trace :).
> 
> Regards!
> 
> 
> 
>  drivers/media/v4l2-core/videobuf2-memops.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/media/v4l2-core/videobuf2-memops.c 
> b/drivers/media/v4l2-core/videobuf2-memops.c
> index dbec5923fcf0..e4e4976c6849 100644
> --- a/drivers/media/v4l2-core/videobuf2-memops.c
> +++ b/drivers/media/v4l2-core/videobuf2-memops.c
> @@ -49,7 +49,7 @@ struct frame_vector *vb2_create_framevec(unsigned long 
> start,
>   vec = frame_vector_create(nr);
>   if (!vec)
>   return ERR_PTR(-ENOMEM);
> - ret = get_vaddr_frames(start, nr, write, 1, vec);
> + ret = get_vaddr_frames(start & PAGE_MASK, nr, write, 1, vec);
>   if (ret < 0)
>   goto out_destroy;
>   /* We accept only complete set of PFNs */
> -- 
> 2.7.0
> 
-- 
Jan Kara <j...@suse.com>
SUSE Labs, CR
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 7/7] [media] ivtv: Convert to get_user_pages_unlocked()

2015-10-06 Thread Jan Kara
From: Jan Kara <j...@suse.cz>

Convert ivtv_yuv_prep_user_dma() to use get_user_pages_unlocked() so
that we don't unnecessarily leak knowledge about mm locking into drivers
code.

CC: Andy Walls <awa...@md.metrocast.net>
CC: Mauro Carvalho Chehab <mche...@osg.samsung.com>
CC: linux-media@vger.kernel.org
Signed-off-by: Jan Kara <j...@suse.cz>
---
 drivers/media/pci/ivtv/ivtv-yuv.c | 12 ++--
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/media/pci/ivtv/ivtv-yuv.c 
b/drivers/media/pci/ivtv/ivtv-yuv.c
index 2ad65eb29832..2b8e7b2f2b86 100644
--- a/drivers/media/pci/ivtv/ivtv-yuv.c
+++ b/drivers/media/pci/ivtv/ivtv-yuv.c
@@ -75,15 +75,15 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct 
ivtv_user_dma *dma,
ivtv_udma_get_page_info (_dma, (unsigned long)args->uv_source, 360 * 
uv_decode_height);
 
/* Get user pages for DMA Xfer */
-   down_read(>mm->mmap_sem);
-   y_pages = get_user_pages(current, current->mm, y_dma.uaddr, 
y_dma.page_count, 0, 1, >map[0], NULL);
+   y_pages = get_user_pages_unlocked(current, current->mm,
+   y_dma.uaddr, y_dma.page_count, 0, 1,
+   >map[0]);
uv_pages = 0; /* silence gcc. value is set and consumed only if: */
if (y_pages == y_dma.page_count) {
-   uv_pages = get_user_pages(current, current->mm,
- uv_dma.uaddr, uv_dma.page_count, 0, 1,
- >map[y_pages], NULL);
+   uv_pages = get_user_pages_unlocked(current, current->mm,
+   uv_dma.uaddr, uv_dma.page_count, 0, 1,
+   >map[y_pages]);
}
-   up_read(>mm->mmap_sem);
 
if (y_pages != y_dma.page_count || uv_pages != uv_dma.page_count) {
int rc = -EFAULT;
-- 
2.1.4

--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 0/7] get_user_pages() cleanup

2015-10-06 Thread Jan Kara
From: Jan Kara <j...@suse.cz>

  Hello,

Now when the usage of get_user_pages() in media drivers got cleaned up, here
comes a series which removes knowledge about mmap_sem from a couple of other
drivers. Patches are trivial and standalone but please check, they are only
compile tested. If you are OK with them, either take them through your
respective trees or ack them and I can take care of pushing them to Linus
(probably through mm tree). Thanks.

After these patches there are some 12 call sites of get_user_pages() outside of
core code (mostly infiniband and RDMA). So we are slowly getting to the goal of
removing knowledge about page fault locking from drivers which will
consequently allow us to change the locking rules with reasonable effort.

Honza

CC: Jesper Nilsson <jesper.nils...@axis.com>
CC: linux-cris-ker...@axis.com
CC: Mikael Starvik <star...@axis.com>
CC: linux-i...@vger.kernel.org
CC: Tony Luck <tony.l...@intel.com>
CC: David Airlie <airl...@linux.ie>
CC: dri-de...@lists.freedesktop.org
CC: Timur Tabi <ti...@freescale.com>
CC: linux-r...@vger.kernel.org
CC: Roland Dreier <rol...@kernel.org>
CC: Daniel Vetter <daniel.vet...@intel.com>
CC: David Airlie <airl...@linux.ie>
CC: dri-de...@lists.freedesktop.org
CC: Andy Walls <awa...@md.metrocast.net>
CC: linux-media@vger.kernel.org
CC: Mauro Carvalho Chehab <mche...@osg.samsung.com>
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 9/9] drm/exynos: Convert g2d_userptr_get_dma_addr() to use get_vaddr_frames()

2015-07-21 Thread Jan Kara
On Sat 18-07-15 12:14:12, Inki Dae wrote:
 On 2015년 07월 17일 19:31, Hans Verkuil wrote:
  On 07/17/2015 12:29 PM, Inki Dae wrote:
  On 2015년 07월 17일 19:20, Hans Verkuil wrote:
  On 07/13/2015 04:55 PM, Jan Kara wrote:
  From: Jan Kara j...@suse.cz
 
  Convert g2d_userptr_get_dma_addr() to pin pages using get_vaddr_frames().
  This removes the knowledge about vmas and mmap_sem locking from exynos
  driver. Also it fixes a problem that the function has been mapping user
  provided address without holding mmap_sem.
 
  I'd like to see an Ack from one of the exynos drm driver maintainers 
  before
  I merge this.
 
  Inki, Marek?
 
  I already gave Ack but it seems that Jan missed it while updating.
 
  Anyway,
  Acked-by: Inki Dae inki@samsung.com
  
  Thanks!
 
 Oops, sorry. This patch would incur a build warning. Below is my comment.
 
  @@ -456,65 +455,38 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct 
  drm_device *drm_dev,
   return ERR_PTR(-ENOMEM);
   
   atomic_set(g2d_userptr-refcount, 1);
  +g2d_userptr-size = size;
   
   start = userptr  PAGE_MASK;
   offset = userptr  ~PAGE_MASK;
   end = PAGE_ALIGN(userptr + size);
   npages = (end - start)  PAGE_SHIFT;
  -g2d_userptr-npages = npages;
  -
  -pages = drm_calloc_large(npages, sizeof(struct page *));
  -if (!pages) {
  -DRM_ERROR(failed to allocate pages.\n);
  -ret = -ENOMEM;
  +g2d_userptr-vec = frame_vector_create(npages);
  +if (!g2d_userptr-vec)
 
 You would need ret = -EFAULT here. And below is a patch posted already,
   http://www.spinics.net/lists/dri-devel/msg85321.html

The error should IMHO be -ENOMEM because frame_vector_create() fails only
if we fail to allocate the structure. Attached is the updated version of
the patch. Hans, can you please pick this one?
 
 ps. please, ignore the codes related to build error in the patch.
 
 With the change, Acked-by: Inki Dae inki@samsung.com

Thanks and sorry for making so many stupid mistakes in the Exynos driver.

Honza
-- 
Jan Kara j...@suse.cz
SUSE Labs, CR
From e1ce3781eb0a3ffe045055f4145bc60ee7b2a6b5 Mon Sep 17 00:00:00 2001
From: Jan Kara j...@suse.cz
Date: Wed, 4 Dec 2013 14:41:22 +0100
Subject: [PATCH 9/9] drm/exynos: Convert g2d_userptr_get_dma_addr() to use
 get_vaddr_frames()

Convert g2d_userptr_get_dma_addr() to pin pages using get_vaddr_frames().
This removes the knowledge about vmas and mmap_sem locking from exynos
driver. Also it fixes a problem that the function has been mapping user
provided address without holding mmap_sem.

Acked-by: Inki Dae inki@samsung.com
Signed-off-by: Jan Kara j...@suse.cz
---
 drivers/gpu/drm/exynos/Kconfig  |  1 +
 drivers/gpu/drm/exynos/exynos_drm_g2d.c | 89 ++
 drivers/gpu/drm/exynos/exynos_drm_gem.c | 97 -
 3 files changed, 30 insertions(+), 157 deletions(-)

diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig
index 43003c4ad80b..b364562dc6c1 100644
--- a/drivers/gpu/drm/exynos/Kconfig
+++ b/drivers/gpu/drm/exynos/Kconfig
@@ -77,6 +77,7 @@ config DRM_EXYNOS_VIDI
 config DRM_EXYNOS_G2D
 	bool Exynos DRM G2D
 	depends on DRM_EXYNOS  !VIDEO_SAMSUNG_S5P_G2D
+	select FRAME_VECTOR
 	help
 	  Choose this option if you want to use Exynos G2D for DRM.
 
diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
index 81a250830808..7584834a53c9 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
@@ -190,10 +190,8 @@ struct g2d_cmdlist_userptr {
 	dma_addr_t		dma_addr;
 	unsigned long		userptr;
 	unsigned long		size;
-	struct page		**pages;
-	unsigned int		npages;
+	struct frame_vector	*vec;
 	struct sg_table		*sgt;
-	struct vm_area_struct	*vma;
 	atomic_t		refcount;
 	bool			in_pool;
 	bool			out_of_list;
@@ -363,6 +361,7 @@ static void g2d_userptr_put_dma_addr(struct drm_device *drm_dev,
 {
 	struct g2d_cmdlist_userptr *g2d_userptr =
 	(struct g2d_cmdlist_userptr *)obj;
+	struct page **pages;
 
 	if (!obj)
 		return;
@@ -382,19 +381,21 @@ out:
 	exynos_gem_unmap_sgt_from_dma(drm_dev, g2d_userptr-sgt,
 	DMA_BIDIRECTIONAL);
 
-	exynos_gem_put_pages_to_userptr(g2d_userptr-pages,
-	g2d_userptr-npages,
-	g2d_userptr-vma);
+	pages = frame_vector_pages(g2d_userptr-vec);
+	if (!IS_ERR(pages)) {
+		int i;
 
-	exynos_gem_put_vma(g2d_userptr-vma);
+		for (i = 0; i  frame_vector_count(g2d_userptr-vec); i++)
+			set_page_dirty_lock(pages[i]);
+	}
+	put_vaddr_frames(g2d_userptr-vec);
+	frame_vector_destroy(g2d_userptr-vec);
 
 	if (!g2d_userptr-out_of_list)
 		list_del_init(g2d_userptr-list);
 
 	sg_free_table(g2d_userptr-sgt);
 	kfree(g2d_userptr-sgt);
-
-	drm_free_large(g2d_userptr-pages);
 	kfree(g2d_userptr);
 }
 
@@ -408,9 +409,7 @@ static dma_addr_t

[PATCH 3/9] media: omap_vout: Convert omap_vout_uservirt_to_phys() to use get_vaddr_pfns()

2015-07-13 Thread Jan Kara
From: Jan Kara j...@suse.cz

Convert omap_vout_uservirt_to_phys() to use get_vaddr_pfns() instead of
hand made mapping of virtual address to physical address. Also the
function leaked page reference from get_user_pages() so fix that by
properly release the reference when omap_vout_buffer_release() is
called.

Signed-off-by: Jan Kara j...@suse.cz
---
 drivers/media/platform/omap/Kconfig |  1 +
 drivers/media/platform/omap/omap_vout.c | 67 +++--
 2 files changed, 32 insertions(+), 36 deletions(-)

diff --git a/drivers/media/platform/omap/Kconfig 
b/drivers/media/platform/omap/Kconfig
index dc2aaab54aef..217d613b0fe7 100644
--- a/drivers/media/platform/omap/Kconfig
+++ b/drivers/media/platform/omap/Kconfig
@@ -10,6 +10,7 @@ config VIDEO_OMAP2_VOUT
select OMAP2_DSS if HAS_IOMEM  ARCH_OMAP2PLUS
select OMAP2_VRFB if ARCH_OMAP2 || ARCH_OMAP3
select VIDEO_OMAP2_VOUT_VRFB if VIDEO_OMAP2_VOUT  OMAP2_VRFB
+   select FRAME_VECTOR
default n
---help---
  V4L2 Display driver support for OMAP2/3 based boards.
diff --git a/drivers/media/platform/omap/omap_vout.c 
b/drivers/media/platform/omap/omap_vout.c
index f09c5f17a42f..b0dad941f7cb 100644
--- a/drivers/media/platform/omap/omap_vout.c
+++ b/drivers/media/platform/omap/omap_vout.c
@@ -195,46 +195,34 @@ static int omap_vout_try_format(struct v4l2_pix_format 
*pix)
 }
 
 /*
- * omap_vout_uservirt_to_phys: This inline function is used to convert user
- * space virtual address to physical address.
+ * omap_vout_get_userptr: Convert user space virtual address to physical
+ * address.
  */
-static unsigned long omap_vout_uservirt_to_phys(unsigned long virtp)
+static int omap_vout_get_userptr(struct videobuf_buffer *vb, u32 virtp,
+u32 *physp)
 {
-   unsigned long physp = 0;
-   struct vm_area_struct *vma;
-   struct mm_struct *mm = current-mm;
+   struct frame_vector *vec;
+   int ret;
 
/* For kernel direct-mapped memory, take the easy way */
-   if (virtp = PAGE_OFFSET)
-   return virt_to_phys((void *) virtp);
-
-   down_read(current-mm-mmap_sem);
-   vma = find_vma(mm, virtp);
-   if (vma  (vma-vm_flags  VM_IO)  vma-vm_pgoff) {
-   /* this will catch, kernel-allocated, mmaped-to-usermode
-  addresses */
-   physp = (vma-vm_pgoff  PAGE_SHIFT) + (virtp - vma-vm_start);
-   up_read(current-mm-mmap_sem);
-   } else {
-   /* otherwise, use get_user_pages() for general userland pages */
-   int res, nr_pages = 1;
-   struct page *pages;
+   if (virtp = PAGE_OFFSET) {
+   *physp = virt_to_phys((void *)virtp);
+   return 0;
+   }
 
-   res = get_user_pages(current, current-mm, virtp, nr_pages, 1,
-   0, pages, NULL);
-   up_read(current-mm-mmap_sem);
+   vec = frame_vector_create(1);
+   if (!vec)
+   return -ENOMEM;
 
-   if (res == nr_pages) {
-   physp =  __pa(page_address(pages[0]) +
-   (virtp  ~PAGE_MASK));
-   } else {
-   printk(KERN_WARNING VOUT_NAME
-   get_user_pages failed\n);
-   return 0;
-   }
+   ret = get_vaddr_frames(virtp, 1, true, false, vec);
+   if (ret != 1) {
+   frame_vector_destroy(vec);
+   return -EINVAL;
}
+   *physp = __pfn_to_phys(frame_vector_pfns(vec)[0]);
+   vb-priv = vec;
 
-   return physp;
+   return 0;
 }
 
 /*
@@ -784,11 +772,15 @@ static int omap_vout_buffer_prepare(struct videobuf_queue 
*q,
 * address of the buffer
 */
if (V4L2_MEMORY_USERPTR == vb-memory) {
+   int ret;
+
if (0 == vb-baddr)
return -EINVAL;
/* Physical address */
-   vout-queued_buf_addr[vb-i] = (u8 *)
-   omap_vout_uservirt_to_phys(vb-baddr);
+   ret = omap_vout_get_userptr(vb, vb-baddr,
+   (u32 *)vout-queued_buf_addr[vb-i]);
+   if (ret  0)
+   return ret;
} else {
unsigned long addr, dma_addr;
unsigned long size;
@@ -837,9 +829,12 @@ static void omap_vout_buffer_release(struct videobuf_queue 
*q,
struct omap_vout_device *vout = q-priv_data;
 
vb-state = VIDEOBUF_NEEDS_INIT;
+   if (vb-memory == V4L2_MEMORY_USERPTR  vb-priv) {
+   struct frame_vector *vec = vb-priv;
 
-   if (V4L2_MEMORY_MMAP != vout-memory)
-   return;
+   put_vaddr_frames(vec);
+   frame_vector_destroy(vec);
+   }
 }
 
 /*
-- 
2.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-media

Re: [PATCH 0/10 v6] Helper to abstract vma handling in media layer

2015-07-13 Thread Jan Kara
On Mon 13-07-15 10:45:25, Hans Verkuil wrote:
 On 07/09/2015 02:12 PM, Hans Verkuil wrote:
  On 07/09/2015 01:48 PM, Jan Kara wrote:
Hello,
 
Hans, did you have a chance to look at these patches? I have tested them
  with the vivid driver but it would be good if you could run them through
  your standard testing procedure as well. Andrew has updated the patches in
  his tree but some ack from you would be welcome...
  
  I've planned a 'patch day' for Monday. So hopefully you'll see a pull 
  request
  by then.
 
 OK, I'm confused. I thought the non-vb2 patches would go in for 4.2? That
 didn't happen, so I guess the plan is to merge the whole lot for 4.3 via
 our media tree? If that's the case, can you post a new patch series on

I guess Andrew wasn't sure what to push and what not so he just chose the
safe option to not push anything.

 top of the master branch of the media tree? I want to make sure I use the
 right patches. Also, if you do make a new patch series, then it would be
 better if patch 10/10 is folded into patch 2/10.

OK, I'll rebase patches on top of media tree.

Honza

  On Thu 18-06-15 16:08:30, Jan Kara wrote:
Hello,
 
  I'm sending the sixth version of my patch series to abstract vma handling 
  from
  the various media drivers. Since the previous version I have added a 
  patch to
  move mm helpers into a separate file and behind a config option. I also
  changed patch pushing mmap_sem down in videobuf2 core to avoid lockdep 
  warning
  and NULL dereference Hans found in his testing. I've also included small
  fixups Andrew was carrying.
 
  After this patch set drivers have to know much less details about vmas, 
  their
  types, and locking. Also quite some code is removed from them. As a bonus
  drivers get automatically VM_FAULT_RETRY handling. The primary motivation 
  for
  this series is to remove knowledge about mmap_sem locking from as many 
  places a
  possible so that we can change it with reasonable effort.
 
  The core of the series is the new helper get_vaddr_frames() which is 
  given a
  virtual address and it fills in PFNs / struct page pointers (depending on 
  VMA
  type) into the provided array. If PFNs correspond to normal pages it also 
  grabs
  references to these pages. The difference from get_user_pages() is that 
  this
  function can also deal with pfnmap, and io mappings which is what the 
  media
  drivers need.
 
  I have tested the patches with vivid driver so at least vb2 code got some
  exposure. Conversion of other drivers was just compile-tested (for x86 so 
  e.g.
  exynos driver which is only for Samsung platform is completely untested).
 
  Andrew, can you please update the patches in mm three? Thanks!
 
Honza
 
  Changes since v5:
  * Moved mm helper into a separate file and behind a config option
  * Changed the first patch pushing mmap_sem down in videobuf2 core to avoid
possible deadlock
 
  Changes since v4:
  * Minor cleanups and fixes pointed out by Mel and Vlasta
  * Added Acked-by tags
 
  Changes since v3:
  * Added include linux/vmalloc.h into mm/gup.c as it's needed for some 
  archs
  * Fixed error path for exynos driver
 
  Changes since v2:
  * Renamed functions and structures as Mel suggested
  * Other minor changes suggested by Mel
  * Rebased on top of 4.1-rc2
  * Changed functions to get pointer to array of pages / pfns to perform
conversion if necessary. This fixes possible issue in the omap I may 
  have
introduced in v2 and generally makes the API less errorprone.
  
  --
  To unsubscribe from this list: send the line unsubscribe linux-media in
  the body of a message to majord...@vger.kernel.org
  More majordomo info at  http://vger.kernel.org/majordomo-info.html
  
 
-- 
Jan Kara j...@suse.cz
SUSE Labs, CR
--
To unsubscribe from this list: send the line unsubscribe linux-media in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 7/9] media: vb2: Convert vb2_dc_get_userptr() to use frame vector

2015-07-13 Thread Jan Kara
From: Jan Kara j...@suse.cz

Convert vb2_dc_get_userptr() to use frame vector infrastructure. When we
are doing that there's no need to allocate page array and some code can
be simplified.

Acked-by: Marek Szyprowski m.szyprow...@samsung.com
Tested-by: Marek Szyprowski m.szyprow...@samsung.com
Signed-off-by: Jan Kara j...@suse.cz
---
 drivers/media/v4l2-core/videobuf2-dma-contig.c | 212 -
 1 file changed, 34 insertions(+), 178 deletions(-)

diff --git a/drivers/media/v4l2-core/videobuf2-dma-contig.c 
b/drivers/media/v4l2-core/videobuf2-dma-contig.c
index c548ce425701..2397ceb1dc6b 100644
--- a/drivers/media/v4l2-core/videobuf2-dma-contig.c
+++ b/drivers/media/v4l2-core/videobuf2-dma-contig.c
@@ -32,15 +32,13 @@ struct vb2_dc_buf {
dma_addr_t  dma_addr;
enum dma_data_direction dma_dir;
struct sg_table *dma_sgt;
+   struct frame_vector *vec;
 
/* MMAP related */
struct vb2_vmarea_handler   handler;
atomic_trefcount;
struct sg_table *sgt_base;
 
-   /* USERPTR related */
-   struct vm_area_struct   *vma;
-
/* DMABUF related */
struct dma_buf_attachment   *db_attach;
 };
@@ -49,24 +47,6 @@ struct vb2_dc_buf {
 /*scatterlist table functions*/
 /*/
 
-
-static void vb2_dc_sgt_foreach_page(struct sg_table *sgt,
-   void (*cb)(struct page *pg))
-{
-   struct scatterlist *s;
-   unsigned int i;
-
-   for_each_sg(sgt-sgl, s, sgt-orig_nents, i) {
-   struct page *page = sg_page(s);
-   unsigned int n_pages = PAGE_ALIGN(s-offset + s-length)
-PAGE_SHIFT;
-   unsigned int j;
-
-   for (j = 0; j  n_pages; ++j, ++page)
-   cb(page);
-   }
-}
-
 static unsigned long vb2_dc_get_contiguous_size(struct sg_table *sgt)
 {
struct scatterlist *s;
@@ -429,92 +409,12 @@ static struct dma_buf *vb2_dc_get_dmabuf(void *buf_priv, 
unsigned long flags)
 /*   callbacks for USERPTR buffers   */
 /*/
 
-static inline int vma_is_io(struct vm_area_struct *vma)
-{
-   return !!(vma-vm_flags  (VM_IO | VM_PFNMAP));
-}
-
-static int vb2_dc_get_user_pfn(unsigned long start, int n_pages,
-   struct vm_area_struct *vma, unsigned long *res)
-{
-   unsigned long pfn, start_pfn, prev_pfn;
-   unsigned int i;
-   int ret;
-
-   if (!vma_is_io(vma))
-   return -EFAULT;
-
-   ret = follow_pfn(vma, start, pfn);
-   if (ret)
-   return ret;
-
-   start_pfn = pfn;
-   start += PAGE_SIZE;
-
-   for (i = 1; i  n_pages; ++i, start += PAGE_SIZE) {
-   prev_pfn = pfn;
-   ret = follow_pfn(vma, start, pfn);
-
-   if (ret) {
-   pr_err(no page for address %lu\n, start);
-   return ret;
-   }
-   if (pfn != prev_pfn + 1)
-   return -EINVAL;
-   }
-
-   *res = start_pfn;
-   return 0;
-}
-
-static int vb2_dc_get_user_pages(unsigned long start, struct page **pages,
-   int n_pages, struct vm_area_struct *vma,
-   enum dma_data_direction dma_dir)
-{
-   if (vma_is_io(vma)) {
-   unsigned int i;
-
-   for (i = 0; i  n_pages; ++i, start += PAGE_SIZE) {
-   unsigned long pfn;
-   int ret = follow_pfn(vma, start, pfn);
-
-   if (!pfn_valid(pfn))
-   return -EINVAL;
-
-   if (ret) {
-   pr_err(no page for address %lu\n, start);
-   return ret;
-   }
-   pages[i] = pfn_to_page(pfn);
-   }
-   } else {
-   int n;
-
-   n = get_user_pages(current, current-mm, start  PAGE_MASK,
-   n_pages, dma_dir == DMA_FROM_DEVICE, 1, pages, NULL);
-   /* negative error means that no page was pinned */
-   n = max(n, 0);
-   if (n != n_pages) {
-   pr_err(got only %d of %d user pages\n, n, n_pages);
-   while (n)
-   put_page(pages[--n]);
-   return -EFAULT;
-   }
-   }
-
-   return 0;
-}
-
-static void vb2_dc_put_dirty_page(struct page *page)
-{
-   set_page_dirty_lock(page);
-   put_page(page);
-}
-
 static void vb2_dc_put_userptr(void *buf_priv)
 {
struct vb2_dc_buf *buf = buf_priv;
struct sg_table *sgt = buf-dma_sgt;
+   int i;
+   struct page **pages;
 
if (sgt) {
DEFINE_DMA_ATTRS(attrs);
@@ -526,13 +426,15 @@ static void vb2_dc_put_userptr(void *buf_priv

[PATCH 8/9] media: vb2: Remove unused functions

2015-07-13 Thread Jan Kara
From: Jan Kara j...@suse.cz

Conversion to the use of pinned pfns made some functions unused. Remove
them. Also there's no need to lock mmap_sem in __buf_prepare() anymore.

Acked-by: Marek Szyprowski m.szyprow...@samsung.com
Tested-by: Marek Szyprowski m.szyprow...@samsung.com
Signed-off-by: Jan Kara j...@suse.cz
---
 drivers/media/v4l2-core/videobuf2-memops.c | 114 -
 include/media/videobuf2-memops.h   |   6 --
 2 files changed, 120 deletions(-)

diff --git a/drivers/media/v4l2-core/videobuf2-memops.c 
b/drivers/media/v4l2-core/videobuf2-memops.c
index 0ec186d41b9b..48c6a49c4928 100644
--- a/drivers/media/v4l2-core/videobuf2-memops.c
+++ b/drivers/media/v4l2-core/videobuf2-memops.c
@@ -23,120 +23,6 @@
 #include media/videobuf2-memops.h
 
 /**
- * vb2_get_vma() - acquire and lock the virtual memory area
- * @vma:   given virtual memory area
- *
- * This function attempts to acquire an area mapped in the userspace for
- * the duration of a hardware operation. The area is locked by performing
- * the same set of operation that are done when process calls fork() and
- * memory areas are duplicated.
- *
- * Returns a copy of a virtual memory region on success or NULL.
- */
-struct vm_area_struct *vb2_get_vma(struct vm_area_struct *vma)
-{
-   struct vm_area_struct *vma_copy;
-
-   vma_copy = kmalloc(sizeof(*vma_copy), GFP_KERNEL);
-   if (vma_copy == NULL)
-   return NULL;
-
-   if (vma-vm_ops  vma-vm_ops-open)
-   vma-vm_ops-open(vma);
-
-   if (vma-vm_file)
-   get_file(vma-vm_file);
-
-   memcpy(vma_copy, vma, sizeof(*vma));
-
-   vma_copy-vm_mm = NULL;
-   vma_copy-vm_next = NULL;
-   vma_copy-vm_prev = NULL;
-
-   return vma_copy;
-}
-EXPORT_SYMBOL_GPL(vb2_get_vma);
-
-/**
- * vb2_put_userptr() - release a userspace virtual memory area
- * @vma:   virtual memory region associated with the area to be released
- *
- * This function releases the previously acquired memory area after a hardware
- * operation.
- */
-void vb2_put_vma(struct vm_area_struct *vma)
-{
-   if (!vma)
-   return;
-
-   if (vma-vm_ops  vma-vm_ops-close)
-   vma-vm_ops-close(vma);
-
-   if (vma-vm_file)
-   fput(vma-vm_file);
-
-   kfree(vma);
-}
-EXPORT_SYMBOL_GPL(vb2_put_vma);
-
-/**
- * vb2_get_contig_userptr() - lock physically contiguous userspace mapped 
memory
- * @vaddr: starting virtual address of the area to be verified
- * @size:  size of the area
- * @res_paddr: will return physical address for the given vaddr
- * @res_vma:   will return locked copy of struct vm_area for the given area
- *
- * This function will go through memory area of size @size mapped at @vaddr and
- * verify that the underlying physical pages are contiguous. If they are
- * contiguous the virtual memory area is locked and a @res_vma is filled with
- * the copy and @res_pa set to the physical address of the buffer.
- *
- * Returns 0 on success.
- */
-int vb2_get_contig_userptr(unsigned long vaddr, unsigned long size,
-  struct vm_area_struct **res_vma, dma_addr_t *res_pa)
-{
-   struct mm_struct *mm = current-mm;
-   struct vm_area_struct *vma;
-   unsigned long offset, start, end;
-   unsigned long this_pfn, prev_pfn;
-   dma_addr_t pa = 0;
-
-   start = vaddr;
-   offset = start  ~PAGE_MASK;
-   end = start + size;
-
-   vma = find_vma(mm, start);
-
-   if (vma == NULL || vma-vm_end  end)
-   return -EFAULT;
-
-   for (prev_pfn = 0; start  end; start += PAGE_SIZE) {
-   int ret = follow_pfn(vma, start, this_pfn);
-   if (ret)
-   return ret;
-
-   if (prev_pfn == 0)
-   pa = this_pfn  PAGE_SHIFT;
-   else if (this_pfn != prev_pfn + 1)
-   return -EFAULT;
-
-   prev_pfn = this_pfn;
-   }
-
-   /*
-* Memory is contigous, lock vma and return to the caller
-*/
-   *res_vma = vb2_get_vma(vma);
-   if (*res_vma == NULL)
-   return -ENOMEM;
-
-   *res_pa = pa + offset;
-   return 0;
-}
-EXPORT_SYMBOL_GPL(vb2_get_contig_userptr);
-
-/**
  * vb2_create_framevec() - map virtual addresses to pfns
  * @start: Virtual user address where we start mapping
  * @length:Length of a range to map
diff --git a/include/media/videobuf2-memops.h b/include/media/videobuf2-memops.h
index 2f0564ff5f31..830b5239fd8b 100644
--- a/include/media/videobuf2-memops.h
+++ b/include/media/videobuf2-memops.h
@@ -31,12 +31,6 @@ struct vb2_vmarea_handler {
 
 extern const struct vm_operations_struct vb2_common_vm_ops;
 
-int vb2_get_contig_userptr(unsigned long vaddr, unsigned long size,
-  struct vm_area_struct **res_vma, dma_addr_t *res_pa);
-
-struct vm_area_struct *vb2_get_vma(struct vm_area_struct *vma);
-void vb2_put_vma(struct

[PATCH 4/9] vb2: Provide helpers for mapping virtual addresses

2015-07-13 Thread Jan Kara
From: Jan Kara j...@suse.cz

Provide simple helper functions to map virtual address range into an
array of pfns / pages.

Acked-by: Marek Szyprowski m.szyprow...@samsung.com
Tested-by: Marek Szyprowski m.szyprow...@samsung.com
Signed-off-by: Jan Kara j...@suse.cz
---
 drivers/media/v4l2-core/Kconfig|  1 +
 drivers/media/v4l2-core/videobuf2-memops.c | 58 ++
 include/media/videobuf2-memops.h   |  5 +++
 3 files changed, 64 insertions(+)

diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig
index b4b022933e29..82876a67f144 100644
--- a/drivers/media/v4l2-core/Kconfig
+++ b/drivers/media/v4l2-core/Kconfig
@@ -84,6 +84,7 @@ config VIDEOBUF2_CORE
 
 config VIDEOBUF2_MEMOPS
tristate
+   select FRAME_VECTOR
 
 config VIDEOBUF2_DMA_CONTIG
tristate
diff --git a/drivers/media/v4l2-core/videobuf2-memops.c 
b/drivers/media/v4l2-core/videobuf2-memops.c
index 81c1ad8b2cf1..0ec186d41b9b 100644
--- a/drivers/media/v4l2-core/videobuf2-memops.c
+++ b/drivers/media/v4l2-core/videobuf2-memops.c
@@ -137,6 +137,64 @@ int vb2_get_contig_userptr(unsigned long vaddr, unsigned 
long size,
 EXPORT_SYMBOL_GPL(vb2_get_contig_userptr);
 
 /**
+ * vb2_create_framevec() - map virtual addresses to pfns
+ * @start: Virtual user address where we start mapping
+ * @length:Length of a range to map
+ * @write: Should we map for writing into the area
+ *
+ * This function allocates and fills in a vector with pfns corresponding to
+ * virtual address range passed in arguments. If pfns have corresponding pages,
+ * page references are also grabbed to pin pages in memory. The function
+ * returns pointer to the vector on success and error pointer in case of
+ * failure. Returned vector needs to be freed via vb2_destroy_pfnvec().
+ */
+struct frame_vector *vb2_create_framevec(unsigned long start,
+unsigned long length,
+bool write)
+{
+   int ret;
+   unsigned long first, last;
+   unsigned long nr;
+   struct frame_vector *vec;
+
+   first = start  PAGE_SHIFT;
+   last = (start + length - 1)  PAGE_SHIFT;
+   nr = last - first + 1;
+   vec = frame_vector_create(nr);
+   if (!vec)
+   return ERR_PTR(-ENOMEM);
+   ret = get_vaddr_frames(start, nr, write, 1, vec);
+   if (ret  0)
+   goto out_destroy;
+   /* We accept only complete set of PFNs */
+   if (ret != nr) {
+   ret = -EFAULT;
+   goto out_release;
+   }
+   return vec;
+out_release:
+   put_vaddr_frames(vec);
+out_destroy:
+   frame_vector_destroy(vec);
+   return ERR_PTR(ret);
+}
+EXPORT_SYMBOL(vb2_create_framevec);
+
+/**
+ * vb2_destroy_framevec() - release vector of mapped pfns
+ * @vec:   vector of pfns / pages to release
+ *
+ * This releases references to all pages in the vector @vec (if corresponding
+ * pfns are backed by pages) and frees the passed vector.
+ */
+void vb2_destroy_framevec(struct frame_vector *vec)
+{
+   put_vaddr_frames(vec);
+   frame_vector_destroy(vec);
+}
+EXPORT_SYMBOL(vb2_destroy_framevec);
+
+/**
  * vb2_common_vm_open() - increase refcount of the vma
  * @vma:   virtual memory region for the mapping
  *
diff --git a/include/media/videobuf2-memops.h b/include/media/videobuf2-memops.h
index f05444ca8c0c..2f0564ff5f31 100644
--- a/include/media/videobuf2-memops.h
+++ b/include/media/videobuf2-memops.h
@@ -15,6 +15,7 @@
 #define _MEDIA_VIDEOBUF2_MEMOPS_H
 
 #include media/videobuf2-core.h
+#include linux/mm.h
 
 /**
  * vb2_vmarea_handler - common vma refcount tracking handler
@@ -36,5 +37,9 @@ int vb2_get_contig_userptr(unsigned long vaddr, unsigned long 
size,
 struct vm_area_struct *vb2_get_vma(struct vm_area_struct *vma);
 void vb2_put_vma(struct vm_area_struct *vma);
 
+struct frame_vector *vb2_create_framevec(unsigned long start,
+unsigned long length,
+bool write);
+void vb2_destroy_framevec(struct frame_vector *vec);
 
 #endif
-- 
2.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-media in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 6/9] media: vb2: Convert vb2_vmalloc_get_userptr() to use frame vector

2015-07-13 Thread Jan Kara
From: Jan Kara j...@suse.cz

Convert vb2_vmalloc_get_userptr() to use frame vector infrastructure.
When we are doing that there's no need to allocate page array and some
code can be simplified.

Acked-by: Marek Szyprowski m.szyprow...@samsung.com
Tested-by: Marek Szyprowski m.szyprow...@samsung.com
Signed-off-by: Jan Kara j...@suse.cz
---
 drivers/media/v4l2-core/videobuf2-vmalloc.c | 92 +++--
 1 file changed, 36 insertions(+), 56 deletions(-)

diff --git a/drivers/media/v4l2-core/videobuf2-vmalloc.c 
b/drivers/media/v4l2-core/videobuf2-vmalloc.c
index 63bef959623e..ecb8f0c7f025 100644
--- a/drivers/media/v4l2-core/videobuf2-vmalloc.c
+++ b/drivers/media/v4l2-core/videobuf2-vmalloc.c
@@ -23,11 +23,9 @@
 
 struct vb2_vmalloc_buf {
void*vaddr;
-   struct page **pages;
-   struct vm_area_struct   *vma;
+   struct frame_vector *vec;
enum dma_data_direction dma_dir;
unsigned long   size;
-   unsigned intn_pages;
atomic_trefcount;
struct vb2_vmarea_handler   handler;
struct dma_buf  *dbuf;
@@ -76,10 +74,8 @@ static void *vb2_vmalloc_get_userptr(void *alloc_ctx, 
unsigned long vaddr,
 enum dma_data_direction dma_dir)
 {
struct vb2_vmalloc_buf *buf;
-   unsigned long first, last;
-   int n_pages, offset;
-   struct vm_area_struct *vma;
-   dma_addr_t physp;
+   struct frame_vector *vec;
+   int n_pages, offset, i;
 
buf = kzalloc(sizeof(*buf), GFP_KERNEL);
if (!buf)
@@ -88,53 +84,36 @@ static void *vb2_vmalloc_get_userptr(void *alloc_ctx, 
unsigned long vaddr,
buf-dma_dir = dma_dir;
offset = vaddr  ~PAGE_MASK;
buf-size = size;
-
-   down_read(current-mm-mmap_sem);
-   vma = find_vma(current-mm, vaddr);
-   if (vma  (vma-vm_flags  VM_PFNMAP)  (vma-vm_pgoff)) {
-   if (vb2_get_contig_userptr(vaddr, size, vma, physp))
-   goto fail_pages_array_alloc;
-   buf-vma = vma;
-   buf-vaddr = (__force void *)ioremap_nocache(physp, size);
-   if (!buf-vaddr)
-   goto fail_pages_array_alloc;
+   vec = vb2_create_framevec(vaddr, size, dma_dir == DMA_FROM_DEVICE);
+   if (IS_ERR(vec))
+   goto fail_pfnvec_create;
+   buf-vec = vec;
+   n_pages = frame_vector_count(vec);
+   if (frame_vector_to_pages(vec)  0) {
+   unsigned long *nums = frame_vector_pfns(vec);
+
+   /*
+* We cannot get page pointers for these pfns. Check memory is
+* physically contiguous and use direct mapping.
+*/
+   for (i = 1; i  n_pages; i++)
+   if (nums[i-1] + 1 != nums[i])
+   goto fail_map;
+   buf-vaddr = (__force void *)
+   ioremap_nocache(nums[0]  PAGE_SHIFT, size);
} else {
-   first = vaddr  PAGE_SHIFT;
-   last  = (vaddr + size - 1)  PAGE_SHIFT;
-   buf-n_pages = last - first + 1;
-   buf-pages = kzalloc(buf-n_pages * sizeof(struct page *),
-GFP_KERNEL);
-   if (!buf-pages)
-   goto fail_pages_array_alloc;
-
-   /* current-mm-mmap_sem is taken by videobuf2 core */
-   n_pages = get_user_pages(current, current-mm,
-vaddr  PAGE_MASK, buf-n_pages,
-dma_dir == DMA_FROM_DEVICE,
-1, /* force */
-buf-pages, NULL);
-   if (n_pages != buf-n_pages)
-   goto fail_get_user_pages;
-
-   buf-vaddr = vm_map_ram(buf-pages, buf-n_pages, -1,
+   buf-vaddr = vm_map_ram(frame_vector_pages(vec), n_pages, -1,
PAGE_KERNEL);
-   if (!buf-vaddr)
-   goto fail_get_user_pages;
}
-   up_read(current-mm-mmap_sem);
 
+   if (!buf-vaddr)
+   goto fail_map;
buf-vaddr += offset;
return buf;
 
-fail_get_user_pages:
-   pr_debug(get_user_pages requested/got: %d/%d]\n, n_pages,
-buf-n_pages);
-   while (--n_pages = 0)
-   put_page(buf-pages[n_pages]);
-   kfree(buf-pages);
-
-fail_pages_array_alloc:
-   up_read(current-mm-mmap_sem);
+fail_map:
+   vb2_destroy_framevec(vec);
+fail_pfnvec_create:
kfree(buf);
 
return NULL;
@@ -145,20 +124,21 @@ static void vb2_vmalloc_put_userptr(void *buf_priv)
struct vb2_vmalloc_buf *buf = buf_priv;
unsigned long vaddr = (unsigned long)buf-vaddr

[PATCH 2/9] mm: Provide new get_vaddr_frames() helper

2015-07-13 Thread Jan Kara
From: Jan Kara j...@suse.cz

Provide new function get_vaddr_frames().  This function maps virtual
addresses from given start and fills given array with page frame numbers of
the corresponding pages. If given start belongs to a normal vma, the function
grabs reference to each of the pages to pin them in memory. If start
belongs to VM_IO | VM_PFNMAP vma, we don't touch page structures. Caller
must make sure pfns aren't reused for anything else while he is using
them.

This function is created for various drivers to simplify handling of
their buffers.

Acked-by: Mel Gorman mgor...@suse.de
Acked-by: Vlastimil Babka vba...@suse.cz
Signed-off-by: Jan Kara j...@suse.cz
---
 include/linux/mm.h |  44 ++
 mm/Kconfig |   3 +
 mm/Makefile|   1 +
 mm/frame_vector.c  | 231 +
 4 files changed, 279 insertions(+)
 create mode 100644 mm/frame_vector.c

diff --git a/include/linux/mm.h b/include/linux/mm.h
index 2e872f92dbac..79ad29a8a60a 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -20,6 +20,7 @@
 #include linux/shrinker.h
 #include linux/resource.h
 #include linux/page_ext.h
+#include linux/err.h
 
 struct mempolicy;
 struct anon_vma;
@@ -1198,6 +1199,49 @@ long get_user_pages_unlocked(struct task_struct *tsk, 
struct mm_struct *mm,
int write, int force, struct page **pages);
 int get_user_pages_fast(unsigned long start, int nr_pages, int write,
struct page **pages);
+
+/* Container for pinned pfns / pages */
+struct frame_vector {
+   unsigned int nr_allocated;  /* Number of frames we have space for */
+   unsigned int nr_frames; /* Number of frames stored in ptrs array */
+   bool got_ref;   /* Did we pin pages by getting page ref? */
+   bool is_pfns;   /* Does array contain pages or pfns? */
+   void *ptrs[0];  /* Array of pinned pfns / pages. Use
+* pfns_vector_pages() or pfns_vector_pfns()
+* for access */
+};
+
+struct frame_vector *frame_vector_create(unsigned int nr_frames);
+void frame_vector_destroy(struct frame_vector *vec);
+int get_vaddr_frames(unsigned long start, unsigned int nr_pfns,
+bool write, bool force, struct frame_vector *vec);
+void put_vaddr_frames(struct frame_vector *vec);
+int frame_vector_to_pages(struct frame_vector *vec);
+void frame_vector_to_pfns(struct frame_vector *vec);
+
+static inline unsigned int frame_vector_count(struct frame_vector *vec)
+{
+   return vec-nr_frames;
+}
+
+static inline struct page **frame_vector_pages(struct frame_vector *vec)
+{
+   if (vec-is_pfns) {
+   int err = frame_vector_to_pages(vec);
+
+   if (err)
+   return ERR_PTR(err);
+   }
+   return (struct page **)(vec-ptrs);
+}
+
+static inline unsigned long *frame_vector_pfns(struct frame_vector *vec)
+{
+   if (!vec-is_pfns)
+   frame_vector_to_pfns(vec);
+   return (unsigned long *)(vec-ptrs);
+}
+
 struct kvec;
 int get_kernel_pages(const struct kvec *iov, int nr_pages, int write,
struct page **pages);
diff --git a/mm/Kconfig b/mm/Kconfig
index e79de2bd12cd..7f146dd32fc5 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -654,3 +654,6 @@ config DEFERRED_STRUCT_PAGE_INIT
  when kswapd starts. This has a potential performance impact on
  processes running early in the lifetime of the systemm until kswapd
  finishes the initialisation.
+
+config FRAME_VECTOR
+   bool
diff --git a/mm/Makefile b/mm/Makefile
index 98c4eaeabdcb..be5d5c866305 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -78,3 +78,4 @@ obj-$(CONFIG_CMA) += cma.o
 obj-$(CONFIG_MEMORY_BALLOON) += balloon_compaction.o
 obj-$(CONFIG_PAGE_EXTENSION) += page_ext.o
 obj-$(CONFIG_CMA_DEBUGFS) += cma_debug.o
+obj-$(CONFIG_FRAME_VECTOR) += frame_vector.o
diff --git a/mm/frame_vector.c b/mm/frame_vector.c
new file mode 100644
index ..f76b579e46f1
--- /dev/null
+++ b/mm/frame_vector.c
@@ -0,0 +1,231 @@
+#include linux/kernel.h
+#include linux/errno.h
+#include linux/err.h
+#include linux/mm.h
+#include linux/slab.h
+#include linux/vmalloc.h
+#include linux/pagemap.h
+#include linux/sched.h
+
+/*
+ * get_vaddr_frames() - map virtual addresses to pfns
+ * @start: starting user address
+ * @nr_frames: number of pages / pfns from start to map
+ * @write: whether pages will be written to by the caller
+ * @force: whether to force write access even if user mapping is
+ * readonly. See description of the same argument of
+   get_user_pages().
+ * @vec:   structure which receives pages / pfns of the addresses mapped.
+ * It should have space for at least nr_frames entries.
+ *
+ * This function maps virtual addresses from @start and fills @vec structure
+ * with page frame numbers or page pointers to corresponding

[PATCH 9/9] drm/exynos: Convert g2d_userptr_get_dma_addr() to use get_vaddr_frames()

2015-07-13 Thread Jan Kara
From: Jan Kara j...@suse.cz

Convert g2d_userptr_get_dma_addr() to pin pages using get_vaddr_frames().
This removes the knowledge about vmas and mmap_sem locking from exynos
driver. Also it fixes a problem that the function has been mapping user
provided address without holding mmap_sem.

Signed-off-by: Jan Kara j...@suse.cz
---
 drivers/gpu/drm/exynos/Kconfig  |  1 +
 drivers/gpu/drm/exynos/exynos_drm_g2d.c | 91 ++-
 drivers/gpu/drm/exynos/exynos_drm_gem.c | 97 -
 3 files changed, 30 insertions(+), 159 deletions(-)

diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig
index 43003c4ad80b..b364562dc6c1 100644
--- a/drivers/gpu/drm/exynos/Kconfig
+++ b/drivers/gpu/drm/exynos/Kconfig
@@ -77,6 +77,7 @@ config DRM_EXYNOS_VIDI
 config DRM_EXYNOS_G2D
bool Exynos DRM G2D
depends on DRM_EXYNOS  !VIDEO_SAMSUNG_S5P_G2D
+   select FRAME_VECTOR
help
  Choose this option if you want to use Exynos G2D for DRM.
 
diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c 
b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
index 81a250830808..1d8d9a508373 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
@@ -190,10 +190,8 @@ struct g2d_cmdlist_userptr {
dma_addr_t  dma_addr;
unsigned long   userptr;
unsigned long   size;
-   struct page **pages;
-   unsigned intnpages;
+   struct frame_vector *vec;
struct sg_table *sgt;
-   struct vm_area_struct   *vma;
atomic_trefcount;
boolin_pool;
boolout_of_list;
@@ -363,6 +361,7 @@ static void g2d_userptr_put_dma_addr(struct drm_device 
*drm_dev,
 {
struct g2d_cmdlist_userptr *g2d_userptr =
(struct g2d_cmdlist_userptr *)obj;
+   struct page **pages;
 
if (!obj)
return;
@@ -382,19 +381,21 @@ out:
exynos_gem_unmap_sgt_from_dma(drm_dev, g2d_userptr-sgt,
DMA_BIDIRECTIONAL);
 
-   exynos_gem_put_pages_to_userptr(g2d_userptr-pages,
-   g2d_userptr-npages,
-   g2d_userptr-vma);
+   pages = frame_vector_pages(g2d_userptr-vec);
+   if (!IS_ERR(pages)) {
+   int i;
 
-   exynos_gem_put_vma(g2d_userptr-vma);
+   for (i = 0; i  frame_vector_count(g2d_userptr-vec); i++)
+   set_page_dirty_lock(pages[i]);
+   }
+   put_vaddr_frames(g2d_userptr-vec);
+   frame_vector_destroy(g2d_userptr-vec);
 
if (!g2d_userptr-out_of_list)
list_del_init(g2d_userptr-list);
 
sg_free_table(g2d_userptr-sgt);
kfree(g2d_userptr-sgt);
-
-   drm_free_large(g2d_userptr-pages);
kfree(g2d_userptr);
 }
 
@@ -408,9 +409,7 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct 
drm_device *drm_dev,
struct exynos_drm_g2d_private *g2d_priv = file_priv-g2d_priv;
struct g2d_cmdlist_userptr *g2d_userptr;
struct g2d_data *g2d;
-   struct page **pages;
struct sg_table *sgt;
-   struct vm_area_struct *vma;
unsigned long start, end;
unsigned int npages, offset;
int ret;
@@ -456,65 +455,38 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct 
drm_device *drm_dev,
return ERR_PTR(-ENOMEM);
 
atomic_set(g2d_userptr-refcount, 1);
+   g2d_userptr-size = size;
 
start = userptr  PAGE_MASK;
offset = userptr  ~PAGE_MASK;
end = PAGE_ALIGN(userptr + size);
npages = (end - start)  PAGE_SHIFT;
-   g2d_userptr-npages = npages;
-
-   pages = drm_calloc_large(npages, sizeof(struct page *));
-   if (!pages) {
-   DRM_ERROR(failed to allocate pages.\n);
-   ret = -ENOMEM;
+   g2d_userptr-vec = frame_vector_create(npages);
+   if (!g2d_userptr-vec)
goto err_free;
-   }
 
-   down_read(current-mm-mmap_sem);
-   vma = find_vma(current-mm, userptr);
-   if (!vma) {
-   up_read(current-mm-mmap_sem);
-   DRM_ERROR(failed to get vm region.\n);
+   ret = get_vaddr_frames(start, npages, true, true, g2d_userptr-vec);
+   if (ret != npages) {
+   DRM_ERROR(failed to get user pages from userptr.\n);
+   if (ret  0)
+   goto err_destroy_framevec;
ret = -EFAULT;
-   goto err_free_pages;
+   goto err_put_framevec;
}
-
-   if (vma-vm_end  userptr + size) {
-   up_read(current-mm-mmap_sem);
-   DRM_ERROR(vma is too small.\n);
+   if (frame_vector_to_pages(g2d_userptr-vec)  0) {
ret = -EFAULT;
-   goto err_free_pages

[PATCH 0/9 v7] Helper to abstract vma handling in media layer

2015-07-13 Thread Jan Kara
From: Jan Kara j...@suse.cz

  Hello,

I'm sending the seventh version of my patch series to abstract vma handling
from the various media drivers. Since the previous version there are just
minor cleanups and fixes (see detailed changelog at the end of the email).

After this patch set drivers have to know much less details about vmas, their
types, and locking. Also quite some code is removed from them. As a bonus
drivers get automatically VM_FAULT_RETRY handling. The primary motivation for
this series is to remove knowledge about mmap_sem locking from as many places a
possible so that we can change it with reasonable effort.

The core of the series is the new helper get_vaddr_frames() which is given a
virtual address and it fills in PFNs / struct page pointers (depending on VMA
type) into the provided array. If PFNs correspond to normal pages it also grabs
references to these pages. The difference from get_user_pages() is that this
function can also deal with pfnmap, and io mappings which is what the media
drivers need.

I have tested the patches with vivid driver so at least vb2 code got some
exposure. Conversion of other drivers was just compile-tested (for x86 so e.g.
exynos driver which is only for Samsung platform is completely untested).

Hans, can you please pull the changes? Thanks!

Honza

Changes since v6:
* Fixed compilation error introduced into exynos driver
* Folded patch allowing get_vaddr_pfn() code to be selected by a config option
  into previous patches
* Rebased on top of linux-media tree

Changes since v5:
* Moved mm helper into a separate file and behind a config option
* Changed the first patch pushing mmap_sem down in videobuf2 core to avoid
  possible deadlock

Changes since v4:
* Minor cleanups and fixes pointed out by Mel and Vlasta
* Added Acked-by tags

Changes since v3:
* Added include linux/vmalloc.h into mm/gup.c as it's needed for some archs
* Fixed error path for exynos driver

Changes since v2:
* Renamed functions and structures as Mel suggested
* Other minor changes suggested by Mel
* Rebased on top of 4.1-rc2
* Changed functions to get pointer to array of pages / pfns to perform
  conversion if necessary. This fixes possible issue in the omap I may have
  introduced in v2 and generally makes the API less errorprone.
--
To unsubscribe from this list: send the line unsubscribe linux-media in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 5/9] media: vb2: Convert vb2_dma_sg_get_userptr() to use frame vector

2015-07-13 Thread Jan Kara
From: Jan Kara j...@suse.cz

Acked-by: Marek Szyprowski m.szyprow...@samsung.com
Tested-by: Marek Szyprowski m.szyprow...@samsung.com
Signed-off-by: Jan Kara j...@suse.cz
---
 drivers/media/v4l2-core/videobuf2-dma-sg.c | 95 +-
 1 file changed, 15 insertions(+), 80 deletions(-)

diff --git a/drivers/media/v4l2-core/videobuf2-dma-sg.c 
b/drivers/media/v4l2-core/videobuf2-dma-sg.c
index d2cf113d1933..be7bd6535c9d 100644
--- a/drivers/media/v4l2-core/videobuf2-dma-sg.c
+++ b/drivers/media/v4l2-core/videobuf2-dma-sg.c
@@ -38,6 +38,7 @@ struct vb2_dma_sg_buf {
struct device   *dev;
void*vaddr;
struct page **pages;
+   struct frame_vector *vec;
int offset;
enum dma_data_direction dma_dir;
struct sg_table sg_table;
@@ -51,7 +52,6 @@ struct vb2_dma_sg_buf {
unsigned intnum_pages;
atomic_trefcount;
struct vb2_vmarea_handler   handler;
-   struct vm_area_struct   *vma;
 
struct dma_buf_attachment   *db_attach;
 };
@@ -225,25 +225,17 @@ static void vb2_dma_sg_finish(void *buf_priv)
dma_sync_sg_for_cpu(buf-dev, sgt-sgl, sgt-nents, buf-dma_dir);
 }
 
-static inline int vma_is_io(struct vm_area_struct *vma)
-{
-   return !!(vma-vm_flags  (VM_IO | VM_PFNMAP));
-}
-
 static void *vb2_dma_sg_get_userptr(void *alloc_ctx, unsigned long vaddr,
unsigned long size,
enum dma_data_direction dma_dir)
 {
struct vb2_dma_sg_conf *conf = alloc_ctx;
struct vb2_dma_sg_buf *buf;
-   unsigned long first, last;
-   int num_pages_from_user;
-   struct vm_area_struct *vma;
struct sg_table *sgt;
DEFINE_DMA_ATTRS(attrs);
+   struct frame_vector *vec;
 
dma_set_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs);
-
buf = kzalloc(sizeof *buf, GFP_KERNEL);
if (!buf)
return NULL;
@@ -254,63 +246,19 @@ static void *vb2_dma_sg_get_userptr(void *alloc_ctx, 
unsigned long vaddr,
buf-offset = vaddr  ~PAGE_MASK;
buf-size = size;
buf-dma_sgt = buf-sg_table;
+   vec = vb2_create_framevec(vaddr, size, buf-dma_dir == DMA_FROM_DEVICE);
+   if (IS_ERR(vec))
+   goto userptr_fail_pfnvec;
+   buf-vec = vec;
 
-   first = (vaddrPAGE_MASK)  PAGE_SHIFT;
-   last  = ((vaddr + size - 1)  PAGE_MASK)  PAGE_SHIFT;
-   buf-num_pages = last - first + 1;
-
-   buf-pages = kzalloc(buf-num_pages * sizeof(struct page *),
-GFP_KERNEL);
-   if (!buf-pages)
-   goto userptr_fail_alloc_pages;
-
-   down_read(current-mm-mmap_sem);
-   vma = find_vma(current-mm, vaddr);
-   if (!vma) {
-   dprintk(1, no vma for address %lu\n, vaddr);
-   goto userptr_fail_find_vma;
-   }
-
-   if (vma-vm_end  vaddr + size) {
-   dprintk(1, vma at %lu is too small for %lu bytes\n,
-   vaddr, size);
-   goto userptr_fail_find_vma;
-   }
-
-   buf-vma = vb2_get_vma(vma);
-   if (!buf-vma) {
-   dprintk(1, failed to copy vma\n);
-   goto userptr_fail_find_vma;
-   }
-
-   if (vma_is_io(buf-vma)) {
-   for (num_pages_from_user = 0;
-num_pages_from_user  buf-num_pages;
-++num_pages_from_user, vaddr += PAGE_SIZE) {
-   unsigned long pfn;
-
-   if (follow_pfn(vma, vaddr, pfn)) {
-   dprintk(1, no page for address %lu\n, vaddr);
-   break;
-   }
-   buf-pages[num_pages_from_user] = pfn_to_page(pfn);
-   }
-   } else
-   num_pages_from_user = get_user_pages(current, current-mm,
-vaddr  PAGE_MASK,
-buf-num_pages,
-buf-dma_dir == DMA_FROM_DEVICE,
-1, /* force */
-buf-pages,
-NULL);
-   up_read(current-mm-mmap_sem);
-
-   if (num_pages_from_user != buf-num_pages)
-   goto userptr_fail_get_user_pages;
+   buf-pages = frame_vector_pages(vec);
+   if (IS_ERR(buf-pages))
+   goto userptr_fail_sgtable;
+   buf-num_pages = frame_vector_count(vec);
 
if (sg_alloc_table_from_pages(buf-dma_sgt, buf-pages,
buf-num_pages, buf-offset, size, 0))
-   goto userptr_fail_alloc_table_from_pages;
+   goto userptr_fail_sgtable;
 
sgt = buf-sg_table

[PATCH 1/9] [media] vb2: Push mmap_sem down to memops

2015-07-13 Thread Jan Kara
From: Jan Kara j...@suse.cz

Currently vb2 core acquires mmap_sem just around call to
__qbuf_userptr(). However since commit f035eb4e976ef5 (videobuf2: fix
lockdep warning) it isn't necessary to acquire it so early as we no
longer have to drop queue mutex before acquiring mmap_sem. So push
acquisition of mmap_sem down into .get_userptr memop so that the
semaphore is acquired for a shorter time and it is clearer what it is
needed for.

Note that we also need mmap_sem in .put_userptr memop since that ends up
calling vb2_put_vma() which calls vma-vm_ops-close() which should be
called with mmap_sem held. However we didn't hold mmap_sem in some code
paths anyway (e.g. when called via vb2_ioctl_reqbufs() -
__vb2_queue_free() - vb2_dma_sg_put_userptr()) and getting mmap_sem in
put_userptr() introduces a lock inversion with queue-mmap_lock in the
above mentioned call path.

Luckily this whole locking mess will get resolved once we convert
videobuf2 core to the new mm helper which avoids the need for mmap_sem
in .put_userptr memop altogether.

Signed-off-by: Jan Kara j...@suse.cz
---
 drivers/media/v4l2-core/videobuf2-core.c   | 2 --
 drivers/media/v4l2-core/videobuf2-dma-contig.c | 5 +
 drivers/media/v4l2-core/videobuf2-dma-sg.c | 4 
 drivers/media/v4l2-core/videobuf2-vmalloc.c| 4 +++-
 4 files changed, 12 insertions(+), 3 deletions(-)

diff --git a/drivers/media/v4l2-core/videobuf2-core.c 
b/drivers/media/v4l2-core/videobuf2-core.c
index 93b315459098..4df6dfc47fc8 100644
--- a/drivers/media/v4l2-core/videobuf2-core.c
+++ b/drivers/media/v4l2-core/videobuf2-core.c
@@ -1675,9 +1675,7 @@ static int __buf_prepare(struct vb2_buffer *vb, const 
struct v4l2_buffer *b)
ret = __qbuf_mmap(vb, b);
break;
case V4L2_MEMORY_USERPTR:
-   down_read(current-mm-mmap_sem);
ret = __qbuf_userptr(vb, b);
-   up_read(current-mm-mmap_sem);
break;
case V4L2_MEMORY_DMABUF:
ret = __qbuf_dmabuf(vb, b);
diff --git a/drivers/media/v4l2-core/videobuf2-dma-contig.c 
b/drivers/media/v4l2-core/videobuf2-dma-contig.c
index 94c1e6455d36..c548ce425701 100644
--- a/drivers/media/v4l2-core/videobuf2-dma-contig.c
+++ b/drivers/media/v4l2-core/videobuf2-dma-contig.c
@@ -616,6 +616,7 @@ static void *vb2_dc_get_userptr(void *alloc_ctx, unsigned 
long vaddr,
goto fail_buf;
}
 
+   down_read(current-mm-mmap_sem);
/* current-mm-mmap_sem is taken by videobuf2 core */
vma = find_vma(current-mm, vaddr);
if (!vma) {
@@ -642,6 +643,7 @@ static void *vb2_dc_get_userptr(void *alloc_ctx, unsigned 
long vaddr,
if (ret) {
unsigned long pfn;
if (vb2_dc_get_user_pfn(start, n_pages, vma, pfn) == 0) {
+   up_read(current-mm-mmap_sem);
buf-dma_addr = vb2_dc_pfn_to_dma(buf-dev, pfn);
buf-size = size;
kfree(pages);
@@ -651,6 +653,7 @@ static void *vb2_dc_get_userptr(void *alloc_ctx, unsigned 
long vaddr,
pr_err(failed to get user pages\n);
goto fail_vma;
}
+   up_read(current-mm-mmap_sem);
 
sgt = kzalloc(sizeof(*sgt), GFP_KERNEL);
if (!sgt) {
@@ -713,10 +716,12 @@ fail_get_user_pages:
while (n_pages)
put_page(pages[--n_pages]);
 
+   down_read(current-mm-mmap_sem);
 fail_vma:
vb2_put_vma(buf-vma);
 
 fail_pages:
+   up_read(current-mm-mmap_sem);
kfree(pages); /* kfree is NULL-proof */
 
 fail_buf:
diff --git a/drivers/media/v4l2-core/videobuf2-dma-sg.c 
b/drivers/media/v4l2-core/videobuf2-dma-sg.c
index 7289b81bd7b7..d2cf113d1933 100644
--- a/drivers/media/v4l2-core/videobuf2-dma-sg.c
+++ b/drivers/media/v4l2-core/videobuf2-dma-sg.c
@@ -264,6 +264,7 @@ static void *vb2_dma_sg_get_userptr(void *alloc_ctx, 
unsigned long vaddr,
if (!buf-pages)
goto userptr_fail_alloc_pages;
 
+   down_read(current-mm-mmap_sem);
vma = find_vma(current-mm, vaddr);
if (!vma) {
dprintk(1, no vma for address %lu\n, vaddr);
@@ -302,6 +303,7 @@ static void *vb2_dma_sg_get_userptr(void *alloc_ctx, 
unsigned long vaddr,
 1, /* force */
 buf-pages,
 NULL);
+   up_read(current-mm-mmap_sem);
 
if (num_pages_from_user != buf-num_pages)
goto userptr_fail_get_user_pages;
@@ -331,8 +333,10 @@ userptr_fail_get_user_pages:
if (!vma_is_io(buf-vma))
while (--num_pages_from_user = 0)
put_page(buf-pages[num_pages_from_user]);
+   down_read(current-mm-mmap_sem);
vb2_put_vma(buf-vma);
 userptr_fail_find_vma:
+   up_read(current-mm-mmap_sem);
kfree(buf-pages);
 userptr_fail_alloc_pages

Re: [PATCH 0/10 v6] Helper to abstract vma handling in media layer

2015-07-09 Thread Jan Kara
  Hello,

  Hans, did you have a chance to look at these patches? I have tested them
with the vivid driver but it would be good if you could run them through
your standard testing procedure as well. Andrew has updated the patches in
his tree but some ack from you would be welcome...

Honza
On Thu 18-06-15 16:08:30, Jan Kara wrote:
   Hello,
 
 I'm sending the sixth version of my patch series to abstract vma handling from
 the various media drivers. Since the previous version I have added a patch to
 move mm helpers into a separate file and behind a config option. I also
 changed patch pushing mmap_sem down in videobuf2 core to avoid lockdep warning
 and NULL dereference Hans found in his testing. I've also included small
 fixups Andrew was carrying.
 
 After this patch set drivers have to know much less details about vmas, their
 types, and locking. Also quite some code is removed from them. As a bonus
 drivers get automatically VM_FAULT_RETRY handling. The primary motivation for
 this series is to remove knowledge about mmap_sem locking from as many places 
 a
 possible so that we can change it with reasonable effort.
 
 The core of the series is the new helper get_vaddr_frames() which is given a
 virtual address and it fills in PFNs / struct page pointers (depending on VMA
 type) into the provided array. If PFNs correspond to normal pages it also 
 grabs
 references to these pages. The difference from get_user_pages() is that this
 function can also deal with pfnmap, and io mappings which is what the media
 drivers need.
 
 I have tested the patches with vivid driver so at least vb2 code got some
 exposure. Conversion of other drivers was just compile-tested (for x86 so e.g.
 exynos driver which is only for Samsung platform is completely untested).
 
 Andrew, can you please update the patches in mm three? Thanks!
 
   Honza
 
 Changes since v5:
 * Moved mm helper into a separate file and behind a config option
 * Changed the first patch pushing mmap_sem down in videobuf2 core to avoid
   possible deadlock
 
 Changes since v4:
 * Minor cleanups and fixes pointed out by Mel and Vlasta
 * Added Acked-by tags
 
 Changes since v3:
 * Added include linux/vmalloc.h into mm/gup.c as it's needed for some archs
 * Fixed error path for exynos driver
 
 Changes since v2:
 * Renamed functions and structures as Mel suggested
 * Other minor changes suggested by Mel
 * Rebased on top of 4.1-rc2
 * Changed functions to get pointer to array of pages / pfns to perform
   conversion if necessary. This fixes possible issue in the omap I may have
   introduced in v2 and generally makes the API less errorprone.
-- 
Jan Kara j...@suse.cz
SUSE Labs, CR
--
To unsubscribe from this list: send the line unsubscribe linux-media in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 9/9] [media] mm: Move get_vaddr_frames() behind a config option

2015-06-18 Thread Jan Kara
On Wed 10-06-15 09:37:20, Josh Triplett wrote:
 On Wed, Jun 10, 2015 at 06:20:52AM -0300, Mauro Carvalho Chehab wrote:
  From: Jan Kara j...@suse.cz
  
  get_vaddr_frames() is used by relatively rare drivers so hide it and the
  related functions behind a config option that is selected only by
  drivers that need the infrastructure.
  
  Suggested-by: Andrew Morton a...@linux-foundation.org
  
  Signed-off-by: Jan Kara j...@suse.cz
  Signed-off-by: Hans Verkuil hans.verk...@cisco.com
  Signed-off-by: Mauro Carvalho Chehab mche...@osg.samsung.com
 
 Seems sensible to me.
 
 Since this patch makes the kernel smaller, can you include the delta
 from bloat-o-meter between allnoconfig with and without this patch?

The results are:

add/remove: 0/6 grow/shrink: 0/0 up/down: 0/-868 (-868)
function old new   delta
frame_vector_destroy  55   - -55
frame_vector_to_pfns  56   - -56
frame_vector_create   81   - -81
put_vaddr_frames  93   - -93
frame_vector_to_pages 98   - -98
get_vaddr_frames 485   --485

I've added it to the changelog of the patch.

 Also, I assume you've compile-tested the kernel with allyesconfig minus
 the three options that now have select FRAME_VECTOR, to make sure it
 builds?
  I did not because the config option VIDEOBUF2_MEMOPS is a virtual one
selected transitively by quite a few video drivers and I didn't bother with
tracking down all of them... But since that config option guards
compilation of the code I modified I'm pretty confident I got it right.

Honza

   create mode 100644 mm/frame_vector.c
  
  diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig
  index 0a6780367d28..fc678289cf79 100644
  --- a/drivers/gpu/drm/exynos/Kconfig
  +++ b/drivers/gpu/drm/exynos/Kconfig
  @@ -71,6 +71,7 @@ config DRM_EXYNOS_VIDI
   config DRM_EXYNOS_G2D
  bool Exynos DRM G2D
  depends on DRM_EXYNOS  !VIDEO_SAMSUNG_S5P_G2D
  +   select FRAME_VECTOR
  help
Choose this option if you want to use Exynos G2D for DRM.
   
  diff --git a/drivers/media/platform/omap/Kconfig 
  b/drivers/media/platform/omap/Kconfig
  index dc2aaab54aef..217d613b0fe7 100644
  --- a/drivers/media/platform/omap/Kconfig
  +++ b/drivers/media/platform/omap/Kconfig
  @@ -10,6 +10,7 @@ config VIDEO_OMAP2_VOUT
  select OMAP2_DSS if HAS_IOMEM  ARCH_OMAP2PLUS
  select OMAP2_VRFB if ARCH_OMAP2 || ARCH_OMAP3
  select VIDEO_OMAP2_VOUT_VRFB if VIDEO_OMAP2_VOUT  OMAP2_VRFB
  +   select FRAME_VECTOR
  default n
  ---help---
V4L2 Display driver support for OMAP2/3 based boards.
  diff --git a/drivers/media/v4l2-core/Kconfig 
  b/drivers/media/v4l2-core/Kconfig
  index f7a01a72eb9e..f38f6e387f04 100644
  --- a/drivers/media/v4l2-core/Kconfig
  +++ b/drivers/media/v4l2-core/Kconfig
  @@ -73,6 +73,7 @@ config VIDEOBUF2_CORE
   
   config VIDEOBUF2_MEMOPS
  tristate
  +   select FRAME_VECTOR
   
   config VIDEOBUF2_DMA_CONTIG
  tristate
  diff --git a/mm/Kconfig b/mm/Kconfig
  index 390214da4546..2ca52e9986f0 100644
  --- a/mm/Kconfig
  +++ b/mm/Kconfig
  @@ -635,3 +635,6 @@ config MAX_STACK_SIZE_MB
changed to a smaller value in which case that is used.
   
A sane initial value is 80 MB.
  +
  +config FRAME_VECTOR
  +   bool
  diff --git a/mm/Makefile b/mm/Makefile
  index 98c4eaeabdcb..be5d5c866305 100644
  --- a/mm/Makefile
  +++ b/mm/Makefile
  @@ -78,3 +78,4 @@ obj-$(CONFIG_CMA) += cma.o
   obj-$(CONFIG_MEMORY_BALLOON) += balloon_compaction.o
   obj-$(CONFIG_PAGE_EXTENSION) += page_ext.o
   obj-$(CONFIG_CMA_DEBUGFS) += cma_debug.o
  +obj-$(CONFIG_FRAME_VECTOR) += frame_vector.o
  diff --git a/mm/frame_vector.c b/mm/frame_vector.c
  new file mode 100644
  index ..31a2bd5f41d5
  --- /dev/null
  +++ b/mm/frame_vector.c
  @@ -0,0 +1,232 @@
  +#include linux/kernel.h
  +#include linux/errno.h
  +#include linux/err.h
  +#include linux/mm.h
  +#include linux/slab.h
  +#include linux/pagemap.h
  +#include linux/sched.h
  +
  +/*
  + * get_vaddr_frames() - map virtual addresses to pfns
  + * @start: starting user address
  + * @nr_frames: number of pages / pfns from start to map
  + * @write: whether pages will be written to by the caller
  + * @force: whether to force write access even if user mapping is
  + * readonly. See description of the same argument of
  +   get_user_pages().
  + * @vec:   structure which receives pages / pfns of the addresses mapped.
  + * It should have space for at least nr_frames entries.
  + *
  + * This function maps virtual addresses from @start and fills @vec 
  structure
  + * with page frame numbers or page pointers to corresponding pages (choice
  + * depends on the type of the vma

Re: [PATCH] Revert [media] vb2: Push mmap_sem down to memops

2015-06-18 Thread Jan Kara
On Thu 18-06-15 12:45:26, Hans Verkuil wrote:
 On 06/18/2015 12:33 PM, Jan Kara wrote:
  On Mon 15-06-15 09:24:55, Hans Verkuil wrote:
  This reverts commit 48b25a3a713b90988b6882d318f7c0a6bed9aabc.
 
  That commit caused two regressions. The first is a BUG:
 
  BUG: unable to handle kernel NULL pointer dereference at 0100
  IP: [810d5cd0] __lock_acquire+0x2f0/0x2070
  PGD 0
  Oops:  [#1] PREEMPT SMP
  Modules linked in: vivid v4l2_dv_timings videobuf2_vmalloc 
  videobuf2_memops videobuf2_core v4l2_common videodev media vmw_balloon 
  vmw_vmci acpi_cpufreq processor button
  CPU: 0 PID: 1542 Comm: v4l2-ctl Not tainted 4.1.0-rc3-test-media #1190
  Hardware name: VMware, Inc. VMware Virtual Platform/440BX Desktop 
  Reference Platform, BIOS 6.00 05/20/2014
  task: 880220ce4200 ti: 88021d16c000 task.ti: 88021d16c000
  RIP: 0010:[810d5cd0]  [810d5cd0] 
  __lock_acquire+0x2f0/0x2070
  RSP: 0018:88021d16f9b8  EFLAGS: 00010002
  RAX: 0046 RBX: 0292 RCX: 0001
  RDX:  RSI: 0001 RDI: 0100
  RBP: 88021d16fa88 R08: 0001 R09: 
  R10: 0001 R11:  R12: 0001
  R13: 880220ce4200 R14: 0100 R15: 
  FS:  7f2441e7f740() GS:880236e0() 
  knlGS:
  CS:  0010 DS:  ES:  CR0: 8005003b
  CR2: 0100 CR3: 01e0b000 CR4: 001406f0
  Stack:
   88021d16fa98 810d6543 0006 0246
   88021d16fa08 810d532d 880220ce4a78 8802
   88020001  0001 0093a4a0
  Call Trace:
   [810d6543] ? __lock_acquire+0xb63/0x2070
   [810d532d] ? mark_held_locks+0x6d/0xa0
   [810d37a8] ? __lock_is_held+0x58/0x80
   [810d852c] lock_acquire+0x6c/0xa0
   [a039f1f6] ? vb2_vmalloc_put_userptr+0x36/0x110 
  [videobuf2_vmalloc]
   [819b1a92] down_read+0x42/0x60
   [a039f1f6] ? vb2_vmalloc_put_userptr+0x36/0x110 
  [videobuf2_vmalloc]
   [819af1b1] ? mutex_lock_nested+0x2b1/0x560
   [a038fdc5] ? vb2_queue_release+0x25/0x40 [videobuf2_core]
   [a039f1f6] vb2_vmalloc_put_userptr+0x36/0x110 
  [videobuf2_vmalloc]
   [a038b626] __vb2_queue_free+0x146/0x5e0 [videobuf2_core]
   [a038fdd3] vb2_queue_release+0x33/0x40 [videobuf2_core]
   [a038fe75] _vb2_fop_release+0x95/0xb0 [videobuf2_core]
   [a038feb9] vb2_fop_release+0x29/0x50 [videobuf2_core]
   [a03ad372] vivid_fop_release+0x92/0x230 [vivid]
   [a0358460] v4l2_release+0x30/0x80 [videodev]
   [811a51d5] __fput+0xe5/0x200
   [811a5339] fput+0x9/0x10
   [810a9fa4] task_work_run+0xc4/0xf0
   [8108c670] do_exit+0x3a0/0xaf0
   [819b3a9b] ? _raw_spin_unlock_irq+0x2b/0x60
   [8108e0ff] do_group_exit+0x4f/0xe0
   [8109a170] get_signal+0x200/0x8c0
   [819b14b5] ? __mutex_unlock_slowpath+0xf5/0x240
   [81002593] do_signal+0x23/0x820
   [819b1609] ? mutex_unlock+0x9/0x10
   [a0358648] ? v4l2_ioctl+0x78/0xf0 [videodev]
   [819b4653] ? int_very_careful+0x5/0x46
   [810d54bd] ? trace_hardirqs_on_caller+0x15d/0x200
   [81002de0] do_notify_resume+0x50/0x60
   [819b46a6] int_signal+0x12/0x17
  Code: ca 81 31 c0 e8 7a e2 8c 00 e8 aa 1d 8d 00 0f 1f 44 00 00 31 db 48 81 
  c4 a8 00 00 00 89 d8 5b 41 5c 41 5d 41 5e 41 5f 5d c3 66 90 49 81 3e 40 
  4e 02 82 b8 00 00 00 00 44 0f 44 e0 41 83 ff 01 0f
  RIP  [810d5cd0] __lock_acquire+0x2f0/0x2070
   RSP 88021d16f9b8
  CR2: 0100
  ---[ end trace 25595c2b8560cb57 ]---
  Fixing recursive fault but reboot is needed!
  
  Ah, that's tricky. We can end up calling task_work_run() via
  exit_task_work() after mm has been shut down. And the task work will be
  dropping the last reference to all file descriptors which ends up shutting
  down vb2 after current-mm has been cleaned up.
  
  So in the light of this it's probably better for the initial patch to
  completely avoid grabbing mmap_sem in put_userptr(). It breaks locking for
  vma-vm_ops-close() but that's already broken in vb2 as I explained in my
  other email. And the remainder of the patch set will make sure we don't
  need mmap_sem in put_userptr() at all and thus fixes the whole issue.
  
  This also explains why I never saw the problem in my testing - I was always
  testing the patch set as a whole.
  
  I'll send an updated first patch later today.
 
 OK, good. I'm thinking: if it is OK with Andrew, then the low-level mm changes
 can be merged for 4.2 through his tree since that doesn't affect anything else
 (right?), but the vb2 changes I prefer to postpone to 4.3. I'd like to give it
 enough time for testing and shake-out any remaining issues (hopefully

[PATCH 8/10] media: vb2: Remove unused functions

2015-06-18 Thread Jan Kara
Conversion to the use of pinned pfns made some functions unused. Remove
them. Also there's no need to lock mmap_sem in __buf_prepare() anymore.

Acked-by: Marek Szyprowski m.szyprow...@samsung.com
Tested-by: Marek Szyprowski m.szyprow...@samsung.com
Signed-off-by: Jan Kara j...@suse.cz
---
 drivers/media/v4l2-core/videobuf2-memops.c | 114 -
 include/media/videobuf2-memops.h   |   6 --
 2 files changed, 120 deletions(-)

diff --git a/drivers/media/v4l2-core/videobuf2-memops.c 
b/drivers/media/v4l2-core/videobuf2-memops.c
index 0ec186d41b9b..48c6a49c4928 100644
--- a/drivers/media/v4l2-core/videobuf2-memops.c
+++ b/drivers/media/v4l2-core/videobuf2-memops.c
@@ -23,120 +23,6 @@
 #include media/videobuf2-memops.h
 
 /**
- * vb2_get_vma() - acquire and lock the virtual memory area
- * @vma:   given virtual memory area
- *
- * This function attempts to acquire an area mapped in the userspace for
- * the duration of a hardware operation. The area is locked by performing
- * the same set of operation that are done when process calls fork() and
- * memory areas are duplicated.
- *
- * Returns a copy of a virtual memory region on success or NULL.
- */
-struct vm_area_struct *vb2_get_vma(struct vm_area_struct *vma)
-{
-   struct vm_area_struct *vma_copy;
-
-   vma_copy = kmalloc(sizeof(*vma_copy), GFP_KERNEL);
-   if (vma_copy == NULL)
-   return NULL;
-
-   if (vma-vm_ops  vma-vm_ops-open)
-   vma-vm_ops-open(vma);
-
-   if (vma-vm_file)
-   get_file(vma-vm_file);
-
-   memcpy(vma_copy, vma, sizeof(*vma));
-
-   vma_copy-vm_mm = NULL;
-   vma_copy-vm_next = NULL;
-   vma_copy-vm_prev = NULL;
-
-   return vma_copy;
-}
-EXPORT_SYMBOL_GPL(vb2_get_vma);
-
-/**
- * vb2_put_userptr() - release a userspace virtual memory area
- * @vma:   virtual memory region associated with the area to be released
- *
- * This function releases the previously acquired memory area after a hardware
- * operation.
- */
-void vb2_put_vma(struct vm_area_struct *vma)
-{
-   if (!vma)
-   return;
-
-   if (vma-vm_ops  vma-vm_ops-close)
-   vma-vm_ops-close(vma);
-
-   if (vma-vm_file)
-   fput(vma-vm_file);
-
-   kfree(vma);
-}
-EXPORT_SYMBOL_GPL(vb2_put_vma);
-
-/**
- * vb2_get_contig_userptr() - lock physically contiguous userspace mapped 
memory
- * @vaddr: starting virtual address of the area to be verified
- * @size:  size of the area
- * @res_paddr: will return physical address for the given vaddr
- * @res_vma:   will return locked copy of struct vm_area for the given area
- *
- * This function will go through memory area of size @size mapped at @vaddr and
- * verify that the underlying physical pages are contiguous. If they are
- * contiguous the virtual memory area is locked and a @res_vma is filled with
- * the copy and @res_pa set to the physical address of the buffer.
- *
- * Returns 0 on success.
- */
-int vb2_get_contig_userptr(unsigned long vaddr, unsigned long size,
-  struct vm_area_struct **res_vma, dma_addr_t *res_pa)
-{
-   struct mm_struct *mm = current-mm;
-   struct vm_area_struct *vma;
-   unsigned long offset, start, end;
-   unsigned long this_pfn, prev_pfn;
-   dma_addr_t pa = 0;
-
-   start = vaddr;
-   offset = start  ~PAGE_MASK;
-   end = start + size;
-
-   vma = find_vma(mm, start);
-
-   if (vma == NULL || vma-vm_end  end)
-   return -EFAULT;
-
-   for (prev_pfn = 0; start  end; start += PAGE_SIZE) {
-   int ret = follow_pfn(vma, start, this_pfn);
-   if (ret)
-   return ret;
-
-   if (prev_pfn == 0)
-   pa = this_pfn  PAGE_SHIFT;
-   else if (this_pfn != prev_pfn + 1)
-   return -EFAULT;
-
-   prev_pfn = this_pfn;
-   }
-
-   /*
-* Memory is contigous, lock vma and return to the caller
-*/
-   *res_vma = vb2_get_vma(vma);
-   if (*res_vma == NULL)
-   return -ENOMEM;
-
-   *res_pa = pa + offset;
-   return 0;
-}
-EXPORT_SYMBOL_GPL(vb2_get_contig_userptr);
-
-/**
  * vb2_create_framevec() - map virtual addresses to pfns
  * @start: Virtual user address where we start mapping
  * @length:Length of a range to map
diff --git a/include/media/videobuf2-memops.h b/include/media/videobuf2-memops.h
index 2f0564ff5f31..830b5239fd8b 100644
--- a/include/media/videobuf2-memops.h
+++ b/include/media/videobuf2-memops.h
@@ -31,12 +31,6 @@ struct vb2_vmarea_handler {
 
 extern const struct vm_operations_struct vb2_common_vm_ops;
 
-int vb2_get_contig_userptr(unsigned long vaddr, unsigned long size,
-  struct vm_area_struct **res_vma, dma_addr_t *res_pa);
-
-struct vm_area_struct *vb2_get_vma(struct vm_area_struct *vma);
-void vb2_put_vma(struct vm_area_struct *vma

[PATCH 5/10] media: vb2: Convert vb2_dma_sg_get_userptr() to use frame vector

2015-06-18 Thread Jan Kara
Acked-by: Marek Szyprowski m.szyprow...@samsung.com
Tested-by: Marek Szyprowski m.szyprow...@samsung.com
Signed-off-by: Jan Kara j...@suse.cz
---
 drivers/media/v4l2-core/videobuf2-dma-sg.c | 95 +-
 1 file changed, 15 insertions(+), 80 deletions(-)

diff --git a/drivers/media/v4l2-core/videobuf2-dma-sg.c 
b/drivers/media/v4l2-core/videobuf2-dma-sg.c
index cdcf5ad79012..4ee1b3fbfe2a 100644
--- a/drivers/media/v4l2-core/videobuf2-dma-sg.c
+++ b/drivers/media/v4l2-core/videobuf2-dma-sg.c
@@ -38,6 +38,7 @@ struct vb2_dma_sg_buf {
struct device   *dev;
void*vaddr;
struct page **pages;
+   struct frame_vector *vec;
int offset;
enum dma_data_direction dma_dir;
struct sg_table sg_table;
@@ -51,7 +52,6 @@ struct vb2_dma_sg_buf {
unsigned intnum_pages;
atomic_trefcount;
struct vb2_vmarea_handler   handler;
-   struct vm_area_struct   *vma;
 
struct dma_buf_attachment   *db_attach;
 };
@@ -224,25 +224,17 @@ static void vb2_dma_sg_finish(void *buf_priv)
dma_sync_sg_for_cpu(buf-dev, sgt-sgl, sgt-nents, buf-dma_dir);
 }
 
-static inline int vma_is_io(struct vm_area_struct *vma)
-{
-   return !!(vma-vm_flags  (VM_IO | VM_PFNMAP));
-}
-
 static void *vb2_dma_sg_get_userptr(void *alloc_ctx, unsigned long vaddr,
unsigned long size,
enum dma_data_direction dma_dir)
 {
struct vb2_dma_sg_conf *conf = alloc_ctx;
struct vb2_dma_sg_buf *buf;
-   unsigned long first, last;
-   int num_pages_from_user;
-   struct vm_area_struct *vma;
struct sg_table *sgt;
DEFINE_DMA_ATTRS(attrs);
+   struct frame_vector *vec;
 
dma_set_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs);
-
buf = kzalloc(sizeof *buf, GFP_KERNEL);
if (!buf)
return NULL;
@@ -253,63 +245,19 @@ static void *vb2_dma_sg_get_userptr(void *alloc_ctx, 
unsigned long vaddr,
buf-offset = vaddr  ~PAGE_MASK;
buf-size = size;
buf-dma_sgt = buf-sg_table;
+   vec = vb2_create_framevec(vaddr, size, buf-dma_dir == DMA_FROM_DEVICE);
+   if (IS_ERR(vec))
+   goto userptr_fail_pfnvec;
+   buf-vec = vec;
 
-   first = (vaddrPAGE_MASK)  PAGE_SHIFT;
-   last  = ((vaddr + size - 1)  PAGE_MASK)  PAGE_SHIFT;
-   buf-num_pages = last - first + 1;
-
-   buf-pages = kzalloc(buf-num_pages * sizeof(struct page *),
-GFP_KERNEL);
-   if (!buf-pages)
-   goto userptr_fail_alloc_pages;
-
-   down_read(current-mm-mmap_sem);
-   vma = find_vma(current-mm, vaddr);
-   if (!vma) {
-   dprintk(1, no vma for address %lu\n, vaddr);
-   goto userptr_fail_find_vma;
-   }
-
-   if (vma-vm_end  vaddr + size) {
-   dprintk(1, vma at %lu is too small for %lu bytes\n,
-   vaddr, size);
-   goto userptr_fail_find_vma;
-   }
-
-   buf-vma = vb2_get_vma(vma);
-   if (!buf-vma) {
-   dprintk(1, failed to copy vma\n);
-   goto userptr_fail_find_vma;
-   }
-
-   if (vma_is_io(buf-vma)) {
-   for (num_pages_from_user = 0;
-num_pages_from_user  buf-num_pages;
-++num_pages_from_user, vaddr += PAGE_SIZE) {
-   unsigned long pfn;
-
-   if (follow_pfn(vma, vaddr, pfn)) {
-   dprintk(1, no page for address %lu\n, vaddr);
-   break;
-   }
-   buf-pages[num_pages_from_user] = pfn_to_page(pfn);
-   }
-   } else
-   num_pages_from_user = get_user_pages(current, current-mm,
-vaddr  PAGE_MASK,
-buf-num_pages,
-buf-dma_dir == DMA_FROM_DEVICE,
-1, /* force */
-buf-pages,
-NULL);
-   up_read(current-mm-mmap_sem);
-
-   if (num_pages_from_user != buf-num_pages)
-   goto userptr_fail_get_user_pages;
+   buf-pages = frame_vector_pages(vec);
+   if (IS_ERR(buf-pages))
+   goto userptr_fail_sgtable;
+   buf-num_pages = frame_vector_count(vec);
 
if (sg_alloc_table_from_pages(buf-dma_sgt, buf-pages,
buf-num_pages, buf-offset, size, 0))
-   goto userptr_fail_alloc_table_from_pages;
+   goto userptr_fail_sgtable;
 
sgt = buf-sg_table;
/*
@@ -323,19 +271,9

[PATCH 10/10] mm: Move get_vaddr_frames() behind a config option

2015-06-18 Thread Jan Kara
get_vaddr_frames() is used by relatively rare drivers so hide it and the
related functions behind a config option that is selected only by
drivers that need the infrastructure.

The saving are:
add/remove: 0/6 grow/shrink: 0/0 up/down: 0/-868 (-868)
function old new   delta
frame_vector_destroy  55   - -55
frame_vector_to_pfns  56   - -56
frame_vector_create   81   - -81
put_vaddr_frames  93   - -93
frame_vector_to_pages 98   - -98
get_vaddr_frames 485   --485

Suggested-by: Andrew Morton a...@linux-foundation.org
Signed-off-by: Jan Kara j...@suse.cz
---
 drivers/gpu/drm/exynos/Kconfig  |   1 +
 drivers/media/platform/omap/Kconfig |   1 +
 drivers/media/v4l2-core/Kconfig |   1 +
 mm/Kconfig  |   3 +
 mm/Makefile |   1 +
 mm/frame_vector.c   | 231 
 mm/gup.c| 222 --
 7 files changed, 238 insertions(+), 222 deletions(-)
 create mode 100644 mm/frame_vector.c

diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig
index 0a6780367d28..fc678289cf79 100644
--- a/drivers/gpu/drm/exynos/Kconfig
+++ b/drivers/gpu/drm/exynos/Kconfig
@@ -71,6 +71,7 @@ config DRM_EXYNOS_VIDI
 config DRM_EXYNOS_G2D
bool Exynos DRM G2D
depends on DRM_EXYNOS  !VIDEO_SAMSUNG_S5P_G2D
+   select FRAME_VECTOR
help
  Choose this option if you want to use Exynos G2D for DRM.
 
diff --git a/drivers/media/platform/omap/Kconfig 
b/drivers/media/platform/omap/Kconfig
index dc2aaab54aef..217d613b0fe7 100644
--- a/drivers/media/platform/omap/Kconfig
+++ b/drivers/media/platform/omap/Kconfig
@@ -10,6 +10,7 @@ config VIDEO_OMAP2_VOUT
select OMAP2_DSS if HAS_IOMEM  ARCH_OMAP2PLUS
select OMAP2_VRFB if ARCH_OMAP2 || ARCH_OMAP3
select VIDEO_OMAP2_VOUT_VRFB if VIDEO_OMAP2_VOUT  OMAP2_VRFB
+   select FRAME_VECTOR
default n
---help---
  V4L2 Display driver support for OMAP2/3 based boards.
diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig
index ba7e21a73023..0cb22add650b 100644
--- a/drivers/media/v4l2-core/Kconfig
+++ b/drivers/media/v4l2-core/Kconfig
@@ -73,6 +73,7 @@ config VIDEOBUF2_CORE
 
 config VIDEOBUF2_MEMOPS
tristate
+   select FRAME_VECTOR
 
 config VIDEOBUF2_DMA_CONTIG
tristate
diff --git a/mm/Kconfig b/mm/Kconfig
index 390214da4546..2ca52e9986f0 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -635,3 +635,6 @@ config MAX_STACK_SIZE_MB
  changed to a smaller value in which case that is used.
 
  A sane initial value is 80 MB.
+
+config FRAME_VECTOR
+   bool
diff --git a/mm/Makefile b/mm/Makefile
index 98c4eaeabdcb..be5d5c866305 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -78,3 +78,4 @@ obj-$(CONFIG_CMA) += cma.o
 obj-$(CONFIG_MEMORY_BALLOON) += balloon_compaction.o
 obj-$(CONFIG_PAGE_EXTENSION) += page_ext.o
 obj-$(CONFIG_CMA_DEBUGFS) += cma_debug.o
+obj-$(CONFIG_FRAME_VECTOR) += frame_vector.o
diff --git a/mm/frame_vector.c b/mm/frame_vector.c
new file mode 100644
index ..f76b579e46f1
--- /dev/null
+++ b/mm/frame_vector.c
@@ -0,0 +1,231 @@
+#include linux/kernel.h
+#include linux/errno.h
+#include linux/err.h
+#include linux/mm.h
+#include linux/slab.h
+#include linux/vmalloc.h
+#include linux/pagemap.h
+#include linux/sched.h
+
+/*
+ * get_vaddr_frames() - map virtual addresses to pfns
+ * @start: starting user address
+ * @nr_frames: number of pages / pfns from start to map
+ * @write: whether pages will be written to by the caller
+ * @force: whether to force write access even if user mapping is
+ * readonly. See description of the same argument of
+   get_user_pages().
+ * @vec:   structure which receives pages / pfns of the addresses mapped.
+ * It should have space for at least nr_frames entries.
+ *
+ * This function maps virtual addresses from @start and fills @vec structure
+ * with page frame numbers or page pointers to corresponding pages (choice
+ * depends on the type of the vma underlying the virtual address). If @start
+ * belongs to a normal vma, the function grabs reference to each of the pages
+ * to pin them in memory. If @start belongs to VM_IO | VM_PFNMAP vma, we don't
+ * touch page structures and the caller must make sure pfns aren't reused for
+ * anything else while he is using them.
+ *
+ * The function returns number of pages mapped which may be less than
+ * @nr_frames. In particular we stop mapping if there are more vmas of
+ * different type underlying the specified range of virtual addresses.
+ * When the function isn't able to map a single page, it returns error

[PATCH 3/10] media: omap_vout: Convert omap_vout_uservirt_to_phys() to use get_vaddr_pfns()

2015-06-18 Thread Jan Kara
Convert omap_vout_uservirt_to_phys() to use get_vaddr_pfns() instead of
hand made mapping of virtual address to physical address. Also the
function leaked page reference from get_user_pages() so fix that by
properly release the reference when omap_vout_buffer_release() is
called.

Signed-off-by: Jan Kara j...@suse.cz
---
 drivers/media/platform/omap/omap_vout.c | 67 +++--
 1 file changed, 31 insertions(+), 36 deletions(-)

diff --git a/drivers/media/platform/omap/omap_vout.c 
b/drivers/media/platform/omap/omap_vout.c
index 17b189a81ec5..0e4b3cfacc5d 100644
--- a/drivers/media/platform/omap/omap_vout.c
+++ b/drivers/media/platform/omap/omap_vout.c
@@ -195,46 +195,34 @@ static int omap_vout_try_format(struct v4l2_pix_format 
*pix)
 }
 
 /*
- * omap_vout_uservirt_to_phys: This inline function is used to convert user
- * space virtual address to physical address.
+ * omap_vout_get_userptr: Convert user space virtual address to physical
+ * address.
  */
-static unsigned long omap_vout_uservirt_to_phys(unsigned long virtp)
+static int omap_vout_get_userptr(struct videobuf_buffer *vb, u32 virtp,
+u32 *physp)
 {
-   unsigned long physp = 0;
-   struct vm_area_struct *vma;
-   struct mm_struct *mm = current-mm;
+   struct frame_vector *vec;
+   int ret;
 
/* For kernel direct-mapped memory, take the easy way */
-   if (virtp = PAGE_OFFSET)
-   return virt_to_phys((void *) virtp);
-
-   down_read(current-mm-mmap_sem);
-   vma = find_vma(mm, virtp);
-   if (vma  (vma-vm_flags  VM_IO)  vma-vm_pgoff) {
-   /* this will catch, kernel-allocated, mmaped-to-usermode
-  addresses */
-   physp = (vma-vm_pgoff  PAGE_SHIFT) + (virtp - vma-vm_start);
-   up_read(current-mm-mmap_sem);
-   } else {
-   /* otherwise, use get_user_pages() for general userland pages */
-   int res, nr_pages = 1;
-   struct page *pages;
+   if (virtp = PAGE_OFFSET) {
+   *physp = virt_to_phys((void *)virtp);
+   return 0;
+   }
 
-   res = get_user_pages(current, current-mm, virtp, nr_pages, 1,
-   0, pages, NULL);
-   up_read(current-mm-mmap_sem);
+   vec = frame_vector_create(1);
+   if (!vec)
+   return -ENOMEM;
 
-   if (res == nr_pages) {
-   physp =  __pa(page_address(pages[0]) +
-   (virtp  ~PAGE_MASK));
-   } else {
-   printk(KERN_WARNING VOUT_NAME
-   get_user_pages failed\n);
-   return 0;
-   }
+   ret = get_vaddr_frames(virtp, 1, true, false, vec);
+   if (ret != 1) {
+   frame_vector_destroy(vec);
+   return -EINVAL;
}
+   *physp = __pfn_to_phys(frame_vector_pfns(vec)[0]);
+   vb-priv = vec;
 
-   return physp;
+   return 0;
 }
 
 /*
@@ -788,11 +776,15 @@ static int omap_vout_buffer_prepare(struct videobuf_queue 
*q,
 * address of the buffer
 */
if (V4L2_MEMORY_USERPTR == vb-memory) {
+   int ret;
+
if (0 == vb-baddr)
return -EINVAL;
/* Physical address */
-   vout-queued_buf_addr[vb-i] = (u8 *)
-   omap_vout_uservirt_to_phys(vb-baddr);
+   ret = omap_vout_get_userptr(vb, vb-baddr,
+   (u32 *)vout-queued_buf_addr[vb-i]);
+   if (ret  0)
+   return ret;
} else {
unsigned long addr, dma_addr;
unsigned long size;
@@ -841,9 +833,12 @@ static void omap_vout_buffer_release(struct videobuf_queue 
*q,
struct omap_vout_device *vout = q-priv_data;
 
vb-state = VIDEOBUF_NEEDS_INIT;
+   if (vb-memory == V4L2_MEMORY_USERPTR  vb-priv) {
+   struct frame_vector *vec = vb-priv;
 
-   if (V4L2_MEMORY_MMAP != vout-memory)
-   return;
+   put_vaddr_frames(vec);
+   frame_vector_destroy(vec);
+   }
 }
 
 /*
-- 
2.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-media in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 6/10] media: vb2: Convert vb2_vmalloc_get_userptr() to use frame vector

2015-06-18 Thread Jan Kara
Convert vb2_vmalloc_get_userptr() to use frame vector infrastructure.
When we are doing that there's no need to allocate page array and some
code can be simplified.

Acked-by: Marek Szyprowski m.szyprow...@samsung.com
Tested-by: Marek Szyprowski m.szyprow...@samsung.com
Signed-off-by: Jan Kara j...@suse.cz
---
 drivers/media/v4l2-core/videobuf2-vmalloc.c | 92 +++--
 1 file changed, 36 insertions(+), 56 deletions(-)

diff --git a/drivers/media/v4l2-core/videobuf2-vmalloc.c 
b/drivers/media/v4l2-core/videobuf2-vmalloc.c
index 3199c379cd47..d2ce81fa2cdf 100644
--- a/drivers/media/v4l2-core/videobuf2-vmalloc.c
+++ b/drivers/media/v4l2-core/videobuf2-vmalloc.c
@@ -23,11 +23,9 @@
 
 struct vb2_vmalloc_buf {
void*vaddr;
-   struct page **pages;
-   struct vm_area_struct   *vma;
+   struct frame_vector *vec;
enum dma_data_direction dma_dir;
unsigned long   size;
-   unsigned intn_pages;
atomic_trefcount;
struct vb2_vmarea_handler   handler;
struct dma_buf  *dbuf;
@@ -76,10 +74,8 @@ static void *vb2_vmalloc_get_userptr(void *alloc_ctx, 
unsigned long vaddr,
 enum dma_data_direction dma_dir)
 {
struct vb2_vmalloc_buf *buf;
-   unsigned long first, last;
-   int n_pages, offset;
-   struct vm_area_struct *vma;
-   dma_addr_t physp;
+   struct frame_vector *vec;
+   int n_pages, offset, i;
 
buf = kzalloc(sizeof(*buf), GFP_KERNEL);
if (!buf)
@@ -88,53 +84,36 @@ static void *vb2_vmalloc_get_userptr(void *alloc_ctx, 
unsigned long vaddr,
buf-dma_dir = dma_dir;
offset = vaddr  ~PAGE_MASK;
buf-size = size;
-
-   down_read(current-mm-mmap_sem);
-   vma = find_vma(current-mm, vaddr);
-   if (vma  (vma-vm_flags  VM_PFNMAP)  (vma-vm_pgoff)) {
-   if (vb2_get_contig_userptr(vaddr, size, vma, physp))
-   goto fail_pages_array_alloc;
-   buf-vma = vma;
-   buf-vaddr = (__force void *)ioremap_nocache(physp, size);
-   if (!buf-vaddr)
-   goto fail_pages_array_alloc;
+   vec = vb2_create_framevec(vaddr, size, dma_dir == DMA_FROM_DEVICE);
+   if (IS_ERR(vec))
+   goto fail_pfnvec_create;
+   buf-vec = vec;
+   n_pages = frame_vector_count(vec);
+   if (frame_vector_to_pages(vec)  0) {
+   unsigned long *nums = frame_vector_pfns(vec);
+
+   /*
+* We cannot get page pointers for these pfns. Check memory is
+* physically contiguous and use direct mapping.
+*/
+   for (i = 1; i  n_pages; i++)
+   if (nums[i-1] + 1 != nums[i])
+   goto fail_map;
+   buf-vaddr = (__force void *)
+   ioremap_nocache(nums[0]  PAGE_SHIFT, size);
} else {
-   first = vaddr  PAGE_SHIFT;
-   last  = (vaddr + size - 1)  PAGE_SHIFT;
-   buf-n_pages = last - first + 1;
-   buf-pages = kzalloc(buf-n_pages * sizeof(struct page *),
-GFP_KERNEL);
-   if (!buf-pages)
-   goto fail_pages_array_alloc;
-
-   /* current-mm-mmap_sem is taken by videobuf2 core */
-   n_pages = get_user_pages(current, current-mm,
-vaddr  PAGE_MASK, buf-n_pages,
-dma_dir == DMA_FROM_DEVICE,
-1, /* force */
-buf-pages, NULL);
-   if (n_pages != buf-n_pages)
-   goto fail_get_user_pages;
-
-   buf-vaddr = vm_map_ram(buf-pages, buf-n_pages, -1,
+   buf-vaddr = vm_map_ram(frame_vector_pages(vec), n_pages, -1,
PAGE_KERNEL);
-   if (!buf-vaddr)
-   goto fail_get_user_pages;
}
-   up_read(current-mm-mmap_sem);
 
+   if (!buf-vaddr)
+   goto fail_map;
buf-vaddr += offset;
return buf;
 
-fail_get_user_pages:
-   pr_debug(get_user_pages requested/got: %d/%d]\n, n_pages,
-buf-n_pages);
-   while (--n_pages = 0)
-   put_page(buf-pages[n_pages]);
-   kfree(buf-pages);
-
-fail_pages_array_alloc:
-   up_read(current-mm-mmap_sem);
+fail_map:
+   vb2_destroy_framevec(vec);
+fail_pfnvec_create:
kfree(buf);
 
return NULL;
@@ -145,20 +124,21 @@ static void vb2_vmalloc_put_userptr(void *buf_priv)
struct vb2_vmalloc_buf *buf = buf_priv;
unsigned long vaddr = (unsigned long)buf-vaddr  PAGE_MASK;
unsigned int i

[PATCH 7/10] media: vb2: Convert vb2_dc_get_userptr() to use frame vector

2015-06-18 Thread Jan Kara
Convert vb2_dc_get_userptr() to use frame vector infrastructure. When we
are doing that there's no need to allocate page array and some code can
be simplified.

Acked-by: Marek Szyprowski m.szyprow...@samsung.com
Tested-by: Marek Szyprowski m.szyprow...@samsung.com
Signed-off-by: Jan Kara j...@suse.cz
---
 drivers/media/v4l2-core/videobuf2-dma-contig.c | 212 -
 1 file changed, 34 insertions(+), 178 deletions(-)

diff --git a/drivers/media/v4l2-core/videobuf2-dma-contig.c 
b/drivers/media/v4l2-core/videobuf2-dma-contig.c
index 8e660f033d3c..e6cea452302b 100644
--- a/drivers/media/v4l2-core/videobuf2-dma-contig.c
+++ b/drivers/media/v4l2-core/videobuf2-dma-contig.c
@@ -32,15 +32,13 @@ struct vb2_dc_buf {
dma_addr_t  dma_addr;
enum dma_data_direction dma_dir;
struct sg_table *dma_sgt;
+   struct frame_vector *vec;
 
/* MMAP related */
struct vb2_vmarea_handler   handler;
atomic_trefcount;
struct sg_table *sgt_base;
 
-   /* USERPTR related */
-   struct vm_area_struct   *vma;
-
/* DMABUF related */
struct dma_buf_attachment   *db_attach;
 };
@@ -49,24 +47,6 @@ struct vb2_dc_buf {
 /*scatterlist table functions*/
 /*/
 
-
-static void vb2_dc_sgt_foreach_page(struct sg_table *sgt,
-   void (*cb)(struct page *pg))
-{
-   struct scatterlist *s;
-   unsigned int i;
-
-   for_each_sg(sgt-sgl, s, sgt-orig_nents, i) {
-   struct page *page = sg_page(s);
-   unsigned int n_pages = PAGE_ALIGN(s-offset + s-length)
-PAGE_SHIFT;
-   unsigned int j;
-
-   for (j = 0; j  n_pages; ++j, ++page)
-   cb(page);
-   }
-}
-
 static unsigned long vb2_dc_get_contiguous_size(struct sg_table *sgt)
 {
struct scatterlist *s;
@@ -429,92 +409,12 @@ static struct dma_buf *vb2_dc_get_dmabuf(void *buf_priv, 
unsigned long flags)
 /*   callbacks for USERPTR buffers   */
 /*/
 
-static inline int vma_is_io(struct vm_area_struct *vma)
-{
-   return !!(vma-vm_flags  (VM_IO | VM_PFNMAP));
-}
-
-static int vb2_dc_get_user_pfn(unsigned long start, int n_pages,
-   struct vm_area_struct *vma, unsigned long *res)
-{
-   unsigned long pfn, start_pfn, prev_pfn;
-   unsigned int i;
-   int ret;
-
-   if (!vma_is_io(vma))
-   return -EFAULT;
-
-   ret = follow_pfn(vma, start, pfn);
-   if (ret)
-   return ret;
-
-   start_pfn = pfn;
-   start += PAGE_SIZE;
-
-   for (i = 1; i  n_pages; ++i, start += PAGE_SIZE) {
-   prev_pfn = pfn;
-   ret = follow_pfn(vma, start, pfn);
-
-   if (ret) {
-   pr_err(no page for address %lu\n, start);
-   return ret;
-   }
-   if (pfn != prev_pfn + 1)
-   return -EINVAL;
-   }
-
-   *res = start_pfn;
-   return 0;
-}
-
-static int vb2_dc_get_user_pages(unsigned long start, struct page **pages,
-   int n_pages, struct vm_area_struct *vma,
-   enum dma_data_direction dma_dir)
-{
-   if (vma_is_io(vma)) {
-   unsigned int i;
-
-   for (i = 0; i  n_pages; ++i, start += PAGE_SIZE) {
-   unsigned long pfn;
-   int ret = follow_pfn(vma, start, pfn);
-
-   if (!pfn_valid(pfn))
-   return -EINVAL;
-
-   if (ret) {
-   pr_err(no page for address %lu\n, start);
-   return ret;
-   }
-   pages[i] = pfn_to_page(pfn);
-   }
-   } else {
-   int n;
-
-   n = get_user_pages(current, current-mm, start  PAGE_MASK,
-   n_pages, dma_dir == DMA_FROM_DEVICE, 1, pages, NULL);
-   /* negative error means that no page was pinned */
-   n = max(n, 0);
-   if (n != n_pages) {
-   pr_err(got only %d of %d user pages\n, n, n_pages);
-   while (n)
-   put_page(pages[--n]);
-   return -EFAULT;
-   }
-   }
-
-   return 0;
-}
-
-static void vb2_dc_put_dirty_page(struct page *page)
-{
-   set_page_dirty_lock(page);
-   put_page(page);
-}
-
 static void vb2_dc_put_userptr(void *buf_priv)
 {
struct vb2_dc_buf *buf = buf_priv;
struct sg_table *sgt = buf-dma_sgt;
+   int i;
+   struct page **pages;
 
if (sgt) {
DEFINE_DMA_ATTRS(attrs);
@@ -526,13 +426,15 @@ static void vb2_dc_put_userptr(void *buf_priv

[PATCH 1/10] [media] vb2: Push mmap_sem down to memops

2015-06-18 Thread Jan Kara
Currently vb2 core acquires mmap_sem just around call to
__qbuf_userptr(). However since commit f035eb4e976ef5 (videobuf2: fix
lockdep warning) it isn't necessary to acquire it so early as we no
longer have to drop queue mutex before acquiring mmap_sem. So push
acquisition of mmap_sem down into .get_userptr memop so that the
semaphore is acquired for a shorter time and it is clearer what it is
needed for.

Note that we also need mmap_sem in .put_userptr memop since that ends up
calling vb2_put_vma() which calls vma-vm_ops-close() which should be
called with mmap_sem held. However we didn't hold mmap_sem in some code
paths anyway (e.g. when called via vb2_ioctl_reqbufs() -
__vb2_queue_free() - vb2_dma_sg_put_userptr()) and getting mmap_sem in
put_userptr() introduces a lock inversion with queue-mmap_lock in the
above mentioned call path.

Luckily this whole locking mess will get resolved once we convert
videobuf2 core to the new mm helper which avoids the need for mmap_sem
in .put_userptr memop altogether.

Signed-off-by: Jan Kara j...@suse.cz
---
 drivers/media/v4l2-core/videobuf2-core.c   | 2 --
 drivers/media/v4l2-core/videobuf2-dma-contig.c | 5 +
 drivers/media/v4l2-core/videobuf2-dma-sg.c | 4 
 drivers/media/v4l2-core/videobuf2-vmalloc.c| 4 +++-
 4 files changed, 12 insertions(+), 3 deletions(-)

diff --git a/drivers/media/v4l2-core/videobuf2-core.c 
b/drivers/media/v4l2-core/videobuf2-core.c
index 66ada01c796c..20cdbc0900ea 100644
--- a/drivers/media/v4l2-core/videobuf2-core.c
+++ b/drivers/media/v4l2-core/videobuf2-core.c
@@ -1657,9 +1657,7 @@ static int __buf_prepare(struct vb2_buffer *vb, const 
struct v4l2_buffer *b)
ret = __qbuf_mmap(vb, b);
break;
case V4L2_MEMORY_USERPTR:
-   down_read(current-mm-mmap_sem);
ret = __qbuf_userptr(vb, b);
-   up_read(current-mm-mmap_sem);
break;
case V4L2_MEMORY_DMABUF:
ret = __qbuf_dmabuf(vb, b);
diff --git a/drivers/media/v4l2-core/videobuf2-dma-contig.c 
b/drivers/media/v4l2-core/videobuf2-dma-contig.c
index 644dec73d220..8e660f033d3c 100644
--- a/drivers/media/v4l2-core/videobuf2-dma-contig.c
+++ b/drivers/media/v4l2-core/videobuf2-dma-contig.c
@@ -616,6 +616,7 @@ static void *vb2_dc_get_userptr(void *alloc_ctx, unsigned 
long vaddr,
goto fail_buf;
}
 
+   down_read(current-mm-mmap_sem);
/* current-mm-mmap_sem is taken by videobuf2 core */
vma = find_vma(current-mm, vaddr);
if (!vma) {
@@ -642,6 +643,7 @@ static void *vb2_dc_get_userptr(void *alloc_ctx, unsigned 
long vaddr,
if (ret) {
unsigned long pfn;
if (vb2_dc_get_user_pfn(start, n_pages, vma, pfn) == 0) {
+   up_read(current-mm-mmap_sem);
buf-dma_addr = vb2_dc_pfn_to_dma(buf-dev, pfn);
buf-size = size;
kfree(pages);
@@ -651,6 +653,7 @@ static void *vb2_dc_get_userptr(void *alloc_ctx, unsigned 
long vaddr,
pr_err(failed to get user pages\n);
goto fail_vma;
}
+   up_read(current-mm-mmap_sem);
 
sgt = kzalloc(sizeof(*sgt), GFP_KERNEL);
if (!sgt) {
@@ -713,10 +716,12 @@ fail_get_user_pages:
while (n_pages)
put_page(pages[--n_pages]);
 
+   down_read(current-mm-mmap_sem);
 fail_vma:
vb2_put_vma(buf-vma);
 
 fail_pages:
+   up_read(current-mm-mmap_sem);
kfree(pages); /* kfree is NULL-proof */
 
 fail_buf:
diff --git a/drivers/media/v4l2-core/videobuf2-dma-sg.c 
b/drivers/media/v4l2-core/videobuf2-dma-sg.c
index 45c708e463b9..cdcf5ad79012 100644
--- a/drivers/media/v4l2-core/videobuf2-dma-sg.c
+++ b/drivers/media/v4l2-core/videobuf2-dma-sg.c
@@ -263,6 +263,7 @@ static void *vb2_dma_sg_get_userptr(void *alloc_ctx, 
unsigned long vaddr,
if (!buf-pages)
goto userptr_fail_alloc_pages;
 
+   down_read(current-mm-mmap_sem);
vma = find_vma(current-mm, vaddr);
if (!vma) {
dprintk(1, no vma for address %lu\n, vaddr);
@@ -301,6 +302,7 @@ static void *vb2_dma_sg_get_userptr(void *alloc_ctx, 
unsigned long vaddr,
 1, /* force */
 buf-pages,
 NULL);
+   up_read(current-mm-mmap_sem);
 
if (num_pages_from_user != buf-num_pages)
goto userptr_fail_get_user_pages;
@@ -328,8 +330,10 @@ userptr_fail_get_user_pages:
if (!vma_is_io(buf-vma))
while (--num_pages_from_user = 0)
put_page(buf-pages[num_pages_from_user]);
+   down_read(current-mm-mmap_sem);
vb2_put_vma(buf-vma);
 userptr_fail_find_vma:
+   up_read(current-mm-mmap_sem);
kfree(buf-pages);
 userptr_fail_alloc_pages:
kfree(buf);
diff --git

[PATCH 9/10] drm/exynos: Convert g2d_userptr_get_dma_addr() to use get_vaddr_frames()

2015-06-18 Thread Jan Kara
Convert g2d_userptr_get_dma_addr() to pin pages using get_vaddr_frames().
This removes the knowledge about vmas and mmap_sem locking from exynos
driver. Also it fixes a problem that the function has been mapping user
provided address without holding mmap_sem.

Signed-off-by: Jan Kara j...@suse.cz
---
 drivers/gpu/drm/exynos/exynos_drm_g2d.c | 91 ++-
 drivers/gpu/drm/exynos/exynos_drm_gem.c | 97 -
 2 files changed, 29 insertions(+), 159 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c 
b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
index 81a250830808..810e1ee7c07d 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
@@ -190,10 +190,8 @@ struct g2d_cmdlist_userptr {
dma_addr_t  dma_addr;
unsigned long   userptr;
unsigned long   size;
-   struct page **pages;
-   unsigned intnpages;
+   struct frame_vector *vec;
struct sg_table *sgt;
-   struct vm_area_struct   *vma;
atomic_trefcount;
boolin_pool;
boolout_of_list;
@@ -363,6 +361,7 @@ static void g2d_userptr_put_dma_addr(struct drm_device 
*drm_dev,
 {
struct g2d_cmdlist_userptr *g2d_userptr =
(struct g2d_cmdlist_userptr *)obj;
+   struct page **pages;
 
if (!obj)
return;
@@ -382,19 +381,21 @@ out:
exynos_gem_unmap_sgt_from_dma(drm_dev, g2d_userptr-sgt,
DMA_BIDIRECTIONAL);
 
-   exynos_gem_put_pages_to_userptr(g2d_userptr-pages,
-   g2d_userptr-npages,
-   g2d_userptr-vma);
+   pages = frame_vector_pages(g2d_userptr-vec);
+   if (!IS_ERR(pages)) {
+   int i;
 
-   exynos_gem_put_vma(g2d_userptr-vma);
+   for (i = 0; i  frame_vector_count(g2d_userptr-vec); i++)
+   set_page_dirty_lock(pages[i]);
+   }
+   put_vaddr_frames(g2d_userptr-vec);
+   frame_vector_destroy(g2d_userptr-vec);
 
if (!g2d_userptr-out_of_list)
list_del_init(g2d_userptr-list);
 
sg_free_table(g2d_userptr-sgt);
kfree(g2d_userptr-sgt);
-
-   drm_free_large(g2d_userptr-pages);
kfree(g2d_userptr);
 }
 
@@ -408,9 +409,7 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct 
drm_device *drm_dev,
struct exynos_drm_g2d_private *g2d_priv = file_priv-g2d_priv;
struct g2d_cmdlist_userptr *g2d_userptr;
struct g2d_data *g2d;
-   struct page **pages;
struct sg_table *sgt;
-   struct vm_area_struct *vma;
unsigned long start, end;
unsigned int npages, offset;
int ret;
@@ -456,65 +455,38 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct 
drm_device *drm_dev,
return ERR_PTR(-ENOMEM);
 
atomic_set(g2d_userptr-refcount, 1);
+   g2d_userptr-size = size;
 
start = userptr  PAGE_MASK;
offset = userptr  ~PAGE_MASK;
end = PAGE_ALIGN(userptr + size);
npages = (end - start)  PAGE_SHIFT;
-   g2d_userptr-npages = npages;
-
-   pages = drm_calloc_large(npages, sizeof(struct page *));
-   if (!pages) {
-   DRM_ERROR(failed to allocate pages.\n);
-   ret = -ENOMEM;
+   g2d_userptr-vec = frame_vector_create(npages);
+   if (!vec)
goto err_free;
-   }
 
-   down_read(current-mm-mmap_sem);
-   vma = find_vma(current-mm, userptr);
-   if (!vma) {
-   up_read(current-mm-mmap_sem);
-   DRM_ERROR(failed to get vm region.\n);
+   ret = get_vaddr_frames(start, npages, true, true, g2d_userptr-vec);
+   if (ret != npages) {
+   DRM_ERROR(failed to get user pages from userptr.\n);
+   if (ret  0)
+   goto err_destroy_framevec;
ret = -EFAULT;
-   goto err_free_pages;
+   goto err_put_framevec;
}
-
-   if (vma-vm_end  userptr + size) {
-   up_read(current-mm-mmap_sem);
-   DRM_ERROR(vma is too small.\n);
+   if (frame_vector_to_pages(g2d_userptr-vec)  0) {
ret = -EFAULT;
-   goto err_free_pages;
+   goto err_put_framevec;
}
 
-   g2d_userptr-vma = exynos_gem_get_vma(vma);
-   if (!g2d_userptr-vma) {
-   up_read(current-mm-mmap_sem);
-   DRM_ERROR(failed to copy vma.\n);
-   ret = -ENOMEM;
-   goto err_free_pages;
-   }
-
-   g2d_userptr-size = size;
-
-   ret = exynos_gem_get_pages_from_userptr(start  PAGE_MASK,
-   npages, pages, vma);
-   if (ret  0) {
-   up_read(current-mm-mmap_sem

[PATCH 0/10 v6] Helper to abstract vma handling in media layer

2015-06-18 Thread Jan Kara
  Hello,

I'm sending the sixth version of my patch series to abstract vma handling from
the various media drivers. Since the previous version I have added a patch to
move mm helpers into a separate file and behind a config option. I also
changed patch pushing mmap_sem down in videobuf2 core to avoid lockdep warning
and NULL dereference Hans found in his testing. I've also included small
fixups Andrew was carrying.

After this patch set drivers have to know much less details about vmas, their
types, and locking. Also quite some code is removed from them. As a bonus
drivers get automatically VM_FAULT_RETRY handling. The primary motivation for
this series is to remove knowledge about mmap_sem locking from as many places a
possible so that we can change it with reasonable effort.

The core of the series is the new helper get_vaddr_frames() which is given a
virtual address and it fills in PFNs / struct page pointers (depending on VMA
type) into the provided array. If PFNs correspond to normal pages it also grabs
references to these pages. The difference from get_user_pages() is that this
function can also deal with pfnmap, and io mappings which is what the media
drivers need.

I have tested the patches with vivid driver so at least vb2 code got some
exposure. Conversion of other drivers was just compile-tested (for x86 so e.g.
exynos driver which is only for Samsung platform is completely untested).

Andrew, can you please update the patches in mm three? Thanks!

Honza

Changes since v5:
* Moved mm helper into a separate file and behind a config option
* Changed the first patch pushing mmap_sem down in videobuf2 core to avoid
  possible deadlock

Changes since v4:
* Minor cleanups and fixes pointed out by Mel and Vlasta
* Added Acked-by tags

Changes since v3:
* Added include linux/vmalloc.h into mm/gup.c as it's needed for some archs
* Fixed error path for exynos driver

Changes since v2:
* Renamed functions and structures as Mel suggested
* Other minor changes suggested by Mel
* Rebased on top of 4.1-rc2
* Changed functions to get pointer to array of pages / pfns to perform
  conversion if necessary. This fixes possible issue in the omap I may have
  introduced in v2 and generally makes the API less errorprone.
--
To unsubscribe from this list: send the line unsubscribe linux-media in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 4/10] vb2: Provide helpers for mapping virtual addresses

2015-06-18 Thread Jan Kara
Provide simple helper functions to map virtual address range into an
array of pfns / pages.

Acked-by: Marek Szyprowski m.szyprow...@samsung.com
Tested-by: Marek Szyprowski m.szyprow...@samsung.com
Signed-off-by: Jan Kara j...@suse.cz
---
 drivers/media/v4l2-core/videobuf2-memops.c | 58 ++
 include/media/videobuf2-memops.h   |  5 +++
 2 files changed, 63 insertions(+)

diff --git a/drivers/media/v4l2-core/videobuf2-memops.c 
b/drivers/media/v4l2-core/videobuf2-memops.c
index 81c1ad8b2cf1..0ec186d41b9b 100644
--- a/drivers/media/v4l2-core/videobuf2-memops.c
+++ b/drivers/media/v4l2-core/videobuf2-memops.c
@@ -137,6 +137,64 @@ int vb2_get_contig_userptr(unsigned long vaddr, unsigned 
long size,
 EXPORT_SYMBOL_GPL(vb2_get_contig_userptr);
 
 /**
+ * vb2_create_framevec() - map virtual addresses to pfns
+ * @start: Virtual user address where we start mapping
+ * @length:Length of a range to map
+ * @write: Should we map for writing into the area
+ *
+ * This function allocates and fills in a vector with pfns corresponding to
+ * virtual address range passed in arguments. If pfns have corresponding pages,
+ * page references are also grabbed to pin pages in memory. The function
+ * returns pointer to the vector on success and error pointer in case of
+ * failure. Returned vector needs to be freed via vb2_destroy_pfnvec().
+ */
+struct frame_vector *vb2_create_framevec(unsigned long start,
+unsigned long length,
+bool write)
+{
+   int ret;
+   unsigned long first, last;
+   unsigned long nr;
+   struct frame_vector *vec;
+
+   first = start  PAGE_SHIFT;
+   last = (start + length - 1)  PAGE_SHIFT;
+   nr = last - first + 1;
+   vec = frame_vector_create(nr);
+   if (!vec)
+   return ERR_PTR(-ENOMEM);
+   ret = get_vaddr_frames(start, nr, write, 1, vec);
+   if (ret  0)
+   goto out_destroy;
+   /* We accept only complete set of PFNs */
+   if (ret != nr) {
+   ret = -EFAULT;
+   goto out_release;
+   }
+   return vec;
+out_release:
+   put_vaddr_frames(vec);
+out_destroy:
+   frame_vector_destroy(vec);
+   return ERR_PTR(ret);
+}
+EXPORT_SYMBOL(vb2_create_framevec);
+
+/**
+ * vb2_destroy_framevec() - release vector of mapped pfns
+ * @vec:   vector of pfns / pages to release
+ *
+ * This releases references to all pages in the vector @vec (if corresponding
+ * pfns are backed by pages) and frees the passed vector.
+ */
+void vb2_destroy_framevec(struct frame_vector *vec)
+{
+   put_vaddr_frames(vec);
+   frame_vector_destroy(vec);
+}
+EXPORT_SYMBOL(vb2_destroy_framevec);
+
+/**
  * vb2_common_vm_open() - increase refcount of the vma
  * @vma:   virtual memory region for the mapping
  *
diff --git a/include/media/videobuf2-memops.h b/include/media/videobuf2-memops.h
index f05444ca8c0c..2f0564ff5f31 100644
--- a/include/media/videobuf2-memops.h
+++ b/include/media/videobuf2-memops.h
@@ -15,6 +15,7 @@
 #define _MEDIA_VIDEOBUF2_MEMOPS_H
 
 #include media/videobuf2-core.h
+#include linux/mm.h
 
 /**
  * vb2_vmarea_handler - common vma refcount tracking handler
@@ -36,5 +37,9 @@ int vb2_get_contig_userptr(unsigned long vaddr, unsigned long 
size,
 struct vm_area_struct *vb2_get_vma(struct vm_area_struct *vma);
 void vb2_put_vma(struct vm_area_struct *vma);
 
+struct frame_vector *vb2_create_framevec(unsigned long start,
+unsigned long length,
+bool write);
+void vb2_destroy_framevec(struct frame_vector *vec);
 
 #endif
-- 
2.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-media in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 2/10] mm: Provide new get_vaddr_frames() helper

2015-06-18 Thread Jan Kara
Provide new function get_vaddr_frames().  This function maps virtual
addresses from given start and fills given array with page frame numbers of
the corresponding pages. If given start belongs to a normal vma, the function
grabs reference to each of the pages to pin them in memory. If start
belongs to VM_IO | VM_PFNMAP vma, we don't touch page structures. Caller
must make sure pfns aren't reused for anything else while he is using
them.

This function is created for various drivers to simplify handling of
their buffers.

Acked-by: Mel Gorman mgor...@suse.de
Acked-by: Vlastimil Babka vba...@suse.cz
Signed-off-by: Jan Kara j...@suse.cz
---
 include/linux/mm.h |  44 +++
 mm/gup.c   | 223 +
 2 files changed, 267 insertions(+)

diff --git a/include/linux/mm.h b/include/linux/mm.h
index 0755b9fd03a7..dcd1f02a78e9 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -20,6 +20,7 @@
 #include linux/shrinker.h
 #include linux/resource.h
 #include linux/page_ext.h
+#include linux/err.h
 
 struct mempolicy;
 struct anon_vma;
@@ -1197,6 +1198,49 @@ long get_user_pages_unlocked(struct task_struct *tsk, 
struct mm_struct *mm,
int write, int force, struct page **pages);
 int get_user_pages_fast(unsigned long start, int nr_pages, int write,
struct page **pages);
+
+/* Container for pinned pfns / pages */
+struct frame_vector {
+   unsigned int nr_allocated;  /* Number of frames we have space for */
+   unsigned int nr_frames; /* Number of frames stored in ptrs array */
+   bool got_ref;   /* Did we pin pages by getting page ref? */
+   bool is_pfns;   /* Does array contain pages or pfns? */
+   void *ptrs[0];  /* Array of pinned pfns / pages. Use
+* pfns_vector_pages() or pfns_vector_pfns()
+* for access */
+};
+
+struct frame_vector *frame_vector_create(unsigned int nr_frames);
+void frame_vector_destroy(struct frame_vector *vec);
+int get_vaddr_frames(unsigned long start, unsigned int nr_pfns,
+bool write, bool force, struct frame_vector *vec);
+void put_vaddr_frames(struct frame_vector *vec);
+int frame_vector_to_pages(struct frame_vector *vec);
+void frame_vector_to_pfns(struct frame_vector *vec);
+
+static inline unsigned int frame_vector_count(struct frame_vector *vec)
+{
+   return vec-nr_frames;
+}
+
+static inline struct page **frame_vector_pages(struct frame_vector *vec)
+{
+   if (vec-is_pfns) {
+   int err = frame_vector_to_pages(vec);
+
+   if (err)
+   return ERR_PTR(err);
+   }
+   return (struct page **)(vec-ptrs);
+}
+
+static inline unsigned long *frame_vector_pfns(struct frame_vector *vec)
+{
+   if (!vec-is_pfns)
+   frame_vector_to_pfns(vec);
+   return (unsigned long *)(vec-ptrs);
+}
+
 struct kvec;
 int get_kernel_pages(const struct kvec *iov, int nr_pages, int write,
struct page **pages);
diff --git a/mm/gup.c b/mm/gup.c
index 6297f6bccfb1..a7a4ac6ae9d0 100644
--- a/mm/gup.c
+++ b/mm/gup.c
@@ -8,6 +8,7 @@
 #include linux/rmap.h
 #include linux/swap.h
 #include linux/swapops.h
+#include linux/vmalloc.h
 
 #include linux/sched.h
 #include linux/rwsem.h
@@ -936,6 +937,228 @@ int __mm_populate(unsigned long start, unsigned long len, 
int ignore_errors)
return ret; /* 0 or negative error code */
 }
 
+/*
+ * get_vaddr_frames() - map virtual addresses to pfns
+ * @start: starting user address
+ * @nr_frames: number of pages / pfns from start to map
+ * @write: whether pages will be written to by the caller
+ * @force: whether to force write access even if user mapping is
+ * readonly. See description of the same argument of
+   get_user_pages().
+ * @vec:   structure which receives pages / pfns of the addresses mapped.
+ * It should have space for at least nr_frames entries.
+ *
+ * This function maps virtual addresses from @start and fills @vec structure
+ * with page frame numbers or page pointers to corresponding pages (choice
+ * depends on the type of the vma underlying the virtual address). If @start
+ * belongs to a normal vma, the function grabs reference to each of the pages
+ * to pin them in memory. If @start belongs to VM_IO | VM_PFNMAP vma, we don't
+ * touch page structures and the caller must make sure pfns aren't reused for
+ * anything else while he is using them.
+ *
+ * The function returns number of pages mapped which may be less than
+ * @nr_frames. In particular we stop mapping if there are more vmas of
+ * different type underlying the specified range of virtual addresses.
+ * When the function isn't able to map a single page, it returns error.
+ *
+ * This function takes care of grabbing mmap_sem as necessary.
+ */
+int get_vaddr_frames(unsigned long start, unsigned int

Re: [git:media_tree/master] [media] vb2: Push mmap_sem down to memops

2015-06-18 Thread Jan Kara
:  /DH67CF, BIOS 
 BLH6710H.86A.0105.2011.0301.1654 03/01/2011
 [   82.290388]  82c46890 8800b4bfb968 81a98687 
 0007
 [   82.290392]  82c46890 8800b4bfb9b8 8110785d 
 
 [   82.290395]  8800b4bfba28 0001 8800d51ce718 
 0001
 [   82.290399] Call Trace:
 [   82.290402]  [81a98687] dump_stack+0x4f/0x7b
 [   82.290405]  [8110785d] print_circular_bug+0x1cd/0x230
 [   82.290407]  [8110adb3] __lock_acquire+0x1d53/0x1fe0
 [   82.290411]  [812142b9] ? kfree+0x169/0x570
 [   82.290414]  [8110bab9] lock_acquire+0xc9/0x290
 [   82.290416]  [a007a870] ? vb2_dma_sg_put_userptr+0xf0/0x170 
 [videobuf2_dma_sg]
 [   82.290419]  [81aa1924] down_read+0x34/0x50
 [   82.290421]  [a007a870] ? vb2_dma_sg_put_userptr+0xf0/0x170 
 [videobuf2_dma_sg]
 [   82.290424]  [a007a870] vb2_dma_sg_put_userptr+0xf0/0x170 
 [videobuf2_dma_sg]
 [   82.290427]  [a0066656] __vb2_queue_free+0x156/0x5f0 
 [videobuf2_core]
 [   82.290430]  [a006aa0f] __reqbufs.isra.13+0x9f/0x410 
 [videobuf2_core]
 [   82.290434]  [811c8a59] ? free_hot_cold_page+0x159/0x200
 [   82.290437]  [a006b084] vb2_ioctl_reqbufs+0x74/0xb0 
 [videobuf2_core]
 [   82.290441]  [a0033d83] v4l_reqbufs+0x43/0x50 [videodev]
 [   82.290445]  [a00329f4] __video_do_ioctl+0x274/0x310 [videodev]
 [   82.290449]  [a0032780] ? v4l_querycap+0x70/0x70 [videodev]
 [   82.290453]  [a00349a8] video_usercopy+0x378/0x8f0 [videodev]
 [   82.290456]  [81108b11] ? mark_held_locks+0x71/0xa0
 [   82.290458]  [81108d4d] ? trace_hardirqs_on+0xd/0x10
 [   82.290461]  [81a9f98e] ? 
 mutex_lock_interruptible_nested+0x25e/0x4a0
 [   82.290464]  [a002d65f] ? v4l2_ioctl+0x5f/0xf0 [videodev]
 [   82.290468]  [a002d65f] ? v4l2_ioctl+0x5f/0xf0 [videodev]
 [   82.290472]  [a0034f35] video_ioctl2+0x15/0x20 [videodev]
 [   82.290475]  [a002d6d0] v4l2_ioctl+0xd0/0xf0 [videodev]
 [   82.290478]  [81238258] do_vfs_ioctl+0x308/0x540
 [   82.290481]  [8124476c] ? __fget_light+0x6c/0xa0
 [   82.290484]  [81238511] SyS_ioctl+0x81/0xa0
 [   82.290487]  [81aa4517] system_call_fastpath+0x12/0x6f
 
 The problem is that the mmap_sem is now taken in vb2_dma_sg_put_userptr() when
 that didn't happen before. This is fine when called from __qbuf_userptr, but
 not when called from __vb2_queue_free. I will see if I have time to dig into
 this during the weekend and solve it, but if not, then this has to be reverted
 and the get_vaddr_frames() patch series postponed since it depends on this 
 one.
 
 Regards,
 
   Hans
 
 On 05/01/15 12:17, Mauro Carvalho Chehab wrote:
  This is an automatic generated email to let you know that the following 
  patch were queued at the 
  http://git.linuxtv.org/cgit.cgi/media_tree.git tree:
  
  Subject: [media] vb2: Push mmap_sem down to memops
  Author:  Jan Kara j...@suse.cz
  Date:Tue Mar 17 08:56:31 2015 -0300
  
  Currently vb2 core acquires mmap_sem just around call to
  __qbuf_userptr(). However since commit f035eb4e976ef5 (videobuf2: fix
  lockdep warning) it isn't necessary to acquire it so early as we no
  longer have to drop queue mutex before acquiring mmap_sem. So push
  acquisition of mmap_sem down into .get_userptr and .put_userptr memops
  so that the semaphore is acquired for a shorter time and it is clearer
  what it is needed for.
  
  Signed-off-by: Jan Kara j...@suse.cz
  Signed-off-by: Hans Verkuil hans.verk...@cisco.com
  Signed-off-by: Mauro Carvalho Chehab mche...@osg.samsung.com
  
   drivers/media/v4l2-core/videobuf2-core.c   |2 --
   drivers/media/v4l2-core/videobuf2-dma-contig.c |7 +++
   drivers/media/v4l2-core/videobuf2-dma-sg.c |6 ++
   drivers/media/v4l2-core/videobuf2-vmalloc.c|6 +-
   4 files changed, 18 insertions(+), 3 deletions(-)
  
  ---
  
  http://git.linuxtv.org/cgit.cgi/media_tree.git/commit/?id=48b25a3a713b90988b6882d318f7c0a6bed9aabc
  
  diff --git a/drivers/media/v4l2-core/videobuf2-core.c 
  b/drivers/media/v4l2-core/videobuf2-core.c
  index 66ada01..20cdbc0 100644
  --- a/drivers/media/v4l2-core/videobuf2-core.c
  +++ b/drivers/media/v4l2-core/videobuf2-core.c
  @@ -1657,9 +1657,7 @@ static int __buf_prepare(struct vb2_buffer *vb, const 
  struct v4l2_buffer *b)
  ret = __qbuf_mmap(vb, b);
  break;
  case V4L2_MEMORY_USERPTR:
  -   down_read(current-mm-mmap_sem);
  ret = __qbuf_userptr(vb, b);
  -   up_read(current-mm-mmap_sem);
  break;
  case V4L2_MEMORY_DMABUF:
  ret = __qbuf_dmabuf(vb, b);
  diff --git a/drivers/media/v4l2-core/videobuf2-dma-contig.c 
  b/drivers/media/v4l2-core/videobuf2-dma-contig.c
  index 644dec7..620c4aa 100644
  --- a/drivers/media/v4l2-core/videobuf2-dma

Re: [PATCH] Revert [media] vb2: Push mmap_sem down to memops

2015-06-18 Thread Jan Kara
] 
lock(q-mmap_lock);
 Jun 14 18:44:07 test-media kernel: [   49.376761]   lock(mm-mmap_sem);
 Jun 14 18:44:07 test-media kernel: [   49.376763]
 Jun 14 18:44:07 test-media kernel: [   49.376763]  *** DEADLOCK ***
 Jun 14 18:44:07 test-media kernel: [   49.376763]
 Jun 14 18:44:07 test-media kernel: [   49.376764] 2 locks held by 
 v4l2-compliance/1468:
 Jun 14 18:44:07 test-media kernel: [   49.376765]  #0:  
 (dev-mutex#3){+.+.+.}, at: [a0398e0a] _vb2_fop_release+0x2a/0xb0 
 [videobuf2_core]
 Jun 14 18:44:07 test-media kernel: [   49.376770]  #1:  
 (q-mmap_lock){+.+...}, at: [a0398dc5] vb2_queue_release+0x25/0x40 
 [videobuf2_core]
 Jun 14 18:44:07 test-media kernel: [   49.376773]
 Jun 14 18:44:07 test-media kernel: [   49.376773] stack backtrace:
 Jun 14 18:44:07 test-media kernel: [   49.376776] CPU: 2 PID: 1468 Comm: 
 v4l2-compliance Not tainted 4.1.0-rc3-test-media #1190
 Jun 14 18:44:07 test-media kernel: [   49.376777] Hardware name: VMware, Inc. 
 VMware Virtual Platform/440BX Desktop Reference Platform, BIOS 6.00 05/20/2014
 Jun 14 18:44:07 test-media kernel: [   49.376779]  8279e0b0 
 88021d6f7ba8 819a7aac 0011
 Jun 14 18:44:07 test-media kernel: [   49.376781]  8279e0b0 
 88021d6f7bf8 819a3964 88021d6f7bd8
 Jun 14 18:44:07 test-media kernel: [   49.376783]  8800ac8aa100 
 0002 8800ac8aa9a0 0002
 Jun 14 18:44:07 test-media kernel: [   49.376785] Call Trace:
 Jun 14 18:44:07 test-media kernel: [   49.376788]  [819a7aac] 
 dump_stack+0x4f/0x7b
 Jun 14 18:44:07 test-media kernel: [   49.376792]  [819a3964] 
 print_circular_bug+0x20f/0x251
 Jun 14 18:44:07 test-media kernel: [   49.376793]  [810d79b3] 
 __lock_acquire+0x1fd3/0x2070
 Jun 14 18:44:07 test-media kernel: [   49.376795]  [810d6543] ? 
 __lock_acquire+0xb63/0x2070
 Jun 14 18:44:07 test-media kernel: [   49.376797]  [810d37a8] ? 
 __lock_is_held+0x58/0x80
 Jun 14 18:44:07 test-media kernel: [   49.376798]  [810d852c] 
 lock_acquire+0x6c/0xa0
 Jun 14 18:44:07 test-media kernel: [   49.376800]  [a03a81f6] ? 
 vb2_vmalloc_put_userptr+0x36/0x110 [videobuf2_vmalloc]
 Jun 14 18:44:07 test-media kernel: [   49.376802]  [819b1a92] 
 down_read+0x42/0x60
 Jun 14 18:44:07 test-media kernel: [   49.376803]  [a03a81f6] ? 
 vb2_vmalloc_put_userptr+0x36/0x110 [videobuf2_vmalloc]
 Jun 14 18:44:07 test-media kernel: [   49.376805]  [819af1b1] ? 
 mutex_lock_nested+0x2b1/0x560
 Jun 14 18:44:07 test-media kernel: [   49.376807]  [a0398dc5] ? 
 vb2_queue_release+0x25/0x40 [videobuf2_core]
 Jun 14 18:44:07 test-media kernel: [   49.376808]  [a03a81f6] 
 vb2_vmalloc_put_userptr+0x36/0x110 [videobuf2_vmalloc]
 Jun 14 18:44:07 test-media kernel: [   49.376810]  [a0398e0a] ? 
 _vb2_fop_release+0x2a/0xb0 [videobuf2_core]
 Jun 14 18:44:07 test-media kernel: [   49.376812]  [a0394626] 
 __vb2_queue_free+0x146/0x5e0 [videobuf2_core]
 Jun 14 18:44:07 test-media kernel: [   49.376814]  [a0398dd3] 
 vb2_queue_release+0x33/0x40 [videobuf2_core]
 Jun 14 18:44:07 test-media kernel: [   49.376816]  [a0398e75] 
 _vb2_fop_release+0x95/0xb0 [videobuf2_core]
 Jun 14 18:44:07 test-media kernel: [   49.376818]  [a0398eb9] 
 vb2_fop_release+0x29/0x50 [videobuf2_core]
 Jun 14 18:44:07 test-media kernel: [   49.376820]  [a03b6372] 
 vivid_fop_release+0x92/0x230 [vivid]
 Jun 14 18:44:07 test-media kernel: [   49.376822]  [a0361460] 
 v4l2_release+0x30/0x80 [videodev]
 Jun 14 18:44:07 test-media kernel: [   49.376824]  [811a51d5] 
 __fput+0xe5/0x200
 Jun 14 18:44:07 test-media kernel: [   49.376825]  [819b4653] ? 
 int_very_careful+0x5/0x46
 Jun 14 18:44:07 test-media kernel: [   49.376827]  [811a5339] 
 fput+0x9/0x10
 Jun 14 18:44:07 test-media kernel: [   49.376828]  [810a9fa4] 
 task_work_run+0xc4/0xf0
 Jun 14 18:44:07 test-media kernel: [   49.376830]  [81002dd1] 
 do_notify_resume+0x41/0x60
 Jun 14 18:44:07 test-media kernel: [   49.376832]  [819b46a6] 
 int_signal+0x12/0x17
 
 This can be triggered by loading the vivid module with the module option 
 'no_error_inj=1'
 and running 'v4l2-compliance -s5'. Again, it may take a few attempts to 
 trigger this
 but for me it happens quite quickly.
 
 Without this patch I cannot reproduce these two issues. So reverting is the 
 best
 solution for now.
 
 Signed-off-by: Hans Verkuil hans.verk...@cisco.com
 Cc: Jan Kara j...@suse.cz
 Cc: Andrew Morton a...@linux-foundation.org
 ---
  drivers/media/v4l2-core/videobuf2-core.c   | 2 ++
  drivers/media/v4l2-core/videobuf2-dma-contig.c | 7 ---
  drivers/media/v4l2-core/videobuf2-dma-sg.c | 6 --
  drivers/media/v4l2-core/videobuf2-vmalloc.c| 6 +-
  4 files changed, 3 insertions(+), 18 deletions(-)
 
 diff --git a/drivers/media/v4l2-core/videobuf2-core.c 
 b/drivers

Re: [PATCH 2/9] mm: Provide new get_vaddr_frames() helper

2015-06-03 Thread Jan Kara
On Tue 02-06-15 15:29:12, Andrew Morton wrote:
 On Tue, 2 Jun 2015 17:23:00 +0200 Jan Kara j...@suse.cz wrote:
 
   That's a lump of new code which many kernels won't be needing.  Can we
   put all this in a new .c file and select it within drivers/media
   Kconfig?
So the attached patch should do what you had in mind. OK?
 
 lgtm.
 
   drivers/gpu/drm/exynos/Kconfig  |   1 +
   drivers/media/platform/omap/Kconfig |   1 +
   drivers/media/v4l2-core/Kconfig |   1 +
   mm/Kconfig  |   3 +
   mm/Makefile |   1 +
   mm/frame-vec.c  | 233 
  
 
 But frame_vector.c would be a more pleasing name.  For `struct frame_vector'.
  OK, makes sense. Updated patch attached.

Honza
-- 
Jan Kara j...@suse.cz
SUSE Labs, CR
From a129ecf637e75421d823d54eab885cd36e54c6ec Mon Sep 17 00:00:00 2001
From: Jan Kara j...@suse.cz
Date: Tue, 2 Jun 2015 16:40:32 +0200
Subject: [PATCH] mm: Move get_vaddr_frames() behind a config option

get_vaddr_frames() is used by relatively rare drivers so hide it and the
related functions behind a config option that is selected only by
drivers that need the infrastructure.

Suggested-by: Andrew Morton a...@linux-foundation.org
Signed-off-by: Jan Kara j...@suse.cz
---
 drivers/gpu/drm/exynos/Kconfig  |   1 +
 drivers/media/platform/omap/Kconfig |   1 +
 drivers/media/v4l2-core/Kconfig |   1 +
 mm/Kconfig  |   3 +
 mm/Makefile |   1 +
 mm/frame_vector.c   | 233 
 mm/gup.c| 225 --
 7 files changed, 240 insertions(+), 225 deletions(-)
 create mode 100644 mm/frame_vector.c

diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig
index 0a6780367d28..fc678289cf79 100644
--- a/drivers/gpu/drm/exynos/Kconfig
+++ b/drivers/gpu/drm/exynos/Kconfig
@@ -71,6 +71,7 @@ config DRM_EXYNOS_VIDI
 config DRM_EXYNOS_G2D
 	bool Exynos DRM G2D
 	depends on DRM_EXYNOS  !VIDEO_SAMSUNG_S5P_G2D
+	select FRAME_VECTOR
 	help
 	  Choose this option if you want to use Exynos G2D for DRM.
 
diff --git a/drivers/media/platform/omap/Kconfig b/drivers/media/platform/omap/Kconfig
index dc2aaab54aef..217d613b0fe7 100644
--- a/drivers/media/platform/omap/Kconfig
+++ b/drivers/media/platform/omap/Kconfig
@@ -10,6 +10,7 @@ config VIDEO_OMAP2_VOUT
 	select OMAP2_DSS if HAS_IOMEM  ARCH_OMAP2PLUS
 	select OMAP2_VRFB if ARCH_OMAP2 || ARCH_OMAP3
 	select VIDEO_OMAP2_VOUT_VRFB if VIDEO_OMAP2_VOUT  OMAP2_VRFB
+	select FRAME_VECTOR
 	default n
 	---help---
 	  V4L2 Display driver support for OMAP2/3 based boards.
diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig
index ba7e21a73023..0cb22add650b 100644
--- a/drivers/media/v4l2-core/Kconfig
+++ b/drivers/media/v4l2-core/Kconfig
@@ -73,6 +73,7 @@ config VIDEOBUF2_CORE
 
 config VIDEOBUF2_MEMOPS
 	tristate
+	select FRAME_VECTOR
 
 config VIDEOBUF2_DMA_CONTIG
 	tristate
diff --git a/mm/Kconfig b/mm/Kconfig
index 390214da4546..2ca52e9986f0 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -635,3 +635,6 @@ config MAX_STACK_SIZE_MB
 	  changed to a smaller value in which case that is used.
 
 	  A sane initial value is 80 MB.
+
+config FRAME_VECTOR
+	bool
diff --git a/mm/Makefile b/mm/Makefile
index 98c4eaeabdcb..be5d5c866305 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -78,3 +78,4 @@ obj-$(CONFIG_CMA)	+= cma.o
 obj-$(CONFIG_MEMORY_BALLOON) += balloon_compaction.o
 obj-$(CONFIG_PAGE_EXTENSION) += page_ext.o
 obj-$(CONFIG_CMA_DEBUGFS) += cma_debug.o
+obj-$(CONFIG_FRAME_VECTOR) += frame_vector.o
diff --git a/mm/frame_vector.c b/mm/frame_vector.c
new file mode 100644
index ..5d85bcd150ae
--- /dev/null
+++ b/mm/frame_vector.c
@@ -0,0 +1,233 @@
+#include linux/kernel.h
+#include linux/errno.h
+#include linux/err.h
+#include linux/mm.h
+#include linux/slab.h
+#include linux/pagemap.h
+#include linux/sched.h
+
+/*
+ * get_vaddr_frames() - map virtual addresses to pfns
+ * @start:	starting user address
+ * @nr_frames:	number of pages / pfns from start to map
+ * @write:	whether pages will be written to by the caller
+ * @force:	whether to force write access even if user mapping is
+ *		readonly. See description of the same argument of
+		get_user_pages().
+ * @vec:	structure which receives pages / pfns of the addresses mapped.
+ *		It should have space for at least nr_frames entries.
+ *
+ * This function maps virtual addresses from @start and fills @vec structure
+ * with page frame numbers or page pointers to corresponding pages (choice
+ * depends on the type of the vma underlying the virtual address). If @start
+ * belongs to a normal vma, the function grabs reference to each of the pages
+ * to pin them in memory. If @start belongs to VM_IO | VM_PFNMAP vma, we don't
+ * touch page structures and the caller

Re: [PATCH 2/9] mm: Provide new get_vaddr_frames() helper

2015-06-02 Thread Jan Kara
On Thu 28-05-15 16:24:02, Andrew Morton wrote:
 On Wed, 13 May 2015 15:08:08 +0200 Jan Kara j...@suse.cz wrote:
 
  Provide new function get_vaddr_frames().  This function maps virtual
  addresses from given start and fills given array with page frame numbers of
  the corresponding pages. If given start belongs to a normal vma, the 
  function
  grabs reference to each of the pages to pin them in memory. If start
  belongs to VM_IO | VM_PFNMAP vma, we don't touch page structures. Caller
  must make sure pfns aren't reused for anything else while he is using
  them.
  
  This function is created for various drivers to simplify handling of
  their buffers.
  
  Acked-by: Mel Gorman mgor...@suse.de
  Acked-by: Vlastimil Babka vba...@suse.cz
  Signed-off-by: Jan Kara j...@suse.cz
  ---
   include/linux/mm.h |  44 +++
   mm/gup.c   | 226 
  +
 
 That's a lump of new code which many kernels won't be needing.  Can we
 put all this in a new .c file and select it within drivers/media
 Kconfig?
  So the attached patch should do what you had in mind. OK?

Honza
-- 
Jan Kara j...@suse.cz
SUSE Labs, CR
From d18fc7863fc62d8ad0c1747b789a0dcf032ccf42 Mon Sep 17 00:00:00 2001
From: Jan Kara j...@suse.cz
Date: Tue, 2 Jun 2015 16:40:32 +0200
Subject: [PATCH] mm: Move get_vaddr_frames() behind a config option

get_vaddr_frames() is used by relatively rare drivers so hide it and the
related functions behind a config option that is selected only by
drivers that need the infrastructure.

Suggested-by: Andrew Morton a...@linux-foundation.org
Signed-off-by: Jan Kara j...@suse.cz
---
 drivers/gpu/drm/exynos/Kconfig  |   1 +
 drivers/media/platform/omap/Kconfig |   1 +
 drivers/media/v4l2-core/Kconfig |   1 +
 mm/Kconfig  |   3 +
 mm/Makefile |   1 +
 mm/frame-vec.c  | 233 
 mm/gup.c| 225 --
 7 files changed, 240 insertions(+), 225 deletions(-)
 create mode 100644 mm/frame-vec.c

diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig
index 0a6780367d28..b2fac87137c7 100644
--- a/drivers/gpu/drm/exynos/Kconfig
+++ b/drivers/gpu/drm/exynos/Kconfig
@@ -71,6 +71,7 @@ config DRM_EXYNOS_VIDI
 config DRM_EXYNOS_G2D
 	bool Exynos DRM G2D
 	depends on DRM_EXYNOS  !VIDEO_SAMSUNG_S5P_G2D
+	select FRAME_VEC
 	help
 	  Choose this option if you want to use Exynos G2D for DRM.
 
diff --git a/drivers/media/platform/omap/Kconfig b/drivers/media/platform/omap/Kconfig
index dc2aaab54aef..7cceca7b184d 100644
--- a/drivers/media/platform/omap/Kconfig
+++ b/drivers/media/platform/omap/Kconfig
@@ -10,6 +10,7 @@ config VIDEO_OMAP2_VOUT
 	select OMAP2_DSS if HAS_IOMEM  ARCH_OMAP2PLUS
 	select OMAP2_VRFB if ARCH_OMAP2 || ARCH_OMAP3
 	select VIDEO_OMAP2_VOUT_VRFB if VIDEO_OMAP2_VOUT  OMAP2_VRFB
+	select FRAME_VEC
 	default n
 	---help---
 	  V4L2 Display driver support for OMAP2/3 based boards.
diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig
index ba7e21a73023..957e5a18b0ff 100644
--- a/drivers/media/v4l2-core/Kconfig
+++ b/drivers/media/v4l2-core/Kconfig
@@ -73,6 +73,7 @@ config VIDEOBUF2_CORE
 
 config VIDEOBUF2_MEMOPS
 	tristate
+	select FRAME_VEC
 
 config VIDEOBUF2_DMA_CONTIG
 	tristate
diff --git a/mm/Kconfig b/mm/Kconfig
index 390214da4546..d039615e8f82 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -635,3 +635,6 @@ config MAX_STACK_SIZE_MB
 	  changed to a smaller value in which case that is used.
 
 	  A sane initial value is 80 MB.
+
+config FRAME_VEC
+	bool
diff --git a/mm/Makefile b/mm/Makefile
index 98c4eaeabdcb..d38305462e17 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -78,3 +78,4 @@ obj-$(CONFIG_CMA)	+= cma.o
 obj-$(CONFIG_MEMORY_BALLOON) += balloon_compaction.o
 obj-$(CONFIG_PAGE_EXTENSION) += page_ext.o
 obj-$(CONFIG_CMA_DEBUGFS) += cma_debug.o
+obj-$(CONFIG_FRAME_VEC)	+= frame-vec.o
diff --git a/mm/frame-vec.c b/mm/frame-vec.c
new file mode 100644
index ..5d85bcd150ae
--- /dev/null
+++ b/mm/frame-vec.c
@@ -0,0 +1,233 @@
+#include linux/kernel.h
+#include linux/errno.h
+#include linux/err.h
+#include linux/mm.h
+#include linux/slab.h
+#include linux/pagemap.h
+#include linux/sched.h
+
+/*
+ * get_vaddr_frames() - map virtual addresses to pfns
+ * @start:	starting user address
+ * @nr_frames:	number of pages / pfns from start to map
+ * @write:	whether pages will be written to by the caller
+ * @force:	whether to force write access even if user mapping is
+ *		readonly. See description of the same argument of
+		get_user_pages().
+ * @vec:	structure which receives pages / pfns of the addresses mapped.
+ *		It should have space for at least nr_frames entries.
+ *
+ * This function maps virtual addresses from @start and fills @vec structure
+ * with page frame numbers or page

Re: [PATCH 2/9] mm: Provide new get_vaddr_frames() helper

2015-06-01 Thread Jan Kara
On Thu 28-05-15 16:24:02, Andrew Morton wrote:
 On Wed, 13 May 2015 15:08:08 +0200 Jan Kara j...@suse.cz wrote:
 
  Provide new function get_vaddr_frames().  This function maps virtual
  addresses from given start and fills given array with page frame numbers of
  the corresponding pages. If given start belongs to a normal vma, the 
  function
  grabs reference to each of the pages to pin them in memory. If start
  belongs to VM_IO | VM_PFNMAP vma, we don't touch page structures. Caller
  must make sure pfns aren't reused for anything else while he is using
  them.
  
  This function is created for various drivers to simplify handling of
  their buffers.
  
  Acked-by: Mel Gorman mgor...@suse.de
  Acked-by: Vlastimil Babka vba...@suse.cz
  Signed-off-by: Jan Kara j...@suse.cz
  ---
   include/linux/mm.h |  44 +++
   mm/gup.c   | 226 
  +
 
 That's a lump of new code which many kernels won't be needing.  Can we
 put all this in a new .c file and select it within drivers/media
 Kconfig?
  Yeah, makes sense. I'll write a patch. Hans, is it OK with you if I
just create a patch on top of the series you have in your tree?

Honza
-- 
Jan Kara j...@suse.cz
SUSE Labs, CR
--
To unsubscribe from this list: send the line unsubscribe linux-media in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 0/9 v5] Helper to abstract vma handling in media layer

2015-05-25 Thread Jan Kara
On Mon 25-05-15 13:37:56, Hans Verkuil wrote:
 Hi Jan,
 
 On 05/13/2015 03:08 PM, Jan Kara wrote:
Hello,
  
  I'm sending the fifth version of my patch series to abstract vma handling
  from the various media drivers. The patches got some review from mm people 
  and
  testing from device driver guys so unless someone objects, patches will be
  queued in media tree for the next merge window.
 
 What is the current status? I saw one comment for patch 9, so I assume it is 
 not
 quite ready yet.
 
 Let me know when you think it is time to merge.
  There was a minor comment to the exynos patch - I've sent updated version
of that patch as a reply to the comment. Do you want me to resend the whole
series? Otherwise I think you can just pick up the patches and merge them.
Thanks!

Honza

  After this patch set drivers have to know much less details about vmas, 
  their
  types, and locking. Also quite some code is removed from them. As a bonus
  drivers get automatically VM_FAULT_RETRY handling. The primary motivation 
  for
  this series is to remove knowledge about mmap_sem locking from as many 
  places a
  possible so that we can change it with reasonable effort.
  
  The core of the series is the new helper get_vaddr_frames() which is given a
  virtual address and it fills in PFNs / struct page pointers (depending on 
  VMA
  type) into the provided array. If PFNs correspond to normal pages it also 
  grabs
  references to these pages. The difference from get_user_pages() is that this
  function can also deal with pfnmap, and io mappings which is what the media
  drivers need.
  
  I have tested the patches with vivid driver so at least vb2 code got some
  exposure. Conversion of other drivers was just compile-tested (for x86 so 
  e.g.
  exynos driver which is only for Samsung platform is completely untested).
  
  Honza
  Changes since v4:
  * Minor cleanups and fixes pointed out by Mel and Vlasta
  * Added Acked-by tags
  
  Changes since v3:
  * Added include linux/vmalloc.h into mm/gup.c as it's needed for some 
  archs
  * Fixed error path for exynos driver
  
  Changes since v2:
  * Renamed functions and structures as Mel suggested
  * Other minor changes suggested by Mel
  * Rebased on top of 4.1-rc2
  * Changed functions to get pointer to array of pages / pfns to perform
conversion if necessary. This fixes possible issue in the omap I may have
introduced in v2 and generally makes the API less errorprone.
  --
  To unsubscribe from this list: send the line unsubscribe linux-media in
  the body of a message to majord...@vger.kernel.org
  More majordomo info at  http://vger.kernel.org/majordomo-info.html
  
 
-- 
Jan Kara j...@suse.cz
SUSE Labs, CR
--
To unsubscribe from this list: send the line unsubscribe linux-media in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 9/9] drm/exynos: Convert g2d_userptr_get_dma_addr() to use get_vaddr_frames()

2015-05-14 Thread Jan Kara
On Thu 14-05-15 19:51:23, Inki Dae wrote:
 Hi,
 
 On 2015년 05월 13일 22:08, Jan Kara wrote:
  Convert g2d_userptr_get_dma_addr() to pin pages using get_vaddr_frames().
  This removes the knowledge about vmas and mmap_sem locking from exynos
  driver. Also it fixes a problem that the function has been mapping user
  provided address without holding mmap_sem.
  
  Signed-off-by: Jan Kara j...@suse.cz
  ---
   drivers/gpu/drm/exynos/exynos_drm_g2d.c | 89 ++
   drivers/gpu/drm/exynos/exynos_drm_gem.c | 97 
  -
   2 files changed, 29 insertions(+), 157 deletions(-)
  
  diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c 
  b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
  index 81a250830808..265519c0fe2d 100644
  --- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c
  +++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
  @@ -190,10 +190,8 @@ struct g2d_cmdlist_userptr {
  dma_addr_t  dma_addr;
  unsigned long   userptr;
  unsigned long   size;
  -   struct page **pages;
  -   unsigned intnpages;
  +   struct frame_vector *vec;
  struct sg_table *sgt;
  -   struct vm_area_struct   *vma;
  atomic_trefcount;
  boolin_pool;
  boolout_of_list;
  @@ -363,6 +361,7 @@ static void g2d_userptr_put_dma_addr(struct drm_device 
  *drm_dev,
   {
  struct g2d_cmdlist_userptr *g2d_userptr =
  (struct g2d_cmdlist_userptr *)obj;
  +   struct page **pages;
   
  if (!obj)
  return;
  @@ -382,19 +381,21 @@ out:
  exynos_gem_unmap_sgt_from_dma(drm_dev, g2d_userptr-sgt,
  DMA_BIDIRECTIONAL);
   
  -   exynos_gem_put_pages_to_userptr(g2d_userptr-pages,
  -   g2d_userptr-npages,
  -   g2d_userptr-vma);
  +   pages = frame_vector_pages(g2d_userptr-vec);
  +   if (!IS_ERR(pages)) {
  +   int i;
   
  -   exynos_gem_put_vma(g2d_userptr-vma);
  +   for (i = 0; i  frame_vector_count(g2d_userptr-vec); i++)
  +   set_page_dirty_lock(pages[i]);
  +   }
  +   put_vaddr_frames(g2d_userptr-vec);
  +   frame_vector_destroy(g2d_userptr-vec);
   
  if (!g2d_userptr-out_of_list)
  list_del_init(g2d_userptr-list);
   
  sg_free_table(g2d_userptr-sgt);
  kfree(g2d_userptr-sgt);
  -
  -   drm_free_large(g2d_userptr-pages);
  kfree(g2d_userptr);
   }
   
  @@ -413,6 +414,7 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct 
  drm_device *drm_dev,
  struct vm_area_struct *vma;
  unsigned long start, end;
  unsigned int npages, offset;
  +   struct frame_vector *vec;
  int ret;
   
  if (!size) {
  @@ -456,65 +458,37 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct 
  drm_device *drm_dev,
  return ERR_PTR(-ENOMEM);
   
  atomic_set(g2d_userptr-refcount, 1);
  +   g2d_userptr-size = size;
   
  start = userptr  PAGE_MASK;
  offset = userptr  ~PAGE_MASK;
  end = PAGE_ALIGN(userptr + size);
  npages = (end - start)  PAGE_SHIFT;
  -   g2d_userptr-npages = npages;
  -
  -   pages = drm_calloc_large(npages, sizeof(struct page *));
 
 The declaration to pages isn't needed anymore because you removed it.
 
  -   if (!pages) {
  -   DRM_ERROR(failed to allocate pages.\n);
  -   ret = -ENOMEM;
  +   vec = g2d_userptr-vec = frame_vector_create(npages);
 
 I think you can use g2d_userptr-vec so it seems that vec isn't needed.
 
  +   if (!vec)
  goto err_free;
  -   }
   
  -   down_read(current-mm-mmap_sem);
  -   vma = find_vma(current-mm, userptr);
 
 For vma, ditto.
  Thanks for review! Attached is a new version of the patch.

Honza

-- 
Jan Kara j...@suse.cz
SUSE Labs, CR
From 24c5c89b5c8a1bd9f230b91a258ea41b42386bb3 Mon Sep 17 00:00:00 2001
From: Jan Kara j...@suse.cz
Date: Wed, 4 Dec 2013 14:41:22 +0100
Subject: [PATCH] drm/exynos: Convert g2d_userptr_get_dma_addr() to use
 get_vaddr_frames()

Convert g2d_userptr_get_dma_addr() to pin pages using get_vaddr_frames().
This removes the knowledge about vmas and mmap_sem locking from exynos
driver. Also it fixes a problem that the function has been mapping user
provided address without holding mmap_sem.

Signed-off-by: Jan Kara j...@suse.cz
---
 drivers/gpu/drm/exynos/exynos_drm_g2d.c | 91 ++-
 drivers/gpu/drm/exynos/exynos_drm_gem.c | 97 -
 2 files changed, 29 insertions(+), 159 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
index 81a250830808..810e1ee7c07d 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
@@ -190,10 +190,8 @@ struct g2d_cmdlist_userptr {
 	dma_addr_t		dma_addr;
 	unsigned long

[PATCH 0/9 v5] Helper to abstract vma handling in media layer

2015-05-13 Thread Jan Kara
  Hello,

I'm sending the fifth version of my patch series to abstract vma handling
from the various media drivers. The patches got some review from mm people and
testing from device driver guys so unless someone objects, patches will be
queued in media tree for the next merge window.

After this patch set drivers have to know much less details about vmas, their
types, and locking. Also quite some code is removed from them. As a bonus
drivers get automatically VM_FAULT_RETRY handling. The primary motivation for
this series is to remove knowledge about mmap_sem locking from as many places a
possible so that we can change it with reasonable effort.

The core of the series is the new helper get_vaddr_frames() which is given a
virtual address and it fills in PFNs / struct page pointers (depending on VMA
type) into the provided array. If PFNs correspond to normal pages it also grabs
references to these pages. The difference from get_user_pages() is that this
function can also deal with pfnmap, and io mappings which is what the media
drivers need.

I have tested the patches with vivid driver so at least vb2 code got some
exposure. Conversion of other drivers was just compile-tested (for x86 so e.g.
exynos driver which is only for Samsung platform is completely untested).

Honza
Changes since v4:
* Minor cleanups and fixes pointed out by Mel and Vlasta
* Added Acked-by tags

Changes since v3:
* Added include linux/vmalloc.h into mm/gup.c as it's needed for some archs
* Fixed error path for exynos driver

Changes since v2:
* Renamed functions and structures as Mel suggested
* Other minor changes suggested by Mel
* Rebased on top of 4.1-rc2
* Changed functions to get pointer to array of pages / pfns to perform
  conversion if necessary. This fixes possible issue in the omap I may have
  introduced in v2 and generally makes the API less errorprone.
--
To unsubscribe from this list: send the line unsubscribe linux-media in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 6/9] media: vb2: Convert vb2_vmalloc_get_userptr() to use frame vector

2015-05-13 Thread Jan Kara
Convert vb2_vmalloc_get_userptr() to use frame vector infrastructure.
When we are doing that there's no need to allocate page array and some
code can be simplified.

Acked-by: Marek Szyprowski m.szyprow...@samsung.com
Tested-by: Marek Szyprowski m.szyprow...@samsung.com
Signed-off-by: Jan Kara j...@suse.cz
---
 drivers/media/v4l2-core/videobuf2-vmalloc.c | 94 +++--
 1 file changed, 36 insertions(+), 58 deletions(-)

diff --git a/drivers/media/v4l2-core/videobuf2-vmalloc.c 
b/drivers/media/v4l2-core/videobuf2-vmalloc.c
index 0ba40be21ebd..d2ce81fa2cdf 100644
--- a/drivers/media/v4l2-core/videobuf2-vmalloc.c
+++ b/drivers/media/v4l2-core/videobuf2-vmalloc.c
@@ -23,11 +23,9 @@
 
 struct vb2_vmalloc_buf {
void*vaddr;
-   struct page **pages;
-   struct vm_area_struct   *vma;
+   struct frame_vector *vec;
enum dma_data_direction dma_dir;
unsigned long   size;
-   unsigned intn_pages;
atomic_trefcount;
struct vb2_vmarea_handler   handler;
struct dma_buf  *dbuf;
@@ -76,10 +74,8 @@ static void *vb2_vmalloc_get_userptr(void *alloc_ctx, 
unsigned long vaddr,
 enum dma_data_direction dma_dir)
 {
struct vb2_vmalloc_buf *buf;
-   unsigned long first, last;
-   int n_pages, offset;
-   struct vm_area_struct *vma;
-   dma_addr_t physp;
+   struct frame_vector *vec;
+   int n_pages, offset, i;
 
buf = kzalloc(sizeof(*buf), GFP_KERNEL);
if (!buf)
@@ -88,53 +84,36 @@ static void *vb2_vmalloc_get_userptr(void *alloc_ctx, 
unsigned long vaddr,
buf-dma_dir = dma_dir;
offset = vaddr  ~PAGE_MASK;
buf-size = size;
-
-   down_read(current-mm-mmap_sem);
-   vma = find_vma(current-mm, vaddr);
-   if (vma  (vma-vm_flags  VM_PFNMAP)  (vma-vm_pgoff)) {
-   if (vb2_get_contig_userptr(vaddr, size, vma, physp))
-   goto fail_pages_array_alloc;
-   buf-vma = vma;
-   buf-vaddr = (__force void *)ioremap_nocache(physp, size);
-   if (!buf-vaddr)
-   goto fail_pages_array_alloc;
+   vec = vb2_create_framevec(vaddr, size, dma_dir == DMA_FROM_DEVICE);
+   if (IS_ERR(vec))
+   goto fail_pfnvec_create;
+   buf-vec = vec;
+   n_pages = frame_vector_count(vec);
+   if (frame_vector_to_pages(vec)  0) {
+   unsigned long *nums = frame_vector_pfns(vec);
+
+   /*
+* We cannot get page pointers for these pfns. Check memory is
+* physically contiguous and use direct mapping.
+*/
+   for (i = 1; i  n_pages; i++)
+   if (nums[i-1] + 1 != nums[i])
+   goto fail_map;
+   buf-vaddr = (__force void *)
+   ioremap_nocache(nums[0]  PAGE_SHIFT, size);
} else {
-   first = vaddr  PAGE_SHIFT;
-   last  = (vaddr + size - 1)  PAGE_SHIFT;
-   buf-n_pages = last - first + 1;
-   buf-pages = kzalloc(buf-n_pages * sizeof(struct page *),
-GFP_KERNEL);
-   if (!buf-pages)
-   goto fail_pages_array_alloc;
-
-   /* current-mm-mmap_sem is taken by videobuf2 core */
-   n_pages = get_user_pages(current, current-mm,
-vaddr  PAGE_MASK, buf-n_pages,
-dma_dir == DMA_FROM_DEVICE,
-1, /* force */
-buf-pages, NULL);
-   if (n_pages != buf-n_pages)
-   goto fail_get_user_pages;
-
-   buf-vaddr = vm_map_ram(buf-pages, buf-n_pages, -1,
+   buf-vaddr = vm_map_ram(frame_vector_pages(vec), n_pages, -1,
PAGE_KERNEL);
-   if (!buf-vaddr)
-   goto fail_get_user_pages;
}
-   up_read(current-mm-mmap_sem);
 
+   if (!buf-vaddr)
+   goto fail_map;
buf-vaddr += offset;
return buf;
 
-fail_get_user_pages:
-   pr_debug(get_user_pages requested/got: %d/%d]\n, n_pages,
-buf-n_pages);
-   while (--n_pages = 0)
-   put_page(buf-pages[n_pages]);
-   kfree(buf-pages);
-
-fail_pages_array_alloc:
-   up_read(current-mm-mmap_sem);
+fail_map:
+   vb2_destroy_framevec(vec);
+fail_pfnvec_create:
kfree(buf);
 
return NULL;
@@ -145,22 +124,21 @@ static void vb2_vmalloc_put_userptr(void *buf_priv)
struct vb2_vmalloc_buf *buf = buf_priv;
unsigned long vaddr = (unsigned long)buf-vaddr  PAGE_MASK;
unsigned int i

[PATCH 5/9] media: vb2: Convert vb2_dma_sg_get_userptr() to use frame vector

2015-05-13 Thread Jan Kara
Acked-by: Marek Szyprowski m.szyprow...@samsung.com
Tested-by: Marek Szyprowski m.szyprow...@samsung.com
Signed-off-by: Jan Kara j...@suse.cz
---
 drivers/media/v4l2-core/videobuf2-dma-sg.c | 97 +-
 1 file changed, 15 insertions(+), 82 deletions(-)

diff --git a/drivers/media/v4l2-core/videobuf2-dma-sg.c 
b/drivers/media/v4l2-core/videobuf2-dma-sg.c
index afd4b514affc..4ee1b3fbfe2a 100644
--- a/drivers/media/v4l2-core/videobuf2-dma-sg.c
+++ b/drivers/media/v4l2-core/videobuf2-dma-sg.c
@@ -38,6 +38,7 @@ struct vb2_dma_sg_buf {
struct device   *dev;
void*vaddr;
struct page **pages;
+   struct frame_vector *vec;
int offset;
enum dma_data_direction dma_dir;
struct sg_table sg_table;
@@ -51,7 +52,6 @@ struct vb2_dma_sg_buf {
unsigned intnum_pages;
atomic_trefcount;
struct vb2_vmarea_handler   handler;
-   struct vm_area_struct   *vma;
 
struct dma_buf_attachment   *db_attach;
 };
@@ -224,25 +224,17 @@ static void vb2_dma_sg_finish(void *buf_priv)
dma_sync_sg_for_cpu(buf-dev, sgt-sgl, sgt-nents, buf-dma_dir);
 }
 
-static inline int vma_is_io(struct vm_area_struct *vma)
-{
-   return !!(vma-vm_flags  (VM_IO | VM_PFNMAP));
-}
-
 static void *vb2_dma_sg_get_userptr(void *alloc_ctx, unsigned long vaddr,
unsigned long size,
enum dma_data_direction dma_dir)
 {
struct vb2_dma_sg_conf *conf = alloc_ctx;
struct vb2_dma_sg_buf *buf;
-   unsigned long first, last;
-   int num_pages_from_user;
-   struct vm_area_struct *vma;
struct sg_table *sgt;
DEFINE_DMA_ATTRS(attrs);
+   struct frame_vector *vec;
 
dma_set_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs);
-
buf = kzalloc(sizeof *buf, GFP_KERNEL);
if (!buf)
return NULL;
@@ -253,63 +245,19 @@ static void *vb2_dma_sg_get_userptr(void *alloc_ctx, 
unsigned long vaddr,
buf-offset = vaddr  ~PAGE_MASK;
buf-size = size;
buf-dma_sgt = buf-sg_table;
+   vec = vb2_create_framevec(vaddr, size, buf-dma_dir == DMA_FROM_DEVICE);
+   if (IS_ERR(vec))
+   goto userptr_fail_pfnvec;
+   buf-vec = vec;
 
-   first = (vaddrPAGE_MASK)  PAGE_SHIFT;
-   last  = ((vaddr + size - 1)  PAGE_MASK)  PAGE_SHIFT;
-   buf-num_pages = last - first + 1;
-
-   buf-pages = kzalloc(buf-num_pages * sizeof(struct page *),
-GFP_KERNEL);
-   if (!buf-pages)
-   goto userptr_fail_alloc_pages;
-
-   down_read(current-mm-mmap_sem);
-   vma = find_vma(current-mm, vaddr);
-   if (!vma) {
-   dprintk(1, no vma for address %lu\n, vaddr);
-   goto userptr_fail_find_vma;
-   }
-
-   if (vma-vm_end  vaddr + size) {
-   dprintk(1, vma at %lu is too small for %lu bytes\n,
-   vaddr, size);
-   goto userptr_fail_find_vma;
-   }
-
-   buf-vma = vb2_get_vma(vma);
-   if (!buf-vma) {
-   dprintk(1, failed to copy vma\n);
-   goto userptr_fail_find_vma;
-   }
-
-   if (vma_is_io(buf-vma)) {
-   for (num_pages_from_user = 0;
-num_pages_from_user  buf-num_pages;
-++num_pages_from_user, vaddr += PAGE_SIZE) {
-   unsigned long pfn;
-
-   if (follow_pfn(vma, vaddr, pfn)) {
-   dprintk(1, no page for address %lu\n, vaddr);
-   break;
-   }
-   buf-pages[num_pages_from_user] = pfn_to_page(pfn);
-   }
-   } else
-   num_pages_from_user = get_user_pages(current, current-mm,
-vaddr  PAGE_MASK,
-buf-num_pages,
-buf-dma_dir == DMA_FROM_DEVICE,
-1, /* force */
-buf-pages,
-NULL);
-   up_read(current-mm-mmap_sem);
-
-   if (num_pages_from_user != buf-num_pages)
-   goto userptr_fail_get_user_pages;
+   buf-pages = frame_vector_pages(vec);
+   if (IS_ERR(buf-pages))
+   goto userptr_fail_sgtable;
+   buf-num_pages = frame_vector_count(vec);
 
if (sg_alloc_table_from_pages(buf-dma_sgt, buf-pages,
buf-num_pages, buf-offset, size, 0))
-   goto userptr_fail_alloc_table_from_pages;
+   goto userptr_fail_sgtable;
 
sgt = buf-sg_table;
/*
@@ -323,19 +271,9

[PATCH 7/9] media: vb2: Convert vb2_dc_get_userptr() to use frame vector

2015-05-13 Thread Jan Kara
Convert vb2_dc_get_userptr() to use frame vector infrastructure. When we
are doing that there's no need to allocate page array and some code can
be simplified.

Acked-by: Marek Szyprowski m.szyprow...@samsung.com
Tested-by: Marek Szyprowski m.szyprow...@samsung.com
Signed-off-by: Jan Kara j...@suse.cz
---
 drivers/media/v4l2-core/videobuf2-dma-contig.c | 214 -
 1 file changed, 34 insertions(+), 180 deletions(-)

diff --git a/drivers/media/v4l2-core/videobuf2-dma-contig.c 
b/drivers/media/v4l2-core/videobuf2-dma-contig.c
index 620c4aa78881..e6cea452302b 100644
--- a/drivers/media/v4l2-core/videobuf2-dma-contig.c
+++ b/drivers/media/v4l2-core/videobuf2-dma-contig.c
@@ -32,15 +32,13 @@ struct vb2_dc_buf {
dma_addr_t  dma_addr;
enum dma_data_direction dma_dir;
struct sg_table *dma_sgt;
+   struct frame_vector *vec;
 
/* MMAP related */
struct vb2_vmarea_handler   handler;
atomic_trefcount;
struct sg_table *sgt_base;
 
-   /* USERPTR related */
-   struct vm_area_struct   *vma;
-
/* DMABUF related */
struct dma_buf_attachment   *db_attach;
 };
@@ -49,24 +47,6 @@ struct vb2_dc_buf {
 /*scatterlist table functions*/
 /*/
 
-
-static void vb2_dc_sgt_foreach_page(struct sg_table *sgt,
-   void (*cb)(struct page *pg))
-{
-   struct scatterlist *s;
-   unsigned int i;
-
-   for_each_sg(sgt-sgl, s, sgt-orig_nents, i) {
-   struct page *page = sg_page(s);
-   unsigned int n_pages = PAGE_ALIGN(s-offset + s-length)
-PAGE_SHIFT;
-   unsigned int j;
-
-   for (j = 0; j  n_pages; ++j, ++page)
-   cb(page);
-   }
-}
-
 static unsigned long vb2_dc_get_contiguous_size(struct sg_table *sgt)
 {
struct scatterlist *s;
@@ -429,92 +409,12 @@ static struct dma_buf *vb2_dc_get_dmabuf(void *buf_priv, 
unsigned long flags)
 /*   callbacks for USERPTR buffers   */
 /*/
 
-static inline int vma_is_io(struct vm_area_struct *vma)
-{
-   return !!(vma-vm_flags  (VM_IO | VM_PFNMAP));
-}
-
-static int vb2_dc_get_user_pfn(unsigned long start, int n_pages,
-   struct vm_area_struct *vma, unsigned long *res)
-{
-   unsigned long pfn, start_pfn, prev_pfn;
-   unsigned int i;
-   int ret;
-
-   if (!vma_is_io(vma))
-   return -EFAULT;
-
-   ret = follow_pfn(vma, start, pfn);
-   if (ret)
-   return ret;
-
-   start_pfn = pfn;
-   start += PAGE_SIZE;
-
-   for (i = 1; i  n_pages; ++i, start += PAGE_SIZE) {
-   prev_pfn = pfn;
-   ret = follow_pfn(vma, start, pfn);
-
-   if (ret) {
-   pr_err(no page for address %lu\n, start);
-   return ret;
-   }
-   if (pfn != prev_pfn + 1)
-   return -EINVAL;
-   }
-
-   *res = start_pfn;
-   return 0;
-}
-
-static int vb2_dc_get_user_pages(unsigned long start, struct page **pages,
-   int n_pages, struct vm_area_struct *vma,
-   enum dma_data_direction dma_dir)
-{
-   if (vma_is_io(vma)) {
-   unsigned int i;
-
-   for (i = 0; i  n_pages; ++i, start += PAGE_SIZE) {
-   unsigned long pfn;
-   int ret = follow_pfn(vma, start, pfn);
-
-   if (!pfn_valid(pfn))
-   return -EINVAL;
-
-   if (ret) {
-   pr_err(no page for address %lu\n, start);
-   return ret;
-   }
-   pages[i] = pfn_to_page(pfn);
-   }
-   } else {
-   int n;
-
-   n = get_user_pages(current, current-mm, start  PAGE_MASK,
-   n_pages, dma_dir == DMA_FROM_DEVICE, 1, pages, NULL);
-   /* negative error means that no page was pinned */
-   n = max(n, 0);
-   if (n != n_pages) {
-   pr_err(got only %d of %d user pages\n, n, n_pages);
-   while (n)
-   put_page(pages[--n]);
-   return -EFAULT;
-   }
-   }
-
-   return 0;
-}
-
-static void vb2_dc_put_dirty_page(struct page *page)
-{
-   set_page_dirty_lock(page);
-   put_page(page);
-}
-
 static void vb2_dc_put_userptr(void *buf_priv)
 {
struct vb2_dc_buf *buf = buf_priv;
struct sg_table *sgt = buf-dma_sgt;
+   int i;
+   struct page **pages;
 
if (sgt) {
DEFINE_DMA_ATTRS(attrs);
@@ -526,15 +426,15 @@ static void vb2_dc_put_userptr(void *buf_priv

[PATCH 8/9] media: vb2: Remove unused functions

2015-05-13 Thread Jan Kara
Conversion to the use of pinned pfns made some functions unused. Remove
them. Also there's no need to lock mmap_sem in __buf_prepare() anymore.

Acked-by: Marek Szyprowski m.szyprow...@samsung.com
Tested-by: Marek Szyprowski m.szyprow...@samsung.com
Signed-off-by: Jan Kara j...@suse.cz
---
 drivers/media/v4l2-core/videobuf2-memops.c | 114 -
 include/media/videobuf2-memops.h   |   6 --
 2 files changed, 120 deletions(-)

diff --git a/drivers/media/v4l2-core/videobuf2-memops.c 
b/drivers/media/v4l2-core/videobuf2-memops.c
index 0ec186d41b9b..48c6a49c4928 100644
--- a/drivers/media/v4l2-core/videobuf2-memops.c
+++ b/drivers/media/v4l2-core/videobuf2-memops.c
@@ -23,120 +23,6 @@
 #include media/videobuf2-memops.h
 
 /**
- * vb2_get_vma() - acquire and lock the virtual memory area
- * @vma:   given virtual memory area
- *
- * This function attempts to acquire an area mapped in the userspace for
- * the duration of a hardware operation. The area is locked by performing
- * the same set of operation that are done when process calls fork() and
- * memory areas are duplicated.
- *
- * Returns a copy of a virtual memory region on success or NULL.
- */
-struct vm_area_struct *vb2_get_vma(struct vm_area_struct *vma)
-{
-   struct vm_area_struct *vma_copy;
-
-   vma_copy = kmalloc(sizeof(*vma_copy), GFP_KERNEL);
-   if (vma_copy == NULL)
-   return NULL;
-
-   if (vma-vm_ops  vma-vm_ops-open)
-   vma-vm_ops-open(vma);
-
-   if (vma-vm_file)
-   get_file(vma-vm_file);
-
-   memcpy(vma_copy, vma, sizeof(*vma));
-
-   vma_copy-vm_mm = NULL;
-   vma_copy-vm_next = NULL;
-   vma_copy-vm_prev = NULL;
-
-   return vma_copy;
-}
-EXPORT_SYMBOL_GPL(vb2_get_vma);
-
-/**
- * vb2_put_userptr() - release a userspace virtual memory area
- * @vma:   virtual memory region associated with the area to be released
- *
- * This function releases the previously acquired memory area after a hardware
- * operation.
- */
-void vb2_put_vma(struct vm_area_struct *vma)
-{
-   if (!vma)
-   return;
-
-   if (vma-vm_ops  vma-vm_ops-close)
-   vma-vm_ops-close(vma);
-
-   if (vma-vm_file)
-   fput(vma-vm_file);
-
-   kfree(vma);
-}
-EXPORT_SYMBOL_GPL(vb2_put_vma);
-
-/**
- * vb2_get_contig_userptr() - lock physically contiguous userspace mapped 
memory
- * @vaddr: starting virtual address of the area to be verified
- * @size:  size of the area
- * @res_paddr: will return physical address for the given vaddr
- * @res_vma:   will return locked copy of struct vm_area for the given area
- *
- * This function will go through memory area of size @size mapped at @vaddr and
- * verify that the underlying physical pages are contiguous. If they are
- * contiguous the virtual memory area is locked and a @res_vma is filled with
- * the copy and @res_pa set to the physical address of the buffer.
- *
- * Returns 0 on success.
- */
-int vb2_get_contig_userptr(unsigned long vaddr, unsigned long size,
-  struct vm_area_struct **res_vma, dma_addr_t *res_pa)
-{
-   struct mm_struct *mm = current-mm;
-   struct vm_area_struct *vma;
-   unsigned long offset, start, end;
-   unsigned long this_pfn, prev_pfn;
-   dma_addr_t pa = 0;
-
-   start = vaddr;
-   offset = start  ~PAGE_MASK;
-   end = start + size;
-
-   vma = find_vma(mm, start);
-
-   if (vma == NULL || vma-vm_end  end)
-   return -EFAULT;
-
-   for (prev_pfn = 0; start  end; start += PAGE_SIZE) {
-   int ret = follow_pfn(vma, start, this_pfn);
-   if (ret)
-   return ret;
-
-   if (prev_pfn == 0)
-   pa = this_pfn  PAGE_SHIFT;
-   else if (this_pfn != prev_pfn + 1)
-   return -EFAULT;
-
-   prev_pfn = this_pfn;
-   }
-
-   /*
-* Memory is contigous, lock vma and return to the caller
-*/
-   *res_vma = vb2_get_vma(vma);
-   if (*res_vma == NULL)
-   return -ENOMEM;
-
-   *res_pa = pa + offset;
-   return 0;
-}
-EXPORT_SYMBOL_GPL(vb2_get_contig_userptr);
-
-/**
  * vb2_create_framevec() - map virtual addresses to pfns
  * @start: Virtual user address where we start mapping
  * @length:Length of a range to map
diff --git a/include/media/videobuf2-memops.h b/include/media/videobuf2-memops.h
index 2f0564ff5f31..830b5239fd8b 100644
--- a/include/media/videobuf2-memops.h
+++ b/include/media/videobuf2-memops.h
@@ -31,12 +31,6 @@ struct vb2_vmarea_handler {
 
 extern const struct vm_operations_struct vb2_common_vm_ops;
 
-int vb2_get_contig_userptr(unsigned long vaddr, unsigned long size,
-  struct vm_area_struct **res_vma, dma_addr_t *res_pa);
-
-struct vm_area_struct *vb2_get_vma(struct vm_area_struct *vma);
-void vb2_put_vma(struct vm_area_struct *vma

[PATCH 2/9] mm: Provide new get_vaddr_frames() helper

2015-05-13 Thread Jan Kara
Provide new function get_vaddr_frames().  This function maps virtual
addresses from given start and fills given array with page frame numbers of
the corresponding pages. If given start belongs to a normal vma, the function
grabs reference to each of the pages to pin them in memory. If start
belongs to VM_IO | VM_PFNMAP vma, we don't touch page structures. Caller
must make sure pfns aren't reused for anything else while he is using
them.

This function is created for various drivers to simplify handling of
their buffers.

Acked-by: Mel Gorman mgor...@suse.de
Acked-by: Vlastimil Babka vba...@suse.cz
Signed-off-by: Jan Kara j...@suse.cz
---
 include/linux/mm.h |  44 +++
 mm/gup.c   | 226 +
 2 files changed, 270 insertions(+)

diff --git a/include/linux/mm.h b/include/linux/mm.h
index 0755b9fd03a7..dcd1f02a78e9 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -20,6 +20,7 @@
 #include linux/shrinker.h
 #include linux/resource.h
 #include linux/page_ext.h
+#include linux/err.h
 
 struct mempolicy;
 struct anon_vma;
@@ -1197,6 +1198,49 @@ long get_user_pages_unlocked(struct task_struct *tsk, 
struct mm_struct *mm,
int write, int force, struct page **pages);
 int get_user_pages_fast(unsigned long start, int nr_pages, int write,
struct page **pages);
+
+/* Container for pinned pfns / pages */
+struct frame_vector {
+   unsigned int nr_allocated;  /* Number of frames we have space for */
+   unsigned int nr_frames; /* Number of frames stored in ptrs array */
+   bool got_ref;   /* Did we pin pages by getting page ref? */
+   bool is_pfns;   /* Does array contain pages or pfns? */
+   void *ptrs[0];  /* Array of pinned pfns / pages. Use
+* pfns_vector_pages() or pfns_vector_pfns()
+* for access */
+};
+
+struct frame_vector *frame_vector_create(unsigned int nr_frames);
+void frame_vector_destroy(struct frame_vector *vec);
+int get_vaddr_frames(unsigned long start, unsigned int nr_pfns,
+bool write, bool force, struct frame_vector *vec);
+void put_vaddr_frames(struct frame_vector *vec);
+int frame_vector_to_pages(struct frame_vector *vec);
+void frame_vector_to_pfns(struct frame_vector *vec);
+
+static inline unsigned int frame_vector_count(struct frame_vector *vec)
+{
+   return vec-nr_frames;
+}
+
+static inline struct page **frame_vector_pages(struct frame_vector *vec)
+{
+   if (vec-is_pfns) {
+   int err = frame_vector_to_pages(vec);
+
+   if (err)
+   return ERR_PTR(err);
+   }
+   return (struct page **)(vec-ptrs);
+}
+
+static inline unsigned long *frame_vector_pfns(struct frame_vector *vec)
+{
+   if (!vec-is_pfns)
+   frame_vector_to_pfns(vec);
+   return (unsigned long *)(vec-ptrs);
+}
+
 struct kvec;
 int get_kernel_pages(const struct kvec *iov, int nr_pages, int write,
struct page **pages);
diff --git a/mm/gup.c b/mm/gup.c
index 6297f6bccfb1..9d7f4fde30cb 100644
--- a/mm/gup.c
+++ b/mm/gup.c
@@ -8,6 +8,7 @@
 #include linux/rmap.h
 #include linux/swap.h
 #include linux/swapops.h
+#include linux/vmalloc.h
 
 #include linux/sched.h
 #include linux/rwsem.h
@@ -936,6 +937,231 @@ int __mm_populate(unsigned long start, unsigned long len, 
int ignore_errors)
return ret; /* 0 or negative error code */
 }
 
+/*
+ * get_vaddr_frames() - map virtual addresses to pfns
+ * @start: starting user address
+ * @nr_frames: number of pages / pfns from start to map
+ * @write: whether pages will be written to by the caller
+ * @force: whether to force write access even if user mapping is
+ * readonly. See description of the same argument of
+   get_user_pages().
+ * @vec:   structure which receives pages / pfns of the addresses mapped.
+ * It should have space for at least nr_frames entries.
+ *
+ * This function maps virtual addresses from @start and fills @vec structure
+ * with page frame numbers or page pointers to corresponding pages (choice
+ * depends on the type of the vma underlying the virtual address). If @start
+ * belongs to a normal vma, the function grabs reference to each of the pages
+ * to pin them in memory. If @start belongs to VM_IO | VM_PFNMAP vma, we don't
+ * touch page structures and the caller must make sure pfns aren't reused for
+ * anything else while he is using them.
+ *
+ * The function returns number of pages mapped which may be less than
+ * @nr_frames. In particular we stop mapping if there are more vmas of
+ * different type underlying the specified range of virtual addresses.
+ * When the function isn't able to map a single page, it returns error.
+ *
+ * This function takes care of grabbing mmap_sem as necessary.
+ */
+int get_vaddr_frames(unsigned long start, unsigned int

[PATCH 9/9] drm/exynos: Convert g2d_userptr_get_dma_addr() to use get_vaddr_frames()

2015-05-13 Thread Jan Kara
Convert g2d_userptr_get_dma_addr() to pin pages using get_vaddr_frames().
This removes the knowledge about vmas and mmap_sem locking from exynos
driver. Also it fixes a problem that the function has been mapping user
provided address without holding mmap_sem.

Signed-off-by: Jan Kara j...@suse.cz
---
 drivers/gpu/drm/exynos/exynos_drm_g2d.c | 89 ++
 drivers/gpu/drm/exynos/exynos_drm_gem.c | 97 -
 2 files changed, 29 insertions(+), 157 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c 
b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
index 81a250830808..265519c0fe2d 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
@@ -190,10 +190,8 @@ struct g2d_cmdlist_userptr {
dma_addr_t  dma_addr;
unsigned long   userptr;
unsigned long   size;
-   struct page **pages;
-   unsigned intnpages;
+   struct frame_vector *vec;
struct sg_table *sgt;
-   struct vm_area_struct   *vma;
atomic_trefcount;
boolin_pool;
boolout_of_list;
@@ -363,6 +361,7 @@ static void g2d_userptr_put_dma_addr(struct drm_device 
*drm_dev,
 {
struct g2d_cmdlist_userptr *g2d_userptr =
(struct g2d_cmdlist_userptr *)obj;
+   struct page **pages;
 
if (!obj)
return;
@@ -382,19 +381,21 @@ out:
exynos_gem_unmap_sgt_from_dma(drm_dev, g2d_userptr-sgt,
DMA_BIDIRECTIONAL);
 
-   exynos_gem_put_pages_to_userptr(g2d_userptr-pages,
-   g2d_userptr-npages,
-   g2d_userptr-vma);
+   pages = frame_vector_pages(g2d_userptr-vec);
+   if (!IS_ERR(pages)) {
+   int i;
 
-   exynos_gem_put_vma(g2d_userptr-vma);
+   for (i = 0; i  frame_vector_count(g2d_userptr-vec); i++)
+   set_page_dirty_lock(pages[i]);
+   }
+   put_vaddr_frames(g2d_userptr-vec);
+   frame_vector_destroy(g2d_userptr-vec);
 
if (!g2d_userptr-out_of_list)
list_del_init(g2d_userptr-list);
 
sg_free_table(g2d_userptr-sgt);
kfree(g2d_userptr-sgt);
-
-   drm_free_large(g2d_userptr-pages);
kfree(g2d_userptr);
 }
 
@@ -413,6 +414,7 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct 
drm_device *drm_dev,
struct vm_area_struct *vma;
unsigned long start, end;
unsigned int npages, offset;
+   struct frame_vector *vec;
int ret;
 
if (!size) {
@@ -456,65 +458,37 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct 
drm_device *drm_dev,
return ERR_PTR(-ENOMEM);
 
atomic_set(g2d_userptr-refcount, 1);
+   g2d_userptr-size = size;
 
start = userptr  PAGE_MASK;
offset = userptr  ~PAGE_MASK;
end = PAGE_ALIGN(userptr + size);
npages = (end - start)  PAGE_SHIFT;
-   g2d_userptr-npages = npages;
-
-   pages = drm_calloc_large(npages, sizeof(struct page *));
-   if (!pages) {
-   DRM_ERROR(failed to allocate pages.\n);
-   ret = -ENOMEM;
+   vec = g2d_userptr-vec = frame_vector_create(npages);
+   if (!vec)
goto err_free;
-   }
 
-   down_read(current-mm-mmap_sem);
-   vma = find_vma(current-mm, userptr);
-   if (!vma) {
-   up_read(current-mm-mmap_sem);
-   DRM_ERROR(failed to get vm region.\n);
+   ret = get_vaddr_frames(start, npages, 1, 1, vec);
+   if (ret != npages) {
+   DRM_ERROR(failed to get user pages from userptr.\n);
+   if (ret  0)
+   goto err_destroy_framevec;
ret = -EFAULT;
-   goto err_free_pages;
+   goto err_put_framevec;
}
-
-   if (vma-vm_end  userptr + size) {
-   up_read(current-mm-mmap_sem);
-   DRM_ERROR(vma is too small.\n);
+   if (frame_vector_to_pages(vec)  0) {
ret = -EFAULT;
-   goto err_free_pages;
+   goto err_put_framevec;
}
 
-   g2d_userptr-vma = exynos_gem_get_vma(vma);
-   if (!g2d_userptr-vma) {
-   up_read(current-mm-mmap_sem);
-   DRM_ERROR(failed to copy vma.\n);
-   ret = -ENOMEM;
-   goto err_free_pages;
-   }
-
-   g2d_userptr-size = size;
-
-   ret = exynos_gem_get_pages_from_userptr(start  PAGE_MASK,
-   npages, pages, vma);
-   if (ret  0) {
-   up_read(current-mm-mmap_sem);
-   DRM_ERROR(failed to get user pages from userptr.\n);
-   goto err_put_vma;
-   }
-
-   up_read(current-mm-mmap_sem);
-   g2d_userptr-pages

[PATCH 4/9] vb2: Provide helpers for mapping virtual addresses

2015-05-13 Thread Jan Kara
Provide simple helper functions to map virtual address range into an
array of pfns / pages.

Acked-by: Marek Szyprowski m.szyprow...@samsung.com
Tested-by: Marek Szyprowski m.szyprow...@samsung.com
Signed-off-by: Jan Kara j...@suse.cz
---
 drivers/media/v4l2-core/videobuf2-memops.c | 58 ++
 include/media/videobuf2-memops.h   |  5 +++
 2 files changed, 63 insertions(+)

diff --git a/drivers/media/v4l2-core/videobuf2-memops.c 
b/drivers/media/v4l2-core/videobuf2-memops.c
index 81c1ad8b2cf1..0ec186d41b9b 100644
--- a/drivers/media/v4l2-core/videobuf2-memops.c
+++ b/drivers/media/v4l2-core/videobuf2-memops.c
@@ -137,6 +137,64 @@ int vb2_get_contig_userptr(unsigned long vaddr, unsigned 
long size,
 EXPORT_SYMBOL_GPL(vb2_get_contig_userptr);
 
 /**
+ * vb2_create_framevec() - map virtual addresses to pfns
+ * @start: Virtual user address where we start mapping
+ * @length:Length of a range to map
+ * @write: Should we map for writing into the area
+ *
+ * This function allocates and fills in a vector with pfns corresponding to
+ * virtual address range passed in arguments. If pfns have corresponding pages,
+ * page references are also grabbed to pin pages in memory. The function
+ * returns pointer to the vector on success and error pointer in case of
+ * failure. Returned vector needs to be freed via vb2_destroy_pfnvec().
+ */
+struct frame_vector *vb2_create_framevec(unsigned long start,
+unsigned long length,
+bool write)
+{
+   int ret;
+   unsigned long first, last;
+   unsigned long nr;
+   struct frame_vector *vec;
+
+   first = start  PAGE_SHIFT;
+   last = (start + length - 1)  PAGE_SHIFT;
+   nr = last - first + 1;
+   vec = frame_vector_create(nr);
+   if (!vec)
+   return ERR_PTR(-ENOMEM);
+   ret = get_vaddr_frames(start, nr, write, 1, vec);
+   if (ret  0)
+   goto out_destroy;
+   /* We accept only complete set of PFNs */
+   if (ret != nr) {
+   ret = -EFAULT;
+   goto out_release;
+   }
+   return vec;
+out_release:
+   put_vaddr_frames(vec);
+out_destroy:
+   frame_vector_destroy(vec);
+   return ERR_PTR(ret);
+}
+EXPORT_SYMBOL(vb2_create_framevec);
+
+/**
+ * vb2_destroy_framevec() - release vector of mapped pfns
+ * @vec:   vector of pfns / pages to release
+ *
+ * This releases references to all pages in the vector @vec (if corresponding
+ * pfns are backed by pages) and frees the passed vector.
+ */
+void vb2_destroy_framevec(struct frame_vector *vec)
+{
+   put_vaddr_frames(vec);
+   frame_vector_destroy(vec);
+}
+EXPORT_SYMBOL(vb2_destroy_framevec);
+
+/**
  * vb2_common_vm_open() - increase refcount of the vma
  * @vma:   virtual memory region for the mapping
  *
diff --git a/include/media/videobuf2-memops.h b/include/media/videobuf2-memops.h
index f05444ca8c0c..2f0564ff5f31 100644
--- a/include/media/videobuf2-memops.h
+++ b/include/media/videobuf2-memops.h
@@ -15,6 +15,7 @@
 #define _MEDIA_VIDEOBUF2_MEMOPS_H
 
 #include media/videobuf2-core.h
+#include linux/mm.h
 
 /**
  * vb2_vmarea_handler - common vma refcount tracking handler
@@ -36,5 +37,9 @@ int vb2_get_contig_userptr(unsigned long vaddr, unsigned long 
size,
 struct vm_area_struct *vb2_get_vma(struct vm_area_struct *vma);
 void vb2_put_vma(struct vm_area_struct *vma);
 
+struct frame_vector *vb2_create_framevec(unsigned long start,
+unsigned long length,
+bool write);
+void vb2_destroy_framevec(struct frame_vector *vec);
 
 #endif
-- 
2.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-media in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 3/9] media: omap_vout: Convert omap_vout_uservirt_to_phys() to use get_vaddr_pfns()

2015-05-13 Thread Jan Kara
Convert omap_vout_uservirt_to_phys() to use get_vaddr_pfns() instead of
hand made mapping of virtual address to physical address. Also the
function leaked page reference from get_user_pages() so fix that by
properly release the reference when omap_vout_buffer_release() is
called.

Signed-off-by: Jan Kara j...@suse.cz
---
 drivers/media/platform/omap/omap_vout.c | 67 +++--
 1 file changed, 31 insertions(+), 36 deletions(-)

diff --git a/drivers/media/platform/omap/omap_vout.c 
b/drivers/media/platform/omap/omap_vout.c
index 17b189a81ec5..0e4b3cfacc5d 100644
--- a/drivers/media/platform/omap/omap_vout.c
+++ b/drivers/media/platform/omap/omap_vout.c
@@ -195,46 +195,34 @@ static int omap_vout_try_format(struct v4l2_pix_format 
*pix)
 }
 
 /*
- * omap_vout_uservirt_to_phys: This inline function is used to convert user
- * space virtual address to physical address.
+ * omap_vout_get_userptr: Convert user space virtual address to physical
+ * address.
  */
-static unsigned long omap_vout_uservirt_to_phys(unsigned long virtp)
+static int omap_vout_get_userptr(struct videobuf_buffer *vb, u32 virtp,
+u32 *physp)
 {
-   unsigned long physp = 0;
-   struct vm_area_struct *vma;
-   struct mm_struct *mm = current-mm;
+   struct frame_vector *vec;
+   int ret;
 
/* For kernel direct-mapped memory, take the easy way */
-   if (virtp = PAGE_OFFSET)
-   return virt_to_phys((void *) virtp);
-
-   down_read(current-mm-mmap_sem);
-   vma = find_vma(mm, virtp);
-   if (vma  (vma-vm_flags  VM_IO)  vma-vm_pgoff) {
-   /* this will catch, kernel-allocated, mmaped-to-usermode
-  addresses */
-   physp = (vma-vm_pgoff  PAGE_SHIFT) + (virtp - vma-vm_start);
-   up_read(current-mm-mmap_sem);
-   } else {
-   /* otherwise, use get_user_pages() for general userland pages */
-   int res, nr_pages = 1;
-   struct page *pages;
+   if (virtp = PAGE_OFFSET) {
+   *physp = virt_to_phys((void *)virtp);
+   return 0;
+   }
 
-   res = get_user_pages(current, current-mm, virtp, nr_pages, 1,
-   0, pages, NULL);
-   up_read(current-mm-mmap_sem);
+   vec = frame_vector_create(1);
+   if (!vec)
+   return -ENOMEM;
 
-   if (res == nr_pages) {
-   physp =  __pa(page_address(pages[0]) +
-   (virtp  ~PAGE_MASK));
-   } else {
-   printk(KERN_WARNING VOUT_NAME
-   get_user_pages failed\n);
-   return 0;
-   }
+   ret = get_vaddr_frames(virtp, 1, true, false, vec);
+   if (ret != 1) {
+   frame_vector_destroy(vec);
+   return -EINVAL;
}
+   *physp = __pfn_to_phys(frame_vector_pfns(vec)[0]);
+   vb-priv = vec;
 
-   return physp;
+   return 0;
 }
 
 /*
@@ -788,11 +776,15 @@ static int omap_vout_buffer_prepare(struct videobuf_queue 
*q,
 * address of the buffer
 */
if (V4L2_MEMORY_USERPTR == vb-memory) {
+   int ret;
+
if (0 == vb-baddr)
return -EINVAL;
/* Physical address */
-   vout-queued_buf_addr[vb-i] = (u8 *)
-   omap_vout_uservirt_to_phys(vb-baddr);
+   ret = omap_vout_get_userptr(vb, vb-baddr,
+   (u32 *)vout-queued_buf_addr[vb-i]);
+   if (ret  0)
+   return ret;
} else {
unsigned long addr, dma_addr;
unsigned long size;
@@ -841,9 +833,12 @@ static void omap_vout_buffer_release(struct videobuf_queue 
*q,
struct omap_vout_device *vout = q-priv_data;
 
vb-state = VIDEOBUF_NEEDS_INIT;
+   if (vb-memory == V4L2_MEMORY_USERPTR  vb-priv) {
+   struct frame_vector *vec = vb-priv;
 
-   if (V4L2_MEMORY_MMAP != vout-memory)
-   return;
+   put_vaddr_frames(vec);
+   frame_vector_destroy(vec);
+   }
 }
 
 /*
-- 
2.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-media in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 1/9] [media] vb2: Push mmap_sem down to memops

2015-05-13 Thread Jan Kara
Currently vb2 core acquires mmap_sem just around call to
__qbuf_userptr(). However since commit f035eb4e976ef5 (videobuf2: fix
lockdep warning) it isn't necessary to acquire it so early as we no
longer have to drop queue mutex before acquiring mmap_sem. So push
acquisition of mmap_sem down into .get_userptr and .put_userptr memops
so that the semaphore is acquired for a shorter time and it is clearer
what it is needed for.

Signed-off-by: Jan Kara j...@suse.cz
---
 drivers/media/v4l2-core/videobuf2-core.c   | 2 --
 drivers/media/v4l2-core/videobuf2-dma-contig.c | 7 +++
 drivers/media/v4l2-core/videobuf2-dma-sg.c | 6 ++
 drivers/media/v4l2-core/videobuf2-vmalloc.c| 6 +-
 4 files changed, 18 insertions(+), 3 deletions(-)

diff --git a/drivers/media/v4l2-core/videobuf2-core.c 
b/drivers/media/v4l2-core/videobuf2-core.c
index 66ada01c796c..20cdbc0900ea 100644
--- a/drivers/media/v4l2-core/videobuf2-core.c
+++ b/drivers/media/v4l2-core/videobuf2-core.c
@@ -1657,9 +1657,7 @@ static int __buf_prepare(struct vb2_buffer *vb, const 
struct v4l2_buffer *b)
ret = __qbuf_mmap(vb, b);
break;
case V4L2_MEMORY_USERPTR:
-   down_read(current-mm-mmap_sem);
ret = __qbuf_userptr(vb, b);
-   up_read(current-mm-mmap_sem);
break;
case V4L2_MEMORY_DMABUF:
ret = __qbuf_dmabuf(vb, b);
diff --git a/drivers/media/v4l2-core/videobuf2-dma-contig.c 
b/drivers/media/v4l2-core/videobuf2-dma-contig.c
index 644dec73d220..620c4aa78881 100644
--- a/drivers/media/v4l2-core/videobuf2-dma-contig.c
+++ b/drivers/media/v4l2-core/videobuf2-dma-contig.c
@@ -532,7 +532,9 @@ static void vb2_dc_put_userptr(void *buf_priv)
sg_free_table(sgt);
kfree(sgt);
}
+   down_read(current-mm-mmap_sem);
vb2_put_vma(buf-vma);
+   up_read(current-mm-mmap_sem);
kfree(buf);
 }
 
@@ -616,6 +618,7 @@ static void *vb2_dc_get_userptr(void *alloc_ctx, unsigned 
long vaddr,
goto fail_buf;
}
 
+   down_read(current-mm-mmap_sem);
/* current-mm-mmap_sem is taken by videobuf2 core */
vma = find_vma(current-mm, vaddr);
if (!vma) {
@@ -642,6 +645,7 @@ static void *vb2_dc_get_userptr(void *alloc_ctx, unsigned 
long vaddr,
if (ret) {
unsigned long pfn;
if (vb2_dc_get_user_pfn(start, n_pages, vma, pfn) == 0) {
+   up_read(current-mm-mmap_sem);
buf-dma_addr = vb2_dc_pfn_to_dma(buf-dev, pfn);
buf-size = size;
kfree(pages);
@@ -651,6 +655,7 @@ static void *vb2_dc_get_userptr(void *alloc_ctx, unsigned 
long vaddr,
pr_err(failed to get user pages\n);
goto fail_vma;
}
+   up_read(current-mm-mmap_sem);
 
sgt = kzalloc(sizeof(*sgt), GFP_KERNEL);
if (!sgt) {
@@ -713,10 +718,12 @@ fail_get_user_pages:
while (n_pages)
put_page(pages[--n_pages]);
 
+   down_read(current-mm-mmap_sem);
 fail_vma:
vb2_put_vma(buf-vma);
 
 fail_pages:
+   up_read(current-mm-mmap_sem);
kfree(pages); /* kfree is NULL-proof */
 
 fail_buf:
diff --git a/drivers/media/v4l2-core/videobuf2-dma-sg.c 
b/drivers/media/v4l2-core/videobuf2-dma-sg.c
index 45c708e463b9..afd4b514affc 100644
--- a/drivers/media/v4l2-core/videobuf2-dma-sg.c
+++ b/drivers/media/v4l2-core/videobuf2-dma-sg.c
@@ -263,6 +263,7 @@ static void *vb2_dma_sg_get_userptr(void *alloc_ctx, 
unsigned long vaddr,
if (!buf-pages)
goto userptr_fail_alloc_pages;
 
+   down_read(current-mm-mmap_sem);
vma = find_vma(current-mm, vaddr);
if (!vma) {
dprintk(1, no vma for address %lu\n, vaddr);
@@ -301,6 +302,7 @@ static void *vb2_dma_sg_get_userptr(void *alloc_ctx, 
unsigned long vaddr,
 1, /* force */
 buf-pages,
 NULL);
+   up_read(current-mm-mmap_sem);
 
if (num_pages_from_user != buf-num_pages)
goto userptr_fail_get_user_pages;
@@ -328,8 +330,10 @@ userptr_fail_get_user_pages:
if (!vma_is_io(buf-vma))
while (--num_pages_from_user = 0)
put_page(buf-pages[num_pages_from_user]);
+   down_read(current-mm-mmap_sem);
vb2_put_vma(buf-vma);
 userptr_fail_find_vma:
+   up_read(current-mm-mmap_sem);
kfree(buf-pages);
 userptr_fail_alloc_pages:
kfree(buf);
@@ -362,7 +366,9 @@ static void vb2_dma_sg_put_userptr(void *buf_priv)
put_page(buf-pages[i]);
}
kfree(buf-pages);
+   down_read(current-mm-mmap_sem);
vb2_put_vma(buf-vma);
+   up_read(current-mm-mmap_sem);
kfree(buf);
 }
 
diff --git a/drivers/media/v4l2-core

Re: [PATCH 2/9] mm: Provide new get_vaddr_frames() helper

2015-05-11 Thread Jan Kara
On Fri 08-05-15 15:49:22, Mel Gorman wrote:
 On Wed, May 06, 2015 at 09:28:09AM +0200, Jan Kara wrote:
  Provide new function get_vaddr_frames().  This function maps virtual
  addresses from given start and fills given array with page frame numbers of
  the corresponding pages. If given start belongs to a normal vma, the 
  function
  grabs reference to each of the pages to pin them in memory. If start
  belongs to VM_IO | VM_PFNMAP vma, we don't touch page structures. Caller
  must make sure pfns aren't reused for anything else while he is using
  them.
  
  This function is created for various drivers to simplify handling of
  their buffers.
  
  Signed-off-by: Jan Kara j...@suse.cz
 
 Trivial comments only;
...
  @@ -936,6 +937,219 @@ int __mm_populate(unsigned long start, unsigned long 
  len, int ignore_errors)
  return ret; /* 0 or negative error code */
   }
   
  +/*
  + * get_vaddr_frames() - map virtual addresses to pfns
  + * @start: starting user address
  + * @nr_frames: number of pages / pfns from start to map
  + * @write: whether pages will be written to by the caller
  + * @force: whether to force write access even if user mapping is
  + * readonly. This will result in the page being COWed even
  + * in MAP_SHARED mappings. You do not want this.
 
 If they don't want it, why does it exist?
  This was copied from get_user_pages(). The original comment changed in
the mean time so I've updated this one somewhat and referenced comment at
get_user_pages() for details.

  + * @vec:   structure which receives pages / pfns of the addresses mapped.
  + * It should have space for at least nr_frames entries.
  + *
  + * This function maps virtual addresses from @start and fills @vec 
  structure
  + * with page frame numbers or page pointers to corresponding pages (choice
  + * depends on the type of the vma underlying the virtual address). If 
  @start
  + * belongs to a normal vma, the function grabs reference to each of the 
  pages
  + * to pin them in memory. If @start belongs to VM_IO | VM_PFNMAP vma, we 
  don't
  + * touch page structures and the caller must make sure pfns aren't reused 
  for
  + * anything else while he is using them.
  + *
  + * The function returns number of pages mapped which may be less than
  + * @nr_frames. In particular we stop mapping if there are more vmas of
  + * different type underlying the specified range of virtual addresses.
  + *
  + * This function takes care of grabbing mmap_sem as necessary.
  + */
  +int get_vaddr_frames(unsigned long start, unsigned int nr_frames,
  +bool write, bool force, struct frame_vector *vec)
  +{
  +   struct mm_struct *mm = current-mm;
  +   struct vm_area_struct *vma;
  +   int ret = 0;
  +   int err;
  +   int locked = 1;
  +
 
 bool locked.
  It cannot be bool. It is passed to get_user_pages_locked() which expects
int *.

  +   if (nr_frames == 0)
  +   return 0;
  +
  +   if (WARN_ON_ONCE(nr_frames  vec-nr_allocated))
  +   nr_frames = vec-nr_allocated;
  +
  +   down_read(mm-mmap_sem);
  +   vma = find_vma_intersection(mm, start, start + 1);
  +   if (!vma) {
  +   ret = -EFAULT;
  +   goto out;
  +   }
  +   if (!(vma-vm_flags  (VM_IO | VM_PFNMAP))) {
  +   vec-got_ref = 1;
  +   vec-is_pfns = 0;
 
 They're bools and while correct, it looks weird. There are a few
 instances of this but I won't comment on it again.
  Thanks. Fixed.

  +   ret = get_user_pages_locked(current, mm, start, nr_frames,
  +   write, force, (struct page **)(vec-ptrs), locked);
  +   goto out;
  +   }
  +
  +   vec-got_ref = 0;
  +   vec-is_pfns = 1;
  +   do {
  +   unsigned long *nums = frame_vector_pfns(vec);
  +
  +   while (ret  nr_frames  start + PAGE_SIZE = vma-vm_end) {
  +   err = follow_pfn(vma, start, nums[ret]);
  +   if (err) {
  +   if (ret == 0)
  +   ret = err;
  +   goto out;
  +   }
  +   start += PAGE_SIZE;
  +   ret++;
  +   }
  +   /*
  +* We stop if we have enough pages or if VMA doesn't completely
  +* cover the tail page.
  +*/
  +   if (ret = nr_frames || start  vma-vm_end)
  +   break;
  +   vma = find_vma_intersection(mm, start, start + 1);
  +   } while (vma  vma-vm_flags  (VM_IO | VM_PFNMAP));
  +out:
  +   if (locked)
  +   up_read(mm-mmap_sem);
  +   if (!ret)
  +   ret = -EFAULT;
  +   if (ret  0)
  +   vec-nr_frames = ret;
  +   return ret;
  +}
  +EXPORT_SYMBOL(get_vaddr_frames);
  +
  +/**
  + * put_vaddr_frames() - drop references to pages if get_vaddr_frames() 
  acquired
  + * them
  + * @vec:   frame vector to put
  + *
  + * Drop references to pages if get_vaddr_frames() acquired

[PATCH 5/9] media: vb2: Convert vb2_dma_sg_get_userptr() to use frame vector

2015-05-06 Thread Jan Kara
Acked-by: Marek Szyprowski m.szyprow...@samsung.com
Tested-by: Marek Szyprowski m.szyprow...@samsung.com
Signed-off-by: Jan Kara j...@suse.cz
---
 drivers/media/v4l2-core/videobuf2-dma-sg.c | 97 +-
 1 file changed, 15 insertions(+), 82 deletions(-)

diff --git a/drivers/media/v4l2-core/videobuf2-dma-sg.c 
b/drivers/media/v4l2-core/videobuf2-dma-sg.c
index afd4b514affc..4ee1b3fbfe2a 100644
--- a/drivers/media/v4l2-core/videobuf2-dma-sg.c
+++ b/drivers/media/v4l2-core/videobuf2-dma-sg.c
@@ -38,6 +38,7 @@ struct vb2_dma_sg_buf {
struct device   *dev;
void*vaddr;
struct page **pages;
+   struct frame_vector *vec;
int offset;
enum dma_data_direction dma_dir;
struct sg_table sg_table;
@@ -51,7 +52,6 @@ struct vb2_dma_sg_buf {
unsigned intnum_pages;
atomic_trefcount;
struct vb2_vmarea_handler   handler;
-   struct vm_area_struct   *vma;
 
struct dma_buf_attachment   *db_attach;
 };
@@ -224,25 +224,17 @@ static void vb2_dma_sg_finish(void *buf_priv)
dma_sync_sg_for_cpu(buf-dev, sgt-sgl, sgt-nents, buf-dma_dir);
 }
 
-static inline int vma_is_io(struct vm_area_struct *vma)
-{
-   return !!(vma-vm_flags  (VM_IO | VM_PFNMAP));
-}
-
 static void *vb2_dma_sg_get_userptr(void *alloc_ctx, unsigned long vaddr,
unsigned long size,
enum dma_data_direction dma_dir)
 {
struct vb2_dma_sg_conf *conf = alloc_ctx;
struct vb2_dma_sg_buf *buf;
-   unsigned long first, last;
-   int num_pages_from_user;
-   struct vm_area_struct *vma;
struct sg_table *sgt;
DEFINE_DMA_ATTRS(attrs);
+   struct frame_vector *vec;
 
dma_set_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs);
-
buf = kzalloc(sizeof *buf, GFP_KERNEL);
if (!buf)
return NULL;
@@ -253,63 +245,19 @@ static void *vb2_dma_sg_get_userptr(void *alloc_ctx, 
unsigned long vaddr,
buf-offset = vaddr  ~PAGE_MASK;
buf-size = size;
buf-dma_sgt = buf-sg_table;
+   vec = vb2_create_framevec(vaddr, size, buf-dma_dir == DMA_FROM_DEVICE);
+   if (IS_ERR(vec))
+   goto userptr_fail_pfnvec;
+   buf-vec = vec;
 
-   first = (vaddrPAGE_MASK)  PAGE_SHIFT;
-   last  = ((vaddr + size - 1)  PAGE_MASK)  PAGE_SHIFT;
-   buf-num_pages = last - first + 1;
-
-   buf-pages = kzalloc(buf-num_pages * sizeof(struct page *),
-GFP_KERNEL);
-   if (!buf-pages)
-   goto userptr_fail_alloc_pages;
-
-   down_read(current-mm-mmap_sem);
-   vma = find_vma(current-mm, vaddr);
-   if (!vma) {
-   dprintk(1, no vma for address %lu\n, vaddr);
-   goto userptr_fail_find_vma;
-   }
-
-   if (vma-vm_end  vaddr + size) {
-   dprintk(1, vma at %lu is too small for %lu bytes\n,
-   vaddr, size);
-   goto userptr_fail_find_vma;
-   }
-
-   buf-vma = vb2_get_vma(vma);
-   if (!buf-vma) {
-   dprintk(1, failed to copy vma\n);
-   goto userptr_fail_find_vma;
-   }
-
-   if (vma_is_io(buf-vma)) {
-   for (num_pages_from_user = 0;
-num_pages_from_user  buf-num_pages;
-++num_pages_from_user, vaddr += PAGE_SIZE) {
-   unsigned long pfn;
-
-   if (follow_pfn(vma, vaddr, pfn)) {
-   dprintk(1, no page for address %lu\n, vaddr);
-   break;
-   }
-   buf-pages[num_pages_from_user] = pfn_to_page(pfn);
-   }
-   } else
-   num_pages_from_user = get_user_pages(current, current-mm,
-vaddr  PAGE_MASK,
-buf-num_pages,
-buf-dma_dir == DMA_FROM_DEVICE,
-1, /* force */
-buf-pages,
-NULL);
-   up_read(current-mm-mmap_sem);
-
-   if (num_pages_from_user != buf-num_pages)
-   goto userptr_fail_get_user_pages;
+   buf-pages = frame_vector_pages(vec);
+   if (IS_ERR(buf-pages))
+   goto userptr_fail_sgtable;
+   buf-num_pages = frame_vector_count(vec);
 
if (sg_alloc_table_from_pages(buf-dma_sgt, buf-pages,
buf-num_pages, buf-offset, size, 0))
-   goto userptr_fail_alloc_table_from_pages;
+   goto userptr_fail_sgtable;
 
sgt = buf-sg_table;
/*
@@ -323,19 +271,9

[PATCH 9/9] drm/exynos: Convert g2d_userptr_get_dma_addr() to use get_vaddr_frames()

2015-05-06 Thread Jan Kara
Convert g2d_userptr_get_dma_addr() to pin pages using get_vaddr_frames().
This removes the knowledge about vmas and mmap_sem locking from exynos
driver. Also it fixes a problem that the function has been mapping user
provided address without holding mmap_sem.

Signed-off-by: Jan Kara j...@suse.cz
---
 drivers/gpu/drm/exynos/exynos_drm_g2d.c | 89 ++
 drivers/gpu/drm/exynos/exynos_drm_gem.c | 97 -
 2 files changed, 29 insertions(+), 157 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c 
b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
index 81a250830808..265519c0fe2d 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
@@ -190,10 +190,8 @@ struct g2d_cmdlist_userptr {
dma_addr_t  dma_addr;
unsigned long   userptr;
unsigned long   size;
-   struct page **pages;
-   unsigned intnpages;
+   struct frame_vector *vec;
struct sg_table *sgt;
-   struct vm_area_struct   *vma;
atomic_trefcount;
boolin_pool;
boolout_of_list;
@@ -363,6 +361,7 @@ static void g2d_userptr_put_dma_addr(struct drm_device 
*drm_dev,
 {
struct g2d_cmdlist_userptr *g2d_userptr =
(struct g2d_cmdlist_userptr *)obj;
+   struct page **pages;
 
if (!obj)
return;
@@ -382,19 +381,21 @@ out:
exynos_gem_unmap_sgt_from_dma(drm_dev, g2d_userptr-sgt,
DMA_BIDIRECTIONAL);
 
-   exynos_gem_put_pages_to_userptr(g2d_userptr-pages,
-   g2d_userptr-npages,
-   g2d_userptr-vma);
+   pages = frame_vector_pages(g2d_userptr-vec);
+   if (!IS_ERR(pages)) {
+   int i;
 
-   exynos_gem_put_vma(g2d_userptr-vma);
+   for (i = 0; i  frame_vector_count(g2d_userptr-vec); i++)
+   set_page_dirty_lock(pages[i]);
+   }
+   put_vaddr_frames(g2d_userptr-vec);
+   frame_vector_destroy(g2d_userptr-vec);
 
if (!g2d_userptr-out_of_list)
list_del_init(g2d_userptr-list);
 
sg_free_table(g2d_userptr-sgt);
kfree(g2d_userptr-sgt);
-
-   drm_free_large(g2d_userptr-pages);
kfree(g2d_userptr);
 }
 
@@ -413,6 +414,7 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct 
drm_device *drm_dev,
struct vm_area_struct *vma;
unsigned long start, end;
unsigned int npages, offset;
+   struct frame_vector *vec;
int ret;
 
if (!size) {
@@ -456,65 +458,37 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct 
drm_device *drm_dev,
return ERR_PTR(-ENOMEM);
 
atomic_set(g2d_userptr-refcount, 1);
+   g2d_userptr-size = size;
 
start = userptr  PAGE_MASK;
offset = userptr  ~PAGE_MASK;
end = PAGE_ALIGN(userptr + size);
npages = (end - start)  PAGE_SHIFT;
-   g2d_userptr-npages = npages;
-
-   pages = drm_calloc_large(npages, sizeof(struct page *));
-   if (!pages) {
-   DRM_ERROR(failed to allocate pages.\n);
-   ret = -ENOMEM;
+   vec = g2d_userptr-vec = frame_vector_create(npages);
+   if (!vec)
goto err_free;
-   }
 
-   down_read(current-mm-mmap_sem);
-   vma = find_vma(current-mm, userptr);
-   if (!vma) {
-   up_read(current-mm-mmap_sem);
-   DRM_ERROR(failed to get vm region.\n);
+   ret = get_vaddr_frames(start, npages, 1, 1, vec);
+   if (ret != npages) {
+   DRM_ERROR(failed to get user pages from userptr.\n);
+   if (ret  0)
+   goto err_destroy_framevec;
ret = -EFAULT;
-   goto err_free_pages;
+   goto err_put_framevec;
}
-
-   if (vma-vm_end  userptr + size) {
-   up_read(current-mm-mmap_sem);
-   DRM_ERROR(vma is too small.\n);
+   if (frame_vector_to_pages(vec)  0) {
ret = -EFAULT;
-   goto err_free_pages;
+   goto err_put_framevec;
}
 
-   g2d_userptr-vma = exynos_gem_get_vma(vma);
-   if (!g2d_userptr-vma) {
-   up_read(current-mm-mmap_sem);
-   DRM_ERROR(failed to copy vma.\n);
-   ret = -ENOMEM;
-   goto err_free_pages;
-   }
-
-   g2d_userptr-size = size;
-
-   ret = exynos_gem_get_pages_from_userptr(start  PAGE_MASK,
-   npages, pages, vma);
-   if (ret  0) {
-   up_read(current-mm-mmap_sem);
-   DRM_ERROR(failed to get user pages from userptr.\n);
-   goto err_put_vma;
-   }
-
-   up_read(current-mm-mmap_sem);
-   g2d_userptr-pages

[PATCH 8/9] media: vb2: Remove unused functions

2015-05-06 Thread Jan Kara
Conversion to the use of pinned pfns made some functions unused. Remove
them. Also there's no need to lock mmap_sem in __buf_prepare() anymore.

Acked-by: Marek Szyprowski m.szyprow...@samsung.com
Tested-by: Marek Szyprowski m.szyprow...@samsung.com
Signed-off-by: Jan Kara j...@suse.cz
---
 drivers/media/v4l2-core/videobuf2-memops.c | 114 -
 include/media/videobuf2-memops.h   |   6 --
 2 files changed, 120 deletions(-)

diff --git a/drivers/media/v4l2-core/videobuf2-memops.c 
b/drivers/media/v4l2-core/videobuf2-memops.c
index 0ec186d41b9b..48c6a49c4928 100644
--- a/drivers/media/v4l2-core/videobuf2-memops.c
+++ b/drivers/media/v4l2-core/videobuf2-memops.c
@@ -23,120 +23,6 @@
 #include media/videobuf2-memops.h
 
 /**
- * vb2_get_vma() - acquire and lock the virtual memory area
- * @vma:   given virtual memory area
- *
- * This function attempts to acquire an area mapped in the userspace for
- * the duration of a hardware operation. The area is locked by performing
- * the same set of operation that are done when process calls fork() and
- * memory areas are duplicated.
- *
- * Returns a copy of a virtual memory region on success or NULL.
- */
-struct vm_area_struct *vb2_get_vma(struct vm_area_struct *vma)
-{
-   struct vm_area_struct *vma_copy;
-
-   vma_copy = kmalloc(sizeof(*vma_copy), GFP_KERNEL);
-   if (vma_copy == NULL)
-   return NULL;
-
-   if (vma-vm_ops  vma-vm_ops-open)
-   vma-vm_ops-open(vma);
-
-   if (vma-vm_file)
-   get_file(vma-vm_file);
-
-   memcpy(vma_copy, vma, sizeof(*vma));
-
-   vma_copy-vm_mm = NULL;
-   vma_copy-vm_next = NULL;
-   vma_copy-vm_prev = NULL;
-
-   return vma_copy;
-}
-EXPORT_SYMBOL_GPL(vb2_get_vma);
-
-/**
- * vb2_put_userptr() - release a userspace virtual memory area
- * @vma:   virtual memory region associated with the area to be released
- *
- * This function releases the previously acquired memory area after a hardware
- * operation.
- */
-void vb2_put_vma(struct vm_area_struct *vma)
-{
-   if (!vma)
-   return;
-
-   if (vma-vm_ops  vma-vm_ops-close)
-   vma-vm_ops-close(vma);
-
-   if (vma-vm_file)
-   fput(vma-vm_file);
-
-   kfree(vma);
-}
-EXPORT_SYMBOL_GPL(vb2_put_vma);
-
-/**
- * vb2_get_contig_userptr() - lock physically contiguous userspace mapped 
memory
- * @vaddr: starting virtual address of the area to be verified
- * @size:  size of the area
- * @res_paddr: will return physical address for the given vaddr
- * @res_vma:   will return locked copy of struct vm_area for the given area
- *
- * This function will go through memory area of size @size mapped at @vaddr and
- * verify that the underlying physical pages are contiguous. If they are
- * contiguous the virtual memory area is locked and a @res_vma is filled with
- * the copy and @res_pa set to the physical address of the buffer.
- *
- * Returns 0 on success.
- */
-int vb2_get_contig_userptr(unsigned long vaddr, unsigned long size,
-  struct vm_area_struct **res_vma, dma_addr_t *res_pa)
-{
-   struct mm_struct *mm = current-mm;
-   struct vm_area_struct *vma;
-   unsigned long offset, start, end;
-   unsigned long this_pfn, prev_pfn;
-   dma_addr_t pa = 0;
-
-   start = vaddr;
-   offset = start  ~PAGE_MASK;
-   end = start + size;
-
-   vma = find_vma(mm, start);
-
-   if (vma == NULL || vma-vm_end  end)
-   return -EFAULT;
-
-   for (prev_pfn = 0; start  end; start += PAGE_SIZE) {
-   int ret = follow_pfn(vma, start, this_pfn);
-   if (ret)
-   return ret;
-
-   if (prev_pfn == 0)
-   pa = this_pfn  PAGE_SHIFT;
-   else if (this_pfn != prev_pfn + 1)
-   return -EFAULT;
-
-   prev_pfn = this_pfn;
-   }
-
-   /*
-* Memory is contigous, lock vma and return to the caller
-*/
-   *res_vma = vb2_get_vma(vma);
-   if (*res_vma == NULL)
-   return -ENOMEM;
-
-   *res_pa = pa + offset;
-   return 0;
-}
-EXPORT_SYMBOL_GPL(vb2_get_contig_userptr);
-
-/**
  * vb2_create_framevec() - map virtual addresses to pfns
  * @start: Virtual user address where we start mapping
  * @length:Length of a range to map
diff --git a/include/media/videobuf2-memops.h b/include/media/videobuf2-memops.h
index 2f0564ff5f31..830b5239fd8b 100644
--- a/include/media/videobuf2-memops.h
+++ b/include/media/videobuf2-memops.h
@@ -31,12 +31,6 @@ struct vb2_vmarea_handler {
 
 extern const struct vm_operations_struct vb2_common_vm_ops;
 
-int vb2_get_contig_userptr(unsigned long vaddr, unsigned long size,
-  struct vm_area_struct **res_vma, dma_addr_t *res_pa);
-
-struct vm_area_struct *vb2_get_vma(struct vm_area_struct *vma);
-void vb2_put_vma(struct vm_area_struct *vma

[PATCH 6/9] media: vb2: Convert vb2_vmalloc_get_userptr() to use frame vector

2015-05-06 Thread Jan Kara
Convert vb2_vmalloc_get_userptr() to use frame vector infrastructure.
When we are doing that there's no need to allocate page array and some
code can be simplified.

Acked-by: Marek Szyprowski m.szyprow...@samsung.com
Tested-by: Marek Szyprowski m.szyprow...@samsung.com
Signed-off-by: Jan Kara j...@suse.cz
---
 drivers/media/v4l2-core/videobuf2-vmalloc.c | 94 +++--
 1 file changed, 36 insertions(+), 58 deletions(-)

diff --git a/drivers/media/v4l2-core/videobuf2-vmalloc.c 
b/drivers/media/v4l2-core/videobuf2-vmalloc.c
index 0ba40be21ebd..d2ce81fa2cdf 100644
--- a/drivers/media/v4l2-core/videobuf2-vmalloc.c
+++ b/drivers/media/v4l2-core/videobuf2-vmalloc.c
@@ -23,11 +23,9 @@
 
 struct vb2_vmalloc_buf {
void*vaddr;
-   struct page **pages;
-   struct vm_area_struct   *vma;
+   struct frame_vector *vec;
enum dma_data_direction dma_dir;
unsigned long   size;
-   unsigned intn_pages;
atomic_trefcount;
struct vb2_vmarea_handler   handler;
struct dma_buf  *dbuf;
@@ -76,10 +74,8 @@ static void *vb2_vmalloc_get_userptr(void *alloc_ctx, 
unsigned long vaddr,
 enum dma_data_direction dma_dir)
 {
struct vb2_vmalloc_buf *buf;
-   unsigned long first, last;
-   int n_pages, offset;
-   struct vm_area_struct *vma;
-   dma_addr_t physp;
+   struct frame_vector *vec;
+   int n_pages, offset, i;
 
buf = kzalloc(sizeof(*buf), GFP_KERNEL);
if (!buf)
@@ -88,53 +84,36 @@ static void *vb2_vmalloc_get_userptr(void *alloc_ctx, 
unsigned long vaddr,
buf-dma_dir = dma_dir;
offset = vaddr  ~PAGE_MASK;
buf-size = size;
-
-   down_read(current-mm-mmap_sem);
-   vma = find_vma(current-mm, vaddr);
-   if (vma  (vma-vm_flags  VM_PFNMAP)  (vma-vm_pgoff)) {
-   if (vb2_get_contig_userptr(vaddr, size, vma, physp))
-   goto fail_pages_array_alloc;
-   buf-vma = vma;
-   buf-vaddr = (__force void *)ioremap_nocache(physp, size);
-   if (!buf-vaddr)
-   goto fail_pages_array_alloc;
+   vec = vb2_create_framevec(vaddr, size, dma_dir == DMA_FROM_DEVICE);
+   if (IS_ERR(vec))
+   goto fail_pfnvec_create;
+   buf-vec = vec;
+   n_pages = frame_vector_count(vec);
+   if (frame_vector_to_pages(vec)  0) {
+   unsigned long *nums = frame_vector_pfns(vec);
+
+   /*
+* We cannot get page pointers for these pfns. Check memory is
+* physically contiguous and use direct mapping.
+*/
+   for (i = 1; i  n_pages; i++)
+   if (nums[i-1] + 1 != nums[i])
+   goto fail_map;
+   buf-vaddr = (__force void *)
+   ioremap_nocache(nums[0]  PAGE_SHIFT, size);
} else {
-   first = vaddr  PAGE_SHIFT;
-   last  = (vaddr + size - 1)  PAGE_SHIFT;
-   buf-n_pages = last - first + 1;
-   buf-pages = kzalloc(buf-n_pages * sizeof(struct page *),
-GFP_KERNEL);
-   if (!buf-pages)
-   goto fail_pages_array_alloc;
-
-   /* current-mm-mmap_sem is taken by videobuf2 core */
-   n_pages = get_user_pages(current, current-mm,
-vaddr  PAGE_MASK, buf-n_pages,
-dma_dir == DMA_FROM_DEVICE,
-1, /* force */
-buf-pages, NULL);
-   if (n_pages != buf-n_pages)
-   goto fail_get_user_pages;
-
-   buf-vaddr = vm_map_ram(buf-pages, buf-n_pages, -1,
+   buf-vaddr = vm_map_ram(frame_vector_pages(vec), n_pages, -1,
PAGE_KERNEL);
-   if (!buf-vaddr)
-   goto fail_get_user_pages;
}
-   up_read(current-mm-mmap_sem);
 
+   if (!buf-vaddr)
+   goto fail_map;
buf-vaddr += offset;
return buf;
 
-fail_get_user_pages:
-   pr_debug(get_user_pages requested/got: %d/%d]\n, n_pages,
-buf-n_pages);
-   while (--n_pages = 0)
-   put_page(buf-pages[n_pages]);
-   kfree(buf-pages);
-
-fail_pages_array_alloc:
-   up_read(current-mm-mmap_sem);
+fail_map:
+   vb2_destroy_framevec(vec);
+fail_pfnvec_create:
kfree(buf);
 
return NULL;
@@ -145,22 +124,21 @@ static void vb2_vmalloc_put_userptr(void *buf_priv)
struct vb2_vmalloc_buf *buf = buf_priv;
unsigned long vaddr = (unsigned long)buf-vaddr  PAGE_MASK;
unsigned int i

[PATCH 1/9] [media] vb2: Push mmap_sem down to memops

2015-05-06 Thread Jan Kara
Currently vb2 core acquires mmap_sem just around call to
__qbuf_userptr(). However since commit f035eb4e976ef5 (videobuf2: fix
lockdep warning) it isn't necessary to acquire it so early as we no
longer have to drop queue mutex before acquiring mmap_sem. So push
acquisition of mmap_sem down into .get_userptr and .put_userptr memops
so that the semaphore is acquired for a shorter time and it is clearer
what it is needed for.

Signed-off-by: Jan Kara j...@suse.cz
---
 drivers/media/v4l2-core/videobuf2-core.c   | 2 --
 drivers/media/v4l2-core/videobuf2-dma-contig.c | 7 +++
 drivers/media/v4l2-core/videobuf2-dma-sg.c | 6 ++
 drivers/media/v4l2-core/videobuf2-vmalloc.c| 6 +-
 4 files changed, 18 insertions(+), 3 deletions(-)

diff --git a/drivers/media/v4l2-core/videobuf2-core.c 
b/drivers/media/v4l2-core/videobuf2-core.c
index 66ada01c796c..20cdbc0900ea 100644
--- a/drivers/media/v4l2-core/videobuf2-core.c
+++ b/drivers/media/v4l2-core/videobuf2-core.c
@@ -1657,9 +1657,7 @@ static int __buf_prepare(struct vb2_buffer *vb, const 
struct v4l2_buffer *b)
ret = __qbuf_mmap(vb, b);
break;
case V4L2_MEMORY_USERPTR:
-   down_read(current-mm-mmap_sem);
ret = __qbuf_userptr(vb, b);
-   up_read(current-mm-mmap_sem);
break;
case V4L2_MEMORY_DMABUF:
ret = __qbuf_dmabuf(vb, b);
diff --git a/drivers/media/v4l2-core/videobuf2-dma-contig.c 
b/drivers/media/v4l2-core/videobuf2-dma-contig.c
index 644dec73d220..620c4aa78881 100644
--- a/drivers/media/v4l2-core/videobuf2-dma-contig.c
+++ b/drivers/media/v4l2-core/videobuf2-dma-contig.c
@@ -532,7 +532,9 @@ static void vb2_dc_put_userptr(void *buf_priv)
sg_free_table(sgt);
kfree(sgt);
}
+   down_read(current-mm-mmap_sem);
vb2_put_vma(buf-vma);
+   up_read(current-mm-mmap_sem);
kfree(buf);
 }
 
@@ -616,6 +618,7 @@ static void *vb2_dc_get_userptr(void *alloc_ctx, unsigned 
long vaddr,
goto fail_buf;
}
 
+   down_read(current-mm-mmap_sem);
/* current-mm-mmap_sem is taken by videobuf2 core */
vma = find_vma(current-mm, vaddr);
if (!vma) {
@@ -642,6 +645,7 @@ static void *vb2_dc_get_userptr(void *alloc_ctx, unsigned 
long vaddr,
if (ret) {
unsigned long pfn;
if (vb2_dc_get_user_pfn(start, n_pages, vma, pfn) == 0) {
+   up_read(current-mm-mmap_sem);
buf-dma_addr = vb2_dc_pfn_to_dma(buf-dev, pfn);
buf-size = size;
kfree(pages);
@@ -651,6 +655,7 @@ static void *vb2_dc_get_userptr(void *alloc_ctx, unsigned 
long vaddr,
pr_err(failed to get user pages\n);
goto fail_vma;
}
+   up_read(current-mm-mmap_sem);
 
sgt = kzalloc(sizeof(*sgt), GFP_KERNEL);
if (!sgt) {
@@ -713,10 +718,12 @@ fail_get_user_pages:
while (n_pages)
put_page(pages[--n_pages]);
 
+   down_read(current-mm-mmap_sem);
 fail_vma:
vb2_put_vma(buf-vma);
 
 fail_pages:
+   up_read(current-mm-mmap_sem);
kfree(pages); /* kfree is NULL-proof */
 
 fail_buf:
diff --git a/drivers/media/v4l2-core/videobuf2-dma-sg.c 
b/drivers/media/v4l2-core/videobuf2-dma-sg.c
index 45c708e463b9..afd4b514affc 100644
--- a/drivers/media/v4l2-core/videobuf2-dma-sg.c
+++ b/drivers/media/v4l2-core/videobuf2-dma-sg.c
@@ -263,6 +263,7 @@ static void *vb2_dma_sg_get_userptr(void *alloc_ctx, 
unsigned long vaddr,
if (!buf-pages)
goto userptr_fail_alloc_pages;
 
+   down_read(current-mm-mmap_sem);
vma = find_vma(current-mm, vaddr);
if (!vma) {
dprintk(1, no vma for address %lu\n, vaddr);
@@ -301,6 +302,7 @@ static void *vb2_dma_sg_get_userptr(void *alloc_ctx, 
unsigned long vaddr,
 1, /* force */
 buf-pages,
 NULL);
+   up_read(current-mm-mmap_sem);
 
if (num_pages_from_user != buf-num_pages)
goto userptr_fail_get_user_pages;
@@ -328,8 +330,10 @@ userptr_fail_get_user_pages:
if (!vma_is_io(buf-vma))
while (--num_pages_from_user = 0)
put_page(buf-pages[num_pages_from_user]);
+   down_read(current-mm-mmap_sem);
vb2_put_vma(buf-vma);
 userptr_fail_find_vma:
+   up_read(current-mm-mmap_sem);
kfree(buf-pages);
 userptr_fail_alloc_pages:
kfree(buf);
@@ -362,7 +366,9 @@ static void vb2_dma_sg_put_userptr(void *buf_priv)
put_page(buf-pages[i]);
}
kfree(buf-pages);
+   down_read(current-mm-mmap_sem);
vb2_put_vma(buf-vma);
+   up_read(current-mm-mmap_sem);
kfree(buf);
 }
 
diff --git a/drivers/media/v4l2-core

[PATCH 3/9] media: omap_vout: Convert omap_vout_uservirt_to_phys() to use get_vaddr_pfns()

2015-05-06 Thread Jan Kara
Convert omap_vout_uservirt_to_phys() to use get_vaddr_pfns() instead of
hand made mapping of virtual address to physical address. Also the
function leaked page reference from get_user_pages() so fix that by
properly release the reference when omap_vout_buffer_release() is
called.

Signed-off-by: Jan Kara j...@suse.cz
---
 drivers/media/platform/omap/omap_vout.c | 67 +++--
 1 file changed, 31 insertions(+), 36 deletions(-)

diff --git a/drivers/media/platform/omap/omap_vout.c 
b/drivers/media/platform/omap/omap_vout.c
index 17b189a81ec5..d3f6d82ccbc1 100644
--- a/drivers/media/platform/omap/omap_vout.c
+++ b/drivers/media/platform/omap/omap_vout.c
@@ -195,46 +195,34 @@ static int omap_vout_try_format(struct v4l2_pix_format 
*pix)
 }
 
 /*
- * omap_vout_uservirt_to_phys: This inline function is used to convert user
- * space virtual address to physical address.
+ * omap_vout_get_userptr: Convert user space virtual address to physical
+ * address.
  */
-static unsigned long omap_vout_uservirt_to_phys(unsigned long virtp)
+static int omap_vout_get_userptr(struct videobuf_buffer *vb, u32 virtp,
+u32 *physp)
 {
-   unsigned long physp = 0;
-   struct vm_area_struct *vma;
-   struct mm_struct *mm = current-mm;
+   struct frame_vector *vec;
+   int ret;
 
/* For kernel direct-mapped memory, take the easy way */
-   if (virtp = PAGE_OFFSET)
-   return virt_to_phys((void *) virtp);
-
-   down_read(current-mm-mmap_sem);
-   vma = find_vma(mm, virtp);
-   if (vma  (vma-vm_flags  VM_IO)  vma-vm_pgoff) {
-   /* this will catch, kernel-allocated, mmaped-to-usermode
-  addresses */
-   physp = (vma-vm_pgoff  PAGE_SHIFT) + (virtp - vma-vm_start);
-   up_read(current-mm-mmap_sem);
-   } else {
-   /* otherwise, use get_user_pages() for general userland pages */
-   int res, nr_pages = 1;
-   struct page *pages;
+   if (virtp = PAGE_OFFSET) {
+   *physp = virt_to_phys((void *)virtp);
+   return 0;
+   }
 
-   res = get_user_pages(current, current-mm, virtp, nr_pages, 1,
-   0, pages, NULL);
-   up_read(current-mm-mmap_sem);
+   vec = frame_vector_create(1);
+   if (!vec)
+   return -ENOMEM;
 
-   if (res == nr_pages) {
-   physp =  __pa(page_address(pages[0]) +
-   (virtp  ~PAGE_MASK));
-   } else {
-   printk(KERN_WARNING VOUT_NAME
-   get_user_pages failed\n);
-   return 0;
-   }
+   ret = get_vaddr_frames(virtp, 1, 1, 0, vec);
+   if (ret != 1) {
+   frame_vector_destroy(vec);
+   return -EINVAL;
}
+   *physp = __pfn_to_phys(frame_vector_pfns(vec)[0]);
+   vb-priv = vec;
 
-   return physp;
+   return 0;
 }
 
 /*
@@ -788,11 +776,15 @@ static int omap_vout_buffer_prepare(struct videobuf_queue 
*q,
 * address of the buffer
 */
if (V4L2_MEMORY_USERPTR == vb-memory) {
+   int ret;
+
if (0 == vb-baddr)
return -EINVAL;
/* Physical address */
-   vout-queued_buf_addr[vb-i] = (u8 *)
-   omap_vout_uservirt_to_phys(vb-baddr);
+   ret = omap_vout_get_userptr(vb, vb-baddr,
+   (u32 *)vout-queued_buf_addr[vb-i]);
+   if (ret  0)
+   return ret;
} else {
unsigned long addr, dma_addr;
unsigned long size;
@@ -841,9 +833,12 @@ static void omap_vout_buffer_release(struct videobuf_queue 
*q,
struct omap_vout_device *vout = q-priv_data;
 
vb-state = VIDEOBUF_NEEDS_INIT;
+   if (vb-memory == V4L2_MEMORY_USERPTR  vb-priv) {
+   struct frame_vector *vec = vb-priv;
 
-   if (V4L2_MEMORY_MMAP != vout-memory)
-   return;
+   put_vaddr_frames(vec);
+   frame_vector_destroy(vec);
+   }
 }
 
 /*
-- 
2.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-media in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 4/9] vb2: Provide helpers for mapping virtual addresses

2015-05-06 Thread Jan Kara
Provide simple helper functions to map virtual address range into an
array of pfns / pages.

Acked-by: Marek Szyprowski m.szyprow...@samsung.com
Tested-by: Marek Szyprowski m.szyprow...@samsung.com
Signed-off-by: Jan Kara j...@suse.cz
---
 drivers/media/v4l2-core/videobuf2-memops.c | 58 ++
 include/media/videobuf2-memops.h   |  5 +++
 2 files changed, 63 insertions(+)

diff --git a/drivers/media/v4l2-core/videobuf2-memops.c 
b/drivers/media/v4l2-core/videobuf2-memops.c
index 81c1ad8b2cf1..0ec186d41b9b 100644
--- a/drivers/media/v4l2-core/videobuf2-memops.c
+++ b/drivers/media/v4l2-core/videobuf2-memops.c
@@ -137,6 +137,64 @@ int vb2_get_contig_userptr(unsigned long vaddr, unsigned 
long size,
 EXPORT_SYMBOL_GPL(vb2_get_contig_userptr);
 
 /**
+ * vb2_create_framevec() - map virtual addresses to pfns
+ * @start: Virtual user address where we start mapping
+ * @length:Length of a range to map
+ * @write: Should we map for writing into the area
+ *
+ * This function allocates and fills in a vector with pfns corresponding to
+ * virtual address range passed in arguments. If pfns have corresponding pages,
+ * page references are also grabbed to pin pages in memory. The function
+ * returns pointer to the vector on success and error pointer in case of
+ * failure. Returned vector needs to be freed via vb2_destroy_pfnvec().
+ */
+struct frame_vector *vb2_create_framevec(unsigned long start,
+unsigned long length,
+bool write)
+{
+   int ret;
+   unsigned long first, last;
+   unsigned long nr;
+   struct frame_vector *vec;
+
+   first = start  PAGE_SHIFT;
+   last = (start + length - 1)  PAGE_SHIFT;
+   nr = last - first + 1;
+   vec = frame_vector_create(nr);
+   if (!vec)
+   return ERR_PTR(-ENOMEM);
+   ret = get_vaddr_frames(start, nr, write, 1, vec);
+   if (ret  0)
+   goto out_destroy;
+   /* We accept only complete set of PFNs */
+   if (ret != nr) {
+   ret = -EFAULT;
+   goto out_release;
+   }
+   return vec;
+out_release:
+   put_vaddr_frames(vec);
+out_destroy:
+   frame_vector_destroy(vec);
+   return ERR_PTR(ret);
+}
+EXPORT_SYMBOL(vb2_create_framevec);
+
+/**
+ * vb2_destroy_framevec() - release vector of mapped pfns
+ * @vec:   vector of pfns / pages to release
+ *
+ * This releases references to all pages in the vector @vec (if corresponding
+ * pfns are backed by pages) and frees the passed vector.
+ */
+void vb2_destroy_framevec(struct frame_vector *vec)
+{
+   put_vaddr_frames(vec);
+   frame_vector_destroy(vec);
+}
+EXPORT_SYMBOL(vb2_destroy_framevec);
+
+/**
  * vb2_common_vm_open() - increase refcount of the vma
  * @vma:   virtual memory region for the mapping
  *
diff --git a/include/media/videobuf2-memops.h b/include/media/videobuf2-memops.h
index f05444ca8c0c..2f0564ff5f31 100644
--- a/include/media/videobuf2-memops.h
+++ b/include/media/videobuf2-memops.h
@@ -15,6 +15,7 @@
 #define _MEDIA_VIDEOBUF2_MEMOPS_H
 
 #include media/videobuf2-core.h
+#include linux/mm.h
 
 /**
  * vb2_vmarea_handler - common vma refcount tracking handler
@@ -36,5 +37,9 @@ int vb2_get_contig_userptr(unsigned long vaddr, unsigned long 
size,
 struct vm_area_struct *vb2_get_vma(struct vm_area_struct *vma);
 void vb2_put_vma(struct vm_area_struct *vma);
 
+struct frame_vector *vb2_create_framevec(unsigned long start,
+unsigned long length,
+bool write);
+void vb2_destroy_framevec(struct frame_vector *vec);
 
 #endif
-- 
2.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-media in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 0/9 v4] Helper to abstract vma handling in media layer

2015-05-06 Thread Jan Kara
  Hello,

  Sorry for a quick resend but the missing vmalloc include in mm/gup.c is
annoying for archs that need it and I was also told to extend CC list a bit.

I'm sending the fourth version of my patch series to abstract vma handling
from the various media drivers. After this patch set drivers have to know much
less details about vmas, their types, and locking. Also quite some code is
removed from them. As a bonus drivers get automatically VM_FAULT_RETRY
handling. The primary motivation for this series is to remove knowledge about
mmap_sem locking from as many places a possible so that we can change it with
reasonable effort.

The core of the series is the new helper get_vaddr_frames() which is given a
virtual address and it fills in PFNs / struct page pointers (depending on VMA
type) into the provided array. If PFNs correspond to normal pages it also grabs
references to these pages. The difference from get_user_pages() is that this
function can also deal with pfnmap, and io mappings which is what the media
drivers need.

I have tested the patches with vivid driver so at least vb2 code got some
exposure. Conversion of other drivers was just compile-tested (for x86 so e.g.
exynos driver which is only for Samsung platform is completely untested) so I'd
like to ask respective maintainers if they could have a look.  Also I'd like to
ask mm folks to check patch 2/9 implementing the helper. Thanks!

Honza
Changes since v3:
* Added include linux/vmalloc.h into mm/gup.c as it's needed for some archs
* Fixed error path for exynos driver

Changes since v2:
* Renamed functions and structures as Mel suggested
* Other minor changes suggested by Mel
* Rebased on top of 4.1-rc2
* Changed functions to get pointer to array of pages / pfns to perform
  conversion if necessary. This fixes possible issue in the omap I may have
  introduced in v2 and generally makes the API less errorprone.
--
To unsubscribe from this list: send the line unsubscribe linux-media in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 7/9] media: vb2: Convert vb2_dc_get_userptr() to use frame vector

2015-05-06 Thread Jan Kara
Convert vb2_dc_get_userptr() to use frame vector infrastructure. When we
are doing that there's no need to allocate page array and some code can
be simplified.

Acked-by: Marek Szyprowski m.szyprow...@samsung.com
Tested-by: Marek Szyprowski m.szyprow...@samsung.com
Signed-off-by: Jan Kara j...@suse.cz
---
 drivers/media/v4l2-core/videobuf2-dma-contig.c | 214 -
 1 file changed, 34 insertions(+), 180 deletions(-)

diff --git a/drivers/media/v4l2-core/videobuf2-dma-contig.c 
b/drivers/media/v4l2-core/videobuf2-dma-contig.c
index 620c4aa78881..e6cea452302b 100644
--- a/drivers/media/v4l2-core/videobuf2-dma-contig.c
+++ b/drivers/media/v4l2-core/videobuf2-dma-contig.c
@@ -32,15 +32,13 @@ struct vb2_dc_buf {
dma_addr_t  dma_addr;
enum dma_data_direction dma_dir;
struct sg_table *dma_sgt;
+   struct frame_vector *vec;
 
/* MMAP related */
struct vb2_vmarea_handler   handler;
atomic_trefcount;
struct sg_table *sgt_base;
 
-   /* USERPTR related */
-   struct vm_area_struct   *vma;
-
/* DMABUF related */
struct dma_buf_attachment   *db_attach;
 };
@@ -49,24 +47,6 @@ struct vb2_dc_buf {
 /*scatterlist table functions*/
 /*/
 
-
-static void vb2_dc_sgt_foreach_page(struct sg_table *sgt,
-   void (*cb)(struct page *pg))
-{
-   struct scatterlist *s;
-   unsigned int i;
-
-   for_each_sg(sgt-sgl, s, sgt-orig_nents, i) {
-   struct page *page = sg_page(s);
-   unsigned int n_pages = PAGE_ALIGN(s-offset + s-length)
-PAGE_SHIFT;
-   unsigned int j;
-
-   for (j = 0; j  n_pages; ++j, ++page)
-   cb(page);
-   }
-}
-
 static unsigned long vb2_dc_get_contiguous_size(struct sg_table *sgt)
 {
struct scatterlist *s;
@@ -429,92 +409,12 @@ static struct dma_buf *vb2_dc_get_dmabuf(void *buf_priv, 
unsigned long flags)
 /*   callbacks for USERPTR buffers   */
 /*/
 
-static inline int vma_is_io(struct vm_area_struct *vma)
-{
-   return !!(vma-vm_flags  (VM_IO | VM_PFNMAP));
-}
-
-static int vb2_dc_get_user_pfn(unsigned long start, int n_pages,
-   struct vm_area_struct *vma, unsigned long *res)
-{
-   unsigned long pfn, start_pfn, prev_pfn;
-   unsigned int i;
-   int ret;
-
-   if (!vma_is_io(vma))
-   return -EFAULT;
-
-   ret = follow_pfn(vma, start, pfn);
-   if (ret)
-   return ret;
-
-   start_pfn = pfn;
-   start += PAGE_SIZE;
-
-   for (i = 1; i  n_pages; ++i, start += PAGE_SIZE) {
-   prev_pfn = pfn;
-   ret = follow_pfn(vma, start, pfn);
-
-   if (ret) {
-   pr_err(no page for address %lu\n, start);
-   return ret;
-   }
-   if (pfn != prev_pfn + 1)
-   return -EINVAL;
-   }
-
-   *res = start_pfn;
-   return 0;
-}
-
-static int vb2_dc_get_user_pages(unsigned long start, struct page **pages,
-   int n_pages, struct vm_area_struct *vma,
-   enum dma_data_direction dma_dir)
-{
-   if (vma_is_io(vma)) {
-   unsigned int i;
-
-   for (i = 0; i  n_pages; ++i, start += PAGE_SIZE) {
-   unsigned long pfn;
-   int ret = follow_pfn(vma, start, pfn);
-
-   if (!pfn_valid(pfn))
-   return -EINVAL;
-
-   if (ret) {
-   pr_err(no page for address %lu\n, start);
-   return ret;
-   }
-   pages[i] = pfn_to_page(pfn);
-   }
-   } else {
-   int n;
-
-   n = get_user_pages(current, current-mm, start  PAGE_MASK,
-   n_pages, dma_dir == DMA_FROM_DEVICE, 1, pages, NULL);
-   /* negative error means that no page was pinned */
-   n = max(n, 0);
-   if (n != n_pages) {
-   pr_err(got only %d of %d user pages\n, n, n_pages);
-   while (n)
-   put_page(pages[--n]);
-   return -EFAULT;
-   }
-   }
-
-   return 0;
-}
-
-static void vb2_dc_put_dirty_page(struct page *page)
-{
-   set_page_dirty_lock(page);
-   put_page(page);
-}
-
 static void vb2_dc_put_userptr(void *buf_priv)
 {
struct vb2_dc_buf *buf = buf_priv;
struct sg_table *sgt = buf-dma_sgt;
+   int i;
+   struct page **pages;
 
if (sgt) {
DEFINE_DMA_ATTRS(attrs);
@@ -526,15 +426,15 @@ static void vb2_dc_put_userptr(void *buf_priv

[PATCH 2/9] mm: Provide new get_vaddr_frames() helper

2015-05-06 Thread Jan Kara
Provide new function get_vaddr_frames().  This function maps virtual
addresses from given start and fills given array with page frame numbers of
the corresponding pages. If given start belongs to a normal vma, the function
grabs reference to each of the pages to pin them in memory. If start
belongs to VM_IO | VM_PFNMAP vma, we don't touch page structures. Caller
must make sure pfns aren't reused for anything else while he is using
them.

This function is created for various drivers to simplify handling of
their buffers.

Signed-off-by: Jan Kara j...@suse.cz
---
 include/linux/mm.h |  44 +++
 mm/gup.c   | 214 +
 2 files changed, 258 insertions(+)

diff --git a/include/linux/mm.h b/include/linux/mm.h
index 0755b9fd03a7..dcd1f02a78e9 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -20,6 +20,7 @@
 #include linux/shrinker.h
 #include linux/resource.h
 #include linux/page_ext.h
+#include linux/err.h
 
 struct mempolicy;
 struct anon_vma;
@@ -1197,6 +1198,49 @@ long get_user_pages_unlocked(struct task_struct *tsk, 
struct mm_struct *mm,
int write, int force, struct page **pages);
 int get_user_pages_fast(unsigned long start, int nr_pages, int write,
struct page **pages);
+
+/* Container for pinned pfns / pages */
+struct frame_vector {
+   unsigned int nr_allocated;  /* Number of frames we have space for */
+   unsigned int nr_frames; /* Number of frames stored in ptrs array */
+   bool got_ref;   /* Did we pin pages by getting page ref? */
+   bool is_pfns;   /* Does array contain pages or pfns? */
+   void *ptrs[0];  /* Array of pinned pfns / pages. Use
+* pfns_vector_pages() or pfns_vector_pfns()
+* for access */
+};
+
+struct frame_vector *frame_vector_create(unsigned int nr_frames);
+void frame_vector_destroy(struct frame_vector *vec);
+int get_vaddr_frames(unsigned long start, unsigned int nr_pfns,
+bool write, bool force, struct frame_vector *vec);
+void put_vaddr_frames(struct frame_vector *vec);
+int frame_vector_to_pages(struct frame_vector *vec);
+void frame_vector_to_pfns(struct frame_vector *vec);
+
+static inline unsigned int frame_vector_count(struct frame_vector *vec)
+{
+   return vec-nr_frames;
+}
+
+static inline struct page **frame_vector_pages(struct frame_vector *vec)
+{
+   if (vec-is_pfns) {
+   int err = frame_vector_to_pages(vec);
+
+   if (err)
+   return ERR_PTR(err);
+   }
+   return (struct page **)(vec-ptrs);
+}
+
+static inline unsigned long *frame_vector_pfns(struct frame_vector *vec)
+{
+   if (!vec-is_pfns)
+   frame_vector_to_pfns(vec);
+   return (unsigned long *)(vec-ptrs);
+}
+
 struct kvec;
 int get_kernel_pages(const struct kvec *iov, int nr_pages, int write,
struct page **pages);
diff --git a/mm/gup.c b/mm/gup.c
index 6297f6bccfb1..8db5c40e65c4 100644
--- a/mm/gup.c
+++ b/mm/gup.c
@@ -8,6 +8,7 @@
 #include linux/rmap.h
 #include linux/swap.h
 #include linux/swapops.h
+#include linux/vmalloc.h
 
 #include linux/sched.h
 #include linux/rwsem.h
@@ -936,6 +937,219 @@ int __mm_populate(unsigned long start, unsigned long len, 
int ignore_errors)
return ret; /* 0 or negative error code */
 }
 
+/*
+ * get_vaddr_frames() - map virtual addresses to pfns
+ * @start: starting user address
+ * @nr_frames: number of pages / pfns from start to map
+ * @write: whether pages will be written to by the caller
+ * @force: whether to force write access even if user mapping is
+ * readonly. This will result in the page being COWed even
+ * in MAP_SHARED mappings. You do not want this.
+ * @vec:   structure which receives pages / pfns of the addresses mapped.
+ * It should have space for at least nr_frames entries.
+ *
+ * This function maps virtual addresses from @start and fills @vec structure
+ * with page frame numbers or page pointers to corresponding pages (choice
+ * depends on the type of the vma underlying the virtual address). If @start
+ * belongs to a normal vma, the function grabs reference to each of the pages
+ * to pin them in memory. If @start belongs to VM_IO | VM_PFNMAP vma, we don't
+ * touch page structures and the caller must make sure pfns aren't reused for
+ * anything else while he is using them.
+ *
+ * The function returns number of pages mapped which may be less than
+ * @nr_frames. In particular we stop mapping if there are more vmas of
+ * different type underlying the specified range of virtual addresses.
+ *
+ * This function takes care of grabbing mmap_sem as necessary.
+ */
+int get_vaddr_frames(unsigned long start, unsigned int nr_frames,
+bool write, bool force, struct frame_vector *vec)
+{
+   struct mm_struct *mm

Re: [PATCH 9/9] drm/exynos: Convert g2d_userptr_get_dma_addr() to use get_vaddr_frames()

2015-05-06 Thread Jan Kara
On Wed 06-05-15 12:47:35, Vlastimil Babka wrote:
 On 05/06/2015 09:28 AM, Jan Kara wrote:
 Convert g2d_userptr_get_dma_addr() to pin pages using get_vaddr_frames().
 This removes the knowledge about vmas and mmap_sem locking from exynos
 driver. Also it fixes a problem that the function has been mapping user
 provided address without holding mmap_sem.
 
 Signed-off-by: Jan Kara j...@suse.cz
 ---
   drivers/gpu/drm/exynos/exynos_drm_g2d.c | 89 ++
   drivers/gpu/drm/exynos/exynos_drm_gem.c | 97 
  -
   2 files changed, 29 insertions(+), 157 deletions(-)
 
 diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c 
 b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
 index 81a250830808..265519c0fe2d 100644
 --- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c
 +++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
 ...
 @@ -456,65 +458,37 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct 
 drm_device *drm_dev,
  return ERR_PTR(-ENOMEM);
 
  atomic_set(g2d_userptr-refcount, 1);
 +g2d_userptr-size = size;
 
  start = userptr  PAGE_MASK;
  offset = userptr  ~PAGE_MASK;
  end = PAGE_ALIGN(userptr + size);
  npages = (end - start)  PAGE_SHIFT;
 -g2d_userptr-npages = npages;
 -
 -pages = drm_calloc_large(npages, sizeof(struct page *));
 -if (!pages) {
 -DRM_ERROR(failed to allocate pages.\n);
 -ret = -ENOMEM;
 +vec = g2d_userptr-vec = frame_vector_create(npages);
 +if (!vec)
  goto err_free;
 -}
 
 -down_read(current-mm-mmap_sem);
 -vma = find_vma(current-mm, userptr);
 -if (!vma) {
 -up_read(current-mm-mmap_sem);
 -DRM_ERROR(failed to get vm region.\n);
 +ret = get_vaddr_frames(start, npages, 1, 1, vec);
 
 Use true instead of 1.
  Yes, thanks!

Honza
-- 
Jan Kara j...@suse.cz
SUSE Labs, CR
--
To unsubscribe from this list: send the line unsubscribe linux-media in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 2/9] mm: Provide new get_vaddr_frames() helper

2015-05-06 Thread Jan Kara
On Wed 06-05-15 12:45:51, Vlastimil Babka wrote:
 On 05/06/2015 09:28 AM, Jan Kara wrote:
 Provide new function get_vaddr_frames().  This function maps virtual
 addresses from given start and fills given array with page frame numbers of
 the corresponding pages. If given start belongs to a normal vma, the function
 grabs reference to each of the pages to pin them in memory. If start
 belongs to VM_IO | VM_PFNMAP vma, we don't touch page structures. Caller
 must make sure pfns aren't reused for anything else while he is using
 them.
 
 This function is created for various drivers to simplify handling of
 their buffers.
 
 Signed-off-by: Jan Kara j...@suse.cz
 
 Acked-by: Vlastimil Babka vba...@suse.cz
 
 With some nitpicks below...
 
 ---
   include/linux/mm.h |  44 +++
   mm/gup.c   | 214 
  +
   2 files changed, 258 insertions(+)
 
 diff --git a/include/linux/mm.h b/include/linux/mm.h
 index 0755b9fd03a7..dcd1f02a78e9 100644
 --- a/include/linux/mm.h
 +++ b/include/linux/mm.h
 @@ -20,6 +20,7 @@
   #include linux/shrinker.h
   #include linux/resource.h
   #include linux/page_ext.h
 +#include linux/err.h
 
   struct mempolicy;
   struct anon_vma;
 @@ -1197,6 +1198,49 @@ long get_user_pages_unlocked(struct task_struct *tsk, 
 struct mm_struct *mm,
  int write, int force, struct page **pages);
   int get_user_pages_fast(unsigned long start, int nr_pages, int write,
  struct page **pages);
 +
 +/* Container for pinned pfns / pages */
 +struct frame_vector {
 +unsigned int nr_allocated;  /* Number of frames we have space for */
 +unsigned int nr_frames; /* Number of frames stored in ptrs array */
 +bool got_ref;   /* Did we pin pages by getting page ref? */
 +bool is_pfns;   /* Does array contain pages or pfns? */
 +void *ptrs[0];  /* Array of pinned pfns / pages. Use
 + * pfns_vector_pages() or pfns_vector_pfns()
 + * for access */
 +};
 +
 +struct frame_vector *frame_vector_create(unsigned int nr_frames);
 +void frame_vector_destroy(struct frame_vector *vec);
 +int get_vaddr_frames(unsigned long start, unsigned int nr_pfns,
 + bool write, bool force, struct frame_vector *vec);
 +void put_vaddr_frames(struct frame_vector *vec);
 +int frame_vector_to_pages(struct frame_vector *vec);
 +void frame_vector_to_pfns(struct frame_vector *vec);
 +
 +static inline unsigned int frame_vector_count(struct frame_vector *vec)
 +{
 +return vec-nr_frames;
 +}
 +
 +static inline struct page **frame_vector_pages(struct frame_vector *vec)
 +{
 +if (vec-is_pfns) {
 +int err = frame_vector_to_pages(vec);
 +
 +if (err)
 +return ERR_PTR(err);
 +}
 +return (struct page **)(vec-ptrs);
 +}
 +
 +static inline unsigned long *frame_vector_pfns(struct frame_vector *vec)
 +{
 +if (!vec-is_pfns)
 +frame_vector_to_pfns(vec);
 +return (unsigned long *)(vec-ptrs);
 +}
 +
   struct kvec;
   int get_kernel_pages(const struct kvec *iov, int nr_pages, int write,
  struct page **pages);
 diff --git a/mm/gup.c b/mm/gup.c
 index 6297f6bccfb1..8db5c40e65c4 100644
 --- a/mm/gup.c
 +++ b/mm/gup.c
 @@ -8,6 +8,7 @@
   #include linux/rmap.h
   #include linux/swap.h
   #include linux/swapops.h
 +#include linux/vmalloc.h
 
   #include linux/sched.h
   #include linux/rwsem.h
 @@ -936,6 +937,219 @@ int __mm_populate(unsigned long start, unsigned long 
 len, int ignore_errors)
  return ret; /* 0 or negative error code */
   }
 
 +/*
 + * get_vaddr_frames() - map virtual addresses to pfns
 + * @start:  starting user address
 + * @nr_frames:  number of pages / pfns from start to map
 + * @write:  whether pages will be written to by the caller
 + * @force:  whether to force write access even if user mapping is
 + *  readonly. This will result in the page being COWed even
 + *  in MAP_SHARED mappings. You do not want this.
 
 You do not want this and yet some of the drivers in later patches
 do. That looks weird. Explain better?
  That was copied from get_user_pages() comment but that got changed in the
mean time. I've referenced that instead of copying it.

 + * @vec:structure which receives pages / pfns of the addresses mapped.
 + *  It should have space for at least nr_frames entries.
 + *
 + * This function maps virtual addresses from @start and fills @vec structure
 + * with page frame numbers or page pointers to corresponding pages (choice
 + * depends on the type of the vma underlying the virtual address). If @start
 + * belongs to a normal vma, the function grabs reference to each of the 
 pages
 + * to pin them in memory. If @start belongs to VM_IO | VM_PFNMAP vma, we 
 don't
 + * touch page structures and the caller must make sure pfns aren't reused 
 for
 + * anything else while he is using them

Re: [PATCH 3/9] media: omap_vout: Convert omap_vout_uservirt_to_phys() to use get_vaddr_pfns()

2015-05-06 Thread Jan Kara
On Wed 06-05-15 12:46:42, Vlastimil Babka wrote:
 On 05/06/2015 09:28 AM, Jan Kara wrote:
 Convert omap_vout_uservirt_to_phys() to use get_vaddr_pfns() instead of
 hand made mapping of virtual address to physical address. Also the
 function leaked page reference from get_user_pages() so fix that by
 properly release the reference when omap_vout_buffer_release() is
 called.
 
 Signed-off-by: Jan Kara j...@suse.cz
 ---
   drivers/media/platform/omap/omap_vout.c | 67 
  +++--
   1 file changed, 31 insertions(+), 36 deletions(-)
 
 
 ...
 
 +vec = frame_vector_create(1);
 +if (!vec)
 +return -ENOMEM;
 
 -if (res == nr_pages) {
 -physp =  __pa(page_address(pages[0]) +
 -(virtp  ~PAGE_MASK));
 -} else {
 -printk(KERN_WARNING VOUT_NAME
 -get_user_pages failed\n);
 -return 0;
 -}
 +ret = get_vaddr_frames(virtp, 1, 1, 0, vec);
 
 Use true/false where appropriate.
  Right. Thanks.

Honza
-- 
Jan Kara j...@suse.cz
SUSE Labs, CR
--
To unsubscribe from this list: send the line unsubscribe linux-media in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 9/9] drm/exynos: Convert g2d_userptr_get_dma_addr() to use get_vaddr_frames()

2015-05-05 Thread Jan Kara
Convert g2d_userptr_get_dma_addr() to pin pages using get_vaddr_frames().
This removes the knowledge about vmas and mmap_sem locking from exynos
driver. Also it fixes a problem that the function has been mapping user
provided address without holding mmap_sem.

Signed-off-by: Jan Kara j...@suse.cz
---
 drivers/gpu/drm/exynos/exynos_drm_g2d.c | 91 ++-
 drivers/gpu/drm/exynos/exynos_drm_gem.c | 97 -
 2 files changed, 30 insertions(+), 158 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c 
b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
index 81a250830808..65eb38797fd3 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
@@ -190,10 +190,8 @@ struct g2d_cmdlist_userptr {
dma_addr_t  dma_addr;
unsigned long   userptr;
unsigned long   size;
-   struct page **pages;
-   unsigned intnpages;
+   struct frame_vector *vec;
struct sg_table *sgt;
-   struct vm_area_struct   *vma;
atomic_trefcount;
boolin_pool;
boolout_of_list;
@@ -363,6 +361,7 @@ static void g2d_userptr_put_dma_addr(struct drm_device 
*drm_dev,
 {
struct g2d_cmdlist_userptr *g2d_userptr =
(struct g2d_cmdlist_userptr *)obj;
+   struct page **pages;
 
if (!obj)
return;
@@ -382,19 +381,21 @@ out:
exynos_gem_unmap_sgt_from_dma(drm_dev, g2d_userptr-sgt,
DMA_BIDIRECTIONAL);
 
-   exynos_gem_put_pages_to_userptr(g2d_userptr-pages,
-   g2d_userptr-npages,
-   g2d_userptr-vma);
+   pages = frame_vector_pages(g2d_userptr-vec);
+   if (!IS_ERR(pages)) {
+   int i;
 
-   exynos_gem_put_vma(g2d_userptr-vma);
+   for (i = 0; i  frame_vector_count(g2d_userptr-vec); i++)
+   set_page_dirty_lock(pages[i]);
+   }
+   put_vaddr_frames(g2d_userptr-vec);
+   frame_vector_destroy(g2d_userptr-vec);
 
if (!g2d_userptr-out_of_list)
list_del_init(g2d_userptr-list);
 
sg_free_table(g2d_userptr-sgt);
kfree(g2d_userptr-sgt);
-
-   drm_free_large(g2d_userptr-pages);
kfree(g2d_userptr);
 }
 
@@ -413,6 +414,7 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct 
drm_device *drm_dev,
struct vm_area_struct *vma;
unsigned long start, end;
unsigned int npages, offset;
+   struct frame_vector *vec;
int ret;
 
if (!size) {
@@ -456,65 +458,37 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct 
drm_device *drm_dev,
return ERR_PTR(-ENOMEM);
 
atomic_set(g2d_userptr-refcount, 1);
+   g2d_userptr-size = size;
 
start = userptr  PAGE_MASK;
offset = userptr  ~PAGE_MASK;
end = PAGE_ALIGN(userptr + size);
npages = (end - start)  PAGE_SHIFT;
-   g2d_userptr-npages = npages;
+   vec = g2d_userptr-vec = frame_vector_create(npages);
+   if (!vec)
+   goto out_free;
 
-   pages = drm_calloc_large(npages, sizeof(struct page *));
-   if (!pages) {
-   DRM_ERROR(failed to allocate pages.\n);
-   ret = -ENOMEM;
-   goto err_free;
-   }
-
-   down_read(current-mm-mmap_sem);
-   vma = find_vma(current-mm, userptr);
-   if (!vma) {
-   up_read(current-mm-mmap_sem);
-   DRM_ERROR(failed to get vm region.\n);
+   ret = get_vaddr_frames(start, npages, 1, 1, vec);
+   if (ret != npages) {
+   DRM_ERROR(failed to get user pages from userptr.\n);
+   if (ret  0)
+   goto err_destroy_framevec;
ret = -EFAULT;
-   goto err_free_pages;
+   goto err_put_framevec;
}
-
-   if (vma-vm_end  userptr + size) {
-   up_read(current-mm-mmap_sem);
-   DRM_ERROR(vma is too small.\n);
+   if (frame_vector_to_pages(vec)  0) {
ret = -EFAULT;
-   goto err_free_pages;
+   goto err_put_framevec;
}
 
-   g2d_userptr-vma = exynos_gem_get_vma(vma);
-   if (!g2d_userptr-vma) {
-   up_read(current-mm-mmap_sem);
-   DRM_ERROR(failed to copy vma.\n);
-   ret = -ENOMEM;
-   goto err_free_pages;
-   }
-
-   g2d_userptr-size = size;
-
-   ret = exynos_gem_get_pages_from_userptr(start  PAGE_MASK,
-   npages, pages, vma);
-   if (ret  0) {
-   up_read(current-mm-mmap_sem);
-   DRM_ERROR(failed to get user pages from userptr.\n);
-   goto err_put_vma;
-   }
-
-   up_read(current-mm

[PATCH 8/9] media: vb2: Remove unused functions

2015-05-05 Thread Jan Kara
Conversion to the use of pinned pfns made some functions unused. Remove
them. Also there's no need to lock mmap_sem in __buf_prepare() anymore.

Acked-by: Marek Szyprowski m.szyprow...@samsung.com
Tested-by: Marek Szyprowski m.szyprow...@samsung.com
Signed-off-by: Jan Kara j...@suse.cz
---
 drivers/media/v4l2-core/videobuf2-memops.c | 114 -
 include/media/videobuf2-memops.h   |   6 --
 2 files changed, 120 deletions(-)

diff --git a/drivers/media/v4l2-core/videobuf2-memops.c 
b/drivers/media/v4l2-core/videobuf2-memops.c
index 0ec186d41b9b..48c6a49c4928 100644
--- a/drivers/media/v4l2-core/videobuf2-memops.c
+++ b/drivers/media/v4l2-core/videobuf2-memops.c
@@ -23,120 +23,6 @@
 #include media/videobuf2-memops.h
 
 /**
- * vb2_get_vma() - acquire and lock the virtual memory area
- * @vma:   given virtual memory area
- *
- * This function attempts to acquire an area mapped in the userspace for
- * the duration of a hardware operation. The area is locked by performing
- * the same set of operation that are done when process calls fork() and
- * memory areas are duplicated.
- *
- * Returns a copy of a virtual memory region on success or NULL.
- */
-struct vm_area_struct *vb2_get_vma(struct vm_area_struct *vma)
-{
-   struct vm_area_struct *vma_copy;
-
-   vma_copy = kmalloc(sizeof(*vma_copy), GFP_KERNEL);
-   if (vma_copy == NULL)
-   return NULL;
-
-   if (vma-vm_ops  vma-vm_ops-open)
-   vma-vm_ops-open(vma);
-
-   if (vma-vm_file)
-   get_file(vma-vm_file);
-
-   memcpy(vma_copy, vma, sizeof(*vma));
-
-   vma_copy-vm_mm = NULL;
-   vma_copy-vm_next = NULL;
-   vma_copy-vm_prev = NULL;
-
-   return vma_copy;
-}
-EXPORT_SYMBOL_GPL(vb2_get_vma);
-
-/**
- * vb2_put_userptr() - release a userspace virtual memory area
- * @vma:   virtual memory region associated with the area to be released
- *
- * This function releases the previously acquired memory area after a hardware
- * operation.
- */
-void vb2_put_vma(struct vm_area_struct *vma)
-{
-   if (!vma)
-   return;
-
-   if (vma-vm_ops  vma-vm_ops-close)
-   vma-vm_ops-close(vma);
-
-   if (vma-vm_file)
-   fput(vma-vm_file);
-
-   kfree(vma);
-}
-EXPORT_SYMBOL_GPL(vb2_put_vma);
-
-/**
- * vb2_get_contig_userptr() - lock physically contiguous userspace mapped 
memory
- * @vaddr: starting virtual address of the area to be verified
- * @size:  size of the area
- * @res_paddr: will return physical address for the given vaddr
- * @res_vma:   will return locked copy of struct vm_area for the given area
- *
- * This function will go through memory area of size @size mapped at @vaddr and
- * verify that the underlying physical pages are contiguous. If they are
- * contiguous the virtual memory area is locked and a @res_vma is filled with
- * the copy and @res_pa set to the physical address of the buffer.
- *
- * Returns 0 on success.
- */
-int vb2_get_contig_userptr(unsigned long vaddr, unsigned long size,
-  struct vm_area_struct **res_vma, dma_addr_t *res_pa)
-{
-   struct mm_struct *mm = current-mm;
-   struct vm_area_struct *vma;
-   unsigned long offset, start, end;
-   unsigned long this_pfn, prev_pfn;
-   dma_addr_t pa = 0;
-
-   start = vaddr;
-   offset = start  ~PAGE_MASK;
-   end = start + size;
-
-   vma = find_vma(mm, start);
-
-   if (vma == NULL || vma-vm_end  end)
-   return -EFAULT;
-
-   for (prev_pfn = 0; start  end; start += PAGE_SIZE) {
-   int ret = follow_pfn(vma, start, this_pfn);
-   if (ret)
-   return ret;
-
-   if (prev_pfn == 0)
-   pa = this_pfn  PAGE_SHIFT;
-   else if (this_pfn != prev_pfn + 1)
-   return -EFAULT;
-
-   prev_pfn = this_pfn;
-   }
-
-   /*
-* Memory is contigous, lock vma and return to the caller
-*/
-   *res_vma = vb2_get_vma(vma);
-   if (*res_vma == NULL)
-   return -ENOMEM;
-
-   *res_pa = pa + offset;
-   return 0;
-}
-EXPORT_SYMBOL_GPL(vb2_get_contig_userptr);
-
-/**
  * vb2_create_framevec() - map virtual addresses to pfns
  * @start: Virtual user address where we start mapping
  * @length:Length of a range to map
diff --git a/include/media/videobuf2-memops.h b/include/media/videobuf2-memops.h
index 2f0564ff5f31..830b5239fd8b 100644
--- a/include/media/videobuf2-memops.h
+++ b/include/media/videobuf2-memops.h
@@ -31,12 +31,6 @@ struct vb2_vmarea_handler {
 
 extern const struct vm_operations_struct vb2_common_vm_ops;
 
-int vb2_get_contig_userptr(unsigned long vaddr, unsigned long size,
-  struct vm_area_struct **res_vma, dma_addr_t *res_pa);
-
-struct vm_area_struct *vb2_get_vma(struct vm_area_struct *vma);
-void vb2_put_vma(struct vm_area_struct *vma

[PATCH 2/9] mm: Provide new get_vaddr_frames() helper

2015-05-05 Thread Jan Kara
Provide new function get_vaddr_frames().  This function maps virtual
addresses from given start and fills given array with page frame numbers of
the corresponding pages. If given start belongs to a normal vma, the function
grabs reference to each of the pages to pin them in memory. If start
belongs to VM_IO | VM_PFNMAP vma, we don't touch page structures. Caller
must make sure pfns aren't reused for anything else while he is using
them.

This function is created for various drivers to simplify handling of
their buffers.

Signed-off-by: Jan Kara j...@suse.cz
---
 include/linux/mm.h |  44 +++
 mm/gup.c   | 213 +
 2 files changed, 257 insertions(+)

diff --git a/include/linux/mm.h b/include/linux/mm.h
index 0755b9fd03a7..dcd1f02a78e9 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -20,6 +20,7 @@
 #include linux/shrinker.h
 #include linux/resource.h
 #include linux/page_ext.h
+#include linux/err.h
 
 struct mempolicy;
 struct anon_vma;
@@ -1197,6 +1198,49 @@ long get_user_pages_unlocked(struct task_struct *tsk, 
struct mm_struct *mm,
int write, int force, struct page **pages);
 int get_user_pages_fast(unsigned long start, int nr_pages, int write,
struct page **pages);
+
+/* Container for pinned pfns / pages */
+struct frame_vector {
+   unsigned int nr_allocated;  /* Number of frames we have space for */
+   unsigned int nr_frames; /* Number of frames stored in ptrs array */
+   bool got_ref;   /* Did we pin pages by getting page ref? */
+   bool is_pfns;   /* Does array contain pages or pfns? */
+   void *ptrs[0];  /* Array of pinned pfns / pages. Use
+* pfns_vector_pages() or pfns_vector_pfns()
+* for access */
+};
+
+struct frame_vector *frame_vector_create(unsigned int nr_frames);
+void frame_vector_destroy(struct frame_vector *vec);
+int get_vaddr_frames(unsigned long start, unsigned int nr_pfns,
+bool write, bool force, struct frame_vector *vec);
+void put_vaddr_frames(struct frame_vector *vec);
+int frame_vector_to_pages(struct frame_vector *vec);
+void frame_vector_to_pfns(struct frame_vector *vec);
+
+static inline unsigned int frame_vector_count(struct frame_vector *vec)
+{
+   return vec-nr_frames;
+}
+
+static inline struct page **frame_vector_pages(struct frame_vector *vec)
+{
+   if (vec-is_pfns) {
+   int err = frame_vector_to_pages(vec);
+
+   if (err)
+   return ERR_PTR(err);
+   }
+   return (struct page **)(vec-ptrs);
+}
+
+static inline unsigned long *frame_vector_pfns(struct frame_vector *vec)
+{
+   if (!vec-is_pfns)
+   frame_vector_to_pfns(vec);
+   return (unsigned long *)(vec-ptrs);
+}
+
 struct kvec;
 int get_kernel_pages(const struct kvec *iov, int nr_pages, int write,
struct page **pages);
diff --git a/mm/gup.c b/mm/gup.c
index 6297f6bccfb1..e99ff3e7f142 100644
--- a/mm/gup.c
+++ b/mm/gup.c
@@ -936,6 +936,219 @@ int __mm_populate(unsigned long start, unsigned long len, 
int ignore_errors)
return ret; /* 0 or negative error code */
 }
 
+/*
+ * get_vaddr_frames() - map virtual addresses to pfns
+ * @start: starting user address
+ * @nr_frames: number of pages / pfns from start to map
+ * @write: whether pages will be written to by the caller
+ * @force: whether to force write access even if user mapping is
+ * readonly. This will result in the page being COWed even
+ * in MAP_SHARED mappings. You do not want this.
+ * @vec:   structure which receives pages / pfns of the addresses mapped.
+ * It should have space for at least nr_frames entries.
+ *
+ * This function maps virtual addresses from @start and fills @vec structure
+ * with page frame numbers or page pointers to corresponding pages (choice
+ * depends on the type of the vma underlying the virtual address). If @start
+ * belongs to a normal vma, the function grabs reference to each of the pages
+ * to pin them in memory. If @start belongs to VM_IO | VM_PFNMAP vma, we don't
+ * touch page structures and the caller must make sure pfns aren't reused for
+ * anything else while he is using them.
+ *
+ * The function returns number of pages mapped which may be less than
+ * @nr_frames. In particular we stop mapping if there are more vmas of
+ * different type underlying the specified range of virtual addresses.
+ *
+ * This function takes care of grabbing mmap_sem as necessary.
+ */
+int get_vaddr_frames(unsigned long start, unsigned int nr_frames,
+bool write, bool force, struct frame_vector *vec)
+{
+   struct mm_struct *mm = current-mm;
+   struct vm_area_struct *vma;
+   int ret = 0;
+   int err;
+   int locked = 1;
+
+   if (nr_frames == 0)
+   return 0

[PATCH 6/9] media: vb2: Convert vb2_vmalloc_get_userptr() to use frame vector

2015-05-05 Thread Jan Kara
Convert vb2_vmalloc_get_userptr() to use frame vector infrastructure.
When we are doing that there's no need to allocate page array and some
code can be simplified.

Acked-by: Marek Szyprowski m.szyprow...@samsung.com
Tested-by: Marek Szyprowski m.szyprow...@samsung.com
Signed-off-by: Jan Kara j...@suse.cz
---
 drivers/media/v4l2-core/videobuf2-vmalloc.c | 94 +++--
 1 file changed, 36 insertions(+), 58 deletions(-)

diff --git a/drivers/media/v4l2-core/videobuf2-vmalloc.c 
b/drivers/media/v4l2-core/videobuf2-vmalloc.c
index 0ba40be21ebd..d2ce81fa2cdf 100644
--- a/drivers/media/v4l2-core/videobuf2-vmalloc.c
+++ b/drivers/media/v4l2-core/videobuf2-vmalloc.c
@@ -23,11 +23,9 @@
 
 struct vb2_vmalloc_buf {
void*vaddr;
-   struct page **pages;
-   struct vm_area_struct   *vma;
+   struct frame_vector *vec;
enum dma_data_direction dma_dir;
unsigned long   size;
-   unsigned intn_pages;
atomic_trefcount;
struct vb2_vmarea_handler   handler;
struct dma_buf  *dbuf;
@@ -76,10 +74,8 @@ static void *vb2_vmalloc_get_userptr(void *alloc_ctx, 
unsigned long vaddr,
 enum dma_data_direction dma_dir)
 {
struct vb2_vmalloc_buf *buf;
-   unsigned long first, last;
-   int n_pages, offset;
-   struct vm_area_struct *vma;
-   dma_addr_t physp;
+   struct frame_vector *vec;
+   int n_pages, offset, i;
 
buf = kzalloc(sizeof(*buf), GFP_KERNEL);
if (!buf)
@@ -88,53 +84,36 @@ static void *vb2_vmalloc_get_userptr(void *alloc_ctx, 
unsigned long vaddr,
buf-dma_dir = dma_dir;
offset = vaddr  ~PAGE_MASK;
buf-size = size;
-
-   down_read(current-mm-mmap_sem);
-   vma = find_vma(current-mm, vaddr);
-   if (vma  (vma-vm_flags  VM_PFNMAP)  (vma-vm_pgoff)) {
-   if (vb2_get_contig_userptr(vaddr, size, vma, physp))
-   goto fail_pages_array_alloc;
-   buf-vma = vma;
-   buf-vaddr = (__force void *)ioremap_nocache(physp, size);
-   if (!buf-vaddr)
-   goto fail_pages_array_alloc;
+   vec = vb2_create_framevec(vaddr, size, dma_dir == DMA_FROM_DEVICE);
+   if (IS_ERR(vec))
+   goto fail_pfnvec_create;
+   buf-vec = vec;
+   n_pages = frame_vector_count(vec);
+   if (frame_vector_to_pages(vec)  0) {
+   unsigned long *nums = frame_vector_pfns(vec);
+
+   /*
+* We cannot get page pointers for these pfns. Check memory is
+* physically contiguous and use direct mapping.
+*/
+   for (i = 1; i  n_pages; i++)
+   if (nums[i-1] + 1 != nums[i])
+   goto fail_map;
+   buf-vaddr = (__force void *)
+   ioremap_nocache(nums[0]  PAGE_SHIFT, size);
} else {
-   first = vaddr  PAGE_SHIFT;
-   last  = (vaddr + size - 1)  PAGE_SHIFT;
-   buf-n_pages = last - first + 1;
-   buf-pages = kzalloc(buf-n_pages * sizeof(struct page *),
-GFP_KERNEL);
-   if (!buf-pages)
-   goto fail_pages_array_alloc;
-
-   /* current-mm-mmap_sem is taken by videobuf2 core */
-   n_pages = get_user_pages(current, current-mm,
-vaddr  PAGE_MASK, buf-n_pages,
-dma_dir == DMA_FROM_DEVICE,
-1, /* force */
-buf-pages, NULL);
-   if (n_pages != buf-n_pages)
-   goto fail_get_user_pages;
-
-   buf-vaddr = vm_map_ram(buf-pages, buf-n_pages, -1,
+   buf-vaddr = vm_map_ram(frame_vector_pages(vec), n_pages, -1,
PAGE_KERNEL);
-   if (!buf-vaddr)
-   goto fail_get_user_pages;
}
-   up_read(current-mm-mmap_sem);
 
+   if (!buf-vaddr)
+   goto fail_map;
buf-vaddr += offset;
return buf;
 
-fail_get_user_pages:
-   pr_debug(get_user_pages requested/got: %d/%d]\n, n_pages,
-buf-n_pages);
-   while (--n_pages = 0)
-   put_page(buf-pages[n_pages]);
-   kfree(buf-pages);
-
-fail_pages_array_alloc:
-   up_read(current-mm-mmap_sem);
+fail_map:
+   vb2_destroy_framevec(vec);
+fail_pfnvec_create:
kfree(buf);
 
return NULL;
@@ -145,22 +124,21 @@ static void vb2_vmalloc_put_userptr(void *buf_priv)
struct vb2_vmalloc_buf *buf = buf_priv;
unsigned long vaddr = (unsigned long)buf-vaddr  PAGE_MASK;
unsigned int i

[PATCH 1/9] [media] vb2: Push mmap_sem down to memops

2015-05-05 Thread Jan Kara
Currently vb2 core acquires mmap_sem just around call to
__qbuf_userptr(). However since commit f035eb4e976ef5 (videobuf2: fix
lockdep warning) it isn't necessary to acquire it so early as we no
longer have to drop queue mutex before acquiring mmap_sem. So push
acquisition of mmap_sem down into .get_userptr and .put_userptr memops
so that the semaphore is acquired for a shorter time and it is clearer
what it is needed for.

Signed-off-by: Jan Kara j...@suse.cz
---
 drivers/media/v4l2-core/videobuf2-core.c   | 2 --
 drivers/media/v4l2-core/videobuf2-dma-contig.c | 7 +++
 drivers/media/v4l2-core/videobuf2-dma-sg.c | 6 ++
 drivers/media/v4l2-core/videobuf2-vmalloc.c| 6 +-
 4 files changed, 18 insertions(+), 3 deletions(-)

diff --git a/drivers/media/v4l2-core/videobuf2-core.c 
b/drivers/media/v4l2-core/videobuf2-core.c
index 66ada01c796c..20cdbc0900ea 100644
--- a/drivers/media/v4l2-core/videobuf2-core.c
+++ b/drivers/media/v4l2-core/videobuf2-core.c
@@ -1657,9 +1657,7 @@ static int __buf_prepare(struct vb2_buffer *vb, const 
struct v4l2_buffer *b)
ret = __qbuf_mmap(vb, b);
break;
case V4L2_MEMORY_USERPTR:
-   down_read(current-mm-mmap_sem);
ret = __qbuf_userptr(vb, b);
-   up_read(current-mm-mmap_sem);
break;
case V4L2_MEMORY_DMABUF:
ret = __qbuf_dmabuf(vb, b);
diff --git a/drivers/media/v4l2-core/videobuf2-dma-contig.c 
b/drivers/media/v4l2-core/videobuf2-dma-contig.c
index 644dec73d220..620c4aa78881 100644
--- a/drivers/media/v4l2-core/videobuf2-dma-contig.c
+++ b/drivers/media/v4l2-core/videobuf2-dma-contig.c
@@ -532,7 +532,9 @@ static void vb2_dc_put_userptr(void *buf_priv)
sg_free_table(sgt);
kfree(sgt);
}
+   down_read(current-mm-mmap_sem);
vb2_put_vma(buf-vma);
+   up_read(current-mm-mmap_sem);
kfree(buf);
 }
 
@@ -616,6 +618,7 @@ static void *vb2_dc_get_userptr(void *alloc_ctx, unsigned 
long vaddr,
goto fail_buf;
}
 
+   down_read(current-mm-mmap_sem);
/* current-mm-mmap_sem is taken by videobuf2 core */
vma = find_vma(current-mm, vaddr);
if (!vma) {
@@ -642,6 +645,7 @@ static void *vb2_dc_get_userptr(void *alloc_ctx, unsigned 
long vaddr,
if (ret) {
unsigned long pfn;
if (vb2_dc_get_user_pfn(start, n_pages, vma, pfn) == 0) {
+   up_read(current-mm-mmap_sem);
buf-dma_addr = vb2_dc_pfn_to_dma(buf-dev, pfn);
buf-size = size;
kfree(pages);
@@ -651,6 +655,7 @@ static void *vb2_dc_get_userptr(void *alloc_ctx, unsigned 
long vaddr,
pr_err(failed to get user pages\n);
goto fail_vma;
}
+   up_read(current-mm-mmap_sem);
 
sgt = kzalloc(sizeof(*sgt), GFP_KERNEL);
if (!sgt) {
@@ -713,10 +718,12 @@ fail_get_user_pages:
while (n_pages)
put_page(pages[--n_pages]);
 
+   down_read(current-mm-mmap_sem);
 fail_vma:
vb2_put_vma(buf-vma);
 
 fail_pages:
+   up_read(current-mm-mmap_sem);
kfree(pages); /* kfree is NULL-proof */
 
 fail_buf:
diff --git a/drivers/media/v4l2-core/videobuf2-dma-sg.c 
b/drivers/media/v4l2-core/videobuf2-dma-sg.c
index 45c708e463b9..afd4b514affc 100644
--- a/drivers/media/v4l2-core/videobuf2-dma-sg.c
+++ b/drivers/media/v4l2-core/videobuf2-dma-sg.c
@@ -263,6 +263,7 @@ static void *vb2_dma_sg_get_userptr(void *alloc_ctx, 
unsigned long vaddr,
if (!buf-pages)
goto userptr_fail_alloc_pages;
 
+   down_read(current-mm-mmap_sem);
vma = find_vma(current-mm, vaddr);
if (!vma) {
dprintk(1, no vma for address %lu\n, vaddr);
@@ -301,6 +302,7 @@ static void *vb2_dma_sg_get_userptr(void *alloc_ctx, 
unsigned long vaddr,
 1, /* force */
 buf-pages,
 NULL);
+   up_read(current-mm-mmap_sem);
 
if (num_pages_from_user != buf-num_pages)
goto userptr_fail_get_user_pages;
@@ -328,8 +330,10 @@ userptr_fail_get_user_pages:
if (!vma_is_io(buf-vma))
while (--num_pages_from_user = 0)
put_page(buf-pages[num_pages_from_user]);
+   down_read(current-mm-mmap_sem);
vb2_put_vma(buf-vma);
 userptr_fail_find_vma:
+   up_read(current-mm-mmap_sem);
kfree(buf-pages);
 userptr_fail_alloc_pages:
kfree(buf);
@@ -362,7 +366,9 @@ static void vb2_dma_sg_put_userptr(void *buf_priv)
put_page(buf-pages[i]);
}
kfree(buf-pages);
+   down_read(current-mm-mmap_sem);
vb2_put_vma(buf-vma);
+   up_read(current-mm-mmap_sem);
kfree(buf);
 }
 
diff --git a/drivers/media/v4l2-core

[PATCH 0/9 v3] Helper to abstract vma handling in media layer

2015-05-05 Thread Jan Kara
  Hello,

  I'm sending the third version of my patch series to abstract vma handling
from the various media drivers. After this patch set drivers have to know much
less details about vmas, their types, and locking. Also quite some code is
removed from them. As a bonus drivers get automatically VM_FAULT_RETRY
handling. The primary motivation for this series is to remove knowledge about
mmap_sem locking from as many places a possible so that we can change it with
reasonable effort.

The core of the series is the new helper get_vaddr_frames() which is given a
virtual address and it fills in PFNs / struct page pointers (depending on VMA
type) into the provided array. If PFNs correspond to normal pages it also grabs
references to these pages. The difference from get_user_pages() is that this
function can also deal with pfnmap, and io mappings which is what the media
drivers need.

I have tested the patches with vivid driver so at least vb2 code got some
exposure. Conversion of other drivers was just compile-tested so I'd like to
ask respective maintainers if they could have a look.  Also I'd like to ask mm
folks to check patch 2/9 implementing the helper. Thanks!

Honza

Changes since v2:
* Renamed functions and structures as Mel suggested
* Other minor changes suggested by Mel
* Rebased on top of 4.1-rc2
* Changed functions to get pointer to array of pages / pfns to perform
  conversion if necessary. This fixes possible issue in the omap I may have
  introduced in v2 and generally makes the API less errorprone.
--
To unsubscribe from this list: send the line unsubscribe linux-media in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 3/9] media: omap_vout: Convert omap_vout_uservirt_to_phys() to use get_vaddr_pfns()

2015-05-05 Thread Jan Kara
Convert omap_vout_uservirt_to_phys() to use get_vaddr_pfns() instead of
hand made mapping of virtual address to physical address. Also the
function leaked page reference from get_user_pages() so fix that by
properly release the reference when omap_vout_buffer_release() is
called.

Signed-off-by: Jan Kara j...@suse.cz
---
 drivers/media/platform/omap/omap_vout.c | 67 +++--
 1 file changed, 31 insertions(+), 36 deletions(-)

diff --git a/drivers/media/platform/omap/omap_vout.c 
b/drivers/media/platform/omap/omap_vout.c
index 17b189a81ec5..d3f6d82ccbc1 100644
--- a/drivers/media/platform/omap/omap_vout.c
+++ b/drivers/media/platform/omap/omap_vout.c
@@ -195,46 +195,34 @@ static int omap_vout_try_format(struct v4l2_pix_format 
*pix)
 }
 
 /*
- * omap_vout_uservirt_to_phys: This inline function is used to convert user
- * space virtual address to physical address.
+ * omap_vout_get_userptr: Convert user space virtual address to physical
+ * address.
  */
-static unsigned long omap_vout_uservirt_to_phys(unsigned long virtp)
+static int omap_vout_get_userptr(struct videobuf_buffer *vb, u32 virtp,
+u32 *physp)
 {
-   unsigned long physp = 0;
-   struct vm_area_struct *vma;
-   struct mm_struct *mm = current-mm;
+   struct frame_vector *vec;
+   int ret;
 
/* For kernel direct-mapped memory, take the easy way */
-   if (virtp = PAGE_OFFSET)
-   return virt_to_phys((void *) virtp);
-
-   down_read(current-mm-mmap_sem);
-   vma = find_vma(mm, virtp);
-   if (vma  (vma-vm_flags  VM_IO)  vma-vm_pgoff) {
-   /* this will catch, kernel-allocated, mmaped-to-usermode
-  addresses */
-   physp = (vma-vm_pgoff  PAGE_SHIFT) + (virtp - vma-vm_start);
-   up_read(current-mm-mmap_sem);
-   } else {
-   /* otherwise, use get_user_pages() for general userland pages */
-   int res, nr_pages = 1;
-   struct page *pages;
+   if (virtp = PAGE_OFFSET) {
+   *physp = virt_to_phys((void *)virtp);
+   return 0;
+   }
 
-   res = get_user_pages(current, current-mm, virtp, nr_pages, 1,
-   0, pages, NULL);
-   up_read(current-mm-mmap_sem);
+   vec = frame_vector_create(1);
+   if (!vec)
+   return -ENOMEM;
 
-   if (res == nr_pages) {
-   physp =  __pa(page_address(pages[0]) +
-   (virtp  ~PAGE_MASK));
-   } else {
-   printk(KERN_WARNING VOUT_NAME
-   get_user_pages failed\n);
-   return 0;
-   }
+   ret = get_vaddr_frames(virtp, 1, 1, 0, vec);
+   if (ret != 1) {
+   frame_vector_destroy(vec);
+   return -EINVAL;
}
+   *physp = __pfn_to_phys(frame_vector_pfns(vec)[0]);
+   vb-priv = vec;
 
-   return physp;
+   return 0;
 }
 
 /*
@@ -788,11 +776,15 @@ static int omap_vout_buffer_prepare(struct videobuf_queue 
*q,
 * address of the buffer
 */
if (V4L2_MEMORY_USERPTR == vb-memory) {
+   int ret;
+
if (0 == vb-baddr)
return -EINVAL;
/* Physical address */
-   vout-queued_buf_addr[vb-i] = (u8 *)
-   omap_vout_uservirt_to_phys(vb-baddr);
+   ret = omap_vout_get_userptr(vb, vb-baddr,
+   (u32 *)vout-queued_buf_addr[vb-i]);
+   if (ret  0)
+   return ret;
} else {
unsigned long addr, dma_addr;
unsigned long size;
@@ -841,9 +833,12 @@ static void omap_vout_buffer_release(struct videobuf_queue 
*q,
struct omap_vout_device *vout = q-priv_data;
 
vb-state = VIDEOBUF_NEEDS_INIT;
+   if (vb-memory == V4L2_MEMORY_USERPTR  vb-priv) {
+   struct frame_vector *vec = vb-priv;
 
-   if (V4L2_MEMORY_MMAP != vout-memory)
-   return;
+   put_vaddr_frames(vec);
+   frame_vector_destroy(vec);
+   }
 }
 
 /*
-- 
2.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-media in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 4/9] vb2: Provide helpers for mapping virtual addresses

2015-05-05 Thread Jan Kara
Provide simple helper functions to map virtual address range into an
array of pfns / pages.

Acked-by: Marek Szyprowski m.szyprow...@samsung.com
Tested-by: Marek Szyprowski m.szyprow...@samsung.com
Signed-off-by: Jan Kara j...@suse.cz
---
 drivers/media/v4l2-core/videobuf2-memops.c | 58 ++
 include/media/videobuf2-memops.h   |  5 +++
 2 files changed, 63 insertions(+)

diff --git a/drivers/media/v4l2-core/videobuf2-memops.c 
b/drivers/media/v4l2-core/videobuf2-memops.c
index 81c1ad8b2cf1..0ec186d41b9b 100644
--- a/drivers/media/v4l2-core/videobuf2-memops.c
+++ b/drivers/media/v4l2-core/videobuf2-memops.c
@@ -137,6 +137,64 @@ int vb2_get_contig_userptr(unsigned long vaddr, unsigned 
long size,
 EXPORT_SYMBOL_GPL(vb2_get_contig_userptr);
 
 /**
+ * vb2_create_framevec() - map virtual addresses to pfns
+ * @start: Virtual user address where we start mapping
+ * @length:Length of a range to map
+ * @write: Should we map for writing into the area
+ *
+ * This function allocates and fills in a vector with pfns corresponding to
+ * virtual address range passed in arguments. If pfns have corresponding pages,
+ * page references are also grabbed to pin pages in memory. The function
+ * returns pointer to the vector on success and error pointer in case of
+ * failure. Returned vector needs to be freed via vb2_destroy_pfnvec().
+ */
+struct frame_vector *vb2_create_framevec(unsigned long start,
+unsigned long length,
+bool write)
+{
+   int ret;
+   unsigned long first, last;
+   unsigned long nr;
+   struct frame_vector *vec;
+
+   first = start  PAGE_SHIFT;
+   last = (start + length - 1)  PAGE_SHIFT;
+   nr = last - first + 1;
+   vec = frame_vector_create(nr);
+   if (!vec)
+   return ERR_PTR(-ENOMEM);
+   ret = get_vaddr_frames(start, nr, write, 1, vec);
+   if (ret  0)
+   goto out_destroy;
+   /* We accept only complete set of PFNs */
+   if (ret != nr) {
+   ret = -EFAULT;
+   goto out_release;
+   }
+   return vec;
+out_release:
+   put_vaddr_frames(vec);
+out_destroy:
+   frame_vector_destroy(vec);
+   return ERR_PTR(ret);
+}
+EXPORT_SYMBOL(vb2_create_framevec);
+
+/**
+ * vb2_destroy_framevec() - release vector of mapped pfns
+ * @vec:   vector of pfns / pages to release
+ *
+ * This releases references to all pages in the vector @vec (if corresponding
+ * pfns are backed by pages) and frees the passed vector.
+ */
+void vb2_destroy_framevec(struct frame_vector *vec)
+{
+   put_vaddr_frames(vec);
+   frame_vector_destroy(vec);
+}
+EXPORT_SYMBOL(vb2_destroy_framevec);
+
+/**
  * vb2_common_vm_open() - increase refcount of the vma
  * @vma:   virtual memory region for the mapping
  *
diff --git a/include/media/videobuf2-memops.h b/include/media/videobuf2-memops.h
index f05444ca8c0c..2f0564ff5f31 100644
--- a/include/media/videobuf2-memops.h
+++ b/include/media/videobuf2-memops.h
@@ -15,6 +15,7 @@
 #define _MEDIA_VIDEOBUF2_MEMOPS_H
 
 #include media/videobuf2-core.h
+#include linux/mm.h
 
 /**
  * vb2_vmarea_handler - common vma refcount tracking handler
@@ -36,5 +37,9 @@ int vb2_get_contig_userptr(unsigned long vaddr, unsigned long 
size,
 struct vm_area_struct *vb2_get_vma(struct vm_area_struct *vma);
 void vb2_put_vma(struct vm_area_struct *vma);
 
+struct frame_vector *vb2_create_framevec(unsigned long start,
+unsigned long length,
+bool write);
+void vb2_destroy_framevec(struct frame_vector *vec);
 
 #endif
-- 
2.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-media in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 5/9] media: vb2: Convert vb2_dma_sg_get_userptr() to use frame vector

2015-05-05 Thread Jan Kara
Acked-by: Marek Szyprowski m.szyprow...@samsung.com
Tested-by: Marek Szyprowski m.szyprow...@samsung.com
Signed-off-by: Jan Kara j...@suse.cz
---
 drivers/media/v4l2-core/videobuf2-dma-sg.c | 97 +-
 1 file changed, 15 insertions(+), 82 deletions(-)

diff --git a/drivers/media/v4l2-core/videobuf2-dma-sg.c 
b/drivers/media/v4l2-core/videobuf2-dma-sg.c
index afd4b514affc..4ee1b3fbfe2a 100644
--- a/drivers/media/v4l2-core/videobuf2-dma-sg.c
+++ b/drivers/media/v4l2-core/videobuf2-dma-sg.c
@@ -38,6 +38,7 @@ struct vb2_dma_sg_buf {
struct device   *dev;
void*vaddr;
struct page **pages;
+   struct frame_vector *vec;
int offset;
enum dma_data_direction dma_dir;
struct sg_table sg_table;
@@ -51,7 +52,6 @@ struct vb2_dma_sg_buf {
unsigned intnum_pages;
atomic_trefcount;
struct vb2_vmarea_handler   handler;
-   struct vm_area_struct   *vma;
 
struct dma_buf_attachment   *db_attach;
 };
@@ -224,25 +224,17 @@ static void vb2_dma_sg_finish(void *buf_priv)
dma_sync_sg_for_cpu(buf-dev, sgt-sgl, sgt-nents, buf-dma_dir);
 }
 
-static inline int vma_is_io(struct vm_area_struct *vma)
-{
-   return !!(vma-vm_flags  (VM_IO | VM_PFNMAP));
-}
-
 static void *vb2_dma_sg_get_userptr(void *alloc_ctx, unsigned long vaddr,
unsigned long size,
enum dma_data_direction dma_dir)
 {
struct vb2_dma_sg_conf *conf = alloc_ctx;
struct vb2_dma_sg_buf *buf;
-   unsigned long first, last;
-   int num_pages_from_user;
-   struct vm_area_struct *vma;
struct sg_table *sgt;
DEFINE_DMA_ATTRS(attrs);
+   struct frame_vector *vec;
 
dma_set_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs);
-
buf = kzalloc(sizeof *buf, GFP_KERNEL);
if (!buf)
return NULL;
@@ -253,63 +245,19 @@ static void *vb2_dma_sg_get_userptr(void *alloc_ctx, 
unsigned long vaddr,
buf-offset = vaddr  ~PAGE_MASK;
buf-size = size;
buf-dma_sgt = buf-sg_table;
+   vec = vb2_create_framevec(vaddr, size, buf-dma_dir == DMA_FROM_DEVICE);
+   if (IS_ERR(vec))
+   goto userptr_fail_pfnvec;
+   buf-vec = vec;
 
-   first = (vaddrPAGE_MASK)  PAGE_SHIFT;
-   last  = ((vaddr + size - 1)  PAGE_MASK)  PAGE_SHIFT;
-   buf-num_pages = last - first + 1;
-
-   buf-pages = kzalloc(buf-num_pages * sizeof(struct page *),
-GFP_KERNEL);
-   if (!buf-pages)
-   goto userptr_fail_alloc_pages;
-
-   down_read(current-mm-mmap_sem);
-   vma = find_vma(current-mm, vaddr);
-   if (!vma) {
-   dprintk(1, no vma for address %lu\n, vaddr);
-   goto userptr_fail_find_vma;
-   }
-
-   if (vma-vm_end  vaddr + size) {
-   dprintk(1, vma at %lu is too small for %lu bytes\n,
-   vaddr, size);
-   goto userptr_fail_find_vma;
-   }
-
-   buf-vma = vb2_get_vma(vma);
-   if (!buf-vma) {
-   dprintk(1, failed to copy vma\n);
-   goto userptr_fail_find_vma;
-   }
-
-   if (vma_is_io(buf-vma)) {
-   for (num_pages_from_user = 0;
-num_pages_from_user  buf-num_pages;
-++num_pages_from_user, vaddr += PAGE_SIZE) {
-   unsigned long pfn;
-
-   if (follow_pfn(vma, vaddr, pfn)) {
-   dprintk(1, no page for address %lu\n, vaddr);
-   break;
-   }
-   buf-pages[num_pages_from_user] = pfn_to_page(pfn);
-   }
-   } else
-   num_pages_from_user = get_user_pages(current, current-mm,
-vaddr  PAGE_MASK,
-buf-num_pages,
-buf-dma_dir == DMA_FROM_DEVICE,
-1, /* force */
-buf-pages,
-NULL);
-   up_read(current-mm-mmap_sem);
-
-   if (num_pages_from_user != buf-num_pages)
-   goto userptr_fail_get_user_pages;
+   buf-pages = frame_vector_pages(vec);
+   if (IS_ERR(buf-pages))
+   goto userptr_fail_sgtable;
+   buf-num_pages = frame_vector_count(vec);
 
if (sg_alloc_table_from_pages(buf-dma_sgt, buf-pages,
buf-num_pages, buf-offset, size, 0))
-   goto userptr_fail_alloc_table_from_pages;
+   goto userptr_fail_sgtable;
 
sgt = buf-sg_table;
/*
@@ -323,19 +271,9

[PATCH 7/9] media: vb2: Convert vb2_dc_get_userptr() to use frame vector

2015-05-05 Thread Jan Kara
Convert vb2_dc_get_userptr() to use frame vector infrastructure. When we
are doing that there's no need to allocate page array and some code can
be simplified.

Acked-by: Marek Szyprowski m.szyprow...@samsung.com
Tested-by: Marek Szyprowski m.szyprow...@samsung.com
Signed-off-by: Jan Kara j...@suse.cz
---
 drivers/media/v4l2-core/videobuf2-dma-contig.c | 214 -
 1 file changed, 34 insertions(+), 180 deletions(-)

diff --git a/drivers/media/v4l2-core/videobuf2-dma-contig.c 
b/drivers/media/v4l2-core/videobuf2-dma-contig.c
index 620c4aa78881..e6cea452302b 100644
--- a/drivers/media/v4l2-core/videobuf2-dma-contig.c
+++ b/drivers/media/v4l2-core/videobuf2-dma-contig.c
@@ -32,15 +32,13 @@ struct vb2_dc_buf {
dma_addr_t  dma_addr;
enum dma_data_direction dma_dir;
struct sg_table *dma_sgt;
+   struct frame_vector *vec;
 
/* MMAP related */
struct vb2_vmarea_handler   handler;
atomic_trefcount;
struct sg_table *sgt_base;
 
-   /* USERPTR related */
-   struct vm_area_struct   *vma;
-
/* DMABUF related */
struct dma_buf_attachment   *db_attach;
 };
@@ -49,24 +47,6 @@ struct vb2_dc_buf {
 /*scatterlist table functions*/
 /*/
 
-
-static void vb2_dc_sgt_foreach_page(struct sg_table *sgt,
-   void (*cb)(struct page *pg))
-{
-   struct scatterlist *s;
-   unsigned int i;
-
-   for_each_sg(sgt-sgl, s, sgt-orig_nents, i) {
-   struct page *page = sg_page(s);
-   unsigned int n_pages = PAGE_ALIGN(s-offset + s-length)
-PAGE_SHIFT;
-   unsigned int j;
-
-   for (j = 0; j  n_pages; ++j, ++page)
-   cb(page);
-   }
-}
-
 static unsigned long vb2_dc_get_contiguous_size(struct sg_table *sgt)
 {
struct scatterlist *s;
@@ -429,92 +409,12 @@ static struct dma_buf *vb2_dc_get_dmabuf(void *buf_priv, 
unsigned long flags)
 /*   callbacks for USERPTR buffers   */
 /*/
 
-static inline int vma_is_io(struct vm_area_struct *vma)
-{
-   return !!(vma-vm_flags  (VM_IO | VM_PFNMAP));
-}
-
-static int vb2_dc_get_user_pfn(unsigned long start, int n_pages,
-   struct vm_area_struct *vma, unsigned long *res)
-{
-   unsigned long pfn, start_pfn, prev_pfn;
-   unsigned int i;
-   int ret;
-
-   if (!vma_is_io(vma))
-   return -EFAULT;
-
-   ret = follow_pfn(vma, start, pfn);
-   if (ret)
-   return ret;
-
-   start_pfn = pfn;
-   start += PAGE_SIZE;
-
-   for (i = 1; i  n_pages; ++i, start += PAGE_SIZE) {
-   prev_pfn = pfn;
-   ret = follow_pfn(vma, start, pfn);
-
-   if (ret) {
-   pr_err(no page for address %lu\n, start);
-   return ret;
-   }
-   if (pfn != prev_pfn + 1)
-   return -EINVAL;
-   }
-
-   *res = start_pfn;
-   return 0;
-}
-
-static int vb2_dc_get_user_pages(unsigned long start, struct page **pages,
-   int n_pages, struct vm_area_struct *vma,
-   enum dma_data_direction dma_dir)
-{
-   if (vma_is_io(vma)) {
-   unsigned int i;
-
-   for (i = 0; i  n_pages; ++i, start += PAGE_SIZE) {
-   unsigned long pfn;
-   int ret = follow_pfn(vma, start, pfn);
-
-   if (!pfn_valid(pfn))
-   return -EINVAL;
-
-   if (ret) {
-   pr_err(no page for address %lu\n, start);
-   return ret;
-   }
-   pages[i] = pfn_to_page(pfn);
-   }
-   } else {
-   int n;
-
-   n = get_user_pages(current, current-mm, start  PAGE_MASK,
-   n_pages, dma_dir == DMA_FROM_DEVICE, 1, pages, NULL);
-   /* negative error means that no page was pinned */
-   n = max(n, 0);
-   if (n != n_pages) {
-   pr_err(got only %d of %d user pages\n, n, n_pages);
-   while (n)
-   put_page(pages[--n]);
-   return -EFAULT;
-   }
-   }
-
-   return 0;
-}
-
-static void vb2_dc_put_dirty_page(struct page *page)
-{
-   set_page_dirty_lock(page);
-   put_page(page);
-}
-
 static void vb2_dc_put_userptr(void *buf_priv)
 {
struct vb2_dc_buf *buf = buf_priv;
struct sg_table *sgt = buf-dma_sgt;
+   int i;
+   struct page **pages;
 
if (sgt) {
DEFINE_DMA_ATTRS(attrs);
@@ -526,15 +426,15 @@ static void vb2_dc_put_userptr(void *buf_priv

Re: [PATCH 2/9] mm: Provide new get_vaddr_pfns() helper

2015-05-04 Thread Jan Kara
On Thu 30-04-15 16:55:31, Mel Gorman wrote:
 On Tue, Mar 17, 2015 at 12:56:32PM +0100, Jan Kara wrote:
  Provide new function get_vaddr_pfns().  This function maps virtual
  addresses from given start and fills given array with page frame numbers of
  the corresponding pages. If given start belongs to a normal vma, the 
  function
  grabs reference to each of the pages to pin them in memory. If start
  belongs to VM_IO | VM_PFNMAP vma, we don't touch page structures. Caller
  should make sure pfns aren't reused for anything else while he is using
  them.
  
  This function is created for various drivers to simplify handling of
  their buffers.
  
  Signed-off-by: Jan Kara j...@suse.cz
  ---
   include/linux/mm.h |  38 +++
   mm/gup.c   | 180 
  +
   2 files changed, 218 insertions(+)
  
  diff --git a/include/linux/mm.h b/include/linux/mm.h
  index 47a93928b90f..a5045df92454 100644
  --- a/include/linux/mm.h
  +++ b/include/linux/mm.h
  @@ -1279,6 +1279,44 @@ long get_user_pages_unlocked(struct task_struct 
  *tsk, struct mm_struct *mm,
  int write, int force, struct page **pages);
   int get_user_pages_fast(unsigned long start, int nr_pages, int write,
  struct page **pages);
  +
  +/* Container for pinned pfns / pages */
  +struct pinned_pfns {
  +   unsigned int nr_allocated_pfns; /* Number of pfns we have space for */
  +   unsigned int nr_pfns;   /* Number of pfns stored in pfns array 
  */
  +   unsigned int got_ref:1; /* Did we pin pfns by getting page ref? 
  */
  +   unsigned int is_pages:1;/* Does array contain pages or pfns? */
 
 The bit field is probably overkill as I expect it'll get padded out for
 pointer alignment anyway. Just use bools.
  Makes sense.

 is_pfns is less ambiguous than is_pages but not very important.
 
 The naming is not great in general. Only struct pages are pinned in the
 traditional meaning of the word. The raw PFNs are not so there is no such
 thing as a pinned pfns. It might be better just to call it frame_vectors
 and document that it's either raw PFNs that the caller should be responsible
 for or struct pages that are pinned.
  Good point. I'll try to come up with a better name.

snip - I agree with minor comments there.

   /**
  + * get_vaddr_pfns() - map virtual addresses to pfns
  + * @start: starting user address
  + * @nr_pfns:   number of pfns from start to map
  + * @write: whether pages will be written to by the caller
  + * @force: whether to force write access even if user mapping is
  + * readonly. This will result in the page being COWed even
  + * in MAP_SHARED mappings. You do not want this.
  + * @pfns:  structure which receives pfns of the pages mapped.
  + * It should have space for at least nr_pfns pfns.
  + *
  + * This function maps virtual addresses from @start and fills @pfns 
  structure
  + * with page frame numbers of corresponding pages. If @start belongs to a
  + * normal vma, the function grabs reference to each of the pages to pin 
  them in
  + * memory. If @start belongs to VM_IO | VM_PFNMAP vma, we don't touch page
  + * structures. Caller should make sure pfns aren't reused for anything else
  + * while he is using them.
  + *
  + * This function takes care of grabbing mmap_sem as necessary.
  + */
  +int get_vaddr_pfns(unsigned long start, int nr_pfns, int write, int force,
  +  struct pinned_pfns *pfns)
  +{
  +   struct mm_struct *mm = current-mm;
  +   struct vm_area_struct *vma;
  +   int ret = 0;
  +   int err;
  +
  +   if (nr_pfns = 0)
  +   return 0;
  +
 
 I know I suggested that nr_pfns should be unsigned earlier and then I
 saw this. Is there any valid use of the API that would pass in a
 negative number here?
  No. It was there just because I had ints everywhere without too much
thought (it's shorter to type *grin*). I'll put unsigned types where it
makes sense and add a test for INT_MAX so that get_vaddr_pfns() can still
return negative errors.

  +   if (nr_pfns  pfns-nr_allocated_pfns)
  +   nr_pfns = pfns-nr_allocated_pfns;
  +
 
 Should this be a WARN_ON_ONCE? You recover from it obviously but the return
 value is not documented to say that it could return less than requested.
 Of course, this is implied but a caller might assume it's due to a transient
 error instead of broken API usage.
  Yep, good idea.

  +   down_read(mm-mmap_sem);
  +   vma = find_vma_intersection(mm, start, start + 1);
  +   if (!vma) {
  +   ret = -EFAULT;
  +   goto out;
  +   }
 
 Returning -EFAULT means that the return value has to be signed but the
 structure itself has unsigned int for counters so the maximum number of
 PFNs supported is not available. We'd never want that number of PFNs pinned
 but still it might make sense to enforce the maximum possible size of the
 structure that takes into account the values needed for returning

Re: [PATCH 0/9 v2] Helper to abstract vma handling in media layer

2015-04-24 Thread Jan Kara
On Fri 24-04-15 13:07:37, Hans Verkuil wrote:
 Hi Marek,
 
 On 04/24/2015 12:59 PM, Marek Szyprowski wrote:
  Dear All,
  
  On 2015-04-02 17:25, Hans Verkuil wrote:
  On 04/02/2015 05:02 PM, Jan Kara wrote:
 Hello,
 
  On Tue 17-03-15 12:56:30, Jan Kara wrote:
 After a long pause I'm sending second version of my patch series to 
  abstract
  vma handling from the various media drivers. After this patch set 
  drivers have
  to know much less details about vmas, their types, and locking. My 
  motivation
  for the series is that I want to change get_user_pages() locking and I 
  want to
  handle subtle locking details in as few places as possible.
 
  The core of the series is the new helper get_vaddr_pfns() which is given 
  a
  virtual address and it fills in PFNs into provided array. If PFNs 
  correspond to
  normal pages it also grabs references to these pages. The difference from
  get_user_pages() is that this function can also deal with pfnmap, mixed, 
  and io
  mappings which is what the media drivers need.
 
  I have tested the patches with vivid driver so at least vb2 code got some
  exposure. Conversion of other drivers was just compile-tested so I'd 
  like to
  ask respective maintainers if they could have a look.  Also I'd like to 
  ask mm
  folks to check patch 2/9 implementing the helper. Thanks!
 Ping? Any reactions?
  For patch 1/9:
 
  Acked-by: Hans Verkuil hans.verk...@cisco.com
 
  For the other patches I do not feel qualified to give Acks. I've Cc-ed 
  Pawel and
  Marek who have a better understanding of the mm internals than I do. 
  Hopefully
  they can review the code.
 
  It definitely looks like a good idea, and if nobody else will comment on 
  the vb2
  patches in the next 2 weeks, then I'll try to review it myself (for 
  whatever that's
  worth).
  
  I'm really sorry that I didn't manage to find time to review this 
  patchset. I really
  like the idea of moving pfn lookup from videobuf2/driver to some common 
  code in mm
  and it is really great that someone managed to provide nice generic code 
  for it.
  
  I've applied the whole patchset onto v4.0 and tested it on Odroid U3 
  (with some
  additional patches). VideoBuf2-dc works still fine with USERPTR gathered 
  from other's
  device mmaped buffer. You can add my:
  
  Acked-by: Marek Szyprowski m.szyprow...@samsung.com
  Tested-by: Marek Szyprowski m.szyprow...@samsung.com
 
 Thanks!
  Thank you both for having a look at the patches!

  for the patches 1-8. Patch 9/9 doesn't apply anymore, so I've skipped 
  it. Patch 2
  needs a small fixup - you need to add '#include linux/vmalloc.h', 
  because otherwise
  it doesn't compile. There have been also a minor conflict to be resolved 
  in patch 7.
 
 I've just added patch 1/9 to my pull request for 4.2. But for patch 2/9 I need
 Acks from the mm maintainers. I think it makes sense if patches 2-8 all go
 in together via the linux-media tree. Jan, can you reach out to the right
 devs to get Acks?
  Sure, I'll ping some mm guys explicitely.

Honza
-- 
Jan Kara j...@suse.cz
SUSE Labs, CR
--
To unsubscribe from this list: send the line unsubscribe linux-media in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 1/9] mm: Provide new get_vaddr_pfns() helper

2015-04-24 Thread Jan Kara
On Mon 17-03-14 20:49:28, Jan Kara wrote:
 Provide new function get_vaddr_pfns().  This function maps virtual
 addresses from given start and fills given array with page frame numbers of
 the corresponding pages. If given start belongs to a normal vma, the function
 grabs reference to each of the pages to pin them in memory. If start
 belongs to VM_IO | VM_PFNMAP vma, we don't touch page structures. Caller
 should make sure pfns aren't reused for anything else while he is using
 them.
 
 This function is created for various drivers to simplify handling of
 their buffers.
  MM guys, could you have a look at this patch? Linux Media people like the
abstraction of buffer handling and would like to merge the patch set (see
http://thread.gmane.org/gmane.linux.drivers.video-input-infrastructure/89268).
But for that they need ack from mm people that the interface is ok with
them. So far the only comment I got regarding the interface was from Dave
Hansen that I could also handle VM_MIXEDMAP mappings - I could if people
really want that but so far there are no users for that. Thanks!

Honza
 
 Signed-off-by: Jan Kara j...@suse.cz
 ---
  include/linux/mm.h |  46 +++
  mm/memory.c| 165 
 +
  2 files changed, 211 insertions(+)
 
 diff --git a/include/linux/mm.h b/include/linux/mm.h
 index da8ad480bea7..b3bd29cc40dd 100644
 --- a/include/linux/mm.h
 +++ b/include/linux/mm.h
 @@ -18,6 +18,8 @@
  #include linux/pfn.h
  #include linux/bit_spinlock.h
  #include linux/shrinker.h
 +#include linux/slab.h
 +#include linux/vmalloc.h
  
  struct mempolicy;
  struct anon_vma;
 @@ -1180,6 +1182,50 @@ get_user_pages_unlocked(struct task_struct *tsk, 
 struct mm_struct *mm,
   return ret;
  }
  
 +/* Container for pinned pfns / pages */
 +struct pinned_pfns {
 + unsigned int nr_allocated_pfns; /* Number of pfns we have space for */
 + unsigned int nr_pfns;   /* Number of pfns stored in pfns array 
 */
 + unsigned int got_ref:1; /* Did we pin pfns by getting page ref? 
 */
 + unsigned int is_pages:1;/* Does array contain pages or pfns? */
 + void *ptrs[0];  /* Array of pinned pfns / pages.
 +  * Use pfns_vector_pages() or
 +  * pfns_vector_pfns() for access */
 +};
 +
 +struct pinned_pfns *pfns_vector_create(int nr_pfns);
 +static inline void pfns_vector_destroy(struct pinned_pfns *pfns)
 +{
 + if (!is_vmalloc_addr(pfns))
 + kfree(pfns);
 + else
 + vfree(pfns);
 +}
 +int get_vaddr_pfns(unsigned long start, int nr_pfns, int write, int force,
 +struct pinned_pfns *pfns);
 +void put_vaddr_pfns(struct pinned_pfns *pfns);
 +int pfns_vector_to_pages(struct pinned_pfns *pfns);
 +
 +static inline int pfns_vector_count(struct pinned_pfns *pfns)
 +{
 + return pfns-nr_pfns;
 +}
 +
 +static inline struct page **pfns_vector_pages(struct pinned_pfns *pfns)
 +{
 + if (!pfns-is_pages)
 + return NULL;
 + return (struct page **)(pfns-ptrs);
 +}
 +
 +static inline unsigned long *pfns_vector_pfns(struct pinned_pfns *pfns)
 +{
 + if (pfns-is_pages)
 + return NULL;
 + return (unsigned long *)(pfns-ptrs);
 +}
 +
 +
  struct kvec;
  int get_kernel_pages(const struct kvec *iov, int nr_pages, int write,
   struct page **pages);
 diff --git a/mm/memory.c b/mm/memory.c
 index 22dfa617bddb..87bebcfb8911 100644
 --- a/mm/memory.c
 +++ b/mm/memory.c
 @@ -2024,6 +2024,171 @@ long get_user_pages(struct task_struct *tsk, struct 
 mm_struct *mm,
  EXPORT_SYMBOL(get_user_pages);
  
  /**
 + * get_vaddr_pfns() - map virtual addresses to pfns
 + * @start:   starting user address
 + * @nr_pfns: number of pfns from start to map
 + * @write:   whether pages will be written to by the caller
 + * @force:   whether to force write access even if user mapping is
 + *   readonly. This will result in the page being COWed even
 + *   in MAP_SHARED mappings. You do not want this.
 + * @pfns:structure which receives pfns of the pages mapped.
 + *   It should have space for at least nr_pfns pfns. 
 + *
 + * This function maps virtual addresses from @start and fills @pfns structure
 + * with page frame numbers of corresponding pages. If @start belongs to a
 + * normal vma, the function grabs reference to each of the pages to pin them 
 in
 + * memory. If @start belongs to VM_IO | VM_PFNMAP vma, we don't touch page
 + * structures. Caller should make sure pfns aren't reused for anything else
 + * while he is using them.
 + *
 + * This function takes care of grabbing mmap_sem as necessary.
 + */
 +int get_vaddr_pfns(unsigned long start, int nr_pfns, int write, int force,
 +struct pinned_pfns *pfns)
 +{
 + struct mm_struct *mm = current-mm;
 + struct

Re: [PATCH 0/9 v2] Helper to abstract vma handling in media layer

2015-04-02 Thread Jan Kara
  Hello,

On Tue 17-03-15 12:56:30, Jan Kara wrote:
   After a long pause I'm sending second version of my patch series to abstract
 vma handling from the various media drivers. After this patch set drivers have
 to know much less details about vmas, their types, and locking. My motivation
 for the series is that I want to change get_user_pages() locking and I want to
 handle subtle locking details in as few places as possible.
 
 The core of the series is the new helper get_vaddr_pfns() which is given a
 virtual address and it fills in PFNs into provided array. If PFNs correspond 
 to
 normal pages it also grabs references to these pages. The difference from
 get_user_pages() is that this function can also deal with pfnmap, mixed, and 
 io
 mappings which is what the media drivers need.
 
 I have tested the patches with vivid driver so at least vb2 code got some
 exposure. Conversion of other drivers was just compile-tested so I'd like to
 ask respective maintainers if they could have a look.  Also I'd like to ask mm
 folks to check patch 2/9 implementing the helper. Thanks!
  Ping? Any reactions?

Honza

-- 
Jan Kara j...@suse.cz
SUSE Labs, CR
--
To unsubscribe from this list: send the line unsubscribe linux-media in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 2/9] mm: Provide new get_vaddr_pfns() helper

2015-03-17 Thread Jan Kara
Provide new function get_vaddr_pfns().  This function maps virtual
addresses from given start and fills given array with page frame numbers of
the corresponding pages. If given start belongs to a normal vma, the function
grabs reference to each of the pages to pin them in memory. If start
belongs to VM_IO | VM_PFNMAP vma, we don't touch page structures. Caller
should make sure pfns aren't reused for anything else while he is using
them.

This function is created for various drivers to simplify handling of
their buffers.

Signed-off-by: Jan Kara j...@suse.cz
---
 include/linux/mm.h |  38 +++
 mm/gup.c   | 180 +
 2 files changed, 218 insertions(+)

diff --git a/include/linux/mm.h b/include/linux/mm.h
index 47a93928b90f..a5045df92454 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -1279,6 +1279,44 @@ long get_user_pages_unlocked(struct task_struct *tsk, 
struct mm_struct *mm,
int write, int force, struct page **pages);
 int get_user_pages_fast(unsigned long start, int nr_pages, int write,
struct page **pages);
+
+/* Container for pinned pfns / pages */
+struct pinned_pfns {
+   unsigned int nr_allocated_pfns; /* Number of pfns we have space for */
+   unsigned int nr_pfns;   /* Number of pfns stored in pfns array 
*/
+   unsigned int got_ref:1; /* Did we pin pfns by getting page ref? 
*/
+   unsigned int is_pages:1;/* Does array contain pages or pfns? */
+   void *ptrs[0];  /* Array of pinned pfns / pages.
+* Use pfns_vector_pages() or
+* pfns_vector_pfns() for access */
+};
+
+struct pinned_pfns *pfns_vector_create(int nr_pfns);
+void pfns_vector_destroy(struct pinned_pfns *pfns);
+int get_vaddr_pfns(unsigned long start, int nr_pfns, int write, int force,
+  struct pinned_pfns *pfns);
+void put_vaddr_pfns(struct pinned_pfns *pfns);
+int pfns_vector_to_pages(struct pinned_pfns *pfns);
+
+static inline int pfns_vector_count(struct pinned_pfns *pfns)
+{
+   return pfns-nr_pfns;
+}
+
+static inline struct page **pfns_vector_pages(struct pinned_pfns *pfns)
+{
+   if (!pfns-is_pages)
+   return NULL;
+   return (struct page **)(pfns-ptrs);
+}
+
+static inline unsigned long *pfns_vector_pfns(struct pinned_pfns *pfns)
+{
+   if (pfns-is_pages)
+   return NULL;
+   return (unsigned long *)(pfns-ptrs);
+}
+
 struct kvec;
 int get_kernel_pages(const struct kvec *iov, int nr_pages, int write,
struct page **pages);
diff --git a/mm/gup.c b/mm/gup.c
index a6e24e246f86..63903913ab04 100644
--- a/mm/gup.c
+++ b/mm/gup.c
@@ -819,6 +819,186 @@ long get_user_pages(struct task_struct *tsk, struct 
mm_struct *mm,
 EXPORT_SYMBOL(get_user_pages);
 
 /**
+ * get_vaddr_pfns() - map virtual addresses to pfns
+ * @start: starting user address
+ * @nr_pfns:   number of pfns from start to map
+ * @write: whether pages will be written to by the caller
+ * @force: whether to force write access even if user mapping is
+ * readonly. This will result in the page being COWed even
+ * in MAP_SHARED mappings. You do not want this.
+ * @pfns:  structure which receives pfns of the pages mapped.
+ * It should have space for at least nr_pfns pfns.
+ *
+ * This function maps virtual addresses from @start and fills @pfns structure
+ * with page frame numbers of corresponding pages. If @start belongs to a
+ * normal vma, the function grabs reference to each of the pages to pin them in
+ * memory. If @start belongs to VM_IO | VM_PFNMAP vma, we don't touch page
+ * structures. Caller should make sure pfns aren't reused for anything else
+ * while he is using them.
+ *
+ * This function takes care of grabbing mmap_sem as necessary.
+ */
+int get_vaddr_pfns(unsigned long start, int nr_pfns, int write, int force,
+  struct pinned_pfns *pfns)
+{
+   struct mm_struct *mm = current-mm;
+   struct vm_area_struct *vma;
+   int ret = 0;
+   int err;
+
+   if (nr_pfns = 0)
+   return 0;
+
+   if (nr_pfns  pfns-nr_allocated_pfns)
+   nr_pfns = pfns-nr_allocated_pfns;
+
+   down_read(mm-mmap_sem);
+   vma = find_vma_intersection(mm, start, start + 1);
+   if (!vma) {
+   ret = -EFAULT;
+   goto out;
+   }
+   if (!(vma-vm_flags  (VM_IO | VM_PFNMAP))) {
+   pfns-got_ref = 1;
+   pfns-is_pages = 1;
+   ret = get_user_pages(current, mm, start, nr_pfns, write, force,
+pfns_vector_pages(pfns), NULL);
+   goto out;
+   }
+
+   pfns-got_ref = 0;
+   pfns-is_pages = 0;
+   do {
+   unsigned long *nums = pfns_vector_pfns(pfns);
+
+   while (ret  nr_pfns

[PATCH 0/9 v2] Helper to abstract vma handling in media layer

2015-03-17 Thread Jan Kara
  Hello,

  After a long pause I'm sending second version of my patch series to abstract
vma handling from the various media drivers. After this patch set drivers have
to know much less details about vmas, their types, and locking. My motivation
for the series is that I want to change get_user_pages() locking and I want to
handle subtle locking details in as few places as possible.

The core of the series is the new helper get_vaddr_pfns() which is given a
virtual address and it fills in PFNs into provided array. If PFNs correspond to
normal pages it also grabs references to these pages. The difference from
get_user_pages() is that this function can also deal with pfnmap, mixed, and io
mappings which is what the media drivers need.

I have tested the patches with vivid driver so at least vb2 code got some
exposure. Conversion of other drivers was just compile-tested so I'd like to
ask respective maintainers if they could have a look.  Also I'd like to ask mm
folks to check patch 2/9 implementing the helper. Thanks!

Honza
--
To unsubscribe from this list: send the line unsubscribe linux-media in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 8/9] media: vb2: Remove unused functions

2015-03-17 Thread Jan Kara
Conversion to the use of pinned pfns made some functions unused. Remove
them. Also there's no need to lock mmap_sem in __buf_prepare() anymore.

Signed-off-by: Jan Kara j...@suse.cz
---
 drivers/media/v4l2-core/videobuf2-memops.c | 114 -
 include/media/videobuf2-memops.h   |   6 --
 2 files changed, 120 deletions(-)

diff --git a/drivers/media/v4l2-core/videobuf2-memops.c 
b/drivers/media/v4l2-core/videobuf2-memops.c
index 80ade22b920c..08daaa5c4e2d 100644
--- a/drivers/media/v4l2-core/videobuf2-memops.c
+++ b/drivers/media/v4l2-core/videobuf2-memops.c
@@ -23,120 +23,6 @@
 #include media/videobuf2-memops.h
 
 /**
- * vb2_get_vma() - acquire and lock the virtual memory area
- * @vma:   given virtual memory area
- *
- * This function attempts to acquire an area mapped in the userspace for
- * the duration of a hardware operation. The area is locked by performing
- * the same set of operation that are done when process calls fork() and
- * memory areas are duplicated.
- *
- * Returns a copy of a virtual memory region on success or NULL.
- */
-struct vm_area_struct *vb2_get_vma(struct vm_area_struct *vma)
-{
-   struct vm_area_struct *vma_copy;
-
-   vma_copy = kmalloc(sizeof(*vma_copy), GFP_KERNEL);
-   if (vma_copy == NULL)
-   return NULL;
-
-   if (vma-vm_ops  vma-vm_ops-open)
-   vma-vm_ops-open(vma);
-
-   if (vma-vm_file)
-   get_file(vma-vm_file);
-
-   memcpy(vma_copy, vma, sizeof(*vma));
-
-   vma_copy-vm_mm = NULL;
-   vma_copy-vm_next = NULL;
-   vma_copy-vm_prev = NULL;
-
-   return vma_copy;
-}
-EXPORT_SYMBOL_GPL(vb2_get_vma);
-
-/**
- * vb2_put_userptr() - release a userspace virtual memory area
- * @vma:   virtual memory region associated with the area to be released
- *
- * This function releases the previously acquired memory area after a hardware
- * operation.
- */
-void vb2_put_vma(struct vm_area_struct *vma)
-{
-   if (!vma)
-   return;
-
-   if (vma-vm_ops  vma-vm_ops-close)
-   vma-vm_ops-close(vma);
-
-   if (vma-vm_file)
-   fput(vma-vm_file);
-
-   kfree(vma);
-}
-EXPORT_SYMBOL_GPL(vb2_put_vma);
-
-/**
- * vb2_get_contig_userptr() - lock physically contiguous userspace mapped 
memory
- * @vaddr: starting virtual address of the area to be verified
- * @size:  size of the area
- * @res_paddr: will return physical address for the given vaddr
- * @res_vma:   will return locked copy of struct vm_area for the given area
- *
- * This function will go through memory area of size @size mapped at @vaddr and
- * verify that the underlying physical pages are contiguous. If they are
- * contiguous the virtual memory area is locked and a @res_vma is filled with
- * the copy and @res_pa set to the physical address of the buffer.
- *
- * Returns 0 on success.
- */
-int vb2_get_contig_userptr(unsigned long vaddr, unsigned long size,
-  struct vm_area_struct **res_vma, dma_addr_t *res_pa)
-{
-   struct mm_struct *mm = current-mm;
-   struct vm_area_struct *vma;
-   unsigned long offset, start, end;
-   unsigned long this_pfn, prev_pfn;
-   dma_addr_t pa = 0;
-
-   start = vaddr;
-   offset = start  ~PAGE_MASK;
-   end = start + size;
-
-   vma = find_vma(mm, start);
-
-   if (vma == NULL || vma-vm_end  end)
-   return -EFAULT;
-
-   for (prev_pfn = 0; start  end; start += PAGE_SIZE) {
-   int ret = follow_pfn(vma, start, this_pfn);
-   if (ret)
-   return ret;
-
-   if (prev_pfn == 0)
-   pa = this_pfn  PAGE_SHIFT;
-   else if (this_pfn != prev_pfn + 1)
-   return -EFAULT;
-
-   prev_pfn = this_pfn;
-   }
-
-   /*
-* Memory is contigous, lock vma and return to the caller
-*/
-   *res_vma = vb2_get_vma(vma);
-   if (*res_vma == NULL)
-   return -ENOMEM;
-
-   *res_pa = pa + offset;
-   return 0;
-}
-EXPORT_SYMBOL_GPL(vb2_get_contig_userptr);
-
-/**
  * vb2_create_pfnvec() - map virtual addresses to pfns
  * @start: Virtual user address where we start mapping
  * @length:Length of a range to map
diff --git a/include/media/videobuf2-memops.h b/include/media/videobuf2-memops.h
index 868f9c1cd92d..01b4325947f1 100644
--- a/include/media/videobuf2-memops.h
+++ b/include/media/videobuf2-memops.h
@@ -31,12 +31,6 @@ struct vb2_vmarea_handler {
 
 extern const struct vm_operations_struct vb2_common_vm_ops;
 
-int vb2_get_contig_userptr(unsigned long vaddr, unsigned long size,
-  struct vm_area_struct **res_vma, dma_addr_t *res_pa);
-
-struct vm_area_struct *vb2_get_vma(struct vm_area_struct *vma);
-void vb2_put_vma(struct vm_area_struct *vma);
-
 struct pinned_pfns *vb2_create_pfnvec(unsigned long start, unsigned long 
length

[PATCH 7/9] media: vb2: Convert vb2_dc_get_userptr() to use pfns vector

2015-03-17 Thread Jan Kara
Convert vb2_dc_get_userptr() to use passed vector of pfns. When we are
doing that there's no need to allocate page array and some code can be
simplified.

Signed-off-by: Jan Kara j...@suse.cz
---
 drivers/media/v4l2-core/videobuf2-dma-contig.c | 213 -
 1 file changed, 32 insertions(+), 181 deletions(-)

diff --git a/drivers/media/v4l2-core/videobuf2-dma-contig.c 
b/drivers/media/v4l2-core/videobuf2-dma-contig.c
index 96eceabb307b..d3cefc5c98bc 100644
--- a/drivers/media/v4l2-core/videobuf2-dma-contig.c
+++ b/drivers/media/v4l2-core/videobuf2-dma-contig.c
@@ -32,15 +32,13 @@ struct vb2_dc_buf {
dma_addr_t  dma_addr;
enum dma_data_direction dma_dir;
struct sg_table *dma_sgt;
+   struct pinned_pfns  *pfns;
 
/* MMAP related */
struct vb2_vmarea_handler   handler;
atomic_trefcount;
struct sg_table *sgt_base;
 
-   /* USERPTR related */
-   struct vm_area_struct   *vma;
-
/* DMABUF related */
struct dma_buf_attachment   *db_attach;
 };
@@ -49,24 +47,6 @@ struct vb2_dc_buf {
 /*scatterlist table functions*/
 /*/
 
-
-static void vb2_dc_sgt_foreach_page(struct sg_table *sgt,
-   void (*cb)(struct page *pg))
-{
-   struct scatterlist *s;
-   unsigned int i;
-
-   for_each_sg(sgt-sgl, s, sgt-orig_nents, i) {
-   struct page *page = sg_page(s);
-   unsigned int n_pages = PAGE_ALIGN(s-offset + s-length)
-PAGE_SHIFT;
-   unsigned int j;
-
-   for (j = 0; j  n_pages; ++j, ++page)
-   cb(page);
-   }
-}
-
 static unsigned long vb2_dc_get_contiguous_size(struct sg_table *sgt)
 {
struct scatterlist *s;
@@ -423,92 +403,12 @@ static struct dma_buf *vb2_dc_get_dmabuf(void *buf_priv, 
unsigned long flags)
 /*   callbacks for USERPTR buffers   */
 /*/
 
-static inline int vma_is_io(struct vm_area_struct *vma)
-{
-   return !!(vma-vm_flags  (VM_IO | VM_PFNMAP));
-}
-
-static int vb2_dc_get_user_pfn(unsigned long start, int n_pages,
-   struct vm_area_struct *vma, unsigned long *res)
-{
-   unsigned long pfn, start_pfn, prev_pfn;
-   unsigned int i;
-   int ret;
-
-   if (!vma_is_io(vma))
-   return -EFAULT;
-
-   ret = follow_pfn(vma, start, pfn);
-   if (ret)
-   return ret;
-
-   start_pfn = pfn;
-   start += PAGE_SIZE;
-
-   for (i = 1; i  n_pages; ++i, start += PAGE_SIZE) {
-   prev_pfn = pfn;
-   ret = follow_pfn(vma, start, pfn);
-
-   if (ret) {
-   pr_err(no page for address %lu\n, start);
-   return ret;
-   }
-   if (pfn != prev_pfn + 1)
-   return -EINVAL;
-   }
-
-   *res = start_pfn;
-   return 0;
-}
-
-static int vb2_dc_get_user_pages(unsigned long start, struct page **pages,
-   int n_pages, struct vm_area_struct *vma,
-   enum dma_data_direction dma_dir)
-{
-   if (vma_is_io(vma)) {
-   unsigned int i;
-
-   for (i = 0; i  n_pages; ++i, start += PAGE_SIZE) {
-   unsigned long pfn;
-   int ret = follow_pfn(vma, start, pfn);
-
-   if (!pfn_valid(pfn))
-   return -EINVAL;
-
-   if (ret) {
-   pr_err(no page for address %lu\n, start);
-   return ret;
-   }
-   pages[i] = pfn_to_page(pfn);
-   }
-   } else {
-   int n;
-
-   n = get_user_pages(current, current-mm, start  PAGE_MASK,
-   n_pages, dma_dir == DMA_FROM_DEVICE, 1, pages, NULL);
-   /* negative error means that no page was pinned */
-   n = max(n, 0);
-   if (n != n_pages) {
-   pr_err(got only %d of %d user pages\n, n, n_pages);
-   while (n)
-   put_page(pages[--n]);
-   return -EFAULT;
-   }
-   }
-
-   return 0;
-}
-
-static void vb2_dc_put_dirty_page(struct page *page)
-{
-   set_page_dirty_lock(page);
-   put_page(page);
-}
-
 static void vb2_dc_put_userptr(void *buf_priv)
 {
struct vb2_dc_buf *buf = buf_priv;
struct sg_table *sgt = buf-dma_sgt;
+   int i;
+   struct page **pages;
 
if (sgt) {
DEFINE_DMA_ATTRS(attrs);
@@ -520,15 +420,13 @@ static void vb2_dc_put_userptr(void *buf_priv)
 */
dma_unmap_sg_attrs(buf-dev, sgt-sgl, sgt-orig_nents,
   buf-dma_dir

[PATCH 3/9] media: omap_vout: Convert omap_vout_uservirt_to_phys() to use get_vaddr_pfns()

2015-03-17 Thread Jan Kara
Convert omap_vout_uservirt_to_phys() to use get_vaddr_pfns() instead of
hand made mapping of virtual address to physical address. Also the
function leaked page reference from get_user_pages() so fix that by
properly release the reference when omap_vout_buffer_release() is
called.

Signed-off-by: Jan Kara j...@suse.cz
---
 drivers/media/platform/omap/omap_vout.c | 67 +++--
 1 file changed, 31 insertions(+), 36 deletions(-)

diff --git a/drivers/media/platform/omap/omap_vout.c 
b/drivers/media/platform/omap/omap_vout.c
index ba2d8f973d58..e7d342bb71dd 100644
--- a/drivers/media/platform/omap/omap_vout.c
+++ b/drivers/media/platform/omap/omap_vout.c
@@ -195,46 +195,34 @@ static int omap_vout_try_format(struct v4l2_pix_format 
*pix)
 }
 
 /*
- * omap_vout_uservirt_to_phys: This inline function is used to convert user
- * space virtual address to physical address.
+ * omap_vout_get_userptr: Convert user space virtual address to physical
+ * address.
  */
-static unsigned long omap_vout_uservirt_to_phys(unsigned long virtp)
+static int omap_vout_get_userptr(struct videobuf_buffer *vb, u32 virtp,
+u32 *physp)
 {
-   unsigned long physp = 0;
-   struct vm_area_struct *vma;
-   struct mm_struct *mm = current-mm;
+   struct pinned_pfns *pfns;
+   int ret;
 
/* For kernel direct-mapped memory, take the easy way */
-   if (virtp = PAGE_OFFSET)
-   return virt_to_phys((void *) virtp);
-
-   down_read(current-mm-mmap_sem);
-   vma = find_vma(mm, virtp);
-   if (vma  (vma-vm_flags  VM_IO)  vma-vm_pgoff) {
-   /* this will catch, kernel-allocated, mmaped-to-usermode
-  addresses */
-   physp = (vma-vm_pgoff  PAGE_SHIFT) + (virtp - vma-vm_start);
-   up_read(current-mm-mmap_sem);
-   } else {
-   /* otherwise, use get_user_pages() for general userland pages */
-   int res, nr_pages = 1;
-   struct page *pages;
+   if (virtp = PAGE_OFFSET) {
+   *physp = virt_to_phys((void *)virtp);
+   return 0;
+   }
 
-   res = get_user_pages(current, current-mm, virtp, nr_pages, 1,
-   0, pages, NULL);
-   up_read(current-mm-mmap_sem);
+   pfns = pfns_vector_create(1);
+   if (!pfns)
+   return -ENOMEM;
 
-   if (res == nr_pages) {
-   physp =  __pa(page_address(pages[0]) +
-   (virtp  ~PAGE_MASK));
-   } else {
-   printk(KERN_WARNING VOUT_NAME
-   get_user_pages failed\n);
-   return 0;
-   }
+   ret = get_vaddr_pfns(virtp, 1, 1, 0, pfns);
+   if (ret != 1) {
+   pfns_vector_destroy(pfns);
+   return -EINVAL;
}
+   *physp = __pfn_to_phys(pfns_vector_pfns(pfns)[0]);
+   vb-priv = pfns;
 
-   return physp;
+   return 0;
 }
 
 /*
@@ -788,11 +776,15 @@ static int omap_vout_buffer_prepare(struct videobuf_queue 
*q,
 * address of the buffer
 */
if (V4L2_MEMORY_USERPTR == vb-memory) {
+   int ret;
+
if (0 == vb-baddr)
return -EINVAL;
/* Physical address */
-   vout-queued_buf_addr[vb-i] = (u8 *)
-   omap_vout_uservirt_to_phys(vb-baddr);
+   ret = omap_vout_get_userptr(vb, vb-baddr,
+   (u32 *)vout-queued_buf_addr[vb-i]);
+   if (ret  0)
+   return ret;
} else {
unsigned long addr, dma_addr;
unsigned long size;
@@ -841,9 +833,12 @@ static void omap_vout_buffer_release(struct videobuf_queue 
*q,
struct omap_vout_device *vout = q-priv_data;
 
vb-state = VIDEOBUF_NEEDS_INIT;
+   if (vb-memory == V4L2_MEMORY_USERPTR  vb-priv) {
+   struct pinned_pfns *pfns = vb-priv;
 
-   if (V4L2_MEMORY_MMAP != vout-memory)
-   return;
+   put_vaddr_pfns(pfns);
+   pfns_vector_destroy(pfns);
+   }
 }
 
 /*
-- 
2.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-media in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 6/9] media: vb2: Convert vb2_vmalloc_get_userptr() to use pfns vector

2015-03-17 Thread Jan Kara
Convert vb2_vmalloc_get_userptr() to use passed vector of pfns. When we
are doing that there's no need to allocate page array and some code can
be simplified.

Signed-off-by: Jan Kara j...@suse.cz
---
 drivers/media/v4l2-core/videobuf2-vmalloc.c | 94 +++--
 1 file changed, 36 insertions(+), 58 deletions(-)

diff --git a/drivers/media/v4l2-core/videobuf2-vmalloc.c 
b/drivers/media/v4l2-core/videobuf2-vmalloc.c
index c060cf9662fa..eb1d9971c54e 100644
--- a/drivers/media/v4l2-core/videobuf2-vmalloc.c
+++ b/drivers/media/v4l2-core/videobuf2-vmalloc.c
@@ -23,11 +23,9 @@
 
 struct vb2_vmalloc_buf {
void*vaddr;
-   struct page **pages;
-   struct vm_area_struct   *vma;
+   struct pinned_pfns  *pfns;
enum dma_data_direction dma_dir;
unsigned long   size;
-   unsigned intn_pages;
atomic_trefcount;
struct vb2_vmarea_handler   handler;
struct dma_buf  *dbuf;
@@ -76,10 +74,8 @@ static void *vb2_vmalloc_get_userptr(void *alloc_ctx, 
unsigned long vaddr,
 enum dma_data_direction dma_dir)
 {
struct vb2_vmalloc_buf *buf;
-   unsigned long first, last;
-   int n_pages, offset;
-   struct vm_area_struct *vma;
-   dma_addr_t physp;
+   struct pinned_pfns *pfns;
+   int n_pages, offset, i;
 
buf = kzalloc(sizeof(*buf), GFP_KERNEL);
if (!buf)
@@ -88,53 +84,36 @@ static void *vb2_vmalloc_get_userptr(void *alloc_ctx, 
unsigned long vaddr,
buf-dma_dir = dma_dir;
offset = vaddr  ~PAGE_MASK;
buf-size = size;
-
-   down_read(current-mm-mmap_sem);
-   vma = find_vma(current-mm, vaddr);
-   if (vma  (vma-vm_flags  VM_PFNMAP)  (vma-vm_pgoff)) {
-   if (vb2_get_contig_userptr(vaddr, size, vma, physp))
-   goto fail_pages_array_alloc;
-   buf-vma = vma;
-   buf-vaddr = (__force void *)ioremap_nocache(physp, size);
-   if (!buf-vaddr)
-   goto fail_pages_array_alloc;
+   pfns = vb2_create_pfnvec(vaddr, size, dma_dir == DMA_FROM_DEVICE);
+   if (IS_ERR(pfns))
+   goto fail_pfnvec_create;
+   buf-pfns = pfns;
+   n_pages = pfns_vector_count(pfns);
+   if (pfns_vector_to_pages(pfns)  0) {
+   unsigned long *nums = pfns_vector_pfns(pfns);
+
+   /*
+* We cannot get page pointers for these pfns. Check memory is
+* physically contiguous and use direct mapping.
+*/
+   for (i = 1; i  n_pages; i++)
+   if (nums[i-1] + 1 != nums[i])
+   goto fail_map;
+   buf-vaddr = (__force void *)
+   ioremap_nocache(nums[0]  PAGE_SHIFT, size);
} else {
-   first = vaddr  PAGE_SHIFT;
-   last  = (vaddr + size - 1)  PAGE_SHIFT;
-   buf-n_pages = last - first + 1;
-   buf-pages = kzalloc(buf-n_pages * sizeof(struct page *),
-GFP_KERNEL);
-   if (!buf-pages)
-   goto fail_pages_array_alloc;
-
-   /* current-mm-mmap_sem is taken by videobuf2 core */
-   n_pages = get_user_pages(current, current-mm,
-vaddr  PAGE_MASK, buf-n_pages,
-dma_dir == DMA_FROM_DEVICE,
-1, /* force */
-buf-pages, NULL);
-   if (n_pages != buf-n_pages)
-   goto fail_get_user_pages;
-
-   buf-vaddr = vm_map_ram(buf-pages, buf-n_pages, -1,
+   buf-vaddr = vm_map_ram(pfns_vector_pages(pfns), n_pages, -1,
PAGE_KERNEL);
-   if (!buf-vaddr)
-   goto fail_get_user_pages;
}
-   up_read(current-mm-mmap_sem);
 
+   if (!buf-vaddr)
+   goto fail_map;
buf-vaddr += offset;
return buf;
 
-fail_get_user_pages:
-   pr_debug(get_user_pages requested/got: %d/%d]\n, n_pages,
-buf-n_pages);
-   while (--n_pages = 0)
-   put_page(buf-pages[n_pages]);
-   kfree(buf-pages);
-
-fail_pages_array_alloc:
-   up_read(current-mm-mmap_sem);
+fail_map:
+   vb2_destroy_pfnvec(pfns);
+fail_pfnvec_create:
kfree(buf);
 
return NULL;
@@ -145,22 +124,21 @@ static void vb2_vmalloc_put_userptr(void *buf_priv)
struct vb2_vmalloc_buf *buf = buf_priv;
unsigned long vaddr = (unsigned long)buf-vaddr  PAGE_MASK;
unsigned int i;
+   struct page **pages;
+   unsigned int n_pages;
 
-   down_read(current-mm-mmap_sem

[PATCH 4/9] vb2: Provide helpers for mapping virtual addresses

2015-03-17 Thread Jan Kara
Provide simple helper functions to map virtual address range into an
array of pfns.

Signed-off-by: Jan Kara j...@suse.cz
---
 drivers/media/v4l2-core/videobuf2-memops.c | 57 ++
 include/media/videobuf2-memops.h   |  4 +++
 2 files changed, 61 insertions(+)

diff --git a/drivers/media/v4l2-core/videobuf2-memops.c 
b/drivers/media/v4l2-core/videobuf2-memops.c
index 81c1ad8b2cf1..80ade22b920c 100644
--- a/drivers/media/v4l2-core/videobuf2-memops.c
+++ b/drivers/media/v4l2-core/videobuf2-memops.c
@@ -137,6 +137,63 @@ int vb2_get_contig_userptr(unsigned long vaddr, unsigned 
long size,
 EXPORT_SYMBOL_GPL(vb2_get_contig_userptr);
 
 /**
+ * vb2_create_pfnvec() - map virtual addresses to pfns
+ * @start: Virtual user address where we start mapping
+ * @length:Length of a range to map
+ * @write: Should we map for writing into the area
+ *
+ * This function allocates and fills in a vector with pfns corresponding to
+ * virtual address range passed in arguments. If pfns have corresponding pages,
+ * page references are also grabbed to pin pages in memory. The function
+ * returns pointer to the vector on success and error pointer in case of
+ * failure. Returned vector needs to be freed via vb2_destroy_pfnvec().
+ */
+struct pinned_pfns *vb2_create_pfnvec(unsigned long start, unsigned long 
length,
+ bool write)
+{
+   int ret;
+   unsigned long first, last;
+   unsigned long nr;
+   struct pinned_pfns *pfns;
+
+   first = start  PAGE_SHIFT;
+   last = (start + length - 1)  PAGE_SHIFT;
+   nr = last - first + 1;
+   pfns = pfns_vector_create(nr);
+   if (!pfns)
+   return ERR_PTR(-ENOMEM);
+   ret = get_vaddr_pfns(start, nr, write, 1, pfns);
+   if (ret  0)
+   goto out_destroy;
+   /* We accept only complete set of PFNs */
+   if (ret != nr) {
+   ret = -EFAULT;
+   goto out_release;
+   }
+   return pfns;
+out_release:
+   put_vaddr_pfns(pfns);
+out_destroy:
+   pfns_vector_destroy(pfns);
+   return ERR_PTR(ret);
+}
+EXPORT_SYMBOL(vb2_create_pfnvec);
+
+/**
+ * vb2_destroy_pfnvec() - release vector of mapped pfns
+ * @pfns:  vector of pfns to release
+ *
+ * This releases references to all pages in the vector @pfns (if corresponding
+ * pfns are backed by pages) and frees the passed vector.
+ */
+void vb2_destroy_pfnvec(struct pinned_pfns *pfns)
+{
+   put_vaddr_pfns(pfns);
+   pfns_vector_destroy(pfns);
+}
+EXPORT_SYMBOL(vb2_destroy_pfnvec);
+
+/**
  * vb2_common_vm_open() - increase refcount of the vma
  * @vma:   virtual memory region for the mapping
  *
diff --git a/include/media/videobuf2-memops.h b/include/media/videobuf2-memops.h
index f05444ca8c0c..868f9c1cd92d 100644
--- a/include/media/videobuf2-memops.h
+++ b/include/media/videobuf2-memops.h
@@ -15,6 +15,7 @@
 #define _MEDIA_VIDEOBUF2_MEMOPS_H
 
 #include media/videobuf2-core.h
+#include linux/mm.h
 
 /**
  * vb2_vmarea_handler - common vma refcount tracking handler
@@ -36,5 +37,8 @@ int vb2_get_contig_userptr(unsigned long vaddr, unsigned long 
size,
 struct vm_area_struct *vb2_get_vma(struct vm_area_struct *vma);
 void vb2_put_vma(struct vm_area_struct *vma);
 
+struct pinned_pfns *vb2_create_pfnvec(unsigned long start, unsigned long 
length,
+ bool write);
+void vb2_destroy_pfnvec(struct pinned_pfns *pfns);
 
 #endif
-- 
2.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-media in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Use of mmap_sem in __qbuf_userptr()

2015-03-05 Thread Jan Kara
  Hello,

  so after a long pause I've got back to my simplification patches around
get_user_pages(). After the simplification done by commit f035eb4e976ef5
(videobuf2: fix lockdep warning) it seems unnecessary to take mmap_sem
already when calling __qbuf_userptr(). As far as I understand what
__qbuf_userptr() does, the only thing where mmap_sem is needed is for
get_userptr and possibly put_userptr memops. So it should be possible to
push mmap_sem locking down into these memops, shouldn't it? Or am I missing
something in __qbuf_userptr() for which mmap_sem is also necessary?

If I'm right, I can prepare patches to do that (and then on top of those
rebase patches which will make v4l2 core use some mm helper functions so
they don't have to care about details of mm locking, vmas, etc.).

Honza
-- 
Jan Kara j...@suse.cz
SUSE Labs, CR
--
To unsubscribe from this list: send the line unsubscribe linux-media in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCHv2] videobuf2-core: take mmap_sem before calling __qbuf_userptr

2014-08-26 Thread Jan Kara
On Fri 22-08-14 23:31:31, Hans Verkuil wrote:
 (Changes since v1: fix the embarrassing bug where mmap_sem wasn't initialized)
 
 Commit f035eb4e976ef5a059e30bc91cfd310ff030a7d3 (videobuf2: fix lockdep 
 warning)
 unfortunately removed the mmap_sem lock that is needed around the call to
 __qbuf_userptr. Amazingly nobody noticed this (especially me as the author)
 until Jan Kara pointed this out to me.
 
 Signed-off-by: Hans Verkuil hans.verk...@cisco.com
 Reported-by: Jan Kara j...@suse.cz
  The patch looks good to me. You can add:
Reviewed-by: Jan Kara j...@suse.cz

Honza

 ---
  drivers/media/v4l2-core/videobuf2-core.c | 4 
  1 file changed, 4 insertions(+)
 
 diff --git a/drivers/media/v4l2-core/videobuf2-core.c 
 b/drivers/media/v4l2-core/videobuf2-core.c
 index 5b808e2..a0ab6af 100644
 --- a/drivers/media/v4l2-core/videobuf2-core.c
 +++ b/drivers/media/v4l2-core/videobuf2-core.c
 @@ -1591,6 +1591,7 @@ static void __enqueue_in_driver(struct vb2_buffer *vb)
  static int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b)
  {
   struct vb2_queue *q = vb-vb2_queue;
 + struct rw_semaphore *mmap_sem;
   int ret;
  
   ret = __verify_length(vb, b);
 @@ -1627,7 +1628,10 @@ static int __buf_prepare(struct vb2_buffer *vb, const 
 struct v4l2_buffer *b)
   ret = __qbuf_mmap(vb, b);
   break;
   case V4L2_MEMORY_USERPTR:
 + mmap_sem = current-mm-mmap_sem;
 + down_read(mmap_sem);
   ret = __qbuf_userptr(vb, b);
 + up_read(mmap_sem);
   break;
   case V4L2_MEMORY_DMABUF:
   ret = __qbuf_dmabuf(vb, b);
 -- 
 2.0.1
 
-- 
Jan Kara j...@suse.cz
SUSE Labs, CR
--
To unsubscribe from this list: send the line unsubscribe linux-media in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH] videobuf2-core: take mmap_sem before calling __qbuf_userptr

2014-08-22 Thread Jan Kara
On Fri 22-08-14 18:01:09, Hans Verkuil wrote:
 Commit f035eb4e976ef5a059e30bc91cfd310ff030a7d3 (videobuf2: fix lockdep 
 warning)
 unfortunately removed the mmap_sem lock that is needed around the call to
 __qbuf_userptr. Amazingly nobody noticed this until Jan Kara pointed this out
 to me.
 
 Signed-off-by: Hans Verkuil hans.verk...@cisco.com
 Reported-by: Jan Kara j...@suse.cz
...
 @@ -1627,7 +1628,9 @@ static int __buf_prepare(struct vb2_buffer *vb, const 
 struct v4l2_buffer *b)
   ret = __qbuf_mmap(vb, b);
   break;
   case V4L2_MEMORY_USERPTR:
  I guess you are missing something like:

mmap_sem = current-mm-mmap_sem;

Honza
 + down_read(mmap_sem);
   ret = __qbuf_userptr(vb, b);
 + up_read(mmap_sem);
   break;
   case V4L2_MEMORY_DMABUF:
   ret = __qbuf_dmabuf(vb, b);
 -- 
 2.0.1
 
-- 
Jan Kara j...@suse.cz
SUSE Labs, CR
--
To unsubscribe from this list: send the line unsubscribe linux-media in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [RFC] Helper to abstract vma handling in media layer

2014-04-14 Thread Jan Kara
On Fri 11-04-14 08:58:59, Hans Verkuil wrote:
 On 04/11/2014 12:18 AM, Jan Kara wrote:
  On Thu 10-04-14 23:57:38, Jan Kara wrote:
  On Thu 10-04-14 14:22:20, Hans Verkuil wrote:
  On 04/10/14 14:15, Jan Kara wrote:
  On Thu 10-04-14 13:07:42, Hans Verkuil wrote:
  On 04/10/14 12:32, Jan Kara wrote:
Hello,
 
  On Thu 10-04-14 12:02:50, Marek Szyprowski wrote:
  On 2014-03-17 20:49, Jan Kara wrote:
The following patch series is my first stab at abstracting vma 
  handling
  from the various media drivers. After this patch set drivers have to 
  know
  much less details about vmas, their types, and locking. My 
  motivation for
  the series is that I want to change get_user_pages() locking and I 
  want
  to handle subtle locking details in as few places as possible.
 
  The core of the series is the new helper get_vaddr_pfns() which is 
  given a
  virtual address and it fills in PFNs into provided array. If PFNs 
  correspond to
  normal pages it also grabs references to these pages. The difference 
  from
  get_user_pages() is that this function can also deal with pfnmap, 
  mixed, and io
  mappings which is what the media drivers need.
 
  The patches are just compile tested (since I don't have any of the 
  hardware
  I'm afraid I won't be able to do any more testing anyway) so please 
  handle
  with care. I'm grateful for any comments.
 
  Thanks for posting this series! I will check if it works with our
  hardware soon.  This is something I wanted to introduce some time ago 
  to
  simplify buffer handling in dma-buf, but I had no time to start 
  working.
Thanks for having a look in the series.
 
  However I would like to go even further with integration of your pfn
  vector idea.  This structure looks like a best solution for a compact
  representation of the memory buffer, which should be considered by the
  hardware as contiguous (either contiguous in physical memory or mapped
  contiguously into dma address space by the respective iommu). As you
  already noticed it is widely used by graphics and video drivers.
 
  I would also like to add support for pfn vector directly to the
  dma-mapping subsystem. This can be done quite easily (even with a
  fallback for architectures which don't provide method for it). I will 
  try
  to prepare rfc soon.  This will finally remove the need for hacks in
  media/v4l2-core/videobuf2-dma-contig.c
That would be a worthwhile thing to do. When I was reading the code 
  this
  seemed like something which could be done but I delibrately avoided 
  doing
  more unification than necessary for my purposes as I don't have any
  hardware to test and don't know all the subtleties in the code... BTW, 
  is
  there some way to test the drivers without the physical video HW?
 
  You can use the vivi driver (drivers/media/platform/vivi) for this.
  However, while the vivi driver can import dma buffers it cannot export
  them. If you want that, then you have to use this tree:
 
  http://git.linuxtv.org/cgit.cgi/hverkuil/media_tree.git/log/?h=vb2-part4
Thanks for the pointer that looks good. I've also found
  drivers/media/platform/mem2mem_testdev.c which seems to do even more
  testing of the area I made changes to. So now I have to find some 
  userspace
  tool which can issue proper ioctls to setup and use the buffers and I can
  start testing what I wrote :)
 
  Get the v4l-utils.git repository 
  (http://git.linuxtv.org/cgit.cgi/v4l-utils.git/).
  You want the v4l2-ctl tool. Don't use the version supplied by your distro,
  that's often too old.
 
  'v4l2-ctl --help-streaming' gives the available options for doing 
  streaming.
 
  So simple capturing from vivi is 'v4l2-ctl --stream-mmap' or 
  '--stream-user'.
  You can't test dmabuf unless you switch to the vb2-part4 branch of my 
  tree.
Great, it seems to be doing something and it shows there's some bug in my
  code. Thanks a lot for help.
OK, so after a small fix the basic functionality seems to be working. It
  doesn't seem there's a way to test multiplanar buffers with vivi, is there?
 
 For that you need to switch to the vb2-part4 branch as well. That has support
 for multiplanar.
  OK, I've merged that branch to my kernel but I failed to find the setting
for vivi that would create multiplanar buffers and in fact I don't see
multiplanar capabilities among the capabilities reported by the v4l2-ctl
tool. Can you help me please?

Honza
-- 
Jan Kara j...@suse.cz
SUSE Labs, CR
--
To unsubscribe from this list: send the line unsubscribe linux-media in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [RFC] Helper to abstract vma handling in media layer

2014-04-10 Thread Jan Kara
  Hello,

On Thu 10-04-14 12:02:50, Marek Szyprowski wrote:
 On 2014-03-17 20:49, Jan Kara wrote:
The following patch series is my first stab at abstracting vma handling
 from the various media drivers. After this patch set drivers have to know
 much less details about vmas, their types, and locking. My motivation for
 the series is that I want to change get_user_pages() locking and I want
 to handle subtle locking details in as few places as possible.
 
 The core of the series is the new helper get_vaddr_pfns() which is given a
 virtual address and it fills in PFNs into provided array. If PFNs correspond 
 to
 normal pages it also grabs references to these pages. The difference from
 get_user_pages() is that this function can also deal with pfnmap, mixed, and 
 io
 mappings which is what the media drivers need.
 
 The patches are just compile tested (since I don't have any of the hardware
 I'm afraid I won't be able to do any more testing anyway) so please handle
 with care. I'm grateful for any comments.
 
 Thanks for posting this series! I will check if it works with our
 hardware soon.  This is something I wanted to introduce some time ago to
 simplify buffer handling in dma-buf, but I had no time to start working.
  Thanks for having a look in the series.

 However I would like to go even further with integration of your pfn
 vector idea.  This structure looks like a best solution for a compact
 representation of the memory buffer, which should be considered by the
 hardware as contiguous (either contiguous in physical memory or mapped
 contiguously into dma address space by the respective iommu). As you
 already noticed it is widely used by graphics and video drivers.
 
 I would also like to add support for pfn vector directly to the
 dma-mapping subsystem. This can be done quite easily (even with a
 fallback for architectures which don't provide method for it). I will try
 to prepare rfc soon.  This will finally remove the need for hacks in
 media/v4l2-core/videobuf2-dma-contig.c
  That would be a worthwhile thing to do. When I was reading the code this
seemed like something which could be done but I delibrately avoided doing
more unification than necessary for my purposes as I don't have any
hardware to test and don't know all the subtleties in the code... BTW, is
there some way to test the drivers without the physical video HW?

Honza
-- 
Jan Kara j...@suse.cz
SUSE Labs, CR
--
To unsubscribe from this list: send the line unsubscribe linux-media in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [RFC] Helper to abstract vma handling in media layer

2014-04-10 Thread Jan Kara
On Thu 10-04-14 13:07:42, Hans Verkuil wrote:
 On 04/10/14 12:32, Jan Kara wrote:
Hello,
  
  On Thu 10-04-14 12:02:50, Marek Szyprowski wrote:
  On 2014-03-17 20:49, Jan Kara wrote:
The following patch series is my first stab at abstracting vma handling
  from the various media drivers. After this patch set drivers have to know
  much less details about vmas, their types, and locking. My motivation for
  the series is that I want to change get_user_pages() locking and I want
  to handle subtle locking details in as few places as possible.
 
  The core of the series is the new helper get_vaddr_pfns() which is given a
  virtual address and it fills in PFNs into provided array. If PFNs 
  correspond to
  normal pages it also grabs references to these pages. The difference from
  get_user_pages() is that this function can also deal with pfnmap, mixed, 
  and io
  mappings which is what the media drivers need.
 
  The patches are just compile tested (since I don't have any of the 
  hardware
  I'm afraid I won't be able to do any more testing anyway) so please handle
  with care. I'm grateful for any comments.
 
  Thanks for posting this series! I will check if it works with our
  hardware soon.  This is something I wanted to introduce some time ago to
  simplify buffer handling in dma-buf, but I had no time to start working.
Thanks for having a look in the series.
  
  However I would like to go even further with integration of your pfn
  vector idea.  This structure looks like a best solution for a compact
  representation of the memory buffer, which should be considered by the
  hardware as contiguous (either contiguous in physical memory or mapped
  contiguously into dma address space by the respective iommu). As you
  already noticed it is widely used by graphics and video drivers.
 
  I would also like to add support for pfn vector directly to the
  dma-mapping subsystem. This can be done quite easily (even with a
  fallback for architectures which don't provide method for it). I will try
  to prepare rfc soon.  This will finally remove the need for hacks in
  media/v4l2-core/videobuf2-dma-contig.c
That would be a worthwhile thing to do. When I was reading the code this
  seemed like something which could be done but I delibrately avoided doing
  more unification than necessary for my purposes as I don't have any
  hardware to test and don't know all the subtleties in the code... BTW, is
  there some way to test the drivers without the physical video HW?
 
 You can use the vivi driver (drivers/media/platform/vivi) for this.
 However, while the vivi driver can import dma buffers it cannot export
 them. If you want that, then you have to use this tree:
 
 http://git.linuxtv.org/cgit.cgi/hverkuil/media_tree.git/log/?h=vb2-part4
  Thanks for the pointer that looks good. I've also found
drivers/media/platform/mem2mem_testdev.c which seems to do even more
testing of the area I made changes to. So now I have to find some userspace
tool which can issue proper ioctls to setup and use the buffers and I can
start testing what I wrote :)

Honza
-- 
Jan Kara j...@suse.cz
SUSE Labs, CR
--
To unsubscribe from this list: send the line unsubscribe linux-media in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


  1   2   >