summaryrefslogtreecommitdiffstats
path: root/include/linux/swapops.h
diff options
context:
space:
mode:
authorKirill A. Shutemov <kirill.shutemov@linux.intel.com>2018-01-19 07:49:24 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2018-01-21 20:44:47 -0500
commit0d665e7b109d512b7cae3ccef6e8654714887844 (patch)
treee6ebae5cd32b4f9008d06592a5301937c0be5875 /include/linux/swapops.h
parent0c5b9b5d9adbad4b60491f9ba0d2af38904bb4b9 (diff)
mm, page_vma_mapped: Drop faulty pointer arithmetics in check_pte()
Tetsuo reported random crashes under memory pressure on 32-bit x86 system and tracked down to change that introduced page_vma_mapped_walk(). The root cause of the issue is the faulty pointer math in check_pte(). As ->pte may point to an arbitrary page we have to check that they are belong to the section before doing math. Otherwise it may lead to weird results. It wasn't noticed until now as mem_map[] is virtually contiguous on flatmem or vmemmap sparsemem. Pointer arithmetic just works against all 'struct page' pointers. But with classic sparsemem, it doesn't because each section memap is allocated separately and so consecutive pfns crossing two sections might have struct pages at completely unrelated addresses. Let's restructure code a bit and replace pointer arithmetic with operations on pfns. Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com> Reported-and-tested-by: Tetsuo Handa <penguin-kernel@i-love.sakura.ne.jp> Acked-by: Michal Hocko <mhocko@suse.com> Fixes: ace71a19cec5 ("mm: introduce page_vma_mapped_walk()") Cc: stable@vger.kernel.org Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'include/linux/swapops.h')
-rw-r--r--include/linux/swapops.h21
1 files changed, 21 insertions, 0 deletions
diff --git a/include/linux/swapops.h b/include/linux/swapops.h
index 9c5a2628d6ce..1d3877c39a00 100644
--- a/include/linux/swapops.h
+++ b/include/linux/swapops.h
@@ -124,6 +124,11 @@ static inline bool is_write_device_private_entry(swp_entry_t entry)
124 return unlikely(swp_type(entry) == SWP_DEVICE_WRITE); 124 return unlikely(swp_type(entry) == SWP_DEVICE_WRITE);
125} 125}
126 126
127static inline unsigned long device_private_entry_to_pfn(swp_entry_t entry)
128{
129 return swp_offset(entry);
130}
131
127static inline struct page *device_private_entry_to_page(swp_entry_t entry) 132static inline struct page *device_private_entry_to_page(swp_entry_t entry)
128{ 133{
129 return pfn_to_page(swp_offset(entry)); 134 return pfn_to_page(swp_offset(entry));
@@ -154,6 +159,11 @@ static inline bool is_write_device_private_entry(swp_entry_t entry)
154 return false; 159 return false;
155} 160}
156 161
162static inline unsigned long device_private_entry_to_pfn(swp_entry_t entry)
163{
164 return 0;
165}
166
157static inline struct page *device_private_entry_to_page(swp_entry_t entry) 167static inline struct page *device_private_entry_to_page(swp_entry_t entry)
158{ 168{
159 return NULL; 169 return NULL;
@@ -189,6 +199,11 @@ static inline int is_write_migration_entry(swp_entry_t entry)
189 return unlikely(swp_type(entry) == SWP_MIGRATION_WRITE); 199 return unlikely(swp_type(entry) == SWP_MIGRATION_WRITE);
190} 200}
191 201
202static inline unsigned long migration_entry_to_pfn(swp_entry_t entry)
203{
204 return swp_offset(entry);
205}
206
192static inline struct page *migration_entry_to_page(swp_entry_t entry) 207static inline struct page *migration_entry_to_page(swp_entry_t entry)
193{ 208{
194 struct page *p = pfn_to_page(swp_offset(entry)); 209 struct page *p = pfn_to_page(swp_offset(entry));
@@ -218,6 +233,12 @@ static inline int is_migration_entry(swp_entry_t swp)
218{ 233{
219 return 0; 234 return 0;
220} 235}
236
237static inline unsigned long migration_entry_to_pfn(swp_entry_t entry)
238{
239 return 0;
240}
241
221static inline struct page *migration_entry_to_page(swp_entry_t entry) 242static inline struct page *migration_entry_to_page(swp_entry_t entry)
222{ 243{
223 return NULL; 244 return NULL;