Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 258969
b: refs/heads/master
c: 27ab700
h: refs/heads/master
i:
  258967: 0d44296
v: v3
  • Loading branch information
Hugh Dickins authored and Linus Torvalds committed Jul 26, 2011
1 parent b96cc00 commit 355d685
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 130 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: e83c32e8f92724a06a22a3b42f3afc07db93e131
refs/heads/master: 27ab700626f048407e9466d389a43c7d3aa45967
237 changes: 108 additions & 129 deletions trunk/mm/shmem.c
Original file line number Diff line number Diff line change
Expand Up @@ -1246,63 +1246,69 @@ static int shmem_getpage_gfp(struct inode *inode, pgoff_t idx,
struct address_space *mapping = inode->i_mapping;
struct shmem_inode_info *info = SHMEM_I(inode);
struct shmem_sb_info *sbinfo;
struct page *filepage;
struct page *swappage;
struct page *page;
struct page *prealloc_page = NULL;
swp_entry_t *entry;
swp_entry_t swap;
int error;
int ret;

if (idx >= SHMEM_MAX_INDEX)
return -EFBIG;
repeat:
filepage = find_lock_page(mapping, idx);
if (filepage && PageUptodate(filepage))
goto done;
if (!filepage) {
page = find_lock_page(mapping, idx);
if (page) {
/*
* Try to preload while we can wait, to not make a habit of
* draining atomic reserves; but don't latch on to this cpu.
* Once we can get the page lock, it must be uptodate:
* if there were an error in reading back from swap,
* the page would not be inserted into the filecache.
*/
error = radix_tree_preload(gfp & GFP_RECLAIM_MASK);
if (error)
goto failed;
radix_tree_preload_end();
if (sgp != SGP_READ && !prealloc_page) {
prealloc_page = shmem_alloc_page(gfp, info, idx);
if (prealloc_page) {
SetPageSwapBacked(prealloc_page);
if (mem_cgroup_cache_charge(prealloc_page,
current->mm, GFP_KERNEL)) {
page_cache_release(prealloc_page);
prealloc_page = NULL;
}
BUG_ON(!PageUptodate(page));
goto done;
}

/*
* Try to preload while we can wait, to not make a habit of
* draining atomic reserves; but don't latch on to this cpu.
*/
error = radix_tree_preload(gfp & GFP_RECLAIM_MASK);
if (error)
goto out;
radix_tree_preload_end();

if (sgp != SGP_READ && !prealloc_page) {
prealloc_page = shmem_alloc_page(gfp, info, idx);
if (prealloc_page) {
SetPageSwapBacked(prealloc_page);
if (mem_cgroup_cache_charge(prealloc_page,
current->mm, GFP_KERNEL)) {
page_cache_release(prealloc_page);
prealloc_page = NULL;
}
}
}
error = 0;

spin_lock(&info->lock);
shmem_recalc_inode(inode);
entry = shmem_swp_alloc(info, idx, sgp, gfp);
if (IS_ERR(entry)) {
spin_unlock(&info->lock);
error = PTR_ERR(entry);
goto failed;
goto out;
}
swap = *entry;

if (swap.val) {
/* Look it up and read it in.. */
swappage = lookup_swap_cache(swap);
if (!swappage) {
page = lookup_swap_cache(swap);
if (!page) {
shmem_swp_unmap(entry);
spin_unlock(&info->lock);
/* here we actually do the io */
if (fault_type)
*fault_type |= VM_FAULT_MAJOR;
swappage = shmem_swapin(swap, gfp, info, idx);
if (!swappage) {
page = shmem_swapin(swap, gfp, info, idx);
if (!page) {
spin_lock(&info->lock);
entry = shmem_swp_alloc(info, idx, sgp, gfp);
if (IS_ERR(entry))
Expand All @@ -1314,62 +1320,42 @@ static int shmem_getpage_gfp(struct inode *inode, pgoff_t idx,
}
spin_unlock(&info->lock);
if (error)
goto failed;
goto out;
goto repeat;
}
wait_on_page_locked(swappage);
page_cache_release(swappage);
wait_on_page_locked(page);
page_cache_release(page);
goto repeat;
}

/* We have to do this with page locked to prevent races */
if (!trylock_page(swappage)) {
if (!trylock_page(page)) {
shmem_swp_unmap(entry);
spin_unlock(&info->lock);
wait_on_page_locked(swappage);
page_cache_release(swappage);
wait_on_page_locked(page);
page_cache_release(page);
goto repeat;
}
if (PageWriteback(swappage)) {
if (PageWriteback(page)) {
shmem_swp_unmap(entry);
spin_unlock(&info->lock);
wait_on_page_writeback(swappage);
unlock_page(swappage);
page_cache_release(swappage);
wait_on_page_writeback(page);
unlock_page(page);
page_cache_release(page);
goto repeat;
}
if (!PageUptodate(swappage)) {
if (!PageUptodate(page)) {
shmem_swp_unmap(entry);
spin_unlock(&info->lock);
unlock_page(swappage);
page_cache_release(swappage);
unlock_page(page);
page_cache_release(page);
error = -EIO;
goto failed;
goto out;
}

if (filepage) {
shmem_swp_set(info, entry, 0);
shmem_swp_unmap(entry);
delete_from_swap_cache(swappage);
spin_unlock(&info->lock);
copy_highpage(filepage, swappage);
unlock_page(swappage);
page_cache_release(swappage);
flush_dcache_page(filepage);
SetPageUptodate(filepage);
set_page_dirty(filepage);
swap_free(swap);
} else if (!(error = add_to_page_cache_locked(swappage, mapping,
idx, GFP_NOWAIT))) {
info->flags |= SHMEM_PAGEIN;
shmem_swp_set(info, entry, 0);
shmem_swp_unmap(entry);
delete_from_swap_cache(swappage);
spin_unlock(&info->lock);
filepage = swappage;
set_page_dirty(filepage);
swap_free(swap);
} else {
error = add_to_page_cache_locked(page, mapping,
idx, GFP_NOWAIT);
if (error) {
shmem_swp_unmap(entry);
spin_unlock(&info->lock);
if (error == -ENOMEM) {
Expand All @@ -1378,28 +1364,33 @@ static int shmem_getpage_gfp(struct inode *inode, pgoff_t idx,
* call memcg's OOM if needed.
*/
error = mem_cgroup_shmem_charge_fallback(
swappage,
current->mm,
gfp);
page, current->mm, gfp);
if (error) {
unlock_page(swappage);
page_cache_release(swappage);
goto failed;
unlock_page(page);
page_cache_release(page);
goto out;
}
}
unlock_page(swappage);
page_cache_release(swappage);
unlock_page(page);
page_cache_release(page);
goto repeat;
}
} else if (sgp == SGP_READ && !filepage) {

info->flags |= SHMEM_PAGEIN;
shmem_swp_set(info, entry, 0);
shmem_swp_unmap(entry);
filepage = find_get_page(mapping, idx);
if (filepage &&
(!PageUptodate(filepage) || !trylock_page(filepage))) {
delete_from_swap_cache(page);
spin_unlock(&info->lock);
set_page_dirty(page);
swap_free(swap);

} else if (sgp == SGP_READ) {
shmem_swp_unmap(entry);
page = find_get_page(mapping, idx);
if (page && !trylock_page(page)) {
spin_unlock(&info->lock);
wait_on_page_locked(filepage);
page_cache_release(filepage);
filepage = NULL;
wait_on_page_locked(page);
page_cache_release(page);
goto repeat;
}
spin_unlock(&info->lock);
Expand All @@ -1417,56 +1408,52 @@ static int shmem_getpage_gfp(struct inode *inode, pgoff_t idx,
} else if (shmem_acct_block(info->flags))
goto nospace;

if (!filepage) {
int ret;
page = prealloc_page;
prealloc_page = NULL;

filepage = prealloc_page;
prealloc_page = NULL;

entry = shmem_swp_alloc(info, idx, sgp, gfp);
if (IS_ERR(entry))
error = PTR_ERR(entry);
else {
swap = *entry;
shmem_swp_unmap(entry);
}
ret = error || swap.val;
if (ret)
mem_cgroup_uncharge_cache_page(filepage);
else
ret = add_to_page_cache_lru(filepage, mapping,
entry = shmem_swp_alloc(info, idx, sgp, gfp);
if (IS_ERR(entry))
error = PTR_ERR(entry);
else {
swap = *entry;
shmem_swp_unmap(entry);
}
ret = error || swap.val;
if (ret)
mem_cgroup_uncharge_cache_page(page);
else
ret = add_to_page_cache_lru(page, mapping,
idx, GFP_NOWAIT);
/*
* At add_to_page_cache_lru() failure, uncharge will
* be done automatically.
*/
if (ret) {
shmem_unacct_blocks(info->flags, 1);
shmem_free_blocks(inode, 1);
spin_unlock(&info->lock);
page_cache_release(filepage);
filepage = NULL;
if (error)
goto failed;
goto repeat;
}
info->flags |= SHMEM_PAGEIN;
/*
* At add_to_page_cache_lru() failure,
* uncharge will be done automatically.
*/
if (ret) {
shmem_unacct_blocks(info->flags, 1);
shmem_free_blocks(inode, 1);
spin_unlock(&info->lock);
page_cache_release(page);
if (error)
goto out;
goto repeat;
}

info->flags |= SHMEM_PAGEIN;
info->alloced++;
spin_unlock(&info->lock);
clear_highpage(filepage);
flush_dcache_page(filepage);
SetPageUptodate(filepage);
clear_highpage(page);
flush_dcache_page(page);
SetPageUptodate(page);
if (sgp == SGP_DIRTY)
set_page_dirty(filepage);
set_page_dirty(page);

} else {
spin_unlock(&info->lock);
error = -ENOMEM;
goto out;
}
done:
*pagep = filepage;
*pagep = page;
error = 0;
out:
if (prealloc_page) {
Expand All @@ -1482,21 +1469,13 @@ static int shmem_getpage_gfp(struct inode *inode, pgoff_t idx,
* but must also avoid reporting a spurious ENOSPC while working on a
* full tmpfs.
*/
if (!filepage) {
struct page *page = find_get_page(mapping, idx);
if (page) {
spin_unlock(&info->lock);
page_cache_release(page);
goto repeat;
}
}
page = find_get_page(mapping, idx);
spin_unlock(&info->lock);
error = -ENOSPC;
failed:
if (filepage) {
unlock_page(filepage);
page_cache_release(filepage);
if (page) {
page_cache_release(page);
goto repeat;
}
error = -ENOSPC;
goto out;
}

Expand Down

0 comments on commit 355d685

Please sign in to comment.