thrash.c 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  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 (300 * HZ)
  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. if (unlikely(!swap_token_default_timeout))
  56. disable_swap_token();
  57. return;
  58. }
  59. if (time_after(jiffies, swap_token_check)) {
  60. if (!swap_token_default_timeout) {
  61. swap_token_check = jiffies + SWAP_TOKEN_CHECK_INTERVAL;
  62. return;
  63. }
  64. /* ... or if we recently held the token. */
  65. if (time_before(jiffies, current->mm->swap_token_time))
  66. return;
  67. if (!spin_trylock(&swap_token_lock))
  68. return;
  69. swap_token_check = jiffies + SWAP_TOKEN_CHECK_INTERVAL;
  70. mm = swap_token_mm;
  71. if ((reason = should_release_swap_token(mm))) {
  72. unsigned long eligible = jiffies;
  73. if (reason == SWAP_TOKEN_TIMED_OUT) {
  74. eligible += swap_token_default_timeout;
  75. }
  76. mm->swap_token_time = eligible;
  77. swap_token_timeout = jiffies + swap_token_default_timeout;
  78. swap_token_mm = current->mm;
  79. }
  80. spin_unlock(&swap_token_lock);
  81. }
  82. return;
  83. }
  84. /* Called on process exit. */
  85. void __put_swap_token(struct mm_struct *mm)
  86. {
  87. spin_lock(&swap_token_lock);
  88. if (likely(mm == swap_token_mm)) {
  89. mm->swap_token_time = jiffies + SWAP_TOKEN_CHECK_INTERVAL;
  90. swap_token_mm = &init_mm;
  91. swap_token_check = jiffies;
  92. }
  93. spin_unlock(&swap_token_lock);
  94. }