RHEL4/mm/thrash.c
<<
>>
Prefs
   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