2005-04-17 02:20:36 +04:00
/*
* mm / thrash . c
*
* Copyright ( C ) 2004 , Red Hat , Inc .
* Copyright ( C ) 2004 , Rik van Riel < riel @ redhat . com >
* Released under the GPL , see the file COPYING for details .
*
* Simple token based thrashing protection , using the algorithm
* described in : http : //www.cs.wm.edu/~sjiang/token.pdf
2006-12-07 07:31:57 +03:00
*
* Sep 2006 , Ashwin Chaugule < ashwin . chaugule @ celunite . com >
* Improved algorithm to pass token :
* Each task has a priority which is incremented if it contended
* for the token in an interval less than its previous attempt .
* If the token is acquired , that task ' s priority is boosted to prevent
* the token from bouncing around too often and to let the task make
* some progress in its execution .
2005-04-17 02:20:36 +04:00
*/
2006-12-07 07:31:57 +03:00
2005-04-17 02:20:36 +04:00
# include <linux/jiffies.h>
# include <linux/mm.h>
# include <linux/sched.h>
# include <linux/swap.h>
static DEFINE_SPINLOCK ( swap_token_lock ) ;
2006-12-07 07:31:57 +03:00
struct mm_struct * swap_token_mm ;
2006-12-07 07:32:43 +03:00
static unsigned int global_faults ;
2005-04-17 02:20:36 +04:00
2009-06-23 23:36:58 +04:00
void grab_swap_token ( struct mm_struct * mm )
2005-04-17 02:20:36 +04:00
{
2006-12-07 07:31:57 +03:00
int current_interval ;
2005-04-17 02:20:36 +04:00
2006-12-07 07:31:57 +03:00
global_faults + + ;
2005-04-17 02:20:36 +04:00
2009-06-23 23:36:58 +04:00
current_interval = global_faults - mm - > faultstamp ;
2005-04-17 02:20:36 +04:00
2006-12-07 07:31:57 +03:00
if ( ! spin_trylock ( & swap_token_lock ) )
return ;
2005-04-17 02:20:36 +04:00
2006-12-07 07:31:57 +03:00
/* First come first served */
if ( swap_token_mm = = NULL ) {
2009-06-23 23:36:58 +04:00
mm - > token_priority = mm - > token_priority + 2 ;
swap_token_mm = mm ;
2006-12-07 07:31:57 +03:00
goto out ;
}
2005-04-17 02:20:36 +04:00
2009-06-23 23:36:58 +04:00
if ( mm ! = swap_token_mm ) {
if ( current_interval < mm - > last_interval )
mm - > token_priority + + ;
2006-12-07 07:31:57 +03:00
else {
2009-06-23 23:36:58 +04:00
if ( likely ( mm - > token_priority > 0 ) )
mm - > token_priority - - ;
2006-12-07 07:31:57 +03:00
}
/* Check if we deserve the token */
2009-06-23 23:36:58 +04:00
if ( mm - > token_priority > swap_token_mm - > token_priority ) {
mm - > token_priority + = 2 ;
swap_token_mm = mm ;
2005-04-17 02:20:36 +04:00
}
2006-12-07 07:31:57 +03:00
} else {
/* Token holder came in again! */
2009-06-23 23:36:58 +04:00
mm - > token_priority + = 2 ;
2005-04-17 02:20:36 +04:00
}
2006-12-07 07:31:57 +03:00
out :
2009-06-23 23:36:58 +04:00
mm - > faultstamp = global_faults ;
mm - > last_interval = current_interval ;
2006-12-07 07:31:57 +03:00
spin_unlock ( & swap_token_lock ) ;
2005-04-17 02:20:36 +04:00
}
/* Called on process exit. */
void __put_swap_token ( struct mm_struct * mm )
{
spin_lock ( & swap_token_lock ) ;
2006-12-07 07:31:57 +03:00
if ( likely ( mm = = swap_token_mm ) )
swap_token_mm = NULL ;
2005-04-17 02:20:36 +04:00
spin_unlock ( & swap_token_lock ) ;
}