Skip to content

Commit b7d6ef5

Browse files
WenjieQiHUSTgregkh
authored andcommitted
f2fs: keep atomic write retry from zeroing original data
[ Upstream commit 6d874b6 ] A partial atomic write reserves a block in the COW inode before reading the original data page for the untouched bytes in that page. If that read fails, write_begin returns an error but leaves the COW inode entry as NEW_ADDR. A retry of the same partial write then finds the COW entry, treats it as existing COW data, and f2fs_write_begin() zeroes the whole folio because blkaddr is NEW_ADDR. If the retry is committed, the bytes outside the retried write range are committed as zeroes instead of preserving the original file contents. Only use the COW inode as the read source when it already has a real data block. If the COW entry is still NEW_ADDR, treat it as a reservation to reuse: keep reading the old data from the original inode and avoid reserving or accounting the same atomic block again. Cc: stable@kernel.org Fixes: 3db1de0 ("f2fs: change the current atomic write way") Signed-off-by: Wenjie Qi <qiwenjie@xiaomi.com> Reviewed-by: Chao Yu <chao@kernel.org> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org> Signed-off-by: Sasha Levin <sashal@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 173b61c commit b7d6ef5

1 file changed

Lines changed: 11 additions & 5 deletions

File tree

fs/f2fs/data.c

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3561,6 +3561,7 @@ static int prepare_atomic_write_begin(struct f2fs_sb_info *sbi,
35613561
pgoff_t index = page->index;
35623562
int err = 0;
35633563
block_t ori_blk_addr = NULL_ADDR;
3564+
bool cow_has_reserved_block = false;
35643565

35653566
/* If pos is beyond the end of file, reserve a new block in COW inode */
35663567
if ((pos & PAGE_MASK) >= i_size_read(inode))
@@ -3570,8 +3571,10 @@ static int prepare_atomic_write_begin(struct f2fs_sb_info *sbi,
35703571
err = __find_data_block(cow_inode, index, blk_addr);
35713572
if (err)
35723573
return err;
3573-
else if (*blk_addr != NULL_ADDR)
3574+
else if (__is_valid_data_blkaddr(*blk_addr))
35743575
return 0;
3576+
else if (*blk_addr == NEW_ADDR)
3577+
cow_has_reserved_block = true;
35753578

35763579
/* Look for the block in the original inode */
35773580
err = __find_data_block(inode, index, &ori_blk_addr);
@@ -3580,10 +3583,13 @@ static int prepare_atomic_write_begin(struct f2fs_sb_info *sbi,
35803583

35813584
reserve_block:
35823585
/* Finally, we should reserve a new block in COW inode for the update */
3583-
err = __reserve_data_block(cow_inode, index, blk_addr, node_changed);
3584-
if (err)
3585-
return err;
3586-
inc_atomic_write_cnt(inode);
3586+
if (!cow_has_reserved_block) {
3587+
err = __reserve_data_block(cow_inode, index, blk_addr,
3588+
node_changed);
3589+
if (err)
3590+
return err;
3591+
inc_atomic_write_cnt(inode);
3592+
}
35873593

35883594
if (ori_blk_addr != NULL_ADDR)
35893595
*blk_addr = ori_blk_addr;

0 commit comments

Comments
 (0)