Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
[firefly-linux-kernel-4.4.55.git] / fs / f2fs / data.c
index 1d2e7e9624d2c4f5fc372a0f86be916169deebe4..0924521306b40c5087f2c2170c92fe7b03452862 100644 (file)
@@ -417,7 +417,7 @@ struct page *find_data_page(struct inode *inode, pgoff_t index, bool sync)
        if (unlikely(dn.data_blkaddr == NEW_ADDR))
                return ERR_PTR(-EINVAL);
 
-       page = grab_cache_page_write_begin(mapping, index, AOP_FLAG_NOFS);
+       page = grab_cache_page(mapping, index);
        if (!page)
                return ERR_PTR(-ENOMEM);
 
@@ -455,7 +455,7 @@ struct page *get_lock_data_page(struct inode *inode, pgoff_t index)
        int err;
 
 repeat:
-       page = grab_cache_page_write_begin(mapping, index, AOP_FLAG_NOFS);
+       page = grab_cache_page(mapping, index);
        if (!page)
                return ERR_PTR(-ENOMEM);
 
@@ -652,8 +652,7 @@ static int get_data_block(struct inode *inode, sector_t iblock,
                goto put_out;
        }
 
-       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));
        bh_result->b_size = (((size_t)1) << blkbits);
        dn.ofs_in_node++;
        pgofs++;
@@ -675,8 +674,7 @@ get_next:
                if (dn.data_blkaddr == NEW_ADDR)
                        goto put_out;
 
-               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));
        }
 
        if (maxblocks > (bh_result->b_size >> blkbits)) {
@@ -710,11 +708,19 @@ out:
        return err;
 }
 
+int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
+               u64 start, u64 len)
+{
+       return generic_block_fiemap(inode, fieinfo, start, len, get_data_block);
+}
+
 static int f2fs_read_data_page(struct file *file, struct page *page)
 {
        struct inode *inode = page->mapping->host;
        int ret;
 
+       trace_f2fs_readpage(page, DATA);
+
        /* If the file has inline data, try to read it directlly */
        if (f2fs_has_inline_data(inode))
                ret = f2fs_read_inline_data(inode, page);
@@ -790,6 +796,8 @@ static int f2fs_write_data_page(struct page *page,
                .rw = (wbc->sync_mode == WB_SYNC_ALL) ? WRITE_SYNC : WRITE,
        };
 
+       trace_f2fs_writepage(page, DATA);
+
        if (page->index < end_index)
                goto write;
 
@@ -798,10 +806,8 @@ static int f2fs_write_data_page(struct page *page,
         * this page does not have to be written to disk.
         */
        offset = i_size & (PAGE_CACHE_SIZE - 1);
-       if ((page->index >= end_index + 1) || !offset) {
-               inode_dec_dirty_dents(inode);
+       if ((page->index >= end_index + 1) || !offset)
                goto out;
-       }
 
        zero_user_segment(page, offset, PAGE_CACHE_SIZE);
 write:
@@ -810,7 +816,6 @@ write:
 
        /* Dentry blocks are controlled by checkpoint */
        if (S_ISDIR(inode->i_mode)) {
-               inode_dec_dirty_dents(inode);
                err = do_write_data_page(page, &fio);
                goto done;
        }
@@ -832,15 +837,16 @@ done:
 
        clear_cold_data(page);
 out:
+       inode_dec_dirty_dents(inode);
        unlock_page(page);
        if (need_balance_fs)
                f2fs_balance_fs(sbi);
+       if (wbc->for_reclaim)
+               f2fs_submit_merged_bio(sbi, DATA, WRITE);
        return 0;
 
 redirty_out:
-       wbc->pages_skipped++;
-       account_page_redirty(page);
-       set_page_dirty(page);
+       redirty_page_for_writepage(wbc, page);
        return AOP_WRITEPAGE_ACTIVATE;
 }
 
@@ -862,12 +868,15 @@ static int f2fs_write_data_pages(struct address_space *mapping,
        int ret;
        long diff;
 
+       trace_f2fs_writepages(mapping->host, wbc, DATA);
+
        /* deal with chardevs and other special file */
        if (!mapping->a_ops->writepage)
                return 0;
 
        if (S_ISDIR(inode->i_mode) && wbc->sync_mode == WB_SYNC_NONE &&
-                       get_dirty_dents(inode) < nr_pages_to_skip(sbi, DATA))
+                       get_dirty_dents(inode) < nr_pages_to_skip(sbi, DATA) &&
+                       available_free_memory(sbi, DIRTY_DENTS))
                goto skip_write;
 
        diff = nr_pages_to_write(sbi, DATA, wbc);
@@ -903,6 +912,8 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
        struct dnode_of_data dn;
        int err = 0;
 
+       trace_f2fs_write_begin(inode, pos, len, flags);
+
        f2fs_balance_fs(sbi);
 repeat:
        err = f2fs_convert_inline_data(inode, pos + len);
@@ -912,6 +923,10 @@ repeat:
        page = grab_cache_page_write_begin(mapping, index, flags);
        if (!page)
                return -ENOMEM;
+
+       /* to avoid latency during memory pressure */
+       unlock_page(page);
+
        *pagep = page;
 
        if (f2fs_has_inline_data(inode) && (pos + len) <= MAX_INLINE_DATA)
@@ -923,10 +938,18 @@ repeat:
        f2fs_unlock_op(sbi);
 
        if (err) {
-               f2fs_put_page(page, 1);
+               f2fs_put_page(page, 0);
                return err;
        }
 inline_data:
+       lock_page(page);
+       if (unlikely(page->mapping != mapping)) {
+               f2fs_put_page(page, 1);
+               goto repeat;
+       }
+
+       f2fs_wait_on_page_writeback(page, DATA);
+
        if ((len == PAGE_CACHE_SIZE) || PageUptodate(page))
                return 0;
 
@@ -978,6 +1001,8 @@ static int f2fs_write_end(struct file *file,
 {
        struct inode *inode = page->mapping->host;
 
+       trace_f2fs_write_end(inode, pos, len, copied);
+
        SetPageUptodate(page);
        set_page_dirty(page);
 
@@ -1021,6 +1046,9 @@ static ssize_t f2fs_direct_IO(int rw, struct kiocb *iocb,
        if (check_direct_IO(inode, rw, iter, offset))
                return 0;
 
+       /* clear fsync mark to recover these blocks */
+       fsync_mark_clear(F2FS_SB(inode->i_sb), inode->i_ino);
+
        return blockdev_direct_IO(rw, iocb, inode, iter, offset,
                                  get_data_block);
 }
@@ -1060,6 +1088,11 @@ static int f2fs_set_data_page_dirty(struct page *page)
 
 static sector_t f2fs_bmap(struct address_space *mapping, sector_t block)
 {
+       struct inode *inode = mapping->host;
+
+       if (f2fs_has_inline_data(inode))
+               return 0;
+
        return generic_block_bmap(mapping, block, get_data_block);
 }