[PATCH] page invalidation cleanup
[linux-2.6-microblaze.git] / mm / truncate.c
index b1a463d..a654928 100644 (file)
@@ -9,6 +9,7 @@
 
 #include <linux/kernel.h>
 #include <linux/mm.h>
+#include <linux/swap.h>
 #include <linux/module.h>
 #include <linux/pagemap.h>
 #include <linux/pagevec.h>
@@ -52,33 +53,26 @@ truncate_complete_page(struct address_space *mapping, struct page *page)
 /*
  * This is for invalidate_inode_pages().  That function can be called at
  * any time, and is not supposed to throw away dirty pages.  But pages can
- * be marked dirty at any time too.  So we re-check the dirtiness inside
- * ->tree_lock.  That provides exclusion against the __set_page_dirty
- * functions.
+ * be marked dirty at any time too, so use remove_mapping which safely
+ * discards clean, unused pages.
  *
  * Returns non-zero if the page was successfully invalidated.
  */
 static int
 invalidate_complete_page(struct address_space *mapping, struct page *page)
 {
+       int ret;
+
        if (page->mapping != mapping)
                return 0;
 
        if (PagePrivate(page) && !try_to_release_page(page, 0))
                return 0;
 
-       write_lock_irq(&mapping->tree_lock);
-       if (PageDirty(page)) {
-               write_unlock_irq(&mapping->tree_lock);
-               return 0;
-       }
-
-       BUG_ON(PagePrivate(page));
-       __remove_from_page_cache(page);
-       write_unlock_irq(&mapping->tree_lock);
+       ret = remove_mapping(mapping, page);
        ClearPageUptodate(page);
-       page_cache_release(page);       /* pagecache ref */
-       return 1;
+
+       return ret;
 }
 
 /**
@@ -196,7 +190,7 @@ EXPORT_SYMBOL(truncate_inode_pages_range);
  * @mapping: mapping to truncate
  * @lstart: offset from which to truncate
  *
- * Called under (and serialised by) inode->i_sem.
+ * Called under (and serialised by) inode->i_mutex.
  */
 void truncate_inode_pages(struct address_space *mapping, loff_t lstart)
 {
@@ -230,14 +224,24 @@ unsigned long invalidate_mapping_pages(struct address_space *mapping,
                        pagevec_lookup(&pvec, mapping, next, PAGEVEC_SIZE)) {
                for (i = 0; i < pagevec_count(&pvec); i++) {
                        struct page *page = pvec.pages[i];
+                       pgoff_t index;
+                       int lock_failed;
 
-                       if (TestSetPageLocked(page)) {
-                               next++;
-                               continue;
-                       }
-                       if (page->index > next)
-                               next = page->index;
+                       lock_failed = TestSetPageLocked(page);
+
+                       /*
+                        * We really shouldn't be looking at the ->index of an
+                        * unlocked page.  But we're not allowed to lock these
+                        * pages.  So we rely upon nobody altering the ->index
+                        * of this (pinned-by-us) page.
+                        */
+                       index = page->index;
+                       if (index > next)
+                               next = index;
                        next++;
+                       if (lock_failed)
+                               continue;
+
                        if (PageDirty(page) || PageWriteback(page))
                                goto unlock;
                        if (page_mapped(page))