f2fs: fix to avoid data update racing between GC and DIO
Datas in file can be operated by GC and DIO simultaneously, so we will face race case as below: For write case: Thread A Thread B - generic_file_direct_write - invalidate_inode_pages2_range - f2fs_direct_IO - do_blockdev_direct_IO - do_direct_IO - get_more_blocks - f2fs_gc - do_garbage_collect - gc_data_segment - move_data_page - do_write_data_page migrate data block to new block address - dio_bio_submit update user data to old block address For read case: Thread A Thread B - generic_file_direct_write - invalidate_inode_pages2_range - f2fs_direct_IO - do_blockdev_direct_IO - do_direct_IO - get_more_blocks - f2fs_balance_fs - f2fs_gc - do_garbage_collect - gc_data_segment - move_data_page - do_write_data_page migrate data block to new block address - write_checkpoint - do_checkpoint - clear_prefree_segments - f2fs_issue_discard discard old block adress - dio_bio_submit update user buffer from obsolete block address In order to fix this, for one file, we should let DIO and GC getting exclusion against with each other. Signed-off-by: Chao Yu <yuchao0@huawei.com> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
Este commit está contenido en:
20
fs/f2fs/gc.c
20
fs/f2fs/gc.c
@@ -755,12 +755,32 @@ next_step:
|
||||
/* phase 3 */
|
||||
inode = find_gc_inode(gc_list, dni.ino);
|
||||
if (inode) {
|
||||
struct f2fs_inode_info *fi = F2FS_I(inode);
|
||||
bool locked = false;
|
||||
|
||||
if (S_ISREG(inode->i_mode)) {
|
||||
if (!down_write_trylock(&fi->dio_rwsem[READ]))
|
||||
continue;
|
||||
if (!down_write_trylock(
|
||||
&fi->dio_rwsem[WRITE])) {
|
||||
up_write(&fi->dio_rwsem[READ]);
|
||||
continue;
|
||||
}
|
||||
locked = true;
|
||||
}
|
||||
|
||||
start_bidx = start_bidx_of_node(nofs, inode)
|
||||
+ ofs_in_node;
|
||||
if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode))
|
||||
move_encrypted_block(inode, start_bidx);
|
||||
else
|
||||
move_data_page(inode, start_bidx, gc_type);
|
||||
|
||||
if (locked) {
|
||||
up_write(&fi->dio_rwsem[WRITE]);
|
||||
up_write(&fi->dio_rwsem[READ]);
|
||||
}
|
||||
|
||||
stat_inc_data_blk_count(sbi, 1, gc_type);
|
||||
}
|
||||
}
|
||||
|
Referencia en una nueva incidencia
Block a user