f2fs: let sync node IO interrupt async one
authorChao Yu <yuchao0@huawei.com>
Mon, 4 Jun 2018 15:20:36 +0000 (23:20 +0800)
committerJaegeuk Kim <jaegeuk@kernel.org>
Mon, 9 Jul 2018 00:40:58 +0000 (17:40 -0700)
Although mixed sync/async IOs can have continuous LBA, as they have
different IO priority, block IO scheduler will add them into different
queues and commit them separately, result in splited IOs which causes
wrose performance.

This patch gives high priority to synchronous IO of nodes, means that
once synchronous flow starts, it can interrupt asynchronous writeback
flow of system flusher, so more big IOs can be expected.

Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
fs/f2fs/checkpoint.c
fs/f2fs/data.c
fs/f2fs/f2fs.h
fs/f2fs/file.c
fs/f2fs/gc.c
fs/f2fs/node.c
fs/f2fs/super.c

index 0f8a6b96fc9c2994e73b6e3e7c02c875530df803..49f92bcd8fe62842680964a63bc622ab0cc4b777 100644 (file)
@@ -1089,7 +1089,9 @@ retry_flush_nodes:
 
        if (get_pages(sbi, F2FS_DIRTY_NODES)) {
                up_write(&sbi->node_write);
+               atomic_inc(&sbi->wb_sync_req[NODE]);
                err = f2fs_sync_node_pages(sbi, &wbc, false, FS_CP_NODE_IO);
+               atomic_dec(&sbi->wb_sync_req[NODE]);
                if (err) {
                        up_write(&sbi->node_change);
                        f2fs_unlock_all(sbi);
index e429891b1e09f69ca7d2665262b92463ecf64d99..a8a1558b7689c7194a570a199a9a04e677446e28 100644 (file)
@@ -1933,6 +1933,7 @@ static int f2fs_write_cache_pages(struct address_space *mapping,
        int ret = 0;
        int done = 0;
        struct pagevec pvec;
+       struct f2fs_sb_info *sbi = F2FS_M_SB(mapping);
        int nr_pages;
        pgoff_t uninitialized_var(writeback_index);
        pgoff_t index;
@@ -1987,7 +1988,7 @@ retry:
                        bool submitted = false;
 
                        /* give a priority to WB_SYNC threads */
-                       if (atomic_read(&F2FS_M_SB(mapping)->wb_sync_req) &&
+                       if (atomic_read(&sbi->wb_sync_req[DATA]) &&
                                        wbc->sync_mode == WB_SYNC_NONE) {
                                done = 1;
                                break;
@@ -2107,8 +2108,8 @@ static int __f2fs_write_data_pages(struct address_space *mapping,
 
        /* to avoid spliting IOs due to mixed WB_SYNC_ALL and WB_SYNC_NONE */
        if (wbc->sync_mode == WB_SYNC_ALL)
-               atomic_inc(&sbi->wb_sync_req);
-       else if (atomic_read(&sbi->wb_sync_req))
+               atomic_inc(&sbi->wb_sync_req[DATA]);
+       else if (atomic_read(&sbi->wb_sync_req[DATA]))
                goto skip_write;
 
        blk_start_plug(&plug);
@@ -2116,7 +2117,7 @@ static int __f2fs_write_data_pages(struct address_space *mapping,
        blk_finish_plug(&plug);
 
        if (wbc->sync_mode == WB_SYNC_ALL)
-               atomic_dec(&sbi->wb_sync_req);
+               atomic_dec(&sbi->wb_sync_req[DATA]);
        /*
         * if some pages were truncated, we cannot guarantee its mapping->host
         * to detect pending bios.
index f167d01443fe0dada2ea378033fb46161797188e..4c09e770a0a3bf6d8ef8f8e79d0582e5df05306d 100644 (file)
@@ -1201,7 +1201,7 @@ struct f2fs_sb_info {
        struct percpu_counter alloc_valid_block_count;
 
        /* writeback control */
-       atomic_t wb_sync_req;                   /* count # of WB_SYNC threads */
+       atomic_t wb_sync_req[META];     /* count # of WB_SYNC threads */
 
        /* valid inode count */
        struct percpu_counter total_valid_inode_count;
index fc60abbe940aa72ad23d4cfe3cdb36e5b5a59701..ebe8171b5d276f2d81f7376d42dc9aabcf0ab22a 100644 (file)
@@ -274,7 +274,9 @@ go_write:
                goto out;
        }
 sync_nodes:
+       atomic_inc(&sbi->wb_sync_req[NODE]);
        ret = f2fs_fsync_node_pages(sbi, inode, &wbc, atomic);
+       atomic_dec(&sbi->wb_sync_req[NODE]);
        if (ret)
                goto out;
 
index 5627e56a696fece46cf06b2733e09fcedb627027..857dcc05df640d1278c219fc3eebeb57352ad4fd 100644 (file)
@@ -473,12 +473,16 @@ static void gc_node_segment(struct f2fs_sb_info *sbi,
        block_t start_addr;
        int off;
        int phase = 0;
+       bool fggc = (gc_type == FG_GC);
 
        start_addr = START_BLOCK(sbi, segno);
 
 next_step:
        entry = sum;
 
+       if (fggc && phase == 2)
+               atomic_inc(&sbi->wb_sync_req[NODE]);
+
        for (off = 0; off < sbi->blocks_per_seg; off++, entry++) {
                nid_t nid = le32_to_cpu(entry->nid);
                struct page *node_page;
@@ -525,6 +529,9 @@ next_step:
 
        if (++phase < 3)
                goto next_step;
+
+       if (fggc)
+               atomic_dec(&sbi->wb_sync_req[NODE]);
 }
 
 /*
index f18b4ce95c21212c8584a93e427099fe2cca33df..04b604591ef90c2eb10fa5ddee2ec09aaa99d815 100644 (file)
@@ -1596,21 +1596,28 @@ int f2fs_sync_node_pages(struct f2fs_sb_info *sbi,
        int step = 0;
        int nwritten = 0;
        int ret = 0;
-       int nr_pages;
+       int nr_pages, done = 0;
 
        pagevec_init(&pvec, 0);
 
 next_step:
        index = 0;
 
-       while ((nr_pages = pagevec_lookup_tag(&pvec, NODE_MAPPING(sbi), &index,
-                               PAGECACHE_TAG_DIRTY))) {
+       while (!done && (nr_pages = pagevec_lookup_tag(&pvec,
+                       NODE_MAPPING(sbi), &index, PAGECACHE_TAG_DIRTY))) {
                int i;
 
                for (i = 0; i < nr_pages; i++) {
                        struct page *page = pvec.pages[i];
                        bool submitted = false;
 
+                       /* give a priority to WB_SYNC threads */
+                       if (atomic_read(&sbi->wb_sync_req[NODE]) &&
+                                       wbc->sync_mode == WB_SYNC_NONE) {
+                               done = 1;
+                               break;
+                       }
+
                        /*
                         * flushing sequence with step:
                         * 0. indirect nodes
@@ -1738,6 +1745,11 @@ static int f2fs_write_node_pages(struct address_space *mapping,
        if (get_pages(sbi, F2FS_DIRTY_NODES) < nr_pages_to_skip(sbi, NODE))
                goto skip_write;
 
+       if (wbc->sync_mode == WB_SYNC_ALL)
+               atomic_inc(&sbi->wb_sync_req[NODE]);
+       else if (atomic_read(&sbi->wb_sync_req[NODE]))
+               goto skip_write;
+
        trace_f2fs_writepages(mapping->host, wbc, NODE);
 
        diff = nr_pages_to_write(sbi, NODE, wbc);
@@ -1745,6 +1757,9 @@ static int f2fs_write_node_pages(struct address_space *mapping,
        f2fs_sync_node_pages(sbi, wbc, true, FS_NODE_IO);
        blk_finish_plug(&plug);
        wbc->nr_to_write = max((long)0, wbc->nr_to_write - diff);
+
+       if (wbc->sync_mode == WB_SYNC_ALL)
+               atomic_dec(&sbi->wb_sync_req[NODE]);
        return 0;
 
 skip_write:
index cfa677acd4129ce72cdf1048840432d4eeb9ce6d..f8b88089a3c43f312fa4f5bd050aad6f607e138e 100644 (file)
@@ -2356,7 +2356,8 @@ static void init_sb_info(struct f2fs_sb_info *sbi)
        for (i = 0; i < NR_COUNT_TYPE; i++)
                atomic_set(&sbi->nr_pages[i], 0);
 
-       atomic_set(&sbi->wb_sync_req, 0);
+       for (i = 0; i < META; i++)
+               atomic_set(&sbi->wb_sync_req[i], 0);
 
        INIT_LIST_HEAD(&sbi->s_list);
        mutex_init(&sbi->umount_mutex);