History

mm/memory.c: add apply_to_existing_page_range() helper

apply_to_page_range() takes an address range, and if any parts of it are not covered by the existing page table hierarchy, it allocates memory to fill them in. In some use cases, this is not what we want - we want to be able to operate exclusively on PTEs that are already in the tables. Add apply_to_existing_page_range() for this. Adjust the walker functions for apply_to_page_range to take 'create', which switches them between the old and new modes. This will be used in KASAN vmalloc. [akpm@linux-foundation.org: reduce code duplication] [akpm@linux-foundation.org: s/apply_to_existing_pages/apply_to_existing_page_range/] [akpm@linux-foundation.org: initialize __apply_to_page_range::err] Link: http://lkml.kernel.org/r/20191205140407.1874-1-dja@axtens.net Signed-off-by: Daniel Axtens <dja@axtens.net> Cc: Dmitry Vyukov <dvyukov@google.com> Cc: Uladzislau Rezki (Sony) <urezki@gmail.com> Cc: Alexander Potapenko <glider@google.com> Cc: Daniel Axtens <dja@axtens.net> Cc: Qian Cai <cai@lca.pw> Cc: Andrey Ryabinin <aryabinin@virtuozzo.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

Daniel Axtens committed 6 years ago

Commit be1db471 parent d98c9e82 files · +97 −42Browse files

Unified · Split

2 files
  1. include/linux/mm.h +3 −0
  2. mm/memory.c +94 −42
include/linux/mm.h+3−0
@@ -2621,6 +2621,9 @@ static inline int vm_fault_to_errno(vm_fault_t vm_fault, int foll_flags) · 2620 unmodified lines
2621typedef int (*pte_fn_t)(pte_t *pte, unsigned long addr, void *data);2621typedef int (*pte_fn_t)(pte_t *pte, unsigned long addr, void *data);
2622extern int apply_to_page_range(struct mm_struct *mm, unsigned long address,2622extern int apply_to_page_range(struct mm_struct *mm, unsigned long address,
2623 unsigned long size, pte_fn_t fn, void *data);2623 unsigned long size, pte_fn_t fn, void *data);
2624extern int apply_to_existing_page_range(struct mm_struct *mm,
2625 unsigned long address, unsigned long size,
2626 pte_fn_t fn, void *data);
2624 2627
2625#ifdef CONFIG_PAGE_POISONING2628#ifdef CONFIG_PAGE_POISONING
2626extern bool page_poisoning_enabled(void);2629extern bool page_poisoning_enabled(void);
mm/memory.c+94−42
@@ -2021,26 +2021,34 @@ EXPORT_SYMBOL(vm_iomap_memory); · 2020 unmodified lines
2021 2021
2022static int apply_to_pte_range(struct mm_struct *mm, pmd_t *pmd,2022static int apply_to_pte_range(struct mm_struct *mm, pmd_t *pmd,
2023 unsigned long addr, unsigned long end,2023 unsigned long addr, unsigned long end,
2024 pte_fn_t fn, void *data)2024 pte_fn_t fn, void *data, bool create)
2025{2025{
2026 pte_t *pte;2026 pte_t *pte;
2027 int err;2027 int err = 0;
2028 spinlock_t *uninitialized_var(ptl);2028 spinlock_t *uninitialized_var(ptl);
2029 2029
2030 pte = (mm == &init_mm) ?2030 if (create) {
2031 pte_alloc_kernel(pmd, addr) :2031 pte = (mm == &init_mm) ?
2032 pte_alloc_map_lock(mm, pmd, addr, &ptl);2032 pte_alloc_kernel(pmd, addr) :
2033 if (!pte)2033 pte_alloc_map_lock(mm, pmd, addr, &ptl);
2034 return -ENOMEM;2034 if (!pte)
2035 return -ENOMEM;
2036 } else {
2037 pte = (mm == &init_mm) ?
2038 pte_offset_kernel(pmd, addr) :
2039 pte_offset_map_lock(mm, pmd, addr, &ptl);
2040 }
2035 2041
2036 BUG_ON(pmd_huge(*pmd));2042 BUG_ON(pmd_huge(*pmd));
2037 2043
2038 arch_enter_lazy_mmu_mode();2044 arch_enter_lazy_mmu_mode();
2039 2045
2040 do {2046 do {
2041 err = fn(pte++, addr, data);2047 if (create || !pte_none(*pte)) {
2042 if (err)2048 err = fn(pte++, addr, data);
2043 break;2049 if (err)
2050 break;
2051 }
2044 } while (addr += PAGE_SIZE, addr != end);2052 } while (addr += PAGE_SIZE, addr != end);
2045 2053
2046 arch_leave_lazy_mmu_mode();2054 arch_leave_lazy_mmu_mode();
@@ -2052,77 +2060,95 @@ static int apply_to_pte_range(struct mm_struct *mm, pmd_t *pmd, · 5 unmodified lines
2052 2060
2053static int apply_to_pmd_range(struct mm_struct *mm, pud_t *pud,2061static int apply_to_pmd_range(struct mm_struct *mm, pud_t *pud,
2054 unsigned long addr, unsigned long end,2062 unsigned long addr, unsigned long end,
2055 pte_fn_t fn, void *data)2063 pte_fn_t fn, void *data, bool create)
2056{2064{
2057 pmd_t *pmd;2065 pmd_t *pmd;
2058 unsigned long next;2066 unsigned long next;
2059 int err;2067 int err = 0;
2060 2068
2061 BUG_ON(pud_huge(*pud));2069 BUG_ON(pud_huge(*pud));
2062 2070
2063 pmd = pmd_alloc(mm, pud, addr);2071 if (create) {
2064 if (!pmd)2072 pmd = pmd_alloc(mm, pud, addr);
2065 return -ENOMEM;2073 if (!pmd)
2074 return -ENOMEM;
2075 } else {
2076 pmd = pmd_offset(pud, addr);
2077 }
2066 do {2078 do {
2067 next = pmd_addr_end(addr, end);2079 next = pmd_addr_end(addr, end);
2068 err = apply_to_pte_range(mm, pmd, addr, next, fn, data);2080 if (create || !pmd_none_or_clear_bad(pmd)) {
2069 if (err)2081 err = apply_to_pte_range(mm, pmd, addr, next, fn, data,
2070 break;2082 create);
2083 if (err)
2084 break;
2085 }
2071 } while (pmd++, addr = next, addr != end);2086 } while (pmd++, addr = next, addr != end);
2072 return err;2087 return err;
2073}2088}
2074 2089
2075static int apply_to_pud_range(struct mm_struct *mm, p4d_t *p4d,2090static int apply_to_pud_range(struct mm_struct *mm, p4d_t *p4d,
2076 unsigned long addr, unsigned long end,2091 unsigned long addr, unsigned long end,
2077 pte_fn_t fn, void *data)2092 pte_fn_t fn, void *data, bool create)
2078{2093{
2079 pud_t *pud;2094 pud_t *pud;
2080 unsigned long next;2095 unsigned long next;
2081 int err;2096 int err = 0;
2082 2097
2083 pud = pud_alloc(mm, p4d, addr);2098 if (create) {
2084 if (!pud)2099 pud = pud_alloc(mm, p4d, addr);
2085 return -ENOMEM;2100 if (!pud)
2101 return -ENOMEM;
2102 } else {
2103 pud = pud_offset(p4d, addr);
2104 }
2086 do {2105 do {
2087 next = pud_addr_end(addr, end);2106 next = pud_addr_end(addr, end);
2088 err = apply_to_pmd_range(mm, pud, addr, next, fn, data);2107 if (create || !pud_none_or_clear_bad(pud)) {
2089 if (err)2108 err = apply_to_pmd_range(mm, pud, addr, next, fn, data,
2090 break;2109 create);
2110 if (err)
2111 break;
2112 }
2091 } while (pud++, addr = next, addr != end);2113 } while (pud++, addr = next, addr != end);
2092 return err;2114 return err;
2093}2115}
2094 2116
2095static int apply_to_p4d_range(struct mm_struct *mm, pgd_t *pgd,2117static int apply_to_p4d_range(struct mm_struct *mm, pgd_t *pgd,
2096 unsigned long addr, unsigned long end,2118 unsigned long addr, unsigned long end,
2097 pte_fn_t fn, void *data)2119 pte_fn_t fn, void *data, bool create)
2098{2120{
2099 p4d_t *p4d;2121 p4d_t *p4d;
2100 unsigned long next;2122 unsigned long next;
2101 int err;2123 int err = 0;
2102 2124
2103 p4d = p4d_alloc(mm, pgd, addr);2125 if (create) {
2104 if (!p4d)2126 p4d = p4d_alloc(mm, pgd, addr);
2105 return -ENOMEM;2127 if (!p4d)
2128 return -ENOMEM;
2129 } else {
2130 p4d = p4d_offset(pgd, addr);
2131 }
2106 do {2132 do {
2107 next = p4d_addr_end(addr, end);2133 next = p4d_addr_end(addr, end);
2108 err = apply_to_pud_range(mm, p4d, addr, next, fn, data);2134 if (create || !p4d_none_or_clear_bad(p4d)) {
2109 if (err)2135 err = apply_to_pud_range(mm, p4d, addr, next, fn, data,
2110 break;2136 create);
2137 if (err)
2138 break;
2139 }
2111 } while (p4d++, addr = next, addr != end);2140 } while (p4d++, addr = next, addr != end);
2112 return err;2141 return err;
2113}2142}
2114 2143
2115/*2144static int __apply_to_page_range(struct mm_struct *mm, unsigned long addr,
2116 * Scan a region of virtual memory, filling in page tables as necessary2145 unsigned long size, pte_fn_t fn,
2117 * and calling a provided function on each leaf page table.2146 void *data, bool create)
2118 */
2119int apply_to_page_range(struct mm_struct *mm, unsigned long addr,
2120 unsigned long size, pte_fn_t fn, void *data)
2121{2147{
2122 pgd_t *pgd;2148 pgd_t *pgd;
2123 unsigned long next;2149 unsigned long next;
2124 unsigned long end = addr + size;2150 unsigned long end = addr + size;
2125 int err;2151 int err = 0;
2126 2152
2127 if (WARN_ON(addr >= end))2153 if (WARN_ON(addr >= end))
2128 return -EINVAL;2154 return -EINVAL;
@@ -2130,15 +2156,41 @@ int apply_to_page_range(struct mm_struct *mm, unsigned long addr, · 1 unmodified line
2130 pgd = pgd_offset(mm, addr);2156 pgd = pgd_offset(mm, addr);
2131 do {2157 do {
2132 next = pgd_addr_end(addr, end);2158 next = pgd_addr_end(addr, end);
2133 err = apply_to_p4d_range(mm, pgd, addr, next, fn, data);2159 if (!create && pgd_none_or_clear_bad(pgd))
2160 continue;
2161 err = apply_to_p4d_range(mm, pgd, addr, next, fn, data, create);
2134 if (err)2162 if (err)
2135 break;2163 break;
2136 } while (pgd++, addr = next, addr != end);2164 } while (pgd++, addr = next, addr != end);
2137 2165
2138 return err;2166 return err;
2139}2167}
2168
2169/*
2170 * Scan a region of virtual memory, filling in page tables as necessary
2171 * and calling a provided function on each leaf page table.
2172 */
2173int apply_to_page_range(struct mm_struct *mm, unsigned long addr,
2174 unsigned long size, pte_fn_t fn, void *data)
2175{
2176 return __apply_to_page_range(mm, addr, size, fn, data, true);
2177}
2140EXPORT_SYMBOL_GPL(apply_to_page_range);2178EXPORT_SYMBOL_GPL(apply_to_page_range);
2141 2179
2180/*
2181 * Scan a region of virtual memory, calling a provided function on
2182 * each leaf page table where it exists.
2183 *
2184 * Unlike apply_to_page_range, this does _not_ fill in page tables
2185 * where they are absent.
2186 */
2187int apply_to_existing_page_range(struct mm_struct *mm, unsigned long addr,
2188 unsigned long size, pte_fn_t fn, void *data)
2189{
2190 return __apply_to_page_range(mm, addr, size, fn, data, false);
2191}
2192EXPORT_SYMBOL_GPL(apply_to_existing_page_range);
2193
2142/*2194/*
2143 * handle_pte_fault chooses page fault handler according to an entry which was2195 * handle_pte_fault chooses page fault handler according to an entry which was
2144 * read non-atomically. Before making any commitment, on those architectures2196 * read non-atomically. Before making any commitment, on those architectures

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t