diff options
Diffstat (limited to 'mm')
-rw-r--r-- | mm/shmem.c | 32 |
1 files changed, 22 insertions, 10 deletions
diff --git a/mm/shmem.c b/mm/shmem.c index dc17551d060a..9e755c166cc5 100644 --- a/mm/shmem.c +++ b/mm/shmem.c | |||
@@ -1407,20 +1407,14 @@ repeat: | |||
1407 | if (sbinfo->max_blocks) { | 1407 | if (sbinfo->max_blocks) { |
1408 | if (percpu_counter_compare(&sbinfo->used_blocks, | 1408 | if (percpu_counter_compare(&sbinfo->used_blocks, |
1409 | sbinfo->max_blocks) >= 0 || | 1409 | sbinfo->max_blocks) >= 0 || |
1410 | shmem_acct_block(info->flags)) { | 1410 | shmem_acct_block(info->flags)) |
1411 | spin_unlock(&info->lock); | 1411 | goto nospace; |
1412 | error = -ENOSPC; | ||
1413 | goto failed; | ||
1414 | } | ||
1415 | percpu_counter_inc(&sbinfo->used_blocks); | 1412 | percpu_counter_inc(&sbinfo->used_blocks); |
1416 | spin_lock(&inode->i_lock); | 1413 | spin_lock(&inode->i_lock); |
1417 | inode->i_blocks += BLOCKS_PER_PAGE; | 1414 | inode->i_blocks += BLOCKS_PER_PAGE; |
1418 | spin_unlock(&inode->i_lock); | 1415 | spin_unlock(&inode->i_lock); |
1419 | } else if (shmem_acct_block(info->flags)) { | 1416 | } else if (shmem_acct_block(info->flags)) |
1420 | spin_unlock(&info->lock); | 1417 | goto nospace; |
1421 | error = -ENOSPC; | ||
1422 | goto failed; | ||
1423 | } | ||
1424 | 1418 | ||
1425 | if (!filepage) { | 1419 | if (!filepage) { |
1426 | int ret; | 1420 | int ret; |
@@ -1500,6 +1494,24 @@ done: | |||
1500 | error = 0; | 1494 | error = 0; |
1501 | goto out; | 1495 | goto out; |
1502 | 1496 | ||
1497 | nospace: | ||
1498 | /* | ||
1499 | * Perhaps the page was brought in from swap between find_lock_page | ||
1500 | * and taking info->lock? We allow for that at add_to_page_cache_lru, | ||
1501 | * but must also avoid reporting a spurious ENOSPC while working on a | ||
1502 | * full tmpfs. (When filepage has been passed in to shmem_getpage, it | ||
1503 | * is already in page cache, which prevents this race from occurring.) | ||
1504 | */ | ||
1505 | if (!filepage) { | ||
1506 | struct page *page = find_get_page(mapping, idx); | ||
1507 | if (page) { | ||
1508 | spin_unlock(&info->lock); | ||
1509 | page_cache_release(page); | ||
1510 | goto repeat; | ||
1511 | } | ||
1512 | } | ||
1513 | spin_unlock(&info->lock); | ||
1514 | error = -ENOSPC; | ||
1503 | failed: | 1515 | failed: |
1504 | if (*pagep != filepage) { | 1516 | if (*pagep != filepage) { |
1505 | unlock_page(filepage); | 1517 | unlock_page(filepage); |