linux-mm.kvack.org archive mirror
 help / color / mirror / Atom feed
From: Hugh Dickins <hugh@veritas.com>
To: Andrew Morton <akpm@linux-foundation.org>
Cc: Nick Piggin <npiggin@suse.de>, linux-mm@kvack.org
Subject: [PATCH mm] mm: speculative page references fix add_to_page_cache
Date: Mon, 14 Jul 2008 00:38:47 +0100 (BST)	[thread overview]
Message-ID: <Pine.LNX.4.64.0807140031220.30686@blonde.site> (raw)

The speculative page references patch actually depends on another patch
of Nick's which he hasn't supplied this time around: an atomic-avoiding
__set_page_locked patch: see http://lkml.org/lkml/2007/11/10/5

This showed up when shmem_unuse_inode's add_to_page_cache failed: the
page was passed in locked and should remain locked, but speculative's
add_to_page_cache had unlocked it already, so the subsequent unlock_page
BUGged.  add_to_page_cache indeed should set and clear the page lock, but
shmem/tmpfs needs an add_to_page_cache_locked entry point to avoid that.

This fix patch below extracts and updates what's needed from Nick's
original, including his comments, but leaving out the atomic-avoidance.

(Do speculative page references actually need the page locked before
it's entered into the page cache?  I'm not sure myself, suspect that
if everywhere else handled PageUptodate and PageError correctly then
it might not be necessary; but we're pretty sure there are gaps in
that error handling, so I agree with Nick that we should lock before.
He may well be able to supply a stronger reason why it's necessary.)

I apologize for not finding this sooner, my testing coverage weaker
than I'd thought: only hit this in checking the swap priority patch.

Signed-off-by: Hugh Dickins <hugh@veritas.com>
---
Should follow mmotm's mm-speculative-page-references-hugh-fix3.patch

 include/linux/pagemap.h |   18 +++++++++++++++++-
 mm/filemap.c            |   19 +++++++++----------
 mm/shmem.c              |    4 ++--
 mm/swap_state.c         |    2 +-
 4 files changed, 29 insertions(+), 14 deletions(-)

--- mmotm.orig/include/linux/pagemap.h	2008-07-12 21:36:26.000000000 +0100
+++ mmotm/include/linux/pagemap.h	2008-07-12 21:36:40.000000000 +0100
@@ -227,7 +227,7 @@ static inline struct page *read_mapping_
 	return read_cache_page(mapping, index, filler, data);
 }
 
-int add_to_page_cache(struct page *page, struct address_space *mapping,
+int add_to_page_cache_locked(struct page *page, struct address_space *mapping,
 				pgoff_t index, gfp_t gfp_mask);
 int add_to_page_cache_lru(struct page *page, struct address_space *mapping,
 				pgoff_t index, gfp_t gfp_mask);
@@ -235,6 +235,22 @@ extern void remove_from_page_cache(struc
 extern void __remove_from_page_cache(struct page *page);
 
 /*
+ * Like add_to_page_cache_locked, but used to add newly allocated pages:
+ * the page is new, so we can just run SetPageLocked() against it.
+ */
+static inline int add_to_page_cache(struct page *page,
+		struct address_space *mapping, pgoff_t offset, gfp_t gfp_mask)
+{
+	int error;
+
+	SetPageLocked(page);
+	error = add_to_page_cache_locked(page, mapping, offset, gfp_mask);
+	if (unlikely(error))
+		ClearPageLocked(page);
+	return error;
+}
+
+/*
  * Return byte-offset into filesystem object for page.
  */
 static inline loff_t page_offset(struct page *page)
--- mmotm.orig/mm/filemap.c	2008-07-12 21:36:26.000000000 +0100
+++ mmotm/mm/filemap.c	2008-07-12 21:36:40.000000000 +0100
@@ -442,22 +442,23 @@ int filemap_write_and_wait_range(struct 
 }
 
 /**
- * add_to_page_cache - add newly allocated pagecache pages
+ * add_to_page_cache_locked - add newly allocated pagecache pages
  * @page:	page to add
  * @mapping:	the page's address_space
  * @offset:	page index
  * @gfp_mask:	page allocation mode
  *
- * This function is used to add newly allocated pagecache pages;
- * the page is new, so we can just run SetPageLocked() against it.
- * The other page state flags were set by rmqueue().
- *
+ * This function is used to add a page to the pagecache. It must be locked.
  * This function does not add the page to the LRU.  The caller must do that.
  */
-int add_to_page_cache(struct page *page, struct address_space *mapping,
+int add_to_page_cache_locked(struct page *page, struct address_space *mapping,
 		pgoff_t offset, gfp_t gfp_mask)
 {
-	int error = mem_cgroup_cache_charge(page, current->mm,
+	int error;
+
+	VM_BUG_ON(!PageLocked(page));
+
+	error = mem_cgroup_cache_charge(page, current->mm,
 					gfp_mask & ~__GFP_HIGHMEM);
 	if (error)
 		goto out;
@@ -465,7 +466,6 @@ int add_to_page_cache(struct page *page,
 	error = radix_tree_preload(gfp_mask & ~__GFP_HIGHMEM);
 	if (error == 0) {
 		page_cache_get(page);
-		SetPageLocked(page);
 		page->mapping = mapping;
 		page->index = offset;
 
@@ -476,7 +476,6 @@ int add_to_page_cache(struct page *page,
 			__inc_zone_page_state(page, NR_FILE_PAGES);
 		} else {
 			page->mapping = NULL;
-			ClearPageLocked(page);
 			mem_cgroup_uncharge_cache_page(page);
 			page_cache_release(page);
 		}
@@ -488,7 +487,7 @@ int add_to_page_cache(struct page *page,
 out:
 	return error;
 }
-EXPORT_SYMBOL(add_to_page_cache);
+EXPORT_SYMBOL(add_to_page_cache_locked);
 
 int add_to_page_cache_lru(struct page *page, struct address_space *mapping,
 				pgoff_t offset, gfp_t gfp_mask)
--- mmotm.orig/mm/shmem.c	2008-07-12 21:25:56.000000000 +0100
+++ mmotm/mm/shmem.c	2008-07-12 21:36:40.000000000 +0100
@@ -936,7 +936,7 @@ found:
 	spin_lock(&info->lock);
 	ptr = shmem_swp_entry(info, idx, NULL);
 	if (ptr && ptr->val == entry.val) {
-		error = add_to_page_cache(page, inode->i_mapping,
+		error = add_to_page_cache_locked(page, inode->i_mapping,
 						idx, GFP_NOWAIT);
 		/* does mem_cgroup_uncharge_cache_page on error */
 	} else	/* we must compensate for our precharge above */
@@ -1301,7 +1301,7 @@ repeat:
 			SetPageUptodate(filepage);
 			set_page_dirty(filepage);
 			swap_free(swap);
-		} else if (!(error = add_to_page_cache(
+		} else if (!(error = add_to_page_cache_locked(
 				swappage, mapping, idx, GFP_NOWAIT))) {
 			info->flags |= SHMEM_PAGEIN;
 			shmem_swp_set(info, entry, 0);
--- mmotm.orig/mm/swap_state.c	2008-07-12 21:36:26.000000000 +0100
+++ mmotm/mm/swap_state.c	2008-07-12 21:36:40.000000000 +0100
@@ -64,7 +64,7 @@ void show_swap_cache_info(void)
 }
 
 /*
- * add_to_swap_cache resembles add_to_page_cache on swapper_space,
+ * add_to_swap_cache resembles add_to_page_cache_locked on swapper_space,
  * but sets SwapCache flag and private instead of mapping and index.
  */
 int add_to_swap_cache(struct page *page, swp_entry_t entry, gfp_t gfp_mask)

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

             reply	other threads:[~2008-07-13 23:38 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-07-13 23:38 Hugh Dickins [this message]
2008-07-14  4:57 ` Nick Piggin

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.0807140031220.30686@blonde.site \
    --to=hugh@veritas.com \
    --cc=akpm@linux-foundation.org \
    --cc=linux-mm@kvack.org \
    --cc=npiggin@suse.de \
    /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