Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pgtable-generic.c
Go to the documentation of this file.
1 /*
2  * mm/pgtable-generic.c
3  *
4  * Generic pgtable methods declared in asm-generic/pgtable.h
5  *
6  * Copyright (C) 2010 Linus Torvalds
7  */
8 
9 #include <linux/pagemap.h>
10 #include <asm/tlb.h>
11 #include <asm-generic/pgtable.h>
12 
13 #ifndef __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
14 /*
15  * Only sets the access flags (dirty, accessed, and
16  * writable). Furthermore, we know it always gets set to a "more
17  * permissive" setting, which allows most architectures to optimize
18  * this. We return whether the PTE actually changed, which in turn
19  * instructs the caller to do things like update__mmu_cache. This
20  * used to be done in the caller, but sparc needs minor faults to
21  * force that call on sun4c so we changed this macro slightly
22  */
24  unsigned long address, pte_t *ptep,
25  pte_t entry, int dirty)
26 {
27  int changed = !pte_same(*ptep, entry);
28  if (changed) {
29  set_pte_at(vma->vm_mm, address, ptep, entry);
30  flush_tlb_page(vma, address);
31  }
32  return changed;
33 }
34 #endif
35 
36 #ifndef __HAVE_ARCH_PMDP_SET_ACCESS_FLAGS
38  unsigned long address, pmd_t *pmdp,
39  pmd_t entry, int dirty)
40 {
41 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
42  int changed = !pmd_same(*pmdp, entry);
43  VM_BUG_ON(address & ~HPAGE_PMD_MASK);
44  if (changed) {
45  set_pmd_at(vma->vm_mm, address, pmdp, entry);
46  flush_tlb_range(vma, address, address + HPAGE_PMD_SIZE);
47  }
48  return changed;
49 #else /* CONFIG_TRANSPARENT_HUGEPAGE */
50  BUG();
51  return 0;
52 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
53 }
54 #endif
55 
56 #ifndef __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH
58  unsigned long address, pte_t *ptep)
59 {
60  int young;
61  young = ptep_test_and_clear_young(vma, address, ptep);
62  if (young)
63  flush_tlb_page(vma, address);
64  return young;
65 }
66 #endif
67 
68 #ifndef __HAVE_ARCH_PMDP_CLEAR_YOUNG_FLUSH
70  unsigned long address, pmd_t *pmdp)
71 {
72  int young;
73 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
74  VM_BUG_ON(address & ~HPAGE_PMD_MASK);
75 #else
76  BUG();
77 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
78  young = pmdp_test_and_clear_young(vma, address, pmdp);
79  if (young)
80  flush_tlb_range(vma, address, address + HPAGE_PMD_SIZE);
81  return young;
82 }
83 #endif
84 
85 #ifndef __HAVE_ARCH_PTEP_CLEAR_FLUSH
86 pte_t ptep_clear_flush(struct vm_area_struct *vma, unsigned long address,
87  pte_t *ptep)
88 {
89  pte_t pte;
90  pte = ptep_get_and_clear((vma)->vm_mm, address, ptep);
91  flush_tlb_page(vma, address);
92  return pte;
93 }
94 #endif
95 
96 #ifndef __HAVE_ARCH_PMDP_CLEAR_FLUSH
97 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
98 pmd_t pmdp_clear_flush(struct vm_area_struct *vma, unsigned long address,
99  pmd_t *pmdp)
100 {
101  pmd_t pmd;
102  VM_BUG_ON(address & ~HPAGE_PMD_MASK);
103  pmd = pmdp_get_and_clear(vma->vm_mm, address, pmdp);
104  flush_tlb_range(vma, address, address + HPAGE_PMD_SIZE);
105  return pmd;
106 }
107 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
108 #endif
109 
110 #ifndef __HAVE_ARCH_PMDP_SPLITTING_FLUSH
111 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
112 void pmdp_splitting_flush(struct vm_area_struct *vma, unsigned long address,
113  pmd_t *pmdp)
114 {
115  pmd_t pmd = pmd_mksplitting(*pmdp);
116  VM_BUG_ON(address & ~HPAGE_PMD_MASK);
117  set_pmd_at(vma->vm_mm, address, pmdp, pmd);
118  /* tlb flush only to serialize against gup-fast */
119  flush_tlb_range(vma, address, address + HPAGE_PMD_SIZE);
120 }
121 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
122 #endif
123 
124 #ifndef __HAVE_ARCH_PGTABLE_DEPOSIT
125 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
126 void pgtable_trans_huge_deposit(struct mm_struct *mm, pgtable_t pgtable)
127 {
129 
130  /* FIFO */
131  if (!mm->pmd_huge_pte)
132  INIT_LIST_HEAD(&pgtable->lru);
133  else
134  list_add(&pgtable->lru, &mm->pmd_huge_pte->lru);
135  mm->pmd_huge_pte = pgtable;
136 }
137 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
138 #endif
139 
140 #ifndef __HAVE_ARCH_PGTABLE_WITHDRAW
141 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
142 /* no "address" argument so destroys page coloring of some arch */
143 pgtable_t pgtable_trans_huge_withdraw(struct mm_struct *mm)
144 {
145  pgtable_t pgtable;
146 
148 
149  /* FIFO */
150  pgtable = mm->pmd_huge_pte;
151  if (list_empty(&pgtable->lru))
152  mm->pmd_huge_pte = NULL;
153  else {
154  mm->pmd_huge_pte = list_entry(pgtable->lru.next,
155  struct page, lru);
156  list_del(&pgtable->lru);
157  }
158  return pgtable;
159 }
160 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
161 #endif
162 
163 #ifndef __HAVE_ARCH_PMDP_INVALIDATE
164 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
165 void pmdp_invalidate(struct vm_area_struct *vma, unsigned long address,
166  pmd_t *pmdp)
167 {
168  set_pmd_at(vma->vm_mm, address, pmdp, pmd_mknotpresent(*pmdp));
169  flush_tlb_range(vma, address, address + HPAGE_PMD_SIZE);
170 }
171 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
172 #endif