f2fs: fix to wait page writeback before update
authorChao Yu <yuchao0@huawei.com>
Sun, 28 Jun 2020 02:58:17 +0000 (10:58 +0800)
committerJaegeuk Kim <jaegeuk@kernel.org>
Wed, 8 Jul 2020 04:51:45 +0000 (21:51 -0700)
Filesystem including f2fs should support stable page for special
device like software raid, however there is one missing path that
page could be updated while it is writeback state as below, fix
this.

- gc_node_segment
 - f2fs_move_node_page
  - __write_node_page
   - set_page_writeback

- do_read_inode
 - f2fs_init_extent_tree
  - __f2fs_init_extent_tree
    i_ext->len = 0;

Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
fs/f2fs/extent_cache.c
fs/f2fs/f2fs.h
fs/f2fs/inode.c

index e60078460ad17975a2bdb39c46614e263ebdb067..686c68b98610b50c0d8bc9b264bb693793b92992 100644 (file)
@@ -325,9 +325,10 @@ static void __drop_largest_extent(struct extent_tree *et,
 }
 
 /* return true, if inode page is changed */
-static bool __f2fs_init_extent_tree(struct inode *inode, struct f2fs_extent *i_ext)
+static void __f2fs_init_extent_tree(struct inode *inode, struct page *ipage)
 {
        struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+       struct f2fs_extent *i_ext = ipage ? &F2FS_INODE(ipage)->i_ext : NULL;
        struct extent_tree *et;
        struct extent_node *en;
        struct extent_info ei;
@@ -335,16 +336,18 @@ static bool __f2fs_init_extent_tree(struct inode *inode, struct f2fs_extent *i_e
        if (!f2fs_may_extent_tree(inode)) {
                /* drop largest extent */
                if (i_ext && i_ext->len) {
+                       f2fs_wait_on_page_writeback(ipage, NODE, true, true);
                        i_ext->len = 0;
-                       return true;
+                       set_page_dirty(ipage);
+                       return;
                }
-               return false;
+               return;
        }
 
        et = __grab_extent_tree(inode);
 
        if (!i_ext || !i_ext->len)
-               return false;
+               return;
 
        get_extent_info(&ei, i_ext);
 
@@ -360,17 +363,14 @@ static bool __f2fs_init_extent_tree(struct inode *inode, struct f2fs_extent *i_e
        }
 out:
        write_unlock(&et->lock);
-       return false;
 }
 
-bool f2fs_init_extent_tree(struct inode *inode, struct f2fs_extent *i_ext)
+void f2fs_init_extent_tree(struct inode *inode, struct page *ipage)
 {
-       bool ret =  __f2fs_init_extent_tree(inode, i_ext);
+       __f2fs_init_extent_tree(inode, ipage);
 
        if (!F2FS_I(inode)->extent_tree)
                set_inode_flag(inode, FI_NO_EXTENT);
-
-       return ret;
 }
 
 static bool f2fs_lookup_extent_tree(struct inode *inode, pgoff_t pgofs,
index 2c6646d1976eaab75c683d2245295dd12ada0a18..70565d81320be15570510cc9c5256dbc67d22a32 100644 (file)
@@ -3798,7 +3798,7 @@ struct rb_entry *f2fs_lookup_rb_tree_ret(struct rb_root_cached *root,
 bool f2fs_check_rb_tree_consistence(struct f2fs_sb_info *sbi,
                                                struct rb_root_cached *root);
 unsigned int f2fs_shrink_extent_tree(struct f2fs_sb_info *sbi, int nr_shrink);
-bool f2fs_init_extent_tree(struct inode *inode, struct f2fs_extent *i_ext);
+void f2fs_init_extent_tree(struct inode *inode, struct page *ipage);
 void f2fs_drop_extent_tree(struct inode *inode);
 unsigned int f2fs_destroy_extent_node(struct inode *inode);
 void f2fs_destroy_extent_tree(struct inode *inode);
index 33affa788588ff95c4b0606656061c8e76b3dc3a..66969ae852b978a9a8435d11d4ba5e8a88218c50 100644 (file)
@@ -367,8 +367,7 @@ static int do_read_inode(struct inode *inode)
        fi->i_pino = le32_to_cpu(ri->i_pino);
        fi->i_dir_level = ri->i_dir_level;
 
-       if (f2fs_init_extent_tree(inode, &ri->i_ext))
-               set_page_dirty(node_page);
+       f2fs_init_extent_tree(inode, node_page);
 
        get_inline_info(inode, ri);