This commit was manufactured by cvs2svn to create tag
[linux-2.6.git] / mm / truncate.c
index fe9071b..dc2e9a5 100644 (file)
@@ -64,8 +64,6 @@ truncate_complete_page(struct address_space *mapping, struct page *page)
  * 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.
- *
- * Returns non-zero if the page was successfully invalidated.
  */
 static int
 invalidate_complete_page(struct address_space *mapping, struct page *page)
@@ -76,15 +74,19 @@ invalidate_complete_page(struct address_space *mapping, struct page *page)
        if (PagePrivate(page) && !try_to_release_page(page, 0))
                return 0;
 
-       write_lock_irq(&mapping->tree_lock);
+       spin_lock_irq(&mapping->tree_lock);
        if (PageDirty(page)) {
-               write_unlock_irq(&mapping->tree_lock);
+               spin_unlock_irq(&mapping->tree_lock);
                return 0;
        }
 
        BUG_ON(PagePrivate(page));
+       if (page_count(page) != 2) {
+               spin_unlock_irq(&mapping->tree_lock);
+               return 0;
+       }
        __remove_from_page_cache(page);
-       write_unlock_irq(&mapping->tree_lock);
+       spin_unlock_irq(&mapping->tree_lock);
        ClearPageUptodate(page);
        page_cache_release(page);       /* pagecache ref */
        return 1;
@@ -243,96 +245,50 @@ unsigned long invalidate_inode_pages(struct address_space *mapping)
 EXPORT_SYMBOL(invalidate_inode_pages);
 
 /**
- * invalidate_inode_pages2_range - remove range of pages from an address_space
- * @mapping: the address_space
- * @start: the page offset 'from' which to invalidate
- * @end: the page offset 'to' which to invalidate (inclusive)
+ * invalidate_inode_pages2 - remove all unmapped pages from an address_space
+ * @mapping - the address_space
  *
- * Any pages which are found to be mapped into pagetables are unmapped prior to
- * invalidation.
+ * invalidate_inode_pages2() is like truncate_inode_pages(), except for the case
+ * where the page is seen to be mapped into process pagetables.  In that case,
+ * the page is marked clean but is left attached to its address_space.
  *
- * Returns -EIO if any pages could not be invalidated.
+ * The page is also marked not uptodate so that a subsequent pagefault will
+ * perform I/O to bringthe page's contents back into sync with its backing
+ * store.
+ *
+ * FIXME: invalidate_inode_pages2() is probably trivially livelockable.
  */
-int invalidate_inode_pages2_range(struct address_space *mapping,
-                                 pgoff_t start, pgoff_t end)
+void invalidate_inode_pages2(struct address_space *mapping)
 {
        struct pagevec pvec;
-       pgoff_t next;
+       pgoff_t next = 0;
        int i;
-       int ret = 0;
-       int did_range_unmap = 0;
-       int wrapped = 0;
 
        pagevec_init(&pvec, 0);
-       next = start;
-       while (next <= end && !ret && !wrapped &&
-               pagevec_lookup(&pvec, mapping, next,
-                       min(end - next, (pgoff_t)PAGEVEC_SIZE - 1) + 1)) {
-               for (i = 0; !ret && i < pagevec_count(&pvec); i++) {
+       while (pagevec_lookup(&pvec, mapping, next, PAGEVEC_SIZE)) {
+               for (i = 0; i < pagevec_count(&pvec); i++) {
                        struct page *page = pvec.pages[i];
-                       pgoff_t page_index;
-                       int was_dirty;
 
                        lock_page(page);
-                       if (page->mapping != mapping) {
-                               unlock_page(page);
-                               continue;
-                       }
-                       page_index = page->index;
-                       next = page_index + 1;
-                       if (next == 0)
-                               wrapped = 1;
-                       if (page_index > end) {
-                               unlock_page(page);
-                               break;
-                       }
-                       wait_on_page_writeback(page);
-                       while (page_mapped(page)) {
-                               if (!did_range_unmap) {
-                                       /*
-                                        * Zap the rest of the file in one hit.
-                                        */
-                                       unmap_mapping_range(mapping,
-                                           page_index << PAGE_CACHE_SHIFT,
-                                           (end - page_index + 1)
-                                                       << PAGE_CACHE_SHIFT,
-                                           0);
-                                       did_range_unmap = 1;
+                       if (page->mapping == mapping) { /* truncate race? */
+                               wait_on_page_writeback(page);
+                               next = page->index + 1;
+                               if (page_mapped(page)) {
+                                       clear_page_dirty(page);
+                                       ClearPageUptodate(page);
                                } else {
-                                       /*
-                                        * Just zap this page
-                                        */
-                                       unmap_mapping_range(mapping,
-                                         page_index << PAGE_CACHE_SHIFT,
-                                         PAGE_CACHE_SIZE, 0);
+                                       if (!invalidate_complete_page(mapping,
+                                                                     page)) {
+                                               clear_page_dirty(page);
+                                               ClearPageUptodate(page);
+                                       }
                                }
                        }
-                       was_dirty = test_clear_page_dirty(page);
-                       if (!invalidate_complete_page(mapping, page)) {
-                               if (was_dirty)
-                                       set_page_dirty(page);
-                               ret = -EIO;
-                       }
                        unlock_page(page);
                }
                pagevec_release(&pvec);
                cond_resched();
        }
-       return ret;
 }
-EXPORT_SYMBOL_GPL(invalidate_inode_pages2_range);
 
-/**
- * invalidate_inode_pages2 - remove all pages from an address_space
- * @mapping: the address_space
- *
- * Any pages which are found to be mapped into pagetables are unmapped prior to
- * invalidation.
- *
- * Returns -EIO if any pages could not be invalidated.
- */
-int invalidate_inode_pages2(struct address_space *mapping)
-{
-       return invalidate_inode_pages2_range(mapping, 0, -1);
-}
 EXPORT_SYMBOL_GPL(invalidate_inode_pages2);