|
@@ -14,6 +14,7 @@
|
|
|
#include <linux/mpage.h>
|
|
|
#include <linux/writeback.h>
|
|
|
#include <linux/backing-dev.h>
|
|
|
+#include <linux/pagevec.h>
|
|
|
#include <linux/blkdev.h>
|
|
|
#include <linux/bio.h>
|
|
|
#include <linux/prefetch.h>
|
|
@@ -1127,6 +1128,139 @@ static int __f2fs_writepage(struct page *page, struct writeback_control *wbc,
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * This function was copied from write_cche_pages from mm/page-writeback.c.
|
|
|
+ * The major change is making write step of cold data page separately from
|
|
|
+ * warm/hot data page.
|
|
|
+ */
|
|
|
+static int f2fs_write_cache_pages(struct address_space *mapping,
|
|
|
+ struct writeback_control *wbc, writepage_t writepage,
|
|
|
+ void *data)
|
|
|
+{
|
|
|
+ int ret = 0;
|
|
|
+ int done = 0;
|
|
|
+ struct pagevec pvec;
|
|
|
+ int nr_pages;
|
|
|
+ pgoff_t uninitialized_var(writeback_index);
|
|
|
+ pgoff_t index;
|
|
|
+ pgoff_t end; /* Inclusive */
|
|
|
+ pgoff_t done_index;
|
|
|
+ int cycled;
|
|
|
+ int range_whole = 0;
|
|
|
+ int tag;
|
|
|
+ int step = 0;
|
|
|
+
|
|
|
+ pagevec_init(&pvec, 0);
|
|
|
+next:
|
|
|
+ if (wbc->range_cyclic) {
|
|
|
+ writeback_index = mapping->writeback_index; /* prev offset */
|
|
|
+ index = writeback_index;
|
|
|
+ if (index == 0)
|
|
|
+ cycled = 1;
|
|
|
+ else
|
|
|
+ cycled = 0;
|
|
|
+ end = -1;
|
|
|
+ } else {
|
|
|
+ index = wbc->range_start >> PAGE_CACHE_SHIFT;
|
|
|
+ end = wbc->range_end >> PAGE_CACHE_SHIFT;
|
|
|
+ if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX)
|
|
|
+ range_whole = 1;
|
|
|
+ cycled = 1; /* ignore range_cyclic tests */
|
|
|
+ }
|
|
|
+ if (wbc->sync_mode == WB_SYNC_ALL || wbc->tagged_writepages)
|
|
|
+ tag = PAGECACHE_TAG_TOWRITE;
|
|
|
+ else
|
|
|
+ tag = PAGECACHE_TAG_DIRTY;
|
|
|
+retry:
|
|
|
+ if (wbc->sync_mode == WB_SYNC_ALL || wbc->tagged_writepages)
|
|
|
+ tag_pages_for_writeback(mapping, index, end);
|
|
|
+ done_index = index;
|
|
|
+ while (!done && (index <= end)) {
|
|
|
+ int i;
|
|
|
+
|
|
|
+ nr_pages = pagevec_lookup_tag(&pvec, mapping, &index, tag,
|
|
|
+ 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];
|
|
|
+
|
|
|
+ if (page->index > end) {
|
|
|
+ done = 1;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ done_index = page->index;
|
|
|
+
|
|
|
+ lock_page(page);
|
|
|
+
|
|
|
+ if (unlikely(page->mapping != mapping)) {
|
|
|
+continue_unlock:
|
|
|
+ unlock_page(page);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!PageDirty(page)) {
|
|
|
+ /* someone wrote it for us */
|
|
|
+ goto continue_unlock;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (step == 0 && !is_cold_data(page))
|
|
|
+ goto continue_unlock;
|
|
|
+ if (step == 1 && is_cold_data(page))
|
|
|
+ goto continue_unlock;
|
|
|
+
|
|
|
+ if (PageWriteback(page)) {
|
|
|
+ if (wbc->sync_mode != WB_SYNC_NONE)
|
|
|
+ f2fs_wait_on_page_writeback(page, DATA);
|
|
|
+ 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)) {
|
|
|
+ if (ret == AOP_WRITEPAGE_ACTIVATE) {
|
|
|
+ unlock_page(page);
|
|
|
+ ret = 0;
|
|
|
+ } else {
|
|
|
+ done_index = page->index + 1;
|
|
|
+ done = 1;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (--wbc->nr_to_write <= 0 &&
|
|
|
+ wbc->sync_mode == WB_SYNC_NONE) {
|
|
|
+ done = 1;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ pagevec_release(&pvec);
|
|
|
+ cond_resched();
|
|
|
+ }
|
|
|
+
|
|
|
+ if (step < 1) {
|
|
|
+ step++;
|
|
|
+ goto next;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!cycled && !done) {
|
|
|
+ cycled = 1;
|
|
|
+ index = 0;
|
|
|
+ end = writeback_index - 1;
|
|
|
+ goto retry;
|
|
|
+ }
|
|
|
+ if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
|
|
|
+ mapping->writeback_index = done_index;
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
static int f2fs_write_data_pages(struct address_space *mapping,
|
|
|
struct writeback_control *wbc)
|
|
|
{
|
|
@@ -1157,7 +1291,7 @@ static int f2fs_write_data_pages(struct address_space *mapping,
|
|
|
mutex_lock(&sbi->writepages);
|
|
|
locked = true;
|
|
|
}
|
|
|
- ret = write_cache_pages(mapping, wbc, __f2fs_writepage, mapping);
|
|
|
+ ret = f2fs_write_cache_pages(mapping, wbc, __f2fs_writepage, mapping);
|
|
|
f2fs_submit_merged_bio(sbi, DATA, WRITE);
|
|
|
if (locked)
|
|
|
mutex_unlock(&sbi->writepages);
|