Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
hugetlbpage.c
Go to the documentation of this file.
1 /*
2  * SPARC64 Huge TLB page support.
3  *
4  * Copyright (C) 2002, 2003, 2006 David S. Miller ([email protected])
5  */
6 
7 #include <linux/init.h>
8 #include <linux/fs.h>
9 #include <linux/mm.h>
10 #include <linux/hugetlb.h>
11 #include <linux/pagemap.h>
12 #include <linux/sysctl.h>
13 
14 #include <asm/mman.h>
15 #include <asm/pgalloc.h>
16 #include <asm/tlb.h>
17 #include <asm/tlbflush.h>
18 #include <asm/cacheflush.h>
19 #include <asm/mmu_context.h>
20 
21 /* Slightly simplified from the non-hugepage variant because by
22  * definition we don't have to worry about any page coloring stuff
23  */
24 #define VA_EXCLUDE_START (0x0000080000000000UL - (1UL << 32UL))
25 #define VA_EXCLUDE_END (0xfffff80000000000UL + (1UL << 32UL))
26 
27 static unsigned long hugetlb_get_unmapped_area_bottomup(struct file *filp,
28  unsigned long addr,
29  unsigned long len,
30  unsigned long pgoff,
31  unsigned long flags)
32 {
33  struct mm_struct *mm = current->mm;
34  struct vm_area_struct * vma;
35  unsigned long task_size = TASK_SIZE;
36  unsigned long start_addr;
37 
38  if (test_thread_flag(TIF_32BIT))
39  task_size = STACK_TOP32;
40  if (unlikely(len >= VA_EXCLUDE_START))
41  return -ENOMEM;
42 
43  if (len > mm->cached_hole_size) {
44  start_addr = addr = mm->free_area_cache;
45  } else {
46  start_addr = addr = TASK_UNMAPPED_BASE;
47  mm->cached_hole_size = 0;
48  }
49 
50  task_size -= len;
51 
52 full_search:
53  addr = ALIGN(addr, HPAGE_SIZE);
54 
55  for (vma = find_vma(mm, addr); ; vma = vma->vm_next) {
56  /* At this point: (!vma || addr < vma->vm_end). */
57  if (addr < VA_EXCLUDE_START &&
58  (addr + len) >= VA_EXCLUDE_START) {
59  addr = VA_EXCLUDE_END;
60  vma = find_vma(mm, VA_EXCLUDE_END);
61  }
62  if (unlikely(task_size < addr)) {
63  if (start_addr != TASK_UNMAPPED_BASE) {
64  start_addr = addr = TASK_UNMAPPED_BASE;
65  mm->cached_hole_size = 0;
66  goto full_search;
67  }
68  return -ENOMEM;
69  }
70  if (likely(!vma || addr + len <= vma->vm_start)) {
71  /*
72  * Remember the place where we stopped the search:
73  */
74  mm->free_area_cache = addr + len;
75  return addr;
76  }
77  if (addr + mm->cached_hole_size < vma->vm_start)
78  mm->cached_hole_size = vma->vm_start - addr;
79 
80  addr = ALIGN(vma->vm_end, HPAGE_SIZE);
81  }
82 }
83 
84 static unsigned long
85 hugetlb_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
86  const unsigned long len,
87  const unsigned long pgoff,
88  const unsigned long flags)
89 {
90  struct vm_area_struct *vma;
91  struct mm_struct *mm = current->mm;
92  unsigned long addr = addr0;
93 
94  /* This should only ever run for 32-bit processes. */
95  BUG_ON(!test_thread_flag(TIF_32BIT));
96 
97  /* check if free_area_cache is useful for us */
98  if (len <= mm->cached_hole_size) {
99  mm->cached_hole_size = 0;
100  mm->free_area_cache = mm->mmap_base;
101  }
102 
103  /* either no address requested or can't fit in requested address hole */
104  addr = mm->free_area_cache & HPAGE_MASK;
105 
106  /* make sure it can fit in the remaining address space */
107  if (likely(addr > len)) {
108  vma = find_vma(mm, addr-len);
109  if (!vma || addr <= vma->vm_start) {
110  /* remember the address as a hint for next time */
111  return (mm->free_area_cache = addr-len);
112  }
113  }
114 
115  if (unlikely(mm->mmap_base < len))
116  goto bottomup;
117 
118  addr = (mm->mmap_base-len) & HPAGE_MASK;
119 
120  do {
121  /*
122  * Lookup failure means no vma is above this address,
123  * else if new region fits below vma->vm_start,
124  * return with success:
125  */
126  vma = find_vma(mm, addr);
127  if (likely(!vma || addr+len <= vma->vm_start)) {
128  /* remember the address as a hint for next time */
129  return (mm->free_area_cache = addr);
130  }
131 
132  /* remember the largest hole we saw so far */
133  if (addr + mm->cached_hole_size < vma->vm_start)
134  mm->cached_hole_size = vma->vm_start - addr;
135 
136  /* try just below the current vma->vm_start */
137  addr = (vma->vm_start-len) & HPAGE_MASK;
138  } while (likely(len < vma->vm_start));
139 
140 bottomup:
141  /*
142  * A failed mmap() very likely causes application failure,
143  * so fall back to the bottom-up function here. This scenario
144  * can happen with large stack limits and large mmap()
145  * allocations.
146  */
147  mm->cached_hole_size = ~0UL;
149  addr = arch_get_unmapped_area(filp, addr0, len, pgoff, flags);
150  /*
151  * Restore the topdown base:
152  */
153  mm->free_area_cache = mm->mmap_base;
154  mm->cached_hole_size = ~0UL;
155 
156  return addr;
157 }
158 
159 unsigned long
160 hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
161  unsigned long len, unsigned long pgoff, unsigned long flags)
162 {
163  struct mm_struct *mm = current->mm;
164  struct vm_area_struct *vma;
165  unsigned long task_size = TASK_SIZE;
166 
167  if (test_thread_flag(TIF_32BIT))
168  task_size = STACK_TOP32;
169 
170  if (len & ~HPAGE_MASK)
171  return -EINVAL;
172  if (len > task_size)
173  return -ENOMEM;
174 
175  if (flags & MAP_FIXED) {
176  if (prepare_hugepage_range(file, addr, len))
177  return -EINVAL;
178  return addr;
179  }
180 
181  if (addr) {
182  addr = ALIGN(addr, HPAGE_SIZE);
183  vma = find_vma(mm, addr);
184  if (task_size - len >= addr &&
185  (!vma || addr + len <= vma->vm_start))
186  return addr;
187  }
188  if (mm->get_unmapped_area == arch_get_unmapped_area)
189  return hugetlb_get_unmapped_area_bottomup(file, addr, len,
190  pgoff, flags);
191  else
192  return hugetlb_get_unmapped_area_topdown(file, addr, len,
193  pgoff, flags);
194 }
195 
197  unsigned long addr, unsigned long sz)
198 {
199  pgd_t *pgd;
200  pud_t *pud;
201  pmd_t *pmd;
202  pte_t *pte = NULL;
203 
204  /* We must align the address, because our caller will run
205  * set_huge_pte_at() on whatever we return, which writes out
206  * all of the sub-ptes for the hugepage range. So we have
207  * to give it the first such sub-pte.
208  */
209  addr &= HPAGE_MASK;
210 
211  pgd = pgd_offset(mm, addr);
212  pud = pud_alloc(mm, pgd, addr);
213  if (pud) {
214  pmd = pmd_alloc(mm, pud, addr);
215  if (pmd)
216  pte = pte_alloc_map(mm, NULL, pmd, addr);
217  }
218  return pte;
219 }
220 
221 pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
222 {
223  pgd_t *pgd;
224  pud_t *pud;
225  pmd_t *pmd;
226  pte_t *pte = NULL;
227 
228  addr &= HPAGE_MASK;
229 
230  pgd = pgd_offset(mm, addr);
231  if (!pgd_none(*pgd)) {
232  pud = pud_offset(pgd, addr);
233  if (!pud_none(*pud)) {
234  pmd = pmd_offset(pud, addr);
235  if (!pmd_none(*pmd))
236  pte = pte_offset_map(pmd, addr);
237  }
238  }
239  return pte;
240 }
241 
242 int huge_pmd_unshare(struct mm_struct *mm, unsigned long *addr, pte_t *ptep)
243 {
244  return 0;
245 }
246 
247 void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
248  pte_t *ptep, pte_t entry)
249 {
250  int i;
251 
252  if (!pte_present(*ptep) && pte_present(entry))
253  mm->context.huge_pte_count++;
254 
255  addr &= HPAGE_MASK;
256  for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) {
257  set_pte_at(mm, addr, ptep, entry);
258  ptep++;
259  addr += PAGE_SIZE;
260  pte_val(entry) += PAGE_SIZE;
261  }
262 }
263 
264 pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
265  pte_t *ptep)
266 {
267  pte_t entry;
268  int i;
269 
270  entry = *ptep;
271  if (pte_present(entry))
272  mm->context.huge_pte_count--;
273 
274  addr &= HPAGE_MASK;
275 
276  for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) {
277  pte_clear(mm, addr, ptep);
278  addr += PAGE_SIZE;
279  ptep++;
280  }
281 
282  return entry;
283 }
284 
285 struct page *follow_huge_addr(struct mm_struct *mm,
286  unsigned long address, int write)
287 {
288  return ERR_PTR(-EINVAL);
289 }
290 
292 {
293  return 0;
294 }
295 
296 int pud_huge(pud_t pud)
297 {
298  return 0;
299 }
300 
301 struct page *follow_huge_pmd(struct mm_struct *mm, unsigned long address,
302  pmd_t *pmd, int write)
303 {
304  return NULL;
305 }