Commit 2d3a36a4 authored by Michal Hocko's avatar Michal Hocko Committed by Linus Torvalds
Browse files

mm, mempolicy: fix up gup usage in lookup_node



ba841078 ("mm/mempolicy: Allow lookup_node() to handle fatal signal")
has added a special casing for 0 return value because that was a possible
gup return value when interrupted by fatal signal.  This has been fixed by
ae46d2aa ("mm/gup: Let __get_user_pages_locked() return -EINTR for
fatal signal") in the mean time so ba841078 can be reverted.

This patch however doesn't go all the way to revert it because the check
for 0 is wrong and confusing here.  Firstly it is inherently unsafe to
access the page when get_user_pages_locked returns 0 (aka no page
returned).

Fortunatelly this will not happen because get_user_pages_locked will not
return 0 when nr_pages > 0 unless FOLL_NOWAIT is specified which is not
the case here.  Document this potential error code in gup code while we
are at it.

Signed-off-by: default avatarMichal Hocko <mhocko@suse.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Cc: Peter Xu <peterx@redhat.com>
Link: http://lkml.kernel.org/r/20200421071026.18394-1-mhocko@kernel.org


Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 5b94ce2f
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -989,6 +989,7 @@ static int check_vma_flags(struct vm_area_struct *vma, unsigned long gup_flags)
 * -- If nr_pages is >0, but no pages were pinned, returns -errno.
 * -- If nr_pages is >0, and some pages were pinned, returns the number of
 *    pages pinned. Again, this may be less than nr_pages.
 * -- 0 return value is possible when the fault would need to be retried.
 *
 * The caller is responsible for releasing returned @pages, via put_page().
 *
@@ -1265,6 +1266,10 @@ retry:
}
EXPORT_SYMBOL_GPL(fixup_user_fault);

/*
 * Please note that this function, unlike __get_user_pages will not
 * return 0 for nr_pages > 0 without FOLL_NOWAIT
 */
static __always_inline long __get_user_pages_locked(struct task_struct *tsk,
						struct mm_struct *mm,
						unsigned long start,
+1 −4
Original line number Diff line number Diff line
@@ -927,10 +927,7 @@ static int lookup_node(struct mm_struct *mm, unsigned long addr)

	int locked = 1;
	err = get_user_pages_locked(addr & PAGE_MASK, 1, 0, &p, &locked);
	if (err == 0) {
		/* E.g. GUP interrupted by fatal signal */
		err = -EFAULT;
	} else if (err > 0) {
	if (err > 0) {
		err = page_to_nid(p);
		put_page(p);
	}