[patch] truncate inode page sleeps

Andrea Arcangeli (andrea@suse.de)
Fri, 25 Jun 1999 16:14:05 +0200 (CEST)


Since truncate_inode_page() can sleep if the page is under I/O, then
shrink_mmap may recycle the page from the page cache while truncate is
sleeping. This patch will fix the race.

--- linux/mm/filemap.c Fri Jun 25 15:25:13 1999
+++ /tmp/filemap.c Fri Jun 25 16:04:40 1999
@@ -149,6 +149,9 @@

lock_page(page);

+ if (!page->inode)
+ goto shrunk;
+
if (inode->i_op->flushpage)
inode->i_op->flushpage(inode, page, 0);

@@ -161,10 +164,11 @@
* to it causing all sorts of fun problems ...
*/
remove_inode_page(page);
+ page_cache_release(page);

+ shrunk:
UnlockPage(page);
page_cache_release(page);
- page_cache_release(page);

/*
* We have done things without the pagecache lock,
@@ -190,6 +194,10 @@
spin_unlock(&pagecache_lock);

lock_page(page);
+
+ if (!page->inode)
+ goto shrunk;
+
partial = 1;

address = page_address(page);

Just to show a bit my current tree the below patch is exactly what I am
doing here:

Index: linux/mm/filemap.c
===================================================================
RCS file: /var/cvs/linux/mm/filemap.c,v
retrieving revision 1.1.1.24
diff -u -r1.1.1.24 filemap.c
--- linux/mm/filemap.c 1999/06/22 22:36:35 1.1.1.24
+++ linux/mm/filemap.c 1999/06/25 14:00:58
@@ -144,13 +152,24 @@

/* page wholly truncated - free it */
if (offset >= start) {
+ int additional_refcount;
get_page(page);
spin_unlock(&pagecache_lock);

lock_page(page);

+ if (!page->inode)
+ goto shrunk;
+
+ additional_refcount = 1;
if (inode->i_op->flushpage)
- inode->i_op->flushpage(inode, page, 0);
+ switch (inode->i_op->flushpage(inode, page, 0))
+ {
+ case FLUSHPAGE_RELEASED:
+ additional_refcount = 2;
+ case FLUSHPAGE_EMPTY:
+ lru_pages_del(page);
+ }

/*
* We remove the page from the page cache
@@ -162,9 +181,10 @@
*/
remove_inode_page(page);

+ put_page_n_refcount(additional_refcount, page);
+ shrunk:
UnlockPage(page);
page_cache_release(page);
- page_cache_release(page);

/*
* We have done things without the pagecache lock,
@@ -190,6 +210,10 @@
spin_unlock(&pagecache_lock);

lock_page(page);
+
+ if (!page->inode)
+ goto shrunk;
+
partial = 1;

address = page_address(page);

Andrea Arcangeli

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/