f2fs: do not preallocate blocks which has wrong buffer
authorJaegeuk Kim <jaegeuk@kernel.org>
Fri, 13 Jan 2017 21:12:29 +0000 (13:12 -0800)
committerJaegeuk Kim <jaegeuk@kernel.org>
Thu, 23 Feb 2017 04:24:48 +0000 (20:24 -0800)
Sheng Yong reports needless preallocation if write(small_buffer, large_size)
is called.

In that case, f2fs preallocates large_size, but vfs returns early due to
small_buffer size. Let's detect it before preallocation phase in f2fs.

Reported-by: Sheng Yong <shengyong1@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
fs/f2fs/data.c
fs/f2fs/f2fs.h
fs/f2fs/file.c

index 848d110dc1ca1c178ba571c78a30a6808c5f2380..2ea80215f26ced9db3df57e2783b9c455730e586 100644 (file)
@@ -749,6 +749,9 @@ int f2fs_preallocate_blocks(struct kiocb *iocb, struct iov_iter *from)
        struct f2fs_map_blocks map;
        int err = 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)
@@ -1653,7 +1656,8 @@ static int prepare_write_begin(struct f2fs_sb_info *sbi,
         * we already allocated all the blocks, so we don't need to get
         * the block addresses when there is no need to fill the page.
         */
-       if (!f2fs_has_inline_data(inode) && len == PAGE_SIZE)
+       if (!f2fs_has_inline_data(inode) && len == PAGE_SIZE &&
+                       !is_inode_flag_set(inode, FI_NO_PREALLOC))
                return 0;
 
        if (f2fs_has_inline_data(inode) ||
index 5d97310363067723d361fddd60cf48f4e6ac85ce..0045ef9a9ad2ca4318027b80c3a95f2cf207c979 100644 (file)
@@ -1665,6 +1665,7 @@ enum {
        FI_INLINE_DOTS,         /* indicate inline dot dentries */
        FI_DO_DEFRAG,           /* indicate defragment is running */
        FI_DIRTY_FILE,          /* indicate regular/symlink has dirty pages */
+       FI_NO_PREALLOC,         /* indicate skipped preallocated blocks */
 };
 
 static inline void __mark_inode_dirty_flag(struct inode *inode,
index e45522115b1c7bface932e5b0b6ab89b867abc3a..9c0f469cde133ed9297947c6086a78d098491801 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/uaccess.h>
 #include <linux/mount.h>
 #include <linux/pagevec.h>
+#include <linux/uio.h>
 #include <linux/uuid.h>
 #include <linux/file.h>
 
@@ -2258,8 +2259,12 @@ static ssize_t f2fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
        inode_lock(inode);
        ret = generic_write_checks(iocb, from);
        if (ret > 0) {
-               int err = f2fs_preallocate_blocks(iocb, from);
+               int err;
 
+               if (iov_iter_fault_in_readable(from, iov_iter_count(from)))
+                       set_inode_flag(inode, FI_NO_PREALLOC);
+
+               err = f2fs_preallocate_blocks(iocb, from);
                if (err) {
                        inode_unlock(inode);
                        return err;
@@ -2267,6 +2272,7 @@ static ssize_t f2fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
                blk_start_plug(&plug);
                ret = __generic_file_write_iter(iocb, from);
                blk_finish_plug(&plug);
+               clear_inode_flag(inode, FI_NO_PREALLOC);
        }
        inode_unlock(inode);