Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
[cascardo/linux.git] / fs / f2fs / file.c
index 7d8b962..208f1a9 100644 (file)
@@ -127,12 +127,30 @@ int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
                return 0;
 
        trace_f2fs_sync_file_enter(inode);
+
+       /* if fdatasync is triggered, let's do in-place-update */
+       if (datasync)
+               set_inode_flag(fi, FI_NEED_IPU);
+
        ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
+       if (datasync)
+               clear_inode_flag(fi, FI_NEED_IPU);
        if (ret) {
                trace_f2fs_sync_file_exit(inode, need_cp, datasync, ret);
                return ret;
        }
 
+       /*
+        * if there is no written data, don't waste time to write recovery info.
+        */
+       if (!is_inode_flag_set(fi, FI_APPEND_WRITE) &&
+               !exist_written_data(sbi, inode->i_ino, APPEND_INO)) {
+               if (is_inode_flag_set(fi, FI_UPDATE_WRITE) ||
+                       exist_written_data(sbi, inode->i_ino, UPDATE_INO))
+                       goto flush_out;
+               goto out;
+       }
+
        /* guarantee free sections for fsync */
        f2fs_balance_fs(sbi);
 
@@ -188,6 +206,13 @@ int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
                ret = wait_on_node_pages_writeback(sbi, inode->i_ino);
                if (ret)
                        goto out;
+
+               /* once recovery info is written, don't need to tack this */
+               remove_dirty_inode(sbi, inode->i_ino, APPEND_INO);
+               clear_inode_flag(fi, FI_APPEND_WRITE);
+flush_out:
+               remove_dirty_inode(sbi, inode->i_ino, UPDATE_INO);
+               clear_inode_flag(fi, FI_UPDATE_WRITE);
                ret = f2fs_issue_flush(F2FS_SB(inode->i_sb));
        }
 out:
@@ -206,8 +231,9 @@ static pgoff_t __get_first_dirty_index(struct address_space *mapping,
 
        /* find first dirty page index */
        pagevec_init(&pvec, 0);
-       nr_pages = pagevec_lookup_tag(&pvec, mapping, &pgofs, PAGECACHE_TAG_DIRTY, 1);
-       pgofs = nr_pages ? pvec.pages[0]->index: LONG_MAX;
+       nr_pages = pagevec_lookup_tag(&pvec, mapping, &pgofs,
+                                       PAGECACHE_TAG_DIRTY, 1);
+       pgofs = nr_pages ? pvec.pages[0]->index : LONG_MAX;
        pagevec_release(&pvec);
        return pgofs;
 }
@@ -272,8 +298,7 @@ static loff_t f2fs_seek_block(struct file *file, loff_t offset, int whence)
                        }
                }
 
-               end_offset = IS_INODE(dn.node_page) ?
-                       ADDRS_PER_INODE(F2FS_I(inode)) : ADDRS_PER_BLOCK;
+               end_offset = ADDRS_PER_PAGE(dn.node_page, F2FS_I(inode));
 
                /* find data/hole in dnode block */
                for (; dn.ofs_in_node < end_offset;
@@ -380,13 +405,15 @@ static void truncate_partial_data_page(struct inode *inode, u64 from)
                return;
 
        lock_page(page);
-       if (unlikely(page->mapping != inode->i_mapping)) {
-               f2fs_put_page(page, 1);
-               return;
-       }
+       if (unlikely(!PageUptodate(page) ||
+                       page->mapping != inode->i_mapping))
+               goto out;
+
        f2fs_wait_on_page_writeback(page, DATA);
        zero_user(page, offset, PAGE_CACHE_SIZE - offset);
        set_page_dirty(page);
+
+out:
        f2fs_put_page(page, 1);
 }
 
@@ -645,6 +672,8 @@ static int expand_inode_data(struct inode *inode, loff_t offset,
        loff_t off_start, off_end;
        int ret = 0;
 
+       f2fs_balance_fs(sbi);
+
        ret = inode_newsize_ok(inode, (len + offset));
        if (ret)
                return ret;