]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * mm/thrash.c | |
3 | * | |
4 | * Copyright (C) 2004, Red Hat, Inc. | |
5 | * Copyright (C) 2004, Rik van Riel <[email protected]> | |
6 | * Released under the GPL, see the file COPYING for details. | |
7 | * | |
8 | * Simple token based thrashing protection, using the algorithm | |
9 | * described in: http://www.cs.wm.edu/~sjiang/token.pdf | |
10 | */ | |
11 | #include <linux/jiffies.h> | |
12 | #include <linux/mm.h> | |
13 | #include <linux/sched.h> | |
14 | #include <linux/swap.h> | |
15 | ||
16 | static DEFINE_SPINLOCK(swap_token_lock); | |
17 | static unsigned long swap_token_timeout; | |
18 | static unsigned long swap_token_check; | |
19 | struct mm_struct * swap_token_mm = &init_mm; | |
20 | ||
21 | #define SWAP_TOKEN_CHECK_INTERVAL (HZ * 2) | |
fcdae29a | 22 | #define SWAP_TOKEN_TIMEOUT (300 * HZ) |
1da177e4 LT |
23 | /* |
24 | * Currently disabled; Needs further code to work at HZ * 300. | |
25 | */ | |
26 | unsigned long swap_token_default_timeout = SWAP_TOKEN_TIMEOUT; | |
27 | ||
28 | /* | |
29 | * Take the token away if the process had no page faults | |
30 | * in the last interval, or if it has held the token for | |
31 | * too long. | |
32 | */ | |
33 | #define SWAP_TOKEN_ENOUGH_RSS 1 | |
34 | #define SWAP_TOKEN_TIMED_OUT 2 | |
35 | static int should_release_swap_token(struct mm_struct *mm) | |
36 | { | |
37 | int ret = 0; | |
38 | if (!mm->recent_pagein) | |
39 | ret = SWAP_TOKEN_ENOUGH_RSS; | |
40 | else if (time_after(jiffies, swap_token_timeout)) | |
41 | ret = SWAP_TOKEN_TIMED_OUT; | |
42 | mm->recent_pagein = 0; | |
43 | return ret; | |
44 | } | |
45 | ||
46 | /* | |
47 | * Try to grab the swapout protection token. We only try to | |
48 | * grab it once every TOKEN_CHECK_INTERVAL, both to prevent | |
49 | * SMP lock contention and to check that the process that held | |
50 | * the token before is no longer thrashing. | |
51 | */ | |
52 | void grab_swap_token(void) | |
53 | { | |
54 | struct mm_struct *mm; | |
55 | int reason; | |
56 | ||
57 | /* We have the token. Let others know we still need it. */ | |
58 | if (has_swap_token(current->mm)) { | |
59 | current->mm->recent_pagein = 1; | |
f7b7fd8f RR |
60 | if (unlikely(!swap_token_default_timeout)) |
61 | disable_swap_token(); | |
1da177e4 LT |
62 | return; |
63 | } | |
64 | ||
65 | if (time_after(jiffies, swap_token_check)) { | |
66 | ||
f7b7fd8f RR |
67 | if (!swap_token_default_timeout) { |
68 | swap_token_check = jiffies + SWAP_TOKEN_CHECK_INTERVAL; | |
69 | return; | |
70 | } | |
1da177e4 LT |
71 | |
72 | /* ... or if we recently held the token. */ | |
73 | if (time_before(jiffies, current->mm->swap_token_time)) | |
74 | return; | |
75 | ||
76 | if (!spin_trylock(&swap_token_lock)) | |
77 | return; | |
78 | ||
79 | swap_token_check = jiffies + SWAP_TOKEN_CHECK_INTERVAL; | |
80 | ||
81 | mm = swap_token_mm; | |
82 | if ((reason = should_release_swap_token(mm))) { | |
83 | unsigned long eligible = jiffies; | |
84 | if (reason == SWAP_TOKEN_TIMED_OUT) { | |
85 | eligible += swap_token_default_timeout; | |
86 | } | |
87 | mm->swap_token_time = eligible; | |
88 | swap_token_timeout = jiffies + swap_token_default_timeout; | |
89 | swap_token_mm = current->mm; | |
90 | } | |
91 | spin_unlock(&swap_token_lock); | |
92 | } | |
93 | return; | |
94 | } | |
95 | ||
96 | /* Called on process exit. */ | |
97 | void __put_swap_token(struct mm_struct *mm) | |
98 | { | |
99 | spin_lock(&swap_token_lock); | |
100 | if (likely(mm == swap_token_mm)) { | |
f7b7fd8f | 101 | mm->swap_token_time = jiffies + SWAP_TOKEN_CHECK_INTERVAL; |
1da177e4 LT |
102 | swap_token_mm = &init_mm; |
103 | swap_token_check = jiffies; | |
104 | } | |
105 | spin_unlock(&swap_token_lock); | |
106 | } |