f2fs: fix redundant block allocation
authorJaegeuk Kim <jaegeuk@kernel.org>
Sat, 12 Nov 2016 00:46:40 +0000 (16:46 -0800)
committerJaegeuk Kim <jaegeuk@kernel.org>
Fri, 25 Nov 2016 18:15:50 +0000 (10:15 -0800)
In direct_IO path of f2fs_file_write_iter(),
1. f2fs_preallocate_blocks(F2FS_GET_BLOCK_PRE_DIO)
   -> allocate LBA X
2. f2fs_direct_IO()
   -> return 0;

Then,
f2fs_write_data_page() will allocate another LBA X+1.

This makes EIO triggered by HM-SMR.

Reviewed-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
fs/f2fs/data.c

index 2938311c97bf1e2c162fd08969f6686e51c8b350..59203a3c143eb5f866bada2d46ae552817970529 100644 (file)
@@ -658,6 +658,13 @@ alloc:
        return 0;
 }
 
+static inline bool __force_buffered_io(struct inode *inode, int rw)
+{
+       return ((f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode)) ||
+                       (rw == WRITE && test_opt(F2FS_I_SB(inode), LFS)) ||
+                       F2FS_I_SB(inode)->s_ndevs);
+}
+
 int f2fs_preallocate_blocks(struct kiocb *iocb, struct iov_iter *from)
 {
        struct inode *inode = file_inode(iocb->ki_filp);
@@ -677,7 +684,10 @@ int f2fs_preallocate_blocks(struct kiocb *iocb, struct iov_iter *from)
                err = f2fs_convert_inline_inode(inode);
                if (err)
                        return err;
-               return f2fs_map_blocks(inode, &map, 1, F2FS_GET_BLOCK_PRE_DIO);
+               return f2fs_map_blocks(inode, &map, 1,
+                       __force_buffered_io(inode, WRITE) ?
+                               F2FS_GET_BLOCK_PRE_AIO :
+                               F2FS_GET_BLOCK_PRE_DIO);
        }
        if (iocb->ki_pos + iov_iter_count(from) > MAX_INLINE_DATA) {
                err = f2fs_convert_inline_inode(inode);
@@ -1769,11 +1779,7 @@ static ssize_t f2fs_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
        if (err)
                return err;
 
-       if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode))
-               return 0;
-       if (rw == WRITE && test_opt(F2FS_I_SB(inode), LFS))
-               return 0;
-       if (F2FS_I_SB(inode)->s_ndevs)
+       if (__force_buffered_io(inode, rw))
                return 0;
 
        trace_f2fs_direct_IO_enter(inode, offset, count, rw);