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.
6 Do lots of funny buggers with underscores to preserve all the existing APIs.
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(-)
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
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)
28 - list_add(&page->lru, &zone->lru[l].list);
29 + /* See if this should be added to the tail of this lru list */
31 + list_add_tail(&page->lru, &zone->lru[l].list);
33 + list_add(&page->lru, &zone->lru[l].list);
34 __inc_zone_state(zone, NR_LRU_BASE + l);
38 +add_page_to_lru_list(struct zone *zone, struct page *page, enum lru_list l)
40 + __add_page_to_lru_list(zone, page, l, 0);
44 del_page_from_lru_list(struct zone *zone, struct page *page, enum lru_list l)
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
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);
63 -static inline void lru_cache_add_file(struct page *page)
64 +static inline void lru_cache_add_file(struct page *page, int tail)
66 - __lru_cache_add(page, LRU_INACTIVE_FILE);
67 + ____lru_cache_add(page, LRU_INACTIVE_FILE, tail);
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:
77 EXPORT_SYMBOL(add_to_page_cache_locked);
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)
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);
89 if (page_is_file_cache(page))
90 - lru_cache_add_file(page);
91 + lru_cache_add_file(page, tail);
93 lru_cache_add_active_anon(page);
98 +int add_to_page_cache_lru(struct page *page, struct address_space *mapping,
99 + pgoff_t offset, gfp_t gfp_mask)
101 + return __add_to_page_cache_lru(page, mapping, offset, gfp_mask, 0);
106 struct page *__page_cache_alloc(gfp_t gfp)
107 @@ -970,6 +977,28 @@ static void shrink_readahead_size_eio(st
109 EXPORT_SYMBOL(find_get_pages);
111 +static inline int nr_mapped(void)
113 + return global_page_state(NR_FILE_MAPPED) +
114 + global_page_state(NR_ANON_PAGES);
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.
122 +static int large_isize(unsigned long nr_pages)
124 + if (nr_pages * 6 > vm_total_pages) {
125 + unsigned long unmapped_ram = vm_total_pages - nr_mapped();
127 + if (nr_pages * 2 > unmapped_ram)
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
138 unsigned long offset; /* offset into pagecache page */
139 unsigned int prev_offset;
141 + int error, tail = 0;
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
151 unsigned long nr, ret;
154 @@ -1170,8 +1199,16 @@ no_cached_page:
155 desc->error = -ENOMEM;
158 - error = add_to_page_cache_lru(page, mapping,
159 - index, GFP_KERNEL);
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.
166 + if (large_isize(end_index))
168 + error = __add_to_page_cache_lru(page, mapping,
169 + index, GFP_KERNEL, tail);
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
179 EXPORT_SYMBOL(mark_page_accessed);
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);
184 +void ____lru_cache_add(struct page *page, enum lru_list lru, int tail)
186 struct pagevec *pvec = &get_cpu_var(lru_add_pvecs)[lru];
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);
195 +void __lru_cache_add(struct page *page, enum lru_list lru)
197 + ____lru_cache_add(page, lru, 0);
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.
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)
208 if (PageActive(page)) {
209 VM_BUG_ON(PageUnevictable(page));
210 @@ -240,7 +247,12 @@ void lru_cache_add_lru(struct page *page
213 VM_BUG_ON(PageLRU(page) || PageActive(page) || PageUnevictable(page));
214 - __lru_cache_add(page, lru);
215 + ____lru_cache_add(page, lru, tail);
218 +void lru_cache_add_lru(struct page *page, enum lru_list lru)
220 + __lru_cache_add_lru(page, lru, 0);
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.
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)
232 struct zone *zone = NULL;
233 @@ -428,7 +440,7 @@ void ____pagevec_lru_add(struct pagevec
235 zone->recent_rotated[file]++;
237 - add_page_to_lru_list(zone, page, lru);
238 + __add_page_to_lru_list(zone, page, lru, tail);
241 spin_unlock_irq(&zone->lru_lock);
242 @@ -436,6 +448,11 @@ void ____pagevec_lru_add(struct pagevec
243 pagevec_reinit(pvec);
246 +void ____pagevec_lru_add(struct pagevec *pvec, enum lru_list lru)
248 + ______pagevec_lru_add(pvec, lru, 0);
251 EXPORT_SYMBOL(____pagevec_lru_add);