| From 643fe10a17ad7446124bc284eb270ee216d9395a Mon Sep 17 00:00:00 2001 |
| From: Jaegeuk Kim <jaegeuk@kernel.org> |
| Date: Tue, 26 Nov 2019 15:01:42 -0800 |
| Subject: [PATCH] f2fs: preallocate DIO blocks when forcing buffered_io |
| MIME-Version: 1.0 |
| Content-Type: text/plain; charset=UTF-8 |
| Content-Transfer-Encoding: 8bit |
| |
| commit 47501f87c61ad2aa234add63e1ae231521dbc3f5 upstream. |
| |
| 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> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c |
| index bc3454b04337..facfcdbb8355 100644 |
| --- a/fs/f2fs/data.c |
| +++ b/fs/f2fs/data.c |
| @@ -949,19 +949,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) |
| diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c |
| index 579d51fb5164..3d4ec1615bfa 100644 |
| --- a/fs/f2fs/file.c |
| +++ b/fs/f2fs/file.c |
| @@ -3084,18 +3084,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); |
| + goto write; |
| + } |
| |
| - err = f2fs_preallocate_blocks(iocb, from); |
| - if (err) { |
| - clear_inode_flag(inode, FI_NO_PREALLOC); |
| - inode_unlock(inode); |
| - ret = err; |
| - goto out; |
| - } |
| + 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); |
| |
| -- |
| 2.7.4 |
| |