diff options
Diffstat (limited to 'mm/shmem.c')
-rw-r--r-- | mm/shmem.c | 44 |
1 files changed, 27 insertions, 17 deletions
diff --git a/mm/shmem.c b/mm/shmem.c index 9ffbea9b79e1..f92fea94d037 100644 --- a/mm/shmem.c +++ b/mm/shmem.c | |||
@@ -922,20 +922,26 @@ found: | |||
922 | error = 1; | 922 | error = 1; |
923 | if (!inode) | 923 | if (!inode) |
924 | goto out; | 924 | goto out; |
925 | /* Precharge page while we can wait, compensate afterwards */ | 925 | /* Precharge page using GFP_KERNEL while we can wait */ |
926 | error = mem_cgroup_cache_charge(page, current->mm, GFP_KERNEL); | 926 | error = mem_cgroup_cache_charge(page, current->mm, GFP_KERNEL); |
927 | if (error) | 927 | if (error) |
928 | goto out; | 928 | goto out; |
929 | error = radix_tree_preload(GFP_KERNEL); | 929 | error = radix_tree_preload(GFP_KERNEL); |
930 | if (error) | 930 | if (error) { |
931 | goto uncharge; | 931 | mem_cgroup_uncharge_cache_page(page); |
932 | goto out; | ||
933 | } | ||
932 | error = 1; | 934 | error = 1; |
933 | 935 | ||
934 | spin_lock(&info->lock); | 936 | spin_lock(&info->lock); |
935 | ptr = shmem_swp_entry(info, idx, NULL); | 937 | ptr = shmem_swp_entry(info, idx, NULL); |
936 | if (ptr && ptr->val == entry.val) | 938 | if (ptr && ptr->val == entry.val) { |
937 | error = add_to_page_cache(page, inode->i_mapping, | 939 | error = add_to_page_cache(page, inode->i_mapping, |
938 | idx, GFP_NOWAIT); | 940 | idx, GFP_NOWAIT); |
941 | /* does mem_cgroup_uncharge_cache_page on error */ | ||
942 | } else /* we must compensate for our precharge above */ | ||
943 | mem_cgroup_uncharge_cache_page(page); | ||
944 | |||
939 | if (error == -EEXIST) { | 945 | if (error == -EEXIST) { |
940 | struct page *filepage = find_get_page(inode->i_mapping, idx); | 946 | struct page *filepage = find_get_page(inode->i_mapping, idx); |
941 | error = 1; | 947 | error = 1; |
@@ -961,8 +967,6 @@ found: | |||
961 | shmem_swp_unmap(ptr); | 967 | shmem_swp_unmap(ptr); |
962 | spin_unlock(&info->lock); | 968 | spin_unlock(&info->lock); |
963 | radix_tree_preload_end(); | 969 | radix_tree_preload_end(); |
964 | uncharge: | ||
965 | mem_cgroup_uncharge_page(page); | ||
966 | out: | 970 | out: |
967 | unlock_page(page); | 971 | unlock_page(page); |
968 | page_cache_release(page); | 972 | page_cache_release(page); |
@@ -1311,17 +1315,14 @@ repeat: | |||
1311 | shmem_swp_unmap(entry); | 1315 | shmem_swp_unmap(entry); |
1312 | spin_unlock(&info->lock); | 1316 | spin_unlock(&info->lock); |
1313 | unlock_page(swappage); | 1317 | unlock_page(swappage); |
1318 | page_cache_release(swappage); | ||
1314 | if (error == -ENOMEM) { | 1319 | if (error == -ENOMEM) { |
1315 | /* allow reclaim from this memory cgroup */ | 1320 | /* allow reclaim from this memory cgroup */ |
1316 | error = mem_cgroup_cache_charge(swappage, | 1321 | error = mem_cgroup_shrink_usage(current->mm, |
1317 | current->mm, gfp & ~__GFP_HIGHMEM); | 1322 | gfp); |
1318 | if (error) { | 1323 | if (error) |
1319 | page_cache_release(swappage); | ||
1320 | goto failed; | 1324 | goto failed; |
1321 | } | ||
1322 | mem_cgroup_uncharge_page(swappage); | ||
1323 | } | 1325 | } |
1324 | page_cache_release(swappage); | ||
1325 | goto repeat; | 1326 | goto repeat; |
1326 | } | 1327 | } |
1327 | } else if (sgp == SGP_READ && !filepage) { | 1328 | } else if (sgp == SGP_READ && !filepage) { |
@@ -1358,6 +1359,8 @@ repeat: | |||
1358 | } | 1359 | } |
1359 | 1360 | ||
1360 | if (!filepage) { | 1361 | if (!filepage) { |
1362 | int ret; | ||
1363 | |||
1361 | spin_unlock(&info->lock); | 1364 | spin_unlock(&info->lock); |
1362 | filepage = shmem_alloc_page(gfp, info, idx); | 1365 | filepage = shmem_alloc_page(gfp, info, idx); |
1363 | if (!filepage) { | 1366 | if (!filepage) { |
@@ -1386,10 +1389,18 @@ repeat: | |||
1386 | swap = *entry; | 1389 | swap = *entry; |
1387 | shmem_swp_unmap(entry); | 1390 | shmem_swp_unmap(entry); |
1388 | } | 1391 | } |
1389 | if (error || swap.val || 0 != add_to_page_cache_lru( | 1392 | ret = error || swap.val; |
1390 | filepage, mapping, idx, GFP_NOWAIT)) { | 1393 | if (ret) |
1394 | mem_cgroup_uncharge_cache_page(filepage); | ||
1395 | else | ||
1396 | ret = add_to_page_cache_lru(filepage, mapping, | ||
1397 | idx, GFP_NOWAIT); | ||
1398 | /* | ||
1399 | * At add_to_page_cache_lru() failure, uncharge will | ||
1400 | * be done automatically. | ||
1401 | */ | ||
1402 | if (ret) { | ||
1391 | spin_unlock(&info->lock); | 1403 | spin_unlock(&info->lock); |
1392 | mem_cgroup_uncharge_page(filepage); | ||
1393 | page_cache_release(filepage); | 1404 | page_cache_release(filepage); |
1394 | shmem_unacct_blocks(info->flags, 1); | 1405 | shmem_unacct_blocks(info->flags, 1); |
1395 | shmem_free_blocks(inode, 1); | 1406 | shmem_free_blocks(inode, 1); |
@@ -1398,7 +1409,6 @@ repeat: | |||
1398 | goto failed; | 1409 | goto failed; |
1399 | goto repeat; | 1410 | goto repeat; |
1400 | } | 1411 | } |
1401 | mem_cgroup_uncharge_page(filepage); | ||
1402 | info->flags |= SHMEM_PAGEIN; | 1412 | info->flags |= SHMEM_PAGEIN; |
1403 | } | 1413 | } |
1404 | 1414 | ||