|
42 | 42 | #include <linux/psi.h>
|
43 | 43 | #include <linux/ramfs.h>
|
44 | 44 | #include <linux/page_idle.h>
|
| 45 | +#include <asm/pgalloc.h> |
45 | 46 | #include "internal.h"
|
46 | 47 |
|
47 | 48 | #define CREATE_TRACE_POINTS
|
@@ -2911,74 +2912,164 @@ vm_fault_t filemap_fault(struct vm_fault *vmf)
|
2911 | 2912 | }
|
2912 | 2913 | EXPORT_SYMBOL(filemap_fault);
|
2913 | 2914 |
|
2914 |
| -void filemap_map_pages(struct vm_fault *vmf, |
2915 |
| - pgoff_t start_pgoff, pgoff_t end_pgoff) |
| 2915 | +static bool filemap_map_pmd(struct vm_fault *vmf, struct page *page) |
2916 | 2916 | {
|
2917 |
| - struct file *file = vmf->vma->vm_file; |
| 2917 | + struct mm_struct *mm = vmf->vma->vm_mm; |
| 2918 | + |
| 2919 | + /* Huge page is mapped? No need to proceed. */ |
| 2920 | + if (pmd_trans_huge(*vmf->pmd)) { |
| 2921 | + unlock_page(page); |
| 2922 | + put_page(page); |
| 2923 | + return true; |
| 2924 | + } |
| 2925 | + |
| 2926 | + if (pmd_none(*vmf->pmd) && PageTransHuge(page)) { |
| 2927 | + vm_fault_t ret = do_set_pmd(vmf, page); |
| 2928 | + if (!ret) { |
| 2929 | + /* The page is mapped successfully, reference consumed. */ |
| 2930 | + unlock_page(page); |
| 2931 | + return true; |
| 2932 | + } |
| 2933 | + } |
| 2934 | + |
| 2935 | + if (pmd_none(*vmf->pmd)) { |
| 2936 | + vmf->ptl = pmd_lock(mm, vmf->pmd); |
| 2937 | + if (likely(pmd_none(*vmf->pmd))) { |
| 2938 | + mm_inc_nr_ptes(mm); |
| 2939 | + pmd_populate(mm, vmf->pmd, vmf->prealloc_pte); |
| 2940 | + vmf->prealloc_pte = NULL; |
| 2941 | + } |
| 2942 | + spin_unlock(vmf->ptl); |
| 2943 | + } |
| 2944 | + |
| 2945 | + /* See comment in handle_pte_fault() */ |
| 2946 | + if (pmd_devmap_trans_unstable(vmf->pmd)) { |
| 2947 | + unlock_page(page); |
| 2948 | + put_page(page); |
| 2949 | + return true; |
| 2950 | + } |
| 2951 | + |
| 2952 | + return false; |
| 2953 | +} |
| 2954 | + |
| 2955 | +static struct page *next_uptodate_page(struct page *page, |
| 2956 | + struct address_space *mapping, |
| 2957 | + struct xa_state *xas, pgoff_t end_pgoff) |
| 2958 | +{ |
| 2959 | + unsigned long max_idx; |
| 2960 | + |
| 2961 | + do { |
| 2962 | + if (!page) |
| 2963 | + return NULL; |
| 2964 | + if (xas_retry(xas, page)) |
| 2965 | + continue; |
| 2966 | + if (xa_is_value(page)) |
| 2967 | + continue; |
| 2968 | + if (PageLocked(page)) |
| 2969 | + continue; |
| 2970 | + if (!page_cache_get_speculative(page)) |
| 2971 | + continue; |
| 2972 | + /* Has the page moved or been split? */ |
| 2973 | + if (unlikely(page != xas_reload(xas))) |
| 2974 | + goto skip; |
| 2975 | + if (!PageUptodate(page) || PageReadahead(page)) |
| 2976 | + goto skip; |
| 2977 | + if (PageHWPoison(page)) |
| 2978 | + goto skip; |
| 2979 | + if (!trylock_page(page)) |
| 2980 | + goto skip; |
| 2981 | + if (page->mapping != mapping) |
| 2982 | + goto unlock; |
| 2983 | + if (!PageUptodate(page)) |
| 2984 | + goto unlock; |
| 2985 | + max_idx = DIV_ROUND_UP(i_size_read(mapping->host), PAGE_SIZE); |
| 2986 | + if (xas->xa_index >= max_idx) |
| 2987 | + goto unlock; |
| 2988 | + return page; |
| 2989 | +unlock: |
| 2990 | + unlock_page(page); |
| 2991 | +skip: |
| 2992 | + put_page(page); |
| 2993 | + } while ((page = xas_next_entry(xas, end_pgoff)) != NULL); |
| 2994 | + |
| 2995 | + return NULL; |
| 2996 | +} |
| 2997 | + |
| 2998 | +static inline struct page *first_map_page(struct address_space *mapping, |
| 2999 | + struct xa_state *xas, |
| 3000 | + pgoff_t end_pgoff) |
| 3001 | +{ |
| 3002 | + return next_uptodate_page(xas_find(xas, end_pgoff), |
| 3003 | + mapping, xas, end_pgoff); |
| 3004 | +} |
| 3005 | + |
| 3006 | +static inline struct page *next_map_page(struct address_space *mapping, |
| 3007 | + struct xa_state *xas, |
| 3008 | + pgoff_t end_pgoff) |
| 3009 | +{ |
| 3010 | + return next_uptodate_page(xas_next_entry(xas, end_pgoff), |
| 3011 | + mapping, xas, end_pgoff); |
| 3012 | +} |
| 3013 | + |
| 3014 | +vm_fault_t filemap_map_pages(struct vm_fault *vmf, |
| 3015 | + pgoff_t start_pgoff, pgoff_t end_pgoff) |
| 3016 | +{ |
| 3017 | + struct vm_area_struct *vma = vmf->vma; |
| 3018 | + struct file *file = vma->vm_file; |
2918 | 3019 | struct address_space *mapping = file->f_mapping;
|
2919 | 3020 | pgoff_t last_pgoff = start_pgoff;
|
2920 |
| - unsigned long max_idx; |
| 3021 | + unsigned long address = vmf->address; |
2921 | 3022 | XA_STATE(xas, &mapping->i_pages, start_pgoff);
|
2922 | 3023 | struct page *head, *page;
|
2923 | 3024 | unsigned int mmap_miss = READ_ONCE(file->f_ra.mmap_miss);
|
| 3025 | + vm_fault_t ret = 0; |
2924 | 3026 |
|
2925 | 3027 | rcu_read_lock();
|
2926 |
| - xas_for_each(&xas, head, end_pgoff) { |
2927 |
| - if (xas_retry(&xas, head)) |
2928 |
| - continue; |
2929 |
| - if (xa_is_value(head)) |
2930 |
| - goto next; |
| 3028 | + head = first_map_page(mapping, &xas, end_pgoff); |
| 3029 | + if (!head) |
| 3030 | + goto out; |
2931 | 3031 |
|
2932 |
| - /* |
2933 |
| - * Check for a locked page first, as a speculative |
2934 |
| - * reference may adversely influence page migration. |
2935 |
| - */ |
2936 |
| - if (PageLocked(head)) |
2937 |
| - goto next; |
2938 |
| - if (!page_cache_get_speculative(head)) |
2939 |
| - goto next; |
| 3032 | + if (filemap_map_pmd(vmf, head)) { |
| 3033 | + ret = VM_FAULT_NOPAGE; |
| 3034 | + goto out; |
| 3035 | + } |
2940 | 3036 |
|
2941 |
| - /* Has the page moved or been split? */ |
2942 |
| - if (unlikely(head != xas_reload(&xas))) |
2943 |
| - goto skip; |
| 3037 | + vmf->address = vma->vm_start + ((start_pgoff - vma->vm_pgoff) << PAGE_SHIFT); |
| 3038 | + vmf->pte = pte_offset_map_lock(vma->vm_mm, vmf->pmd, vmf->address, &vmf->ptl); |
| 3039 | + do { |
2944 | 3040 | page = find_subpage(head, xas.xa_index);
|
2945 |
| - |
2946 |
| - if (!PageUptodate(head) || |
2947 |
| - PageReadahead(page) || |
2948 |
| - PageHWPoison(page)) |
2949 |
| - goto skip; |
2950 |
| - if (!trylock_page(head)) |
2951 |
| - goto skip; |
2952 |
| - |
2953 |
| - if (head->mapping != mapping || !PageUptodate(head)) |
2954 |
| - goto unlock; |
2955 |
| - |
2956 |
| - max_idx = DIV_ROUND_UP(i_size_read(mapping->host), PAGE_SIZE); |
2957 |
| - if (xas.xa_index >= max_idx) |
| 3041 | + if (PageHWPoison(page)) |
2958 | 3042 | goto unlock;
|
2959 | 3043 |
|
2960 | 3044 | if (mmap_miss > 0)
|
2961 | 3045 | mmap_miss--;
|
2962 | 3046 |
|
2963 | 3047 | vmf->address += (xas.xa_index - last_pgoff) << PAGE_SHIFT;
|
2964 |
| - if (vmf->pte) |
2965 |
| - vmf->pte += xas.xa_index - last_pgoff; |
| 3048 | + vmf->pte += xas.xa_index - last_pgoff; |
2966 | 3049 | last_pgoff = xas.xa_index;
|
2967 |
| - if (alloc_set_pte(vmf, page)) |
| 3050 | + |
| 3051 | + if (!pte_none(*vmf->pte)) |
2968 | 3052 | goto unlock;
|
| 3053 | + |
| 3054 | + do_set_pte(vmf, page); |
| 3055 | + /* no need to invalidate: a not-present page won't be cached */ |
| 3056 | + update_mmu_cache(vma, vmf->address, vmf->pte); |
2969 | 3057 | unlock_page(head);
|
2970 |
| - goto next; |
| 3058 | + |
| 3059 | + /* The fault is handled */ |
| 3060 | + if (vmf->address == address) |
| 3061 | + ret = VM_FAULT_NOPAGE; |
| 3062 | + continue; |
2971 | 3063 | unlock:
|
2972 | 3064 | unlock_page(head);
|
2973 |
| -skip: |
2974 | 3065 | put_page(head);
|
2975 |
| -next: |
2976 |
| - /* Huge page is mapped? No need to proceed. */ |
2977 |
| - if (pmd_trans_huge(*vmf->pmd)) |
2978 |
| - break; |
2979 |
| - } |
| 3066 | + } while ((head = next_map_page(mapping, &xas, end_pgoff)) != NULL); |
| 3067 | + pte_unmap_unlock(vmf->pte, vmf->ptl); |
| 3068 | +out: |
2980 | 3069 | rcu_read_unlock();
|
| 3070 | + vmf->address = address; |
2981 | 3071 | WRITE_ONCE(file->f_ra.mmap_miss, mmap_miss);
|
| 3072 | + return ret; |
2982 | 3073 | }
|
2983 | 3074 | EXPORT_SYMBOL(filemap_map_pages);
|
2984 | 3075 |
|
|
0 commit comments