diff options
author | Hugh Dickins <hugh@veritas.com> | 2005-06-21 20:15:06 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-06-21 21:46:19 -0400 |
commit | 941150a326be88af245034ef4b3e9fa00229aa2d (patch) | |
tree | 03a058776dccd007150a3f57b1f36bf63b8f6a5d | |
parent | 400e65146c428d2ef677a927786fda2cec545a76 (diff) |
[PATCH] mbind: fix verify_pages pte_page
Strict mbind's check that pages already mapped are on right node has been
using pte_page without checking if pfn_valid, and without page_table_lock
to prevent spurious failures when try_to_unmap_one intervenes between the
pte_present and the pte_page.
Signed-off-by: Hugh Dickins <hugh@veritas.com>
Cc: Andi Kleen <ak@muc.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r-- | mm/mempolicy.c | 19 |
1 files changed, 14 insertions, 5 deletions
diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 39252c732db2..c512cc911e22 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c | |||
@@ -242,6 +242,9 @@ static int | |||
242 | verify_pages(struct mm_struct *mm, | 242 | verify_pages(struct mm_struct *mm, |
243 | unsigned long addr, unsigned long end, unsigned long *nodes) | 243 | unsigned long addr, unsigned long end, unsigned long *nodes) |
244 | { | 244 | { |
245 | int err = 0; | ||
246 | |||
247 | spin_lock(&mm->page_table_lock); | ||
245 | while (addr < end) { | 248 | while (addr < end) { |
246 | struct page *p; | 249 | struct page *p; |
247 | pte_t *pte; | 250 | pte_t *pte; |
@@ -268,17 +271,23 @@ verify_pages(struct mm_struct *mm, | |||
268 | } | 271 | } |
269 | p = NULL; | 272 | p = NULL; |
270 | pte = pte_offset_map(pmd, addr); | 273 | pte = pte_offset_map(pmd, addr); |
271 | if (pte_present(*pte)) | 274 | if (pte_present(*pte)) { |
272 | p = pte_page(*pte); | 275 | unsigned long pfn = pte_pfn(*pte); |
276 | if (pfn_valid(pfn)) | ||
277 | p = pfn_to_page(pfn); | ||
278 | } | ||
273 | pte_unmap(pte); | 279 | pte_unmap(pte); |
274 | if (p) { | 280 | if (p) { |
275 | unsigned nid = page_to_nid(p); | 281 | unsigned nid = page_to_nid(p); |
276 | if (!test_bit(nid, nodes)) | 282 | if (!test_bit(nid, nodes)) { |
277 | return -EIO; | 283 | err = -EIO; |
284 | break; | ||
285 | } | ||
278 | } | 286 | } |
279 | addr += PAGE_SIZE; | 287 | addr += PAGE_SIZE; |
280 | } | 288 | } |
281 | return 0; | 289 | spin_unlock(&mm->page_table_lock); |
290 | return err; | ||
282 | } | 291 | } |
283 | 292 | ||
284 | /* Step 1: check the range */ | 293 | /* Step 1: check the range */ |