Another patchset from CK to lighten vm load
[kernel-bfs] / kernel-bfs-2.6.28 / debian / patches / mm-background_scan-2.patch
1 Add a background scanning timer to restore the watermarks to the pages_lots
2 level and only call on it if kswapd has not been called upon for the last 5
3 seconds. This allows us to balance all zones to the more generous pages_lots
4 watermark at a time unrelated to page allocation thus leading to lighter
5 levels of vm load when called upon under page allocation.
6
7 Signed-off-by: Con Kolivas <kernel@kolivas.org>
8
9 The -ck patches modify mm/vmscan.c and add a timer to wake up kswapd every 5 
10 seconds. This timer is initialized after the creation of the kswapd thread.
11
12 The kswapd() thread function calls mod_timer at the front of its infinite 
13 service loop (to reset the timer to 5 seconds in the future). mod_timer() 
14 includes a BUG_ON() to assert that the timer's callback function is set.
15
16 Since the wakeup timer is initialized after the kswapd thread is created, if 
17 kswapd gets scheduled before kswapd_run() has prepared the timer, the 
18 BUG_ON() check will throw a stack trace and immediately terminate the kswapd 
19 thread.
20
21 This patch modifies the kswapd_run() function in mm/vmscan.c to initialize the 
22 watermark timer before starting the kswapd thread.
23
24 Signed-off-by: Chase Venters <chase.venters at clientec.com>
25
26  include/linux/mmzone.h |    2 ++
27  mm/vmscan.c            |   42 ++++++++++++++++++++++++++++++++++++++++++
28  2 files changed, 44 insertions(+)
29
30 Index: linux-2.6.22-ck1/include/linux/mmzone.h
31 ===================================================================
32 --- linux-2.6.22-ck1.orig/include/linux/mmzone.h        2007-07-09 18:44:40.000000000 +1000
33 +++ linux-2.6.22-ck1/include/linux/mmzone.h     2007-07-09 18:44:40.000000000 +1000
34 @@ -13,6 +13,7 @@
35  #include <linux/init.h>
36  #include <linux/seqlock.h>
37  #include <linux/nodemask.h>
38 +#include <linux/timer.h>
39  #include <linux/pageblock-flags.h>
40  #include <linux/bounds.h>
41  #include <asm/atomic.h>
42 @@ -452,6 +453,7 @@ typedef struct pglist_data {
43         wait_queue_head_t kswapd_wait;
44         struct task_struct *kswapd;
45         int kswapd_max_order;
46 +       struct timer_list watermark_timer;
47  } pg_data_t;
48  
49  #define node_present_pages(nid)        (NODE_DATA(nid)->node_present_pages)
50 Index: linux-2.6.22-ck1/mm/vmscan.c
51 ===================================================================
52 --- linux-2.6.22-ck1.orig/mm/vmscan.c   2007-07-09 18:44:40.000000000 +1000
53 +++ linux-2.6.22-ck1/mm/vmscan.c        2007-07-09 18:44:40.000000000 +1000
54 @@ -37,6 +37,7 @@
55  #include <linux/rwsem.h>
56  #include <linux/delay.h>
57  #include <linux/kthread.h>
58 +#include <linux/timer.h>
59  #include <linux/freezer.h>
60  #include <linux/memcontrol.h>
61  #include <linux/delayacct.h>
62 @@ -1330,6 +1331,8 @@ out:
63         return nr_reclaimed;
64  }
65  
66 +#define WT_EXPIRY      (HZ * 5)        /* Time to wakeup watermark_timer */
67 +
68  /*
69   * The background pageout daemon, started as a kernel thread
70   * from the init process. 
71 @@ -1377,6 +1380,8 @@ static int kswapd(void *p)
72         for ( ; ; ) {
73                 unsigned long new_order;
74  
75 +               /* kswapd has been busy so delay watermark_timer */
76 +               mod_timer(&pgdat->watermark_timer, jiffies + WT_EXPIRY);
77                 prepare_to_wait(&pgdat->kswapd_wait, &wait, TASK_INTERRUPTIBLE);
78                 new_order = pgdat->kswapd_max_order;
79                 pgdat->kswapd_max_order = 0;
80 @@ -1604,20 +1609,57 @@ static int __devinit cpu_callback(struct
81  }
82  
83  /*
84 + * We wake up kswapd every WT_EXPIRY till free ram is above pages_lots
85 + */
86 +static void watermark_wakeup(unsigned long data)
87 +{
88 +       pg_data_t *pgdat = (pg_data_t *)data;
89 +       struct timer_list *wt = &pgdat->watermark_timer;
90 +       int i;
91 +
92 +       if (!waitqueue_active(&pgdat->kswapd_wait) || above_background_load())
93 +               goto out;
94 +       for (i = pgdat->nr_zones - 1; i >= 0; i--) {
95 +               struct zone *z = pgdat->node_zones + i;
96 +
97 +               if (!populated_zone(z) || is_highmem(z)) {
98 +                       /* We are better off leaving highmem full */
99 +                       continue;
100 +               }
101 +               if (!zone_watermark_ok(z, 0, z->pages_lots, 0, 0)) {
102 +                       wake_up_interruptible(&pgdat->kswapd_wait);
103 +                       goto out;
104 +               }
105 +       }
106 +out:
107 +       mod_timer(wt, jiffies + WT_EXPIRY);
108 +       return;
109 +}
110 +
111 +/*
112   * This kswapd start function will be called by init and node-hot-add.
113   * On node-hot-add, kswapd will moved to proper cpus if cpus are hot-added.
114   */
115  int kswapd_run(int nid)
116  {
117         pg_data_t *pgdat = NODE_DATA(nid);
118 +       struct timer_list *wt;
119         int ret = 0;
120  
121         if (pgdat->kswapd)
122                 return 0;
123  
124 +       wt = &pgdat->watermark_timer;
125 +       init_timer(wt);
126 +       wt->data = (unsigned long)pgdat;
127 +       wt->function = watermark_wakeup;
128 +       wt->expires = jiffies + WT_EXPIRY;
129 +       add_timer(wt);
130 +
131         pgdat->kswapd = kthread_run(kswapd, pgdat, "kswapd%d", nid);
132         if (IS_ERR(pgdat->kswapd)) {
133                 /* failure at boot is fatal */
134 +               del_timer(wt);
135                 BUG_ON(system_state == SYSTEM_BOOTING);
136                 printk("Failed to start kswapd on node %d\n",nid);
137                 ret = -1;
138