OSDN Git Service

Merge tag 'f2fs-for-v3.10' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk...
[uclinux-h8/linux.git] / fs / f2fs / data.c
index 7bd22a2..91ff93b 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/f2fs_fs.h>
 #include <linux/buffer_head.h>
 #include <linux/mpage.h>
+#include <linux/aio.h>
 #include <linux/writeback.h>
 #include <linux/backing-dev.h>
 #include <linux/blkdev.h>
@@ -21,6 +22,7 @@
 #include "f2fs.h"
 #include "node.h"
 #include "segment.h"
+#include <trace/events/f2fs.h>
 
 /*
  * Lock ordering for the change of data block address:
@@ -54,6 +56,8 @@ int reserve_new_block(struct dnode_of_data *dn)
        if (!inc_valid_block_count(sbi, dn->inode, 1))
                return -ENOSPC;
 
+       trace_f2fs_reserve_new_block(dn->inode, dn->nid, dn->ofs_in_node);
+
        __set_data_blkaddr(dn, NEW_ADDR);
        dn->data_blkaddr = NEW_ADDR;
        sync_inode_page(dn);
@@ -133,7 +137,7 @@ void update_extent_cache(block_t blk_addr, struct dnode_of_data *dn)
                goto end_update;
        }
 
-       /* Frone merge */
+       /* Front merge */
        if (fofs == start_fofs - 1 && blk_addr == start_blkaddr - 1) {
                fi->ext.fofs--;
                fi->ext.blk_addr--;
@@ -169,7 +173,7 @@ end_update:
        return;
 }
 
-struct page *find_data_page(struct inode *inode, pgoff_t index)
+struct page *find_data_page(struct inode *inode, pgoff_t index, bool sync)
 {
        struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
        struct address_space *mapping = inode->i_mapping;
@@ -183,7 +187,7 @@ struct page *find_data_page(struct inode *inode, pgoff_t index)
        f2fs_put_page(page, 0);
 
        set_new_dnode(&dn, inode, NULL, NULL, 0);
-       err = get_dnode_of_data(&dn, index, RDONLY_NODE);
+       err = get_dnode_of_data(&dn, index, LOOKUP_NODE);
        if (err)
                return ERR_PTR(err);
        f2fs_put_dnode(&dn);
@@ -199,12 +203,20 @@ struct page *find_data_page(struct inode *inode, pgoff_t index)
        if (!page)
                return ERR_PTR(-ENOMEM);
 
-       err = f2fs_readpage(sbi, page, dn.data_blkaddr, READ_SYNC);
-       if (err) {
-               f2fs_put_page(page, 1);
-               return ERR_PTR(err);
+       if (PageUptodate(page)) {
+               unlock_page(page);
+               return page;
+       }
+
+       err = f2fs_readpage(sbi, page, dn.data_blkaddr,
+                                       sync ? READ_SYNC : READA);
+       if (sync) {
+               wait_on_page_locked(page);
+               if (!PageUptodate(page)) {
+                       f2fs_put_page(page, 0);
+                       return ERR_PTR(-EIO);
+               }
        }
-       unlock_page(page);
        return page;
 }
 
@@ -222,14 +234,14 @@ struct page *get_lock_data_page(struct inode *inode, pgoff_t index)
        int err;
 
        set_new_dnode(&dn, inode, NULL, NULL, 0);
-       err = get_dnode_of_data(&dn, index, RDONLY_NODE);
+       err = get_dnode_of_data(&dn, index, LOOKUP_NODE);
        if (err)
                return ERR_PTR(err);
        f2fs_put_dnode(&dn);
 
        if (dn.data_blkaddr == NULL_ADDR)
                return ERR_PTR(-ENOENT);
-
+repeat:
        page = grab_cache_page(mapping, index);
        if (!page)
                return ERR_PTR(-ENOMEM);
@@ -241,9 +253,17 @@ struct page *get_lock_data_page(struct inode *inode, pgoff_t index)
        BUG_ON(dn.data_blkaddr == NULL_ADDR);
 
        err = f2fs_readpage(sbi, page, dn.data_blkaddr, READ_SYNC);
-       if (err) {
-               f2fs_put_page(page, 1);
+       if (err)
                return ERR_PTR(err);
+
+       lock_page(page);
+       if (!PageUptodate(page)) {
+               f2fs_put_page(page, 1);
+               return ERR_PTR(-EIO);
+       }
+       if (page->mapping != mapping) {
+               f2fs_put_page(page, 1);
+               goto repeat;
        }
        return page;
 }
@@ -251,6 +271,9 @@ struct page *get_lock_data_page(struct inode *inode, pgoff_t index)
 /*
  * Caller ensures that this data page is never allocated.
  * A new zero-filled data page is allocated in the page cache.
+ *
+ * Also, caller should grab and release a mutex by calling mutex_lock_op() and
+ * mutex_unlock_op().
  */
 struct page *get_new_data_page(struct inode *inode, pgoff_t index,
                                                bool new_i_size)
@@ -262,7 +285,7 @@ struct page *get_new_data_page(struct inode *inode, pgoff_t index,
        int err;
 
        set_new_dnode(&dn, inode, NULL, NULL, 0);
-       err = get_dnode_of_data(&dn, index, 0);
+       err = get_dnode_of_data(&dn, index, ALLOC_NODE);
        if (err)
                return ERR_PTR(err);
 
@@ -273,7 +296,7 @@ struct page *get_new_data_page(struct inode *inode, pgoff_t index,
                }
        }
        f2fs_put_dnode(&dn);
-
+repeat:
        page = grab_cache_page(mapping, index);
        if (!page)
                return ERR_PTR(-ENOMEM);
@@ -283,14 +306,21 @@ struct page *get_new_data_page(struct inode *inode, pgoff_t index,
 
        if (dn.data_blkaddr == NEW_ADDR) {
                zero_user_segment(page, 0, PAGE_CACHE_SIZE);
+               SetPageUptodate(page);
        } else {
                err = f2fs_readpage(sbi, page, dn.data_blkaddr, READ_SYNC);
-               if (err) {
-                       f2fs_put_page(page, 1);
+               if (err)
                        return ERR_PTR(err);
+               lock_page(page);
+               if (!PageUptodate(page)) {
+                       f2fs_put_page(page, 1);
+                       return ERR_PTR(-EIO);
+               }
+               if (page->mapping != mapping) {
+                       f2fs_put_page(page, 1);
+                       goto repeat;
                }
        }
-       SetPageUptodate(page);
 
        if (new_i_size &&
                i_size_read(inode) < ((index + 1) << PAGE_CACHE_SHIFT)) {
@@ -325,21 +355,15 @@ static void read_end_io(struct bio *bio, int err)
 
 /*
  * Fill the locked page with data located in the block address.
- * Read operation is synchronous, and caller must unlock the page.
+ * Return unlocked page.
  */
 int f2fs_readpage(struct f2fs_sb_info *sbi, struct page *page,
                                        block_t blk_addr, int type)
 {
        struct block_device *bdev = sbi->sb->s_bdev;
-       bool sync = (type == READ_SYNC);
        struct bio *bio;
 
-       /* This page can be already read by other threads */
-       if (PageUptodate(page)) {
-               if (!sync)
-                       unlock_page(page);
-               return 0;
-       }
+       trace_f2fs_readpage(page, blk_addr, type);
 
        down_read(&sbi->bio_sem);
 
@@ -354,18 +378,12 @@ int f2fs_readpage(struct f2fs_sb_info *sbi, struct page *page,
                kfree(bio->bi_private);
                bio_put(bio);
                up_read(&sbi->bio_sem);
+               f2fs_put_page(page, 1);
                return -EFAULT;
        }
 
        submit_bio(type, bio);
        up_read(&sbi->bio_sem);
-
-       /* wait for read completion if sync */
-       if (sync) {
-               lock_page(page);
-               if (PageError(page))
-                       return -EIO;
-       }
        return 0;
 }
 
@@ -387,14 +405,18 @@ static int get_data_block_ro(struct inode *inode, sector_t iblock,
        /* Get the page offset from the block offset(iblock) */
        pgofs = (pgoff_t)(iblock >> (PAGE_CACHE_SHIFT - blkbits));
 
-       if (check_extent_cache(inode, pgofs, bh_result))
+       if (check_extent_cache(inode, pgofs, bh_result)) {
+               trace_f2fs_get_data_block(inode, iblock, bh_result, 0);
                return 0;
+       }
 
        /* When reading holes, we need its node page */
        set_new_dnode(&dn, inode, NULL, NULL, 0);
-       err = get_dnode_of_data(&dn, pgofs, RDONLY_NODE);
-       if (err)
+       err = get_dnode_of_data(&dn, pgofs, LOOKUP_NODE_RA);
+       if (err) {
+               trace_f2fs_get_data_block(inode, iblock, bh_result, err);
                return (err == -ENOENT) ? 0 : err;
+       }
 
        /* It does not support data allocation */
        BUG_ON(create);
@@ -419,6 +441,7 @@ static int get_data_block_ro(struct inode *inode, sector_t iblock,
                bh_result->b_size = (i << blkbits);
        }
        f2fs_put_dnode(&dn);
+       trace_f2fs_get_data_block(inode, iblock, bh_result, 0);
        return 0;
 }
 
@@ -437,13 +460,12 @@ static int f2fs_read_data_pages(struct file *file,
 int do_write_data_page(struct page *page)
 {
        struct inode *inode = page->mapping->host;
-       struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
        block_t old_blk_addr, new_blk_addr;
        struct dnode_of_data dn;
        int err = 0;
 
        set_new_dnode(&dn, inode, NULL, NULL, 0);
-       err = get_dnode_of_data(&dn, page->index, RDONLY_NODE);
+       err = get_dnode_of_data(&dn, page->index, LOOKUP_NODE);
        if (err)
                return err;
 
@@ -467,8 +489,6 @@ int do_write_data_page(struct page *page)
                write_data_page(inode, page, &dn,
                                old_blk_addr, &new_blk_addr);
                update_extent_cache(new_blk_addr, &dn);
-               F2FS_I(inode)->data_version =
-                       le64_to_cpu(F2FS_CKPT(sbi)->checkpoint_ver);
        }
 out_writepage:
        f2fs_put_dnode(&dn);
@@ -484,10 +504,11 @@ static int f2fs_write_data_page(struct page *page,
        const pgoff_t end_index = ((unsigned long long) i_size)
                                                        >> PAGE_CACHE_SHIFT;
        unsigned offset;
+       bool need_balance_fs = false;
        int err = 0;
 
        if (page->index < end_index)
-               goto out;
+               goto write;
 
        /*
         * If the offset is out-of-range of file size,
@@ -499,50 +520,46 @@ static int f2fs_write_data_page(struct page *page,
                        dec_page_count(sbi, F2FS_DIRTY_DENTS);
                        inode_dec_dirty_dents(inode);
                }
-               goto unlock_out;
+               goto out;
        }
 
        zero_user_segment(page, offset, PAGE_CACHE_SIZE);
-out:
-       if (sbi->por_doing)
-               goto redirty_out;
-
-       if (wbc->for_reclaim && !S_ISDIR(inode->i_mode) && !is_cold_data(page))
+write:
+       if (sbi->por_doing) {
+               err = AOP_WRITEPAGE_ACTIVATE;
                goto redirty_out;
+       }
 
-       mutex_lock_op(sbi, DATA_WRITE);
+       /* Dentry blocks are controlled by checkpoint */
        if (S_ISDIR(inode->i_mode)) {
                dec_page_count(sbi, F2FS_DIRTY_DENTS);
                inode_dec_dirty_dents(inode);
+               err = do_write_data_page(page);
+       } else {
+               int ilock = mutex_lock_op(sbi);
+               err = do_write_data_page(page);
+               mutex_unlock_op(sbi, ilock);
+               need_balance_fs = true;
        }
-       err = do_write_data_page(page);
-       if (err && err != -ENOENT) {
-               wbc->pages_skipped++;
-               set_page_dirty(page);
-       }
-       mutex_unlock_op(sbi, DATA_WRITE);
+       if (err == -ENOENT)
+               goto out;
+       else if (err)
+               goto redirty_out;
 
        if (wbc->for_reclaim)
                f2fs_submit_bio(sbi, DATA, true);
 
-       if (err == -ENOENT)
-               goto unlock_out;
-
        clear_cold_data(page);
+out:
        unlock_page(page);
-
-       if (!wbc->for_reclaim && !S_ISDIR(inode->i_mode))
+       if (need_balance_fs)
                f2fs_balance_fs(sbi);
        return 0;
 
-unlock_out:
-       unlock_page(page);
-       return (err == -ENOENT) ? 0 : err;
-
 redirty_out:
        wbc->pages_skipped++;
        set_page_dirty(page);
-       return AOP_WRITEPAGE_ACTIVATE;
+       return err;
 }
 
 #define MAX_DESIRED_PAGES_WP   4096
@@ -561,19 +578,26 @@ static int f2fs_write_data_pages(struct address_space *mapping,
 {
        struct inode *inode = mapping->host;
        struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
+       bool locked = false;
        int ret;
        long excess_nrtw = 0, desired_nrtw;
 
+       /* deal with chardevs and other special file */
+       if (!mapping->a_ops->writepage)
+               return 0;
+
        if (wbc->nr_to_write < MAX_DESIRED_PAGES_WP) {
                desired_nrtw = MAX_DESIRED_PAGES_WP;
                excess_nrtw = desired_nrtw - wbc->nr_to_write;
                wbc->nr_to_write = desired_nrtw;
        }
 
-       if (!S_ISDIR(inode->i_mode))
+       if (!S_ISDIR(inode->i_mode)) {
                mutex_lock(&sbi->writepages);
+               locked = true;
+       }
        ret = write_cache_pages(mapping, wbc, __f2fs_writepage, mapping);
-       if (!S_ISDIR(inode->i_mode))
+       if (locked)
                mutex_unlock(&sbi->writepages);
        f2fs_submit_bio(sbi, DATA, (wbc->sync_mode == WB_SYNC_ALL));
 
@@ -593,39 +617,33 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
        pgoff_t index = ((unsigned long long) pos) >> PAGE_CACHE_SHIFT;
        struct dnode_of_data dn;
        int err = 0;
+       int ilock;
 
        /* for nobh_write_end */
        *fsdata = NULL;
 
        f2fs_balance_fs(sbi);
-
+repeat:
        page = grab_cache_page_write_begin(mapping, index, flags);
        if (!page)
                return -ENOMEM;
        *pagep = page;
 
-       mutex_lock_op(sbi, DATA_NEW);
+       ilock = mutex_lock_op(sbi);
 
        set_new_dnode(&dn, inode, NULL, NULL, 0);
-       err = get_dnode_of_data(&dn, index, 0);
-       if (err) {
-               mutex_unlock_op(sbi, DATA_NEW);
-               f2fs_put_page(page, 1);
-               return err;
-       }
+       err = get_dnode_of_data(&dn, index, ALLOC_NODE);
+       if (err)
+               goto err;
 
-       if (dn.data_blkaddr == NULL_ADDR) {
+       if (dn.data_blkaddr == NULL_ADDR)
                err = reserve_new_block(&dn);
-               if (err) {
-                       f2fs_put_dnode(&dn);
-                       mutex_unlock_op(sbi, DATA_NEW);
-                       f2fs_put_page(page, 1);
-                       return err;
-               }
-       }
+
        f2fs_put_dnode(&dn);
+       if (err)
+               goto err;
 
-       mutex_unlock_op(sbi, DATA_NEW);
+       mutex_unlock_op(sbi, ilock);
 
        if ((len == PAGE_CACHE_SIZE) || PageUptodate(page))
                return 0;
@@ -636,21 +654,34 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
 
                /* Reading beyond i_size is simple: memset to zero */
                zero_user_segments(page, 0, start, end, PAGE_CACHE_SIZE);
-               return 0;
+               goto out;
        }
 
        if (dn.data_blkaddr == NEW_ADDR) {
                zero_user_segment(page, 0, PAGE_CACHE_SIZE);
        } else {
                err = f2fs_readpage(sbi, page, dn.data_blkaddr, READ_SYNC);
-               if (err) {
-                       f2fs_put_page(page, 1);
+               if (err)
                        return err;
+               lock_page(page);
+               if (!PageUptodate(page)) {
+                       f2fs_put_page(page, 1);
+                       return -EIO;
+               }
+               if (page->mapping != mapping) {
+                       f2fs_put_page(page, 1);
+                       goto repeat;
                }
        }
+out:
        SetPageUptodate(page);
        clear_cold_data(page);
        return 0;
+
+err:
+       mutex_unlock_op(sbi, ilock);
+       f2fs_put_page(page, 1);
+       return err;
 }
 
 static ssize_t f2fs_direct_IO(int rw, struct kiocb *iocb,
@@ -681,7 +712,7 @@ static void f2fs_invalidate_data_page(struct page *page, unsigned long offset)
 static int f2fs_release_data_page(struct page *page, gfp_t wait)
 {
        ClearPagePrivate(page);
-       return 0;
+       return 1;
 }
 
 static int f2fs_set_data_page_dirty(struct page *page)