All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jan Kara <jack@suse.cz>
To: Lorenzo Stoakes <lstoakes@gmail.com>
Cc: linux-mips@linux-mips.org, linux-fbdev@vger.kernel.org,
	Jan Kara <jack@suse.cz>,
	kvm@vger.kernel.org, linux-sh@vger.kernel.org,
	Dave Hansen <dave.hansen@linux.intel.com>,
	dri-devel@lists.freedesktop.org, linux-mm@kvack.org,
	netdev@vger.kernel.org, sparclinux@vger.kernel.org,
	linux-ia64@vger.kernel.org, linux-s390@vger.kernel.org,
	linux-samsung-soc@vger.kernel.org, linux-scsi@vger.kernel.org,
	linux-rdma@vger.kernel.org, x86@kernel.org,
	Hugh Dickins <hughd@google.com>,
	linux-media@vger.kernel.org, Rik van Riel <riel@redhat.com>,
	intel-gfx@lists.freedesktop.org,
	adi-buildroot-devel@lists.sourceforge.net,
	ceph-devel@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
	linux-cris-kernel@axis.com,
	Linus Torvalds <torvalds@linux-foundation.org>,
	linuxppc-dev@lists.ozlabs.org, linux-kernel@vger.kernel.org,
	linux-security-module@vger.kernel.org,
	linux-alpha@vger.kernel.orglin
Subject: Re: [PATCH 07/10] mm: replace get_user_pages_remote() write/force parameters with gup_flags
Date: Wed, 19 Oct 2016 07:47:07 +0000	[thread overview]
Message-ID: <20161019074707.GO29967@quack2.suse.cz> (raw)
In-Reply-To: <20161013002020.3062-8-lstoakes@gmail.com>

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 <lstoakes@gmail.com>

Looks good. You can add:

Reviewed-by: Jan Kara <jack@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(&mm->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->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,
> -				access_mask & ODP_WRITE_ALLOWED_BIT,
> -				0, local_page_list, NULL);
> +				flags, local_page_list, NULL);
>  		up_read(&owning_mm->mmap_sem);
>  
>  		if (npages < 0)
> diff --git a/fs/exec.c b/fs/exec.c
> index 6fcfb3f..4e497b9 100644
> --- a/fs/exec.c
> +++ b/fs/exec.c
> @@ -191,6 +191,7 @@ static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
>  {
>  	struct page *page;
>  	int ret;
> +	unsigned int gup_flags = FOLL_FORCE;
>  
>  #ifdef CONFIG_STACK_GROWSUP
>  	if (write) {
> @@ -199,12 +200,16 @@ static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
>  			return NULL;
>  	}
>  #endif
> +
> +	if (write)
> +		gup_flags |= FOLL_WRITE;
> +
>  	/*
>  	 * We are doing an exec().  'current' is the process
>  	 * doing the exec and bprm->mm is the new process's mm.
>  	 */
> -	ret = get_user_pages_remote(current, bprm->mm, pos, 1, write,
> -			1, &page, NULL);
> +	ret = get_user_pages_remote(current, bprm->mm, pos, 1, gup_flags,
> +			&page, NULL);
>  	if (ret <= 0)
>  		return NULL;
>  
> diff --git a/include/linux/mm.h b/include/linux/mm.h
> index 686a477..2a481d3 100644
> --- a/include/linux/mm.h
> +++ b/include/linux/mm.h
> @@ -1276,7 +1276,7 @@ long __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
>  		      struct vm_area_struct **vmas, int *nonblocking);
>  long get_user_pages_remote(struct task_struct *tsk, struct mm_struct *mm,
>  			    unsigned long start, unsigned long nr_pages,
> -			    int write, int force, struct page **pages,
> +			    unsigned int gup_flags, struct page **pages,
>  			    struct vm_area_struct **vmas);
>  long get_user_pages(unsigned long start, unsigned long nr_pages,
>  			    unsigned int gup_flags, struct page **pages,
> diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
> index d4129bb..f9ec9ad 100644
> --- a/kernel/events/uprobes.c
> +++ b/kernel/events/uprobes.c
> @@ -300,7 +300,8 @@ int uprobe_write_opcode(struct mm_struct *mm, unsigned long vaddr,
>  
>  retry:
>  	/* Read the page with vaddr into memory */
> -	ret = get_user_pages_remote(NULL, mm, vaddr, 1, 0, 1, &old_page, &vma);
> +	ret = get_user_pages_remote(NULL, mm, vaddr, 1, FOLL_FORCE, &old_page,
> +			&vma);
>  	if (ret <= 0)
>  		return ret;
>  
> @@ -1710,7 +1711,8 @@ static int is_trap_at_addr(struct mm_struct *mm, unsigned long vaddr)
>  	 * but we treat this as a 'remote' access since it is
>  	 * essentially a kernel access to the memory.
>  	 */
> -	result = get_user_pages_remote(NULL, mm, vaddr, 1, 0, 1, &page, NULL);
> +	result = get_user_pages_remote(NULL, mm, vaddr, 1, FOLL_FORCE, &page,
> +			NULL);
>  	if (result < 0)
>  		return result;
>  
> diff --git a/mm/gup.c b/mm/gup.c
> index dc91303..0deecf3 100644
> --- a/mm/gup.c
> +++ b/mm/gup.c
> @@ -905,9 +905,7 @@ EXPORT_SYMBOL(get_user_pages_unlocked);
>   * @mm:		mm_struct of target mm
>   * @start:	starting user address
>   * @nr_pages:	number of pages from start to pin
> - * @write:	whether pages will be written to by the caller
> - * @force:	whether to force access even when user mapping is currently
> - *		protected (but never forces write access to shared mapping).
> + * @gup_flags:	flags modifying lookup behaviour
>   * @pages:	array that receives pointers to the pages pinned.
>   *		Should be at least nr_pages long. Or NULL, if caller
>   *		only intends to ensure the pages are faulted in.
> @@ -936,9 +934,9 @@ EXPORT_SYMBOL(get_user_pages_unlocked);
>   * or similar operation cannot guarantee anything stronger anyway because
>   * locks can't be held over the syscall boundary.
>   *
> - * If write=0, the page must not be written to. If the page is written to,
> - * set_page_dirty (or set_page_dirty_lock, as appropriate) must be called
> - * after the page is finished with, and before put_page is called.
> + * If gup_flags & FOLL_WRITE = 0, the page must not be written to. If the page
> + * is written to, set_page_dirty (or set_page_dirty_lock, as appropriate) must
> + * be called after the page is finished with, and before put_page is called.
>   *
>   * get_user_pages is typically used for fewer-copy IO operations, to get a
>   * handle on the memory by some means other than accesses via the user virtual
> @@ -955,18 +953,12 @@ EXPORT_SYMBOL(get_user_pages_unlocked);
>   */
>  long get_user_pages_remote(struct task_struct *tsk, struct mm_struct *mm,
>  		unsigned long start, unsigned long nr_pages,
> -		int write, int force, struct page **pages,
> +		unsigned int gup_flags, struct page **pages,
>  		struct vm_area_struct **vmas)
>  {
> -	unsigned int flags = FOLL_TOUCH | FOLL_REMOTE;
> -
> -	if (write)
> -		flags |= FOLL_WRITE;
> -	if (force)
> -		flags |= FOLL_FORCE;
> -
>  	return __get_user_pages_locked(tsk, mm, start, nr_pages, pages, vmas,
> -				       NULL, false, flags);
> +				       NULL, false,
> +				       gup_flags | FOLL_TOUCH | FOLL_REMOTE);
>  }
>  EXPORT_SYMBOL(get_user_pages_remote);
>  
> diff --git a/mm/memory.c b/mm/memory.c
> index fc1987d..20a9adb 100644
> --- a/mm/memory.c
> +++ b/mm/memory.c
> @@ -3873,6 +3873,10 @@ static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm,
>  {
>  	struct vm_area_struct *vma;
>  	void *old_buf = buf;
> +	unsigned int flags = FOLL_FORCE;
> +
> +	if (write)
> +		flags |= FOLL_WRITE;
>  
>  	down_read(&mm->mmap_sem);
>  	/* ignore errors, just check how much was successfully transferred */
> @@ -3882,7 +3886,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,
> -				write, 1, &page, &vma);
> +				flags, &page, &vma);
>  		if (ret <= 0) {
>  #ifndef CONFIG_HAVE_IOREMAP_PROT
>  			break;
> diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c
> index ade7c6c..682b73a 100644
> --- a/security/tomoyo/domain.c
> +++ b/security/tomoyo/domain.c
> @@ -881,7 +881,7 @@ bool tomoyo_dump_page(struct linux_binprm *bprm, unsigned long pos,
>  	 * the execve().
>  	 */
>  	if (get_user_pages_remote(current, bprm->mm, pos, 1,
> -				0, 1, &page, NULL) <= 0)
> +				FOLL_FORCE, &page, NULL) <= 0)
>  		return false;
>  #else
>  	page = bprm->page[pos / PAGE_SIZE];
> -- 
> 2.10.0
> 
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR

WARNING: multiple messages have this Message-ID (diff)
From: Jan Kara <jack@suse.cz>
To: Lorenzo Stoakes <lstoakes@gmail.com>
Cc: linux-mips@linux-mips.org, linux-fbdev@vger.kernel.org,
	Jan Kara <jack@suse.cz>,
	kvm@vger.kernel.org, linux-sh@vger.kernel.org,
	Dave Hansen <dave.hansen@linux.intel.com>,
	dri-devel@lists.freedesktop.org, linux-mm@kvack.org,
	netdev@vger.kernel.org, sparclinux@vger.kernel.org,
	linux-ia64@vger.kernel.org, linux-s390@vger.kernel.org,
	linux-samsung-soc@vger.kernel.org, linux-scsi@vger.kernel.org,
	linux-rdma@vger.kernel.org, x86@kernel.org,
	Hugh Dickins <hughd@google.com>,
	linux-media@vger.kernel.org, Rik van Riel <riel@redhat.com>,
	intel-gfx@lists.freedesktop.org,
	adi-buildroot-devel@lists.sourceforge.net,
	ceph-devel@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
	linux-cris-kernel@axis.com,
	Linus Torvalds <torvalds@linux-foundation.org>,
	linuxppc-dev@lists.ozlabs.org, linux-kernel@vger.kernel.org,
	linux-security-module@vger.kernel.org,
	linux-alpha@vger.kernel.orglin
Subject: Re: [PATCH 07/10] mm: replace get_user_pages_remote() write/force parameters with gup_flags
Date: Wed, 19 Oct 2016 09:47:07 +0200	[thread overview]
Message-ID: <20161019074707.GO29967@quack2.suse.cz> (raw)
In-Reply-To: <20161013002020.3062-8-lstoakes@gmail.com>

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 <lstoakes@gmail.com>

Looks good. You can add:

Reviewed-by: Jan Kara <jack@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(&mm->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->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,
> -				access_mask & ODP_WRITE_ALLOWED_BIT,
> -				0, local_page_list, NULL);
> +				flags, local_page_list, NULL);
>  		up_read(&owning_mm->mmap_sem);
>  
>  		if (npages < 0)
> diff --git a/fs/exec.c b/fs/exec.c
> index 6fcfb3f..4e497b9 100644
> --- a/fs/exec.c
> +++ b/fs/exec.c
> @@ -191,6 +191,7 @@ static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
>  {
>  	struct page *page;
>  	int ret;
> +	unsigned int gup_flags = FOLL_FORCE;
>  
>  #ifdef CONFIG_STACK_GROWSUP
>  	if (write) {
> @@ -199,12 +200,16 @@ static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
>  			return NULL;
>  	}
>  #endif
> +
> +	if (write)
> +		gup_flags |= FOLL_WRITE;
> +
>  	/*
>  	 * We are doing an exec().  'current' is the process
>  	 * doing the exec and bprm->mm is the new process's mm.
>  	 */
> -	ret = get_user_pages_remote(current, bprm->mm, pos, 1, write,
> -			1, &page, NULL);
> +	ret = get_user_pages_remote(current, bprm->mm, pos, 1, gup_flags,
> +			&page, NULL);
>  	if (ret <= 0)
>  		return NULL;
>  
> diff --git a/include/linux/mm.h b/include/linux/mm.h
> index 686a477..2a481d3 100644
> --- a/include/linux/mm.h
> +++ b/include/linux/mm.h
> @@ -1276,7 +1276,7 @@ long __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
>  		      struct vm_area_struct **vmas, int *nonblocking);
>  long get_user_pages_remote(struct task_struct *tsk, struct mm_struct *mm,
>  			    unsigned long start, unsigned long nr_pages,
> -			    int write, int force, struct page **pages,
> +			    unsigned int gup_flags, struct page **pages,
>  			    struct vm_area_struct **vmas);
>  long get_user_pages(unsigned long start, unsigned long nr_pages,
>  			    unsigned int gup_flags, struct page **pages,
> diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
> index d4129bb..f9ec9ad 100644
> --- a/kernel/events/uprobes.c
> +++ b/kernel/events/uprobes.c
> @@ -300,7 +300,8 @@ int uprobe_write_opcode(struct mm_struct *mm, unsigned long vaddr,
>  
>  retry:
>  	/* Read the page with vaddr into memory */
> -	ret = get_user_pages_remote(NULL, mm, vaddr, 1, 0, 1, &old_page, &vma);
> +	ret = get_user_pages_remote(NULL, mm, vaddr, 1, FOLL_FORCE, &old_page,
> +			&vma);
>  	if (ret <= 0)
>  		return ret;
>  
> @@ -1710,7 +1711,8 @@ static int is_trap_at_addr(struct mm_struct *mm, unsigned long vaddr)
>  	 * but we treat this as a 'remote' access since it is
>  	 * essentially a kernel access to the memory.
>  	 */
> -	result = get_user_pages_remote(NULL, mm, vaddr, 1, 0, 1, &page, NULL);
> +	result = get_user_pages_remote(NULL, mm, vaddr, 1, FOLL_FORCE, &page,
> +			NULL);
>  	if (result < 0)
>  		return result;
>  
> diff --git a/mm/gup.c b/mm/gup.c
> index dc91303..0deecf3 100644
> --- a/mm/gup.c
> +++ b/mm/gup.c
> @@ -905,9 +905,7 @@ EXPORT_SYMBOL(get_user_pages_unlocked);
>   * @mm:		mm_struct of target mm
>   * @start:	starting user address
>   * @nr_pages:	number of pages from start to pin
> - * @write:	whether pages will be written to by the caller
> - * @force:	whether to force access even when user mapping is currently
> - *		protected (but never forces write access to shared mapping).
> + * @gup_flags:	flags modifying lookup behaviour
>   * @pages:	array that receives pointers to the pages pinned.
>   *		Should be at least nr_pages long. Or NULL, if caller
>   *		only intends to ensure the pages are faulted in.
> @@ -936,9 +934,9 @@ EXPORT_SYMBOL(get_user_pages_unlocked);
>   * or similar operation cannot guarantee anything stronger anyway because
>   * locks can't be held over the syscall boundary.
>   *
> - * If write=0, the page must not be written to. If the page is written to,
> - * set_page_dirty (or set_page_dirty_lock, as appropriate) must be called
> - * after the page is finished with, and before put_page is called.
> + * If gup_flags & FOLL_WRITE == 0, the page must not be written to. If the page
> + * is written to, set_page_dirty (or set_page_dirty_lock, as appropriate) must
> + * be called after the page is finished with, and before put_page is called.
>   *
>   * get_user_pages is typically used for fewer-copy IO operations, to get a
>   * handle on the memory by some means other than accesses via the user virtual
> @@ -955,18 +953,12 @@ EXPORT_SYMBOL(get_user_pages_unlocked);
>   */
>  long get_user_pages_remote(struct task_struct *tsk, struct mm_struct *mm,
>  		unsigned long start, unsigned long nr_pages,
> -		int write, int force, struct page **pages,
> +		unsigned int gup_flags, struct page **pages,
>  		struct vm_area_struct **vmas)
>  {
> -	unsigned int flags = FOLL_TOUCH | FOLL_REMOTE;
> -
> -	if (write)
> -		flags |= FOLL_WRITE;
> -	if (force)
> -		flags |= FOLL_FORCE;
> -
>  	return __get_user_pages_locked(tsk, mm, start, nr_pages, pages, vmas,
> -				       NULL, false, flags);
> +				       NULL, false,
> +				       gup_flags | FOLL_TOUCH | FOLL_REMOTE);
>  }
>  EXPORT_SYMBOL(get_user_pages_remote);
>  
> diff --git a/mm/memory.c b/mm/memory.c
> index fc1987d..20a9adb 100644
> --- a/mm/memory.c
> +++ b/mm/memory.c
> @@ -3873,6 +3873,10 @@ static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm,
>  {
>  	struct vm_area_struct *vma;
>  	void *old_buf = buf;
> +	unsigned int flags = FOLL_FORCE;
> +
> +	if (write)
> +		flags |= FOLL_WRITE;
>  
>  	down_read(&mm->mmap_sem);
>  	/* ignore errors, just check how much was successfully transferred */
> @@ -3882,7 +3886,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,
> -				write, 1, &page, &vma);
> +				flags, &page, &vma);
>  		if (ret <= 0) {
>  #ifndef CONFIG_HAVE_IOREMAP_PROT
>  			break;
> diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c
> index ade7c6c..682b73a 100644
> --- a/security/tomoyo/domain.c
> +++ b/security/tomoyo/domain.c
> @@ -881,7 +881,7 @@ bool tomoyo_dump_page(struct linux_binprm *bprm, unsigned long pos,
>  	 * the execve().
>  	 */
>  	if (get_user_pages_remote(current, bprm->mm, pos, 1,
> -				0, 1, &page, NULL) <= 0)
> +				FOLL_FORCE, &page, NULL) <= 0)
>  		return false;
>  #else
>  	page = bprm->page[pos / PAGE_SIZE];
> -- 
> 2.10.0
> 
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

WARNING: multiple messages have this Message-ID (diff)
From: Jan Kara <jack@suse.cz>
To: Lorenzo Stoakes <lstoakes@gmail.com>
Cc: linux-mm@kvack.org,
	Linus Torvalds <torvalds@linux-foundation.org>,
	Jan Kara <jack@suse.cz>, Hugh Dickins <hughd@google.com>,
	Dave Hansen <dave.hansen@linux.intel.com>,
	Rik van Riel <riel@redhat.com>,
	Mel Gorman <mgorman@techsingularity.net>,
	Andrew Morton <akpm@linux-foundation.org>,
	adi-buildroot-devel@lists.sourceforge.net,
	ceph-devel@vger.kernel.org, dri-devel@lists.freedesktop.org,
	intel-gfx@lists.freedesktop.org, kvm@vger.kernel.org,
	linux-alpha@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org, linux-cris-kernel@axis.com,
	linux-fbdev@vger.kernel.org, linux-fsdevel@vger.kernel.org,
	linux-ia64@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-media@vger.kernel.org, linux-mips@linux-mips.org,
	linux-rdma@vger.kernel.org, linux-s390@vger.kernel.org,
	linux-samsung-soc@vger.kernel.org, linux-scsi@vger.kernel.org,
	linux-security-module@vger.kernel.org, linux-sh@vger.kernel.org,
	linuxppc-dev@lists.ozlabs.org, netdev@vger.kernel.org,
	sparclinux@vger.kernel.org, x86@kernel.org
Subject: Re: [PATCH 07/10] mm: replace get_user_pages_remote() write/force parameters with gup_flags
Date: Wed, 19 Oct 2016 09:47:07 +0200	[thread overview]
Message-ID: <20161019074707.GO29967@quack2.suse.cz> (raw)
In-Reply-To: <20161013002020.3062-8-lstoakes@gmail.com>

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 <lstoakes@gmail.com>

Looks good. You can add:

Reviewed-by: Jan Kara <jack@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(&mm->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->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,
> -				access_mask & ODP_WRITE_ALLOWED_BIT,
> -				0, local_page_list, NULL);
> +				flags, local_page_list, NULL);
>  		up_read(&owning_mm->mmap_sem);
>  
>  		if (npages < 0)
> diff --git a/fs/exec.c b/fs/exec.c
> index 6fcfb3f..4e497b9 100644
> --- a/fs/exec.c
> +++ b/fs/exec.c
> @@ -191,6 +191,7 @@ static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
>  {
>  	struct page *page;
>  	int ret;
> +	unsigned int gup_flags = FOLL_FORCE;
>  
>  #ifdef CONFIG_STACK_GROWSUP
>  	if (write) {
> @@ -199,12 +200,16 @@ static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
>  			return NULL;
>  	}
>  #endif
> +
> +	if (write)
> +		gup_flags |= FOLL_WRITE;
> +
>  	/*
>  	 * We are doing an exec().  'current' is the process
>  	 * doing the exec and bprm->mm is the new process's mm.
>  	 */
> -	ret = get_user_pages_remote(current, bprm->mm, pos, 1, write,
> -			1, &page, NULL);
> +	ret = get_user_pages_remote(current, bprm->mm, pos, 1, gup_flags,
> +			&page, NULL);
>  	if (ret <= 0)
>  		return NULL;
>  
> diff --git a/include/linux/mm.h b/include/linux/mm.h
> index 686a477..2a481d3 100644
> --- a/include/linux/mm.h
> +++ b/include/linux/mm.h
> @@ -1276,7 +1276,7 @@ long __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
>  		      struct vm_area_struct **vmas, int *nonblocking);
>  long get_user_pages_remote(struct task_struct *tsk, struct mm_struct *mm,
>  			    unsigned long start, unsigned long nr_pages,
> -			    int write, int force, struct page **pages,
> +			    unsigned int gup_flags, struct page **pages,
>  			    struct vm_area_struct **vmas);
>  long get_user_pages(unsigned long start, unsigned long nr_pages,
>  			    unsigned int gup_flags, struct page **pages,
> diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
> index d4129bb..f9ec9ad 100644
> --- a/kernel/events/uprobes.c
> +++ b/kernel/events/uprobes.c
> @@ -300,7 +300,8 @@ int uprobe_write_opcode(struct mm_struct *mm, unsigned long vaddr,
>  
>  retry:
>  	/* Read the page with vaddr into memory */
> -	ret = get_user_pages_remote(NULL, mm, vaddr, 1, 0, 1, &old_page, &vma);
> +	ret = get_user_pages_remote(NULL, mm, vaddr, 1, FOLL_FORCE, &old_page,
> +			&vma);
>  	if (ret <= 0)
>  		return ret;
>  
> @@ -1710,7 +1711,8 @@ static int is_trap_at_addr(struct mm_struct *mm, unsigned long vaddr)
>  	 * but we treat this as a 'remote' access since it is
>  	 * essentially a kernel access to the memory.
>  	 */
> -	result = get_user_pages_remote(NULL, mm, vaddr, 1, 0, 1, &page, NULL);
> +	result = get_user_pages_remote(NULL, mm, vaddr, 1, FOLL_FORCE, &page,
> +			NULL);
>  	if (result < 0)
>  		return result;
>  
> diff --git a/mm/gup.c b/mm/gup.c
> index dc91303..0deecf3 100644
> --- a/mm/gup.c
> +++ b/mm/gup.c
> @@ -905,9 +905,7 @@ EXPORT_SYMBOL(get_user_pages_unlocked);
>   * @mm:		mm_struct of target mm
>   * @start:	starting user address
>   * @nr_pages:	number of pages from start to pin
> - * @write:	whether pages will be written to by the caller
> - * @force:	whether to force access even when user mapping is currently
> - *		protected (but never forces write access to shared mapping).
> + * @gup_flags:	flags modifying lookup behaviour
>   * @pages:	array that receives pointers to the pages pinned.
>   *		Should be at least nr_pages long. Or NULL, if caller
>   *		only intends to ensure the pages are faulted in.
> @@ -936,9 +934,9 @@ EXPORT_SYMBOL(get_user_pages_unlocked);
>   * or similar operation cannot guarantee anything stronger anyway because
>   * locks can't be held over the syscall boundary.
>   *
> - * If write=0, the page must not be written to. If the page is written to,
> - * set_page_dirty (or set_page_dirty_lock, as appropriate) must be called
> - * after the page is finished with, and before put_page is called.
> + * If gup_flags & FOLL_WRITE == 0, the page must not be written to. If the page
> + * is written to, set_page_dirty (or set_page_dirty_lock, as appropriate) must
> + * be called after the page is finished with, and before put_page is called.
>   *
>   * get_user_pages is typically used for fewer-copy IO operations, to get a
>   * handle on the memory by some means other than accesses via the user virtual
> @@ -955,18 +953,12 @@ EXPORT_SYMBOL(get_user_pages_unlocked);
>   */
>  long get_user_pages_remote(struct task_struct *tsk, struct mm_struct *mm,
>  		unsigned long start, unsigned long nr_pages,
> -		int write, int force, struct page **pages,
> +		unsigned int gup_flags, struct page **pages,
>  		struct vm_area_struct **vmas)
>  {
> -	unsigned int flags = FOLL_TOUCH | FOLL_REMOTE;
> -
> -	if (write)
> -		flags |= FOLL_WRITE;
> -	if (force)
> -		flags |= FOLL_FORCE;
> -
>  	return __get_user_pages_locked(tsk, mm, start, nr_pages, pages, vmas,
> -				       NULL, false, flags);
> +				       NULL, false,
> +				       gup_flags | FOLL_TOUCH | FOLL_REMOTE);
>  }
>  EXPORT_SYMBOL(get_user_pages_remote);
>  
> diff --git a/mm/memory.c b/mm/memory.c
> index fc1987d..20a9adb 100644
> --- a/mm/memory.c
> +++ b/mm/memory.c
> @@ -3873,6 +3873,10 @@ static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm,
>  {
>  	struct vm_area_struct *vma;
>  	void *old_buf = buf;
> +	unsigned int flags = FOLL_FORCE;
> +
> +	if (write)
> +		flags |= FOLL_WRITE;
>  
>  	down_read(&mm->mmap_sem);
>  	/* ignore errors, just check how much was successfully transferred */
> @@ -3882,7 +3886,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,
> -				write, 1, &page, &vma);
> +				flags, &page, &vma);
>  		if (ret <= 0) {
>  #ifndef CONFIG_HAVE_IOREMAP_PROT
>  			break;
> diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c
> index ade7c6c..682b73a 100644
> --- a/security/tomoyo/domain.c
> +++ b/security/tomoyo/domain.c
> @@ -881,7 +881,7 @@ bool tomoyo_dump_page(struct linux_binprm *bprm, unsigned long pos,
>  	 * the execve().
>  	 */
>  	if (get_user_pages_remote(current, bprm->mm, pos, 1,
> -				0, 1, &page, NULL) <= 0)
> +				FOLL_FORCE, &page, NULL) <= 0)
>  		return false;
>  #else
>  	page = bprm->page[pos / PAGE_SIZE];
> -- 
> 2.10.0
> 
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR

WARNING: multiple messages have this Message-ID (diff)
From: Jan Kara <jack@suse.cz>
To: Lorenzo Stoakes <lstoakes@gmail.com>
Cc: linux-mips@linux-mips.org, linux-fbdev@vger.kernel.org,
	Jan Kara <jack@suse.cz>,
	kvm@vger.kernel.org, linux-sh@vger.kernel.org,
	Dave Hansen <dave.hansen@linux.intel.com>,
	dri-devel@lists.freedesktop.org, linux-mm@kvack.org,
	netdev@vger.kernel.org, sparclinux@vger.kernel.org,
	linux-ia64@vger.kernel.org, linux-s390@vger.kernel.org,
	linux-samsung-soc@vger.kernel.org, linux-scsi@vger.kernel.org,
	linux-rdma@vger.kernel.org, x86@kernel.org,
	Hugh Dickins <hughd@google.com>,
	linux-media@vger.kernel.org, Rik van Riel <riel@redhat.com>,
	intel-gfx@lists.freedesktop.org,
	adi-buildroot-devel@lists.sourceforge.net,
	ceph-devel@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
	linux-cris-kernel@axis.com,
	Linus Torvalds <torvalds@linux-foundation.org>,
	linuxppc-dev@lists.ozlabs.org, linux-kernel@vger.kernel.org,
	linux-security-module@vger.kernel.org,
	linux-alpha@vger.kernel.org, lin
Subject: Re: [PATCH 07/10] mm: replace get_user_pages_remote() write/force parameters with gup_flags
Date: Wed, 19 Oct 2016 09:47:07 +0200	[thread overview]
Message-ID: <20161019074707.GO29967@quack2.suse.cz> (raw)
In-Reply-To: <20161013002020.3062-8-lstoakes@gmail.com>

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 <lstoakes@gmail.com>

Looks good. You can add:

Reviewed-by: Jan Kara <jack@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(&mm->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->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,
> -				access_mask & ODP_WRITE_ALLOWED_BIT,
> -				0, local_page_list, NULL);
> +				flags, local_page_list, NULL);
>  		up_read(&owning_mm->mmap_sem);
>  
>  		if (npages < 0)
> diff --git a/fs/exec.c b/fs/exec.c
> index 6fcfb3f..4e497b9 100644
> --- a/fs/exec.c
> +++ b/fs/exec.c
> @@ -191,6 +191,7 @@ static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
>  {
>  	struct page *page;
>  	int ret;
> +	unsigned int gup_flags = FOLL_FORCE;
>  
>  #ifdef CONFIG_STACK_GROWSUP
>  	if (write) {
> @@ -199,12 +200,16 @@ static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
>  			return NULL;
>  	}
>  #endif
> +
> +	if (write)
> +		gup_flags |= FOLL_WRITE;
> +
>  	/*
>  	 * We are doing an exec().  'current' is the process
>  	 * doing the exec and bprm->mm is the new process's mm.
>  	 */
> -	ret = get_user_pages_remote(current, bprm->mm, pos, 1, write,
> -			1, &page, NULL);
> +	ret = get_user_pages_remote(current, bprm->mm, pos, 1, gup_flags,
> +			&page, NULL);
>  	if (ret <= 0)
>  		return NULL;
>  
> diff --git a/include/linux/mm.h b/include/linux/mm.h
> index 686a477..2a481d3 100644
> --- a/include/linux/mm.h
> +++ b/include/linux/mm.h
> @@ -1276,7 +1276,7 @@ long __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
>  		      struct vm_area_struct **vmas, int *nonblocking);
>  long get_user_pages_remote(struct task_struct *tsk, struct mm_struct *mm,
>  			    unsigned long start, unsigned long nr_pages,
> -			    int write, int force, struct page **pages,
> +			    unsigned int gup_flags, struct page **pages,
>  			    struct vm_area_struct **vmas);
>  long get_user_pages(unsigned long start, unsigned long nr_pages,
>  			    unsigned int gup_flags, struct page **pages,
> diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
> index d4129bb..f9ec9ad 100644
> --- a/kernel/events/uprobes.c
> +++ b/kernel/events/uprobes.c
> @@ -300,7 +300,8 @@ int uprobe_write_opcode(struct mm_struct *mm, unsigned long vaddr,
>  
>  retry:
>  	/* Read the page with vaddr into memory */
> -	ret = get_user_pages_remote(NULL, mm, vaddr, 1, 0, 1, &old_page, &vma);
> +	ret = get_user_pages_remote(NULL, mm, vaddr, 1, FOLL_FORCE, &old_page,
> +			&vma);
>  	if (ret <= 0)
>  		return ret;
>  
> @@ -1710,7 +1711,8 @@ static int is_trap_at_addr(struct mm_struct *mm, unsigned long vaddr)
>  	 * but we treat this as a 'remote' access since it is
>  	 * essentially a kernel access to the memory.
>  	 */
> -	result = get_user_pages_remote(NULL, mm, vaddr, 1, 0, 1, &page, NULL);
> +	result = get_user_pages_remote(NULL, mm, vaddr, 1, FOLL_FORCE, &page,
> +			NULL);
>  	if (result < 0)
>  		return result;
>  
> diff --git a/mm/gup.c b/mm/gup.c
> index dc91303..0deecf3 100644
> --- a/mm/gup.c
> +++ b/mm/gup.c
> @@ -905,9 +905,7 @@ EXPORT_SYMBOL(get_user_pages_unlocked);
>   * @mm:		mm_struct of target mm
>   * @start:	starting user address
>   * @nr_pages:	number of pages from start to pin
> - * @write:	whether pages will be written to by the caller
> - * @force:	whether to force access even when user mapping is currently
> - *		protected (but never forces write access to shared mapping).
> + * @gup_flags:	flags modifying lookup behaviour
>   * @pages:	array that receives pointers to the pages pinned.
>   *		Should be at least nr_pages long. Or NULL, if caller
>   *		only intends to ensure the pages are faulted in.
> @@ -936,9 +934,9 @@ EXPORT_SYMBOL(get_user_pages_unlocked);
>   * or similar operation cannot guarantee anything stronger anyway because
>   * locks can't be held over the syscall boundary.
>   *
> - * If write=0, the page must not be written to. If the page is written to,
> - * set_page_dirty (or set_page_dirty_lock, as appropriate) must be called
> - * after the page is finished with, and before put_page is called.
> + * If gup_flags & FOLL_WRITE == 0, the page must not be written to. If the page
> + * is written to, set_page_dirty (or set_page_dirty_lock, as appropriate) must
> + * be called after the page is finished with, and before put_page is called.
>   *
>   * get_user_pages is typically used for fewer-copy IO operations, to get a
>   * handle on the memory by some means other than accesses via the user virtual
> @@ -955,18 +953,12 @@ EXPORT_SYMBOL(get_user_pages_unlocked);
>   */
>  long get_user_pages_remote(struct task_struct *tsk, struct mm_struct *mm,
>  		unsigned long start, unsigned long nr_pages,
> -		int write, int force, struct page **pages,
> +		unsigned int gup_flags, struct page **pages,
>  		struct vm_area_struct **vmas)
>  {
> -	unsigned int flags = FOLL_TOUCH | FOLL_REMOTE;
> -
> -	if (write)
> -		flags |= FOLL_WRITE;
> -	if (force)
> -		flags |= FOLL_FORCE;
> -
>  	return __get_user_pages_locked(tsk, mm, start, nr_pages, pages, vmas,
> -				       NULL, false, flags);
> +				       NULL, false,
> +				       gup_flags | FOLL_TOUCH | FOLL_REMOTE);
>  }
>  EXPORT_SYMBOL(get_user_pages_remote);
>  
> diff --git a/mm/memory.c b/mm/memory.c
> index fc1987d..20a9adb 100644
> --- a/mm/memory.c
> +++ b/mm/memory.c
> @@ -3873,6 +3873,10 @@ static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm,
>  {
>  	struct vm_area_struct *vma;
>  	void *old_buf = buf;
> +	unsigned int flags = FOLL_FORCE;
> +
> +	if (write)
> +		flags |= FOLL_WRITE;
>  
>  	down_read(&mm->mmap_sem);
>  	/* ignore errors, just check how much was successfully transferred */
> @@ -3882,7 +3886,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,
> -				write, 1, &page, &vma);
> +				flags, &page, &vma);
>  		if (ret <= 0) {
>  #ifndef CONFIG_HAVE_IOREMAP_PROT
>  			break;
> diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c
> index ade7c6c..682b73a 100644
> --- a/security/tomoyo/domain.c
> +++ b/security/tomoyo/domain.c
> @@ -881,7 +881,7 @@ bool tomoyo_dump_page(struct linux_binprm *bprm, unsigned long pos,
>  	 * the execve().
>  	 */
>  	if (get_user_pages_remote(current, bprm->mm, pos, 1,
> -				0, 1, &page, NULL) <= 0)
> +				FOLL_FORCE, &page, NULL) <= 0)
>  		return false;
>  #else
>  	page = bprm->page[pos / PAGE_SIZE];
> -- 
> 2.10.0
> 
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

WARNING: multiple messages have this Message-ID (diff)
From: Jan Kara <jack@suse.cz>
To: Lorenzo Stoakes <lstoakes@gmail.com>
Cc: linux-mm@kvack.org,
	Linus Torvalds <torvalds@linux-foundation.org>,
	Jan Kara <jack@suse.cz>, Hugh Dickins <hughd@google.com>,
	Dave Hansen <dave.hansen@linux.intel.com>,
	Rik van Riel <riel@redhat.com>,
	Mel Gorman <mgorman@techsingularity.net>,
	Andrew Morton <akpm@linux-foundation.org>,
	adi-buildroot-devel@lists.sourceforge.net,
	ceph-devel@vger.kernel.org, dri-devel@lists.freedesktop.org,
	intel-gfx@lists.freedesktop.org, kvm@vger.kernel.org,
	linux-alpha@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org, linux-cris-kernel@axis.com,
	linux-fbdev@vger.kernel.org, linux-fsdevel@vger.kernel.org,
	linux-ia64@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-media@vger.kernel.org, linux-mips@linux-mips.org,
	linux-rdma@vger.kernel.org, linux-s390@vger.kernel.org,
	linux-samsung-soc@vger.kernel.org, linux-scsi@vger.kernel.org,
	linux-security-module@vger.kernel.org, linux-sh@vger.kernel.org,
	linuxppc-dev@lists.ozlabs.org, netdev@vger.kernel.org,
	sparclinux@vger.kernel.org, x86@kernel.org
Subject: Re: [PATCH 07/10] mm: replace get_user_pages_remote() write/force parameters with gup_flags
Date: Wed, 19 Oct 2016 09:47:07 +0200	[thread overview]
Message-ID: <20161019074707.GO29967@quack2.suse.cz> (raw)
In-Reply-To: <20161013002020.3062-8-lstoakes@gmail.com>

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 <lstoakes@gmail.com>

Looks good. You can add:

Reviewed-by: Jan Kara <jack@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(&mm->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->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,
> -				access_mask & ODP_WRITE_ALLOWED_BIT,
> -				0, local_page_list, NULL);
> +				flags, local_page_list, NULL);
>  		up_read(&owning_mm->mmap_sem);
>  
>  		if (npages < 0)
> diff --git a/fs/exec.c b/fs/exec.c
> index 6fcfb3f..4e497b9 100644
> --- a/fs/exec.c
> +++ b/fs/exec.c
> @@ -191,6 +191,7 @@ static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
>  {
>  	struct page *page;
>  	int ret;
> +	unsigned int gup_flags = FOLL_FORCE;
>  
>  #ifdef CONFIG_STACK_GROWSUP
>  	if (write) {
> @@ -199,12 +200,16 @@ static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
>  			return NULL;
>  	}
>  #endif
> +
> +	if (write)
> +		gup_flags |= FOLL_WRITE;
> +
>  	/*
>  	 * We are doing an exec().  'current' is the process
>  	 * doing the exec and bprm->mm is the new process's mm.
>  	 */
> -	ret = get_user_pages_remote(current, bprm->mm, pos, 1, write,
> -			1, &page, NULL);
> +	ret = get_user_pages_remote(current, bprm->mm, pos, 1, gup_flags,
> +			&page, NULL);
>  	if (ret <= 0)
>  		return NULL;
>  
> diff --git a/include/linux/mm.h b/include/linux/mm.h
> index 686a477..2a481d3 100644
> --- a/include/linux/mm.h
> +++ b/include/linux/mm.h
> @@ -1276,7 +1276,7 @@ long __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
>  		      struct vm_area_struct **vmas, int *nonblocking);
>  long get_user_pages_remote(struct task_struct *tsk, struct mm_struct *mm,
>  			    unsigned long start, unsigned long nr_pages,
> -			    int write, int force, struct page **pages,
> +			    unsigned int gup_flags, struct page **pages,
>  			    struct vm_area_struct **vmas);
>  long get_user_pages(unsigned long start, unsigned long nr_pages,
>  			    unsigned int gup_flags, struct page **pages,
> diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
> index d4129bb..f9ec9ad 100644
> --- a/kernel/events/uprobes.c
> +++ b/kernel/events/uprobes.c
> @@ -300,7 +300,8 @@ int uprobe_write_opcode(struct mm_struct *mm, unsigned long vaddr,
>  
>  retry:
>  	/* Read the page with vaddr into memory */
> -	ret = get_user_pages_remote(NULL, mm, vaddr, 1, 0, 1, &old_page, &vma);
> +	ret = get_user_pages_remote(NULL, mm, vaddr, 1, FOLL_FORCE, &old_page,
> +			&vma);
>  	if (ret <= 0)
>  		return ret;
>  
> @@ -1710,7 +1711,8 @@ static int is_trap_at_addr(struct mm_struct *mm, unsigned long vaddr)
>  	 * but we treat this as a 'remote' access since it is
>  	 * essentially a kernel access to the memory.
>  	 */
> -	result = get_user_pages_remote(NULL, mm, vaddr, 1, 0, 1, &page, NULL);
> +	result = get_user_pages_remote(NULL, mm, vaddr, 1, FOLL_FORCE, &page,
> +			NULL);
>  	if (result < 0)
>  		return result;
>  
> diff --git a/mm/gup.c b/mm/gup.c
> index dc91303..0deecf3 100644
> --- a/mm/gup.c
> +++ b/mm/gup.c
> @@ -905,9 +905,7 @@ EXPORT_SYMBOL(get_user_pages_unlocked);
>   * @mm:		mm_struct of target mm
>   * @start:	starting user address
>   * @nr_pages:	number of pages from start to pin
> - * @write:	whether pages will be written to by the caller
> - * @force:	whether to force access even when user mapping is currently
> - *		protected (but never forces write access to shared mapping).
> + * @gup_flags:	flags modifying lookup behaviour
>   * @pages:	array that receives pointers to the pages pinned.
>   *		Should be at least nr_pages long. Or NULL, if caller
>   *		only intends to ensure the pages are faulted in.
> @@ -936,9 +934,9 @@ EXPORT_SYMBOL(get_user_pages_unlocked);
>   * or similar operation cannot guarantee anything stronger anyway because
>   * locks can't be held over the syscall boundary.
>   *
> - * If write=0, the page must not be written to. If the page is written to,
> - * set_page_dirty (or set_page_dirty_lock, as appropriate) must be called
> - * after the page is finished with, and before put_page is called.
> + * If gup_flags & FOLL_WRITE == 0, the page must not be written to. If the page
> + * is written to, set_page_dirty (or set_page_dirty_lock, as appropriate) must
> + * be called after the page is finished with, and before put_page is called.
>   *
>   * get_user_pages is typically used for fewer-copy IO operations, to get a
>   * handle on the memory by some means other than accesses via the user virtual
> @@ -955,18 +953,12 @@ EXPORT_SYMBOL(get_user_pages_unlocked);
>   */
>  long get_user_pages_remote(struct task_struct *tsk, struct mm_struct *mm,
>  		unsigned long start, unsigned long nr_pages,
> -		int write, int force, struct page **pages,
> +		unsigned int gup_flags, struct page **pages,
>  		struct vm_area_struct **vmas)
>  {
> -	unsigned int flags = FOLL_TOUCH | FOLL_REMOTE;
> -
> -	if (write)
> -		flags |= FOLL_WRITE;
> -	if (force)
> -		flags |= FOLL_FORCE;
> -
>  	return __get_user_pages_locked(tsk, mm, start, nr_pages, pages, vmas,
> -				       NULL, false, flags);
> +				       NULL, false,
> +				       gup_flags | FOLL_TOUCH | FOLL_REMOTE);
>  }
>  EXPORT_SYMBOL(get_user_pages_remote);
>  
> diff --git a/mm/memory.c b/mm/memory.c
> index fc1987d..20a9adb 100644
> --- a/mm/memory.c
> +++ b/mm/memory.c
> @@ -3873,6 +3873,10 @@ static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm,
>  {
>  	struct vm_area_struct *vma;
>  	void *old_buf = buf;
> +	unsigned int flags = FOLL_FORCE;
> +
> +	if (write)
> +		flags |= FOLL_WRITE;
>  
>  	down_read(&mm->mmap_sem);
>  	/* ignore errors, just check how much was successfully transferred */
> @@ -3882,7 +3886,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,
> -				write, 1, &page, &vma);
> +				flags, &page, &vma);
>  		if (ret <= 0) {
>  #ifndef CONFIG_HAVE_IOREMAP_PROT
>  			break;
> diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c
> index ade7c6c..682b73a 100644
> --- a/security/tomoyo/domain.c
> +++ b/security/tomoyo/domain.c
> @@ -881,7 +881,7 @@ bool tomoyo_dump_page(struct linux_binprm *bprm, unsigned long pos,
>  	 * the execve().
>  	 */
>  	if (get_user_pages_remote(current, bprm->mm, pos, 1,
> -				0, 1, &page, NULL) <= 0)
> +				FOLL_FORCE, &page, NULL) <= 0)
>  		return false;
>  #else
>  	page = bprm->page[pos / PAGE_SIZE];
> -- 
> 2.10.0
> 
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

WARNING: multiple messages have this Message-ID (diff)
From: jack@suse.cz (Jan Kara)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH 07/10] mm: replace get_user_pages_remote() write/force parameters with gup_flags
Date: Wed, 19 Oct 2016 09:47:07 +0200	[thread overview]
Message-ID: <20161019074707.GO29967@quack2.suse.cz> (raw)
In-Reply-To: <20161013002020.3062-8-lstoakes@gmail.com>

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 <lstoakes@gmail.com>

Looks good. You can add:

Reviewed-by: Jan Kara <jack@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(&mm->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->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,
> -				access_mask & ODP_WRITE_ALLOWED_BIT,
> -				0, local_page_list, NULL);
> +				flags, local_page_list, NULL);
>  		up_read(&owning_mm->mmap_sem);
>  
>  		if (npages < 0)
> diff --git a/fs/exec.c b/fs/exec.c
> index 6fcfb3f..4e497b9 100644
> --- a/fs/exec.c
> +++ b/fs/exec.c
> @@ -191,6 +191,7 @@ static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
>  {
>  	struct page *page;
>  	int ret;
> +	unsigned int gup_flags = FOLL_FORCE;
>  
>  #ifdef CONFIG_STACK_GROWSUP
>  	if (write) {
> @@ -199,12 +200,16 @@ static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
>  			return NULL;
>  	}
>  #endif
> +
> +	if (write)
> +		gup_flags |= FOLL_WRITE;
> +
>  	/*
>  	 * We are doing an exec().  'current' is the process
>  	 * doing the exec and bprm->mm is the new process's mm.
>  	 */
> -	ret = get_user_pages_remote(current, bprm->mm, pos, 1, write,
> -			1, &page, NULL);
> +	ret = get_user_pages_remote(current, bprm->mm, pos, 1, gup_flags,
> +			&page, NULL);
>  	if (ret <= 0)
>  		return NULL;
>  
> diff --git a/include/linux/mm.h b/include/linux/mm.h
> index 686a477..2a481d3 100644
> --- a/include/linux/mm.h
> +++ b/include/linux/mm.h
> @@ -1276,7 +1276,7 @@ long __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
>  		      struct vm_area_struct **vmas, int *nonblocking);
>  long get_user_pages_remote(struct task_struct *tsk, struct mm_struct *mm,
>  			    unsigned long start, unsigned long nr_pages,
> -			    int write, int force, struct page **pages,
> +			    unsigned int gup_flags, struct page **pages,
>  			    struct vm_area_struct **vmas);
>  long get_user_pages(unsigned long start, unsigned long nr_pages,
>  			    unsigned int gup_flags, struct page **pages,
> diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
> index d4129bb..f9ec9ad 100644
> --- a/kernel/events/uprobes.c
> +++ b/kernel/events/uprobes.c
> @@ -300,7 +300,8 @@ int uprobe_write_opcode(struct mm_struct *mm, unsigned long vaddr,
>  
>  retry:
>  	/* Read the page with vaddr into memory */
> -	ret = get_user_pages_remote(NULL, mm, vaddr, 1, 0, 1, &old_page, &vma);
> +	ret = get_user_pages_remote(NULL, mm, vaddr, 1, FOLL_FORCE, &old_page,
> +			&vma);
>  	if (ret <= 0)
>  		return ret;
>  
> @@ -1710,7 +1711,8 @@ static int is_trap_at_addr(struct mm_struct *mm, unsigned long vaddr)
>  	 * but we treat this as a 'remote' access since it is
>  	 * essentially a kernel access to the memory.
>  	 */
> -	result = get_user_pages_remote(NULL, mm, vaddr, 1, 0, 1, &page, NULL);
> +	result = get_user_pages_remote(NULL, mm, vaddr, 1, FOLL_FORCE, &page,
> +			NULL);
>  	if (result < 0)
>  		return result;
>  
> diff --git a/mm/gup.c b/mm/gup.c
> index dc91303..0deecf3 100644
> --- a/mm/gup.c
> +++ b/mm/gup.c
> @@ -905,9 +905,7 @@ EXPORT_SYMBOL(get_user_pages_unlocked);
>   * @mm:		mm_struct of target mm
>   * @start:	starting user address
>   * @nr_pages:	number of pages from start to pin
> - * @write:	whether pages will be written to by the caller
> - * @force:	whether to force access even when user mapping is currently
> - *		protected (but never forces write access to shared mapping).
> + * @gup_flags:	flags modifying lookup behaviour
>   * @pages:	array that receives pointers to the pages pinned.
>   *		Should be at least nr_pages long. Or NULL, if caller
>   *		only intends to ensure the pages are faulted in.
> @@ -936,9 +934,9 @@ EXPORT_SYMBOL(get_user_pages_unlocked);
>   * or similar operation cannot guarantee anything stronger anyway because
>   * locks can't be held over the syscall boundary.
>   *
> - * If write=0, the page must not be written to. If the page is written to,
> - * set_page_dirty (or set_page_dirty_lock, as appropriate) must be called
> - * after the page is finished with, and before put_page is called.
> + * If gup_flags & FOLL_WRITE == 0, the page must not be written to. If the page
> + * is written to, set_page_dirty (or set_page_dirty_lock, as appropriate) must
> + * be called after the page is finished with, and before put_page is called.
>   *
>   * get_user_pages is typically used for fewer-copy IO operations, to get a
>   * handle on the memory by some means other than accesses via the user virtual
> @@ -955,18 +953,12 @@ EXPORT_SYMBOL(get_user_pages_unlocked);
>   */
>  long get_user_pages_remote(struct task_struct *tsk, struct mm_struct *mm,
>  		unsigned long start, unsigned long nr_pages,
> -		int write, int force, struct page **pages,
> +		unsigned int gup_flags, struct page **pages,
>  		struct vm_area_struct **vmas)
>  {
> -	unsigned int flags = FOLL_TOUCH | FOLL_REMOTE;
> -
> -	if (write)
> -		flags |= FOLL_WRITE;
> -	if (force)
> -		flags |= FOLL_FORCE;
> -
>  	return __get_user_pages_locked(tsk, mm, start, nr_pages, pages, vmas,
> -				       NULL, false, flags);
> +				       NULL, false,
> +				       gup_flags | FOLL_TOUCH | FOLL_REMOTE);
>  }
>  EXPORT_SYMBOL(get_user_pages_remote);
>  
> diff --git a/mm/memory.c b/mm/memory.c
> index fc1987d..20a9adb 100644
> --- a/mm/memory.c
> +++ b/mm/memory.c
> @@ -3873,6 +3873,10 @@ static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm,
>  {
>  	struct vm_area_struct *vma;
>  	void *old_buf = buf;
> +	unsigned int flags = FOLL_FORCE;
> +
> +	if (write)
> +		flags |= FOLL_WRITE;
>  
>  	down_read(&mm->mmap_sem);
>  	/* ignore errors, just check how much was successfully transferred */
> @@ -3882,7 +3886,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,
> -				write, 1, &page, &vma);
> +				flags, &page, &vma);
>  		if (ret <= 0) {
>  #ifndef CONFIG_HAVE_IOREMAP_PROT
>  			break;
> diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c
> index ade7c6c..682b73a 100644
> --- a/security/tomoyo/domain.c
> +++ b/security/tomoyo/domain.c
> @@ -881,7 +881,7 @@ bool tomoyo_dump_page(struct linux_binprm *bprm, unsigned long pos,
>  	 * the execve().
>  	 */
>  	if (get_user_pages_remote(current, bprm->mm, pos, 1,
> -				0, 1, &page, NULL) <= 0)
> +				FOLL_FORCE, &page, NULL) <= 0)
>  		return false;
>  #else
>  	page = bprm->page[pos / PAGE_SIZE];
> -- 
> 2.10.0
> 
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR

  reply	other threads:[~2016-10-19  7:47 UTC|newest]

Thread overview: 226+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-10-13  0:20 [PATCH 00/10] mm: adjust get_user_pages* functions to explicitly pass FOLL_* flags Lorenzo Stoakes
2016-10-13  0:20 ` Lorenzo Stoakes
2016-10-13  0:20 ` Lorenzo Stoakes
2016-10-13  0:20 ` Lorenzo Stoakes
2016-10-13  0:20 ` Lorenzo Stoakes
2016-10-13  0:20 ` [PATCH 01/10] mm: remove write/force parameters from __get_user_pages_locked() Lorenzo Stoakes
2016-10-13  0:20   ` Lorenzo Stoakes
2016-10-13  0:20   ` Lorenzo Stoakes
2016-10-13  0:20   ` Lorenzo Stoakes
2016-10-13  0:20   ` Lorenzo Stoakes
2016-10-18 12:43   ` Jan Kara
2016-10-18 12:43     ` Jan Kara
2016-10-18 12:43     ` Jan Kara
2016-10-18 12:43     ` Jan Kara
2016-10-18 12:43     ` Jan Kara
2016-10-18 12:43     ` Jan Kara
2016-10-13  0:20 ` [PATCH 02/10] mm: remove write/force parameters from __get_user_pages_unlocked() Lorenzo Stoakes
2016-10-13  0:20   ` Lorenzo Stoakes
2016-10-13  0:20   ` Lorenzo Stoakes
2016-10-13  0:20   ` Lorenzo Stoakes
2016-10-13  0:20   ` Lorenzo Stoakes
2016-10-13  6:54   ` Paolo Bonzini
2016-10-13  6:54     ` Paolo Bonzini
2016-10-13  6:54     ` Paolo Bonzini
2016-10-13  6:54     ` Paolo Bonzini
2016-10-13  6:54     ` Paolo Bonzini
2016-10-18 12:46   ` Jan Kara
2016-10-18 12:46     ` Jan Kara
2016-10-18 12:46     ` Jan Kara
2016-10-18 12:46     ` Jan Kara
2016-10-18 12:46     ` Jan Kara
2016-10-18 12:46     ` Jan Kara
2016-10-13  0:20 ` [PATCH 03/10] mm: replace get_user_pages_unlocked() write/force parameters with gup_flags Lorenzo Stoakes
2016-10-13  0:20   ` Lorenzo Stoakes
2016-10-13  0:20   ` Lorenzo Stoakes
2016-10-13  0:20   ` Lorenzo Stoakes
2016-10-13  0:20   ` Lorenzo Stoakes
2016-10-18 12:50   ` Jan Kara
2016-10-18 12:50     ` Jan Kara
2016-10-18 12:50     ` Jan Kara
2016-10-18 12:50     ` Jan Kara
2016-10-18 12:50     ` Jan Kara
2016-10-18 12:50     ` Jan Kara
2016-10-13  0:20 ` [PATCH 04/10] mm: replace get_user_pages_locked() " Lorenzo Stoakes
2016-10-13  0:20   ` Lorenzo Stoakes
2016-10-13  0:20   ` Lorenzo Stoakes
2016-10-13  0:20   ` Lorenzo Stoakes
2016-10-13  0:20   ` Lorenzo Stoakes
2016-10-18 12:54   ` Jan Kara
2016-10-18 12:54     ` Jan Kara
2016-10-18 12:54     ` Jan Kara
2016-10-18 12:54     ` Jan Kara
2016-10-18 12:54     ` Jan Kara
2016-10-18 12:54     ` Jan Kara
2016-10-18 13:56     ` Lorenzo Stoakes
2016-10-18 13:56       ` Lorenzo Stoakes
2016-10-18 13:56       ` Lorenzo Stoakes
2016-10-18 13:56       ` Lorenzo Stoakes
2016-10-18 13:56       ` Lorenzo Stoakes
2016-10-18 13:56       ` Lorenzo Stoakes
2016-10-19  7:32       ` Jan Kara
2016-10-19  7:32         ` Jan Kara
2016-10-19  7:32         ` Jan Kara
2016-10-19  7:32         ` Jan Kara
2016-10-19  7:32         ` Jan Kara
2016-10-19  7:33   ` Jan Kara
2016-10-19  7:33     ` Jan Kara
2016-10-19  7:33     ` Jan Kara
2016-10-19  7:33     ` Jan Kara
2016-10-19  7:33     ` Jan Kara
2016-10-19  7:33     ` Jan Kara
2016-10-19  7:33     ` Jan Kara
2016-10-19  7:33     ` Jan Kara
2016-10-13  0:20 ` [PATCH 05/10] mm: replace get_vaddr_frames() " Lorenzo Stoakes
2016-10-13  0:20   ` Lorenzo Stoakes
2016-10-13  0:20   ` Lorenzo Stoakes
2016-10-13  0:20   ` Lorenzo Stoakes
2016-10-13  0:20   ` Lorenzo Stoakes
2016-10-19  7:34   ` Jan Kara
2016-10-19  7:34     ` Jan Kara
2016-10-19  7:34     ` Jan Kara
2016-10-19  7:34     ` Jan Kara
2016-10-19  7:34     ` Jan Kara
2016-10-19  7:34     ` Jan Kara
2016-10-13  0:20 ` [PATCH 06/10] mm: replace get_user_pages() " Lorenzo Stoakes
2016-10-13  0:20   ` Lorenzo Stoakes
2016-10-13  0:20   ` Lorenzo Stoakes
2016-10-13  0:20   ` Lorenzo Stoakes
2016-10-13  0:20   ` Lorenzo Stoakes
2016-10-17  9:22   ` Jesper Nilsson
2016-10-17  9:22     ` Jesper Nilsson
2016-10-17  9:22     ` Jesper Nilsson
2016-10-17  9:22     ` Jesper Nilsson
2016-10-17  9:22     ` Jesper Nilsson
2016-10-17  9:22     ` Jesper Nilsson
2016-10-19  7:44   ` Jan Kara
2016-10-19  7:44     ` Jan Kara
2016-10-19  7:44     ` Jan Kara
2016-10-19  7:44     ` Jan Kara
2016-10-19  7:44     ` Jan Kara
2016-10-19  7:44     ` Jan Kara
2016-10-13  0:20 ` [PATCH 07/10] mm: replace get_user_pages_remote() " Lorenzo Stoakes
2016-10-13  0:20   ` Lorenzo Stoakes
2016-10-13  0:20   ` Lorenzo Stoakes
2016-10-13  0:20   ` Lorenzo Stoakes
2016-10-13  0:20   ` Lorenzo Stoakes
2016-10-19  7:47   ` Jan Kara [this message]
2016-10-19  7:47     ` Jan Kara
2016-10-19  7:47     ` Jan Kara
2016-10-19  7:47     ` Jan Kara
2016-10-19  7:47     ` Jan Kara
2016-10-19  7:47     ` Jan Kara
2016-10-13  0:20 ` [PATCH 08/10] mm: replace __access_remote_vm() write parameter " Lorenzo Stoakes
2016-10-13  0:20   ` Lorenzo Stoakes
2016-10-13  0:20   ` Lorenzo Stoakes
2016-10-13  0:20   ` Lorenzo Stoakes
2016-10-13  0:20   ` Lorenzo Stoakes
2016-10-19  7:59   ` Jan Kara
2016-10-19  7:59     ` Jan Kara
2016-10-19  7:59     ` Jan Kara
2016-10-19  7:59     ` Jan Kara
2016-10-19  7:59     ` Jan Kara
2016-10-19  7:59     ` Jan Kara
2016-10-19  7:59     ` Jan Kara
2016-10-19  7:59     ` Jan Kara
2016-10-19  8:13     ` Michal Hocko
2016-10-19  8:13       ` Michal Hocko
2016-10-19  8:13       ` Michal Hocko
2016-10-19  8:13       ` Michal Hocko
2016-10-19  8:13       ` Michal Hocko
2016-10-19  8:40       ` Lorenzo Stoakes
2016-10-19  8:40         ` Lorenzo Stoakes
2016-10-19  8:40         ` Lorenzo Stoakes
2016-10-19  8:40         ` Lorenzo Stoakes
2016-10-19  8:40         ` Lorenzo Stoakes
2016-10-19  8:52         ` Michal Hocko
2016-10-19  8:52           ` Michal Hocko
2016-10-19  8:52           ` Michal Hocko
2016-10-19  8:52           ` Michal Hocko
2016-10-19  8:52           ` Michal Hocko
2016-10-19  9:06           ` Lorenzo Stoakes
2016-10-19  9:06             ` Lorenzo Stoakes
2016-10-19  9:06             ` Lorenzo Stoakes
2016-10-19  9:06             ` Lorenzo Stoakes
2016-10-19  9:06             ` Lorenzo Stoakes
2016-10-19  9:23             ` Michal Hocko
2016-10-19  9:23               ` Michal Hocko
2016-10-19  9:23               ` Michal Hocko
2016-10-19  9:23               ` Michal Hocko
2016-10-19  9:23               ` Michal Hocko
2016-10-13  0:20 ` [PATCH 09/10] mm: replace access_remote_vm() " Lorenzo Stoakes
2016-10-13  0:20   ` Lorenzo Stoakes
2016-10-13  0:20   ` Lorenzo Stoakes
2016-10-13  0:20   ` Lorenzo Stoakes
2016-10-13  0:20   ` Lorenzo Stoakes
2016-10-13  0:20 ` [PATCH 10/10] mm: replace access_process_vm() " Lorenzo Stoakes
2016-10-13  0:20   ` Lorenzo Stoakes
2016-10-13  0:20   ` Lorenzo Stoakes
2016-10-13  0:20   ` Lorenzo Stoakes
2016-10-13  0:20   ` Lorenzo Stoakes
2016-10-17  9:23   ` Jesper Nilsson
2016-10-17  9:23     ` Jesper Nilsson
2016-10-17  9:23     ` Jesper Nilsson
2016-10-17  9:23     ` Jesper Nilsson
2016-10-17  9:23     ` Jesper Nilsson
2016-10-17  9:23     ` Jesper Nilsson
2016-10-19 11:10   ` Michael Ellerman
2016-10-19 11:10     ` Michael Ellerman
2016-10-19 11:10     ` Michael Ellerman
2016-10-19 11:10     ` Michael Ellerman
2016-10-19 11:10     ` Michael Ellerman
2016-10-19 11:10     ` Michael Ellerman
2016-10-19 11:10     ` Michael Ellerman
2016-10-13  7:32 ` [PATCH 00/10] mm: adjust get_user_pages* functions to explicitly pass FOLL_* flags Christian König
2016-10-13  7:32   ` Christian König
2016-10-13  7:32   ` Christian König
2016-10-13  7:32   ` Christian König
2016-10-13  7:32   ` Christian König
2016-10-13  7:32   ` Christian König
2016-10-13  7:32   ` Christian König
2016-10-13  7:32   ` Christian König
2016-10-13  7:32   ` Christian König
2016-10-18 15:30 ` Michal Hocko
2016-10-18 15:30   ` Michal Hocko
2016-10-18 15:30   ` Michal Hocko
2016-10-18 15:30   ` Michal Hocko
2016-10-18 15:30   ` Michal Hocko
2016-10-18 15:30   ` Michal Hocko
2016-10-18 15:30   ` Michal Hocko
2016-10-18 15:30   ` Michal Hocko
2016-10-19  8:58   ` Lorenzo Stoakes
2016-10-19  8:58     ` Lorenzo Stoakes
2016-10-19  8:58     ` Lorenzo Stoakes
2016-10-19  8:58     ` Lorenzo Stoakes
2016-10-19  8:58     ` Lorenzo Stoakes
2016-10-19  8:58     ` Lorenzo Stoakes
2016-10-19  9:07     ` Michal Hocko
2016-10-19  9:07       ` Michal Hocko
2016-10-19  9:07       ` Michal Hocko
2016-10-19  9:07       ` Michal Hocko
2016-10-19  9:07       ` Michal Hocko
2016-10-19  9:07       ` Michal Hocko
2016-10-19  9:07       ` Michal Hocko
2016-10-19  9:07       ` Michal Hocko
2016-10-19 16:49       ` Dave Hansen
2016-10-19 16:49         ` Dave Hansen
2016-10-19 16:49         ` Dave Hansen
2016-10-19 16:49         ` Dave Hansen
2016-10-19 16:49         ` Dave Hansen
2016-10-19 17:01         ` Michal Hocko
2016-10-19 17:01           ` Michal Hocko
2016-10-19 17:01           ` Michal Hocko
2016-10-19 17:01           ` Michal Hocko
2016-10-19 17:01           ` Michal Hocko
2016-10-19 17:23           ` Dave Hansen
2016-10-19 17:23             ` Dave Hansen
2016-10-19 17:23             ` Dave Hansen
2016-10-19 17:23             ` Dave Hansen
2016-10-19 17:23             ` Dave Hansen
2016-10-20 19:26             ` Michal Hocko
2016-10-20 19:26               ` Michal Hocko
2016-10-20 19:26               ` Michal Hocko
2016-10-20 19:26               ` Michal Hocko
2016-10-20 19:26               ` Michal Hocko
2016-10-26  8:55   ` Lorenzo Stoakes
2016-10-26  8:55     ` Lorenzo Stoakes

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20161019074707.GO29967@quack2.suse.cz \
    --to=jack@suse.cz \
    --cc=adi-buildroot-devel@lists.sourceforge.net \
    --cc=ceph-devel@vger.kernel.org \
    --cc=dave.hansen@linux.intel.com \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=hughd@google.com \
    --cc=intel-gfx@lists.freedesktop.org \
    --cc=kvm@vger.kernel.org \
    --cc=linux-alpha@vger.kernel.orglin \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-cris-kernel@axis.com \
    --cc=linux-fbdev@vger.kernel.org \
    --cc=linux-ia64@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-media@vger.kernel.org \
    --cc=linux-mips@linux-mips.org \
    --cc=linux-mm@kvack.org \
    --cc=linux-rdma@vger.kernel.org \
    --cc=linux-s390@vger.kernel.org \
    --cc=linux-samsung-soc@vger.kernel.org \
    --cc=linux-scsi@vger.kernel.org \
    --cc=linux-security-module@vger.kernel.org \
    --cc=linux-sh@vger.kernel.org \
    --cc=linuxppc-dev@lists.ozlabs.org \
    --cc=lstoakes@gmail.com \
    --cc=netdev@vger.kernel.org \
    --cc=riel@redhat.com \
    --cc=sparclinux@vger.kernel.org \
    --cc=torvalds@linux-foundation.org \
    --cc=x86@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.