]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
f2fs: preallocate DIO blocks when forcing buffered_io
authorJaegeuk Kim <jaegeuk@kernel.org>
Tue, 26 Nov 2019 23:01:42 +0000 (15:01 -0800)
committerJaegeuk Kim <jaegeuk@kernel.org>
Mon, 9 Dec 2019 23:57:45 +0000 (15:57 -0800)
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>
fs/f2fs/data.c
fs/f2fs/file.c

index a034cd0ce02170a4477a4dfc2c01b0653f94cb0d..fc40a72f7827fff258c262c128e6a5b9d515e76c 100644 (file)
@@ -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)
index 85af112e868d18bd9c9f77b31349d8901f481206..e7fcbd8c23f4b24284ff50ad573b0288ea4fc65c 100644 (file)
@@ -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);
+                       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);