Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

huge pagecache: extend mremap pmd rmap lockout to files

Whatever huge pagecache implementation we go with, file rmap locking
must be added to anon rmap locking, when mremap's move_page_tables()
finds a pmd_trans_huge pmd entry: a simple change, let's do it now.

Factor out take_rmap_locks() and drop_rmap_locks() to handle the locking
for make move_ptes() and move_page_tables(), and delete the
VM_BUG_ON_VMA which rejected vm_file and required anon_vma.

Signed-off-by: Hugh Dickins <hughd@google.com>
Cc: "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com>
Cc: Andrea Arcangeli <aarcange@redhat.com>
Cc: Andres Lagar-Cavilla <andreslc@google.com>
Cc: Yang Shi <yang.shi@linaro.org>
Cc: Ning Qu <quning@gmail.com>
Cc: Mel Gorman <mgorman@techsingularity.net>
Cc: Andres Lagar-Cavilla <andreslc@google.com>
Cc: Konstantin Khlebnikov <koct9i@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Hugh Dickins and committed by
Linus Torvalds
1d069b7d bf8616d5

+22 -20
+22 -20
mm/mremap.c
··· 70 70 return pmd; 71 71 } 72 72 73 + static void take_rmap_locks(struct vm_area_struct *vma) 74 + { 75 + if (vma->vm_file) 76 + i_mmap_lock_write(vma->vm_file->f_mapping); 77 + if (vma->anon_vma) 78 + anon_vma_lock_write(vma->anon_vma); 79 + } 80 + 81 + static void drop_rmap_locks(struct vm_area_struct *vma) 82 + { 83 + if (vma->anon_vma) 84 + anon_vma_unlock_write(vma->anon_vma); 85 + if (vma->vm_file) 86 + i_mmap_unlock_write(vma->vm_file->f_mapping); 87 + } 88 + 73 89 static pte_t move_soft_dirty_pte(pte_t pte) 74 90 { 75 91 /* ··· 106 90 struct vm_area_struct *new_vma, pmd_t *new_pmd, 107 91 unsigned long new_addr, bool need_rmap_locks) 108 92 { 109 - struct address_space *mapping = NULL; 110 - struct anon_vma *anon_vma = NULL; 111 93 struct mm_struct *mm = vma->vm_mm; 112 94 pte_t *old_pte, *new_pte, pte; 113 95 spinlock_t *old_ptl, *new_ptl; ··· 128 114 * serialize access to individual ptes, but only rmap traversal 129 115 * order guarantees that we won't miss both the old and new ptes). 130 116 */ 131 - if (need_rmap_locks) { 132 - if (vma->vm_file) { 133 - mapping = vma->vm_file->f_mapping; 134 - i_mmap_lock_write(mapping); 135 - } 136 - if (vma->anon_vma) { 137 - anon_vma = vma->anon_vma; 138 - anon_vma_lock_write(anon_vma); 139 - } 140 - } 117 + if (need_rmap_locks) 118 + take_rmap_locks(vma); 141 119 142 120 /* 143 121 * We don't have to worry about the ordering of src and dst ··· 157 151 spin_unlock(new_ptl); 158 152 pte_unmap(new_pte - 1); 159 153 pte_unmap_unlock(old_pte - 1, old_ptl); 160 - if (anon_vma) 161 - anon_vma_unlock_write(anon_vma); 162 - if (mapping) 163 - i_mmap_unlock_write(mapping); 154 + if (need_rmap_locks) 155 + drop_rmap_locks(vma); 164 156 } 165 157 166 158 #define LATENCY_LIMIT (64 * PAGE_SIZE) ··· 197 193 if (pmd_trans_huge(*old_pmd)) { 198 194 if (extent == HPAGE_PMD_SIZE) { 199 195 bool moved; 200 - VM_BUG_ON_VMA(vma->vm_file || !vma->anon_vma, 201 - vma); 202 196 /* See comment in move_ptes() */ 203 197 if (need_rmap_locks) 204 - anon_vma_lock_write(vma->anon_vma); 198 + take_rmap_locks(vma); 205 199 moved = move_huge_pmd(vma, old_addr, new_addr, 206 200 old_end, old_pmd, new_pmd); 207 201 if (need_rmap_locks) 208 - anon_vma_unlock_write(vma->anon_vma); 202 + drop_rmap_locks(vma); 209 203 if (moved) { 210 204 need_flush = true; 211 205 continue;