Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

f2fs: prevent newly created inode from being dirtied incorrectly

Now, we invoke f2fs_mark_inode_dirty_sync() to make an inode dirty in
advance of creating a new node page for the inode. By this, some inodes
whose node page is not created yet can be linked into the global dirty
list.

If the checkpoint is executed at this moment, the inode will be written
back by writeback_single_inode() and finally update_inode_page() will
fail to detach the inode from the global dirty list because the inode
doesn't have a node page.

The problem is that the inode's state in VFS layer will become clean
after execution of writeback_single_inode() and it's still linked in
the global dirty list of f2fs and this will cause a kernel panic.

So, we will prevent the newly created inode from being dirtied during
the FI_NEW_INODE flag of the inode is set. We will make it dirty
right after the flag is cleared.

Signed-off-by: Daeho Jeong <daeho.jeong@samsung.com>
Signed-off-by: Youngjin Gil <youngjin.gil@samsung.com>
Tested-by: Hobin Woo <hobin.woo@samsung.com>
Reviewed-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>

authored by

Daeho Jeong and committed by
Jaegeuk Kim
9ac1e2d8 442a9dbd

+6 -2
+1
fs/f2fs/f2fs.h
··· 2150 2150 case FI_INLINE_XATTR: 2151 2151 case FI_INLINE_DATA: 2152 2152 case FI_INLINE_DENTRY: 2153 + case FI_NEW_INODE: 2153 2154 if (set) 2154 2155 return; 2155 2156 case FI_DATA_EXIST:
+3
fs/f2fs/inode.c
··· 22 22 23 23 void f2fs_mark_inode_dirty_sync(struct inode *inode, bool sync) 24 24 { 25 + if (is_inode_flag_set(inode, FI_NEW_INODE)) 26 + return; 27 + 25 28 if (f2fs_inode_dirtied(inode, sync)) 26 29 return; 27 30
+2 -2
fs/f2fs/namei.c
··· 74 74 if (err) 75 75 goto fail_drop; 76 76 77 + set_inode_flag(inode, FI_NEW_INODE); 78 + 77 79 /* If the directory encrypted, then we should encrypt the inode. */ 78 80 if (f2fs_encrypted_inode(dir) && f2fs_may_encrypt(inode)) 79 81 f2fs_set_encrypted_inode(inode); 80 - 81 - set_inode_flag(inode, FI_NEW_INODE); 82 82 83 83 if (f2fs_sb_has_extra_attr(sbi->sb)) { 84 84 set_inode_flag(inode, FI_EXTRA_ATTR);