From: Nadav Amit <namit@xxxxxxxxxx> When FAULT_FLAG_RETRY_NOWAIT is set, the caller arguably wants only a lightweight reclaim to avoid a long reclamation, which would not respect the "NOWAIT" semantic. Regard the request in swap and file-backed page-faults accordingly during the first try. Cc: Andy Lutomirski <luto@xxxxxxxxxx> Cc: Peter Zijlstra <peterz@xxxxxxxxxxxxx> Cc: Sean Christopherson <seanjc@xxxxxxxxxx> Cc: Thomas Gleixner <tglx@xxxxxxxxxxxxx> Cc: Ingo Molnar <mingo@xxxxxxxxxx> Cc: Borislav Petkov <bp@xxxxxxxxx> Cc: Andrew Morton <akpm@xxxxxxxxxxxxxxxxxxxx> Cc: x86@xxxxxxxxxx Signed-off-by: Nadav Amit <namit@xxxxxxxxxx> --- mm/memory.c | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/mm/memory.c b/mm/memory.c index 13b9cf36268f..70899c92a9e6 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -2679,18 +2679,31 @@ static inline bool cow_user_page(struct page *dst, struct page *src, return ret; } -static gfp_t __get_fault_gfp_mask(struct vm_area_struct *vma) +static gfp_t massage_page_gfp_mask(gfp_t gfp_mask, unsigned long vmf_flags) { - struct file *vm_file = vma->vm_file; + if (fault_flag_allow_retry_first(vmf_flags) && + (vmf_flags & FAULT_FLAG_RETRY_NOWAIT)) + gfp_mask |= __GFP_NORETRY | __GFP_NOWARN; - if (vm_file) - return mapping_gfp_mask(vm_file->f_mapping) | __GFP_FS | __GFP_IO; + return gfp_mask; +} + +static gfp_t __get_fault_gfp_mask(struct vm_area_struct *vma, + unsigned long flags) +{ + struct file *vm_file = vma->vm_file; + gfp_t gfp_mask; /* * Special mappings (e.g. VDSO) do not have any file so fake * a default GFP_KERNEL for them. */ - return GFP_KERNEL; + if (!vm_file) + return GFP_KERNEL; + + gfp_mask = mapping_gfp_mask(vm_file->f_mapping) | __GFP_FS | __GFP_IO; + + return massage_page_gfp_mask(gfp_mask, flags); } /* @@ -3253,6 +3266,7 @@ EXPORT_SYMBOL(unmap_mapping_range); */ vm_fault_t do_swap_page(struct vm_fault *vmf) { + gfp_t gfp_mask = massage_page_gfp_mask(GFP_HIGHUSER_MOVABLE, vmf->flags); struct vm_area_struct *vma = vmf->vma; struct page *page = NULL, *swapcache; swp_entry_t entry; @@ -3293,8 +3307,7 @@ vm_fault_t do_swap_page(struct vm_fault *vmf) if (data_race(si->flags & SWP_SYNCHRONOUS_IO) && __swap_count(entry) == 1) { /* skip swapcache */ - page = alloc_page_vma(GFP_HIGHUSER_MOVABLE, vma, - vmf->address); + page = alloc_page_vma(gfp_mask, vma, vmf->address); if (page) { int err; @@ -3320,8 +3333,7 @@ vm_fault_t do_swap_page(struct vm_fault *vmf) swap_readpage(page, true); } } else { - page = swapin_readahead(entry, GFP_HIGHUSER_MOVABLE, - vmf); + page = swapin_readahead(entry, gfp_mask, vmf); swapcache = page; } @@ -4452,7 +4464,7 @@ static vm_fault_t __handle_mm_fault(struct vm_area_struct *vma, .address = address & PAGE_MASK, .flags = flags, .pgoff = linear_page_index(vma, address), - .gfp_mask = __get_fault_gfp_mask(vma), + .gfp_mask = __get_fault_gfp_mask(vma, flags), }; unsigned int dirty = flags & FAULT_FLAG_WRITE; struct mm_struct *mm = vma->vm_mm; -- 2.25.1