forked from Minki/linux
f2fs: fix race between write_checkpoint and write_begin
The following race could lead to inconsistent SIT bitmap: Task A Task B ====== ====== f2fs_write_checkpoint block_operations f2fs_lock_all down_write(node_change) down_write(node_write) ... sync ... up_write(node_change) f2fs_file_write_iter set_inode_flag(FI_NO_PREALLOC) ...... f2fs_write_begin(index=0, has inline data) prepare_write_begin __do_map_lock(AIO) => down_read(node_change) f2fs_convert_inline_page => update SIT __do_map_lock(AIO) => up_read(node_change) f2fs_flush_sit_entries <= inconsistent SIT finish write checkpoint sudden-power-off If SPO occurs after checkpoint is finished, SIT bitmap will be set incorrectly. Signed-off-by: Sheng Yong <shengyong1@huawei.com> Reviewed-by: Chao Yu <yuchao0@huawei.com> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
This commit is contained in:
parent
4e240d1bab
commit
2866fb16d6
@ -2322,6 +2322,7 @@ static int prepare_write_begin(struct f2fs_sb_info *sbi,
|
||||
bool locked = false;
|
||||
struct extent_info ei = {0,0,0};
|
||||
int err = 0;
|
||||
int flag;
|
||||
|
||||
/*
|
||||
* we already allocated all the blocks, so we don't need to get
|
||||
@ -2331,9 +2332,15 @@ static int prepare_write_begin(struct f2fs_sb_info *sbi,
|
||||
!is_inode_flag_set(inode, FI_NO_PREALLOC))
|
||||
return 0;
|
||||
|
||||
/* f2fs_lock_op avoids race between write CP and convert_inline_page */
|
||||
if (f2fs_has_inline_data(inode) && pos + len > MAX_INLINE_DATA(inode))
|
||||
flag = F2FS_GET_BLOCK_DEFAULT;
|
||||
else
|
||||
flag = F2FS_GET_BLOCK_PRE_AIO;
|
||||
|
||||
if (f2fs_has_inline_data(inode) ||
|
||||
(pos & PAGE_MASK) >= i_size_read(inode)) {
|
||||
__do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO, true);
|
||||
__do_map_lock(sbi, flag, true);
|
||||
locked = true;
|
||||
}
|
||||
restart:
|
||||
@ -2371,6 +2378,7 @@ restart:
|
||||
f2fs_put_dnode(&dn);
|
||||
__do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO,
|
||||
true);
|
||||
WARN_ON(flag != F2FS_GET_BLOCK_PRE_AIO);
|
||||
locked = true;
|
||||
goto restart;
|
||||
}
|
||||
@ -2384,7 +2392,7 @@ out:
|
||||
f2fs_put_dnode(&dn);
|
||||
unlock_out:
|
||||
if (locked)
|
||||
__do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO, false);
|
||||
__do_map_lock(sbi, flag, false);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user