]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - mm/page-writeback.c
signalfd: fill in ssi_int for posix timers and message queues
[karo-tx-linux.git] / mm / page-writeback.c
index 362640c3228c3281ce376a568e8a6c8d463b52c7..e5c4ca2fc55735dd52a9b51aca44c6667601fd12 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;
 
-                       if (PageWriteback(page) ||
-                           !clear_page_dirty_for_io(page)) {
+                       lock_page(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)) {
@@ -967,19 +985,35 @@ retry:
                                }
                        }
 
-                       if (wbc->sync_mode == WB_SYNC_NONE) {
-                               if (--wbc->nr_to_write <= 0)
+                       if (wbc->nr_to_write > 0) {
+                               wbc->nr_to_write--;
+                               if (wbc->nr_to_write == 0 &&
+                                   wbc->sync_mode == WB_SYNC_NONE) {
+                                       /*
+                                        * We stop writing back only if we are
+                                        * not doing integrity sync. In case of
+                                        * integrity sync we have to keep going
+                                        * because someone may be concurrently
+                                        * dirtying pages, and we might have
+                                        * synced a lot of newly appeared dirty
+                                        * pages, but have not synced all of the
+                                        * old dirty pages.
+                                        */
                                        done = 1;
+                                       break;
+                               }
                        }
+
                        if (wbc->nonblocking && bdi_write_congested(bdi)) {
                                wbc->encountered_congestion = 1;
                                done = 1;
+                               break;
                        }
                }
                pagevec_release(&pvec);
                cond_resched();
        }
-       if (!cycled) {
+       if (!cycled && !done) {
                /*
                 * range_cyclic:
                 * We hit the last page and there is more work to be done: wrap
@@ -993,8 +1027,6 @@ retry:
        if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
                mapping->writeback_index = done_index;
 
-       if (wbc->range_cont)
-               wbc->range_start = index << PAGE_CACHE_SHIFT;
        return ret;
 }
 EXPORT_SYMBOL(write_cache_pages);