* [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(¤t->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(¤t->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).