thrash.c 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  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. static DEFINE_SPINLOCK(swap_token_lock);
  16. static unsigned long swap_token_timeout;
  17. static unsigned long swap_token_check;
  18. struct mm_struct * swap_token_mm = &init_mm;
  19. #define SWAP_TOKEN_CHECK_INTERVAL (HZ * 2)
  20. #define SWAP_TOKEN_TIMEOUT 0
  21. /*
  22. * Currently disabled; Needs further code to work at HZ * 300.
  23. */
  24. unsigned long swap_token_default_timeout = SWAP_TOKEN_TIMEOUT;
  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
  32. static 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. * 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. /* We have the token. Let others know we still need it. */
  53. if (has_swap_token(current->mm)) {
  54. current->mm->recent_pagein = 1;
  55. return;
  56. }
  57. if (time_after(jiffies, swap_token_check)) {
  58. /* Can't get swapout protection if we exceed our RSS limit. */
  59. // if (current->mm->rss > current->mm->rlimit_rss)
  60. // return;
  61. /* ... or if we recently held the token. */
  62. if (time_before(jiffies, current->mm->swap_token_time))
  63. return;
  64. if (!spin_trylock(&swap_token_lock))
  65. return;
  66. swap_token_check = jiffies + SWAP_TOKEN_CHECK_INTERVAL;
  67. mm = swap_token_mm;
  68. if ((reason = should_release_swap_token(mm))) {
  69. unsigned long eligible = jiffies;
  70. if (reason == SWAP_TOKEN_TIMED_OUT) {
  71. eligible += swap_token_default_timeout;
  72. }
  73. mm->swap_token_time = eligible;
  74. swap_token_timeout = jiffies + swap_token_default_timeout;
  75. swap_token_mm = current->mm;
  76. }
  77. spin_unlock(&swap_token_lock);
  78. }
  79. return;
  80. }
  81. /* Called on process exit. */
  82. void __put_swap_token(struct mm_struct *mm)
  83. {
  84. spin_lock(&swap_token_lock);
  85. if (likely(mm == swap_token_mm)) {
  86. swap_token_mm = &init_mm;
  87. swap_token_check = jiffies;
  88. }
  89. spin_unlock(&swap_token_lock);
  90. }