|
| 1 | +mm: remove follow_pte() |
| 2 | + |
| 3 | +jira LE-3557 |
| 4 | +Rebuild_History Non-Buildable kernel-5.14.0-570.26.1.el9_6 |
| 5 | +commit-author Peter Xu < [email protected]> |
| 6 | +commit b0a1c0d0edcd75a0f8ec5fd19dbd64b8d097f534 |
| 7 | +Empty-Commit: Cherry-Pick Conflicts during history rebuild. |
| 8 | +Will be included in final tarball splat. Ref for failed cherry-pick at: |
| 9 | +ciq/ciq_backports/kernel-5.14.0-570.26.1.el9_6/b0a1c0d0.failed |
| 10 | + |
| 11 | +follow_pte() users have been converted to follow_pfnmap*(). Remove the |
| 12 | +API. |
| 13 | + |
| 14 | +Link: https://lkml.kernel.org/r/ [email protected] |
| 15 | + Signed-off-by: Peter Xu < [email protected]> |
| 16 | + Cc: Alexander Gordeev < [email protected]> |
| 17 | + Cc: Alex Williamson < [email protected]> |
| 18 | + Cc: Aneesh Kumar K.V < [email protected]> |
| 19 | + Cc: Borislav Petkov < [email protected]> |
| 20 | + Cc: Catalin Marinas < [email protected]> |
| 21 | + Cc: Christian Borntraeger < [email protected]> |
| 22 | + Cc: Dave Hansen < [email protected]> |
| 23 | + Cc: David Hildenbrand < [email protected]> |
| 24 | + Cc: Gavin Shan < [email protected]> |
| 25 | + Cc: Gerald Schaefer < [email protected]> |
| 26 | + Cc: Heiko Carstens < [email protected]> |
| 27 | + Cc: Ingo Molnar < [email protected]> |
| 28 | + Cc: Jason Gunthorpe < [email protected]> |
| 29 | + Cc: Matthew Wilcox < [email protected]> |
| 30 | + Cc: Niklas Schnelle < [email protected]> |
| 31 | + Cc: Paolo Bonzini < [email protected]> |
| 32 | + Cc: Ryan Roberts < [email protected]> |
| 33 | + Cc: Sean Christopherson < [email protected]> |
| 34 | + Cc: Sven Schnelle < [email protected]> |
| 35 | + Cc: Thomas Gleixner < [email protected]> |
| 36 | + Cc: Vasily Gorbik < [email protected]> |
| 37 | + Cc: Will Deacon < [email protected]> |
| 38 | + |
| 39 | + Signed-off-by: Andrew Morton < [email protected]> |
| 40 | +(cherry picked from commit b0a1c0d0edcd75a0f8ec5fd19dbd64b8d097f534) |
| 41 | + Signed-off-by: Jonathan Maple < [email protected]> |
| 42 | + |
| 43 | +# Conflicts: |
| 44 | +# include/linux/mm.h |
| 45 | +# mm/memory.c |
| 46 | +diff --cc include/linux/mm.h |
| 47 | +index 196c481ec160,d750be768121..000000000000 |
| 48 | +--- a/include/linux/mm.h |
| 49 | ++++ b/include/linux/mm.h |
| 50 | +@@@ -2427,12 -2368,6 +2427,15 @@@ void free_pgd_range(struct mmu_gather * |
| 51 | + unsigned long end, unsigned long floor, unsigned long ceiling); |
| 52 | + int |
| 53 | + copy_page_range(struct vm_area_struct *dst_vma, struct vm_area_struct *src_vma); |
| 54 | +++<<<<<<< HEAD |
| 55 | + +int follow_pte(struct mm_struct *mm, unsigned long address, |
| 56 | + + pte_t **ptepp, spinlock_t **ptlp); |
| 57 | + +int follow_pfn(struct vm_area_struct *vma, unsigned long address, |
| 58 | + + unsigned long *pfn); |
| 59 | + +int follow_phys(struct vm_area_struct *vma, unsigned long address, |
| 60 | + + unsigned int flags, unsigned long *prot, resource_size_t *phys); |
| 61 | +++======= |
| 62 | +++>>>>>>> b0a1c0d0edcd (mm: remove follow_pte()) |
| 63 | + int generic_access_phys(struct vm_area_struct *vma, unsigned long addr, |
| 64 | + void *buf, int len, int write); |
| 65 | + |
| 66 | +diff --cc mm/memory.c |
| 67 | +index e2794e3b8919,42674c0748cb..000000000000 |
| 68 | +--- a/mm/memory.c |
| 69 | ++++ b/mm/memory.c |
| 70 | +@@@ -5607,130 -6099,157 +5607,159 @@@ int __pmd_alloc(struct mm_struct *mm, p |
| 71 | + } |
| 72 | + #endif /* __PAGETABLE_PMD_FOLDED */ |
| 73 | + |
| 74 | +++<<<<<<< HEAD |
| 75 | + +/** |
| 76 | + + * follow_pte - look up PTE at a user virtual address |
| 77 | + + * @mm: the mm_struct of the target address space |
| 78 | + + * @address: user virtual address |
| 79 | + + * @ptepp: location to store found PTE |
| 80 | + + * @ptlp: location to store the lock for the PTE |
| 81 | + + * |
| 82 | + + * On a successful return, the pointer to the PTE is stored in @ptepp; |
| 83 | + + * the corresponding lock is taken and its location is stored in @ptlp. |
| 84 | + + * The contents of the PTE are only stable until @ptlp is released; |
| 85 | + + * any further use, if any, must be protected against invalidation |
| 86 | + + * with MMU notifiers. |
| 87 | + + * |
| 88 | + + * Only IO mappings and raw PFN mappings are allowed. The mmap semaphore |
| 89 | + + * should be taken for read. |
| 90 | + + * |
| 91 | + + * KVM uses this function. While it is arguably less bad than ``follow_pfn``, |
| 92 | + + * it is not a good general-purpose API. |
| 93 | + + * |
| 94 | + + * Return: zero on success, -ve otherwise. |
| 95 | + + */ |
| 96 | + +int follow_pte(struct mm_struct *mm, unsigned long address, |
| 97 | + + pte_t **ptepp, spinlock_t **ptlp) |
| 98 | + +{ |
| 99 | + + pgd_t *pgd; |
| 100 | + + p4d_t *p4d; |
| 101 | + + pud_t *pud; |
| 102 | + + pmd_t *pmd; |
| 103 | + + pte_t *ptep; |
| 104 | + + |
| 105 | + + pgd = pgd_offset(mm, address); |
| 106 | + + if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd))) |
| 107 | + + goto out; |
| 108 | + + |
| 109 | + + p4d = p4d_offset(pgd, address); |
| 110 | + + if (p4d_none(*p4d) || unlikely(p4d_bad(*p4d))) |
| 111 | + + goto out; |
| 112 | + + |
| 113 | + + pud = pud_offset(p4d, address); |
| 114 | + + if (pud_none(*pud) || unlikely(pud_bad(*pud))) |
| 115 | + + goto out; |
| 116 | + + |
| 117 | + + pmd = pmd_offset(pud, address); |
| 118 | + + VM_BUG_ON(pmd_trans_huge(*pmd)); |
| 119 | + + |
| 120 | + + ptep = pte_offset_map_lock(mm, pmd, address, ptlp); |
| 121 | + + if (!ptep) |
| 122 | + + goto out; |
| 123 | + + if (!pte_present(ptep_get(ptep))) |
| 124 | + + goto unlock; |
| 125 | + + *ptepp = ptep; |
| 126 | + + return 0; |
| 127 | + +unlock: |
| 128 | + + pte_unmap_unlock(ptep, *ptlp); |
| 129 | + +out: |
| 130 | + + return -EINVAL; |
| 131 | + +} |
| 132 | + +EXPORT_SYMBOL_GPL(follow_pte); |
| 133 | +++======= |
| 134 | ++ static inline void pfnmap_args_setup(struct follow_pfnmap_args *args, |
| 135 | ++ spinlock_t *lock, pte_t *ptep, |
| 136 | ++ pgprot_t pgprot, unsigned long pfn_base, |
| 137 | ++ unsigned long addr_mask, bool writable, |
| 138 | ++ bool special) |
| 139 | ++ { |
| 140 | ++ args->lock = lock; |
| 141 | ++ args->ptep = ptep; |
| 142 | ++ args->pfn = pfn_base + ((args->address & ~addr_mask) >> PAGE_SHIFT); |
| 143 | ++ args->pgprot = pgprot; |
| 144 | ++ args->writable = writable; |
| 145 | ++ args->special = special; |
| 146 | ++ } |
| 147 | ++ |
| 148 | ++ static inline void pfnmap_lockdep_assert(struct vm_area_struct *vma) |
| 149 | ++ { |
| 150 | ++ #ifdef CONFIG_LOCKDEP |
| 151 | ++ struct address_space *mapping = vma->vm_file->f_mapping; |
| 152 | ++ |
| 153 | ++ if (mapping) |
| 154 | ++ lockdep_assert(lockdep_is_held(&vma->vm_file->f_mapping->i_mmap_rwsem) || |
| 155 | ++ lockdep_is_held(&vma->vm_mm->mmap_lock)); |
| 156 | ++ else |
| 157 | ++ lockdep_assert(lockdep_is_held(&vma->vm_mm->mmap_lock)); |
| 158 | ++ #endif |
| 159 | ++ } |
| 160 | +++>>>>>>> b0a1c0d0edcd (mm: remove follow_pte()) |
| 161 | + |
| 162 | + /** |
| 163 | + - * follow_pfnmap_start() - Look up a pfn mapping at a user virtual address |
| 164 | + - * @args: Pointer to struct @follow_pfnmap_args |
| 165 | + + * follow_pfn - look up PFN at a user virtual address |
| 166 | + + * @vma: memory mapping |
| 167 | + + * @address: user virtual address |
| 168 | + + * @pfn: location to store found PFN |
| 169 | + * |
| 170 | + - * The caller needs to setup args->vma and args->address to point to the |
| 171 | + - * virtual address as the target of such lookup. On a successful return, |
| 172 | + - * the results will be put into other output fields. |
| 173 | + + * Only IO mappings and raw PFN mappings are allowed. |
| 174 | + * |
| 175 | + - * After the caller finished using the fields, the caller must invoke |
| 176 | + - * another follow_pfnmap_end() to proper releases the locks and resources |
| 177 | + - * of such look up request. |
| 178 | + + * This function does not allow the caller to read the permissions |
| 179 | + + * of the PTE. Do not use it. |
| 180 | + * |
| 181 | + - * During the start() and end() calls, the results in @args will be valid |
| 182 | + - * as proper locks will be held. After the end() is called, all the fields |
| 183 | + - * in @follow_pfnmap_args will be invalid to be further accessed. Further |
| 184 | + - * use of such information after end() may require proper synchronizations |
| 185 | + - * by the caller with page table updates, otherwise it can create a |
| 186 | + - * security bug. |
| 187 | + - * |
| 188 | + - * If the PTE maps a refcounted page, callers are responsible to protect |
| 189 | + - * against invalidation with MMU notifiers; otherwise access to the PFN at |
| 190 | + - * a later point in time can trigger use-after-free. |
| 191 | + - * |
| 192 | + - * Only IO mappings and raw PFN mappings are allowed. The mmap semaphore |
| 193 | + - * should be taken for read, and the mmap semaphore cannot be released |
| 194 | + - * before the end() is invoked. |
| 195 | + - * |
| 196 | + - * This function must not be used to modify PTE content. |
| 197 | + - * |
| 198 | + - * Return: zero on success, negative otherwise. |
| 199 | + + * Return: zero and the pfn at @pfn on success, -ve otherwise. |
| 200 | + */ |
| 201 | + -int follow_pfnmap_start(struct follow_pfnmap_args *args) |
| 202 | + +int follow_pfn(struct vm_area_struct *vma, unsigned long address, |
| 203 | + + unsigned long *pfn) |
| 204 | + { |
| 205 | + - struct vm_area_struct *vma = args->vma; |
| 206 | + - unsigned long address = args->address; |
| 207 | + - struct mm_struct *mm = vma->vm_mm; |
| 208 | + - spinlock_t *lock; |
| 209 | + - pgd_t *pgdp; |
| 210 | + - p4d_t *p4dp, p4d; |
| 211 | + - pud_t *pudp, pud; |
| 212 | + - pmd_t *pmdp, pmd; |
| 213 | + - pte_t *ptep, pte; |
| 214 | + + int ret = -EINVAL; |
| 215 | + + spinlock_t *ptl; |
| 216 | + + pte_t *ptep; |
| 217 | + |
| 218 | + - pfnmap_lockdep_assert(vma); |
| 219 | + + if (!(vma->vm_flags & (VM_IO | VM_PFNMAP))) |
| 220 | + + return ret; |
| 221 | + |
| 222 | + - if (unlikely(address < vma->vm_start || address >= vma->vm_end)) |
| 223 | + - goto out; |
| 224 | + + ret = follow_pte(vma->vm_mm, address, &ptep, &ptl); |
| 225 | + + if (ret) |
| 226 | + + return ret; |
| 227 | + + *pfn = pte_pfn(ptep_get(ptep)); |
| 228 | + + pte_unmap_unlock(ptep, ptl); |
| 229 | + + return 0; |
| 230 | + +} |
| 231 | + +EXPORT_SYMBOL(follow_pfn); |
| 232 | + |
| 233 | + - if (!(vma->vm_flags & (VM_IO | VM_PFNMAP))) |
| 234 | + - goto out; |
| 235 | + -retry: |
| 236 | + - pgdp = pgd_offset(mm, address); |
| 237 | + - if (pgd_none(*pgdp) || unlikely(pgd_bad(*pgdp))) |
| 238 | + - goto out; |
| 239 | + +#ifdef CONFIG_HAVE_IOREMAP_PROT |
| 240 | + +int follow_phys(struct vm_area_struct *vma, |
| 241 | + + unsigned long address, unsigned int flags, |
| 242 | + + unsigned long *prot, resource_size_t *phys) |
| 243 | + +{ |
| 244 | + + int ret = -EINVAL; |
| 245 | + + pte_t *ptep, pte; |
| 246 | + + spinlock_t *ptl; |
| 247 | + |
| 248 | + - p4dp = p4d_offset(pgdp, address); |
| 249 | + - p4d = READ_ONCE(*p4dp); |
| 250 | + - if (p4d_none(p4d) || unlikely(p4d_bad(p4d))) |
| 251 | + + if (!(vma->vm_flags & (VM_IO | VM_PFNMAP))) |
| 252 | + goto out; |
| 253 | + |
| 254 | + - pudp = pud_offset(p4dp, address); |
| 255 | + - pud = READ_ONCE(*pudp); |
| 256 | + - if (pud_none(pud)) |
| 257 | + + if (follow_pte(vma->vm_mm, address, &ptep, &ptl)) |
| 258 | + goto out; |
| 259 | + - if (pud_leaf(pud)) { |
| 260 | + - lock = pud_lock(mm, pudp); |
| 261 | + - if (!unlikely(pud_leaf(pud))) { |
| 262 | + - spin_unlock(lock); |
| 263 | + - goto retry; |
| 264 | + - } |
| 265 | + - pfnmap_args_setup(args, lock, NULL, pud_pgprot(pud), |
| 266 | + - pud_pfn(pud), PUD_MASK, pud_write(pud), |
| 267 | + - pud_special(pud)); |
| 268 | + - return 0; |
| 269 | + - } |
| 270 | + + pte = ptep_get(ptep); |
| 271 | + |
| 272 | + - pmdp = pmd_offset(pudp, address); |
| 273 | + - pmd = pmdp_get_lockless(pmdp); |
| 274 | + - if (pmd_leaf(pmd)) { |
| 275 | + - lock = pmd_lock(mm, pmdp); |
| 276 | + - if (!unlikely(pmd_leaf(pmd))) { |
| 277 | + - spin_unlock(lock); |
| 278 | + - goto retry; |
| 279 | + - } |
| 280 | + - pfnmap_args_setup(args, lock, NULL, pmd_pgprot(pmd), |
| 281 | + - pmd_pfn(pmd), PMD_MASK, pmd_write(pmd), |
| 282 | + - pmd_special(pmd)); |
| 283 | + - return 0; |
| 284 | + - } |
| 285 | + + /* Never return PFNs of anon folios in COW mappings. */ |
| 286 | + + if (vm_normal_folio(vma, address, pte)) |
| 287 | + + goto unlock; |
| 288 | + |
| 289 | + - ptep = pte_offset_map_lock(mm, pmdp, address, &lock); |
| 290 | + - if (!ptep) |
| 291 | + - goto out; |
| 292 | + - pte = ptep_get(ptep); |
| 293 | + - if (!pte_present(pte)) |
| 294 | + + if ((flags & FOLL_WRITE) && !pte_write(pte)) |
| 295 | + goto unlock; |
| 296 | + - pfnmap_args_setup(args, lock, ptep, pte_pgprot(pte), |
| 297 | + - pte_pfn(pte), PAGE_MASK, pte_write(pte), |
| 298 | + - pte_special(pte)); |
| 299 | + - return 0; |
| 300 | + + |
| 301 | + + *prot = pgprot_val(pte_pgprot(pte)); |
| 302 | + + *phys = (resource_size_t)pte_pfn(pte) << PAGE_SHIFT; |
| 303 | + + |
| 304 | + + ret = 0; |
| 305 | + unlock: |
| 306 | + - pte_unmap_unlock(ptep, lock); |
| 307 | + + pte_unmap_unlock(ptep, ptl); |
| 308 | + out: |
| 309 | + - return -EINVAL; |
| 310 | + -} |
| 311 | + -EXPORT_SYMBOL_GPL(follow_pfnmap_start); |
| 312 | + - |
| 313 | + -/** |
| 314 | + - * follow_pfnmap_end(): End a follow_pfnmap_start() process |
| 315 | + - * @args: Pointer to struct @follow_pfnmap_args |
| 316 | + - * |
| 317 | + - * Must be used in pair of follow_pfnmap_start(). See the start() function |
| 318 | + - * above for more information. |
| 319 | + - */ |
| 320 | + -void follow_pfnmap_end(struct follow_pfnmap_args *args) |
| 321 | + -{ |
| 322 | + - if (args->lock) |
| 323 | + - spin_unlock(args->lock); |
| 324 | + - if (args->ptep) |
| 325 | + - pte_unmap(args->ptep); |
| 326 | + + return ret; |
| 327 | + } |
| 328 | + -EXPORT_SYMBOL_GPL(follow_pfnmap_end); |
| 329 | + |
| 330 | + -#ifdef CONFIG_HAVE_IOREMAP_PROT |
| 331 | + /** |
| 332 | + * generic_access_phys - generic implementation for iomem mmap access |
| 333 | + * @vma: the vma to access |
| 334 | +* Unmerged path include/linux/mm.h |
| 335 | +* Unmerged path mm/memory.c |
0 commit comments