1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23#include <linux/mm.h>
24#include <linux/pagemap.h>
25#include <linux/swapops.h>
26#include <linux/slab.h>
27#include <linux/init.h>
28#include <linux/rmap-locking.h>
29
30#include <asm/pgalloc.h>
31#include <asm/rmap.h>
32#include <asm/tlb.h>
33#include <asm/tlbflush.h>
34
35
36
37
38
39
40
41
42
43
44
45
46#define NRPTE ((L1_CACHE_BYTES - sizeof(void *))/sizeof(pte_addr_t))
47
48struct pte_chain {
49 struct pte_chain *next;
50 pte_addr_t ptes[NRPTE];
51};
52
53static kmem_cache_t *pte_chain_cache;
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79static inline struct pte_chain *pte_chain_alloc(void)
80{
81 struct pte_chain *ret;
82
83 ret = kmem_cache_alloc(pte_chain_cache, GFP_ATOMIC);
84#ifdef DEBUG_RMAP
85 {
86 int i;
87 for (i = 0; i < NRPTE; i++)
88 BUG_ON(ret->ptes[i]);
89 BUG_ON(ret->next);
90 }
91#endif
92 return ret;
93}
94
95
96
97
98
99static inline void pte_chain_free(struct pte_chain *pte_chain)
100{
101 pte_chain->next = NULL;
102 kmem_cache_free(pte_chain_cache, pte_chain);
103}
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120int page_referenced(struct page * page)
121{
122 struct pte_chain * pc;
123 int referenced = 0;
124
125 if (TestClearPageReferenced(page))
126 referenced++;
127
128 if (PageDirect(page)) {
129 pte_t *pte = rmap_ptep_map(page->pte.direct);
130 if (ptep_test_and_clear_young(pte))
131 referenced++;
132 rmap_ptep_unmap(pte);
133 } else {
134 int nr_chains = 0;
135
136
137 for (pc = page->pte.chain; pc; pc = pc->next) {
138 int i;
139
140 for (i = NRPTE-1; i >= 0; i--) {
141 pte_addr_t pte_paddr = pc->ptes[i];
142 pte_t *p;
143
144 if (!pte_paddr)
145 break;
146 p = rmap_ptep_map(pte_paddr);
147 if (ptep_test_and_clear_young(p))
148 referenced++;
149 rmap_ptep_unmap(p);
150 nr_chains++;
151 }
152 }
153 if (nr_chains == 1) {
154 pc = page->pte.chain;
155 page->pte.direct = pc->ptes[NRPTE-1];
156 SetPageDirect(page);
157 pc->ptes[NRPTE-1] = 0;
158 pte_chain_free(pc);
159 }
160 }
161 return referenced;
162}
163
164
165
166
167
168
169
170
171
172void page_add_rmap(struct page * page, pte_t * ptep)
173{
174 pte_addr_t pte_paddr = ptep_to_paddr(ptep);
175 struct pte_chain *pte_chain;
176 int i;
177
178#ifdef DEBUG_RMAP
179 if (!page || !ptep)
180 BUG();
181 if (!pte_present(*ptep))
182 BUG();
183 if (!ptep_to_mm(ptep))
184 BUG();
185#endif
186
187 if (!pfn_valid(page_to_pfn(page)) || PageReserved(page))
188 return;
189
190 pte_chain_lock(page);
191
192#ifdef DEBUG_RMAP
193
194
195
196 {
197 struct pte_chain * pc;
198 if (PageDirect(page)) {
199 if (page->pte.direct == pte_paddr)
200 BUG();
201 } else {
202 for (pc = page->pte.chain; pc; pc = pc->next) {
203 for (i = 0; i < NRPTE; i++) {
204 pte_addr_t p = pc->ptes[i];
205
206 if (p && p == pte_paddr)
207 BUG();
208 }
209 }
210 }
211 }
212#endif
213
214 if (page->pte.direct == 0) {
215 page->pte.direct = pte_paddr;
216 SetPageDirect(page);
217 inc_page_state(nr_mapped);
218 goto out;
219 }
220
221 if (PageDirect(page)) {
222
223 ClearPageDirect(page);
224 pte_chain = pte_chain_alloc();
225 pte_chain->ptes[NRPTE-1] = page->pte.direct;
226 pte_chain->ptes[NRPTE-2] = pte_paddr;
227 page->pte.direct = 0;
228 page->pte.chain = pte_chain;
229 goto out;
230 }
231
232 pte_chain = page->pte.chain;
233 if (pte_chain->ptes[0]) {
234 struct pte_chain *new;
235
236 new = pte_chain_alloc();
237 new->next = pte_chain;
238 page->pte.chain = new;
239 new->ptes[NRPTE-1] = pte_paddr;
240 goto out;
241 }
242
243 BUG_ON(!pte_chain->ptes[NRPTE-1]);
244
245 for (i = NRPTE-2; i >= 0; i--) {
246 if (!pte_chain->ptes[i]) {
247 pte_chain->ptes[i] = pte_paddr;
248 goto out;
249 }
250 }
251 BUG();
252out:
253 pte_chain_unlock(page);
254 inc_page_state(nr_reverse_maps);
255 return;
256}
257
258
259
260
261
262
263
264
265
266
267
268void page_remove_rmap(struct page * page, pte_t * ptep)
269{
270 pte_addr_t pte_paddr = ptep_to_paddr(ptep);
271 struct pte_chain *pc;
272
273 if (!page || !ptep)
274 BUG();
275 if (!pfn_valid(page_to_pfn(page)) || PageReserved(page))
276 return;
277
278 pte_chain_lock(page);
279
280 BUG_ON(page->pte.direct == 0);
281
282 if (PageDirect(page)) {
283 if (page->pte.direct == pte_paddr) {
284 page->pte.direct = 0;
285 dec_page_state(nr_reverse_maps);
286 ClearPageDirect(page);
287 goto out;
288 }
289 } else {
290 struct pte_chain *start = page->pte.chain;
291 int victim_i = -1;
292
293 for (pc = start; pc; pc = pc->next) {
294 int i;
295
296 if (pc->next)
297 prefetch(pc->next);
298 for (i = 0; i < NRPTE; i++) {
299 pte_addr_t pa = pc->ptes[i];
300
301 if (!pa)
302 continue;
303 if (victim_i == -1)
304 victim_i = i;
305 if (pa != pte_paddr)
306 continue;
307 pc->ptes[i] = start->ptes[victim_i];
308 dec_page_state(nr_reverse_maps);
309 start->ptes[victim_i] = 0;
310 if (victim_i == NRPTE-1) {
311
312 page->pte.chain = start->next;
313 pte_chain_free(start);
314 } else {
315
316 }
317 goto out;
318 }
319 }
320 }
321#ifdef DEBUG_RMAP
322
323 printk(KERN_ERR "page_remove_rmap: pte_chain %p not present.\n", ptep);
324 printk(KERN_ERR "page_remove_rmap: only found: ");
325 if (PageDirect(page)) {
326 printk("%llx", (u64)page->pte.direct);
327 } else {
328 for (pc = page->pte.chain; pc; pc = pc->next) {
329 int i;
330 for (i = 0; i < NRPTE; i++)
331 printk(" %d:%llx", i, (u64)pc->ptes[i]);
332 }
333 }
334 printk("\n");
335 printk(KERN_ERR "page_remove_rmap: driver cleared PG_reserved ?\n");
336#endif
337
338out:
339 pte_chain_unlock(page);
340 if (!page_mapped(page))
341 dec_page_state(nr_mapped);
342 return;
343}
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359static int FASTCALL(try_to_unmap_one(struct page *, pte_addr_t));
360static int try_to_unmap_one(struct page * page, pte_addr_t paddr)
361{
362 pte_t *ptep = rmap_ptep_map(paddr);
363 unsigned long address = ptep_to_address(ptep);
364 struct mm_struct * mm = ptep_to_mm(ptep);
365 struct vm_area_struct * vma;
366 pte_t pte;
367 int ret;
368
369 if (!mm)
370 BUG();
371
372
373
374
375
376 if (!spin_trylock(&mm->page_table_lock)) {
377 rmap_ptep_unmap(ptep);
378 return SWAP_AGAIN;
379 }
380
381
382
383 vma = find_vma(mm, address);
384 if (!vma) {
385 ret = SWAP_FAIL;
386 goto out_unlock;
387 }
388
389
390 if (vma->vm_flags & VM_LOCKED) {
391 ret = SWAP_FAIL;
392 goto out_unlock;
393 }
394
395
396 pte = ptep_get_and_clear(ptep);
397 flush_tlb_page(vma, address);
398 flush_cache_page(vma, address);
399
400
401 if (PageSwapCache(page)) {
402 swp_entry_t entry = { .val = page->index };
403 swap_duplicate(entry);
404 set_pte(ptep, swp_entry_to_pte(entry));
405 }
406
407
408 if (pte_dirty(pte))
409 set_page_dirty(page);
410
411 mm->rss--;
412 page_cache_release(page);
413 ret = SWAP_SUCCESS;
414
415out_unlock:
416 rmap_ptep_unmap(ptep);
417 spin_unlock(&mm->page_table_lock);
418 return ret;
419}
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434int try_to_unmap(struct page * page)
435{
436 struct pte_chain *pc, *next_pc, *start;
437 int ret = SWAP_SUCCESS;
438 int victim_i = -1;
439
440
441 if (PageReserved(page))
442 BUG();
443 if (!PageLocked(page))
444 BUG();
445
446 if (!page->mapping)
447 BUG();
448
449 if (PageDirect(page)) {
450 ret = try_to_unmap_one(page, page->pte.direct);
451 if (ret == SWAP_SUCCESS) {
452 page->pte.direct = 0;
453 dec_page_state(nr_reverse_maps);
454 ClearPageDirect(page);
455 }
456 goto out;
457 }
458
459 start = page->pte.chain;
460 for (pc = start; pc; pc = next_pc) {
461 int i;
462
463 next_pc = pc->next;
464 if (next_pc)
465 prefetch(next_pc);
466 for (i = 0; i < NRPTE; i++) {
467 pte_addr_t pte_paddr = pc->ptes[i];
468
469 if (!pte_paddr)
470 continue;
471 if (victim_i == -1)
472 victim_i = i;
473
474 switch (try_to_unmap_one(page, pte_paddr)) {
475 case SWAP_SUCCESS:
476
477
478
479
480
481
482 pc->ptes[i] = start->ptes[victim_i];
483 start->ptes[victim_i] = 0;
484 dec_page_state(nr_reverse_maps);
485 victim_i++;
486 if (victim_i == NRPTE) {
487 page->pte.chain = start->next;
488 pte_chain_free(start);
489 start = page->pte.chain;
490 victim_i = 0;
491 }
492 break;
493 case SWAP_AGAIN:
494
495 ret = SWAP_AGAIN;
496 continue;
497 case SWAP_FAIL:
498 ret = SWAP_FAIL;
499 goto out;
500 case SWAP_ERROR:
501 ret = SWAP_ERROR;
502 goto out;
503 }
504 }
505 }
506out:
507 if (!page_mapped(page))
508 dec_page_state(nr_mapped);
509 return ret;
510}
511
512
513
514
515
516
517static void pte_chain_ctor(void *p, kmem_cache_t *cachep, unsigned long flags)
518{
519 struct pte_chain *pc = p;
520
521 memset(pc, 0, sizeof(*pc));
522}
523
524void __init pte_chain_init(void)
525{
526 pte_chain_cache = kmem_cache_create( "pte_chain",
527 sizeof(struct pte_chain),
528 0,
529 0,
530 pte_chain_ctor,
531 NULL);
532
533 if (!pte_chain_cache)
534 panic("failed to create pte_chain cache!\n");
535}
536