diff options
Diffstat (limited to 'mm')
-rw-r--r-- | mm/memcontrol.c | 37 | ||||
-rw-r--r-- | mm/shmem.c | 28 |
2 files changed, 48 insertions, 17 deletions
diff --git a/mm/memcontrol.c b/mm/memcontrol.c index dbf571547c03..11b23f203d68 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c | |||
@@ -329,23 +329,26 @@ static int mem_cgroup_charge_common(struct page *page, struct mm_struct *mm, | |||
329 | * with it | 329 | * with it |
330 | */ | 330 | */ |
331 | retry: | 331 | retry: |
332 | lock_page_cgroup(page); | 332 | if (page) { |
333 | pc = page_get_page_cgroup(page); | 333 | lock_page_cgroup(page); |
334 | /* | 334 | pc = page_get_page_cgroup(page); |
335 | * The page_cgroup exists and the page has already been accounted | 335 | /* |
336 | */ | 336 | * The page_cgroup exists and |
337 | if (pc) { | 337 | * the page has already been accounted. |
338 | if (unlikely(!atomic_inc_not_zero(&pc->ref_cnt))) { | 338 | */ |
339 | /* this page is under being uncharged ? */ | 339 | if (pc) { |
340 | unlock_page_cgroup(page); | 340 | if (unlikely(!atomic_inc_not_zero(&pc->ref_cnt))) { |
341 | cpu_relax(); | 341 | /* this page is under being uncharged ? */ |
342 | goto retry; | 342 | unlock_page_cgroup(page); |
343 | } else { | 343 | cpu_relax(); |
344 | unlock_page_cgroup(page); | 344 | goto retry; |
345 | goto done; | 345 | } else { |
346 | unlock_page_cgroup(page); | ||
347 | goto done; | ||
348 | } | ||
346 | } | 349 | } |
350 | unlock_page_cgroup(page); | ||
347 | } | 351 | } |
348 | unlock_page_cgroup(page); | ||
349 | 352 | ||
350 | pc = kzalloc(sizeof(struct page_cgroup), gfp_mask); | 353 | pc = kzalloc(sizeof(struct page_cgroup), gfp_mask); |
351 | if (pc == NULL) | 354 | if (pc == NULL) |
@@ -404,7 +407,7 @@ retry: | |||
404 | if (ctype == MEM_CGROUP_CHARGE_TYPE_CACHE) | 407 | if (ctype == MEM_CGROUP_CHARGE_TYPE_CACHE) |
405 | pc->flags |= PAGE_CGROUP_FLAG_CACHE; | 408 | pc->flags |= PAGE_CGROUP_FLAG_CACHE; |
406 | 409 | ||
407 | if (page_cgroup_assign_new_page_cgroup(page, pc)) { | 410 | if (!page || page_cgroup_assign_new_page_cgroup(page, pc)) { |
408 | /* | 411 | /* |
409 | * Another charge has been added to this page already. | 412 | * Another charge has been added to this page already. |
410 | * We take lock_page_cgroup(page) again and read | 413 | * We take lock_page_cgroup(page) again and read |
@@ -413,6 +416,8 @@ retry: | |||
413 | res_counter_uncharge(&mem->res, PAGE_SIZE); | 416 | res_counter_uncharge(&mem->res, PAGE_SIZE); |
414 | css_put(&mem->css); | 417 | css_put(&mem->css); |
415 | kfree(pc); | 418 | kfree(pc); |
419 | if (!page) | ||
420 | goto done; | ||
416 | goto retry; | 421 | goto retry; |
417 | } | 422 | } |
418 | 423 | ||
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 | ||