diff options
| author | Hugh Dickins <hugh.dickins@tiscali.co.uk> | 2009-06-23 15:36:58 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-06-23 15:50:05 -0400 |
| commit | a5c9b696ec109bb54d547fdb437a7a0c2d514670 (patch) | |
| tree | c97533e38359a2e731bcc2c65f063a27f4f629e6 | |
| parent | 626f380d0b264a1e40237f5a2a3dffc5d14f256e (diff) | |
mm: pass mm to grab_swap_token
If a kthread happens to use get_user_pages() on an mm (as KSM does),
there's a chance that it will end up trying to read in a swap page, then
oops in grab_swap_token() because the kthread has no mm: GUP passes down
the right mm, so grab_swap_token() ought to be using it.
We have not identified a stronger case than KSM's daemon (not yet in
mainline), but the issue must have come up before, since RHEL has included
a fix for this for years (though a different fix, they just back out of
grab_swap_token if current->mm is unset: which is what we first proposed,
but using the right mm here seems more correct).
Reported-by: Izik Eidus <ieidus@redhat.com>
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
Signed-off-by: Hugh Dickins <hugh.dickins@tiscali.co.uk>
Acked-by: Rik van Riel <riel@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
| -rw-r--r-- | include/linux/swap.h | 12 | ||||
| -rw-r--r-- | mm/memory.c | 2 | ||||
| -rw-r--r-- | mm/thrash.c | 32 |
3 files changed, 22 insertions, 24 deletions
diff --git a/include/linux/swap.h b/include/linux/swap.h index c88b36665f79..7c15334f3ff2 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h | |||
| @@ -298,8 +298,8 @@ extern int try_to_free_swap(struct page *); | |||
| 298 | struct backing_dev_info; | 298 | struct backing_dev_info; |
| 299 | 299 | ||
| 300 | /* linux/mm/thrash.c */ | 300 | /* linux/mm/thrash.c */ |
| 301 | extern struct mm_struct * swap_token_mm; | 301 | extern struct mm_struct *swap_token_mm; |
| 302 | extern void grab_swap_token(void); | 302 | extern void grab_swap_token(struct mm_struct *); |
| 303 | extern void __put_swap_token(struct mm_struct *); | 303 | extern void __put_swap_token(struct mm_struct *); |
| 304 | 304 | ||
| 305 | static inline int has_swap_token(struct mm_struct *mm) | 305 | static inline int has_swap_token(struct mm_struct *mm) |
| @@ -419,10 +419,10 @@ static inline swp_entry_t get_swap_page(void) | |||
| 419 | } | 419 | } |
| 420 | 420 | ||
| 421 | /* linux/mm/thrash.c */ | 421 | /* linux/mm/thrash.c */ |
| 422 | #define put_swap_token(x) do { } while(0) | 422 | #define put_swap_token(mm) do { } while (0) |
| 423 | #define grab_swap_token() do { } while(0) | 423 | #define grab_swap_token(mm) do { } while (0) |
| 424 | #define has_swap_token(x) 0 | 424 | #define has_swap_token(mm) 0 |
| 425 | #define disable_swap_token() do { } while(0) | 425 | #define disable_swap_token() do { } while (0) |
| 426 | 426 | ||
| 427 | static inline void | 427 | static inline void |
| 428 | mem_cgroup_uncharge_swapcache(struct page *page, swp_entry_t ent) | 428 | mem_cgroup_uncharge_swapcache(struct page *page, swp_entry_t ent) |
diff --git a/mm/memory.c b/mm/memory.c index 50da9511aa77..f46ac18ba231 100644 --- a/mm/memory.c +++ b/mm/memory.c | |||
| @@ -2519,7 +2519,7 @@ static int do_swap_page(struct mm_struct *mm, struct vm_area_struct *vma, | |||
| 2519 | delayacct_set_flag(DELAYACCT_PF_SWAPIN); | 2519 | delayacct_set_flag(DELAYACCT_PF_SWAPIN); |
| 2520 | page = lookup_swap_cache(entry); | 2520 | page = lookup_swap_cache(entry); |
| 2521 | if (!page) { | 2521 | if (!page) { |
| 2522 | grab_swap_token(); /* Contend for token _before_ read-in */ | 2522 | grab_swap_token(mm); /* Contend for token _before_ read-in */ |
| 2523 | page = swapin_readahead(entry, | 2523 | page = swapin_readahead(entry, |
| 2524 | GFP_HIGHUSER_MOVABLE, vma, address); | 2524 | GFP_HIGHUSER_MOVABLE, vma, address); |
| 2525 | if (!page) { | 2525 | if (!page) { |
diff --git a/mm/thrash.c b/mm/thrash.c index c4c5205a9c35..2372d4ed5dd8 100644 --- a/mm/thrash.c +++ b/mm/thrash.c | |||
| @@ -26,47 +26,45 @@ static DEFINE_SPINLOCK(swap_token_lock); | |||
| 26 | struct mm_struct *swap_token_mm; | 26 | struct mm_struct *swap_token_mm; |
| 27 | static unsigned int global_faults; | 27 | static unsigned int global_faults; |
| 28 | 28 | ||
| 29 | void grab_swap_token(void) | 29 | void grab_swap_token(struct mm_struct *mm) |
| 30 | { | 30 | { |
| 31 | int current_interval; | 31 | int current_interval; |
| 32 | 32 | ||
| 33 | global_faults++; | 33 | global_faults++; |
| 34 | 34 | ||
| 35 | current_interval = global_faults - current->mm->faultstamp; | 35 | current_interval = global_faults - mm->faultstamp; |
| 36 | 36 | ||
| 37 | if (!spin_trylock(&swap_token_lock)) | 37 | if (!spin_trylock(&swap_token_lock)) |
| 38 | return; | 38 | return; |
| 39 | 39 | ||
| 40 | /* First come first served */ | 40 | /* First come first served */ |
| 41 | if (swap_token_mm == NULL) { | 41 | if (swap_token_mm == NULL) { |
| 42 | current->mm->token_priority = current->mm->token_priority + 2; | 42 | mm->token_priority = mm->token_priority + 2; |
| 43 | swap_token_mm = current->mm; | 43 | swap_token_mm = mm; |
| 44 | goto out; | 44 | goto out; |
| 45 | } | 45 | } |
| 46 | 46 | ||
| 47 | if (current->mm != swap_token_mm) { | 47 | if (mm != swap_token_mm) { |
| 48 | if (current_interval < current->mm->last_interval) | 48 | if (current_interval < mm->last_interval) |
| 49 | current->mm->token_priority++; | 49 | mm->token_priority++; |
| 50 | else { | 50 | else { |
| 51 | if (likely(current->mm->token_priority > 0)) | 51 | if (likely(mm->token_priority > 0)) |
| 52 | current->mm->token_priority--; | 52 | mm->token_priority--; |
| 53 | } | 53 | } |
| 54 | /* Check if we deserve the token */ | 54 | /* Check if we deserve the token */ |
| 55 | if (current->mm->token_priority > | 55 | if (mm->token_priority > swap_token_mm->token_priority) { |
| 56 | swap_token_mm->token_priority) { | 56 | mm->token_priority += 2; |
| 57 | current->mm->token_priority += 2; | 57 | swap_token_mm = mm; |
| 58 | swap_token_mm = current->mm; | ||
| 59 | } | 58 | } |
| 60 | } else { | 59 | } else { |
| 61 | /* Token holder came in again! */ | 60 | /* Token holder came in again! */ |
| 62 | current->mm->token_priority += 2; | 61 | mm->token_priority += 2; |
| 63 | } | 62 | } |
| 64 | 63 | ||
| 65 | out: | 64 | out: |
| 66 | current->mm->faultstamp = global_faults; | 65 | mm->faultstamp = global_faults; |
| 67 | current->mm->last_interval = current_interval; | 66 | mm->last_interval = current_interval; |
| 68 | spin_unlock(&swap_token_lock); | 67 | spin_unlock(&swap_token_lock); |
| 69 | return; | ||
| 70 | } | 68 | } |
| 71 | 69 | ||
| 72 | /* Called on process exit. */ | 70 | /* Called on process exit. */ |
