diff options
Diffstat (limited to 'mm/shmem.c')
-rw-r--r-- | mm/shmem.c | 37 |
1 files changed, 23 insertions, 14 deletions
diff --git a/mm/shmem.c b/mm/shmem.c index 302d1cf7ad07..1f1a8085538b 100644 --- a/mm/shmem.c +++ b/mm/shmem.c | |||
@@ -621,7 +621,7 @@ static int shmem_unuse_inode(struct shmem_inode_info *info, | |||
621 | radswap = swp_to_radix_entry(swap); | 621 | radswap = swp_to_radix_entry(swap); |
622 | index = radix_tree_locate_item(&mapping->page_tree, radswap); | 622 | index = radix_tree_locate_item(&mapping->page_tree, radswap); |
623 | if (index == -1) | 623 | if (index == -1) |
624 | return 0; | 624 | return -EAGAIN; /* tell shmem_unuse we found nothing */ |
625 | 625 | ||
626 | /* | 626 | /* |
627 | * Move _head_ to start search for next from here. | 627 | * Move _head_ to start search for next from here. |
@@ -680,7 +680,6 @@ static int shmem_unuse_inode(struct shmem_inode_info *info, | |||
680 | spin_unlock(&info->lock); | 680 | spin_unlock(&info->lock); |
681 | swap_free(swap); | 681 | swap_free(swap); |
682 | } | 682 | } |
683 | error = 1; /* not an error, but entry was found */ | ||
684 | } | 683 | } |
685 | return error; | 684 | return error; |
686 | } | 685 | } |
@@ -692,7 +691,7 @@ int shmem_unuse(swp_entry_t swap, struct page *page) | |||
692 | { | 691 | { |
693 | struct list_head *this, *next; | 692 | struct list_head *this, *next; |
694 | struct shmem_inode_info *info; | 693 | struct shmem_inode_info *info; |
695 | int found = 0; | 694 | struct mem_cgroup *memcg; |
696 | int error = 0; | 695 | int error = 0; |
697 | 696 | ||
698 | /* | 697 | /* |
@@ -707,26 +706,32 @@ int shmem_unuse(swp_entry_t swap, struct page *page) | |||
707 | * the shmem_swaplist_mutex which might hold up shmem_writepage(). | 706 | * the shmem_swaplist_mutex which might hold up shmem_writepage(). |
708 | * Charged back to the user (not to caller) when swap account is used. | 707 | * Charged back to the user (not to caller) when swap account is used. |
709 | */ | 708 | */ |
710 | error = mem_cgroup_charge_file(page, current->mm, GFP_KERNEL); | 709 | error = mem_cgroup_try_charge(page, current->mm, GFP_KERNEL, &memcg); |
711 | if (error) | 710 | if (error) |
712 | goto out; | 711 | goto out; |
713 | /* No radix_tree_preload: swap entry keeps a place for page in tree */ | 712 | /* No radix_tree_preload: swap entry keeps a place for page in tree */ |
713 | error = -EAGAIN; | ||
714 | 714 | ||
715 | mutex_lock(&shmem_swaplist_mutex); | 715 | mutex_lock(&shmem_swaplist_mutex); |
716 | list_for_each_safe(this, next, &shmem_swaplist) { | 716 | list_for_each_safe(this, next, &shmem_swaplist) { |
717 | info = list_entry(this, struct shmem_inode_info, swaplist); | 717 | info = list_entry(this, struct shmem_inode_info, swaplist); |
718 | if (info->swapped) | 718 | if (info->swapped) |
719 | found = shmem_unuse_inode(info, swap, &page); | 719 | error = shmem_unuse_inode(info, swap, &page); |
720 | else | 720 | else |
721 | list_del_init(&info->swaplist); | 721 | list_del_init(&info->swaplist); |
722 | cond_resched(); | 722 | cond_resched(); |
723 | if (found) | 723 | if (error != -EAGAIN) |
724 | break; | 724 | break; |
725 | /* found nothing in this: move on to search the next */ | ||
725 | } | 726 | } |
726 | mutex_unlock(&shmem_swaplist_mutex); | 727 | mutex_unlock(&shmem_swaplist_mutex); |
727 | 728 | ||
728 | if (found < 0) | 729 | if (error) { |
729 | error = found; | 730 | if (error != -ENOMEM) |
731 | error = 0; | ||
732 | mem_cgroup_cancel_charge(page, memcg); | ||
733 | } else | ||
734 | mem_cgroup_commit_charge(page, memcg, true); | ||
730 | out: | 735 | out: |
731 | unlock_page(page); | 736 | unlock_page(page); |
732 | page_cache_release(page); | 737 | page_cache_release(page); |
@@ -1030,6 +1035,7 @@ static int shmem_getpage_gfp(struct inode *inode, pgoff_t index, | |||
1030 | struct address_space *mapping = inode->i_mapping; | 1035 | struct address_space *mapping = inode->i_mapping; |
1031 | struct shmem_inode_info *info; | 1036 | struct shmem_inode_info *info; |
1032 | struct shmem_sb_info *sbinfo; | 1037 | struct shmem_sb_info *sbinfo; |
1038 | struct mem_cgroup *memcg; | ||
1033 | struct page *page; | 1039 | struct page *page; |
1034 | swp_entry_t swap; | 1040 | swp_entry_t swap; |
1035 | int error; | 1041 | int error; |
@@ -1108,8 +1114,7 @@ repeat: | |||
1108 | goto failed; | 1114 | goto failed; |
1109 | } | 1115 | } |
1110 | 1116 | ||
1111 | error = mem_cgroup_charge_file(page, current->mm, | 1117 | error = mem_cgroup_try_charge(page, current->mm, gfp, &memcg); |
1112 | gfp & GFP_RECLAIM_MASK); | ||
1113 | if (!error) { | 1118 | if (!error) { |
1114 | error = shmem_add_to_page_cache(page, mapping, index, | 1119 | error = shmem_add_to_page_cache(page, mapping, index, |
1115 | swp_to_radix_entry(swap)); | 1120 | swp_to_radix_entry(swap)); |
@@ -1125,12 +1130,16 @@ repeat: | |||
1125 | * Reset swap.val? No, leave it so "failed" goes back to | 1130 | * Reset swap.val? No, leave it so "failed" goes back to |
1126 | * "repeat": reading a hole and writing should succeed. | 1131 | * "repeat": reading a hole and writing should succeed. |
1127 | */ | 1132 | */ |
1128 | if (error) | 1133 | if (error) { |
1134 | mem_cgroup_cancel_charge(page, memcg); | ||
1129 | delete_from_swap_cache(page); | 1135 | delete_from_swap_cache(page); |
1136 | } | ||
1130 | } | 1137 | } |
1131 | if (error) | 1138 | if (error) |
1132 | goto failed; | 1139 | goto failed; |
1133 | 1140 | ||
1141 | mem_cgroup_commit_charge(page, memcg, true); | ||
1142 | |||
1134 | spin_lock(&info->lock); | 1143 | spin_lock(&info->lock); |
1135 | info->swapped--; | 1144 | info->swapped--; |
1136 | shmem_recalc_inode(inode); | 1145 | shmem_recalc_inode(inode); |
@@ -1168,8 +1177,7 @@ repeat: | |||
1168 | if (sgp == SGP_WRITE) | 1177 | if (sgp == SGP_WRITE) |
1169 | __SetPageReferenced(page); | 1178 | __SetPageReferenced(page); |
1170 | 1179 | ||
1171 | error = mem_cgroup_charge_file(page, current->mm, | 1180 | error = mem_cgroup_try_charge(page, current->mm, gfp, &memcg); |
1172 | gfp & GFP_RECLAIM_MASK); | ||
1173 | if (error) | 1181 | if (error) |
1174 | goto decused; | 1182 | goto decused; |
1175 | error = radix_tree_maybe_preload(gfp & GFP_RECLAIM_MASK); | 1183 | error = radix_tree_maybe_preload(gfp & GFP_RECLAIM_MASK); |
@@ -1179,9 +1187,10 @@ repeat: | |||
1179 | radix_tree_preload_end(); | 1187 | radix_tree_preload_end(); |
1180 | } | 1188 | } |
1181 | if (error) { | 1189 | if (error) { |
1182 | mem_cgroup_uncharge_cache_page(page); | 1190 | mem_cgroup_cancel_charge(page, memcg); |
1183 | goto decused; | 1191 | goto decused; |
1184 | } | 1192 | } |
1193 | mem_cgroup_commit_charge(page, memcg, false); | ||
1185 | lru_cache_add_anon(page); | 1194 | lru_cache_add_anon(page); |
1186 | 1195 | ||
1187 | spin_lock(&info->lock); | 1196 | spin_lock(&info->lock); |