vserver 2.0 rc7
[linux-2.6.git] / mm / truncate.c
index 9645008..60c8764 100644 (file)
@@ -76,15 +76,15 @@ invalidate_complete_page(struct address_space *mapping, struct page *page)
        if (PagePrivate(page) && !try_to_release_page(page, 0))
                return 0;
 
-       spin_lock_irq(&mapping->tree_lock);
+       write_lock_irq(&mapping->tree_lock);
        if (PageDirty(page)) {
-               spin_unlock_irq(&mapping->tree_lock);
+               write_unlock_irq(&mapping->tree_lock);
                return 0;
        }
 
        BUG_ON(PagePrivate(page));
        __remove_from_page_cache(page);
-       spin_unlock_irq(&mapping->tree_lock);
+       write_unlock_irq(&mapping->tree_lock);
        ClearPageUptodate(page);
        page_cache_release(page);       /* pagecache ref */
        return 1;
@@ -241,54 +241,68 @@ unsigned long invalidate_inode_pages(struct address_space *mapping)
 EXPORT_SYMBOL(invalidate_inode_pages);
 
 /**
- * invalidate_inode_pages2 - remove all pages from an address_space
- * @mapping - the address_space
+ * 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)
  *
  * 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)
+int invalidate_inode_pages2_range(struct address_space *mapping,
+                                 pgoff_t start, pgoff_t end)
 {
        struct pagevec pvec;
-       pgoff_t next = 0;
+       pgoff_t next;
        int i;
        int ret = 0;
-       int did_full_unmap = 0;
+       int did_range_unmap = 0;
+       int wrapped = 0;
 
        pagevec_init(&pvec, 0);
-       while (!ret && pagevec_lookup(&pvec, mapping, next, PAGEVEC_SIZE)) {
+       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++) {
                        struct page *page = pvec.pages[i];
+                       pgoff_t page_index;
                        int was_dirty;
 
                        lock_page(page);
-                       if (page->mapping != mapping) { /* truncate race? */
+                       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);
-                       next = page->index + 1;
                        while (page_mapped(page)) {
-                               if (!did_full_unmap) {
+                               if (!did_range_unmap) {
                                        /*
                                         * Zap the rest of the file in one hit.
-                                        * FIXME: invalidate_inode_pages2()
-                                        * should take start/end offsets.
                                         */
                                        unmap_mapping_range(mapping,
-                                               page->index << PAGE_CACHE_SHIFT,
-                                               -1, 0);
-                                       did_full_unmap = 1;
+                                           page_index << PAGE_CACHE_SHIFT,
+                                           (end - page_index + 1)
+                                                       << PAGE_CACHE_SHIFT,
+                                           0);
+                                       did_range_unmap = 1;
                                } else {
                                        /*
                                         * Just zap this page
                                         */
                                        unmap_mapping_range(mapping,
-                                         page->index << PAGE_CACHE_SHIFT,
-                                         (page->index << PAGE_CACHE_SHIFT)+1,
-                                         0);
+                                         page_index << PAGE_CACHE_SHIFT,
+                                         PAGE_CACHE_SIZE, 0);
                                }
                        }
                        was_dirty = test_clear_page_dirty(page);
@@ -304,4 +318,19 @@ int invalidate_inode_pages2(struct address_space *mapping)
        }
        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);