diff options
author | Jeff Garzik <jgarzik@pobox.com> | 2005-10-20 10:06:09 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2005-10-20 10:06:09 -0400 |
commit | 902f90735b693550eb51a3989895f3148b8229d8 (patch) | |
tree | faddc60f0b27ed6d2a26f20c2c09f365dc4a2d7d /mm | |
parent | 07b8fede6da76ae6a0f547716c44b801a116bb4a (diff) | |
parent | 93918e9afc76717176e9e114e79cdbb602a45ae8 (diff) |
Merge branch 'master'
Diffstat (limited to 'mm')
-rw-r--r-- | mm/bootmem.c | 31 | ||||
-rw-r--r-- | mm/hugetlb.c | 35 | ||||
-rw-r--r-- | mm/memory.c | 14 |
3 files changed, 54 insertions, 26 deletions
diff --git a/mm/bootmem.c b/mm/bootmem.c index c1330cc19783..a58699b6579e 100644 --- a/mm/bootmem.c +++ b/mm/bootmem.c | |||
@@ -154,10 +154,10 @@ static void __init free_bootmem_core(bootmem_data_t *bdata, unsigned long addr, | |||
154 | */ | 154 | */ |
155 | static void * __init | 155 | static void * __init |
156 | __alloc_bootmem_core(struct bootmem_data *bdata, unsigned long size, | 156 | __alloc_bootmem_core(struct bootmem_data *bdata, unsigned long size, |
157 | unsigned long align, unsigned long goal) | 157 | unsigned long align, unsigned long goal, unsigned long limit) |
158 | { | 158 | { |
159 | unsigned long offset, remaining_size, areasize, preferred; | 159 | unsigned long offset, remaining_size, areasize, preferred; |
160 | unsigned long i, start = 0, incr, eidx; | 160 | unsigned long i, start = 0, incr, eidx, end_pfn = bdata->node_low_pfn; |
161 | void *ret; | 161 | void *ret; |
162 | 162 | ||
163 | if(!size) { | 163 | if(!size) { |
@@ -166,7 +166,14 @@ __alloc_bootmem_core(struct bootmem_data *bdata, unsigned long size, | |||
166 | } | 166 | } |
167 | BUG_ON(align & (align-1)); | 167 | BUG_ON(align & (align-1)); |
168 | 168 | ||
169 | eidx = bdata->node_low_pfn - (bdata->node_boot_start >> PAGE_SHIFT); | 169 | if (limit && bdata->node_boot_start >= limit) |
170 | return NULL; | ||
171 | |||
172 | limit >>=PAGE_SHIFT; | ||
173 | if (limit && end_pfn > limit) | ||
174 | end_pfn = limit; | ||
175 | |||
176 | eidx = end_pfn - (bdata->node_boot_start >> PAGE_SHIFT); | ||
170 | offset = 0; | 177 | offset = 0; |
171 | if (align && | 178 | if (align && |
172 | (bdata->node_boot_start & (align - 1UL)) != 0) | 179 | (bdata->node_boot_start & (align - 1UL)) != 0) |
@@ -178,11 +185,12 @@ __alloc_bootmem_core(struct bootmem_data *bdata, unsigned long size, | |||
178 | * first, then we try to allocate lower pages. | 185 | * first, then we try to allocate lower pages. |
179 | */ | 186 | */ |
180 | if (goal && (goal >= bdata->node_boot_start) && | 187 | if (goal && (goal >= bdata->node_boot_start) && |
181 | ((goal >> PAGE_SHIFT) < bdata->node_low_pfn)) { | 188 | ((goal >> PAGE_SHIFT) < end_pfn)) { |
182 | preferred = goal - bdata->node_boot_start; | 189 | preferred = goal - bdata->node_boot_start; |
183 | 190 | ||
184 | if (bdata->last_success >= preferred) | 191 | if (bdata->last_success >= preferred) |
185 | preferred = bdata->last_success; | 192 | if (!limit || (limit && limit > bdata->last_success)) |
193 | preferred = bdata->last_success; | ||
186 | } else | 194 | } else |
187 | preferred = 0; | 195 | preferred = 0; |
188 | 196 | ||
@@ -382,14 +390,15 @@ unsigned long __init free_all_bootmem (void) | |||
382 | return(free_all_bootmem_core(NODE_DATA(0))); | 390 | return(free_all_bootmem_core(NODE_DATA(0))); |
383 | } | 391 | } |
384 | 392 | ||
385 | void * __init __alloc_bootmem (unsigned long size, unsigned long align, unsigned long goal) | 393 | void * __init __alloc_bootmem_limit (unsigned long size, unsigned long align, unsigned long goal, |
394 | unsigned long limit) | ||
386 | { | 395 | { |
387 | pg_data_t *pgdat = pgdat_list; | 396 | pg_data_t *pgdat = pgdat_list; |
388 | void *ptr; | 397 | void *ptr; |
389 | 398 | ||
390 | for_each_pgdat(pgdat) | 399 | for_each_pgdat(pgdat) |
391 | if ((ptr = __alloc_bootmem_core(pgdat->bdata, size, | 400 | if ((ptr = __alloc_bootmem_core(pgdat->bdata, size, |
392 | align, goal))) | 401 | align, goal, limit))) |
393 | return(ptr); | 402 | return(ptr); |
394 | 403 | ||
395 | /* | 404 | /* |
@@ -400,14 +409,16 @@ void * __init __alloc_bootmem (unsigned long size, unsigned long align, unsigned | |||
400 | return NULL; | 409 | return NULL; |
401 | } | 410 | } |
402 | 411 | ||
403 | void * __init __alloc_bootmem_node (pg_data_t *pgdat, unsigned long size, unsigned long align, unsigned long goal) | 412 | |
413 | void * __init __alloc_bootmem_node_limit (pg_data_t *pgdat, unsigned long size, unsigned long align, | ||
414 | unsigned long goal, unsigned long limit) | ||
404 | { | 415 | { |
405 | void *ptr; | 416 | void *ptr; |
406 | 417 | ||
407 | ptr = __alloc_bootmem_core(pgdat->bdata, size, align, goal); | 418 | ptr = __alloc_bootmem_core(pgdat->bdata, size, align, goal, limit); |
408 | if (ptr) | 419 | if (ptr) |
409 | return (ptr); | 420 | return (ptr); |
410 | 421 | ||
411 | return __alloc_bootmem(size, align, goal); | 422 | return __alloc_bootmem_limit(size, align, goal, limit); |
412 | } | 423 | } |
413 | 424 | ||
diff --git a/mm/hugetlb.c b/mm/hugetlb.c index 901ac523a1c3..a1b30d45459e 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c | |||
@@ -274,21 +274,22 @@ int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src, | |||
274 | { | 274 | { |
275 | pte_t *src_pte, *dst_pte, entry; | 275 | pte_t *src_pte, *dst_pte, entry; |
276 | struct page *ptepage; | 276 | struct page *ptepage; |
277 | unsigned long addr = vma->vm_start; | 277 | unsigned long addr; |
278 | unsigned long end = vma->vm_end; | ||
279 | 278 | ||
280 | while (addr < end) { | 279 | for (addr = vma->vm_start; addr < vma->vm_end; addr += HPAGE_SIZE) { |
281 | dst_pte = huge_pte_alloc(dst, addr); | 280 | dst_pte = huge_pte_alloc(dst, addr); |
282 | if (!dst_pte) | 281 | if (!dst_pte) |
283 | goto nomem; | 282 | goto nomem; |
283 | spin_lock(&src->page_table_lock); | ||
284 | src_pte = huge_pte_offset(src, addr); | 284 | src_pte = huge_pte_offset(src, addr); |
285 | BUG_ON(!src_pte || pte_none(*src_pte)); /* prefaulted */ | 285 | if (src_pte && !pte_none(*src_pte)) { |
286 | entry = *src_pte; | 286 | entry = *src_pte; |
287 | ptepage = pte_page(entry); | 287 | ptepage = pte_page(entry); |
288 | get_page(ptepage); | 288 | get_page(ptepage); |
289 | add_mm_counter(dst, rss, HPAGE_SIZE / PAGE_SIZE); | 289 | add_mm_counter(dst, rss, HPAGE_SIZE / PAGE_SIZE); |
290 | set_huge_pte_at(dst, addr, dst_pte, entry); | 290 | set_huge_pte_at(dst, addr, dst_pte, entry); |
291 | addr += HPAGE_SIZE; | 291 | } |
292 | spin_unlock(&src->page_table_lock); | ||
292 | } | 293 | } |
293 | return 0; | 294 | return 0; |
294 | 295 | ||
@@ -323,8 +324,8 @@ void unmap_hugepage_range(struct vm_area_struct *vma, unsigned long start, | |||
323 | 324 | ||
324 | page = pte_page(pte); | 325 | page = pte_page(pte); |
325 | put_page(page); | 326 | put_page(page); |
327 | add_mm_counter(mm, rss, - (HPAGE_SIZE / PAGE_SIZE)); | ||
326 | } | 328 | } |
327 | add_mm_counter(mm, rss, -((end - start) >> PAGE_SHIFT)); | ||
328 | flush_tlb_range(vma, start, end); | 329 | flush_tlb_range(vma, start, end); |
329 | } | 330 | } |
330 | 331 | ||
@@ -403,6 +404,7 @@ int follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma, | |||
403 | BUG_ON(!is_vm_hugetlb_page(vma)); | 404 | BUG_ON(!is_vm_hugetlb_page(vma)); |
404 | 405 | ||
405 | vpfn = vaddr/PAGE_SIZE; | 406 | vpfn = vaddr/PAGE_SIZE; |
407 | spin_lock(&mm->page_table_lock); | ||
406 | while (vaddr < vma->vm_end && remainder) { | 408 | while (vaddr < vma->vm_end && remainder) { |
407 | 409 | ||
408 | if (pages) { | 410 | if (pages) { |
@@ -415,8 +417,13 @@ int follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma, | |||
415 | * indexing below to work. */ | 417 | * indexing below to work. */ |
416 | pte = huge_pte_offset(mm, vaddr & HPAGE_MASK); | 418 | pte = huge_pte_offset(mm, vaddr & HPAGE_MASK); |
417 | 419 | ||
418 | /* hugetlb should be locked, and hence, prefaulted */ | 420 | /* the hugetlb file might have been truncated */ |
419 | WARN_ON(!pte || pte_none(*pte)); | 421 | if (!pte || pte_none(*pte)) { |
422 | remainder = 0; | ||
423 | if (!i) | ||
424 | i = -EFAULT; | ||
425 | break; | ||
426 | } | ||
420 | 427 | ||
421 | page = &pte_page(*pte)[vpfn % (HPAGE_SIZE/PAGE_SIZE)]; | 428 | page = &pte_page(*pte)[vpfn % (HPAGE_SIZE/PAGE_SIZE)]; |
422 | 429 | ||
@@ -434,7 +441,7 @@ int follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma, | |||
434 | --remainder; | 441 | --remainder; |
435 | ++i; | 442 | ++i; |
436 | } | 443 | } |
437 | 444 | spin_unlock(&mm->page_table_lock); | |
438 | *length = remainder; | 445 | *length = remainder; |
439 | *position = vaddr; | 446 | *position = vaddr; |
440 | 447 | ||
diff --git a/mm/memory.c b/mm/memory.c index ae8161f1f459..8c88b973abc5 100644 --- a/mm/memory.c +++ b/mm/memory.c | |||
@@ -2045,8 +2045,18 @@ int __handle_mm_fault(struct mm_struct *mm, struct vm_area_struct * vma, | |||
2045 | 2045 | ||
2046 | inc_page_state(pgfault); | 2046 | inc_page_state(pgfault); |
2047 | 2047 | ||
2048 | if (is_vm_hugetlb_page(vma)) | 2048 | if (unlikely(is_vm_hugetlb_page(vma))) { |
2049 | return VM_FAULT_SIGBUS; /* mapping truncation does this. */ | 2049 | if (valid_hugetlb_file_off(vma, address)) |
2050 | /* We get here only if there was a stale(zero) TLB entry | ||
2051 | * (because of HW prefetching). | ||
2052 | * Low-level arch code (if needed) should have already | ||
2053 | * purged the stale entry as part of this fault handling. | ||
2054 | * Here we just return. | ||
2055 | */ | ||
2056 | return VM_FAULT_MINOR; | ||
2057 | else | ||
2058 | return VM_FAULT_SIGBUS; /* mapping truncation does this. */ | ||
2059 | } | ||
2050 | 2060 | ||
2051 | /* | 2061 | /* |
2052 | * We need the page table lock to synchronize with kswapd | 2062 | * We need the page table lock to synchronize with kswapd |