diff options
Diffstat (limited to 'mm/memory.c')
-rw-r--r-- | mm/memory.c | 47 |
1 files changed, 32 insertions, 15 deletions
diff --git a/mm/memory.c b/mm/memory.c index 59d42e50fa53..da642b5528fa 100644 --- a/mm/memory.c +++ b/mm/memory.c | |||
@@ -332,6 +332,16 @@ out: | |||
332 | return pte_offset_kernel(pmd, address); | 332 | return pte_offset_kernel(pmd, address); |
333 | } | 333 | } |
334 | 334 | ||
335 | static inline void add_mm_rss(struct mm_struct *mm, int file_rss, int anon_rss) | ||
336 | { | ||
337 | if (file_rss) | ||
338 | add_mm_counter(mm, file_rss, file_rss); | ||
339 | if (anon_rss) | ||
340 | add_mm_counter(mm, anon_rss, anon_rss); | ||
341 | } | ||
342 | |||
343 | #define NO_RSS 2 /* Increment neither file_rss nor anon_rss */ | ||
344 | |||
335 | /* | 345 | /* |
336 | * copy one vm_area from one task to the other. Assumes the page tables | 346 | * copy one vm_area from one task to the other. Assumes the page tables |
337 | * already present in the new task to be cleared in the whole range | 347 | * already present in the new task to be cleared in the whole range |
@@ -341,7 +351,7 @@ out: | |||
341 | * but may be dropped within p[mg]d_alloc() and pte_alloc_map(). | 351 | * but may be dropped within p[mg]d_alloc() and pte_alloc_map(). |
342 | */ | 352 | */ |
343 | 353 | ||
344 | static inline void | 354 | static inline int |
345 | copy_one_pte(struct mm_struct *dst_mm, struct mm_struct *src_mm, | 355 | copy_one_pte(struct mm_struct *dst_mm, struct mm_struct *src_mm, |
346 | pte_t *dst_pte, pte_t *src_pte, unsigned long vm_flags, | 356 | pte_t *dst_pte, pte_t *src_pte, unsigned long vm_flags, |
347 | unsigned long addr) | 357 | unsigned long addr) |
@@ -349,6 +359,7 @@ copy_one_pte(struct mm_struct *dst_mm, struct mm_struct *src_mm, | |||
349 | pte_t pte = *src_pte; | 359 | pte_t pte = *src_pte; |
350 | struct page *page; | 360 | struct page *page; |
351 | unsigned long pfn; | 361 | unsigned long pfn; |
362 | int anon = NO_RSS; | ||
352 | 363 | ||
353 | /* pte contains position in swap or file, so copy. */ | 364 | /* pte contains position in swap or file, so copy. */ |
354 | if (unlikely(!pte_present(pte))) { | 365 | if (unlikely(!pte_present(pte))) { |
@@ -361,8 +372,7 @@ copy_one_pte(struct mm_struct *dst_mm, struct mm_struct *src_mm, | |||
361 | spin_unlock(&mmlist_lock); | 372 | spin_unlock(&mmlist_lock); |
362 | } | 373 | } |
363 | } | 374 | } |
364 | set_pte_at(dst_mm, addr, dst_pte, pte); | 375 | goto out_set_pte; |
365 | return; | ||
366 | } | 376 | } |
367 | 377 | ||
368 | pfn = pte_pfn(pte); | 378 | pfn = pte_pfn(pte); |
@@ -375,10 +385,8 @@ copy_one_pte(struct mm_struct *dst_mm, struct mm_struct *src_mm, | |||
375 | if (pfn_valid(pfn)) | 385 | if (pfn_valid(pfn)) |
376 | page = pfn_to_page(pfn); | 386 | page = pfn_to_page(pfn); |
377 | 387 | ||
378 | if (!page || PageReserved(page)) { | 388 | if (!page || PageReserved(page)) |
379 | set_pte_at(dst_mm, addr, dst_pte, pte); | 389 | goto out_set_pte; |
380 | return; | ||
381 | } | ||
382 | 390 | ||
383 | /* | 391 | /* |
384 | * If it's a COW mapping, write protect it both | 392 | * If it's a COW mapping, write protect it both |
@@ -397,12 +405,12 @@ copy_one_pte(struct mm_struct *dst_mm, struct mm_struct *src_mm, | |||
397 | pte = pte_mkclean(pte); | 405 | pte = pte_mkclean(pte); |
398 | pte = pte_mkold(pte); | 406 | pte = pte_mkold(pte); |
399 | get_page(page); | 407 | get_page(page); |
400 | if (PageAnon(page)) | ||
401 | inc_mm_counter(dst_mm, anon_rss); | ||
402 | else | ||
403 | inc_mm_counter(dst_mm, file_rss); | ||
404 | set_pte_at(dst_mm, addr, dst_pte, pte); | ||
405 | page_dup_rmap(page); | 408 | page_dup_rmap(page); |
409 | anon = !!PageAnon(page); | ||
410 | |||
411 | out_set_pte: | ||
412 | set_pte_at(dst_mm, addr, dst_pte, pte); | ||
413 | return anon; | ||
406 | } | 414 | } |
407 | 415 | ||
408 | static int copy_pte_range(struct mm_struct *dst_mm, struct mm_struct *src_mm, | 416 | static int copy_pte_range(struct mm_struct *dst_mm, struct mm_struct *src_mm, |
@@ -412,8 +420,10 @@ static int copy_pte_range(struct mm_struct *dst_mm, struct mm_struct *src_mm, | |||
412 | pte_t *src_pte, *dst_pte; | 420 | pte_t *src_pte, *dst_pte; |
413 | unsigned long vm_flags = vma->vm_flags; | 421 | unsigned long vm_flags = vma->vm_flags; |
414 | int progress = 0; | 422 | int progress = 0; |
423 | int rss[NO_RSS+1], anon; | ||
415 | 424 | ||
416 | again: | 425 | again: |
426 | rss[1] = rss[0] = 0; | ||
417 | dst_pte = pte_alloc_map(dst_mm, dst_pmd, addr); | 427 | dst_pte = pte_alloc_map(dst_mm, dst_pmd, addr); |
418 | if (!dst_pte) | 428 | if (!dst_pte) |
419 | return -ENOMEM; | 429 | return -ENOMEM; |
@@ -436,13 +446,16 @@ again: | |||
436 | progress++; | 446 | progress++; |
437 | continue; | 447 | continue; |
438 | } | 448 | } |
439 | copy_one_pte(dst_mm, src_mm, dst_pte, src_pte, vm_flags, addr); | 449 | anon = copy_one_pte(dst_mm, src_mm, dst_pte, src_pte, |
450 | vm_flags, addr); | ||
451 | rss[anon]++; | ||
440 | progress += 8; | 452 | progress += 8; |
441 | } while (dst_pte++, src_pte++, addr += PAGE_SIZE, addr != end); | 453 | } while (dst_pte++, src_pte++, addr += PAGE_SIZE, addr != end); |
442 | spin_unlock(&src_mm->page_table_lock); | 454 | spin_unlock(&src_mm->page_table_lock); |
443 | 455 | ||
444 | pte_unmap_nested(src_pte - 1); | 456 | pte_unmap_nested(src_pte - 1); |
445 | pte_unmap(dst_pte - 1); | 457 | pte_unmap(dst_pte - 1); |
458 | add_mm_rss(dst_mm, rss[0], rss[1]); | ||
446 | cond_resched_lock(&dst_mm->page_table_lock); | 459 | cond_resched_lock(&dst_mm->page_table_lock); |
447 | if (addr != end) | 460 | if (addr != end) |
448 | goto again; | 461 | goto again; |
@@ -533,6 +546,8 @@ static void zap_pte_range(struct mmu_gather *tlb, pmd_t *pmd, | |||
533 | struct zap_details *details) | 546 | struct zap_details *details) |
534 | { | 547 | { |
535 | pte_t *pte; | 548 | pte_t *pte; |
549 | int file_rss = 0; | ||
550 | int anon_rss = 0; | ||
536 | 551 | ||
537 | pte = pte_offset_map(pmd, addr); | 552 | pte = pte_offset_map(pmd, addr); |
538 | do { | 553 | do { |
@@ -576,13 +591,13 @@ static void zap_pte_range(struct mmu_gather *tlb, pmd_t *pmd, | |||
576 | set_pte_at(tlb->mm, addr, pte, | 591 | set_pte_at(tlb->mm, addr, pte, |
577 | pgoff_to_pte(page->index)); | 592 | pgoff_to_pte(page->index)); |
578 | if (PageAnon(page)) | 593 | if (PageAnon(page)) |
579 | dec_mm_counter(tlb->mm, anon_rss); | 594 | anon_rss++; |
580 | else { | 595 | else { |
581 | if (pte_dirty(ptent)) | 596 | if (pte_dirty(ptent)) |
582 | set_page_dirty(page); | 597 | set_page_dirty(page); |
583 | if (pte_young(ptent)) | 598 | if (pte_young(ptent)) |
584 | mark_page_accessed(page); | 599 | mark_page_accessed(page); |
585 | dec_mm_counter(tlb->mm, file_rss); | 600 | file_rss++; |
586 | } | 601 | } |
587 | page_remove_rmap(page); | 602 | page_remove_rmap(page); |
588 | tlb_remove_page(tlb, page); | 603 | tlb_remove_page(tlb, page); |
@@ -598,6 +613,8 @@ static void zap_pte_range(struct mmu_gather *tlb, pmd_t *pmd, | |||
598 | free_swap_and_cache(pte_to_swp_entry(ptent)); | 613 | free_swap_and_cache(pte_to_swp_entry(ptent)); |
599 | pte_clear_full(tlb->mm, addr, pte, tlb->fullmm); | 614 | pte_clear_full(tlb->mm, addr, pte, tlb->fullmm); |
600 | } while (pte++, addr += PAGE_SIZE, addr != end); | 615 | } while (pte++, addr += PAGE_SIZE, addr != end); |
616 | |||
617 | add_mm_rss(tlb->mm, -file_rss, -anon_rss); | ||
601 | pte_unmap(pte - 1); | 618 | pte_unmap(pte - 1); |
602 | } | 619 | } |
603 | 620 | ||