Blame view

mm/swap.c 27.7 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
  /*
   *  linux/mm/swap.c
   *
   *  Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
   */
  
  /*
183ff22bb   Simon Arlott   spelling fixes: mm/
8
   * This file contains the default values for the operation of the
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
   * Linux VM subsystem. Fine-tuning documentation can be found in
   * Documentation/sysctl/vm.txt.
   * Started 18.12.91
   * Swap aging added 23.2.95, Stephen Tweedie.
   * Buffermem limits added 12.3.98, Rik van Riel.
   */
  
  #include <linux/mm.h>
  #include <linux/sched.h>
  #include <linux/kernel_stat.h>
  #include <linux/swap.h>
  #include <linux/mman.h>
  #include <linux/pagemap.h>
  #include <linux/pagevec.h>
  #include <linux/init.h>
b95f1b31b   Paul Gortmaker   mm: Map most file...
24
  #include <linux/export.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
25
  #include <linux/mm_inline.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
26
  #include <linux/percpu_counter.h>
3565fce3a   Dan Williams   mm, x86: get_user...
27
  #include <linux/memremap.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
29
30
  #include <linux/percpu.h>
  #include <linux/cpu.h>
  #include <linux/notifier.h>
e0bf68dde   Peter Zijlstra   mm: bdi init hooks
31
  #include <linux/backing-dev.h>
66e1707bc   Balbir Singh   Memory controller...
32
  #include <linux/memcontrol.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
33
  #include <linux/gfp.h>
a27bb332c   Kent Overstreet   aio: don't includ...
34
  #include <linux/uio.h>
822fc6136   Naoya Horiguchi   mm: don't call __...
35
  #include <linux/hugetlb.h>
33c3fc71c   Vladimir Davydov   mm: introduce idl...
36
  #include <linux/page_idle.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37

64d6519dd   Lee Schermerhorn   swap: cull unevic...
38
  #include "internal.h"
c6286c983   Mel Gorman   mm: add tracepoin...
39
40
  #define CREATE_TRACE_POINTS
  #include <trace/events/pagemap.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
41
42
  /* How many pages do we try to swap or page in/out together? */
  int page_cluster;
13f7f7898   Mel Gorman   mm: pagevec: defe...
43
  static DEFINE_PER_CPU(struct pagevec, lru_add_pvec);
f84f9504b   Vegard Nossum   mm: remove initia...
44
  static DEFINE_PER_CPU(struct pagevec, lru_rotate_pvecs);
cc5993bd7   Minchan Kim   mm: rename deacti...
45
  static DEFINE_PER_CPU(struct pagevec, lru_deactivate_file_pvecs);
f7ad2a6cb   Shaohua Li   mm: move MADV_FRE...
46
  static DEFINE_PER_CPU(struct pagevec, lru_lazyfree_pvecs);
a4a921aa5   Ming Li   mm/swap.c: put ac...
47
48
49
  #ifdef CONFIG_SMP
  static DEFINE_PER_CPU(struct pagevec, activate_page_pvecs);
  #endif
902aaed0d   Hisashi Hifumi   mm: use pagevec t...
50

b221385bc   Adrian Bunk   [PATCH] mm/: make...
51
52
53
54
  /*
   * This path almost never happens for VM activity - pages are normally
   * freed via pagevecs.  But it gets used by networking.
   */
920c7a5d0   Harvey Harrison   mm: remove fastca...
55
  static void __page_cache_release(struct page *page)
b221385bc   Adrian Bunk   [PATCH] mm/: make...
56
57
  {
  	if (PageLRU(page)) {
b221385bc   Adrian Bunk   [PATCH] mm/: make...
58
  		struct zone *zone = page_zone(page);
fa9add641   Hugh Dickins   mm/memcg: apply a...
59
60
  		struct lruvec *lruvec;
  		unsigned long flags;
b221385bc   Adrian Bunk   [PATCH] mm/: make...
61

a52633d8e   Mel Gorman   mm, vmscan: move ...
62
  		spin_lock_irqsave(zone_lru_lock(zone), flags);
599d0c954   Mel Gorman   mm, vmscan: move ...
63
  		lruvec = mem_cgroup_page_lruvec(page, zone->zone_pgdat);
309381fea   Sasha Levin   mm: dump page whe...
64
  		VM_BUG_ON_PAGE(!PageLRU(page), page);
b221385bc   Adrian Bunk   [PATCH] mm/: make...
65
  		__ClearPageLRU(page);
fa9add641   Hugh Dickins   mm/memcg: apply a...
66
  		del_page_from_lru_list(page, lruvec, page_off_lru(page));
a52633d8e   Mel Gorman   mm, vmscan: move ...
67
  		spin_unlock_irqrestore(zone_lru_lock(zone), flags);
b221385bc   Adrian Bunk   [PATCH] mm/: make...
68
  	}
629060270   Nicholas Piggin   mm: add PageWaite...
69
  	__ClearPageWaiters(page);
0a31bc97c   Johannes Weiner   mm: memcontrol: r...
70
  	mem_cgroup_uncharge(page);
918070634   Andrea Arcangeli   thp: alter compou...
71
72
73
74
75
  }
  
  static void __put_single_page(struct page *page)
  {
  	__page_cache_release(page);
b745bc85f   Mel Gorman   mm: page_alloc: c...
76
  	free_hot_cold_page(page, false);
b221385bc   Adrian Bunk   [PATCH] mm/: make...
77
  }
918070634   Andrea Arcangeli   thp: alter compou...
78
  static void __put_compound_page(struct page *page)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
79
  {
918070634   Andrea Arcangeli   thp: alter compou...
80
  	compound_page_dtor *dtor;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
81

822fc6136   Naoya Horiguchi   mm: don't call __...
82
83
84
85
86
87
88
89
  	/*
  	 * __page_cache_release() is supposed to be called for thp, not for
  	 * hugetlb. This is because hugetlb page does never have PageLRU set
  	 * (it's never listed to any LRU lists) and no memcg routines should
  	 * be called for hugetlb (it has a separate hugetlb_cgroup.)
  	 */
  	if (!PageHuge(page))
  		__page_cache_release(page);
918070634   Andrea Arcangeli   thp: alter compou...
90
91
92
  	dtor = get_compound_page_dtor(page);
  	(*dtor)(page);
  }
ddc58f27f   Kirill A. Shutemov   mm: drop tail pag...
93
  void __put_page(struct page *page)
8519fb30e   Nick Piggin   [PATCH] mm: compo...
94
  {
713897038   Dan Williams   mm, zone_device: ...
95
96
97
98
99
100
101
102
103
  	if (is_zone_device_page(page)) {
  		put_dev_pagemap(page->pgmap);
  
  		/*
  		 * The page belongs to the device that created pgmap. Do
  		 * not return it to page allocator.
  		 */
  		return;
  	}
8519fb30e   Nick Piggin   [PATCH] mm: compo...
104
  	if (unlikely(PageCompound(page)))
ddc58f27f   Kirill A. Shutemov   mm: drop tail pag...
105
106
  		__put_compound_page(page);
  	else
918070634   Andrea Arcangeli   thp: alter compou...
107
  		__put_single_page(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
108
  }
ddc58f27f   Kirill A. Shutemov   mm: drop tail pag...
109
  EXPORT_SYMBOL(__put_page);
70b50f94f   Andrea Arcangeli   mm: thp: tail pag...
110

1d7ea7324   Alexander Zarochentsev   [PATCH] fuse: fix...
111
  /**
7682486b3   Randy Dunlap   mm: fix various k...
112
113
   * put_pages_list() - release a list of pages
   * @pages: list of pages threaded on page->lru
1d7ea7324   Alexander Zarochentsev   [PATCH] fuse: fix...
114
115
116
   *
   * Release a list of pages which are strung together on page.lru.  Currently
   * used by read_cache_pages() and related error recovery code.
1d7ea7324   Alexander Zarochentsev   [PATCH] fuse: fix...
117
118
119
120
121
122
123
124
   */
  void put_pages_list(struct list_head *pages)
  {
  	while (!list_empty(pages)) {
  		struct page *victim;
  
  		victim = list_entry(pages->prev, struct page, lru);
  		list_del(&victim->lru);
09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
125
  		put_page(victim);
1d7ea7324   Alexander Zarochentsev   [PATCH] fuse: fix...
126
127
128
  	}
  }
  EXPORT_SYMBOL(put_pages_list);
18022c5d8   Mel Gorman   mm: add get_kerne...
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
  /*
   * get_kernel_pages() - pin kernel pages in memory
   * @kiov:	An array of struct kvec structures
   * @nr_segs:	number of segments to pin
   * @write:	pinning for read/write, currently ignored
   * @pages:	array that receives pointers to the pages pinned.
   *		Should be at least nr_segs long.
   *
   * Returns number of pages pinned. This may be fewer than the number
   * requested. If nr_pages is 0 or negative, returns 0. If no pages
   * were pinned, returns -errno. Each page returned must be released
   * with a put_page() call when it is finished with.
   */
  int get_kernel_pages(const struct kvec *kiov, int nr_segs, int write,
  		struct page **pages)
  {
  	int seg;
  
  	for (seg = 0; seg < nr_segs; seg++) {
  		if (WARN_ON(kiov[seg].iov_len != PAGE_SIZE))
  			return seg;
5a178119b   Mel Gorman   mm: add support f...
150
  		pages[seg] = kmap_to_page(kiov[seg].iov_base);
09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
151
  		get_page(pages[seg]);
18022c5d8   Mel Gorman   mm: add get_kerne...
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
  	}
  
  	return seg;
  }
  EXPORT_SYMBOL_GPL(get_kernel_pages);
  
  /*
   * get_kernel_page() - pin a kernel page in memory
   * @start:	starting kernel address
   * @write:	pinning for read/write, currently ignored
   * @pages:	array that receives pointer to the page pinned.
   *		Must be at least nr_segs long.
   *
   * Returns 1 if page is pinned. If the page was not pinned, returns
   * -errno. The page returned must be released with a put_page() call
   * when it is finished with.
   */
  int get_kernel_page(unsigned long start, int write, struct page **pages)
  {
  	const struct kvec kiov = {
  		.iov_base = (void *)start,
  		.iov_len = PAGE_SIZE
  	};
  
  	return get_kernel_pages(&kiov, 1, write, pages);
  }
  EXPORT_SYMBOL_GPL(get_kernel_page);
3dd7ae8ec   Shaohua Li   mm: simplify code...
179
  static void pagevec_lru_move_fn(struct pagevec *pvec,
fa9add641   Hugh Dickins   mm/memcg: apply a...
180
181
  	void (*move_fn)(struct page *page, struct lruvec *lruvec, void *arg),
  	void *arg)
902aaed0d   Hisashi Hifumi   mm: use pagevec t...
182
183
  {
  	int i;
68eb0731c   Mel Gorman   mm, pagevec: rele...
184
  	struct pglist_data *pgdat = NULL;
fa9add641   Hugh Dickins   mm/memcg: apply a...
185
  	struct lruvec *lruvec;
3dd7ae8ec   Shaohua Li   mm: simplify code...
186
  	unsigned long flags = 0;
902aaed0d   Hisashi Hifumi   mm: use pagevec t...
187
188
189
  
  	for (i = 0; i < pagevec_count(pvec); i++) {
  		struct page *page = pvec->pages[i];
68eb0731c   Mel Gorman   mm, pagevec: rele...
190
  		struct pglist_data *pagepgdat = page_pgdat(page);
902aaed0d   Hisashi Hifumi   mm: use pagevec t...
191

68eb0731c   Mel Gorman   mm, pagevec: rele...
192
193
194
195
196
  		if (pagepgdat != pgdat) {
  			if (pgdat)
  				spin_unlock_irqrestore(&pgdat->lru_lock, flags);
  			pgdat = pagepgdat;
  			spin_lock_irqsave(&pgdat->lru_lock, flags);
902aaed0d   Hisashi Hifumi   mm: use pagevec t...
197
  		}
3dd7ae8ec   Shaohua Li   mm: simplify code...
198

68eb0731c   Mel Gorman   mm, pagevec: rele...
199
  		lruvec = mem_cgroup_page_lruvec(page, pgdat);
fa9add641   Hugh Dickins   mm/memcg: apply a...
200
  		(*move_fn)(page, lruvec, arg);
902aaed0d   Hisashi Hifumi   mm: use pagevec t...
201
  	}
68eb0731c   Mel Gorman   mm, pagevec: rele...
202
203
  	if (pgdat)
  		spin_unlock_irqrestore(&pgdat->lru_lock, flags);
83896fb5e   Linus Torvalds   Revert "mm: simpl...
204
205
  	release_pages(pvec->pages, pvec->nr, pvec->cold);
  	pagevec_reinit(pvec);
d8505dee1   Shaohua Li   mm: simplify code...
206
  }
fa9add641   Hugh Dickins   mm/memcg: apply a...
207
208
  static void pagevec_move_tail_fn(struct page *page, struct lruvec *lruvec,
  				 void *arg)
3dd7ae8ec   Shaohua Li   mm: simplify code...
209
210
  {
  	int *pgmoved = arg;
3dd7ae8ec   Shaohua Li   mm: simplify code...
211

c55e8d035   Johannes Weiner   mm: vmscan: move ...
212
213
214
215
  	if (PageLRU(page) && !PageUnevictable(page)) {
  		del_page_from_lru_list(page, lruvec, page_lru(page));
  		ClearPageActive(page);
  		add_page_to_lru_list_tail(page, lruvec, page_lru(page));
3dd7ae8ec   Shaohua Li   mm: simplify code...
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
  		(*pgmoved)++;
  	}
  }
  
  /*
   * pagevec_move_tail() must be called with IRQ disabled.
   * Otherwise this may cause nasty races.
   */
  static void pagevec_move_tail(struct pagevec *pvec)
  {
  	int pgmoved = 0;
  
  	pagevec_lru_move_fn(pvec, pagevec_move_tail_fn, &pgmoved);
  	__count_vm_events(PGROTATED, pgmoved);
  }
902aaed0d   Hisashi Hifumi   mm: use pagevec t...
231
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
232
233
   * Writeback is about to end against a page which has been marked for immediate
   * reclaim.  If it still appears to be reclaimable, move it to the tail of the
902aaed0d   Hisashi Hifumi   mm: use pagevec t...
234
   * inactive list.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
235
   */
3dd7ae8ec   Shaohua Li   mm: simplify code...
236
  void rotate_reclaimable_page(struct page *page)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
237
  {
c55e8d035   Johannes Weiner   mm: vmscan: move ...
238
  	if (!PageLocked(page) && !PageDirty(page) &&
894bc3104   Lee Schermerhorn   Unevictable LRU I...
239
  	    !PageUnevictable(page) && PageLRU(page)) {
ac6aadb24   Miklos Szeredi   mm: rotate_reclai...
240
241
  		struct pagevec *pvec;
  		unsigned long flags;
09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
242
  		get_page(page);
ac6aadb24   Miklos Szeredi   mm: rotate_reclai...
243
  		local_irq_save(flags);
7c8e0181e   Christoph Lameter   mm: replace __get...
244
  		pvec = this_cpu_ptr(&lru_rotate_pvecs);
8f182270d   Lukasz Odzioba   mm/swap.c: flush ...
245
  		if (!pagevec_add(pvec, page) || PageCompound(page))
ac6aadb24   Miklos Szeredi   mm: rotate_reclai...
246
247
248
  			pagevec_move_tail(pvec);
  		local_irq_restore(flags);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
249
  }
fa9add641   Hugh Dickins   mm/memcg: apply a...
250
  static void update_page_reclaim_stat(struct lruvec *lruvec,
3e2f41f1f   KOSAKI Motohiro   memcg: add zone_r...
251
252
  				     int file, int rotated)
  {
fa9add641   Hugh Dickins   mm/memcg: apply a...
253
  	struct zone_reclaim_stat *reclaim_stat = &lruvec->reclaim_stat;
3e2f41f1f   KOSAKI Motohiro   memcg: add zone_r...
254
255
256
257
  
  	reclaim_stat->recent_scanned[file]++;
  	if (rotated)
  		reclaim_stat->recent_rotated[file]++;
3e2f41f1f   KOSAKI Motohiro   memcg: add zone_r...
258
  }
fa9add641   Hugh Dickins   mm/memcg: apply a...
259
260
  static void __activate_page(struct page *page, struct lruvec *lruvec,
  			    void *arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
261
  {
744ed1442   Shaohua Li   mm: batch activat...
262
  	if (PageLRU(page) && !PageActive(page) && !PageUnevictable(page)) {
7a608572a   Linus Torvalds   Revert "mm: batch...
263
264
  		int file = page_is_file_cache(page);
  		int lru = page_lru_base_type(page);
744ed1442   Shaohua Li   mm: batch activat...
265

fa9add641   Hugh Dickins   mm/memcg: apply a...
266
  		del_page_from_lru_list(page, lruvec, lru);
7a608572a   Linus Torvalds   Revert "mm: batch...
267
268
  		SetPageActive(page);
  		lru += LRU_ACTIVE;
fa9add641   Hugh Dickins   mm/memcg: apply a...
269
  		add_page_to_lru_list(page, lruvec, lru);
24b7e5819   Mel Gorman   mm: pagemap: avoi...
270
  		trace_mm_lru_activate(page);
4f98a2fee   Rik van Riel   vmscan: split LRU...
271

fa9add641   Hugh Dickins   mm/memcg: apply a...
272
273
  		__count_vm_event(PGACTIVATE);
  		update_page_reclaim_stat(lruvec, file, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
274
  	}
eb709b0d0   Shaohua Li   mm: batch activat...
275
276
277
  }
  
  #ifdef CONFIG_SMP
eb709b0d0   Shaohua Li   mm: batch activat...
278
279
280
281
282
283
284
  static void activate_page_drain(int cpu)
  {
  	struct pagevec *pvec = &per_cpu(activate_page_pvecs, cpu);
  
  	if (pagevec_count(pvec))
  		pagevec_lru_move_fn(pvec, __activate_page, NULL);
  }
5fbc46163   Chris Metcalf   mm: make lru_add_...
285
286
287
288
  static bool need_activate_page_drain(int cpu)
  {
  	return pagevec_count(&per_cpu(activate_page_pvecs, cpu)) != 0;
  }
eb709b0d0   Shaohua Li   mm: batch activat...
289
290
  void activate_page(struct page *page)
  {
800d8c63b   Kirill A. Shutemov   shmem: add huge p...
291
  	page = compound_head(page);
eb709b0d0   Shaohua Li   mm: batch activat...
292
293
  	if (PageLRU(page) && !PageActive(page) && !PageUnevictable(page)) {
  		struct pagevec *pvec = &get_cpu_var(activate_page_pvecs);
09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
294
  		get_page(page);
8f182270d   Lukasz Odzioba   mm/swap.c: flush ...
295
  		if (!pagevec_add(pvec, page) || PageCompound(page))
eb709b0d0   Shaohua Li   mm: batch activat...
296
297
298
299
300
301
302
303
304
  			pagevec_lru_move_fn(pvec, __activate_page, NULL);
  		put_cpu_var(activate_page_pvecs);
  	}
  }
  
  #else
  static inline void activate_page_drain(int cpu)
  {
  }
5fbc46163   Chris Metcalf   mm: make lru_add_...
305
306
307
308
  static bool need_activate_page_drain(int cpu)
  {
  	return false;
  }
eb709b0d0   Shaohua Li   mm: batch activat...
309
310
311
  void activate_page(struct page *page)
  {
  	struct zone *zone = page_zone(page);
800d8c63b   Kirill A. Shutemov   shmem: add huge p...
312
  	page = compound_head(page);
a52633d8e   Mel Gorman   mm, vmscan: move ...
313
  	spin_lock_irq(zone_lru_lock(zone));
599d0c954   Mel Gorman   mm, vmscan: move ...
314
  	__activate_page(page, mem_cgroup_page_lruvec(page, zone->zone_pgdat), NULL);
a52633d8e   Mel Gorman   mm, vmscan: move ...
315
  	spin_unlock_irq(zone_lru_lock(zone));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
316
  }
eb709b0d0   Shaohua Li   mm: batch activat...
317
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
318

059285a25   Mel Gorman   mm: activate !Pag...
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
  static void __lru_cache_activate_page(struct page *page)
  {
  	struct pagevec *pvec = &get_cpu_var(lru_add_pvec);
  	int i;
  
  	/*
  	 * Search backwards on the optimistic assumption that the page being
  	 * activated has just been added to this pagevec. Note that only
  	 * the local pagevec is examined as a !PageLRU page could be in the
  	 * process of being released, reclaimed, migrated or on a remote
  	 * pagevec that is currently being drained. Furthermore, marking
  	 * a remote pagevec's page PageActive potentially hits a race where
  	 * a page is marked PageActive just after it is added to the inactive
  	 * list causing accounting errors and BUG_ON checks to trigger.
  	 */
  	for (i = pagevec_count(pvec) - 1; i >= 0; i--) {
  		struct page *pagevec_page = pvec->pages[i];
  
  		if (pagevec_page == page) {
  			SetPageActive(page);
  			break;
  		}
  	}
  
  	put_cpu_var(lru_add_pvec);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
345
346
347
348
349
350
  /*
   * Mark a page as having seen activity.
   *
   * inactive,unreferenced	->	inactive,referenced
   * inactive,referenced		->	active,unreferenced
   * active,unreferenced		->	active,referenced
eb39d618f   Hugh Dickins   mm: replace init_...
351
352
353
   *
   * When a newly allocated page is not yet visible, so safe for non-atomic ops,
   * __SetPageReferenced(page) may be substituted for mark_page_accessed(page).
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
354
   */
920c7a5d0   Harvey Harrison   mm: remove fastca...
355
  void mark_page_accessed(struct page *page)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
356
  {
e90309c9f   Kirill A. Shutemov   thp: allow mlocke...
357
  	page = compound_head(page);
894bc3104   Lee Schermerhorn   Unevictable LRU I...
358
  	if (!PageActive(page) && !PageUnevictable(page) &&
059285a25   Mel Gorman   mm: activate !Pag...
359
360
361
362
363
364
365
366
367
368
369
370
  			PageReferenced(page)) {
  
  		/*
  		 * If the page is on the LRU, queue it for activation via
  		 * activate_page_pvecs. Otherwise, assume the page is on a
  		 * pagevec, mark it active and it'll be moved to the active
  		 * LRU on the next drain.
  		 */
  		if (PageLRU(page))
  			activate_page(page);
  		else
  			__lru_cache_activate_page(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
371
  		ClearPageReferenced(page);
a528910e1   Johannes Weiner   mm: thrash detect...
372
373
  		if (page_is_file_cache(page))
  			workingset_activation(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
374
375
376
  	} else if (!PageReferenced(page)) {
  		SetPageReferenced(page);
  	}
33c3fc71c   Vladimir Davydov   mm: introduce idl...
377
378
  	if (page_is_idle(page))
  		clear_page_idle(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
379
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
380
  EXPORT_SYMBOL(mark_page_accessed);
2329d3751   Jianyu Zhan   mm/swap.c: clean ...
381
  static void __lru_cache_add(struct page *page)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
382
  {
13f7f7898   Mel Gorman   mm: pagevec: defe...
383
  	struct pagevec *pvec = &get_cpu_var(lru_add_pvec);
09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
384
  	get_page(page);
8f182270d   Lukasz Odzioba   mm/swap.c: flush ...
385
  	if (!pagevec_add(pvec, page) || PageCompound(page))
a0b8cab3b   Mel Gorman   mm: remove lru pa...
386
  		__pagevec_lru_add(pvec);
13f7f7898   Mel Gorman   mm: pagevec: defe...
387
  	put_cpu_var(lru_add_pvec);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
388
  }
2329d3751   Jianyu Zhan   mm/swap.c: clean ...
389
390
391
392
393
394
395
  
  /**
   * lru_cache_add: add a page to the page lists
   * @page: the page to add
   */
  void lru_cache_add_anon(struct page *page)
  {
6fb81a17d   Mel Gorman   mm: do not use un...
396
397
  	if (PageActive(page))
  		ClearPageActive(page);
2329d3751   Jianyu Zhan   mm/swap.c: clean ...
398
399
400
401
402
  	__lru_cache_add(page);
  }
  
  void lru_cache_add_file(struct page *page)
  {
6fb81a17d   Mel Gorman   mm: do not use un...
403
404
  	if (PageActive(page))
  		ClearPageActive(page);
2329d3751   Jianyu Zhan   mm/swap.c: clean ...
405
406
407
  	__lru_cache_add(page);
  }
  EXPORT_SYMBOL(lru_cache_add_file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
408

f04e9ebbe   KOSAKI Motohiro   swap: use an arra...
409
  /**
c53954a09   Mel Gorman   mm: remove lru pa...
410
   * lru_cache_add - add a page to a page list
f04e9ebbe   KOSAKI Motohiro   swap: use an arra...
411
   * @page: the page to be added to the LRU.
2329d3751   Jianyu Zhan   mm/swap.c: clean ...
412
413
414
415
416
   *
   * Queue the page for addition to the LRU via pagevec. The decision on whether
   * to add the page to the [in]active [file|anon] list is deferred until the
   * pagevec is drained. This gives a chance for the caller of lru_cache_add()
   * have the page added to the active list using mark_page_accessed().
f04e9ebbe   KOSAKI Motohiro   swap: use an arra...
417
   */
c53954a09   Mel Gorman   mm: remove lru pa...
418
  void lru_cache_add(struct page *page)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
419
  {
309381fea   Sasha Levin   mm: dump page whe...
420
421
  	VM_BUG_ON_PAGE(PageActive(page) && PageUnevictable(page), page);
  	VM_BUG_ON_PAGE(PageLRU(page), page);
c53954a09   Mel Gorman   mm: remove lru pa...
422
  	__lru_cache_add(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
423
  }
894bc3104   Lee Schermerhorn   Unevictable LRU I...
424
425
426
427
428
429
430
431
432
433
434
435
  /**
   * add_page_to_unevictable_list - add a page to the unevictable list
   * @page:  the page to be added to the unevictable list
   *
   * Add page directly to its zone's unevictable list.  To avoid races with
   * tasks that might be making the page evictable, through eg. munlock,
   * munmap or exit, while it's not on the lru, we want to add the page
   * while it's locked or otherwise "invisible" to other tasks.  This is
   * difficult to do when using the pagevec cache, so bypass that.
   */
  void add_page_to_unevictable_list(struct page *page)
  {
599d0c954   Mel Gorman   mm, vmscan: move ...
436
  	struct pglist_data *pgdat = page_pgdat(page);
fa9add641   Hugh Dickins   mm/memcg: apply a...
437
  	struct lruvec *lruvec;
894bc3104   Lee Schermerhorn   Unevictable LRU I...
438

599d0c954   Mel Gorman   mm, vmscan: move ...
439
440
  	spin_lock_irq(&pgdat->lru_lock);
  	lruvec = mem_cgroup_page_lruvec(page, pgdat);
ef2a2cbdd   Naoya Horiguchi   mm/swap.c: clear ...
441
  	ClearPageActive(page);
894bc3104   Lee Schermerhorn   Unevictable LRU I...
442
443
  	SetPageUnevictable(page);
  	SetPageLRU(page);
fa9add641   Hugh Dickins   mm/memcg: apply a...
444
  	add_page_to_lru_list(page, lruvec, LRU_UNEVICTABLE);
599d0c954   Mel Gorman   mm, vmscan: move ...
445
  	spin_unlock_irq(&pgdat->lru_lock);
894bc3104   Lee Schermerhorn   Unevictable LRU I...
446
  }
00501b531   Johannes Weiner   mm: memcontrol: r...
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
  /**
   * lru_cache_add_active_or_unevictable
   * @page:  the page to be added to LRU
   * @vma:   vma in which page is mapped for determining reclaimability
   *
   * Place @page on the active or unevictable LRU list, depending on its
   * evictability.  Note that if the page is not evictable, it goes
   * directly back onto it's zone's unevictable list, it does NOT use a
   * per cpu pagevec.
   */
  void lru_cache_add_active_or_unevictable(struct page *page,
  					 struct vm_area_struct *vma)
  {
  	VM_BUG_ON_PAGE(PageLRU(page), page);
  
  	if (likely((vma->vm_flags & (VM_LOCKED | VM_SPECIAL)) != VM_LOCKED)) {
  		SetPageActive(page);
  		lru_cache_add(page);
  		return;
  	}
  
  	if (!TestSetPageMlocked(page)) {
  		/*
  		 * We use the irq-unsafe __mod_zone_page_stat because this
  		 * counter is not modified from interrupt context, and the pte
  		 * lock is held(spinlock), which implies preemption disabled.
  		 */
  		__mod_zone_page_state(page_zone(page), NR_MLOCK,
  				    hpage_nr_pages(page));
  		count_vm_event(UNEVICTABLE_PGMLOCKED);
  	}
  	add_page_to_unevictable_list(page);
  }
902aaed0d   Hisashi Hifumi   mm: use pagevec t...
480
  /*
315601809   Minchan Kim   mm: deactivate in...
481
482
483
484
485
   * If the page can not be invalidated, it is moved to the
   * inactive list to speed up its reclaim.  It is moved to the
   * head of the list, rather than the tail, to give the flusher
   * threads some time to write it out, as this is much more
   * effective than the single-page writeout from reclaim.
278df9f45   Minchan Kim   mm: reclaim inval...
486
487
488
489
490
491
492
493
494
495
496
497
498
499
   *
   * If the page isn't page_mapped and dirty/writeback, the page
   * could reclaim asap using PG_reclaim.
   *
   * 1. active, mapped page -> none
   * 2. active, dirty/writeback page -> inactive, head, PG_reclaim
   * 3. inactive, mapped page -> none
   * 4. inactive, dirty/writeback page -> inactive, head, PG_reclaim
   * 5. inactive, clean -> inactive, tail
   * 6. Others -> none
   *
   * In 4, why it moves inactive's head, the VM expects the page would
   * be write it out by flusher threads as this is much more effective
   * than the single-page writeout from reclaim.
315601809   Minchan Kim   mm: deactivate in...
500
   */
cc5993bd7   Minchan Kim   mm: rename deacti...
501
  static void lru_deactivate_file_fn(struct page *page, struct lruvec *lruvec,
fa9add641   Hugh Dickins   mm/memcg: apply a...
502
  			      void *arg)
315601809   Minchan Kim   mm: deactivate in...
503
504
  {
  	int lru, file;
278df9f45   Minchan Kim   mm: reclaim inval...
505
  	bool active;
315601809   Minchan Kim   mm: deactivate in...
506

278df9f45   Minchan Kim   mm: reclaim inval...
507
  	if (!PageLRU(page))
315601809   Minchan Kim   mm: deactivate in...
508
  		return;
bad49d9c8   Minchan Kim   mm: check PageUne...
509
510
  	if (PageUnevictable(page))
  		return;
315601809   Minchan Kim   mm: deactivate in...
511
512
513
  	/* Some processes are using the page */
  	if (page_mapped(page))
  		return;
278df9f45   Minchan Kim   mm: reclaim inval...
514
  	active = PageActive(page);
315601809   Minchan Kim   mm: deactivate in...
515
516
  	file = page_is_file_cache(page);
  	lru = page_lru_base_type(page);
fa9add641   Hugh Dickins   mm/memcg: apply a...
517
518
  
  	del_page_from_lru_list(page, lruvec, lru + active);
315601809   Minchan Kim   mm: deactivate in...
519
520
  	ClearPageActive(page);
  	ClearPageReferenced(page);
fa9add641   Hugh Dickins   mm/memcg: apply a...
521
  	add_page_to_lru_list(page, lruvec, lru);
315601809   Minchan Kim   mm: deactivate in...
522

278df9f45   Minchan Kim   mm: reclaim inval...
523
524
525
526
527
528
529
530
531
532
533
534
  	if (PageWriteback(page) || PageDirty(page)) {
  		/*
  		 * PG_reclaim could be raced with end_page_writeback
  		 * It can make readahead confusing.  But race window
  		 * is _really_ small and  it's non-critical problem.
  		 */
  		SetPageReclaim(page);
  	} else {
  		/*
  		 * The page's writeback ends up during pagevec
  		 * We moves tha page into tail of inactive.
  		 */
925b7673c   Johannes Weiner   mm: make per-memc...
535
  		list_move_tail(&page->lru, &lruvec->lists[lru]);
278df9f45   Minchan Kim   mm: reclaim inval...
536
537
538
539
540
  		__count_vm_event(PGROTATED);
  	}
  
  	if (active)
  		__count_vm_event(PGDEACTIVATE);
fa9add641   Hugh Dickins   mm/memcg: apply a...
541
  	update_page_reclaim_stat(lruvec, file, 0);
315601809   Minchan Kim   mm: deactivate in...
542
  }
10853a039   Minchan Kim   mm: move lazily f...
543

f7ad2a6cb   Shaohua Li   mm: move MADV_FRE...
544
  static void lru_lazyfree_fn(struct page *page, struct lruvec *lruvec,
10853a039   Minchan Kim   mm: move lazily f...
545
546
  			    void *arg)
  {
f7ad2a6cb   Shaohua Li   mm: move MADV_FRE...
547
  	if (PageLRU(page) && PageAnon(page) && PageSwapBacked(page) &&
24c92eb7d   Shaohua Li   mm: avoid marking...
548
  	    !PageSwapCache(page) && !PageUnevictable(page)) {
f7ad2a6cb   Shaohua Li   mm: move MADV_FRE...
549
  		bool active = PageActive(page);
10853a039   Minchan Kim   mm: move lazily f...
550

f7ad2a6cb   Shaohua Li   mm: move MADV_FRE...
551
552
  		del_page_from_lru_list(page, lruvec,
  				       LRU_INACTIVE_ANON + active);
10853a039   Minchan Kim   mm: move lazily f...
553
554
  		ClearPageActive(page);
  		ClearPageReferenced(page);
f7ad2a6cb   Shaohua Li   mm: move MADV_FRE...
555
556
557
558
559
560
561
  		/*
  		 * lazyfree pages are clean anonymous pages. They have
  		 * SwapBacked flag cleared to distinguish normal anonymous
  		 * pages
  		 */
  		ClearPageSwapBacked(page);
  		add_page_to_lru_list(page, lruvec, LRU_INACTIVE_FILE);
10853a039   Minchan Kim   mm: move lazily f...
562

f7ad2a6cb   Shaohua Li   mm: move MADV_FRE...
563
  		__count_vm_events(PGLAZYFREE, hpage_nr_pages(page));
2262185c5   Roman Gushchin   mm: per-cgroup me...
564
  		count_memcg_page_event(page, PGLAZYFREE);
f7ad2a6cb   Shaohua Li   mm: move MADV_FRE...
565
  		update_page_reclaim_stat(lruvec, 1, 0);
10853a039   Minchan Kim   mm: move lazily f...
566
567
  	}
  }
315601809   Minchan Kim   mm: deactivate in...
568
  /*
902aaed0d   Hisashi Hifumi   mm: use pagevec t...
569
570
571
572
   * Drain pages out of the cpu's pagevecs.
   * Either "cpu" is the current CPU, and preemption has already been
   * disabled; or "cpu" is being hot-unplugged, and is already dead.
   */
f0cb3c76a   Konstantin Khlebnikov   mm: drain percpu ...
573
  void lru_add_drain_cpu(int cpu)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
574
  {
13f7f7898   Mel Gorman   mm: pagevec: defe...
575
  	struct pagevec *pvec = &per_cpu(lru_add_pvec, cpu);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
576

13f7f7898   Mel Gorman   mm: pagevec: defe...
577
  	if (pagevec_count(pvec))
a0b8cab3b   Mel Gorman   mm: remove lru pa...
578
  		__pagevec_lru_add(pvec);
902aaed0d   Hisashi Hifumi   mm: use pagevec t...
579
580
581
582
583
584
585
586
587
588
  
  	pvec = &per_cpu(lru_rotate_pvecs, cpu);
  	if (pagevec_count(pvec)) {
  		unsigned long flags;
  
  		/* No harm done if a racing interrupt already did this */
  		local_irq_save(flags);
  		pagevec_move_tail(pvec);
  		local_irq_restore(flags);
  	}
315601809   Minchan Kim   mm: deactivate in...
589

cc5993bd7   Minchan Kim   mm: rename deacti...
590
  	pvec = &per_cpu(lru_deactivate_file_pvecs, cpu);
315601809   Minchan Kim   mm: deactivate in...
591
  	if (pagevec_count(pvec))
cc5993bd7   Minchan Kim   mm: rename deacti...
592
  		pagevec_lru_move_fn(pvec, lru_deactivate_file_fn, NULL);
eb709b0d0   Shaohua Li   mm: batch activat...
593

f7ad2a6cb   Shaohua Li   mm: move MADV_FRE...
594
  	pvec = &per_cpu(lru_lazyfree_pvecs, cpu);
10853a039   Minchan Kim   mm: move lazily f...
595
  	if (pagevec_count(pvec))
f7ad2a6cb   Shaohua Li   mm: move MADV_FRE...
596
  		pagevec_lru_move_fn(pvec, lru_lazyfree_fn, NULL);
10853a039   Minchan Kim   mm: move lazily f...
597

eb709b0d0   Shaohua Li   mm: batch activat...
598
  	activate_page_drain(cpu);
315601809   Minchan Kim   mm: deactivate in...
599
600
601
  }
  
  /**
cc5993bd7   Minchan Kim   mm: rename deacti...
602
   * deactivate_file_page - forcefully deactivate a file page
315601809   Minchan Kim   mm: deactivate in...
603
604
605
606
607
608
   * @page: page to deactivate
   *
   * This function hints the VM that @page is a good reclaim candidate,
   * for example if its invalidation fails due to the page being dirty
   * or under writeback.
   */
cc5993bd7   Minchan Kim   mm: rename deacti...
609
  void deactivate_file_page(struct page *page)
315601809   Minchan Kim   mm: deactivate in...
610
  {
821ed6bbe   Minchan Kim   mm: filter unevic...
611
  	/*
cc5993bd7   Minchan Kim   mm: rename deacti...
612
613
  	 * In a workload with many unevictable page such as mprotect,
  	 * unevictable page deactivation for accelerating reclaim is pointless.
821ed6bbe   Minchan Kim   mm: filter unevic...
614
615
616
  	 */
  	if (PageUnevictable(page))
  		return;
315601809   Minchan Kim   mm: deactivate in...
617
  	if (likely(get_page_unless_zero(page))) {
cc5993bd7   Minchan Kim   mm: rename deacti...
618
  		struct pagevec *pvec = &get_cpu_var(lru_deactivate_file_pvecs);
315601809   Minchan Kim   mm: deactivate in...
619

8f182270d   Lukasz Odzioba   mm/swap.c: flush ...
620
  		if (!pagevec_add(pvec, page) || PageCompound(page))
cc5993bd7   Minchan Kim   mm: rename deacti...
621
622
  			pagevec_lru_move_fn(pvec, lru_deactivate_file_fn, NULL);
  		put_cpu_var(lru_deactivate_file_pvecs);
315601809   Minchan Kim   mm: deactivate in...
623
  	}
80bfed904   Andrew Morton   [PATCH] consolida...
624
  }
10853a039   Minchan Kim   mm: move lazily f...
625
  /**
f7ad2a6cb   Shaohua Li   mm: move MADV_FRE...
626
   * mark_page_lazyfree - make an anon page lazyfree
10853a039   Minchan Kim   mm: move lazily f...
627
628
   * @page: page to deactivate
   *
f7ad2a6cb   Shaohua Li   mm: move MADV_FRE...
629
630
   * mark_page_lazyfree() moves @page to the inactive file list.
   * This is done to accelerate the reclaim of @page.
10853a039   Minchan Kim   mm: move lazily f...
631
   */
f7ad2a6cb   Shaohua Li   mm: move MADV_FRE...
632
  void mark_page_lazyfree(struct page *page)
10853a039   Minchan Kim   mm: move lazily f...
633
  {
f7ad2a6cb   Shaohua Li   mm: move MADV_FRE...
634
  	if (PageLRU(page) && PageAnon(page) && PageSwapBacked(page) &&
24c92eb7d   Shaohua Li   mm: avoid marking...
635
  	    !PageSwapCache(page) && !PageUnevictable(page)) {
f7ad2a6cb   Shaohua Li   mm: move MADV_FRE...
636
  		struct pagevec *pvec = &get_cpu_var(lru_lazyfree_pvecs);
10853a039   Minchan Kim   mm: move lazily f...
637

09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
638
  		get_page(page);
8f182270d   Lukasz Odzioba   mm/swap.c: flush ...
639
  		if (!pagevec_add(pvec, page) || PageCompound(page))
f7ad2a6cb   Shaohua Li   mm: move MADV_FRE...
640
641
  			pagevec_lru_move_fn(pvec, lru_lazyfree_fn, NULL);
  		put_cpu_var(lru_lazyfree_pvecs);
10853a039   Minchan Kim   mm: move lazily f...
642
643
  	}
  }
80bfed904   Andrew Morton   [PATCH] consolida...
644
645
  void lru_add_drain(void)
  {
f0cb3c76a   Konstantin Khlebnikov   mm: drain percpu ...
646
  	lru_add_drain_cpu(get_cpu());
80bfed904   Andrew Morton   [PATCH] consolida...
647
  	put_cpu();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
648
  }
c4028958b   David Howells   WorkStruct: make ...
649
  static void lru_add_drain_per_cpu(struct work_struct *dummy)
053837fce   Nick Piggin   [PATCH] mm: migra...
650
651
652
  {
  	lru_add_drain();
  }
5fbc46163   Chris Metcalf   mm: make lru_add_...
653
  static DEFINE_PER_CPU(struct work_struct, lru_add_drain_work);
a47fed5b5   Thomas Gleixner   mm: swap: provide...
654
  void lru_add_drain_all_cpuslocked(void)
053837fce   Nick Piggin   [PATCH] mm: migra...
655
  {
5fbc46163   Chris Metcalf   mm: make lru_add_...
656
657
658
  	static DEFINE_MUTEX(lock);
  	static struct cpumask has_work;
  	int cpu;
ce612879d   Michal Hocko   mm: move pcp and ...
659
660
661
662
663
664
  	/*
  	 * Make sure nobody triggers this path before mm_percpu_wq is fully
  	 * initialized.
  	 */
  	if (WARN_ON(!mm_percpu_wq))
  		return;
5fbc46163   Chris Metcalf   mm: make lru_add_...
665
  	mutex_lock(&lock);
5fbc46163   Chris Metcalf   mm: make lru_add_...
666
667
668
669
670
671
672
  	cpumask_clear(&has_work);
  
  	for_each_online_cpu(cpu) {
  		struct work_struct *work = &per_cpu(lru_add_drain_work, cpu);
  
  		if (pagevec_count(&per_cpu(lru_add_pvec, cpu)) ||
  		    pagevec_count(&per_cpu(lru_rotate_pvecs, cpu)) ||
cc5993bd7   Minchan Kim   mm: rename deacti...
673
  		    pagevec_count(&per_cpu(lru_deactivate_file_pvecs, cpu)) ||
f7ad2a6cb   Shaohua Li   mm: move MADV_FRE...
674
  		    pagevec_count(&per_cpu(lru_lazyfree_pvecs, cpu)) ||
5fbc46163   Chris Metcalf   mm: make lru_add_...
675
676
  		    need_activate_page_drain(cpu)) {
  			INIT_WORK(work, lru_add_drain_per_cpu);
ce612879d   Michal Hocko   mm: move pcp and ...
677
  			queue_work_on(cpu, mm_percpu_wq, work);
5fbc46163   Chris Metcalf   mm: make lru_add_...
678
679
680
681
682
683
  			cpumask_set_cpu(cpu, &has_work);
  		}
  	}
  
  	for_each_cpu(cpu, &has_work)
  		flush_work(&per_cpu(lru_add_drain_work, cpu));
5fbc46163   Chris Metcalf   mm: make lru_add_...
684
  	mutex_unlock(&lock);
053837fce   Nick Piggin   [PATCH] mm: migra...
685
  }
a47fed5b5   Thomas Gleixner   mm: swap: provide...
686
687
688
689
690
691
  void lru_add_drain_all(void)
  {
  	get_online_cpus();
  	lru_add_drain_all_cpuslocked();
  	put_online_cpus();
  }
aabfb5729   Michal Hocko   mm: memcontrol: d...
692
  /**
ea1754a08   Kirill A. Shutemov   mm, fs: remove re...
693
   * release_pages - batched put_page()
aabfb5729   Michal Hocko   mm: memcontrol: d...
694
695
696
   * @pages: array of pages to release
   * @nr: number of pages
   * @cold: whether the pages are cache cold
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
697
   *
aabfb5729   Michal Hocko   mm: memcontrol: d...
698
699
   * Decrement the reference count on all the pages in @pages.  If it
   * fell to zero, remove the page from the LRU and free it.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
700
   */
b745bc85f   Mel Gorman   mm: page_alloc: c...
701
  void release_pages(struct page **pages, int nr, bool cold)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
702
703
  {
  	int i;
cc59850ef   Konstantin Khlebnikov   mm: add free_hot_...
704
  	LIST_HEAD(pages_to_free);
599d0c954   Mel Gorman   mm, vmscan: move ...
705
  	struct pglist_data *locked_pgdat = NULL;
fa9add641   Hugh Dickins   mm/memcg: apply a...
706
  	struct lruvec *lruvec;
902aaed0d   Hisashi Hifumi   mm: use pagevec t...
707
  	unsigned long uninitialized_var(flags);
aabfb5729   Michal Hocko   mm: memcontrol: d...
708
  	unsigned int uninitialized_var(lock_batch);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
709

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
710
711
  	for (i = 0; i < nr; i++) {
  		struct page *page = pages[i];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
712

aabfb5729   Michal Hocko   mm: memcontrol: d...
713
714
715
  		/*
  		 * Make sure the IRQ-safe lock-holding time does not get
  		 * excessive with a continuous string of pages from the
599d0c954   Mel Gorman   mm, vmscan: move ...
716
  		 * same pgdat. The lock is held only if pgdat != NULL.
aabfb5729   Michal Hocko   mm: memcontrol: d...
717
  		 */
599d0c954   Mel Gorman   mm, vmscan: move ...
718
719
720
  		if (locked_pgdat && ++lock_batch == SWAP_CLUSTER_MAX) {
  			spin_unlock_irqrestore(&locked_pgdat->lru_lock, flags);
  			locked_pgdat = NULL;
aabfb5729   Michal Hocko   mm: memcontrol: d...
721
  		}
6fcb52a56   Aaron Lu   thp: reduce usage...
722
  		if (is_huge_zero_page(page))
aa88b68c3   Kirill A. Shutemov   thp: keep huge ze...
723
  			continue;
aa88b68c3   Kirill A. Shutemov   thp: keep huge ze...
724

df6ad6983   Jérôme Glisse   mm/device-public-...
725
726
727
728
729
730
731
732
733
734
  		/* Device public page can not be huge page */
  		if (is_device_public_page(page)) {
  			if (locked_pgdat) {
  				spin_unlock_irqrestore(&locked_pgdat->lru_lock,
  						       flags);
  				locked_pgdat = NULL;
  			}
  			put_zone_device_private_or_public_page(page);
  			continue;
  		}
ddc58f27f   Kirill A. Shutemov   mm: drop tail pag...
735
  		page = compound_head(page);
b5810039a   Nick Piggin   [PATCH] core remo...
736
  		if (!put_page_testzero(page))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
737
  			continue;
ddc58f27f   Kirill A. Shutemov   mm: drop tail pag...
738
  		if (PageCompound(page)) {
599d0c954   Mel Gorman   mm, vmscan: move ...
739
740
741
  			if (locked_pgdat) {
  				spin_unlock_irqrestore(&locked_pgdat->lru_lock, flags);
  				locked_pgdat = NULL;
ddc58f27f   Kirill A. Shutemov   mm: drop tail pag...
742
743
744
745
  			}
  			__put_compound_page(page);
  			continue;
  		}
46453a6e1   Nick Piggin   [PATCH] mm: never...
746
  		if (PageLRU(page)) {
599d0c954   Mel Gorman   mm, vmscan: move ...
747
  			struct pglist_data *pgdat = page_pgdat(page);
894bc3104   Lee Schermerhorn   Unevictable LRU I...
748

599d0c954   Mel Gorman   mm, vmscan: move ...
749
750
751
  			if (pgdat != locked_pgdat) {
  				if (locked_pgdat)
  					spin_unlock_irqrestore(&locked_pgdat->lru_lock,
902aaed0d   Hisashi Hifumi   mm: use pagevec t...
752
  									flags);
aabfb5729   Michal Hocko   mm: memcontrol: d...
753
  				lock_batch = 0;
599d0c954   Mel Gorman   mm, vmscan: move ...
754
755
  				locked_pgdat = pgdat;
  				spin_lock_irqsave(&locked_pgdat->lru_lock, flags);
46453a6e1   Nick Piggin   [PATCH] mm: never...
756
  			}
fa9add641   Hugh Dickins   mm/memcg: apply a...
757

599d0c954   Mel Gorman   mm, vmscan: move ...
758
  			lruvec = mem_cgroup_page_lruvec(page, locked_pgdat);
309381fea   Sasha Levin   mm: dump page whe...
759
  			VM_BUG_ON_PAGE(!PageLRU(page), page);
674539115   Nick Piggin   [PATCH] mm: less ...
760
  			__ClearPageLRU(page);
fa9add641   Hugh Dickins   mm/memcg: apply a...
761
  			del_page_from_lru_list(page, lruvec, page_off_lru(page));
46453a6e1   Nick Piggin   [PATCH] mm: never...
762
  		}
c53954a09   Mel Gorman   mm: remove lru pa...
763
  		/* Clear Active bit in case of parallel mark_page_accessed */
e3741b506   Mel Gorman   mm: do not use at...
764
  		__ClearPageActive(page);
629060270   Nicholas Piggin   mm: add PageWaite...
765
  		__ClearPageWaiters(page);
c53954a09   Mel Gorman   mm: remove lru pa...
766

cc59850ef   Konstantin Khlebnikov   mm: add free_hot_...
767
  		list_add(&page->lru, &pages_to_free);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
768
  	}
599d0c954   Mel Gorman   mm, vmscan: move ...
769
770
  	if (locked_pgdat)
  		spin_unlock_irqrestore(&locked_pgdat->lru_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
771

747db954c   Johannes Weiner   mm: memcontrol: u...
772
  	mem_cgroup_uncharge_list(&pages_to_free);
cc59850ef   Konstantin Khlebnikov   mm: add free_hot_...
773
  	free_hot_cold_page_list(&pages_to_free, cold);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
774
  }
0be8557bc   Miklos Szeredi   fuse: use release...
775
  EXPORT_SYMBOL(release_pages);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
  
  /*
   * The pages which we're about to release may be in the deferred lru-addition
   * queues.  That would prevent them from really being freed right now.  That's
   * OK from a correctness point of view but is inefficient - those pages may be
   * cache-warm and we want to give them back to the page allocator ASAP.
   *
   * So __pagevec_release() will drain those queues here.  __pagevec_lru_add()
   * and __pagevec_lru_add_active() call release_pages() directly to avoid
   * mutual recursion.
   */
  void __pagevec_release(struct pagevec *pvec)
  {
  	lru_add_drain();
  	release_pages(pvec->pages, pagevec_count(pvec), pvec->cold);
  	pagevec_reinit(pvec);
  }
7f2857018   Steve French   Export __pagevec_...
793
  EXPORT_SYMBOL(__pagevec_release);
12d271078   Hugh Dickins   memcg: fix split_...
794
  #ifdef CONFIG_TRANSPARENT_HUGEPAGE
71e3aac07   Andrea Arcangeli   thp: transparent ...
795
  /* used by __split_huge_page_refcount() */
fa9add641   Hugh Dickins   mm/memcg: apply a...
796
  void lru_add_page_tail(struct page *page, struct page *page_tail,
5bc7b8aca   Shaohua Li   mm: thp: add spli...
797
  		       struct lruvec *lruvec, struct list_head *list)
71e3aac07   Andrea Arcangeli   thp: transparent ...
798
  {
71e3aac07   Andrea Arcangeli   thp: transparent ...
799
  	const int file = 0;
71e3aac07   Andrea Arcangeli   thp: transparent ...
800

309381fea   Sasha Levin   mm: dump page whe...
801
802
803
  	VM_BUG_ON_PAGE(!PageHead(page), page);
  	VM_BUG_ON_PAGE(PageCompound(page_tail), page);
  	VM_BUG_ON_PAGE(PageLRU(page_tail), page);
fa9add641   Hugh Dickins   mm/memcg: apply a...
804
  	VM_BUG_ON(NR_CPUS != 1 &&
599d0c954   Mel Gorman   mm, vmscan: move ...
805
  		  !spin_is_locked(&lruvec_pgdat(lruvec)->lru_lock));
71e3aac07   Andrea Arcangeli   thp: transparent ...
806

5bc7b8aca   Shaohua Li   mm: thp: add spli...
807
808
  	if (!list)
  		SetPageLRU(page_tail);
71e3aac07   Andrea Arcangeli   thp: transparent ...
809

12d271078   Hugh Dickins   memcg: fix split_...
810
811
  	if (likely(PageLRU(page)))
  		list_add_tail(&page_tail->lru, &page->lru);
5bc7b8aca   Shaohua Li   mm: thp: add spli...
812
813
814
815
816
  	else if (list) {
  		/* page reclaim is reclaiming a huge page */
  		get_page(page_tail);
  		list_add_tail(&page_tail->lru, list);
  	} else {
12d271078   Hugh Dickins   memcg: fix split_...
817
818
819
820
821
822
823
824
  		struct list_head *list_head;
  		/*
  		 * Head page has not yet been counted, as an hpage,
  		 * so we must account for each subpage individually.
  		 *
  		 * Use the standard add function to put page_tail on the list,
  		 * but then correct its position so they all end up in order.
  		 */
e180cf806   Kirill A. Shutemov   thp, mm: avoid Pa...
825
  		add_page_to_lru_list(page_tail, lruvec, page_lru(page_tail));
12d271078   Hugh Dickins   memcg: fix split_...
826
827
  		list_head = page_tail->lru.prev;
  		list_move_tail(&page_tail->lru, list_head);
71e3aac07   Andrea Arcangeli   thp: transparent ...
828
  	}
7512102cf   Hugh Dickins   memcg: fix GPF wh...
829
830
  
  	if (!PageUnevictable(page))
e180cf806   Kirill A. Shutemov   thp, mm: avoid Pa...
831
  		update_page_reclaim_stat(lruvec, file, PageActive(page_tail));
71e3aac07   Andrea Arcangeli   thp: transparent ...
832
  }
12d271078   Hugh Dickins   memcg: fix split_...
833
  #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
71e3aac07   Andrea Arcangeli   thp: transparent ...
834

fa9add641   Hugh Dickins   mm/memcg: apply a...
835
836
  static void __pagevec_lru_add_fn(struct page *page, struct lruvec *lruvec,
  				 void *arg)
3dd7ae8ec   Shaohua Li   mm: simplify code...
837
  {
13f7f7898   Mel Gorman   mm: pagevec: defe...
838
839
840
  	int file = page_is_file_cache(page);
  	int active = PageActive(page);
  	enum lru_list lru = page_lru(page);
3dd7ae8ec   Shaohua Li   mm: simplify code...
841

309381fea   Sasha Levin   mm: dump page whe...
842
  	VM_BUG_ON_PAGE(PageLRU(page), page);
3dd7ae8ec   Shaohua Li   mm: simplify code...
843
844
  
  	SetPageLRU(page);
fa9add641   Hugh Dickins   mm/memcg: apply a...
845
846
  	add_page_to_lru_list(page, lruvec, lru);
  	update_page_reclaim_stat(lruvec, file, active);
24b7e5819   Mel Gorman   mm: pagemap: avoi...
847
  	trace_mm_lru_insertion(page, lru);
3dd7ae8ec   Shaohua Li   mm: simplify code...
848
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
849
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
850
851
852
   * Add the passed pages to the LRU, then drop the caller's refcount
   * on them.  Reinitialises the caller's pagevec.
   */
a0b8cab3b   Mel Gorman   mm: remove lru pa...
853
  void __pagevec_lru_add(struct pagevec *pvec)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
854
  {
a0b8cab3b   Mel Gorman   mm: remove lru pa...
855
  	pagevec_lru_move_fn(pvec, __pagevec_lru_add_fn, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
856
  }
5095ae837   Hugh Dickins   mm: fewer undersc...
857
  EXPORT_SYMBOL(__pagevec_lru_add);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
858

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
859
  /**
0cd6144aa   Johannes Weiner   mm + fs: prepare ...
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
   * pagevec_lookup_entries - gang pagecache lookup
   * @pvec:	Where the resulting entries are placed
   * @mapping:	The address_space to search
   * @start:	The starting entry index
   * @nr_entries:	The maximum number of entries
   * @indices:	The cache indices corresponding to the entries in @pvec
   *
   * pagevec_lookup_entries() will search for and return a group of up
   * to @nr_entries pages and shadow entries in the mapping.  All
   * entries are placed in @pvec.  pagevec_lookup_entries() takes a
   * reference against actual pages in @pvec.
   *
   * The search returns a group of mapping-contiguous entries with
   * ascending indexes.  There may be holes in the indices due to
   * not-present entries.
   *
   * pagevec_lookup_entries() returns the number of entries which were
   * found.
   */
  unsigned pagevec_lookup_entries(struct pagevec *pvec,
  				struct address_space *mapping,
  				pgoff_t start, unsigned nr_pages,
  				pgoff_t *indices)
  {
  	pvec->nr = find_get_entries(mapping, start, nr_pages,
  				    pvec->pages, indices);
  	return pagevec_count(pvec);
  }
  
  /**
   * pagevec_remove_exceptionals - pagevec exceptionals pruning
   * @pvec:	The pagevec to prune
   *
   * pagevec_lookup_entries() fills both pages and exceptional radix
   * tree entries into the pagevec.  This function prunes all
   * exceptionals from @pvec without leaving holes, so that it can be
   * passed on to page-only pagevec operations.
   */
  void pagevec_remove_exceptionals(struct pagevec *pvec)
  {
  	int i, j;
  
  	for (i = 0, j = 0; i < pagevec_count(pvec); i++) {
  		struct page *page = pvec->pages[i];
  		if (!radix_tree_exceptional_entry(page))
  			pvec->pages[j++] = page;
  	}
  	pvec->nr = j;
  }
  
  /**
b947cee4b   Jan Kara   mm: implement fin...
911
   * pagevec_lookup_range - gang pagecache lookup
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
912
913
914
   * @pvec:	Where the resulting pages are placed
   * @mapping:	The address_space to search
   * @start:	The starting page index
b947cee4b   Jan Kara   mm: implement fin...
915
   * @end:	The final page index
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
916
917
   * @nr_pages:	The maximum number of pages
   *
b947cee4b   Jan Kara   mm: implement fin...
918
919
920
   * pagevec_lookup_range() will search for and return a group of up to @nr_pages
   * pages in the mapping starting from index @start and upto index @end
   * (inclusive).  The pages are placed in @pvec.  pagevec_lookup() takes a
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
921
922
923
   * reference against the pages in @pvec.
   *
   * The search returns a group of mapping-contiguous pages with ascending
d72dc8a25   Jan Kara   mm: make pagevec_...
924
925
   * indexes.  There may be holes in the indices due to not-present pages. We
   * also update @start to index the next page for the traversal.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
926
   *
b947cee4b   Jan Kara   mm: implement fin...
927
928
929
   * pagevec_lookup_range() returns the number of pages which were found. If this
   * number is smaller than @nr_pages, the end of specified range has been
   * reached.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
930
   */
b947cee4b   Jan Kara   mm: implement fin...
931
  unsigned pagevec_lookup_range(struct pagevec *pvec,
397162ffa   Jan Kara   mm: remove nr_pag...
932
  		struct address_space *mapping, pgoff_t *start, pgoff_t end)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
933
  {
397162ffa   Jan Kara   mm: remove nr_pag...
934
  	pvec->nr = find_get_pages_range(mapping, start, end, PAGEVEC_SIZE,
b947cee4b   Jan Kara   mm: implement fin...
935
  					pvec->pages);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
936
937
  	return pagevec_count(pvec);
  }
b947cee4b   Jan Kara   mm: implement fin...
938
  EXPORT_SYMBOL(pagevec_lookup_range);
78539fdfa   Christoph Hellwig   [XFS] Export page...
939

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
940
941
942
943
944
945
946
  unsigned pagevec_lookup_tag(struct pagevec *pvec, struct address_space *mapping,
  		pgoff_t *index, int tag, unsigned nr_pages)
  {
  	pvec->nr = find_get_pages_tag(mapping, index, tag,
  					nr_pages, pvec->pages);
  	return pagevec_count(pvec);
  }
7f2857018   Steve French   Export __pagevec_...
947
  EXPORT_SYMBOL(pagevec_lookup_tag);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
948

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
949
950
951
952
953
  /*
   * Perform any setup for the swap system
   */
  void __init swap_setup(void)
  {
4481374ce   Jan Beulich   mm: replace vario...
954
  	unsigned long megs = totalram_pages >> (20 - PAGE_SHIFT);
e0bf68dde   Peter Zijlstra   mm: bdi init hooks
955

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
956
957
958
959
960
961
962
963
964
  	/* Use a smaller cluster for small-memory machines */
  	if (megs < 16)
  		page_cluster = 2;
  	else
  		page_cluster = 3;
  	/*
  	 * Right now other parts of the system means that we
  	 * _really_ don't want to cluster much more
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
965
  }