linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/2] mm: unexport __get_user_pages_unlocked()
@ 2016-10-27  9:51 Lorenzo Stoakes
  2016-10-27  9:51 ` [PATCH 1/2] mm: add locked parameter to get_user_pages_remote() Lorenzo Stoakes
                   ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: Lorenzo Stoakes @ 2016-10-27  9:51 UTC (permalink / raw)
  To: linux-mm
  Cc: Michal Hocko, Linus Torvalds, Jan Kara, Hugh Dickins,
	Dave Hansen, Rik van Riel, Mel Gorman, Andrew Morton,
	Paolo Bonzini, Radim Krčmář,
	kvm, linux-kernel, linux-security-module, linux-rdma, dri-devel,
	linux-fsdevel

This patch series continues the cleanup of get_user_pages*() functions taking
advantage of the fact we can now pass gup_flags as we please.

It firstly adds an additional 'locked' parameter to get_user_pages_remote() to
allow for its callers to utilise VM_FAULT_RETRY functionality. This is necessary
as the invocation of __get_user_pages_unlocked() in process_vm_rw_single_vec()
makes use of this and no other existing higher level function would allow it to
do so.

Secondly existing callers of __get_user_pages_unlocked() are replaced with the
appropriate higher-level replacement - get_user_pages_unlocked() if the current
task and memory descriptor are referenced, or get_user_pages_remote() if other
task/memory descriptors are referenced (having acquiring mmap_sem.)

Lorenzo Stoakes (2):
  mm: add locked parameter to get_user_pages_remote()
  mm: unexport __get_user_pages_unlocked()

 drivers/gpu/drm/etnaviv/etnaviv_gem.c   |  2 +-
 drivers/gpu/drm/i915/i915_gem_userptr.c |  2 +-
 drivers/infiniband/core/umem_odp.c      |  2 +-
 fs/exec.c                               |  2 +-
 include/linux/mm.h                      |  5 +----
 kernel/events/uprobes.c                 |  4 ++--
 mm/gup.c                                | 20 ++++++++++++--------
 mm/memory.c                             |  2 +-
 mm/nommu.c                              |  7 +++----
 mm/process_vm_access.c                  | 12 ++++++++----
 security/tomoyo/domain.c                |  2 +-
 virt/kvm/async_pf.c                     | 10 +++++++---
 virt/kvm/kvm_main.c                     |  5 ++---
 13 files changed, 41 insertions(+), 34 deletions(-)

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 1/2] mm: add locked parameter to get_user_pages_remote()
  2016-10-27  9:51 [PATCH 0/2] mm: unexport __get_user_pages_unlocked() Lorenzo Stoakes
@ 2016-10-27  9:51 ` Lorenzo Stoakes
  2016-10-27 10:55   ` Michal Hocko
  2016-10-27  9:51 ` [PATCH 2/2] mm: unexport __get_user_pages_unlocked() Lorenzo Stoakes
  2016-10-27  9:54 ` [PATCH 0/2] " Lorenzo Stoakes
  2 siblings, 1 reply; 7+ messages in thread
From: Lorenzo Stoakes @ 2016-10-27  9:51 UTC (permalink / raw)
  To: linux-mm
  Cc: Michal Hocko, Linus Torvalds, Jan Kara, Hugh Dickins,
	Dave Hansen, Rik van Riel, Mel Gorman, Andrew Morton,
	Paolo Bonzini, Radim Krčmář,
	kvm, linux-kernel, linux-security-module, linux-rdma, dri-devel,
	linux-fsdevel, Lorenzo Stoakes

This patch adds a int *locked parameter to get_user_pages_remote() to allow
VM_FAULT_RETRY faulting behaviour similar to get_user_pages_[un]locked().

Taking into account the previous adjustments to get_user_pages*() functions
allowing for the passing of gup_flags, we are now in a position where
__get_user_pages_unlocked() need only be exported for his ability to allow
VM_FAULT_RETRY behaviour, this adjustment allows us to subsequently unexport
__get_user_pages_unlocked() as well as allowing for future flexibility in the
use of get_user_pages_remote().

Signed-off-by: Lorenzo Stoakes <lstoakes@gmail.com>
---
 drivers/gpu/drm/etnaviv/etnaviv_gem.c   |  2 +-
 drivers/gpu/drm/i915/i915_gem_userptr.c |  2 +-
 drivers/infiniband/core/umem_odp.c      |  2 +-
 fs/exec.c                               |  2 +-
 include/linux/mm.h                      |  2 +-
 kernel/events/uprobes.c                 |  4 ++--
 mm/gup.c                                | 12 ++++++++----
 mm/memory.c                             |  2 +-
 security/tomoyo/domain.c                |  2 +-
 9 files changed, 17 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.c b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
index 0370b84..0c69a97f 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
@@ -763,7 +763,7 @@ static struct page **etnaviv_gem_userptr_do_get_pages(
 	down_read(&mm->mmap_sem);
 	while (pinned < npages) {
 		ret = get_user_pages_remote(task, mm, ptr, npages - pinned,
-					    flags, pvec + pinned, NULL);
+					    flags, pvec + pinned, NULL, 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 c6f780f..836b525 100644
--- a/drivers/gpu/drm/i915/i915_gem_userptr.c
+++ b/drivers/gpu/drm/i915/i915_gem_userptr.c
@@ -522,7 +522,7 @@ __i915_gem_userptr_get_pages_worker(struct work_struct *_work)
 					 obj->userptr.ptr + pinned * PAGE_SIZE,
 					 npages - pinned,
 					 flags,
-					 pvec + pinned, NULL);
+					 pvec + pinned, NULL, NULL);
 				if (ret < 0)
 					break;

diff --git a/drivers/infiniband/core/umem_odp.c b/drivers/infiniband/core/umem_odp.c
index 1f0fe32..6b079a3 100644
--- a/drivers/infiniband/core/umem_odp.c
+++ b/drivers/infiniband/core/umem_odp.c
@@ -578,7 +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,
-				flags, local_page_list, NULL);
+				flags, local_page_list, NULL, NULL);
 		up_read(&owning_mm->mmap_sem);

 		if (npages < 0)
diff --git a/fs/exec.c b/fs/exec.c
index 4e497b9..2cf049d 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -209,7 +209,7 @@ static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
 	 * doing the exec and bprm->mm is the new process's mm.
 	 */
 	ret = get_user_pages_remote(current, bprm->mm, pos, 1, gup_flags,
-			&page, NULL);
+			&page, NULL, NULL);
 	if (ret <= 0)
 		return NULL;

diff --git a/include/linux/mm.h b/include/linux/mm.h
index a92c8d7..cc15445 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -1274,7 +1274,7 @@ extern int access_remote_vm(struct mm_struct *mm, unsigned long addr,
 long get_user_pages_remote(struct task_struct *tsk, struct mm_struct *mm,
 			    unsigned long start, unsigned long nr_pages,
 			    unsigned int gup_flags, struct page **pages,
-			    struct vm_area_struct **vmas);
+			    struct vm_area_struct **vmas, int *locked);
 long get_user_pages(unsigned long start, unsigned long nr_pages,
 			    unsigned int gup_flags, struct page **pages,
 			    struct vm_area_struct **vmas);
diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
index f9ec9ad..215871b 100644
--- a/kernel/events/uprobes.c
+++ b/kernel/events/uprobes.c
@@ -301,7 +301,7 @@ 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, FOLL_FORCE, &old_page,
-			&vma);
+			&vma, NULL);
 	if (ret <= 0)
 		return ret;

@@ -1712,7 +1712,7 @@ static int is_trap_at_addr(struct mm_struct *mm, unsigned long vaddr)
 	 * essentially a kernel access to the memory.
 	 */
 	result = get_user_pages_remote(NULL, mm, vaddr, 1, FOLL_FORCE, &page,
-			NULL);
+			NULL, NULL);
 	if (result < 0)
 		return result;

diff --git a/mm/gup.c b/mm/gup.c
index ec4f827..0567851 100644
--- a/mm/gup.c
+++ b/mm/gup.c
@@ -920,6 +920,9 @@ EXPORT_SYMBOL(get_user_pages_unlocked);
  *		only intends to ensure the pages are faulted in.
  * @vmas:	array of pointers to vmas corresponding to each page.
  *		Or NULL if the caller does not require them.
+ * @locked:	pointer to lock flag indicating whether lock is held and
+ *		subsequently whether VM_FAULT_RETRY functionality can be
+ *		utilised. Lock must initially be held.
  *
  * Returns number of pages pinned. This may be fewer than the number
  * requested. If nr_pages is 0 or negative, returns 0. If no pages
@@ -963,10 +966,10 @@ 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,
 		unsigned int gup_flags, struct page **pages,
-		struct vm_area_struct **vmas)
+		struct vm_area_struct **vmas, int *locked)
 {
 	return __get_user_pages_locked(tsk, mm, start, nr_pages, pages, vmas,
-				       NULL, false,
+				       locked, true,
 				       gup_flags | FOLL_TOUCH | FOLL_REMOTE);
 }
 EXPORT_SYMBOL(get_user_pages_remote);
@@ -974,8 +977,9 @@ EXPORT_SYMBOL(get_user_pages_remote);
 /*
  * This is the same as get_user_pages_remote(), just with a
  * less-flexible calling convention where we assume that the task
- * and mm being operated on are the current task's.  We also
- * obviously don't pass FOLL_REMOTE in here.
+ * and mm being operated on are the current task's and don't allow
+ * passing of a locked parameter.  We also obviously don't pass
+ * FOLL_REMOTE in here.
  */
 long get_user_pages(unsigned long start, unsigned long nr_pages,
 		unsigned int gup_flags, struct page **pages,
diff --git a/mm/memory.c b/mm/memory.c
index e18c57b..2f3949b 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -3883,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,
-				gup_flags, &page, &vma);
+				gup_flags, &page, &vma, NULL);
 		if (ret <= 0) {
 #ifndef CONFIG_HAVE_IOREMAP_PROT
 			break;
diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c
index 682b73a..838ffa7 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,
-				FOLL_FORCE, &page, NULL) <= 0)
+				FOLL_FORCE, &page, NULL, NULL) <= 0)
 		return false;
 #else
 	page = bprm->page[pos / PAGE_SIZE];
--
2.10.1

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 2/2] mm: unexport __get_user_pages_unlocked()
  2016-10-27  9:51 [PATCH 0/2] mm: unexport __get_user_pages_unlocked() Lorenzo Stoakes
  2016-10-27  9:51 ` [PATCH 1/2] mm: add locked parameter to get_user_pages_remote() Lorenzo Stoakes
@ 2016-10-27  9:51 ` Lorenzo Stoakes
  2016-10-27 10:57   ` Michal Hocko
  2016-10-27  9:54 ` [PATCH 0/2] " Lorenzo Stoakes
  2 siblings, 1 reply; 7+ messages in thread
From: Lorenzo Stoakes @ 2016-10-27  9:51 UTC (permalink / raw)
  To: linux-mm
  Cc: Michal Hocko, Linus Torvalds, Jan Kara, Hugh Dickins,
	Dave Hansen, Rik van Riel, Mel Gorman, Andrew Morton,
	Paolo Bonzini, Radim Krčmář,
	kvm, linux-kernel, linux-security-module, linux-rdma, dri-devel,
	linux-fsdevel, Lorenzo Stoakes

This patch unexports the low-level __get_user_pages_unlocked() function and
replaces invocations with calls to more appropriate higher-level functions.

In hva_to_pfn_slow() we are able to replace __get_user_pages_unlocked() with
get_user_pages_unlocked() since we can now pass gup_flags.

In async_pf_execute() and process_vm_rw_single_vec() we need to pass different
tsk, mm arguments so get_user_pages_remote() is the sane replacement in these
cases (having added manual acquisition and release of mmap_sem.)

Additionally get_user_pages_remote() reintroduces use of the FOLL_TOUCH
flag. However, this flag was originally silently dropped by 1e9877902dc7e
("mm/gup: Introduce get_user_pages_remote()"), so this appears to have been
unintentional and reintroducing it is therefore not an issue.

Signed-off-by: Lorenzo Stoakes <lstoakes@gmail.com>
---
 include/linux/mm.h     |  3 ---
 mm/gup.c               |  8 ++++----
 mm/nommu.c             |  7 +++----
 mm/process_vm_access.c | 12 ++++++++----
 virt/kvm/async_pf.c    | 10 +++++++---
 virt/kvm/kvm_main.c    |  5 ++---
 6 files changed, 24 insertions(+), 21 deletions(-)

diff --git a/include/linux/mm.h b/include/linux/mm.h
index cc15445..7b2d14e 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -1280,9 +1280,6 @@ long get_user_pages(unsigned long start, unsigned long nr_pages,
 			    struct vm_area_struct **vmas);
 long get_user_pages_locked(unsigned long start, unsigned long nr_pages,
 		    unsigned int gup_flags, struct page **pages, int *locked);
-long __get_user_pages_unlocked(struct task_struct *tsk, struct mm_struct *mm,
-			       unsigned long start, unsigned long nr_pages,
-			       struct page **pages, unsigned int gup_flags);
 long get_user_pages_unlocked(unsigned long start, unsigned long nr_pages,
 		    struct page **pages, unsigned int gup_flags);
 int get_user_pages_fast(unsigned long start, int nr_pages, int write,
diff --git a/mm/gup.c b/mm/gup.c
index 0567851..8028af1 100644
--- a/mm/gup.c
+++ b/mm/gup.c
@@ -866,9 +866,10 @@ EXPORT_SYMBOL(get_user_pages_locked);
  * caller if required (just like with __get_user_pages). "FOLL_GET"
  * is set implicitly if "pages" is non-NULL.
  */
-__always_inline long __get_user_pages_unlocked(struct task_struct *tsk, struct mm_struct *mm,
-					       unsigned long start, unsigned long nr_pages,
-					       struct page **pages, unsigned int gup_flags)
+static __always_inline long __get_user_pages_unlocked(struct task_struct *tsk,
+		struct mm_struct *mm, unsigned long start,
+		unsigned long nr_pages, struct page **pages,
+		unsigned int gup_flags)
 {
 	long ret;
 	int locked = 1;
@@ -880,7 +881,6 @@ __always_inline long __get_user_pages_unlocked(struct task_struct *tsk, struct m
 		up_read(&mm->mmap_sem);
 	return ret;
 }
-EXPORT_SYMBOL(__get_user_pages_unlocked);

 /*
  * get_user_pages_unlocked() is suitable to replace the form:
diff --git a/mm/nommu.c b/mm/nommu.c
index 8b8faaf..669437b 100644
--- a/mm/nommu.c
+++ b/mm/nommu.c
@@ -176,9 +176,9 @@ long get_user_pages_locked(unsigned long start, unsigned long nr_pages,
 }
 EXPORT_SYMBOL(get_user_pages_locked);

-long __get_user_pages_unlocked(struct task_struct *tsk, struct mm_struct *mm,
-			       unsigned long start, unsigned long nr_pages,
-			       struct page **pages, unsigned int gup_flags)
+static long __get_user_pages_unlocked(struct task_struct *tsk, struct mm_struct *mm,
+				      unsigned long start, unsigned long nr_pages,
+			              struct page **pages, unsigned int gup_flags)
 {
 	long ret;
 	down_read(&mm->mmap_sem);
@@ -187,7 +187,6 @@ long __get_user_pages_unlocked(struct task_struct *tsk, struct mm_struct *mm,
 	up_read(&mm->mmap_sem);
 	return ret;
 }
-EXPORT_SYMBOL(__get_user_pages_unlocked);

 long get_user_pages_unlocked(unsigned long start, unsigned long nr_pages,
 			     struct page **pages, unsigned int gup_flags)
diff --git a/mm/process_vm_access.c b/mm/process_vm_access.c
index be8dc8d..84d0c7e 100644
--- a/mm/process_vm_access.c
+++ b/mm/process_vm_access.c
@@ -88,7 +88,7 @@ static int process_vm_rw_single_vec(unsigned long addr,
 	ssize_t rc = 0;
 	unsigned long max_pages_per_loop = PVM_MAX_KMALLOC_PAGES
 		/ sizeof(struct pages *);
-	unsigned int flags = FOLL_REMOTE;
+	unsigned int flags = 0;

 	/* Work out address and page range required */
 	if (len == 0)
@@ -100,15 +100,19 @@ static int process_vm_rw_single_vec(unsigned long addr,

 	while (!rc && nr_pages && iov_iter_count(iter)) {
 		int pages = min(nr_pages, max_pages_per_loop);
+		int locked = 1;
 		size_t bytes;

 		/*
 		 * Get the pages we're interested in.  We must
-		 * add FOLL_REMOTE because task/mm might not
+		 * access remotely because task/mm might not
 		 * current/current->mm
 		 */
-		pages = __get_user_pages_unlocked(task, mm, pa, pages,
-						  process_pages, flags);
+		down_read(&mm->mmap_sem);
+		pages = get_user_pages_remote(task, mm, pa, pages, flags,
+					      process_pages, NULL, &locked);
+		if (locked)
+			up_read(&mm->mmap_sem);
 		if (pages <= 0)
 			return -EFAULT;

diff --git a/virt/kvm/async_pf.c b/virt/kvm/async_pf.c
index 8035cc1..dab8b19 100644
--- a/virt/kvm/async_pf.c
+++ b/virt/kvm/async_pf.c
@@ -76,16 +76,20 @@ static void async_pf_execute(struct work_struct *work)
 	struct kvm_vcpu *vcpu = apf->vcpu;
 	unsigned long addr = apf->addr;
 	gva_t gva = apf->gva;
+	int locked = 1;

 	might_sleep();

 	/*
 	 * This work is run asynchromously to the task which owns
 	 * mm and might be done in another context, so we must
-	 * use FOLL_REMOTE.
+	 * access remotely.
 	 */
-	__get_user_pages_unlocked(NULL, mm, addr, 1, NULL,
-			FOLL_WRITE | FOLL_REMOTE);
+	down_read(&mm->mmap_sem);
+	get_user_pages_remote(NULL, mm, addr, 1, FOLL_WRITE, NULL, NULL,
+			&locked);
+	if (locked)
+		up_read(&mm->mmap_sem);

 	kvm_async_page_present_sync(vcpu, apf);

diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 2907b7b..c45d951 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -1415,13 +1415,12 @@ static int hva_to_pfn_slow(unsigned long addr, bool *async, bool write_fault,
 		npages = get_user_page_nowait(addr, write_fault, page);
 		up_read(&current->mm->mmap_sem);
 	} else {
-		unsigned int flags = FOLL_TOUCH | FOLL_HWPOISON;
+		unsigned int flags = FOLL_HWPOISON;

 		if (write_fault)
 			flags |= FOLL_WRITE;

-		npages = __get_user_pages_unlocked(current, current->mm, addr, 1,
-						   page, flags);
+		npages = get_user_pages_unlocked(addr, 1, page, flags);
 	}
 	if (npages != 1)
 		return npages;
--
2.10.1

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH 0/2] mm: unexport __get_user_pages_unlocked()
  2016-10-27  9:51 [PATCH 0/2] mm: unexport __get_user_pages_unlocked() Lorenzo Stoakes
  2016-10-27  9:51 ` [PATCH 1/2] mm: add locked parameter to get_user_pages_remote() Lorenzo Stoakes
  2016-10-27  9:51 ` [PATCH 2/2] mm: unexport __get_user_pages_unlocked() Lorenzo Stoakes
@ 2016-10-27  9:54 ` Lorenzo Stoakes
  2 siblings, 0 replies; 7+ messages in thread
From: Lorenzo Stoakes @ 2016-10-27  9:54 UTC (permalink / raw)
  To: linux-mm
  Cc: Michal Hocko, Linus Torvalds, Jan Kara, Hugh Dickins,
	Dave Hansen, Rik van Riel, Mel Gorman, Andrew Morton,
	Paolo Bonzini, Radim Krčmář,
	kvm, linux-kernel, linux-security-module, linux-rdma, dri-devel,
	linux-fsdevel

On Thu, Oct 27, 2016 at 10:51:39AM +0100, Lorenzo Stoakes wrote:
> This patch series continues the cleanup of get_user_pages*() functions taking
> advantage of the fact we can now pass gup_flags as we please.

Note that this patch series has an unfortunate trivial dependency on my recent
'fix up get_user_pages* comments' patch which means this series applies against
-mmots but not mainline at this point in time.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/2] mm: add locked parameter to get_user_pages_remote()
  2016-10-27  9:51 ` [PATCH 1/2] mm: add locked parameter to get_user_pages_remote() Lorenzo Stoakes
@ 2016-10-27 10:55   ` Michal Hocko
  2016-10-27 10:59     ` Michal Hocko
  0 siblings, 1 reply; 7+ messages in thread
From: Michal Hocko @ 2016-10-27 10:55 UTC (permalink / raw)
  To: Lorenzo Stoakes
  Cc: linux-mm, Linus Torvalds, Jan Kara, Hugh Dickins, Dave Hansen,
	Rik van Riel, Mel Gorman, Andrew Morton, Paolo Bonzini,
	Radim Krčmář,
	kvm, linux-kernel, linux-security-module, linux-rdma, dri-devel,
	linux-fsdevel

On Thu 27-10-16 10:51:40, Lorenzo Stoakes wrote:
> This patch adds a int *locked parameter to get_user_pages_remote() to allow
> VM_FAULT_RETRY faulting behaviour similar to get_user_pages_[un]locked().
> 
> Taking into account the previous adjustments to get_user_pages*() functions
> allowing for the passing of gup_flags, we are now in a position where
> __get_user_pages_unlocked() need only be exported for his ability to allow
> VM_FAULT_RETRY behaviour, this adjustment allows us to subsequently unexport
> __get_user_pages_unlocked() as well as allowing for future flexibility in the
> use of get_user_pages_remote().

I would also add that this shouldn't introduce any functional change.

> Signed-off-by: Lorenzo Stoakes <lstoakes@gmail.com>

Acked-by: Michal Hocko <mhocko@suse.com>

> ---
>  drivers/gpu/drm/etnaviv/etnaviv_gem.c   |  2 +-
>  drivers/gpu/drm/i915/i915_gem_userptr.c |  2 +-
>  drivers/infiniband/core/umem_odp.c      |  2 +-
>  fs/exec.c                               |  2 +-
>  include/linux/mm.h                      |  2 +-
>  kernel/events/uprobes.c                 |  4 ++--
>  mm/gup.c                                | 12 ++++++++----
>  mm/memory.c                             |  2 +-
>  security/tomoyo/domain.c                |  2 +-
>  9 files changed, 17 insertions(+), 13 deletions(-)
> 
> diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.c b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
> index 0370b84..0c69a97f 100644
> --- a/drivers/gpu/drm/etnaviv/etnaviv_gem.c
> +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
> @@ -763,7 +763,7 @@ static struct page **etnaviv_gem_userptr_do_get_pages(
>  	down_read(&mm->mmap_sem);
>  	while (pinned < npages) {
>  		ret = get_user_pages_remote(task, mm, ptr, npages - pinned,
> -					    flags, pvec + pinned, NULL);
> +					    flags, pvec + pinned, NULL, 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 c6f780f..836b525 100644
> --- a/drivers/gpu/drm/i915/i915_gem_userptr.c
> +++ b/drivers/gpu/drm/i915/i915_gem_userptr.c
> @@ -522,7 +522,7 @@ __i915_gem_userptr_get_pages_worker(struct work_struct *_work)
>  					 obj->userptr.ptr + pinned * PAGE_SIZE,
>  					 npages - pinned,
>  					 flags,
> -					 pvec + pinned, NULL);
> +					 pvec + pinned, NULL, NULL);
>  				if (ret < 0)
>  					break;
> 
> diff --git a/drivers/infiniband/core/umem_odp.c b/drivers/infiniband/core/umem_odp.c
> index 1f0fe32..6b079a3 100644
> --- a/drivers/infiniband/core/umem_odp.c
> +++ b/drivers/infiniband/core/umem_odp.c
> @@ -578,7 +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,
> -				flags, local_page_list, NULL);
> +				flags, local_page_list, NULL, NULL);
>  		up_read(&owning_mm->mmap_sem);
> 
>  		if (npages < 0)
> diff --git a/fs/exec.c b/fs/exec.c
> index 4e497b9..2cf049d 100644
> --- a/fs/exec.c
> +++ b/fs/exec.c
> @@ -209,7 +209,7 @@ static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
>  	 * doing the exec and bprm->mm is the new process's mm.
>  	 */
>  	ret = get_user_pages_remote(current, bprm->mm, pos, 1, gup_flags,
> -			&page, NULL);
> +			&page, NULL, NULL);
>  	if (ret <= 0)
>  		return NULL;
> 
> diff --git a/include/linux/mm.h b/include/linux/mm.h
> index a92c8d7..cc15445 100644
> --- a/include/linux/mm.h
> +++ b/include/linux/mm.h
> @@ -1274,7 +1274,7 @@ extern int access_remote_vm(struct mm_struct *mm, unsigned long addr,
>  long get_user_pages_remote(struct task_struct *tsk, struct mm_struct *mm,
>  			    unsigned long start, unsigned long nr_pages,
>  			    unsigned int gup_flags, struct page **pages,
> -			    struct vm_area_struct **vmas);
> +			    struct vm_area_struct **vmas, int *locked);
>  long get_user_pages(unsigned long start, unsigned long nr_pages,
>  			    unsigned int gup_flags, struct page **pages,
>  			    struct vm_area_struct **vmas);
> diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
> index f9ec9ad..215871b 100644
> --- a/kernel/events/uprobes.c
> +++ b/kernel/events/uprobes.c
> @@ -301,7 +301,7 @@ 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, FOLL_FORCE, &old_page,
> -			&vma);
> +			&vma, NULL);
>  	if (ret <= 0)
>  		return ret;
> 
> @@ -1712,7 +1712,7 @@ static int is_trap_at_addr(struct mm_struct *mm, unsigned long vaddr)
>  	 * essentially a kernel access to the memory.
>  	 */
>  	result = get_user_pages_remote(NULL, mm, vaddr, 1, FOLL_FORCE, &page,
> -			NULL);
> +			NULL, NULL);
>  	if (result < 0)
>  		return result;
> 
> diff --git a/mm/gup.c b/mm/gup.c
> index ec4f827..0567851 100644
> --- a/mm/gup.c
> +++ b/mm/gup.c
> @@ -920,6 +920,9 @@ EXPORT_SYMBOL(get_user_pages_unlocked);
>   *		only intends to ensure the pages are faulted in.
>   * @vmas:	array of pointers to vmas corresponding to each page.
>   *		Or NULL if the caller does not require them.
> + * @locked:	pointer to lock flag indicating whether lock is held and
> + *		subsequently whether VM_FAULT_RETRY functionality can be
> + *		utilised. Lock must initially be held.
>   *
>   * Returns number of pages pinned. This may be fewer than the number
>   * requested. If nr_pages is 0 or negative, returns 0. If no pages
> @@ -963,10 +966,10 @@ 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,
>  		unsigned int gup_flags, struct page **pages,
> -		struct vm_area_struct **vmas)
> +		struct vm_area_struct **vmas, int *locked)
>  {
>  	return __get_user_pages_locked(tsk, mm, start, nr_pages, pages, vmas,
> -				       NULL, false,
> +				       locked, true,
>  				       gup_flags | FOLL_TOUCH | FOLL_REMOTE);
>  }
>  EXPORT_SYMBOL(get_user_pages_remote);
> @@ -974,8 +977,9 @@ EXPORT_SYMBOL(get_user_pages_remote);
>  /*
>   * This is the same as get_user_pages_remote(), just with a
>   * less-flexible calling convention where we assume that the task
> - * and mm being operated on are the current task's.  We also
> - * obviously don't pass FOLL_REMOTE in here.
> + * and mm being operated on are the current task's and don't allow
> + * passing of a locked parameter.  We also obviously don't pass
> + * FOLL_REMOTE in here.
>   */
>  long get_user_pages(unsigned long start, unsigned long nr_pages,
>  		unsigned int gup_flags, struct page **pages,
> diff --git a/mm/memory.c b/mm/memory.c
> index e18c57b..2f3949b 100644
> --- a/mm/memory.c
> +++ b/mm/memory.c
> @@ -3883,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,
> -				gup_flags, &page, &vma);
> +				gup_flags, &page, &vma, NULL);
>  		if (ret <= 0) {
>  #ifndef CONFIG_HAVE_IOREMAP_PROT
>  			break;
> diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c
> index 682b73a..838ffa7 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,
> -				FOLL_FORCE, &page, NULL) <= 0)
> +				FOLL_FORCE, &page, NULL, NULL) <= 0)
>  		return false;
>  #else
>  	page = bprm->page[pos / PAGE_SIZE];
> --
> 2.10.1

-- 
Michal Hocko
SUSE Labs

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 2/2] mm: unexport __get_user_pages_unlocked()
  2016-10-27  9:51 ` [PATCH 2/2] mm: unexport __get_user_pages_unlocked() Lorenzo Stoakes
@ 2016-10-27 10:57   ` Michal Hocko
  0 siblings, 0 replies; 7+ messages in thread
From: Michal Hocko @ 2016-10-27 10:57 UTC (permalink / raw)
  To: Lorenzo Stoakes
  Cc: linux-mm, Linus Torvalds, Jan Kara, Hugh Dickins, Dave Hansen,
	Rik van Riel, Mel Gorman, Andrew Morton, Paolo Bonzini,
	Radim Krčmář,
	kvm, linux-kernel, linux-security-module, linux-rdma, dri-devel,
	linux-fsdevel

On Thu 27-10-16 10:51:41, Lorenzo Stoakes wrote:
> This patch unexports the low-level __get_user_pages_unlocked() function and
> replaces invocations with calls to more appropriate higher-level functions.
> 
> In hva_to_pfn_slow() we are able to replace __get_user_pages_unlocked() with
> get_user_pages_unlocked() since we can now pass gup_flags.
> 
> In async_pf_execute() and process_vm_rw_single_vec() we need to pass different
> tsk, mm arguments so get_user_pages_remote() is the sane replacement in these
> cases (having added manual acquisition and release of mmap_sem.)
> 
> Additionally get_user_pages_remote() reintroduces use of the FOLL_TOUCH
> flag. However, this flag was originally silently dropped by 1e9877902dc7e
> ("mm/gup: Introduce get_user_pages_remote()"), so this appears to have been
> unintentional and reintroducing it is therefore not an issue.

Looks good to me.
 
> Signed-off-by: Lorenzo Stoakes <lstoakes@gmail.com>

Acked-by: Michal Hocko <mhocko@suse.com>

> ---
>  include/linux/mm.h     |  3 ---
>  mm/gup.c               |  8 ++++----
>  mm/nommu.c             |  7 +++----
>  mm/process_vm_access.c | 12 ++++++++----
>  virt/kvm/async_pf.c    | 10 +++++++---
>  virt/kvm/kvm_main.c    |  5 ++---
>  6 files changed, 24 insertions(+), 21 deletions(-)
> 
> diff --git a/include/linux/mm.h b/include/linux/mm.h
> index cc15445..7b2d14e 100644
> --- a/include/linux/mm.h
> +++ b/include/linux/mm.h
> @@ -1280,9 +1280,6 @@ long get_user_pages(unsigned long start, unsigned long nr_pages,
>  			    struct vm_area_struct **vmas);
>  long get_user_pages_locked(unsigned long start, unsigned long nr_pages,
>  		    unsigned int gup_flags, struct page **pages, int *locked);
> -long __get_user_pages_unlocked(struct task_struct *tsk, struct mm_struct *mm,
> -			       unsigned long start, unsigned long nr_pages,
> -			       struct page **pages, unsigned int gup_flags);
>  long get_user_pages_unlocked(unsigned long start, unsigned long nr_pages,
>  		    struct page **pages, unsigned int gup_flags);
>  int get_user_pages_fast(unsigned long start, int nr_pages, int write,
> diff --git a/mm/gup.c b/mm/gup.c
> index 0567851..8028af1 100644
> --- a/mm/gup.c
> +++ b/mm/gup.c
> @@ -866,9 +866,10 @@ EXPORT_SYMBOL(get_user_pages_locked);
>   * caller if required (just like with __get_user_pages). "FOLL_GET"
>   * is set implicitly if "pages" is non-NULL.
>   */
> -__always_inline long __get_user_pages_unlocked(struct task_struct *tsk, struct mm_struct *mm,
> -					       unsigned long start, unsigned long nr_pages,
> -					       struct page **pages, unsigned int gup_flags)
> +static __always_inline long __get_user_pages_unlocked(struct task_struct *tsk,
> +		struct mm_struct *mm, unsigned long start,
> +		unsigned long nr_pages, struct page **pages,
> +		unsigned int gup_flags)
>  {
>  	long ret;
>  	int locked = 1;
> @@ -880,7 +881,6 @@ __always_inline long __get_user_pages_unlocked(struct task_struct *tsk, struct m
>  		up_read(&mm->mmap_sem);
>  	return ret;
>  }
> -EXPORT_SYMBOL(__get_user_pages_unlocked);
> 
>  /*
>   * get_user_pages_unlocked() is suitable to replace the form:
> diff --git a/mm/nommu.c b/mm/nommu.c
> index 8b8faaf..669437b 100644
> --- a/mm/nommu.c
> +++ b/mm/nommu.c
> @@ -176,9 +176,9 @@ long get_user_pages_locked(unsigned long start, unsigned long nr_pages,
>  }
>  EXPORT_SYMBOL(get_user_pages_locked);
> 
> -long __get_user_pages_unlocked(struct task_struct *tsk, struct mm_struct *mm,
> -			       unsigned long start, unsigned long nr_pages,
> -			       struct page **pages, unsigned int gup_flags)
> +static long __get_user_pages_unlocked(struct task_struct *tsk, struct mm_struct *mm,
> +				      unsigned long start, unsigned long nr_pages,
> +			              struct page **pages, unsigned int gup_flags)
>  {
>  	long ret;
>  	down_read(&mm->mmap_sem);
> @@ -187,7 +187,6 @@ long __get_user_pages_unlocked(struct task_struct *tsk, struct mm_struct *mm,
>  	up_read(&mm->mmap_sem);
>  	return ret;
>  }
> -EXPORT_SYMBOL(__get_user_pages_unlocked);
> 
>  long get_user_pages_unlocked(unsigned long start, unsigned long nr_pages,
>  			     struct page **pages, unsigned int gup_flags)
> diff --git a/mm/process_vm_access.c b/mm/process_vm_access.c
> index be8dc8d..84d0c7e 100644
> --- a/mm/process_vm_access.c
> +++ b/mm/process_vm_access.c
> @@ -88,7 +88,7 @@ static int process_vm_rw_single_vec(unsigned long addr,
>  	ssize_t rc = 0;
>  	unsigned long max_pages_per_loop = PVM_MAX_KMALLOC_PAGES
>  		/ sizeof(struct pages *);
> -	unsigned int flags = FOLL_REMOTE;
> +	unsigned int flags = 0;
> 
>  	/* Work out address and page range required */
>  	if (len == 0)
> @@ -100,15 +100,19 @@ static int process_vm_rw_single_vec(unsigned long addr,
> 
>  	while (!rc && nr_pages && iov_iter_count(iter)) {
>  		int pages = min(nr_pages, max_pages_per_loop);
> +		int locked = 1;
>  		size_t bytes;
> 
>  		/*
>  		 * Get the pages we're interested in.  We must
> -		 * add FOLL_REMOTE because task/mm might not
> +		 * access remotely because task/mm might not
>  		 * current/current->mm
>  		 */
> -		pages = __get_user_pages_unlocked(task, mm, pa, pages,
> -						  process_pages, flags);
> +		down_read(&mm->mmap_sem);
> +		pages = get_user_pages_remote(task, mm, pa, pages, flags,
> +					      process_pages, NULL, &locked);
> +		if (locked)
> +			up_read(&mm->mmap_sem);
>  		if (pages <= 0)
>  			return -EFAULT;
> 
> diff --git a/virt/kvm/async_pf.c b/virt/kvm/async_pf.c
> index 8035cc1..dab8b19 100644
> --- a/virt/kvm/async_pf.c
> +++ b/virt/kvm/async_pf.c
> @@ -76,16 +76,20 @@ static void async_pf_execute(struct work_struct *work)
>  	struct kvm_vcpu *vcpu = apf->vcpu;
>  	unsigned long addr = apf->addr;
>  	gva_t gva = apf->gva;
> +	int locked = 1;
> 
>  	might_sleep();
> 
>  	/*
>  	 * This work is run asynchromously to the task which owns
>  	 * mm and might be done in another context, so we must
> -	 * use FOLL_REMOTE.
> +	 * access remotely.
>  	 */
> -	__get_user_pages_unlocked(NULL, mm, addr, 1, NULL,
> -			FOLL_WRITE | FOLL_REMOTE);
> +	down_read(&mm->mmap_sem);
> +	get_user_pages_remote(NULL, mm, addr, 1, FOLL_WRITE, NULL, NULL,
> +			&locked);
> +	if (locked)
> +		up_read(&mm->mmap_sem);
> 
>  	kvm_async_page_present_sync(vcpu, apf);
> 
> diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
> index 2907b7b..c45d951 100644
> --- a/virt/kvm/kvm_main.c
> +++ b/virt/kvm/kvm_main.c
> @@ -1415,13 +1415,12 @@ static int hva_to_pfn_slow(unsigned long addr, bool *async, bool write_fault,
>  		npages = get_user_page_nowait(addr, write_fault, page);
>  		up_read(&current->mm->mmap_sem);
>  	} else {
> -		unsigned int flags = FOLL_TOUCH | FOLL_HWPOISON;
> +		unsigned int flags = FOLL_HWPOISON;
> 
>  		if (write_fault)
>  			flags |= FOLL_WRITE;
> 
> -		npages = __get_user_pages_unlocked(current, current->mm, addr, 1,
> -						   page, flags);
> +		npages = get_user_pages_unlocked(addr, 1, page, flags);
>  	}
>  	if (npages != 1)
>  		return npages;
> --
> 2.10.1

-- 
Michal Hocko
SUSE Labs

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/2] mm: add locked parameter to get_user_pages_remote()
  2016-10-27 10:55   ` Michal Hocko
@ 2016-10-27 10:59     ` Michal Hocko
  0 siblings, 0 replies; 7+ messages in thread
From: Michal Hocko @ 2016-10-27 10:59 UTC (permalink / raw)
  To: Lorenzo Stoakes
  Cc: linux-mm, Linus Torvalds, Jan Kara, Hugh Dickins, Dave Hansen,
	Rik van Riel, Mel Gorman, Andrew Morton, Paolo Bonzini,
	Radim Krčmář,
	kvm, linux-kernel, linux-security-module, linux-rdma, dri-devel,
	linux-fsdevel

On Thu 27-10-16 12:55:27, Michal Hocko wrote:
> On Thu 27-10-16 10:51:40, Lorenzo Stoakes wrote:
> > This patch adds a int *locked parameter to get_user_pages_remote() to allow
> > VM_FAULT_RETRY faulting behaviour similar to get_user_pages_[un]locked().
> > 
> > Taking into account the previous adjustments to get_user_pages*() functions
> > allowing for the passing of gup_flags, we are now in a position where
> > __get_user_pages_unlocked() need only be exported for his ability to allow
> > VM_FAULT_RETRY behaviour, this adjustment allows us to subsequently unexport
> > __get_user_pages_unlocked() as well as allowing for future flexibility in the
> > use of get_user_pages_remote().
> 
> I would also add that this shouldn't introduce any functional change.

Forgot to mention that this also opens doors to change other g_u_p_r
callers to allow FAULT_RETRY logic.

-- 
Michal Hocko
SUSE Labs

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2016-10-27 15:20 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-10-27  9:51 [PATCH 0/2] mm: unexport __get_user_pages_unlocked() Lorenzo Stoakes
2016-10-27  9:51 ` [PATCH 1/2] mm: add locked parameter to get_user_pages_remote() Lorenzo Stoakes
2016-10-27 10:55   ` Michal Hocko
2016-10-27 10:59     ` Michal Hocko
2016-10-27  9:51 ` [PATCH 2/2] mm: unexport __get_user_pages_unlocked() Lorenzo Stoakes
2016-10-27 10:57   ` Michal Hocko
2016-10-27  9:54 ` [PATCH 0/2] " Lorenzo Stoakes

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).