diff options
Diffstat (limited to 'mm/shmem.c')
-rw-r--r-- | mm/shmem.c | 28 |
1 files changed, 27 insertions, 1 deletions
diff --git a/mm/shmem.c b/mm/shmem.c index 0f246c44a574..85bed948fafc 100644 --- a/mm/shmem.c +++ b/mm/shmem.c | |||
@@ -912,9 +912,13 @@ found: | |||
912 | error = 1; | 912 | error = 1; |
913 | if (!inode) | 913 | if (!inode) |
914 | goto out; | 914 | goto out; |
915 | error = radix_tree_preload(GFP_KERNEL); | 915 | /* Precharge page while we can wait, compensate afterwards */ |
916 | error = mem_cgroup_cache_charge(page, current->mm, GFP_KERNEL); | ||
916 | if (error) | 917 | if (error) |
917 | goto out; | 918 | goto out; |
919 | error = radix_tree_preload(GFP_KERNEL); | ||
920 | if (error) | ||
921 | goto uncharge; | ||
918 | error = 1; | 922 | error = 1; |
919 | 923 | ||
920 | spin_lock(&info->lock); | 924 | spin_lock(&info->lock); |
@@ -947,6 +951,8 @@ found: | |||
947 | shmem_swp_unmap(ptr); | 951 | shmem_swp_unmap(ptr); |
948 | spin_unlock(&info->lock); | 952 | spin_unlock(&info->lock); |
949 | radix_tree_preload_end(); | 953 | radix_tree_preload_end(); |
954 | uncharge: | ||
955 | mem_cgroup_uncharge_page(page); | ||
950 | out: | 956 | out: |
951 | unlock_page(page); | 957 | unlock_page(page); |
952 | page_cache_release(page); | 958 | page_cache_release(page); |
@@ -1308,6 +1314,13 @@ repeat: | |||
1308 | spin_unlock(&info->lock); | 1314 | spin_unlock(&info->lock); |
1309 | unlock_page(swappage); | 1315 | unlock_page(swappage); |
1310 | page_cache_release(swappage); | 1316 | page_cache_release(swappage); |
1317 | if (error == -ENOMEM) { | ||
1318 | /* allow reclaim from this memory cgroup */ | ||
1319 | error = mem_cgroup_cache_charge(NULL, | ||
1320 | current->mm, gfp & ~__GFP_HIGHMEM); | ||
1321 | if (error) | ||
1322 | goto failed; | ||
1323 | } | ||
1311 | goto repeat; | 1324 | goto repeat; |
1312 | } | 1325 | } |
1313 | } else if (sgp == SGP_READ && !filepage) { | 1326 | } else if (sgp == SGP_READ && !filepage) { |
@@ -1353,6 +1366,17 @@ repeat: | |||
1353 | goto failed; | 1366 | goto failed; |
1354 | } | 1367 | } |
1355 | 1368 | ||
1369 | /* Precharge page while we can wait, compensate after */ | ||
1370 | error = mem_cgroup_cache_charge(filepage, current->mm, | ||
1371 | gfp & ~__GFP_HIGHMEM); | ||
1372 | if (error) { | ||
1373 | page_cache_release(filepage); | ||
1374 | shmem_unacct_blocks(info->flags, 1); | ||
1375 | shmem_free_blocks(inode, 1); | ||
1376 | filepage = NULL; | ||
1377 | goto failed; | ||
1378 | } | ||
1379 | |||
1356 | spin_lock(&info->lock); | 1380 | spin_lock(&info->lock); |
1357 | entry = shmem_swp_alloc(info, idx, sgp); | 1381 | entry = shmem_swp_alloc(info, idx, sgp); |
1358 | if (IS_ERR(entry)) | 1382 | if (IS_ERR(entry)) |
@@ -1364,6 +1388,7 @@ repeat: | |||
1364 | if (error || swap.val || 0 != add_to_page_cache_lru( | 1388 | if (error || swap.val || 0 != add_to_page_cache_lru( |
1365 | filepage, mapping, idx, GFP_NOWAIT)) { | 1389 | filepage, mapping, idx, GFP_NOWAIT)) { |
1366 | spin_unlock(&info->lock); | 1390 | spin_unlock(&info->lock); |
1391 | mem_cgroup_uncharge_page(filepage); | ||
1367 | page_cache_release(filepage); | 1392 | page_cache_release(filepage); |
1368 | shmem_unacct_blocks(info->flags, 1); | 1393 | shmem_unacct_blocks(info->flags, 1); |
1369 | shmem_free_blocks(inode, 1); | 1394 | shmem_free_blocks(inode, 1); |
@@ -1372,6 +1397,7 @@ repeat: | |||
1372 | goto failed; | 1397 | goto failed; |
1373 | goto repeat; | 1398 | goto repeat; |
1374 | } | 1399 | } |
1400 | mem_cgroup_uncharge_page(filepage); | ||
1375 | info->flags |= SHMEM_PAGEIN; | 1401 | info->flags |= SHMEM_PAGEIN; |
1376 | } | 1402 | } |
1377 | 1403 | ||