diff options
author | Gleb Natapov <gleb@redhat.com> | 2011-03-22 19:30:51 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-22 20:44:02 -0400 |
commit | 318b275fbca1ab9ec0862de71420e0e92c3d1aa7 (patch) | |
tree | aa4984469443ed53b4e7fa23d3f91966e536a803 /mm | |
parent | 5fda1bd5b8869574dad8e1f9f71e23bf0c186274 (diff) |
mm: allow GUP to fail instead of waiting on a page
GUP user may want to try to acquire a reference to a page if it is already
in memory, but not if IO, to bring it in, is needed. For example KVM may
tell vcpu to schedule another guest process if current one is trying to
access swapped out page. Meanwhile, the page will be swapped in and the
guest process, that depends on it, will be able to run again.
This patch adds FAULT_FLAG_RETRY_NOWAIT (suggested by Linus) and
FOLL_NOWAIT follow_page flags. FAULT_FLAG_RETRY_NOWAIT, when used in
conjunction with VM_FAULT_ALLOW_RETRY, indicates to handle_mm_fault that
it shouldn't drop mmap_sem and wait on a page, but return VM_FAULT_RETRY
instead.
[akpm@linux-foundation.org: improve FOLL_NOWAIT comment]
Signed-off-by: Gleb Natapov <gleb@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Hugh Dickins <hughd@google.com>
Acked-by: Rik van Riel <riel@redhat.com>
Cc: Michel Lespinasse <walken@google.com>
Cc: Avi Kivity <avi@redhat.com>
Cc: Marcelo Tosatti <mtosatti@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm')
-rw-r--r-- | mm/filemap.c | 6 | ||||
-rw-r--r-- | mm/memory.c | 5 |
2 files changed, 8 insertions, 3 deletions
diff --git a/mm/filemap.c b/mm/filemap.c index 83a45d35468b..312b6eb78430 100644 --- a/mm/filemap.c +++ b/mm/filemap.c | |||
@@ -621,8 +621,10 @@ int __lock_page_or_retry(struct page *page, struct mm_struct *mm, | |||
621 | __lock_page(page); | 621 | __lock_page(page); |
622 | return 1; | 622 | return 1; |
623 | } else { | 623 | } else { |
624 | up_read(&mm->mmap_sem); | 624 | if (!(flags & FAULT_FLAG_RETRY_NOWAIT)) { |
625 | wait_on_page_locked(page); | 625 | up_read(&mm->mmap_sem); |
626 | wait_on_page_locked(page); | ||
627 | } | ||
626 | return 0; | 628 | return 0; |
627 | } | 629 | } |
628 | } | 630 | } |
diff --git a/mm/memory.c b/mm/memory.c index e48945ab362b..615be5127ce1 100644 --- a/mm/memory.c +++ b/mm/memory.c | |||
@@ -1569,6 +1569,8 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm, | |||
1569 | fault_flags |= FAULT_FLAG_WRITE; | 1569 | fault_flags |= FAULT_FLAG_WRITE; |
1570 | if (nonblocking) | 1570 | if (nonblocking) |
1571 | fault_flags |= FAULT_FLAG_ALLOW_RETRY; | 1571 | fault_flags |= FAULT_FLAG_ALLOW_RETRY; |
1572 | if (foll_flags & FOLL_NOWAIT) | ||
1573 | fault_flags |= (FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_RETRY_NOWAIT); | ||
1572 | 1574 | ||
1573 | ret = handle_mm_fault(mm, vma, start, | 1575 | ret = handle_mm_fault(mm, vma, start, |
1574 | fault_flags); | 1576 | fault_flags); |
@@ -1595,7 +1597,8 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm, | |||
1595 | tsk->min_flt++; | 1597 | tsk->min_flt++; |
1596 | 1598 | ||
1597 | if (ret & VM_FAULT_RETRY) { | 1599 | if (ret & VM_FAULT_RETRY) { |
1598 | *nonblocking = 0; | 1600 | if (nonblocking) |
1601 | *nonblocking = 0; | ||
1599 | return i; | 1602 | return i; |
1600 | } | 1603 | } |
1601 | 1604 | ||