mm: write_cache_pages terminate quickly
[pandora-kernel.git] / mm / page-writeback.c
index 362640c..0f225bf 100644 (file)
@@ -902,50 +902,68 @@ int write_cache_pages(struct address_space *mapping,
        }
 retry:
        done_index = index;
-       while (!done && (index <= end) &&
-              (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
-                                             PAGECACHE_TAG_DIRTY,
-                                             min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1))) {
-               unsigned i;
+       while (!done && (index <= end)) {
+               int i;
+
+               nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
+                             PAGECACHE_TAG_DIRTY,
+                             min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1);
+               if (nr_pages == 0)
+                       break;
 
                for (i = 0; i < nr_pages; i++) {
                        struct page *page = pvec.pages[i];
 
-                       done_index = page->index + 1;
-
                        /*
-                        * At this point we hold neither mapping->tree_lock nor
-                        * lock on the page itself: the page may be truncated or
-                        * invalidated (changing page->mapping to NULL), or even
-                        * swizzled back from swapper_space to tmpfs file
-                        * mapping
+                        * At this point, the page may be truncated or
+                        * invalidated (changing page->mapping to NULL), or
+                        * even swizzled back from swapper_space to tmpfs file
+                        * mapping. However, page->index will not change
+                        * because we have a reference on the page.
                         */
-                       lock_page(page);
-
-                       if (unlikely(page->mapping != mapping)) {
-                               unlock_page(page);
-                               continue;
-                       }
-
                        if (page->index > end) {
                                /*
                                 * can't be range_cyclic (1st pass) because
                                 * end == -1 in that case.
                                 */
                                done = 1;
-                               unlock_page(page);
-                               continue;
+                               break;
                        }
 
-                       if (wbc->sync_mode != WB_SYNC_NONE)
-                               wait_on_page_writeback(page);
+                       done_index = page->index + 1;
+
+                       lock_page(page);
 
-                       if (PageWriteback(page) ||
-                           !clear_page_dirty_for_io(page)) {
+                       /*
+                        * Page truncated or invalidated. We can freely skip it
+                        * then, even for data integrity operations: the page
+                        * has disappeared concurrently, so there could be no
+                        * real expectation of this data interity operation
+                        * even if there is now a new, dirty page at the same
+                        * pagecache address.
+                        */
+                       if (unlikely(page->mapping != mapping)) {
+continue_unlock:
                                unlock_page(page);
                                continue;
                        }
 
+                       if (!PageDirty(page)) {
+                               /* someone wrote it for us */
+                               goto continue_unlock;
+                       }
+
+                       if (PageWriteback(page)) {
+                               if (wbc->sync_mode != WB_SYNC_NONE)
+                                       wait_on_page_writeback(page);
+                               else
+                                       goto continue_unlock;
+                       }
+
+                       BUG_ON(PageWriteback(page));
+                       if (!clear_page_dirty_for_io(page))
+                               goto continue_unlock;
+
                        ret = (*writepage)(page, wbc, data);
 
                        if (unlikely(ret)) {
@@ -968,7 +986,8 @@ retry:
                        }
 
                        if (wbc->sync_mode == WB_SYNC_NONE) {
-                               if (--wbc->nr_to_write <= 0)
+                               wbc->nr_to_write--;
+                               if (wbc->nr_to_write <= 0)
                                        done = 1;
                        }
                        if (wbc->nonblocking && bdi_write_congested(bdi)) {