]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/commitdiff
f2fs: flush cp pack except cp pack 2 page at first
authorGao Xiang <hsiangkao@aol.com>
Sat, 10 Feb 2018 04:12:51 +0000 (12:12 +0800)
committerKleber Sacilotto de Souza <kleber.souza@canonical.com>
Mon, 27 Aug 2018 14:40:05 +0000 (16:40 +0200)
BugLink: http://bugs.launchpad.net/bugs/1786352
[ Upstream commit 46706d5917f4457a6befe7a39a15c89dbb1ce9ca ]

Previously, we attempt to flush the whole cp pack in a single bio,
however, when suddenly powering off at this time, we could get into
an extreme scenario that cp pack 1 page and cp pack 2 page are updated
and latest, but payload or current summaries are still partially
outdated. (see reliable write in the UFS specification)

This patch submits the whole cp pack except cp pack 2 page at first,
and then writes the cp pack 2 page with an extra independent
bio with pre-io barrier.

Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Reviewed-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
Signed-off-by: Sasha Levin <alexander.levin@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Kamal Mostafa <kamal@canonical.com>
Signed-off-by: Khalid Elmously <khalid.elmously@canonical.com>
fs/f2fs/checkpoint.c

index aa02878f844922312e4df4514f802b7545ac13b8..9bcd5c9f3f5118c1fb84e7279a9e411be3d43733 100644 (file)
@@ -1160,6 +1160,39 @@ static void update_ckpt_flags(struct f2fs_sb_info *sbi, struct cp_control *cpc)
        spin_unlock_irqrestore(&sbi->cp_lock, flags);
 }
 
+static void commit_checkpoint(struct f2fs_sb_info *sbi,
+       void *src, block_t blk_addr)
+{
+       struct writeback_control wbc = {
+               .for_reclaim = 0,
+       };
+
+       /*
+        * pagevec_lookup_tag and lock_page again will take
+        * some extra time. Therefore, update_meta_pages and
+        * sync_meta_pages are combined in this function.
+        */
+       struct page *page = grab_meta_page(sbi, blk_addr);
+       int err;
+
+       memcpy(page_address(page), src, PAGE_SIZE);
+       set_page_dirty(page);
+
+       f2fs_wait_on_page_writeback(page, META, true);
+       f2fs_bug_on(sbi, PageWriteback(page));
+       if (unlikely(!clear_page_dirty_for_io(page)))
+               f2fs_bug_on(sbi, 1);
+
+       /* writeout cp pack 2 page */
+       err = __f2fs_write_meta_page(page, &wbc, FS_CP_META_IO);
+       f2fs_bug_on(sbi, err);
+
+       f2fs_put_page(page, 0);
+
+       /* submit checkpoint (with barrier if NOBARRIER is not set) */
+       f2fs_submit_merged_write(sbi, META_FLUSH);
+}
+
 static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
 {
        struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
@@ -1262,16 +1295,6 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
                }
        }
 
-       /* need to wait for end_io results */
-       wait_on_all_pages_writeback(sbi);
-       if (unlikely(f2fs_cp_error(sbi)))
-               return -EIO;
-
-       /* flush all device cache */
-       err = f2fs_flush_device_cache(sbi);
-       if (err)
-               return err;
-
        /* write out checkpoint buffer at block 0 */
        update_meta_page(sbi, ckpt, start_blk++);
 
@@ -1299,26 +1322,26 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
                start_blk += NR_CURSEG_NODE_TYPE;
        }
 
-       /* writeout checkpoint block */
-       update_meta_page(sbi, ckpt, start_blk);
+       /* update user_block_counts */
+       sbi->last_valid_block_count = sbi->total_valid_block_count;
+       percpu_counter_set(&sbi->alloc_valid_block_count, 0);
 
-       /* wait for previous submitted node/meta pages writeback */
+       /* Here, we have one bio having CP pack except cp pack 2 page */
+       sync_meta_pages(sbi, META, LONG_MAX, FS_CP_META_IO);
+
+       /* wait for previous submitted meta pages writeback */
        wait_on_all_pages_writeback(sbi);
 
        if (unlikely(f2fs_cp_error(sbi)))
                return -EIO;
 
-       filemap_fdatawait_range(NODE_MAPPING(sbi), 0, LLONG_MAX);
-       filemap_fdatawait_range(META_MAPPING(sbi), 0, LLONG_MAX);
-
-       /* update user_block_counts */
-       sbi->last_valid_block_count = sbi->total_valid_block_count;
-       percpu_counter_set(&sbi->alloc_valid_block_count, 0);
-
-       /* Here, we only have one bio having CP pack */
-       sync_meta_pages(sbi, META_FLUSH, LONG_MAX, FS_CP_META_IO);
+       /* flush all device cache */
+       err = f2fs_flush_device_cache(sbi);
+       if (err)
+               return err;
 
-       /* wait for previous submitted meta pages writeback */
+       /* barrier and flush checkpoint cp pack 2 page if it can */
+       commit_checkpoint(sbi, ckpt, start_blk);
        wait_on_all_pages_writeback(sbi);
 
        release_ino_entry(sbi, false);