Another patchset from CK to lighten vm load
[kernel-bfs] / kernel-bfs-2.6.28 / debian / patches / mm-lru_cache_add_lru_tail.patch
1 When reading from large files through the generic file read functions into
2 page cache we can detect when a file is so large that it is unlikely to be
3 fully cached in ram. If that happens we can put it on the tail end of the
4 inactive lru list so it can be the first thing evicted next time we need ram.
5
6 Do lots of funny buggers with underscores to preserve all the existing APIs.
7
8 -ck
9
10 ---
11  include/linux/mm_inline.h |   14 ++++++++++--
12  include/linux/swap.h      |    5 ++--
13  mm/filemap.c              |   51 +++++++++++++++++++++++++++++++++++++++-------
14  mm/swap.c                 |   29 ++++++++++++++++++++------
15  4 files changed, 82 insertions(+), 17 deletions(-)
16
17 Index: linux-2.6.32-ck1/include/linux/mm_inline.h
18 ===================================================================
19 --- linux-2.6.32-ck1.orig/include/linux/mm_inline.h     2009-12-10 20:47:13.927251742 +1100
20 +++ linux-2.6.32-ck1/include/linux/mm_inline.h  2009-12-10 22:45:33.041376670 +1100
21 @@ -20,13 +20,23 @@ static inline int page_is_file_cache(str
22  }
23  
24  static inline void
25 -add_page_to_lru_list(struct zone *zone, struct page *page, enum lru_list l)
26 +__add_page_to_lru_list(struct zone *zone, struct page *page, enum lru_list l, int tail)
27  {
28 -       list_add(&page->lru, &zone->lru[l].list);
29 +       /* See if this should be added to the tail of this lru list */
30 +       if (tail)
31 +               list_add_tail(&page->lru, &zone->lru[l].list);
32 +       else
33 +               list_add(&page->lru, &zone->lru[l].list);
34         __inc_zone_state(zone, NR_LRU_BASE + l);
35  }
36  
37  static inline void
38 +add_page_to_lru_list(struct zone *zone, struct page *page, enum lru_list l)
39 +{
40 +       __add_page_to_lru_list(zone, page, l, 0);
41 +}
42 +
43 +static inline void
44  del_page_from_lru_list(struct zone *zone, struct page *page, enum lru_list l)
45  {
46         list_del(&page->lru);
47 Index: linux-2.6.32-ck1/include/linux/swap.h
48 ===================================================================
49 --- linux-2.6.32-ck1.orig/include/linux/swap.h  2009-12-10 20:45:55.306251536 +1100
50 +++ linux-2.6.32-ck1/include/linux/swap.h       2009-12-10 22:47:38.415251020 +1100
51 @@ -198,6 +198,7 @@ extern unsigned int nr_free_pagecache_pa
52  
53  
54  /* linux/mm/swap.c */
55 +extern void ____lru_cache_add(struct page *, enum lru_list lru, int tail);
56  extern void __lru_cache_add(struct page *, enum lru_list lru);
57  extern void lru_cache_add_lru(struct page *, enum lru_list lru);
58  extern void activate_page(struct page *);
59 @@ -223,9 +224,9 @@ static inline void lru_cache_add_active_
60         __lru_cache_add(page, LRU_ACTIVE_ANON);
61  }
62  
63 -static inline void lru_cache_add_file(struct page *page)
64 +static inline void lru_cache_add_file(struct page *page, int tail)
65  {
66 -       __lru_cache_add(page, LRU_INACTIVE_FILE);
67 +       ____lru_cache_add(page, LRU_INACTIVE_FILE, tail);
68  }
69  
70  static inline void lru_cache_add_active_file(struct page *page)
71 Index: linux-2.6.32-ck1/mm/filemap.c
72 ===================================================================
73 --- linux-2.6.32-ck1.orig/mm/filemap.c  2009-12-10 20:52:17.597126805 +1100
74 +++ linux-2.6.32-ck1/mm/filemap.c       2009-12-10 22:41:11.812251151 +1100
75 @@ -454,8 +454,8 @@ out:
76  }
77  EXPORT_SYMBOL(add_to_page_cache_locked);
78  
79 -int add_to_page_cache_lru(struct page *page, struct address_space *mapping,
80 -                               pgoff_t offset, gfp_t gfp_mask)
81 +int __add_to_page_cache_lru(struct page *page, struct address_space *mapping,
82 +                               pgoff_t offset, gfp_t gfp_mask, int tail)
83  {
84         int ret;
85  
86 @@ -471,12 +471,19 @@ int add_to_page_cache_lru(struct page *p
87         ret = add_to_page_cache(page, mapping, offset, gfp_mask);
88         if (ret == 0) {
89                 if (page_is_file_cache(page))
90 -                       lru_cache_add_file(page);
91 +                       lru_cache_add_file(page, tail);
92                 else
93                         lru_cache_add_active_anon(page);
94         }
95         return ret;
96  }
97 +
98 +int add_to_page_cache_lru(struct page *page, struct address_space *mapping,
99 +                               pgoff_t offset, gfp_t gfp_mask)
100 +{
101 +       return __add_to_page_cache_lru(page, mapping, offset, gfp_mask, 0);
102 +}
103 +
104  
105  #ifdef CONFIG_NUMA
106  struct page *__page_cache_alloc(gfp_t gfp)
107 @@ -970,6 +977,28 @@ static void shrink_readahead_size_eio(st
108  }
109  EXPORT_SYMBOL(find_get_pages);
110
111 +static inline int nr_mapped(void)
112 +{
113 +       return global_page_state(NR_FILE_MAPPED) +
114 +               global_page_state(NR_ANON_PAGES);
115 +}
116 +
117 +/*
118 + * This examines how large in pages a file size is and returns 1 if it is
119 + * more than half the unmapped ram. Avoid doing read_page_state which is
120 + * expensive unless we already know it is likely to be large enough.
121 + */
122 +static int large_isize(unsigned long nr_pages)
123 +{
124 +       if (nr_pages * 6 > vm_total_pages) {
125 +                unsigned long unmapped_ram = vm_total_pages - nr_mapped();
126 +
127 +               if (nr_pages * 2 > unmapped_ram)
128 +                       return 1;
129 +       }
130 +       return 0;
131 +}
132 +
133  /**
134   * do_generic_file_read - generic file read routine
135   * @filp:      the file to read
136 @@ -994,7 +1023,7 @@ static void do_generic_file_read(struct 
137         pgoff_t prev_index;
138         unsigned long offset;      /* offset into pagecache page */
139         unsigned int prev_offset;
140 -       int error;
141 +       int error, tail = 0;
142  
143         index = *ppos >> PAGE_CACHE_SHIFT;
144         prev_index = ra->prev_pos >> PAGE_CACHE_SHIFT;
145 @@ -1005,7 +1034,7 @@ static void do_generic_file_read(struct 
146         for (;;) {
147                 struct page *page;
148                 pgoff_t end_index;
149 -               loff_t isize;
150 +               loff_t isize = 0;
151                 unsigned long nr, ret;
152  
153                 cond_resched();
154 @@ -1170,8 +1199,16 @@ no_cached_page:
155                         desc->error = -ENOMEM;
156                         goto out;
157                 }
158 -               error = add_to_page_cache_lru(page, mapping,
159 -                                               index, GFP_KERNEL);
160 +               /*
161 +                * If we know the file is large we add the pages read to the
162 +                * end of the lru as we're unlikely to be able to cache the
163 +                * whole file in ram so make those pages the first to be
164 +                * dropped if not referenced soon.
165 +                */
166 +               if (large_isize(end_index))
167 +                       tail = 1;
168 +               error = __add_to_page_cache_lru(page, mapping,
169 +                                               index, GFP_KERNEL, tail);
170                 if (error) {
171                         page_cache_release(page);
172                         if (error == -EEXIST)
173 Index: linux-2.6.32-ck1/mm/swap.c
174 ===================================================================
175 --- linux-2.6.32-ck1.orig/mm/swap.c     2009-12-10 20:45:55.320251262 +1100
176 +++ linux-2.6.32-ck1/mm/swap.c  2009-12-10 22:53:10.138009481 +1100
177 @@ -214,22 +214,29 @@ void mark_page_accessed(struct page *pag
178  
179  EXPORT_SYMBOL(mark_page_accessed);
180  
181 -void __lru_cache_add(struct page *page, enum lru_list lru)
182 +void ______pagevec_lru_add(struct pagevec *pvec, enum lru_list lru, int tail);
183 +
184 +void ____lru_cache_add(struct page *page, enum lru_list lru, int tail)
185  {
186         struct pagevec *pvec = &get_cpu_var(lru_add_pvecs)[lru];
187  
188         page_cache_get(page);
189         if (!pagevec_add(pvec, page))
190 -               ____pagevec_lru_add(pvec, lru);
191 +               ______pagevec_lru_add(pvec, lru, tail);
192         put_cpu_var(lru_add_pvecs);
193  }
194  
195 +void __lru_cache_add(struct page *page, enum lru_list lru)
196 +{
197 +       ____lru_cache_add(page, lru, 0);
198 +}
199 +
200  /**
201   * lru_cache_add_lru - add a page to a page list
202   * @page: the page to be added to the LRU.
203   * @lru: the LRU list to which the page is added.
204   */
205 -void lru_cache_add_lru(struct page *page, enum lru_list lru)
206 +void __lru_cache_add_lru(struct page *page, enum lru_list lru, int tail)
207  {
208         if (PageActive(page)) {
209                 VM_BUG_ON(PageUnevictable(page));
210 @@ -240,7 +247,12 @@ void lru_cache_add_lru(struct page *page
211         }
212  
213         VM_BUG_ON(PageLRU(page) || PageActive(page) || PageUnevictable(page));
214 -       __lru_cache_add(page, lru);
215 +       ____lru_cache_add(page, lru, tail);
216 +}
217 +
218 +void lru_cache_add_lru(struct page *page, enum lru_list lru)
219 +{
220 +       __lru_cache_add_lru(page, lru, 0);
221  }
222  
223  /**
224 @@ -400,7 +412,7 @@ EXPORT_SYMBOL(__pagevec_release);
225   * Add the passed pages to the LRU, then drop the caller's refcount
226   * on them.  Reinitialises the caller's pagevec.
227   */
228 -void ____pagevec_lru_add(struct pagevec *pvec, enum lru_list lru)
229 +void ______pagevec_lru_add(struct pagevec *pvec, enum lru_list lru, int tail)
230  {
231         int i;
232         struct zone *zone = NULL;
233 @@ -428,7 +440,7 @@ void ____pagevec_lru_add(struct pagevec 
234                         SetPageActive(page);
235                         zone->recent_rotated[file]++;
236                 }
237 -               add_page_to_lru_list(zone, page, lru);
238 +               __add_page_to_lru_list(zone, page, lru, tail);
239         }
240         if (zone)
241                 spin_unlock_irq(&zone->lru_lock);
242 @@ -436,6 +448,11 @@ void ____pagevec_lru_add(struct pagevec 
243         pagevec_reinit(pvec);
244  }
245  
246 +void ____pagevec_lru_add(struct pagevec *pvec, enum lru_list lru)
247 +{
248 +       ______pagevec_lru_add(pvec, lru, 0);
249 +}
250 +
251  EXPORT_SYMBOL(____pagevec_lru_add);
252  
253  /*
254