Commit 0857b9e95c1af8bfe84630ef6747b9d4d61de4c6

Authored by Gleb Natapov
Committed by Avi Kivity
1 parent 9e02fb9633

KVM: Enable async page fault processing

If asynchronous hva_to_pfn() is requested call GUP with FOLL_NOWAIT to
avoid sleeping on IO. Check for hwpoison is done at the same time,
otherwise check_user_page_hwpoison() will call GUP again and will put
vcpu to sleep.

Signed-off-by: Gleb Natapov <gleb@redhat.com>
Signed-off-by: Avi Kivity <avi@redhat.com>

Showing 1 changed file with 21 additions and 2 deletions Side-by-side Diff

... ... @@ -1037,6 +1037,17 @@
1037 1037 return fault_pfn;
1038 1038 }
1039 1039  
  1040 +int get_user_page_nowait(struct task_struct *tsk, struct mm_struct *mm,
  1041 + unsigned long start, int write, struct page **page)
  1042 +{
  1043 + int flags = FOLL_TOUCH | FOLL_NOWAIT | FOLL_HWPOISON | FOLL_GET;
  1044 +
  1045 + if (write)
  1046 + flags |= FOLL_WRITE;
  1047 +
  1048 + return __get_user_pages(tsk, mm, start, 1, flags, page, NULL, NULL);
  1049 +}
  1050 +
1040 1051 static inline int check_user_page_hwpoison(unsigned long addr)
1041 1052 {
1042 1053 int rc, flags = FOLL_TOUCH | FOLL_HWPOISON | FOLL_WRITE;
... ... @@ -1070,7 +1081,14 @@
1070 1081 if (writable)
1071 1082 *writable = write_fault;
1072 1083  
1073   - npages = get_user_pages_fast(addr, 1, write_fault, page);
  1084 + if (async) {
  1085 + down_read(&current->mm->mmap_sem);
  1086 + npages = get_user_page_nowait(current, current->mm,
  1087 + addr, write_fault, page);
  1088 + up_read(&current->mm->mmap_sem);
  1089 + } else
  1090 + npages = get_user_pages_fast(addr, 1, write_fault,
  1091 + page);
1074 1092  
1075 1093 /* map read fault as writable if possible */
1076 1094 if (unlikely(!write_fault) && npages == 1) {
... ... @@ -1093,7 +1111,8 @@
1093 1111 return get_fault_pfn();
1094 1112  
1095 1113 down_read(&current->mm->mmap_sem);
1096   - if (check_user_page_hwpoison(addr)) {
  1114 + if (npages == -EHWPOISON ||
  1115 + (!async && check_user_page_hwpoison(addr))) {
1097 1116 up_read(&current->mm->mmap_sem);
1098 1117 get_page(hwpoison_page);
1099 1118 return page_to_pfn(hwpoison_page);