This commit was manufactured by cvs2svn to create branch 'vserver'.
[linux-2.6.git] / mm / thrash.c
1 /*
2  * mm/thrash.c
3  *
4  * Copyright (C) 2004, Red Hat, Inc.
5  * Copyright (C) 2004, Rik van Riel <riel@redhat.com>
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 spinlock_t swap_token_lock = SPIN_LOCK_UNLOCKED;
17 static unsigned long swap_token_timeout;
18 unsigned long swap_token_check;
19 struct mm_struct * swap_token_mm = &init_mm;
20
21 #define SWAP_TOKEN_CHECK_INTERVAL (HZ * 2)
22 #define SWAP_TOKEN_TIMEOUT (HZ * 300)
23
24 /*
25  * Take the token away if the process had no page faults
26  * in the last interval, or if it has held the token for
27  * too long.
28  */
29 #define SWAP_TOKEN_ENOUGH_RSS 1
30 #define SWAP_TOKEN_TIMED_OUT 2
31 static int should_release_swap_token(struct mm_struct *mm)
32 {
33         int ret = 0;
34         if (!mm->recent_pagein)
35                 ret = SWAP_TOKEN_ENOUGH_RSS;
36         else if (time_after(jiffies, swap_token_timeout))
37                 ret = SWAP_TOKEN_TIMED_OUT;
38         mm->recent_pagein = 0;
39         return ret;
40 }
41
42 /*
43  * Try to grab the swapout protection token.  We only try to
44  * grab it once every TOKEN_CHECK_INTERVAL, both to prevent
45  * SMP lock contention and to check that the process that held
46  * the token before is no longer thrashing.
47  */
48 void grab_swap_token(void)
49 {
50         struct mm_struct *mm;
51         int reason;
52
53         /* We have the token. Let others know we still need it. */
54         if (has_swap_token(current->mm)) {
55                 current->mm->recent_pagein = 1;
56                 return;
57         }
58
59         if (time_after(jiffies, swap_token_check)) {
60
61                 /* Can't get swapout protection if we exceed our RSS limit. */
62                 // if (current->mm->rss > current->mm->rlimit_rss)
63                 //      return;
64
65                 /* ... or if we recently held the token. */
66                 if (time_before(jiffies, current->mm->swap_token_time))
67                         return;
68
69                 if (!spin_trylock(&swap_token_lock))
70                         return;
71
72                 swap_token_check = jiffies + SWAP_TOKEN_CHECK_INTERVAL;
73
74                 mm = swap_token_mm;
75                 if ((reason = should_release_swap_token(mm))) {
76                         unsigned long eligible = jiffies;
77                         if (reason == SWAP_TOKEN_TIMED_OUT) {
78                                 eligible += SWAP_TOKEN_TIMEOUT;
79                         }
80                         mm->swap_token_time = eligible;
81                         swap_token_timeout = jiffies + SWAP_TOKEN_TIMEOUT;
82                         swap_token_mm = current->mm;
83                 }
84                 spin_unlock(&swap_token_lock);
85         }
86         return;
87 }
88
89 /* Called on process exit. */
90 void __put_swap_token(struct mm_struct *mm)
91 {
92         spin_lock(&swap_token_lock);
93         if (likely(mm == swap_token_mm)) {
94                 swap_token_mm = &init_mm;
95                 swap_token_check = jiffies;
96         }
97         spin_unlock(&swap_token_lock);
98 }