
From: Hans Reiser <reiser@namesys.com>

reiser4 keeps its meta-data pages in the page cache, attached to a special
"fake" inode.  Meta-data blocks have "znodes" attached to them (reiser4 analog
of buffer_head) and initially don't have real disk block numbers assigned. 
Later meta-data blocks can be "relocated" to decrease fragmentation.  As a
result, their pages cannot be easily indexed by block number.  Instead reiser4
indexes pages of fake inode by some function of znode address.  This looks
weird, but it works.  The only problem is that there is a race involving
->releasepage(): there is a window when znode has already been freed by
reiser4_releasepage(), but its page still exists (albeit locked).  If at this
moment another znode is allocated at the same address as one just destroyed,
then some other thread can acquire a reference to lingering page (because it
is indexed by address of znode), and prevent shrink_list() from freeing it.

To avoid this, reiser4_releasepage() removes page from radix-tree manually. 
This requires re-checking page->mapping after calling try_to_release_page().

Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 25-akpm/mm/truncate.c |    7 +++++++
 25-akpm/mm/vmscan.c   |    5 +++++
 2 files changed, 12 insertions(+)

diff -puN mm/truncate.c~reiser4-reget-page-mapping mm/truncate.c
--- 25/mm/truncate.c~reiser4-reget-page-mapping	2005-02-28 16:59:30.000000000 -0800
+++ 25-akpm/mm/truncate.c	2005-02-28 16:59:30.000000000 -0800
@@ -76,6 +76,13 @@ invalidate_complete_page(struct address_
 	if (PagePrivate(page) && !try_to_release_page(page, 0))
 		return 0;
 
+	/*
+	 * file system may manually remove page from the page
+	 * cache in ->releasepage(). Check for this.
+	 */
+	if (page->mapping != mapping)
+		return 0;
+
 	write_lock_irq(&mapping->tree_lock);
 	if (PageDirty(page)) {
 		write_unlock_irq(&mapping->tree_lock);
diff -puN mm/vmscan.c~reiser4-reget-page-mapping mm/vmscan.c
--- 25/mm/vmscan.c~reiser4-reget-page-mapping	2005-02-28 16:59:30.000000000 -0800
+++ 25-akpm/mm/vmscan.c	2005-02-28 16:59:30.000000000 -0800
@@ -480,6 +480,11 @@ static int shrink_list(struct list_head 
 		if (PagePrivate(page)) {
 			if (!try_to_release_page(page, sc->gfp_mask))
 				goto activate_locked;
+			/*
+			 * file system may manually remove page from the page
+			 * cache in ->releasepage(). Check for this.
+			 */
+			mapping = page_mapping(page);
 			if (!mapping && page_count(page) == 1)
 				goto free_it;
 		}
_
