Skip to content

Commit

Permalink
f2fs: fix data corruption issue with hardware encryption
Browse files Browse the repository at this point in the history
Direct IO can be used in case of hardware encryption. The following
scenario results into data corruption issue in this path -

Thread A -                          Thread B-
-> write file#1 in direct IO
                                    -> GC gets kicked in
                                    -> GC submitted bio on meta mapping
				       for file#1, but pending completion
-> write file#1 again with new data
   in direct IO
                                    -> GC bio gets completed now
                                    -> GC writes old data to the new
                                       location and thus file#1 is
				       corrupted.

Fix this by submitting and waiting for pending io on meta mapping
for direct IO case in f2fs_map_blocks().

Signed-off-by: Sahitya Tummala <stummala@codeaurora.org>
Reviewed-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
  • Loading branch information
Sahitya Tummala authored and Jaegeuk Kim committed Oct 23, 2018
1 parent 0c093b5 commit 1e78e8b
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 0 deletions.
11 changes: 11 additions & 0 deletions fs/f2fs/data.c
Original file line number Diff line number Diff line change
Expand Up @@ -1053,6 +1053,11 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map,
map->m_flags = F2FS_MAP_MAPPED;
if (map->m_next_extent)
*map->m_next_extent = pgofs + map->m_len;

/* for hardware encryption, but to avoid potential issue in future */
if (flag == F2FS_GET_BLOCK_DIO)
f2fs_wait_on_block_writeback_range(inode,
map->m_pblk, map->m_len);
goto out;
}

Expand Down Expand Up @@ -1211,6 +1216,12 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map,
goto next_dnode;

sync_out:

/* for hardware encryption, but to avoid potential issue in future */
if (flag == F2FS_GET_BLOCK_DIO && map->m_flags & F2FS_MAP_MAPPED)
f2fs_wait_on_block_writeback_range(inode,
map->m_pblk, map->m_len);

if (flag == F2FS_GET_BLOCK_PRECACHE) {
if (map->m_flags & F2FS_MAP_MAPPED) {
unsigned int ofs = start_pgofs - map->m_lblk;
Expand Down
2 changes: 2 additions & 0 deletions fs/f2fs/f2fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -2988,6 +2988,8 @@ void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,
void f2fs_wait_on_page_writeback(struct page *page,
enum page_type type, bool ordered);
void f2fs_wait_on_block_writeback(struct inode *inode, block_t blkaddr);
void f2fs_wait_on_block_writeback_range(struct inode *inode, block_t blkaddr,
block_t len);
void f2fs_write_data_summaries(struct f2fs_sb_info *sbi, block_t start_blk);
void f2fs_write_node_summaries(struct f2fs_sb_info *sbi, block_t start_blk);
int f2fs_lookup_journal_in_cursum(struct f2fs_journal *journal, int type,
Expand Down
9 changes: 9 additions & 0 deletions fs/f2fs/segment.c
Original file line number Diff line number Diff line change
Expand Up @@ -3303,6 +3303,15 @@ void f2fs_wait_on_block_writeback(struct inode *inode, block_t blkaddr)
}
}

void f2fs_wait_on_block_writeback_range(struct inode *inode, block_t blkaddr,
block_t len)
{
block_t i;

for (i = 0; i < len; i++)
f2fs_wait_on_block_writeback(inode, blkaddr + i);
}

static int read_compacted_summaries(struct f2fs_sb_info *sbi)
{
struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
Expand Down

0 comments on commit 1e78e8b

Please sign in to comment.