diff options
Diffstat (limited to 'mm/swapfile.c')
-rw-r--r-- | mm/swapfile.c | 24 |
1 files changed, 19 insertions, 5 deletions
diff --git a/mm/swapfile.c b/mm/swapfile.c index eec5ca758a23..da422c47e2ee 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <asm/pgtable.h> | 33 | #include <asm/pgtable.h> |
34 | #include <asm/tlbflush.h> | 34 | #include <asm/tlbflush.h> |
35 | #include <linux/swapops.h> | 35 | #include <linux/swapops.h> |
36 | #include <linux/page_cgroup.h> | ||
36 | 37 | ||
37 | static DEFINE_SPINLOCK(swap_lock); | 38 | static DEFINE_SPINLOCK(swap_lock); |
38 | static unsigned int nr_swapfiles; | 39 | static unsigned int nr_swapfiles; |
@@ -470,8 +471,9 @@ out: | |||
470 | return NULL; | 471 | return NULL; |
471 | } | 472 | } |
472 | 473 | ||
473 | static int swap_entry_free(struct swap_info_struct *p, unsigned long offset) | 474 | static int swap_entry_free(struct swap_info_struct *p, swp_entry_t ent) |
474 | { | 475 | { |
476 | unsigned long offset = swp_offset(ent); | ||
475 | int count = p->swap_map[offset]; | 477 | int count = p->swap_map[offset]; |
476 | 478 | ||
477 | if (count < SWAP_MAP_MAX) { | 479 | if (count < SWAP_MAP_MAX) { |
@@ -486,6 +488,7 @@ static int swap_entry_free(struct swap_info_struct *p, unsigned long offset) | |||
486 | swap_list.next = p - swap_info; | 488 | swap_list.next = p - swap_info; |
487 | nr_swap_pages++; | 489 | nr_swap_pages++; |
488 | p->inuse_pages--; | 490 | p->inuse_pages--; |
491 | mem_cgroup_uncharge_swap(ent); | ||
489 | } | 492 | } |
490 | } | 493 | } |
491 | return count; | 494 | return count; |
@@ -501,7 +504,7 @@ void swap_free(swp_entry_t entry) | |||
501 | 504 | ||
502 | p = swap_info_get(entry); | 505 | p = swap_info_get(entry); |
503 | if (p) { | 506 | if (p) { |
504 | swap_entry_free(p, swp_offset(entry)); | 507 | swap_entry_free(p, entry); |
505 | spin_unlock(&swap_lock); | 508 | spin_unlock(&swap_lock); |
506 | } | 509 | } |
507 | } | 510 | } |
@@ -581,7 +584,7 @@ int free_swap_and_cache(swp_entry_t entry) | |||
581 | 584 | ||
582 | p = swap_info_get(entry); | 585 | p = swap_info_get(entry); |
583 | if (p) { | 586 | if (p) { |
584 | if (swap_entry_free(p, swp_offset(entry)) == 1) { | 587 | if (swap_entry_free(p, entry) == 1) { |
585 | page = find_get_page(&swapper_space, entry.val); | 588 | page = find_get_page(&swapper_space, entry.val); |
586 | if (page && !trylock_page(page)) { | 589 | if (page && !trylock_page(page)) { |
587 | page_cache_release(page); | 590 | page_cache_release(page); |
@@ -690,17 +693,18 @@ unsigned int count_swap_pages(int type, int free) | |||
690 | static int unuse_pte(struct vm_area_struct *vma, pmd_t *pmd, | 693 | static int unuse_pte(struct vm_area_struct *vma, pmd_t *pmd, |
691 | unsigned long addr, swp_entry_t entry, struct page *page) | 694 | unsigned long addr, swp_entry_t entry, struct page *page) |
692 | { | 695 | { |
696 | struct mem_cgroup *ptr = NULL; | ||
693 | spinlock_t *ptl; | 697 | spinlock_t *ptl; |
694 | pte_t *pte; | 698 | pte_t *pte; |
695 | int ret = 1; | 699 | int ret = 1; |
696 | 700 | ||
697 | if (mem_cgroup_charge(page, vma->vm_mm, GFP_KERNEL)) | 701 | if (mem_cgroup_try_charge_swapin(vma->vm_mm, page, GFP_KERNEL, &ptr)) |
698 | ret = -ENOMEM; | 702 | ret = -ENOMEM; |
699 | 703 | ||
700 | pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl); | 704 | pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl); |
701 | if (unlikely(!pte_same(*pte, swp_entry_to_pte(entry)))) { | 705 | if (unlikely(!pte_same(*pte, swp_entry_to_pte(entry)))) { |
702 | if (ret > 0) | 706 | if (ret > 0) |
703 | mem_cgroup_uncharge_page(page); | 707 | mem_cgroup_cancel_charge_swapin(ptr); |
704 | ret = 0; | 708 | ret = 0; |
705 | goto out; | 709 | goto out; |
706 | } | 710 | } |
@@ -710,6 +714,7 @@ static int unuse_pte(struct vm_area_struct *vma, pmd_t *pmd, | |||
710 | set_pte_at(vma->vm_mm, addr, pte, | 714 | set_pte_at(vma->vm_mm, addr, pte, |
711 | pte_mkold(mk_pte(page, vma->vm_page_prot))); | 715 | pte_mkold(mk_pte(page, vma->vm_page_prot))); |
712 | page_add_anon_rmap(page, vma, addr); | 716 | page_add_anon_rmap(page, vma, addr); |
717 | mem_cgroup_commit_charge_swapin(page, ptr); | ||
713 | swap_free(entry); | 718 | swap_free(entry); |
714 | /* | 719 | /* |
715 | * Move the page to the active list so it is not | 720 | * Move the page to the active list so it is not |
@@ -1492,6 +1497,9 @@ asmlinkage long sys_swapoff(const char __user * specialfile) | |||
1492 | spin_unlock(&swap_lock); | 1497 | spin_unlock(&swap_lock); |
1493 | mutex_unlock(&swapon_mutex); | 1498 | mutex_unlock(&swapon_mutex); |
1494 | vfree(swap_map); | 1499 | vfree(swap_map); |
1500 | /* Destroy swap account informatin */ | ||
1501 | swap_cgroup_swapoff(type); | ||
1502 | |||
1495 | inode = mapping->host; | 1503 | inode = mapping->host; |
1496 | if (S_ISBLK(inode->i_mode)) { | 1504 | if (S_ISBLK(inode->i_mode)) { |
1497 | struct block_device *bdev = I_BDEV(inode); | 1505 | struct block_device *bdev = I_BDEV(inode); |
@@ -1809,6 +1817,11 @@ asmlinkage long sys_swapon(const char __user * specialfile, int swap_flags) | |||
1809 | } | 1817 | } |
1810 | swap_map[page_nr] = SWAP_MAP_BAD; | 1818 | swap_map[page_nr] = SWAP_MAP_BAD; |
1811 | } | 1819 | } |
1820 | |||
1821 | error = swap_cgroup_swapon(type, maxpages); | ||
1822 | if (error) | ||
1823 | goto bad_swap; | ||
1824 | |||
1812 | nr_good_pages = swap_header->info.last_page - | 1825 | nr_good_pages = swap_header->info.last_page - |
1813 | swap_header->info.nr_badpages - | 1826 | swap_header->info.nr_badpages - |
1814 | 1 /* header page */; | 1827 | 1 /* header page */; |
@@ -1880,6 +1893,7 @@ bad_swap: | |||
1880 | bd_release(bdev); | 1893 | bd_release(bdev); |
1881 | } | 1894 | } |
1882 | destroy_swap_extents(p); | 1895 | destroy_swap_extents(p); |
1896 | swap_cgroup_swapoff(type); | ||
1883 | bad_swap_2: | 1897 | bad_swap_2: |
1884 | spin_lock(&swap_lock); | 1898 | spin_lock(&swap_lock); |
1885 | p->swap_file = NULL; | 1899 | p->swap_file = NULL; |