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

