From: Hugh Dickins <hugh@veritas.com>
To: Andrew Morton <akpm@linux-foundation.org>
Cc: Christoph Rohland <hans-christoph.rohland@sap.com>,
Erez Zadok <ezk@cs.sunysb.edu>,
linux-kernel@vger.kernel.org
Subject: [PATCH 4/9] tmpfs: allow filepage alongside swappage
Date: Tue, 18 Dec 2007 22:01:24 +0000 (GMT) [thread overview]
Message-ID: <Pine.LNX.4.64.0712182200230.27165@blonde.wat.veritas.com> (raw)
In-Reply-To: <Pine.LNX.4.64.0712182144370.26235@blonde.wat.veritas.com>
tmpfs has long allowed for a fresh filepage to be created in pagecache,
just before shmem_getpage gets the chance to match it up with the swappage
which already belongs to that offset. But unionfs_writepage now does a
find_or_create_page, divorced from shmem_getpage, which leaves conflicting
filepage and swappage outstanding indefinitely, when unionfs is over tmpfs.
Therefore shmem_writepage (where a page is swizzled from file to swap) must
now be on the lookout for existing swap, ready to free it in favour of the
more uptodate filepage, instead of BUGging on that clash. And when the
add_to_page_cache fails in shmem_unuse_inode, it must defer to an uptodate
filepage, otherwise swapoff would hang. Whereas when add_to_page_cache
fails in shmem_getpage, it should retry in the same way it already does.
Signed-off-by: Hugh Dickins <hugh@veritas.com>
---
mm/shmem.c | 69 ++++++++++++++++++++++++++++++++-------------------
1 file changed, 44 insertions(+), 25 deletions(-)
--- tmpfs3/mm/shmem.c 2007-12-05 16:42:18.000000000 +0000
+++ tmpfs4/mm/shmem.c 2007-12-05 16:42:19.000000000 +0000
@@ -827,6 +827,7 @@ static int shmem_unuse_inode(struct shme
struct page *subdir;
swp_entry_t *ptr;
int offset;
+ int error;
idx = 0;
ptr = info->i_direct;
@@ -884,7 +885,20 @@ lost2:
found:
idx += offset;
inode = &info->vfs_inode;
- if (add_to_page_cache(page, inode->i_mapping, idx, GFP_ATOMIC) == 0) {
+ error = add_to_page_cache(page, inode->i_mapping, idx, GFP_ATOMIC);
+ if (error == -EEXIST) {
+ struct page *filepage = find_get_page(inode->i_mapping, idx);
+ if (filepage) {
+ /*
+ * There might be a more uptodate page coming down
+ * from a stacked writepage: forget our swappage if so.
+ */
+ if (PageUptodate(filepage))
+ error = 0;
+ page_cache_release(filepage);
+ }
+ }
+ if (!error) {
delete_from_swap_cache(page);
set_page_dirty(page);
info->flags |= SHMEM_PAGEIN;
@@ -937,44 +951,45 @@ static int shmem_writepage(struct page *
struct inode *inode;
BUG_ON(!PageLocked(page));
- /*
- * shmem_backing_dev_info's capabilities prevent regular writeback or
- * sync from ever calling shmem_writepage; but a stacking filesystem
- * may use the ->writepage of its underlying filesystem, in which case
- * we want to do nothing when that underlying filesystem is tmpfs
- * (writing out to swap is useful as a response to memory pressure, but
- * of no use to stabilize the data) - just redirty the page, unlock it
- * and claim success in this case. AOP_WRITEPAGE_ACTIVATE, and the
- * page_mapped check below, must be avoided unless we're in reclaim.
- */
- if (!wbc->for_reclaim) {
- set_page_dirty(page);
- unlock_page(page);
- return 0;
- }
- BUG_ON(page_mapped(page));
-
mapping = page->mapping;
index = page->index;
inode = mapping->host;
info = SHMEM_I(inode);
if (info->flags & VM_LOCKED)
goto redirty;
- swap = get_swap_page();
- if (!swap.val)
+ if (!total_swap_pages)
goto redirty;
+ /*
+ * shmem_backing_dev_info's capabilities prevent regular writeback or
+ * sync from ever calling shmem_writepage; but a stacking filesystem
+ * may use the ->writepage of its underlying filesystem, in which case
+ * tmpfs should write out to swap only in response to memory pressure,
+ * and not for pdflush or sync. However, in those cases, we do still
+ * want to check if there's a redundant swappage to be discarded.
+ */
+ if (wbc->for_reclaim)
+ swap = get_swap_page();
+ else
+ swap.val = 0;
+
spin_lock(&info->lock);
- shmem_recalc_inode(inode);
if (index >= info->next_index) {
BUG_ON(!(info->flags & SHMEM_TRUNCATE));
goto unlock;
}
entry = shmem_swp_entry(info, index, NULL);
- BUG_ON(!entry);
- BUG_ON(entry->val);
+ if (entry->val) {
+ /*
+ * The more uptodate page coming down from a stacked
+ * writepage should replace our old swappage.
+ */
+ free_swap_and_cache(*entry);
+ shmem_swp_set(info, entry, 0);
+ }
+ shmem_recalc_inode(inode);
- if (add_to_swap_cache(page, swap, GFP_ATOMIC) == 0) {
+ if (swap.val && add_to_swap_cache(page, swap, GFP_ATOMIC) == 0) {
remove_from_page_cache(page);
shmem_swp_set(info, entry, swap.val);
shmem_swp_unmap(entry);
@@ -986,6 +1001,7 @@ static int shmem_writepage(struct page *
spin_unlock(&shmem_swaplist_lock);
}
swap_duplicate(swap);
+ BUG_ON(page_mapped(page));
page_cache_release(page); /* pagecache ref */
set_page_dirty(page);
unlock_page(page);
@@ -998,7 +1014,10 @@ unlock:
swap_free(swap);
redirty:
set_page_dirty(page);
- return AOP_WRITEPAGE_ACTIVATE; /* Return with the page locked */
+ if (wbc->for_reclaim)
+ return AOP_WRITEPAGE_ACTIVATE; /* Return with page locked */
+ unlock_page(page);
+ return 0;
}
#ifdef CONFIG_NUMA
next prev parent reply other threads:[~2007-12-18 22:02 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-12-18 21:55 [PATCH 0/9] tmpfs: towards unionfs and memcgroups Hugh Dickins
2007-12-18 21:57 ` [PATCH 1/9] tmpfs: move swap_state stats update Hugh Dickins
2007-12-18 21:59 ` [PATCH 2/9] tmpfs: shuffle add_to_swap_caches Hugh Dickins
2007-12-19 1:55 ` Nick Piggin
2007-12-18 22:00 ` [PATCH 3/9] tmpfs: move swap swizzling into shmem Hugh Dickins
2007-12-18 22:01 ` Hugh Dickins [this message]
2007-12-18 22:51 ` [PATCH 4/9] tmpfs: allow filepage alongside swappage Erez Zadok
2007-12-19 0:30 ` Hugh Dickins
2007-12-18 22:02 ` [PATCH 5/9] tmpfs: allocate on read when stacked Hugh Dickins
2007-12-18 22:03 ` [PATCH 6/9] tmpfs: make shmem_unuse more preemptible Hugh Dickins
2007-12-18 22:04 ` [PATCH 7/9] tmpfs: open a window in shmem_unuse_inode Hugh Dickins
2007-12-18 22:05 ` [PATCH 8/9] tmpfs: radix_tree_preloading Hugh Dickins
2007-12-19 6:50 ` Nick Piggin
2007-12-18 22:06 ` [PATCH 9/9] tmpfs: fix shmem_swaplist races Hugh Dickins
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=Pine.LNX.4.64.0712182200230.27165@blonde.wat.veritas.com \
--to=hugh@veritas.com \
--cc=akpm@linux-foundation.org \
--cc=ezk@cs.sunysb.edu \
--cc=hans-christoph.rohland@sap.com \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®