]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
f2fs: fix to recover cold bit of inode block during POR
authorChao Yu <yuchao0@huawei.com>
Wed, 3 Oct 2018 14:32:44 +0000 (22:32 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 13 Nov 2018 19:08:39 +0000 (11:08 -0800)
commit ef2a007134b4eaa39264c885999f296577bc87d2 upstream.

Testcase to reproduce this bug:
1. mkfs.f2fs /dev/sdd
2. mount -t f2fs /dev/sdd /mnt/f2fs
3. touch /mnt/f2fs/file
4. sync
5. chattr +A /mnt/f2fs/file
6. xfs_io -f /mnt/f2fs/file -c "fsync"
7. godown /mnt/f2fs
8. umount /mnt/f2fs
9. mount -t f2fs /dev/sdd /mnt/f2fs
10. chattr -A /mnt/f2fs/file
11. xfs_io -f /mnt/f2fs/file -c "fsync"
12. umount /mnt/f2fs
13. mount -t f2fs /dev/sdd /mnt/f2fs
14. lsattr /mnt/f2fs/file

-----------------N- /mnt/f2fs/file

But actually, we expect the corrct result is:

-------A---------N- /mnt/f2fs/file

The reason is in step 9) we missed to recover cold bit flag in inode
block, so later, in fsync, we will skip write inode block due to below
condition check, result in lossing data in another SPOR.

f2fs_fsync_node_pages()
if (!IS_DNODE(page) || !is_cold_node(page))
continue;

Note that, I guess that some non-dir inode has already lost cold bit
during POR, so in order to reenable recovery for those inode, let's
try to recover cold bit in f2fs_iget() to save more fsynced data.

Fixes: c56675750d7c ("f2fs: remove unneeded set_cold_node()")
Cc: <stable@vger.kernel.org> 4.17+
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/f2fs/inode.c
fs/f2fs/node.c

index 959df2249875c484d6b7a51369fd97466e9002a8..dd608b819a3c330a2421cfacc187fcce3ebc8125 100644 (file)
@@ -368,6 +368,12 @@ static int do_read_inode(struct inode *inode)
        if (f2fs_has_inline_data(inode) && !f2fs_exist_data(inode))
                __recover_inline_status(inode, node_page);
 
+       /* try to recover cold bit for non-dir inode */
+       if (!S_ISDIR(inode->i_mode) && !is_cold_node(node_page)) {
+               set_cold_node(node_page, false);
+               set_page_dirty(node_page);
+       }
+
        /* get rdev by using inline_info */
        __get_inode_rdev(inode, ri);
 
index 96e6f47862a5aab08880bc931a5030ff9e133833..42ea42acb487ae819600bdd8e745e2241fce063f 100644 (file)
@@ -2539,7 +2539,7 @@ retry:
        if (!PageUptodate(ipage))
                SetPageUptodate(ipage);
        fill_node_footer(ipage, ino, ino, 0, true);
-       set_cold_node(page, false);
+       set_cold_node(ipage, false);
 
        src = F2FS_INODE(page);
        dst = F2FS_INODE(ipage);