Commit 47501f87 authored by Jaegeuk Kim's avatar Jaegeuk Kim

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: default avatarJavier Gonzalez <javier@javigon.com>
Signed-off-by: default avatarDamien Le Moal <damien.lemoal@wdc.com>
Tested-by: default avatarShin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
Reviewed-by: default avatarChao Yu <yuchao0@huawei.com>
Reviewed-by: default avatarJavier González <javier@javigon.com>
Signed-off-by: default avatarJaegeuk Kim <jaegeuk@kernel.org>
parent 6794862a
...@@ -1180,19 +1180,6 @@ int f2fs_preallocate_blocks(struct kiocb *iocb, struct iov_iter *from) ...@@ -1180,19 +1180,6 @@ int f2fs_preallocate_blocks(struct kiocb *iocb, struct iov_iter *from)
int err = 0; int err = 0;
bool direct_io = iocb->ki_flags & IOCB_DIRECT; 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_lblk = F2FS_BLK_ALIGN(iocb->ki_pos);
map.m_len = F2FS_BYTES_TO_BLK(iocb->ki_pos + iov_iter_count(from)); map.m_len = F2FS_BYTES_TO_BLK(iocb->ki_pos + iov_iter_count(from));
if (map.m_len > map.m_lblk) 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) ...@@ -3389,18 +3389,41 @@ static ssize_t f2fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
ret = -EAGAIN; ret = -EAGAIN;
goto out; goto out;
} }
} else { goto write;
preallocated = true; }
target_size = iocb->ki_pos + iov_iter_count(from);
err = f2fs_preallocate_blocks(iocb, from); if (is_inode_flag_set(inode, FI_NO_PREALLOC))
if (err) { goto write;
clear_inode_flag(inode, FI_NO_PREALLOC);
inode_unlock(inode); if (iocb->ki_flags & IOCB_DIRECT) {
ret = err; /*
goto out; * 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); ret = __generic_file_write_iter(iocb, from);
clear_inode_flag(inode, FI_NO_PREALLOC); clear_inode_flag(inode, FI_NO_PREALLOC);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment