f2fs: preallocate DIO blocks when forcing buffered_io
The previous preallocation and DIO decision like below. allow_outplace_dio !allow_outplace_dio f2fs_force_buffered_io (*) No_Prealloc / Buffered_IO Prealloc / Buffered_IO !f2fs_force_buffered_io No_Prealloc / DIO Prealloc / DIO But, Javier reported Case (*) where zoned device bypassed preallocation but fell back to buffered writes in f2fs_direct_IO(), resulting in stale data being read. In order to fix the issue, actually we need to preallocate blocks whenever we fall back to buffered IO like this. No change is made in the other cases. allow_outplace_dio !allow_outplace_dio f2fs_force_buffered_io (*) Prealloc / Buffered_IO Prealloc / Buffered_IO !f2fs_force_buffered_io No_Prealloc / DIO Prealloc / DIO Reported-and-tested-by: Javier Gonzalez <javier@javigon.com> Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com> Tested-by: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com> Reviewed-by: Chao Yu <yuchao0@huawei.com> Reviewed-by: Javier González <javier@javigon.com> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
This commit is contained in:
parent
6794862a16
commit
47501f87c6
|
@ -1180,19 +1180,6 @@ int f2fs_preallocate_blocks(struct kiocb *iocb, struct iov_iter *from)
|
|||
int err = 0;
|
||||
bool direct_io = iocb->ki_flags & IOCB_DIRECT;
|
||||
|
||||
/* convert inline data for Direct I/O*/
|
||||
if (direct_io) {
|
||||
err = f2fs_convert_inline_inode(inode);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (direct_io && allow_outplace_dio(inode, iocb, from))
|
||||
return 0;
|
||||
|
||||
if (is_inode_flag_set(inode, FI_NO_PREALLOC))
|
||||
return 0;
|
||||
|
||||
map.m_lblk = F2FS_BLK_ALIGN(iocb->ki_pos);
|
||||
map.m_len = F2FS_BYTES_TO_BLK(iocb->ki_pos + iov_iter_count(from));
|
||||
if (map.m_len > map.m_lblk)
|
||||
|
|
|
@ -3389,18 +3389,41 @@ static ssize_t f2fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
|
|||
ret = -EAGAIN;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
preallocated = true;
|
||||
target_size = iocb->ki_pos + iov_iter_count(from);
|
||||
|
||||
err = f2fs_preallocate_blocks(iocb, from);
|
||||
if (err) {
|
||||
clear_inode_flag(inode, FI_NO_PREALLOC);
|
||||
inode_unlock(inode);
|
||||
ret = err;
|
||||
goto out;
|
||||
}
|
||||
goto write;
|
||||
}
|
||||
|
||||
if (is_inode_flag_set(inode, FI_NO_PREALLOC))
|
||||
goto write;
|
||||
|
||||
if (iocb->ki_flags & IOCB_DIRECT) {
|
||||
/*
|
||||
* Convert inline data for Direct I/O before entering
|
||||
* f2fs_direct_IO().
|
||||
*/
|
||||
err = f2fs_convert_inline_inode(inode);
|
||||
if (err)
|
||||
goto out_err;
|
||||
/*
|
||||
* If force_buffere_io() is true, we have to allocate
|
||||
* blocks all the time, since f2fs_direct_IO will fall
|
||||
* back to buffered IO.
|
||||
*/
|
||||
if (!f2fs_force_buffered_io(inode, iocb, from) &&
|
||||
allow_outplace_dio(inode, iocb, from))
|
||||
goto write;
|
||||
}
|
||||
preallocated = true;
|
||||
target_size = iocb->ki_pos + iov_iter_count(from);
|
||||
|
||||
err = f2fs_preallocate_blocks(iocb, from);
|
||||
if (err) {
|
||||
out_err:
|
||||
clear_inode_flag(inode, FI_NO_PREALLOC);
|
||||
inode_unlock(inode);
|
||||
ret = err;
|
||||
goto out;
|
||||
}
|
||||
write:
|
||||
ret = __generic_file_write_iter(iocb, from);
|
||||
clear_inode_flag(inode, FI_NO_PREALLOC);
|
||||
|
||||
|
|
Loading…
Reference in New Issue