OSDN Git Service

Merge tag 'f2fs-for-v3.10' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk...
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 8 May 2013 22:11:48 +0000 (15:11 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 8 May 2013 22:11:48 +0000 (15:11 -0700)
Pull f2fs updates from Jaegeuk Kim:
 "This patch-set includes the following major enhancement patches.
   - introduce a new gloabl lock scheme
   - add tracepoints on several major functions
   - fix the overall cleaning process focused on victim selection
   - apply the block plugging to merge IOs as much as possible
   - enhance management of free nids and its list
   - enhance the readahead mode for node pages
   - address several cretical deadlock conditions
   - reduce lock_page calls

  The other minor bug fixes and enhancements are as follows.
   - calculation mistakes: overflow
   - bio types: READ, READA, and READ_SYNC
   - fix the recovery flow, data races, and null pointer errors"

* tag 'f2fs-for-v3.10' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs: (68 commits)
  f2fs: cover free_nid management with spin_lock
  f2fs: optimize scan_nat_page()
  f2fs: code cleanup for scan_nat_page() and build_free_nids()
  f2fs: bugfix for alloc_nid_failed()
  f2fs: recover when journal contains deleted files
  f2fs: continue to mount after failing recovery
  f2fs: avoid deadlock during evict after f2fs_gc
  f2fs: modify the number of issued pages to merge IOs
  f2fs: remove useless #include <linux/proc_fs.h> as we're now using sysfs as debug entry.
  f2fs: fix inconsistent using of NM_WOUT_THRESHOLD
  f2fs: check truncation of mapping after lock_page
  f2fs: enhance alloc_nid and build_free_nids flows
  f2fs: add a tracepoint on f2fs_new_inode
  f2fs: check nid == 0 in add_free_nid
  f2fs: add REQ_META about metadata requests for submit
  f2fs: give a chance to merge IOs by IO scheduler
  f2fs: avoid frequent background GC
  f2fs: add tracepoints to debug checkpoint request
  f2fs: add tracepoints for write page operations
  f2fs: add tracepoints to debug the block allocation
  ...

20 files changed:
Documentation/filesystems/f2fs.txt
fs/f2fs/checkpoint.c
fs/f2fs/data.c
fs/f2fs/debug.c
fs/f2fs/dir.c
fs/f2fs/f2fs.h
fs/f2fs/file.c
fs/f2fs/gc.c
fs/f2fs/gc.h
fs/f2fs/inode.c
fs/f2fs/namei.c
fs/f2fs/node.c
fs/f2fs/node.h
fs/f2fs/recovery.c
fs/f2fs/segment.c
fs/f2fs/segment.h
fs/f2fs/super.c
fs/f2fs/xattr.c
include/linux/f2fs_fs.h
include/trace/events/f2fs.h [new file with mode: 0644]

index dcf338e..bd3c56c 100644 (file)
@@ -146,7 +146,7 @@ USAGE
 
 Format options
 --------------
--l [label]   : Give a volume label, up to 256 unicode name.
+-l [label]   : Give a volume label, up to 512 unicode name.
 -a [0 or 1]  : Split start location of each area for heap-based allocation.
                1 is set by default, which performs this.
 -o [int]     : Set overprovision ratio in percent over volume size.
@@ -156,6 +156,8 @@ Format options
 -z [int]     : Set the number of sections per zone.
                1 is set by default.
 -e [str]     : Set basic extension list. e.g. "mp3,gif,mov"
+-t [0 or 1]  : Disable discard command or not.
+               1 is set by default, which conducts discard.
 
 ================================================================================
 DESIGN
index 2b6fc13..b1de01d 100644 (file)
@@ -20,6 +20,7 @@
 #include "f2fs.h"
 #include "node.h"
 #include "segment.h"
+#include <trace/events/f2fs.h>
 
 static struct kmem_cache *orphan_entry_slab;
 static struct kmem_cache *inode_entry_slab;
@@ -57,13 +58,19 @@ repeat:
                cond_resched();
                goto repeat;
        }
-       if (f2fs_readpage(sbi, page, index, READ_SYNC)) {
+       if (PageUptodate(page))
+               goto out;
+
+       if (f2fs_readpage(sbi, page, index, READ_SYNC))
+               goto repeat;
+
+       lock_page(page);
+       if (page->mapping != mapping) {
                f2fs_put_page(page, 1);
                goto repeat;
        }
+out:
        mark_page_accessed(page);
-
-       /* We do not allow returning an errorneous page */
        return page;
 }
 
@@ -541,54 +548,44 @@ retry:
  */
 static void block_operations(struct f2fs_sb_info *sbi)
 {
-       int t;
        struct writeback_control wbc = {
                .sync_mode = WB_SYNC_ALL,
                .nr_to_write = LONG_MAX,
                .for_reclaim = 0,
        };
+       struct blk_plug plug;
 
-       /* Stop renaming operation */
-       mutex_lock_op(sbi, RENAME);
-       mutex_lock_op(sbi, DENTRY_OPS);
+       blk_start_plug(&plug);
 
-retry_dents:
-       /* write all the dirty dentry pages */
-       sync_dirty_dir_inodes(sbi);
+retry_flush_dents:
+       mutex_lock_all(sbi);
 
-       mutex_lock_op(sbi, DATA_WRITE);
+       /* write all the dirty dentry pages */
        if (get_pages(sbi, F2FS_DIRTY_DENTS)) {
-               mutex_unlock_op(sbi, DATA_WRITE);
-               goto retry_dents;
+               mutex_unlock_all(sbi);
+               sync_dirty_dir_inodes(sbi);
+               goto retry_flush_dents;
        }
 
-       /* block all the operations */
-       for (t = DATA_NEW; t <= NODE_TRUNC; t++)
-               mutex_lock_op(sbi, t);
-
-       mutex_lock(&sbi->write_inode);
-
        /*
         * POR: we should ensure that there is no dirty node pages
         * until finishing nat/sit flush.
         */
-retry:
-       sync_node_pages(sbi, 0, &wbc);
-
-       mutex_lock_op(sbi, NODE_WRITE);
+retry_flush_nodes:
+       mutex_lock(&sbi->node_write);
 
        if (get_pages(sbi, F2FS_DIRTY_NODES)) {
-               mutex_unlock_op(sbi, NODE_WRITE);
-               goto retry;
+               mutex_unlock(&sbi->node_write);
+               sync_node_pages(sbi, 0, &wbc);
+               goto retry_flush_nodes;
        }
-       mutex_unlock(&sbi->write_inode);
+       blk_finish_plug(&plug);
 }
 
 static void unblock_operations(struct f2fs_sb_info *sbi)
 {
-       int t;
-       for (t = NODE_WRITE; t >= RENAME; t--)
-               mutex_unlock_op(sbi, t);
+       mutex_unlock(&sbi->node_write);
+       mutex_unlock_all(sbi);
 }
 
 static void do_checkpoint(struct f2fs_sb_info *sbi, bool is_umount)
@@ -727,9 +724,13 @@ void write_checkpoint(struct f2fs_sb_info *sbi, bool is_umount)
        struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
        unsigned long long ckpt_ver;
 
+       trace_f2fs_write_checkpoint(sbi->sb, is_umount, "start block_ops");
+
        mutex_lock(&sbi->cp_mutex);
        block_operations(sbi);
 
+       trace_f2fs_write_checkpoint(sbi->sb, is_umount, "finish block_ops");
+
        f2fs_submit_bio(sbi, DATA, true);
        f2fs_submit_bio(sbi, NODE, true);
        f2fs_submit_bio(sbi, META, true);
@@ -746,13 +747,13 @@ void write_checkpoint(struct f2fs_sb_info *sbi, bool is_umount)
        flush_nat_entries(sbi);
        flush_sit_entries(sbi);
 
-       reset_victim_segmap(sbi);
-
        /* unlock all the fs_lock[] in do_checkpoint() */
        do_checkpoint(sbi, is_umount);
 
        unblock_operations(sbi);
        mutex_unlock(&sbi->cp_mutex);
+
+       trace_f2fs_write_checkpoint(sbi->sb, is_umount, "finish checkpoint");
 }
 
 void init_orphan_info(struct f2fs_sb_info *sbi)
index d0ed4ba..91ff93b 100644 (file)
@@ -22,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:
@@ -55,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);
@@ -134,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--;
@@ -170,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;
@@ -184,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);
@@ -200,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;
 }
 
@@ -223,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);
@@ -242,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;
 }
@@ -252,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)
@@ -263,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);
 
@@ -274,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);
@@ -284,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)) {
@@ -326,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);
 
@@ -355,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;
 }
 
@@ -388,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);
@@ -420,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;
 }
 
@@ -438,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;
 
@@ -468,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);
@@ -485,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,
@@ -500,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
@@ -562,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));
 
@@ -594,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;
@@ -637,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,
@@ -682,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)
index 025b9e2..8d99437 100644 (file)
@@ -13,7 +13,6 @@
 
 #include <linux/fs.h>
 #include <linux/backing-dev.h>
-#include <linux/proc_fs.h>
 #include <linux/f2fs_fs.h>
 #include <linux/blkdev.h>
 #include <linux/debugfs.h>
@@ -106,7 +105,7 @@ static void update_sit_info(struct f2fs_sb_info *sbi)
                }
        }
        mutex_unlock(&sit_i->sentry_lock);
-       dist = sbi->total_sections * hblks_per_sec * hblks_per_sec / 100;
+       dist = TOTAL_SECS(sbi) * hblks_per_sec * hblks_per_sec / 100;
        si->bimodal = bimodal / dist;
        if (si->dirty_count)
                si->avg_vblocks = total_vblocks / ndirty;
@@ -138,14 +137,13 @@ static void update_mem_info(struct f2fs_sb_info *sbi)
        si->base_mem += f2fs_bitmap_size(TOTAL_SEGS(sbi));
        si->base_mem += 2 * SIT_VBLOCK_MAP_SIZE * TOTAL_SEGS(sbi);
        if (sbi->segs_per_sec > 1)
-               si->base_mem += sbi->total_sections *
-                       sizeof(struct sec_entry);
+               si->base_mem += TOTAL_SECS(sbi) * sizeof(struct sec_entry);
        si->base_mem += __bitmap_size(sbi, SIT_BITMAP);
 
        /* build free segmap */
        si->base_mem += sizeof(struct free_segmap_info);
        si->base_mem += f2fs_bitmap_size(TOTAL_SEGS(sbi));
-       si->base_mem += f2fs_bitmap_size(sbi->total_sections);
+       si->base_mem += f2fs_bitmap_size(TOTAL_SECS(sbi));
 
        /* build curseg */
        si->base_mem += sizeof(struct curseg_info) * NR_CURSEG_TYPE;
@@ -154,7 +152,7 @@ static void update_mem_info(struct f2fs_sb_info *sbi)
        /* build dirty segmap */
        si->base_mem += sizeof(struct dirty_seglist_info);
        si->base_mem += NR_DIRTY_TYPE * f2fs_bitmap_size(TOTAL_SEGS(sbi));
-       si->base_mem += 2 * f2fs_bitmap_size(TOTAL_SEGS(sbi));
+       si->base_mem += f2fs_bitmap_size(TOTAL_SECS(sbi));
 
        /* buld nm */
        si->base_mem += sizeof(struct f2fs_nm_info);
index 1be9487..1ac6b93 100644 (file)
@@ -148,7 +148,7 @@ static struct f2fs_dir_entry *find_in_level(struct inode *dir,
 
        for (; bidx < end_block; bidx++) {
                /* no need to allocate new dentry pages to all the indices */
-               dentry_page = find_data_page(dir, bidx);
+               dentry_page = find_data_page(dir, bidx, true);
                if (IS_ERR(dentry_page)) {
                        room = true;
                        continue;
@@ -189,6 +189,9 @@ struct f2fs_dir_entry *f2fs_find_entry(struct inode *dir,
        unsigned int max_depth;
        unsigned int level;
 
+       if (namelen > F2FS_NAME_LEN)
+               return NULL;
+
        if (npages == 0)
                return NULL;
 
@@ -246,9 +249,6 @@ ino_t f2fs_inode_by_name(struct inode *dir, struct qstr *qstr)
 void f2fs_set_link(struct inode *dir, struct f2fs_dir_entry *de,
                struct page *page, struct inode *inode)
 {
-       struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb);
-
-       mutex_lock_op(sbi, DENTRY_OPS);
        lock_page(page);
        wait_on_page_writeback(page);
        de->ino = cpu_to_le32(inode->i_ino);
@@ -262,7 +262,6 @@ void f2fs_set_link(struct inode *dir, struct f2fs_dir_entry *de,
        F2FS_I(inode)->i_pino = dir->i_ino;
 
        f2fs_put_page(page, 1);
-       mutex_unlock_op(sbi, DENTRY_OPS);
 }
 
 void init_dent_inode(const struct qstr *name, struct page *ipage)
@@ -281,6 +280,43 @@ void init_dent_inode(const struct qstr *name, struct page *ipage)
        set_page_dirty(ipage);
 }
 
+static int make_empty_dir(struct inode *inode, struct inode *parent)
+{
+       struct page *dentry_page;
+       struct f2fs_dentry_block *dentry_blk;
+       struct f2fs_dir_entry *de;
+       void *kaddr;
+
+       dentry_page = get_new_data_page(inode, 0, true);
+       if (IS_ERR(dentry_page))
+               return PTR_ERR(dentry_page);
+
+       kaddr = kmap_atomic(dentry_page);
+       dentry_blk = (struct f2fs_dentry_block *)kaddr;
+
+       de = &dentry_blk->dentry[0];
+       de->name_len = cpu_to_le16(1);
+       de->hash_code = 0;
+       de->ino = cpu_to_le32(inode->i_ino);
+       memcpy(dentry_blk->filename[0], ".", 1);
+       set_de_type(de, inode);
+
+       de = &dentry_blk->dentry[1];
+       de->hash_code = 0;
+       de->name_len = cpu_to_le16(2);
+       de->ino = cpu_to_le32(parent->i_ino);
+       memcpy(dentry_blk->filename[1], "..", 2);
+       set_de_type(de, inode);
+
+       test_and_set_bit_le(0, &dentry_blk->dentry_bitmap);
+       test_and_set_bit_le(1, &dentry_blk->dentry_bitmap);
+       kunmap_atomic(kaddr);
+
+       set_page_dirty(dentry_page);
+       f2fs_put_page(dentry_page, 1);
+       return 0;
+}
+
 static int init_inode_metadata(struct inode *inode,
                struct inode *dir, const struct qstr *name)
 {
@@ -291,7 +327,7 @@ static int init_inode_metadata(struct inode *inode,
                        return err;
 
                if (S_ISDIR(inode->i_mode)) {
-                       err = f2fs_make_empty(inode, dir);
+                       err = make_empty_dir(inode, dir);
                        if (err) {
                                remove_inode_page(inode);
                                return err;
@@ -314,7 +350,7 @@ static int init_inode_metadata(struct inode *inode,
        }
        if (is_inode_flag_set(F2FS_I(inode), FI_INC_LINK)) {
                inc_nlink(inode);
-               f2fs_write_inode(inode, NULL);
+               update_inode_page(inode);
        }
        return 0;
 }
@@ -338,7 +374,7 @@ static void update_parent_metadata(struct inode *dir, struct inode *inode,
        }
 
        if (need_dir_update)
-               f2fs_write_inode(dir, NULL);
+               update_inode_page(dir);
        else
                mark_inode_dirty(dir);
 
@@ -370,6 +406,10 @@ next:
        goto next;
 }
 
+/*
+ * Caller should grab and release a mutex by calling mutex_lock_op() and
+ * mutex_unlock_op().
+ */
 int __f2fs_add_link(struct inode *dir, const struct qstr *name, struct inode *inode)
 {
        unsigned int bit_pos;
@@ -379,7 +419,6 @@ int __f2fs_add_link(struct inode *dir, const struct qstr *name, struct inode *in
        f2fs_hash_t dentry_hash;
        struct f2fs_dir_entry *de;
        unsigned int nbucket, nblock;
-       struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb);
        size_t namelen = name->len;
        struct page *dentry_page = NULL;
        struct f2fs_dentry_block *dentry_blk = NULL;
@@ -409,12 +448,9 @@ start:
        bidx = dir_block_index(level, (le32_to_cpu(dentry_hash) % nbucket));
 
        for (block = bidx; block <= (bidx + nblock - 1); block++) {
-               mutex_lock_op(sbi, DENTRY_OPS);
                dentry_page = get_new_data_page(dir, block, true);
-               if (IS_ERR(dentry_page)) {
-                       mutex_unlock_op(sbi, DENTRY_OPS);
+               if (IS_ERR(dentry_page))
                        return PTR_ERR(dentry_page);
-               }
 
                dentry_blk = kmap(dentry_page);
                bit_pos = room_for_filename(dentry_blk, slots);
@@ -423,7 +459,6 @@ start:
 
                kunmap(dentry_page);
                f2fs_put_page(dentry_page, 1);
-               mutex_unlock_op(sbi, DENTRY_OPS);
        }
 
        /* Move to next level to find the empty slot for new dentry */
@@ -453,7 +488,6 @@ add_dentry:
 fail:
        kunmap(dentry_page);
        f2fs_put_page(dentry_page, 1);
-       mutex_unlock_op(sbi, DENTRY_OPS);
        return err;
 }
 
@@ -473,8 +507,6 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page,
        void *kaddr = page_address(page);
        int i;
 
-       mutex_lock_op(sbi, DENTRY_OPS);
-
        lock_page(page);
        wait_on_page_writeback(page);
 
@@ -494,7 +526,7 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page,
 
        if (inode && S_ISDIR(inode->i_mode)) {
                drop_nlink(dir);
-               f2fs_write_inode(dir, NULL);
+               update_inode_page(dir);
        } else {
                mark_inode_dirty(dir);
        }
@@ -506,7 +538,8 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page,
                        drop_nlink(inode);
                        i_size_write(inode, 0);
                }
-               f2fs_write_inode(inode, NULL);
+               update_inode_page(inode);
+
                if (inode->i_nlink == 0)
                        add_orphan_inode(sbi, inode->i_ino);
        }
@@ -519,45 +552,6 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page,
                inode_dec_dirty_dents(dir);
        }
        f2fs_put_page(page, 1);
-
-       mutex_unlock_op(sbi, DENTRY_OPS);
-}
-
-int f2fs_make_empty(struct inode *inode, struct inode *parent)
-{
-       struct page *dentry_page;
-       struct f2fs_dentry_block *dentry_blk;
-       struct f2fs_dir_entry *de;
-       void *kaddr;
-
-       dentry_page = get_new_data_page(inode, 0, true);
-       if (IS_ERR(dentry_page))
-               return PTR_ERR(dentry_page);
-
-       kaddr = kmap_atomic(dentry_page);
-       dentry_blk = (struct f2fs_dentry_block *)kaddr;
-
-       de = &dentry_blk->dentry[0];
-       de->name_len = cpu_to_le16(1);
-       de->hash_code = f2fs_dentry_hash(".", 1);
-       de->ino = cpu_to_le32(inode->i_ino);
-       memcpy(dentry_blk->filename[0], ".", 1);
-       set_de_type(de, inode);
-
-       de = &dentry_blk->dentry[1];
-       de->hash_code = f2fs_dentry_hash("..", 2);
-       de->name_len = cpu_to_le16(2);
-       de->ino = cpu_to_le32(parent->i_ino);
-       memcpy(dentry_blk->filename[1], "..", 2);
-       set_de_type(de, inode);
-
-       test_and_set_bit_le(0, &dentry_blk->dentry_bitmap);
-       test_and_set_bit_le(1, &dentry_blk->dentry_bitmap);
-       kunmap_atomic(kaddr);
-
-       set_page_dirty(dentry_page);
-       f2fs_put_page(dentry_page, 1);
-       return 0;
 }
 
 bool f2fs_empty_dir(struct inode *dir)
index 201c8d3..20aab02 100644 (file)
@@ -125,11 +125,15 @@ static inline int update_sits_in_cursum(struct f2fs_summary_block *rs, int i)
                                         * file keeping -1 as its node offset to
                                         * distinguish from index node blocks.
                                         */
-#define RDONLY_NODE            1       /*
-                                        * specify a read-only mode when getting
-                                        * a node block. 0 is read-write mode.
-                                        * used by get_dnode_of_data().
+enum {
+       ALLOC_NODE,                     /* allocate a new node page if needed */
+       LOOKUP_NODE,                    /* look up a node without readahead */
+       LOOKUP_NODE_RA,                 /*
+                                        * look up a node with readahead called
+                                        * by get_datablock_ro.
                                         */
+};
+
 #define F2FS_LINK_MAX          32000   /* maximum link count per file */
 
 /* for in-memory extent cache entry */
@@ -144,6 +148,7 @@ struct extent_info {
  * i_advise uses FADVISE_XXX_BIT. We can add additional hints later.
  */
 #define FADVISE_COLD_BIT       0x01
+#define FADVISE_CP_BIT         0x02
 
 struct f2fs_inode_info {
        struct inode vfs_inode;         /* serve a vfs inode */
@@ -155,7 +160,6 @@ struct f2fs_inode_info {
 
        /* Use below internally in f2fs*/
        unsigned long flags;            /* use to pass per-file flags */
-       unsigned long long data_version;/* latest version of data for fsync */
        atomic_t dirty_dents;           /* # of dirty dentry pages */
        f2fs_hash_t chash;              /* hash value of given file name */
        unsigned int clevel;            /* maximum level of given file name */
@@ -186,7 +190,6 @@ static inline void set_raw_extent(struct extent_info *ext,
 struct f2fs_nm_info {
        block_t nat_blkaddr;            /* base disk address of NAT */
        nid_t max_nid;                  /* maximum possible node ids */
-       nid_t init_scan_nid;            /* the first nid to be scanned */
        nid_t next_scan_nid;            /* the next nid to be scanned */
 
        /* NAT cache management */
@@ -305,23 +308,12 @@ enum count_type {
 };
 
 /*
- * FS_LOCK nesting subclasses for the lock validator:
- *
- * The locking order between these classes is
- * RENAME -> DENTRY_OPS -> DATA_WRITE -> DATA_NEW
- *    -> DATA_TRUNC -> NODE_WRITE -> NODE_NEW -> NODE_TRUNC
+ * Uses as sbi->fs_lock[NR_GLOBAL_LOCKS].
+ * The checkpoint procedure blocks all the locks in this fs_lock array.
+ * Some FS operations grab free locks, and if there is no free lock,
+ * then wait to grab a lock in a round-robin manner.
  */
-enum lock_type {
-       RENAME,         /* for renaming operations */
-       DENTRY_OPS,     /* for directory operations */
-       DATA_WRITE,     /* for data write */
-       DATA_NEW,       /* for data allocation */
-       DATA_TRUNC,     /* for data truncate */
-       NODE_NEW,       /* for node allocation */
-       NODE_TRUNC,     /* for node truncate */
-       NODE_WRITE,     /* for node write */
-       NR_LOCK_TYPE,
-};
+#define NR_GLOBAL_LOCKS        8
 
 /*
  * The below are the page types of bios used in submti_bio().
@@ -361,11 +353,13 @@ struct f2fs_sb_info {
        /* for checkpoint */
        struct f2fs_checkpoint *ckpt;           /* raw checkpoint pointer */
        struct inode *meta_inode;               /* cache meta blocks */
-       struct mutex cp_mutex;                  /* for checkpoint procedure */
-       struct mutex fs_lock[NR_LOCK_TYPE];     /* for blocking FS operations */
-       struct mutex write_inode;               /* mutex for write inode */
+       struct mutex cp_mutex;                  /* checkpoint procedure lock */
+       struct mutex fs_lock[NR_GLOBAL_LOCKS];  /* blocking FS operations */
+       struct mutex node_write;                /* locking node writes */
        struct mutex writepages;                /* mutex for writepages() */
+       unsigned char next_lock_num;            /* round-robin global locks */
        int por_doing;                          /* recovery is doing or not */
+       int on_build_free_nids;                 /* build_free_nids is doing */
 
        /* for orphan inode management */
        struct list_head orphan_inode_list;     /* orphan inode list */
@@ -406,6 +400,7 @@ struct f2fs_sb_info {
        /* for cleaning operations */
        struct mutex gc_mutex;                  /* mutex for GC */
        struct f2fs_gc_kthread  *gc_thread;     /* GC thread */
+       unsigned int cur_victim_sec;            /* current victim section num */
 
        /*
         * for stat information.
@@ -498,22 +493,51 @@ static inline void clear_ckpt_flags(struct f2fs_checkpoint *cp, unsigned int f)
        cp->ckpt_flags = cpu_to_le32(ckpt_flags);
 }
 
-static inline void mutex_lock_op(struct f2fs_sb_info *sbi, enum lock_type t)
+static inline void mutex_lock_all(struct f2fs_sb_info *sbi)
 {
-       mutex_lock_nested(&sbi->fs_lock[t], t);
+       int i = 0;
+       for (; i < NR_GLOBAL_LOCKS; i++)
+               mutex_lock(&sbi->fs_lock[i]);
 }
 
-static inline void mutex_unlock_op(struct f2fs_sb_info *sbi, enum lock_type t)
+static inline void mutex_unlock_all(struct f2fs_sb_info *sbi)
 {
-       mutex_unlock(&sbi->fs_lock[t]);
+       int i = 0;
+       for (; i < NR_GLOBAL_LOCKS; i++)
+               mutex_unlock(&sbi->fs_lock[i]);
+}
+
+static inline int mutex_lock_op(struct f2fs_sb_info *sbi)
+{
+       unsigned char next_lock = sbi->next_lock_num % NR_GLOBAL_LOCKS;
+       int i = 0;
+
+       for (; i < NR_GLOBAL_LOCKS; i++)
+               if (mutex_trylock(&sbi->fs_lock[i]))
+                       return i;
+
+       mutex_lock(&sbi->fs_lock[next_lock]);
+       sbi->next_lock_num++;
+       return next_lock;
+}
+
+static inline void mutex_unlock_op(struct f2fs_sb_info *sbi, int ilock)
+{
+       if (ilock < 0)
+               return;
+       BUG_ON(ilock >= NR_GLOBAL_LOCKS);
+       mutex_unlock(&sbi->fs_lock[ilock]);
 }
 
 /*
  * Check whether the given nid is within node id range.
  */
-static inline void check_nid_range(struct f2fs_sb_info *sbi, nid_t nid)
+static inline int check_nid_range(struct f2fs_sb_info *sbi, nid_t nid)
 {
-       BUG_ON((nid >= NM_I(sbi)->max_nid));
+       WARN_ON((nid >= NM_I(sbi)->max_nid));
+       if (nid >= NM_I(sbi)->max_nid)
+               return -EINVAL;
+       return 0;
 }
 
 #define F2FS_DEFAULT_ALLOCATED_BLOCKS  1
@@ -819,7 +843,6 @@ static inline int f2fs_clear_bit(unsigned int nr, char *addr)
 /* used for f2fs_inode_info->flags */
 enum {
        FI_NEW_INODE,           /* indicate newly allocated inode */
-       FI_NEED_CP,             /* need to do checkpoint during fsync */
        FI_INC_LINK,            /* need to increment i_nlink */
        FI_ACL_MODE,            /* indicate acl mode */
        FI_NO_ALLOC,            /* should not allocate any blocks */
@@ -872,6 +895,7 @@ long f2fs_compat_ioctl(struct file *, unsigned int, unsigned long);
 void f2fs_set_inode_flags(struct inode *);
 struct inode *f2fs_iget(struct super_block *, unsigned long);
 void update_inode(struct inode *, struct page *);
+int update_inode_page(struct inode *);
 int f2fs_write_inode(struct inode *, struct writeback_control *);
 void f2fs_evict_inode(struct inode *);
 
@@ -973,7 +997,6 @@ int lookup_journal_in_cursum(struct f2fs_summary_block *,
                                        int, unsigned int, int);
 void flush_sit_entries(struct f2fs_sb_info *);
 int build_segment_manager(struct f2fs_sb_info *);
-void reset_victim_segmap(struct f2fs_sb_info *);
 void destroy_segment_manager(struct f2fs_sb_info *);
 
 /*
@@ -1000,7 +1023,7 @@ void destroy_checkpoint_caches(void);
  */
 int reserve_new_block(struct dnode_of_data *);
 void update_extent_cache(block_t, struct dnode_of_data *);
-struct page *find_data_page(struct inode *, pgoff_t);
+struct page *find_data_page(struct inode *, pgoff_t, bool);
 struct page *get_lock_data_page(struct inode *, pgoff_t);
 struct page *get_new_data_page(struct inode *, pgoff_t, bool);
 int f2fs_readpage(struct f2fs_sb_info *, struct page *, block_t, int);
@@ -1020,7 +1043,7 @@ void destroy_gc_caches(void);
 /*
  * recovery.c
  */
-void recover_fsync_data(struct f2fs_sb_info *);
+int recover_fsync_data(struct f2fs_sb_info *);
 bool space_for_roll_forward(struct f2fs_sb_info *);
 
 /*
index db62628..1cae864 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/stat.h>
 #include <linux/buffer_head.h>
 #include <linux/writeback.h>
+#include <linux/blkdev.h>
 #include <linux/falloc.h>
 #include <linux/types.h>
 #include <linux/compat.h>
@@ -24,6 +25,7 @@
 #include "segment.h"
 #include "xattr.h"
 #include "acl.h"
+#include <trace/events/f2fs.h>
 
 static int f2fs_vm_page_mkwrite(struct vm_area_struct *vma,
                                                struct vm_fault *vmf)
@@ -33,19 +35,18 @@ static int f2fs_vm_page_mkwrite(struct vm_area_struct *vma,
        struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
        block_t old_blk_addr;
        struct dnode_of_data dn;
-       int err;
+       int err, ilock;
 
        f2fs_balance_fs(sbi);
 
        sb_start_pagefault(inode->i_sb);
 
-       mutex_lock_op(sbi, DATA_NEW);
-
        /* block allocation */
+       ilock = mutex_lock_op(sbi);
        set_new_dnode(&dn, inode, NULL, NULL, 0);
-       err = get_dnode_of_data(&dn, page->index, 0);
+       err = get_dnode_of_data(&dn, page->index, ALLOC_NODE);
        if (err) {
-               mutex_unlock_op(sbi, DATA_NEW);
+               mutex_unlock_op(sbi, ilock);
                goto out;
        }
 
@@ -55,13 +56,12 @@ static int f2fs_vm_page_mkwrite(struct vm_area_struct *vma,
                err = reserve_new_block(&dn);
                if (err) {
                        f2fs_put_dnode(&dn);
-                       mutex_unlock_op(sbi, DATA_NEW);
+                       mutex_unlock_op(sbi, ilock);
                        goto out;
                }
        }
        f2fs_put_dnode(&dn);
-
-       mutex_unlock_op(sbi, DATA_NEW);
+       mutex_unlock_op(sbi, ilock);
 
        lock_page(page);
        if (page->mapping != inode->i_mapping ||
@@ -102,28 +102,10 @@ static const struct vm_operations_struct f2fs_file_vm_ops = {
        .remap_pages    = generic_file_remap_pages,
 };
 
-static int need_to_sync_dir(struct f2fs_sb_info *sbi, struct inode *inode)
-{
-       struct dentry *dentry;
-       nid_t pino;
-
-       inode = igrab(inode);
-       dentry = d_find_any_alias(inode);
-       if (!dentry) {
-               iput(inode);
-               return 0;
-       }
-       pino = dentry->d_parent->d_inode->i_ino;
-       dput(dentry);
-       iput(inode);
-       return !is_checkpointed_node(sbi, pino);
-}
-
 int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
 {
        struct inode *inode = file->f_mapping->host;
        struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
-       unsigned long long cur_version;
        int ret = 0;
        bool need_cp = false;
        struct writeback_control wbc = {
@@ -135,9 +117,12 @@ int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
        if (inode->i_sb->s_flags & MS_RDONLY)
                return 0;
 
+       trace_f2fs_sync_file_enter(inode);
        ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
-       if (ret)
+       if (ret) {
+               trace_f2fs_sync_file_exit(inode, need_cp, datasync, ret);
                return ret;
+       }
 
        /* guarantee free sections for fsync */
        f2fs_balance_fs(sbi);
@@ -147,28 +132,18 @@ int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
        if (datasync && !(inode->i_state & I_DIRTY_DATASYNC))
                goto out;
 
-       mutex_lock(&sbi->cp_mutex);
-       cur_version = le64_to_cpu(F2FS_CKPT(sbi)->checkpoint_ver);
-       mutex_unlock(&sbi->cp_mutex);
-
-       if (F2FS_I(inode)->data_version != cur_version &&
-                                       !(inode->i_state & I_DIRTY))
-               goto out;
-       F2FS_I(inode)->data_version--;
-
        if (!S_ISREG(inode->i_mode) || inode->i_nlink != 1)
                need_cp = true;
-       else if (is_inode_flag_set(F2FS_I(inode), FI_NEED_CP))
+       else if (is_cp_file(inode))
                need_cp = true;
        else if (!space_for_roll_forward(sbi))
                need_cp = true;
-       else if (need_to_sync_dir(sbi, inode))
+       else if (!is_checkpointed_node(sbi, F2FS_I(inode)->i_pino))
                need_cp = true;
 
        if (need_cp) {
                /* all the dirty node pages should be flushed for POR */
                ret = f2fs_sync_fs(inode->i_sb, 1);
-               clear_inode_flag(F2FS_I(inode), FI_NEED_CP);
        } else {
                /* if there is no written node page, write its inode page */
                while (!sync_node_pages(sbi, inode->i_ino, &wbc)) {
@@ -178,9 +153,11 @@ int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
                }
                filemap_fdatawait_range(sbi->node_inode->i_mapping,
                                                        0, LONG_MAX);
+               ret = blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL);
        }
 out:
        mutex_unlock(&inode->i_mutex);
+       trace_f2fs_sync_file_exit(inode, need_cp, datasync, ret);
        return ret;
 }
 
@@ -216,6 +193,9 @@ static int truncate_data_blocks_range(struct dnode_of_data *dn, int count)
                sync_inode_page(dn);
        }
        dn->ofs_in_node = ofs;
+
+       trace_f2fs_truncate_data_blocks_range(dn->inode, dn->nid,
+                                        dn->ofs_in_node, nr_free);
        return nr_free;
 }
 
@@ -232,11 +212,15 @@ static void truncate_partial_data_page(struct inode *inode, u64 from)
        if (!offset)
                return;
 
-       page = find_data_page(inode, from >> PAGE_CACHE_SHIFT);
+       page = find_data_page(inode, from >> PAGE_CACHE_SHIFT, false);
        if (IS_ERR(page))
                return;
 
        lock_page(page);
+       if (page->mapping != inode->i_mapping) {
+               f2fs_put_page(page, 1);
+               return;
+       }
        wait_on_page_writeback(page);
        zero_user(page, offset, PAGE_CACHE_SIZE - offset);
        set_page_dirty(page);
@@ -249,20 +233,22 @@ static int truncate_blocks(struct inode *inode, u64 from)
        unsigned int blocksize = inode->i_sb->s_blocksize;
        struct dnode_of_data dn;
        pgoff_t free_from;
-       int count = 0;
+       int count = 0, ilock = -1;
        int err;
 
+       trace_f2fs_truncate_blocks_enter(inode, from);
+
        free_from = (pgoff_t)
                        ((from + blocksize - 1) >> (sbi->log_blocksize));
 
-       mutex_lock_op(sbi, DATA_TRUNC);
-
+       ilock = mutex_lock_op(sbi);
        set_new_dnode(&dn, inode, NULL, NULL, 0);
-       err = get_dnode_of_data(&dn, free_from, RDONLY_NODE);
+       err = get_dnode_of_data(&dn, free_from, LOOKUP_NODE);
        if (err) {
                if (err == -ENOENT)
                        goto free_next;
-               mutex_unlock_op(sbi, DATA_TRUNC);
+               mutex_unlock_op(sbi, ilock);
+               trace_f2fs_truncate_blocks_exit(inode, err);
                return err;
        }
 
@@ -273,6 +259,7 @@ static int truncate_blocks(struct inode *inode, u64 from)
 
        count -= dn.ofs_in_node;
        BUG_ON(count < 0);
+
        if (dn.ofs_in_node || IS_INODE(dn.node_page)) {
                truncate_data_blocks_range(&dn, count);
                free_from += count;
@@ -281,11 +268,12 @@ static int truncate_blocks(struct inode *inode, u64 from)
        f2fs_put_dnode(&dn);
 free_next:
        err = truncate_inode_blocks(inode, free_from);
-       mutex_unlock_op(sbi, DATA_TRUNC);
+       mutex_unlock_op(sbi, ilock);
 
        /* lastly zero out the first data page */
        truncate_partial_data_page(inode, from);
 
+       trace_f2fs_truncate_blocks_exit(inode, err);
        return err;
 }
 
@@ -295,6 +283,8 @@ void f2fs_truncate(struct inode *inode)
                                S_ISLNK(inode->i_mode)))
                return;
 
+       trace_f2fs_truncate(inode);
+
        if (!truncate_blocks(inode, i_size_read(inode))) {
                inode->i_mtime = inode->i_ctime = CURRENT_TIME;
                mark_inode_dirty(inode);
@@ -389,15 +379,16 @@ static void fill_zero(struct inode *inode, pgoff_t index,
 {
        struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
        struct page *page;
+       int ilock;
 
        if (!len)
                return;
 
        f2fs_balance_fs(sbi);
 
-       mutex_lock_op(sbi, DATA_NEW);
+       ilock = mutex_lock_op(sbi);
        page = get_new_data_page(inode, index, false);
-       mutex_unlock_op(sbi, DATA_NEW);
+       mutex_unlock_op(sbi, ilock);
 
        if (!IS_ERR(page)) {
                wait_on_page_writeback(page);
@@ -414,15 +405,10 @@ int truncate_hole(struct inode *inode, pgoff_t pg_start, pgoff_t pg_end)
 
        for (index = pg_start; index < pg_end; index++) {
                struct dnode_of_data dn;
-               struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
-
-               f2fs_balance_fs(sbi);
 
-               mutex_lock_op(sbi, DATA_TRUNC);
                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) {
-                       mutex_unlock_op(sbi, DATA_TRUNC);
                        if (err == -ENOENT)
                                continue;
                        return err;
@@ -431,7 +417,6 @@ int truncate_hole(struct inode *inode, pgoff_t pg_start, pgoff_t pg_end)
                if (dn.data_blkaddr != NULL_ADDR)
                        truncate_data_blocks_range(&dn, 1);
                f2fs_put_dnode(&dn);
-               mutex_unlock_op(sbi, DATA_TRUNC);
        }
        return 0;
 }
@@ -461,12 +446,19 @@ static int punch_hole(struct inode *inode, loff_t offset, loff_t len, int mode)
                if (pg_start < pg_end) {
                        struct address_space *mapping = inode->i_mapping;
                        loff_t blk_start, blk_end;
+                       struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
+                       int ilock;
+
+                       f2fs_balance_fs(sbi);
 
                        blk_start = pg_start << PAGE_CACHE_SHIFT;
                        blk_end = pg_end << PAGE_CACHE_SHIFT;
                        truncate_inode_pages_range(mapping, blk_start,
                                        blk_end - 1);
+
+                       ilock = mutex_lock_op(sbi);
                        ret = truncate_hole(inode, pg_start, pg_end);
+                       mutex_unlock_op(sbi, ilock);
                }
        }
 
@@ -500,13 +492,13 @@ static int expand_inode_data(struct inode *inode, loff_t offset,
 
        for (index = pg_start; index <= pg_end; index++) {
                struct dnode_of_data dn;
+               int ilock;
 
-               mutex_lock_op(sbi, DATA_NEW);
-
+               ilock = mutex_lock_op(sbi);
                set_new_dnode(&dn, inode, NULL, NULL, 0);
-               ret = get_dnode_of_data(&dn, index, 0);
+               ret = get_dnode_of_data(&dn, index, ALLOC_NODE);
                if (ret) {
-                       mutex_unlock_op(sbi, DATA_NEW);
+                       mutex_unlock_op(sbi, ilock);
                        break;
                }
 
@@ -514,13 +506,12 @@ static int expand_inode_data(struct inode *inode, loff_t offset,
                        ret = reserve_new_block(&dn);
                        if (ret) {
                                f2fs_put_dnode(&dn);
-                               mutex_unlock_op(sbi, DATA_NEW);
+                               mutex_unlock_op(sbi, ilock);
                                break;
                        }
                }
                f2fs_put_dnode(&dn);
-
-               mutex_unlock_op(sbi, DATA_NEW);
+               mutex_unlock_op(sbi, ilock);
 
                if (pg_start == pg_end)
                        new_size = offset + len;
@@ -559,6 +550,7 @@ static long f2fs_fallocate(struct file *file, int mode,
                inode->i_mtime = inode->i_ctime = CURRENT_TIME;
                mark_inode_dirty(inode);
        }
+       trace_f2fs_fallocate(inode, mode, offset, len, ret);
        return ret;
 }
 
index 2e3eb2d..1496159 100644 (file)
@@ -11,7 +11,6 @@
 #include <linux/fs.h>
 #include <linux/module.h>
 #include <linux/backing-dev.h>
-#include <linux/proc_fs.h>
 #include <linux/init.h>
 #include <linux/f2fs_fs.h>
 #include <linux/kthread.h>
@@ -23,6 +22,7 @@
 #include "node.h"
 #include "segment.h"
 #include "gc.h"
+#include <trace/events/f2fs.h>
 
 static struct kmem_cache *winode_slab;
 
@@ -81,9 +81,6 @@ static int gc_thread_func(void *data)
                /* if return value is not zero, no victim was selected */
                if (f2fs_gc(sbi))
                        wait_ms = GC_THREAD_NOGC_SLEEP_TIME;
-               else if (wait_ms == GC_THREAD_NOGC_SLEEP_TIME)
-                       wait_ms = GC_THREAD_MAX_SLEEP_TIME;
-
        } while (!kthread_should_stop());
        return 0;
 }
@@ -131,7 +128,7 @@ static void select_policy(struct f2fs_sb_info *sbi, int gc_type,
 {
        struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
 
-       if (p->alloc_mode) {
+       if (p->alloc_mode == SSR) {
                p->gc_mode = GC_GREEDY;
                p->dirty_segmap = dirty_i->dirty_segmap[type];
                p->ofs_unit = 1;
@@ -160,18 +157,21 @@ static unsigned int get_max_cost(struct f2fs_sb_info *sbi,
 static unsigned int check_bg_victims(struct f2fs_sb_info *sbi)
 {
        struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
-       unsigned int segno;
+       unsigned int hint = 0;
+       unsigned int secno;
 
        /*
         * If the gc_type is FG_GC, we can select victim segments
         * selected by background GC before.
         * Those segments guarantee they have small valid blocks.
         */
-       segno = find_next_bit(dirty_i->victim_segmap[BG_GC],
-                                               TOTAL_SEGS(sbi), 0);
-       if (segno < TOTAL_SEGS(sbi)) {
-               clear_bit(segno, dirty_i->victim_segmap[BG_GC]);
-               return segno;
+next:
+       secno = find_next_bit(dirty_i->victim_secmap, TOTAL_SECS(sbi), hint++);
+       if (secno < TOTAL_SECS(sbi)) {
+               if (sec_usage_check(sbi, secno))
+                       goto next;
+               clear_bit(secno, dirty_i->victim_secmap);
+               return secno * sbi->segs_per_sec;
        }
        return NULL_SEGNO;
 }
@@ -234,7 +234,7 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi,
 {
        struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
        struct victim_sel_policy p;
-       unsigned int segno;
+       unsigned int secno;
        int nsearched = 0;
 
        p.alloc_mode = alloc_mode;
@@ -253,6 +253,7 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi,
 
        while (1) {
                unsigned long cost;
+               unsigned int segno;
 
                segno = find_next_bit(p.dirty_segmap,
                                                TOTAL_SEGS(sbi), p.offset);
@@ -265,13 +266,11 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi,
                        break;
                }
                p.offset = ((segno / p.ofs_unit) * p.ofs_unit) + p.ofs_unit;
+               secno = GET_SECNO(sbi, segno);
 
-               if (test_bit(segno, dirty_i->victim_segmap[FG_GC]))
-                       continue;
-               if (gc_type == BG_GC &&
-                               test_bit(segno, dirty_i->victim_segmap[BG_GC]))
+               if (sec_usage_check(sbi, secno))
                        continue;
-               if (IS_CURSEC(sbi, GET_SECNO(sbi, segno)))
+               if (gc_type == BG_GC && test_bit(secno, dirty_i->victim_secmap))
                        continue;
 
                cost = get_gc_cost(sbi, segno, &p);
@@ -291,13 +290,18 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi,
        }
 got_it:
        if (p.min_segno != NULL_SEGNO) {
-               *result = (p.min_segno / p.ofs_unit) * p.ofs_unit;
                if (p.alloc_mode == LFS) {
-                       int i;
-                       for (i = 0; i < p.ofs_unit; i++)
-                               set_bit(*result + i,
-                                       dirty_i->victim_segmap[gc_type]);
+                       secno = GET_SECNO(sbi, p.min_segno);
+                       if (gc_type == FG_GC)
+                               sbi->cur_victim_sec = secno;
+                       else
+                               set_bit(secno, dirty_i->victim_secmap);
                }
+               *result = (p.min_segno / p.ofs_unit) * p.ofs_unit;
+
+               trace_f2fs_get_victim(sbi->sb, type, gc_type, &p,
+                               sbi->cur_victim_sec,
+                               prefree_segments(sbi), free_segments(sbi));
        }
        mutex_unlock(&dirty_i->seglist_lock);
 
@@ -381,6 +385,7 @@ static void gc_node_segment(struct f2fs_sb_info *sbi,
 
 next_step:
        entry = sum;
+
        for (off = 0; off < sbi->blocks_per_seg; off++, entry++) {
                nid_t nid = le32_to_cpu(entry->nid);
                struct page *node_page;
@@ -401,11 +406,18 @@ next_step:
                        continue;
 
                /* set page dirty and write it */
-               if (!PageWriteback(node_page))
+               if (gc_type == FG_GC) {
+                       f2fs_submit_bio(sbi, NODE, true);
+                       wait_on_page_writeback(node_page);
                        set_page_dirty(node_page);
+               } else {
+                       if (!PageWriteback(node_page))
+                               set_page_dirty(node_page);
+               }
                f2fs_put_page(node_page, 1);
                stat_inc_node_blk_count(sbi, 1);
        }
+
        if (initial) {
                initial = false;
                goto next_step;
@@ -418,6 +430,13 @@ next_step:
                        .for_reclaim = 0,
                };
                sync_node_pages(sbi, 0, &wbc);
+
+               /*
+                * In the case of FG_GC, it'd be better to reclaim this victim
+                * completely.
+                */
+               if (get_valid_blocks(sbi, segno, 1) != 0)
+                       goto next_step;
        }
 }
 
@@ -481,21 +500,19 @@ static int check_dnode(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
 
 static void move_data_page(struct inode *inode, struct page *page, int gc_type)
 {
-       if (page->mapping != inode->i_mapping)
-               goto out;
-
-       if (inode != page->mapping->host)
-               goto out;
-
-       if (PageWriteback(page))
-               goto out;
-
        if (gc_type == BG_GC) {
+               if (PageWriteback(page))
+                       goto out;
                set_page_dirty(page);
                set_cold_data(page);
        } else {
                struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
-               mutex_lock_op(sbi, DATA_WRITE);
+
+               if (PageWriteback(page)) {
+                       f2fs_submit_bio(sbi, DATA, true);
+                       wait_on_page_writeback(page);
+               }
+
                if (clear_page_dirty_for_io(page) &&
                        S_ISDIR(inode->i_mode)) {
                        dec_page_count(sbi, F2FS_DIRTY_DENTS);
@@ -503,7 +520,6 @@ static void move_data_page(struct inode *inode, struct page *page, int gc_type)
                }
                set_cold_data(page);
                do_write_data_page(page);
-               mutex_unlock_op(sbi, DATA_WRITE);
                clear_cold_data(page);
        }
 out:
@@ -530,6 +546,7 @@ static void gc_data_segment(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
 
 next_step:
        entry = sum;
+
        for (off = 0; off < sbi->blocks_per_seg; off++, entry++) {
                struct page *data_page;
                struct inode *inode;
@@ -567,7 +584,7 @@ next_step:
                                continue;
 
                        data_page = find_data_page(inode,
-                                       start_bidx + ofs_in_node);
+                                       start_bidx + ofs_in_node, false);
                        if (IS_ERR(data_page))
                                goto next_iput;
 
@@ -588,11 +605,22 @@ next_step:
 next_iput:
                iput(inode);
        }
+
        if (++phase < 4)
                goto next_step;
 
-       if (gc_type == FG_GC)
+       if (gc_type == FG_GC) {
                f2fs_submit_bio(sbi, DATA, true);
+
+               /*
+                * In the case of FG_GC, it'd be better to reclaim this victim
+                * completely.
+                */
+               if (get_valid_blocks(sbi, segno, 1) != 0) {
+                       phase = 2;
+                       goto next_step;
+               }
+       }
 }
 
 static int __get_victim(struct f2fs_sb_info *sbi, unsigned int *victim,
@@ -611,18 +639,15 @@ static void do_garbage_collect(struct f2fs_sb_info *sbi, unsigned int segno,
 {
        struct page *sum_page;
        struct f2fs_summary_block *sum;
+       struct blk_plug plug;
 
        /* read segment summary of victim */
        sum_page = get_sum_page(sbi, segno);
        if (IS_ERR(sum_page))
                return;
 
-       /*
-        * CP needs to lock sum_page. In this time, we don't need
-        * to lock this page, because this summary page is not gone anywhere.
-        * Also, this page is not gonna be updated before GC is done.
-        */
-       unlock_page(sum_page);
+       blk_start_plug(&plug);
+
        sum = page_address(sum_page);
 
        switch (GET_SUM_TYPE((&sum->footer))) {
@@ -633,10 +658,12 @@ static void do_garbage_collect(struct f2fs_sb_info *sbi, unsigned int segno,
                gc_data_segment(sbi, sum->entries, ilist, segno, gc_type);
                break;
        }
+       blk_finish_plug(&plug);
+
        stat_inc_seg_count(sbi, GET_SUM_TYPE((&sum->footer)));
        stat_inc_call_count(sbi->stat_info);
 
-       f2fs_put_page(sum_page, 0);
+       f2fs_put_page(sum_page, 1);
 }
 
 int f2fs_gc(struct f2fs_sb_info *sbi)
@@ -652,8 +679,10 @@ gc_more:
        if (!(sbi->sb->s_flags & MS_ACTIVE))
                goto stop;
 
-       if (gc_type == BG_GC && has_not_enough_free_secs(sbi, nfree))
+       if (gc_type == BG_GC && has_not_enough_free_secs(sbi, nfree)) {
                gc_type = FG_GC;
+               write_checkpoint(sbi, false);
+       }
 
        if (!__get_victim(sbi, &segno, gc_type, NO_CHECK_TYPE))
                goto stop;
@@ -662,9 +691,11 @@ gc_more:
        for (i = 0; i < sbi->segs_per_sec; i++)
                do_garbage_collect(sbi, segno + i, &ilist, gc_type);
 
-       if (gc_type == FG_GC &&
-                       get_valid_blocks(sbi, segno, sbi->segs_per_sec) == 0)
+       if (gc_type == FG_GC) {
+               sbi->cur_victim_sec = NULL_SEGNO;
                nfree++;
+               WARN_ON(get_valid_blocks(sbi, segno, sbi->segs_per_sec));
+       }
 
        if (has_not_enough_free_secs(sbi, nfree))
                goto gc_more;
index 30b2db0..2c6a6bd 100644 (file)
@@ -13,9 +13,9 @@
                                                 * whether IO subsystem is idle
                                                 * or not
                                                 */
-#define GC_THREAD_MIN_SLEEP_TIME       10000 /* milliseconds */
-#define GC_THREAD_MAX_SLEEP_TIME       30000
-#define GC_THREAD_NOGC_SLEEP_TIME      10000
+#define GC_THREAD_MIN_SLEEP_TIME       30000   /* milliseconds */
+#define GC_THREAD_MAX_SLEEP_TIME       60000
+#define GC_THREAD_NOGC_SLEEP_TIME      300000  /* wait 5 min */
 #define LIMIT_INVALID_BLOCK    40 /* percentage over total user space */
 #define LIMIT_FREE_BLOCK       40 /* percentage over invalid + free space */
 
@@ -58,6 +58,9 @@ static inline block_t limit_free_user_blocks(struct f2fs_sb_info *sbi)
 
 static inline long increase_sleep_time(long wait)
 {
+       if (wait == GC_THREAD_NOGC_SLEEP_TIME)
+               return wait;
+
        wait += GC_THREAD_MIN_SLEEP_TIME;
        if (wait > GC_THREAD_MAX_SLEEP_TIME)
                wait = GC_THREAD_MAX_SLEEP_TIME;
@@ -66,6 +69,9 @@ static inline long increase_sleep_time(long wait)
 
 static inline long decrease_sleep_time(long wait)
 {
+       if (wait == GC_THREAD_NOGC_SLEEP_TIME)
+               wait = GC_THREAD_MAX_SLEEP_TIME;
+
        wait -= GC_THREAD_MIN_SLEEP_TIME;
        if (wait <= GC_THREAD_MIN_SLEEP_TIME)
                wait = GC_THREAD_MIN_SLEEP_TIME;
index ddae412..91ac7f9 100644 (file)
@@ -16,6 +16,8 @@
 #include "f2fs.h"
 #include "node.h"
 
+#include <trace/events/f2fs.h>
+
 void f2fs_set_inode_flags(struct inode *inode)
 {
        unsigned int flags = F2FS_I(inode)->i_flags;
@@ -44,7 +46,11 @@ static int do_read_inode(struct inode *inode)
        struct f2fs_inode *ri;
 
        /* Check if ino is within scope */
-       check_nid_range(sbi, inode->i_ino);
+       if (check_nid_range(sbi, inode->i_ino)) {
+               f2fs_msg(inode->i_sb, KERN_ERR, "bad inode number: %lu",
+                        (unsigned long) inode->i_ino);
+               return -EINVAL;
+       }
 
        node_page = get_node_page(sbi, inode->i_ino);
        if (IS_ERR(node_page))
@@ -76,7 +82,6 @@ static int do_read_inode(struct inode *inode)
        fi->i_xattr_nid = le32_to_cpu(ri->i_xattr_nid);
        fi->i_flags = le32_to_cpu(ri->i_flags);
        fi->flags = 0;
-       fi->data_version = le64_to_cpu(F2FS_CKPT(sbi)->checkpoint_ver) - 1;
        fi->i_advise = ri->i_advise;
        fi->i_pino = le32_to_cpu(ri->i_pino);
        get_extent_info(&fi->ext, ri->i_ext);
@@ -88,13 +93,16 @@ struct inode *f2fs_iget(struct super_block *sb, unsigned long ino)
 {
        struct f2fs_sb_info *sbi = F2FS_SB(sb);
        struct inode *inode;
-       int ret;
+       int ret = 0;
 
        inode = iget_locked(sb, ino);
        if (!inode)
                return ERR_PTR(-ENOMEM);
-       if (!(inode->i_state & I_NEW))
+
+       if (!(inode->i_state & I_NEW)) {
+               trace_f2fs_iget(inode);
                return inode;
+       }
        if (ino == F2FS_NODE_INO(sbi) || ino == F2FS_META_INO(sbi))
                goto make_now;
 
@@ -136,11 +144,12 @@ make_now:
                goto bad_inode;
        }
        unlock_new_inode(inode);
-
+       trace_f2fs_iget(inode);
        return inode;
 
 bad_inode:
        iget_failed(inode);
+       trace_f2fs_iget_exit(inode, ret);
        return ERR_PTR(ret);
 }
 
@@ -192,47 +201,51 @@ void update_inode(struct inode *inode, struct page *node_page)
        set_page_dirty(node_page);
 }
 
-int f2fs_write_inode(struct inode *inode, struct writeback_control *wbc)
+int update_inode_page(struct inode *inode)
 {
        struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
        struct page *node_page;
-       bool need_lock = false;
-
-       if (inode->i_ino == F2FS_NODE_INO(sbi) ||
-                       inode->i_ino == F2FS_META_INO(sbi))
-               return 0;
-
-       if (wbc)
-               f2fs_balance_fs(sbi);
 
        node_page = get_node_page(sbi, inode->i_ino);
        if (IS_ERR(node_page))
                return PTR_ERR(node_page);
 
-       if (!PageDirty(node_page)) {
-               need_lock = true;
-               f2fs_put_page(node_page, 1);
-               mutex_lock(&sbi->write_inode);
-               node_page = get_node_page(sbi, inode->i_ino);
-               if (IS_ERR(node_page)) {
-                       mutex_unlock(&sbi->write_inode);
-                       return PTR_ERR(node_page);
-               }
-       }
        update_inode(inode, node_page);
        f2fs_put_page(node_page, 1);
-       if (need_lock)
-               mutex_unlock(&sbi->write_inode);
        return 0;
 }
 
+int f2fs_write_inode(struct inode *inode, struct writeback_control *wbc)
+{
+       struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
+       int ret, ilock;
+
+       if (inode->i_ino == F2FS_NODE_INO(sbi) ||
+                       inode->i_ino == F2FS_META_INO(sbi))
+               return 0;
+
+       if (wbc)
+               f2fs_balance_fs(sbi);
+
+       /*
+        * We need to lock here to prevent from producing dirty node pages
+        * during the urgent cleaning time when runing out of free sections.
+        */
+       ilock = mutex_lock_op(sbi);
+       ret = update_inode_page(inode);
+       mutex_unlock_op(sbi, ilock);
+       return ret;
+}
+
 /*
  * Called at the last iput() if i_nlink is zero
  */
 void f2fs_evict_inode(struct inode *inode)
 {
        struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
+       int ilock;
 
+       trace_f2fs_evict_inode(inode);
        truncate_inode_pages(&inode->i_data, 0);
 
        if (inode->i_ino == F2FS_NODE_INO(sbi) ||
@@ -252,7 +265,10 @@ void f2fs_evict_inode(struct inode *inode)
        if (F2FS_HAS_BLOCKS(inode))
                f2fs_truncate(inode);
 
+       ilock = mutex_lock_op(sbi);
        remove_inode_page(inode);
+       mutex_unlock_op(sbi, ilock);
+
        sb_end_intwrite(inode->i_sb);
 no_delete:
        clear_inode(inode);
index 1a49b88..47abc97 100644 (file)
 #include <linux/ctype.h>
 
 #include "f2fs.h"
+#include "node.h"
 #include "xattr.h"
 #include "acl.h"
+#include <trace/events/f2fs.h>
 
 static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode)
 {
@@ -25,19 +27,19 @@ static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode)
        nid_t ino;
        struct inode *inode;
        bool nid_free = false;
-       int err;
+       int err, ilock;
 
        inode = new_inode(sb);
        if (!inode)
                return ERR_PTR(-ENOMEM);
 
-       mutex_lock_op(sbi, NODE_NEW);
+       ilock = mutex_lock_op(sbi);
        if (!alloc_nid(sbi, &ino)) {
-               mutex_unlock_op(sbi, NODE_NEW);
+               mutex_unlock_op(sbi, ilock);
                err = -ENOSPC;
                goto fail;
        }
-       mutex_unlock_op(sbi, NODE_NEW);
+       mutex_unlock_op(sbi, ilock);
 
        inode->i_uid = current_fsuid();
 
@@ -61,7 +63,7 @@ static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode)
                nid_free = true;
                goto out;
        }
-
+       trace_f2fs_new_inode(inode, 0);
        mark_inode_dirty(inode);
        return inode;
 
@@ -69,6 +71,8 @@ out:
        clear_nlink(inode);
        unlock_new_inode(inode);
 fail:
+       trace_f2fs_new_inode(inode, err);
+       make_bad_inode(inode);
        iput(inode);
        if (nid_free)
                alloc_nid_failed(sbi, ino);
@@ -82,7 +86,7 @@ static int is_multimedia_file(const unsigned char *s, const char *sub)
        int ret;
 
        if (sublen > slen)
-               return 1;
+               return 0;
 
        ret = memcmp(s + slen - sublen, sub, sublen);
        if (ret) {      /* compare upper case */
@@ -90,16 +94,16 @@ static int is_multimedia_file(const unsigned char *s, const char *sub)
                char upper_sub[8];
                for (i = 0; i < sublen && i < sizeof(upper_sub); i++)
                        upper_sub[i] = toupper(sub[i]);
-               return memcmp(s + slen - sublen, upper_sub, sublen);
+               return !memcmp(s + slen - sublen, upper_sub, sublen);
        }
 
-       return ret;
+       return !ret;
 }
 
 /*
  * Set multimedia files as cold files for hot/cold data separation
  */
-static inline void set_cold_file(struct f2fs_sb_info *sbi, struct inode *inode,
+static inline void set_cold_files(struct f2fs_sb_info *sbi, struct inode *inode,
                const unsigned char *name)
 {
        int i;
@@ -107,8 +111,8 @@ static inline void set_cold_file(struct f2fs_sb_info *sbi, struct inode *inode,
 
        int count = le32_to_cpu(sbi->raw_super->extension_count);
        for (i = 0; i < count; i++) {
-               if (!is_multimedia_file(name, extlist[i])) {
-                       F2FS_I(inode)->i_advise |= FADVISE_COLD_BIT;
+               if (is_multimedia_file(name, extlist[i])) {
+                       set_cold_file(inode);
                        break;
                }
        }
@@ -121,7 +125,7 @@ static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
        struct f2fs_sb_info *sbi = F2FS_SB(sb);
        struct inode *inode;
        nid_t ino = 0;
-       int err;
+       int err, ilock;
 
        f2fs_balance_fs(sbi);
 
@@ -130,14 +134,16 @@ static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
                return PTR_ERR(inode);
 
        if (!test_opt(sbi, DISABLE_EXT_IDENTIFY))
-               set_cold_file(sbi, inode, dentry->d_name.name);
+               set_cold_files(sbi, inode, dentry->d_name.name);
 
        inode->i_op = &f2fs_file_inode_operations;
        inode->i_fop = &f2fs_file_operations;
        inode->i_mapping->a_ops = &f2fs_dblock_aops;
        ino = inode->i_ino;
 
+       ilock = mutex_lock_op(sbi);
        err = f2fs_add_link(dentry, inode);
+       mutex_unlock_op(sbi, ilock);
        if (err)
                goto out;
 
@@ -150,6 +156,7 @@ static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
 out:
        clear_nlink(inode);
        unlock_new_inode(inode);
+       make_bad_inode(inode);
        iput(inode);
        alloc_nid_failed(sbi, ino);
        return err;
@@ -161,7 +168,7 @@ static int f2fs_link(struct dentry *old_dentry, struct inode *dir,
        struct inode *inode = old_dentry->d_inode;
        struct super_block *sb = dir->i_sb;
        struct f2fs_sb_info *sbi = F2FS_SB(sb);
-       int err;
+       int err, ilock;
 
        f2fs_balance_fs(sbi);
 
@@ -169,14 +176,23 @@ static int f2fs_link(struct dentry *old_dentry, struct inode *dir,
        atomic_inc(&inode->i_count);
 
        set_inode_flag(F2FS_I(inode), FI_INC_LINK);
+       ilock = mutex_lock_op(sbi);
        err = f2fs_add_link(dentry, inode);
+       mutex_unlock_op(sbi, ilock);
        if (err)
                goto out;
 
+       /*
+        * This file should be checkpointed during fsync.
+        * We lost i_pino from now on.
+        */
+       set_cp_file(inode);
+
        d_instantiate(dentry, inode);
        return 0;
 out:
        clear_inode_flag(F2FS_I(inode), FI_INC_LINK);
+       make_bad_inode(inode);
        iput(inode);
        return err;
 }
@@ -197,7 +213,7 @@ static struct dentry *f2fs_lookup(struct inode *dir, struct dentry *dentry,
        struct f2fs_dir_entry *de;
        struct page *page;
 
-       if (dentry->d_name.len > F2FS_MAX_NAME_LEN)
+       if (dentry->d_name.len > F2FS_NAME_LEN)
                return ERR_PTR(-ENAMETOOLONG);
 
        de = f2fs_find_entry(dir, &dentry->d_name, &page);
@@ -222,7 +238,9 @@ static int f2fs_unlink(struct inode *dir, struct dentry *dentry)
        struct f2fs_dir_entry *de;
        struct page *page;
        int err = -ENOENT;
+       int ilock;
 
+       trace_f2fs_unlink_enter(dir, dentry);
        f2fs_balance_fs(sbi);
 
        de = f2fs_find_entry(dir, &dentry->d_name, &page);
@@ -236,11 +254,14 @@ static int f2fs_unlink(struct inode *dir, struct dentry *dentry)
                goto fail;
        }
 
+       ilock = mutex_lock_op(sbi);
        f2fs_delete_entry(de, page, inode);
+       mutex_unlock_op(sbi, ilock);
 
        /* In order to evict this inode,  we set it dirty */
        mark_inode_dirty(inode);
 fail:
+       trace_f2fs_unlink_exit(inode, err);
        return err;
 }
 
@@ -251,7 +272,7 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry,
        struct f2fs_sb_info *sbi = F2FS_SB(sb);
        struct inode *inode;
        size_t symlen = strlen(symname) + 1;
-       int err;
+       int err, ilock;
 
        f2fs_balance_fs(sbi);
 
@@ -262,7 +283,9 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry,
        inode->i_op = &f2fs_symlink_inode_operations;
        inode->i_mapping->a_ops = &f2fs_dblock_aops;
 
+       ilock = mutex_lock_op(sbi);
        err = f2fs_add_link(dentry, inode);
+       mutex_unlock_op(sbi, ilock);
        if (err)
                goto out;
 
@@ -275,6 +298,7 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry,
 out:
        clear_nlink(inode);
        unlock_new_inode(inode);
+       make_bad_inode(inode);
        iput(inode);
        alloc_nid_failed(sbi, inode->i_ino);
        return err;
@@ -284,7 +308,7 @@ static int f2fs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
 {
        struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb);
        struct inode *inode;
-       int err;
+       int err, ilock;
 
        f2fs_balance_fs(sbi);
 
@@ -298,7 +322,9 @@ static int f2fs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
        mapping_set_gfp_mask(inode->i_mapping, GFP_F2FS_ZERO);
 
        set_inode_flag(F2FS_I(inode), FI_INC_LINK);
+       ilock = mutex_lock_op(sbi);
        err = f2fs_add_link(dentry, inode);
+       mutex_unlock_op(sbi, ilock);
        if (err)
                goto out_fail;
 
@@ -313,6 +339,7 @@ out_fail:
        clear_inode_flag(F2FS_I(inode), FI_INC_LINK);
        clear_nlink(inode);
        unlock_new_inode(inode);
+       make_bad_inode(inode);
        iput(inode);
        alloc_nid_failed(sbi, inode->i_ino);
        return err;
@@ -333,6 +360,7 @@ static int f2fs_mknod(struct inode *dir, struct dentry *dentry,
        struct f2fs_sb_info *sbi = F2FS_SB(sb);
        struct inode *inode;
        int err = 0;
+       int ilock;
 
        if (!new_valid_dev(rdev))
                return -EINVAL;
@@ -346,7 +374,9 @@ static int f2fs_mknod(struct inode *dir, struct dentry *dentry,
        init_special_inode(inode, inode->i_mode, rdev);
        inode->i_op = &f2fs_special_inode_operations;
 
+       ilock = mutex_lock_op(sbi);
        err = f2fs_add_link(dentry, inode);
+       mutex_unlock_op(sbi, ilock);
        if (err)
                goto out;
 
@@ -357,6 +387,7 @@ static int f2fs_mknod(struct inode *dir, struct dentry *dentry,
 out:
        clear_nlink(inode);
        unlock_new_inode(inode);
+       make_bad_inode(inode);
        iput(inode);
        alloc_nid_failed(sbi, inode->i_ino);
        return err;
@@ -374,7 +405,7 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
        struct f2fs_dir_entry *old_dir_entry = NULL;
        struct f2fs_dir_entry *old_entry;
        struct f2fs_dir_entry *new_entry;
-       int err = -ENOENT;
+       int err = -ENOENT, ilock = -1;
 
        f2fs_balance_fs(sbi);
 
@@ -389,7 +420,7 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
                        goto out_old;
        }
 
-       mutex_lock_op(sbi, RENAME);
+       ilock = mutex_lock_op(sbi);
 
        if (new_inode) {
                struct page *new_page;
@@ -412,7 +443,7 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
                drop_nlink(new_inode);
                if (!new_inode->i_nlink)
                        add_orphan_inode(sbi, new_inode->i_ino);
-               f2fs_write_inode(new_inode, NULL);
+               update_inode_page(new_inode);
        } else {
                err = f2fs_add_link(new_dentry, old_inode);
                if (err)
@@ -420,12 +451,11 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
 
                if (old_dir_entry) {
                        inc_nlink(new_dir);
-                       f2fs_write_inode(new_dir, NULL);
+                       update_inode_page(new_dir);
                }
        }
 
        old_inode->i_ctime = CURRENT_TIME;
-       set_inode_flag(F2FS_I(old_inode), FI_NEED_CP);
        mark_inode_dirty(old_inode);
 
        f2fs_delete_entry(old_entry, old_page, NULL);
@@ -439,10 +469,10 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
                        f2fs_put_page(old_dir_page, 0);
                }
                drop_nlink(old_dir);
-               f2fs_write_inode(old_dir, NULL);
+               update_inode_page(old_dir);
        }
 
-       mutex_unlock_op(sbi, RENAME);
+       mutex_unlock_op(sbi, ilock);
        return 0;
 
 out_dir:
@@ -450,7 +480,7 @@ out_dir:
                kunmap(old_dir_page);
                f2fs_put_page(old_dir_page, 0);
        }
-       mutex_unlock_op(sbi, RENAME);
+       mutex_unlock_op(sbi, ilock);
 out_old:
        kunmap(old_page);
        f2fs_put_page(old_page, 0);
index e275218..3df43b4 100644 (file)
@@ -19,6 +19,7 @@
 #include "f2fs.h"
 #include "node.h"
 #include "segment.h"
+#include <trace/events/f2fs.h>
 
 static struct kmem_cache *nat_entry_slab;
 static struct kmem_cache *free_nid_slab;
@@ -88,10 +89,13 @@ static void ra_nat_pages(struct f2fs_sb_info *sbi, int nid)
 {
        struct address_space *mapping = sbi->meta_inode->i_mapping;
        struct f2fs_nm_info *nm_i = NM_I(sbi);
+       struct blk_plug plug;
        struct page *page;
        pgoff_t index;
        int i;
 
+       blk_start_plug(&plug);
+
        for (i = 0; i < FREE_NID_PAGES; i++, nid += NAT_ENTRY_PER_BLOCK) {
                if (nid >= nm_i->max_nid)
                        nid = 0;
@@ -100,12 +104,16 @@ static void ra_nat_pages(struct f2fs_sb_info *sbi, int nid)
                page = grab_cache_page(mapping, index);
                if (!page)
                        continue;
-               if (f2fs_readpage(sbi, page, index, READ)) {
+               if (PageUptodate(page)) {
                        f2fs_put_page(page, 1);
                        continue;
                }
+               if (f2fs_readpage(sbi, page, index, READ))
+                       continue;
+
                f2fs_put_page(page, 0);
        }
+       blk_finish_plug(&plug);
 }
 
 static struct nat_entry *__lookup_nat_cache(struct f2fs_nm_info *nm_i, nid_t n)
@@ -236,7 +244,7 @@ static int try_to_free_nats(struct f2fs_sb_info *sbi, int nr_shrink)
 {
        struct f2fs_nm_info *nm_i = NM_I(sbi);
 
-       if (nm_i->nat_cnt < 2 * NM_WOUT_THRESHOLD)
+       if (nm_i->nat_cnt <= NM_WOUT_THRESHOLD)
                return 0;
 
        write_lock(&nm_i->nat_tree_lock);
@@ -320,15 +328,14 @@ static int get_node_path(long block, int offset[4], unsigned int noffset[4])
        noffset[0] = 0;
 
        if (block < direct_index) {
-               offset[n++] = block;
-               level = 0;
+               offset[n] = block;
                goto got;
        }
        block -= direct_index;
        if (block < direct_blks) {
                offset[n++] = NODE_DIR1_BLOCK;
                noffset[n] = 1;
-               offset[n++] = block;
+               offset[n] = block;
                level = 1;
                goto got;
        }
@@ -336,7 +343,7 @@ static int get_node_path(long block, int offset[4], unsigned int noffset[4])
        if (block < direct_blks) {
                offset[n++] = NODE_DIR2_BLOCK;
                noffset[n] = 2;
-               offset[n++] = block;
+               offset[n] = block;
                level = 1;
                goto got;
        }
@@ -346,7 +353,7 @@ static int get_node_path(long block, int offset[4], unsigned int noffset[4])
                noffset[n] = 3;
                offset[n++] = block / direct_blks;
                noffset[n] = 4 + offset[n - 1];
-               offset[n++] = block % direct_blks;
+               offset[n] = block % direct_blks;
                level = 2;
                goto got;
        }
@@ -356,7 +363,7 @@ static int get_node_path(long block, int offset[4], unsigned int noffset[4])
                noffset[n] = 4 + dptrs_per_blk;
                offset[n++] = block / direct_blks;
                noffset[n] = 5 + dptrs_per_blk + offset[n - 1];
-               offset[n++] = block % direct_blks;
+               offset[n] = block % direct_blks;
                level = 2;
                goto got;
        }
@@ -371,7 +378,7 @@ static int get_node_path(long block, int offset[4], unsigned int noffset[4])
                noffset[n] = 7 + (dptrs_per_blk * 2) +
                              offset[n - 2] * (dptrs_per_blk + 1) +
                              offset[n - 1];
-               offset[n++] = block % direct_blks;
+               offset[n] = block % direct_blks;
                level = 3;
                goto got;
        } else {
@@ -383,8 +390,11 @@ got:
 
 /*
  * Caller should call f2fs_put_dnode(dn).
+ * Also, it should grab and release a mutex by calling mutex_lock_op() and
+ * mutex_unlock_op() only if ro is not set RDONLY_NODE.
+ * In the case of RDONLY_NODE, we don't need to care about mutex.
  */
-int get_dnode_of_data(struct dnode_of_data *dn, pgoff_t index, int ro)
+int get_dnode_of_data(struct dnode_of_data *dn, pgoff_t index, int mode)
 {
        struct f2fs_sb_info *sbi = F2FS_SB(dn->inode->i_sb);
        struct page *npage[4];
@@ -403,7 +413,8 @@ int get_dnode_of_data(struct dnode_of_data *dn, pgoff_t index, int ro)
                return PTR_ERR(npage[0]);
 
        parent = npage[0];
-       nids[1] = get_nid(parent, offset[0], true);
+       if (level != 0)
+               nids[1] = get_nid(parent, offset[0], true);
        dn->inode_page = npage[0];
        dn->inode_page_locked = true;
 
@@ -411,12 +422,9 @@ int get_dnode_of_data(struct dnode_of_data *dn, pgoff_t index, int ro)
        for (i = 1; i <= level; i++) {
                bool done = false;
 
-               if (!nids[i] && !ro) {
-                       mutex_lock_op(sbi, NODE_NEW);
-
+               if (!nids[i] && mode == ALLOC_NODE) {
                        /* alloc new node */
                        if (!alloc_nid(sbi, &(nids[i]))) {
-                               mutex_unlock_op(sbi, NODE_NEW);
                                err = -ENOSPC;
                                goto release_pages;
                        }
@@ -425,16 +433,14 @@ int get_dnode_of_data(struct dnode_of_data *dn, pgoff_t index, int ro)
                        npage[i] = new_node_page(dn, noffset[i]);
                        if (IS_ERR(npage[i])) {
                                alloc_nid_failed(sbi, nids[i]);
-                               mutex_unlock_op(sbi, NODE_NEW);
                                err = PTR_ERR(npage[i]);
                                goto release_pages;
                        }
 
                        set_nid(parent, offset[i - 1], nids[i], i == 1);
                        alloc_nid_done(sbi, nids[i]);
-                       mutex_unlock_op(sbi, NODE_NEW);
                        done = true;
-               } else if (ro && i == level && level > 1) {
+               } else if (mode == LOOKUP_NODE_RA && i == level && level > 1) {
                        npage[i] = get_node_page_ra(parent, offset[i - 1]);
                        if (IS_ERR(npage[i])) {
                                err = PTR_ERR(npage[i]);
@@ -507,6 +513,7 @@ invalidate:
 
        f2fs_put_page(dn->node_page, 1);
        dn->node_page = NULL;
+       trace_f2fs_truncate_node(dn->inode, dn->nid, ni.blk_addr);
 }
 
 static int truncate_dnode(struct dnode_of_data *dn)
@@ -547,9 +554,13 @@ static int truncate_nodes(struct dnode_of_data *dn, unsigned int nofs,
        if (dn->nid == 0)
                return NIDS_PER_BLOCK + 1;
 
+       trace_f2fs_truncate_nodes_enter(dn->inode, dn->nid, dn->data_blkaddr);
+
        page = get_node_page(sbi, dn->nid);
-       if (IS_ERR(page))
+       if (IS_ERR(page)) {
+               trace_f2fs_truncate_nodes_exit(dn->inode, PTR_ERR(page));
                return PTR_ERR(page);
+       }
 
        rn = (struct f2fs_node *)page_address(page);
        if (depth < 3) {
@@ -591,10 +602,12 @@ static int truncate_nodes(struct dnode_of_data *dn, unsigned int nofs,
        } else {
                f2fs_put_page(page, 1);
        }
+       trace_f2fs_truncate_nodes_exit(dn->inode, freed);
        return freed;
 
 out_err:
        f2fs_put_page(page, 1);
+       trace_f2fs_truncate_nodes_exit(dn->inode, ret);
        return ret;
 }
 
@@ -649,6 +662,9 @@ static int truncate_partial_nodes(struct dnode_of_data *dn,
 fail:
        for (i = depth - 3; i >= 0; i--)
                f2fs_put_page(pages[i], 1);
+
+       trace_f2fs_truncate_partial_nodes(dn->inode, nid, depth, err);
+
        return err;
 }
 
@@ -658,6 +674,7 @@ fail:
 int truncate_inode_blocks(struct inode *inode, pgoff_t from)
 {
        struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
+       struct address_space *node_mapping = sbi->node_inode->i_mapping;
        int err = 0, cont = 1;
        int level, offset[4], noffset[4];
        unsigned int nofs = 0;
@@ -665,11 +682,15 @@ int truncate_inode_blocks(struct inode *inode, pgoff_t from)
        struct dnode_of_data dn;
        struct page *page;
 
-       level = get_node_path(from, offset, noffset);
+       trace_f2fs_truncate_inode_blocks_enter(inode, from);
 
+       level = get_node_path(from, offset, noffset);
+restart:
        page = get_node_page(sbi, inode->i_ino);
-       if (IS_ERR(page))
+       if (IS_ERR(page)) {
+               trace_f2fs_truncate_inode_blocks_exit(inode, PTR_ERR(page));
                return PTR_ERR(page);
+       }
 
        set_new_dnode(&dn, inode, page, NULL, 0);
        unlock_page(page);
@@ -728,6 +749,10 @@ skip_partial:
                if (offset[1] == 0 &&
                                rn->i.i_nid[offset[0] - NODE_DIR1_BLOCK]) {
                        lock_page(page);
+                       if (page->mapping != node_mapping) {
+                               f2fs_put_page(page, 1);
+                               goto restart;
+                       }
                        wait_on_page_writeback(page);
                        rn->i.i_nid[offset[0] - NODE_DIR1_BLOCK] = 0;
                        set_page_dirty(page);
@@ -739,9 +764,14 @@ skip_partial:
        }
 fail:
        f2fs_put_page(page, 0);
+       trace_f2fs_truncate_inode_blocks_exit(inode, err);
        return err > 0 ? 0 : err;
 }
 
+/*
+ * Caller should grab and release a mutex by calling mutex_lock_op() and
+ * mutex_unlock_op().
+ */
 int remove_inode_page(struct inode *inode)
 {
        struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
@@ -749,21 +779,16 @@ int remove_inode_page(struct inode *inode)
        nid_t ino = inode->i_ino;
        struct dnode_of_data dn;
 
-       mutex_lock_op(sbi, NODE_TRUNC);
        page = get_node_page(sbi, ino);
-       if (IS_ERR(page)) {
-               mutex_unlock_op(sbi, NODE_TRUNC);
+       if (IS_ERR(page))
                return PTR_ERR(page);
-       }
 
        if (F2FS_I(inode)->i_xattr_nid) {
                nid_t nid = F2FS_I(inode)->i_xattr_nid;
                struct page *npage = get_node_page(sbi, nid);
 
-               if (IS_ERR(npage)) {
-                       mutex_unlock_op(sbi, NODE_TRUNC);
+               if (IS_ERR(npage))
                        return PTR_ERR(npage);
-               }
 
                F2FS_I(inode)->i_xattr_nid = 0;
                set_new_dnode(&dn, inode, page, npage, nid);
@@ -775,23 +800,18 @@ int remove_inode_page(struct inode *inode)
        BUG_ON(inode->i_blocks != 0 && inode->i_blocks != 1);
        set_new_dnode(&dn, inode, page, page, ino);
        truncate_node(&dn);
-
-       mutex_unlock_op(sbi, NODE_TRUNC);
        return 0;
 }
 
 int new_inode_page(struct inode *inode, const struct qstr *name)
 {
-       struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
        struct page *page;
        struct dnode_of_data dn;
 
        /* allocate inode page for new inode */
        set_new_dnode(&dn, inode, NULL, NULL, inode->i_ino);
-       mutex_lock_op(sbi, NODE_NEW);
        page = new_node_page(&dn, 0);
        init_dent_inode(name, page);
-       mutex_unlock_op(sbi, NODE_NEW);
        if (IS_ERR(page))
                return PTR_ERR(page);
        f2fs_put_page(page, 1);
@@ -844,6 +864,12 @@ fail:
        return ERR_PTR(err);
 }
 
+/*
+ * Caller should do after getting the following values.
+ * 0: f2fs_put_page(page, 0)
+ * LOCKED_PAGE: f2fs_put_page(page, 1)
+ * error: nothing
+ */
 static int read_node_page(struct page *page, int type)
 {
        struct f2fs_sb_info *sbi = F2FS_SB(page->mapping->host->i_sb);
@@ -851,8 +877,14 @@ static int read_node_page(struct page *page, int type)
 
        get_node_info(sbi, page->index, &ni);
 
-       if (ni.blk_addr == NULL_ADDR)
+       if (ni.blk_addr == NULL_ADDR) {
+               f2fs_put_page(page, 1);
                return -ENOENT;
+       }
+
+       if (PageUptodate(page))
+               return LOCKED_PAGE;
+
        return f2fs_readpage(sbi, page, ni.blk_addr, type);
 }
 
@@ -863,40 +895,53 @@ void ra_node_page(struct f2fs_sb_info *sbi, nid_t nid)
 {
        struct address_space *mapping = sbi->node_inode->i_mapping;
        struct page *apage;
+       int err;
 
        apage = find_get_page(mapping, nid);
-       if (apage && PageUptodate(apage))
-               goto release_out;
+       if (apage && PageUptodate(apage)) {
+               f2fs_put_page(apage, 0);
+               return;
+       }
        f2fs_put_page(apage, 0);
 
        apage = grab_cache_page(mapping, nid);
        if (!apage)
                return;
 
-       if (read_node_page(apage, READA))
-               unlock_page(apage);
-
-release_out:
-       f2fs_put_page(apage, 0);
+       err = read_node_page(apage, READA);
+       if (err == 0)
+               f2fs_put_page(apage, 0);
+       else if (err == LOCKED_PAGE)
+               f2fs_put_page(apage, 1);
        return;
 }
 
 struct page *get_node_page(struct f2fs_sb_info *sbi, pgoff_t nid)
 {
-       int err;
-       struct page *page;
        struct address_space *mapping = sbi->node_inode->i_mapping;
-
+       struct page *page;
+       int err;
+repeat:
        page = grab_cache_page(mapping, nid);
        if (!page)
                return ERR_PTR(-ENOMEM);
 
        err = read_node_page(page, READ_SYNC);
-       if (err) {
-               f2fs_put_page(page, 1);
+       if (err < 0)
                return ERR_PTR(err);
-       }
+       else if (err == LOCKED_PAGE)
+               goto got_it;
 
+       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;
+       }
+got_it:
        BUG_ON(nid != nid_of_node(page));
        mark_page_accessed(page);
        return page;
@@ -910,31 +955,27 @@ struct page *get_node_page_ra(struct page *parent, int start)
 {
        struct f2fs_sb_info *sbi = F2FS_SB(parent->mapping->host->i_sb);
        struct address_space *mapping = sbi->node_inode->i_mapping;
-       int i, end;
-       int err = 0;
-       nid_t nid;
+       struct blk_plug plug;
        struct page *page;
+       int err, i, end;
+       nid_t nid;
 
        /* First, try getting the desired direct node. */
        nid = get_nid(parent, start, false);
        if (!nid)
                return ERR_PTR(-ENOENT);
-
-       page = find_get_page(mapping, nid);
-       if (page && PageUptodate(page))
-               goto page_hit;
-       f2fs_put_page(page, 0);
-
 repeat:
        page = grab_cache_page(mapping, nid);
        if (!page)
                return ERR_PTR(-ENOMEM);
 
-       err = read_node_page(page, READA);
-       if (err) {
-               f2fs_put_page(page, 1);
+       err = read_node_page(page, READ_SYNC);
+       if (err < 0)
                return ERR_PTR(err);
-       }
+       else if (err == LOCKED_PAGE)
+               goto page_hit;
+
+       blk_start_plug(&plug);
 
        /* Then, try readahead for siblings of the desired node */
        end = start + MAX_RA_NODE;
@@ -946,18 +987,19 @@ repeat:
                ra_node_page(sbi, nid);
        }
 
-page_hit:
-       lock_page(page);
-       if (PageError(page)) {
-               f2fs_put_page(page, 1);
-               return ERR_PTR(-EIO);
-       }
+       blk_finish_plug(&plug);
 
-       /* Has the page been truncated? */
+       lock_page(page);
        if (page->mapping != mapping) {
                f2fs_put_page(page, 1);
                goto repeat;
        }
+page_hit:
+       if (!PageUptodate(page)) {
+               f2fs_put_page(page, 1);
+               return ERR_PTR(-EIO);
+       }
+       mark_page_accessed(page);
        return page;
 }
 
@@ -972,7 +1014,7 @@ void sync_inode_page(struct dnode_of_data *dn)
                if (!dn->inode_page_locked)
                        unlock_page(dn->inode_page);
        } else {
-               f2fs_write_inode(dn->inode, NULL);
+               update_inode_page(dn->inode);
        }
 }
 
@@ -1087,17 +1129,8 @@ static int f2fs_write_node_page(struct page *page,
        block_t new_addr;
        struct node_info ni;
 
-       if (wbc->for_reclaim) {
-               dec_page_count(sbi, F2FS_DIRTY_NODES);
-               wbc->pages_skipped++;
-               set_page_dirty(page);
-               return AOP_WRITEPAGE_ACTIVATE;
-       }
-
        wait_on_page_writeback(page);
 
-       mutex_lock_op(sbi, NODE_WRITE);
-
        /* get old block addr of this node page */
        nid = nid_of_node(page);
        BUG_ON(page->index != nid);
@@ -1105,17 +1138,25 @@ static int f2fs_write_node_page(struct page *page,
        get_node_info(sbi, nid, &ni);
 
        /* This page is already truncated */
-       if (ni.blk_addr == NULL_ADDR)
+       if (ni.blk_addr == NULL_ADDR) {
+               dec_page_count(sbi, F2FS_DIRTY_NODES);
+               unlock_page(page);
                return 0;
+       }
 
-       set_page_writeback(page);
+       if (wbc->for_reclaim) {
+               dec_page_count(sbi, F2FS_DIRTY_NODES);
+               wbc->pages_skipped++;
+               set_page_dirty(page);
+               return AOP_WRITEPAGE_ACTIVATE;
+       }
 
-       /* insert node offset */
+       mutex_lock(&sbi->node_write);
+       set_page_writeback(page);
        write_node_page(sbi, page, nid, ni.blk_addr, &new_addr);
        set_node_addr(sbi, &ni, new_addr);
        dec_page_count(sbi, F2FS_DIRTY_NODES);
-
-       mutex_unlock_op(sbi, NODE_WRITE);
+       mutex_unlock(&sbi->node_write);
        unlock_page(page);
        return 0;
 }
@@ -1130,12 +1171,11 @@ static int f2fs_write_node_pages(struct address_space *mapping,
                            struct writeback_control *wbc)
 {
        struct f2fs_sb_info *sbi = F2FS_SB(mapping->host->i_sb);
-       struct block_device *bdev = sbi->sb->s_bdev;
        long nr_to_write = wbc->nr_to_write;
 
        /* First check balancing cached NAT entries */
        if (try_to_free_nats(sbi, NAT_ENTRY_PER_BLOCK)) {
-               write_checkpoint(sbi, false);
+               f2fs_sync_fs(sbi->sb, true);
                return 0;
        }
 
@@ -1144,10 +1184,9 @@ static int f2fs_write_node_pages(struct address_space *mapping,
                return 0;
 
        /* if mounting is failed, skip writing node pages */
-       wbc->nr_to_write = bio_get_nr_vecs(bdev);
+       wbc->nr_to_write = max_hw_blocks(sbi);
        sync_node_pages(sbi, 0, wbc);
-       wbc->nr_to_write = nr_to_write -
-               (bio_get_nr_vecs(bdev) - wbc->nr_to_write);
+       wbc->nr_to_write = nr_to_write - (max_hw_blocks(sbi) - wbc->nr_to_write);
        return 0;
 }
 
@@ -1178,7 +1217,7 @@ static void f2fs_invalidate_node_page(struct page *page, unsigned long offset)
 static int f2fs_release_node_page(struct page *page, gfp_t wait)
 {
        ClearPagePrivate(page);
-       return 0;
+       return 1;
 }
 
 /*
@@ -1195,14 +1234,13 @@ const struct address_space_operations f2fs_node_aops = {
 static struct free_nid *__lookup_free_nid_list(nid_t n, struct list_head *head)
 {
        struct list_head *this;
-       struct free_nid *i = NULL;
+       struct free_nid *i;
        list_for_each(this, head) {
                i = list_entry(this, struct free_nid, list);
                if (i->nid == n)
-                       break;
-               i = NULL;
+                       return i;
        }
-       return i;
+       return NULL;
 }
 
 static void __del_from_free_nid_list(struct free_nid *i)
@@ -1211,11 +1249,29 @@ static void __del_from_free_nid_list(struct free_nid *i)
        kmem_cache_free(free_nid_slab, i);
 }
 
-static int add_free_nid(struct f2fs_nm_info *nm_i, nid_t nid)
+static int add_free_nid(struct f2fs_nm_info *nm_i, nid_t nid, bool build)
 {
        struct free_nid *i;
+       struct nat_entry *ne;
+       bool allocated = false;
 
        if (nm_i->fcnt > 2 * MAX_FREE_NIDS)
+               return -1;
+
+       /* 0 nid should not be used */
+       if (nid == 0)
+               return 0;
+
+       if (!build)
+               goto retry;
+
+       /* do not add allocated nids */
+       read_lock(&nm_i->nat_tree_lock);
+       ne = __lookup_nat_cache(nm_i, nid);
+       if (ne && nat_get_blkaddr(ne) != NULL_ADDR)
+               allocated = true;
+       read_unlock(&nm_i->nat_tree_lock);
+       if (allocated)
                return 0;
 retry:
        i = kmem_cache_alloc(free_nid_slab, GFP_NOFS);
@@ -1250,63 +1306,59 @@ static void remove_free_nid(struct f2fs_nm_info *nm_i, nid_t nid)
        spin_unlock(&nm_i->free_nid_list_lock);
 }
 
-static int scan_nat_page(struct f2fs_nm_info *nm_i,
+static void scan_nat_page(struct f2fs_nm_info *nm_i,
                        struct page *nat_page, nid_t start_nid)
 {
        struct f2fs_nat_block *nat_blk = page_address(nat_page);
        block_t blk_addr;
-       int fcnt = 0;
        int i;
 
-       /* 0 nid should not be used */
-       if (start_nid == 0)
-               ++start_nid;
-
        i = start_nid % NAT_ENTRY_PER_BLOCK;
 
        for (; i < NAT_ENTRY_PER_BLOCK; i++, start_nid++) {
-               blk_addr  = le32_to_cpu(nat_blk->entries[i].block_addr);
+
+               if (start_nid >= nm_i->max_nid)
+                       break;
+
+               blk_addr = le32_to_cpu(nat_blk->entries[i].block_addr);
                BUG_ON(blk_addr == NEW_ADDR);
-               if (blk_addr == NULL_ADDR)
-                       fcnt += add_free_nid(nm_i, start_nid);
+               if (blk_addr == NULL_ADDR) {
+                       if (add_free_nid(nm_i, start_nid, true) < 0)
+                               break;
+               }
        }
-       return fcnt;
 }
 
 static void build_free_nids(struct f2fs_sb_info *sbi)
 {
-       struct free_nid *fnid, *next_fnid;
        struct f2fs_nm_info *nm_i = NM_I(sbi);
        struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA);
        struct f2fs_summary_block *sum = curseg->sum_blk;
-       nid_t nid = 0;
-       bool is_cycled = false;
-       int fcnt = 0;
-       int i;
+       int i = 0;
+       nid_t nid = nm_i->next_scan_nid;
 
-       nid = nm_i->next_scan_nid;
-       nm_i->init_scan_nid = nid;
+       /* Enough entries */
+       if (nm_i->fcnt > NAT_ENTRY_PER_BLOCK)
+               return;
 
+       /* readahead nat pages to be scanned */
        ra_nat_pages(sbi, nid);
 
        while (1) {
                struct page *page = get_current_nat_page(sbi, nid);
 
-               fcnt += scan_nat_page(nm_i, page, nid);
+               scan_nat_page(nm_i, page, nid);
                f2fs_put_page(page, 1);
 
                nid += (NAT_ENTRY_PER_BLOCK - (nid % NAT_ENTRY_PER_BLOCK));
-
-               if (nid >= nm_i->max_nid) {
+               if (nid >= nm_i->max_nid)
                        nid = 0;
-                       is_cycled = true;
-               }
-               if (fcnt > MAX_FREE_NIDS)
-                       break;
-               if (is_cycled && nm_i->init_scan_nid <= nid)
+
+               if (i++ == FREE_NID_PAGES)
                        break;
        }
 
+       /* go to the next free nat pages to find free nids abundantly */
        nm_i->next_scan_nid = nid;
 
        /* find free nids from current sum_pages */
@@ -1315,22 +1367,11 @@ static void build_free_nids(struct f2fs_sb_info *sbi)
                block_t addr = le32_to_cpu(nat_in_journal(sum, i).block_addr);
                nid = le32_to_cpu(nid_in_journal(sum, i));
                if (addr == NULL_ADDR)
-                       add_free_nid(nm_i, nid);
+                       add_free_nid(nm_i, nid, true);
                else
                        remove_free_nid(nm_i, nid);
        }
        mutex_unlock(&curseg->curseg_mutex);
-
-       /* remove the free nids from current allocated nids */
-       list_for_each_entry_safe(fnid, next_fnid, &nm_i->free_nid_list, list) {
-               struct nat_entry *ne;
-
-               read_lock(&nm_i->nat_tree_lock);
-               ne = __lookup_nat_cache(nm_i, fnid->nid);
-               if (ne && nat_get_blkaddr(ne) != NULL_ADDR)
-                       remove_free_nid(nm_i, fnid->nid);
-               read_unlock(&nm_i->nat_tree_lock);
-       }
 }
 
 /*
@@ -1344,41 +1385,36 @@ bool alloc_nid(struct f2fs_sb_info *sbi, nid_t *nid)
        struct free_nid *i = NULL;
        struct list_head *this;
 retry:
-       mutex_lock(&nm_i->build_lock);
-       if (!nm_i->fcnt) {
-               /* scan NAT in order to build free nid list */
-               build_free_nids(sbi);
-               if (!nm_i->fcnt) {
-                       mutex_unlock(&nm_i->build_lock);
-                       return false;
-               }
-       }
-       mutex_unlock(&nm_i->build_lock);
+       if (sbi->total_valid_node_count + 1 >= nm_i->max_nid)
+               return false;
 
-       /*
-        * We check fcnt again since previous check is racy as
-        * we didn't hold free_nid_list_lock. So other thread
-        * could consume all of free nids.
-        */
        spin_lock(&nm_i->free_nid_list_lock);
-       if (!nm_i->fcnt) {
-               spin_unlock(&nm_i->free_nid_list_lock);
-               goto retry;
-       }
 
-       BUG_ON(list_empty(&nm_i->free_nid_list));
-       list_for_each(this, &nm_i->free_nid_list) {
-               i = list_entry(this, struct free_nid, list);
-               if (i->state == NID_NEW)
-                       break;
-       }
+       /* We should not use stale free nids created by build_free_nids */
+       if (nm_i->fcnt && !sbi->on_build_free_nids) {
+               BUG_ON(list_empty(&nm_i->free_nid_list));
+               list_for_each(this, &nm_i->free_nid_list) {
+                       i = list_entry(this, struct free_nid, list);
+                       if (i->state == NID_NEW)
+                               break;
+               }
 
-       BUG_ON(i->state != NID_NEW);
-       *nid = i->nid;
-       i->state = NID_ALLOC;
-       nm_i->fcnt--;
+               BUG_ON(i->state != NID_NEW);
+               *nid = i->nid;
+               i->state = NID_ALLOC;
+               nm_i->fcnt--;
+               spin_unlock(&nm_i->free_nid_list_lock);
+               return true;
+       }
        spin_unlock(&nm_i->free_nid_list_lock);
-       return true;
+
+       /* Let's scan nat pages and its caches to get free nids */
+       mutex_lock(&nm_i->build_lock);
+       sbi->on_build_free_nids = 1;
+       build_free_nids(sbi);
+       sbi->on_build_free_nids = 0;
+       mutex_unlock(&nm_i->build_lock);
+       goto retry;
 }
 
 /*
@@ -1391,10 +1427,8 @@ void alloc_nid_done(struct f2fs_sb_info *sbi, nid_t nid)
 
        spin_lock(&nm_i->free_nid_list_lock);
        i = __lookup_free_nid_list(nid, &nm_i->free_nid_list);
-       if (i) {
-               BUG_ON(i->state != NID_ALLOC);
-               __del_from_free_nid_list(i);
-       }
+       BUG_ON(!i || i->state != NID_ALLOC);
+       __del_from_free_nid_list(i);
        spin_unlock(&nm_i->free_nid_list_lock);
 }
 
@@ -1403,8 +1437,19 @@ void alloc_nid_done(struct f2fs_sb_info *sbi, nid_t nid)
  */
 void alloc_nid_failed(struct f2fs_sb_info *sbi, nid_t nid)
 {
-       alloc_nid_done(sbi, nid);
-       add_free_nid(NM_I(sbi), nid);
+       struct f2fs_nm_info *nm_i = NM_I(sbi);
+       struct free_nid *i;
+
+       spin_lock(&nm_i->free_nid_list_lock);
+       i = __lookup_free_nid_list(nid, &nm_i->free_nid_list);
+       BUG_ON(!i || i->state != NID_ALLOC);
+       if (nm_i->fcnt > 2 * MAX_FREE_NIDS) {
+               __del_from_free_nid_list(i);
+       } else {
+               i->state = NID_NEW;
+               nm_i->fcnt++;
+       }
+       spin_unlock(&nm_i->free_nid_list_lock);
 }
 
 void recover_node_page(struct f2fs_sb_info *sbi, struct page *page,
@@ -1475,23 +1520,24 @@ int restore_node_summary(struct f2fs_sb_info *sbi,
        sum_entry = &sum->entries[0];
 
        for (i = 0; i < last_offset; i++, sum_entry++) {
+               /*
+                * In order to read next node page,
+                * we must clear PageUptodate flag.
+                */
+               ClearPageUptodate(page);
+
                if (f2fs_readpage(sbi, page, addr, READ_SYNC))
                        goto out;
 
+               lock_page(page);
                rn = (struct f2fs_node *)page_address(page);
                sum_entry->nid = rn->footer.nid;
                sum_entry->version = 0;
                sum_entry->ofs_in_node = 0;
                addr++;
-
-               /*
-                * In order to read next node page,
-                * we must clear PageUptodate flag.
-                */
-               ClearPageUptodate(page);
        }
-out:
        unlock_page(page);
+out:
        __free_pages(page, 0);
        return 0;
 }
@@ -1614,13 +1660,11 @@ flush_now:
                        nid_in_journal(sum, offset) = cpu_to_le32(nid);
                }
 
-               if (nat_get_blkaddr(ne) == NULL_ADDR) {
+               if (nat_get_blkaddr(ne) == NULL_ADDR &&
+                               add_free_nid(NM_I(sbi), nid, false) <= 0) {
                        write_lock(&nm_i->nat_tree_lock);
                        __del_from_nat_cache(nm_i, ne);
                        write_unlock(&nm_i->nat_tree_lock);
-
-                       /* We can reuse this freed nid at this point */
-                       add_free_nid(NM_I(sbi), nid);
                } else {
                        write_lock(&nm_i->nat_tree_lock);
                        __clear_nat_cache_dirty(nm_i, ne);
@@ -1661,19 +1705,16 @@ static int init_node_manager(struct f2fs_sb_info *sbi)
        spin_lock_init(&nm_i->free_nid_list_lock);
        rwlock_init(&nm_i->nat_tree_lock);
 
-       nm_i->bitmap_size = __bitmap_size(sbi, NAT_BITMAP);
-       nm_i->init_scan_nid = le32_to_cpu(sbi->ckpt->next_free_nid);
        nm_i->next_scan_nid = le32_to_cpu(sbi->ckpt->next_free_nid);
-
-       nm_i->nat_bitmap = kzalloc(nm_i->bitmap_size, GFP_KERNEL);
-       if (!nm_i->nat_bitmap)
-               return -ENOMEM;
+       nm_i->bitmap_size = __bitmap_size(sbi, NAT_BITMAP);
        version_bitmap = __bitmap_ptr(sbi, NAT_BITMAP);
        if (!version_bitmap)
                return -EFAULT;
 
-       /* copy version bitmap */
-       memcpy(nm_i->nat_bitmap, version_bitmap, nm_i->bitmap_size);
+       nm_i->nat_bitmap = kmemdup(version_bitmap, nm_i->bitmap_size,
+                                       GFP_KERNEL);
+       if (!nm_i->nat_bitmap)
+               return -ENOMEM;
        return 0;
 }
 
index afdb130..0a2d72f 100644 (file)
@@ -29,6 +29,9 @@
 /* vector size for gang look-up from nat cache that consists of radix tree */
 #define NATVEC_SIZE    64
 
+/* return value for read_node_page */
+#define LOCKED_PAGE    1
+
 /*
  * For node information
  */
@@ -239,7 +242,7 @@ static inline bool IS_DNODE(struct page *node_page)
                return false;
        if (ofs >= 6 + 2 * NIDS_PER_BLOCK) {
                ofs -= 6 + 2 * NIDS_PER_BLOCK;
-               if ((long int)ofs % (NIDS_PER_BLOCK + 1))
+               if (!((long int)ofs % (NIDS_PER_BLOCK + 1)))
                        return false;
        }
        return true;
@@ -277,6 +280,21 @@ static inline int is_cold_file(struct inode *inode)
        return F2FS_I(inode)->i_advise & FADVISE_COLD_BIT;
 }
 
+static inline void set_cold_file(struct inode *inode)
+{
+       F2FS_I(inode)->i_advise |= FADVISE_COLD_BIT;
+}
+
+static inline int is_cp_file(struct inode *inode)
+{
+       return F2FS_I(inode)->i_advise & FADVISE_CP_BIT;
+}
+
+static inline void set_cp_file(struct inode *inode)
+{
+       F2FS_I(inode)->i_advise |= FADVISE_CP_BIT;
+}
+
 static inline int is_cold_data(struct page *page)
 {
        return PageChecked(page);
index b235215..60c8a50 100644 (file)
@@ -53,7 +53,7 @@ static int recover_dentry(struct page *ipage, struct inode *inode)
 
        dir = f2fs_iget(inode->i_sb, le32_to_cpu(raw_inode->i_pino));
        if (IS_ERR(dir)) {
-               err = -EINVAL;
+               err = PTR_ERR(dir);
                goto out;
        }
 
@@ -112,11 +112,14 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head)
        while (1) {
                struct fsync_inode_entry *entry;
 
-               if (f2fs_readpage(sbi, page, blkaddr, READ_SYNC))
+               err = f2fs_readpage(sbi, page, blkaddr, READ_SYNC);
+               if (err)
                        goto out;
 
+               lock_page(page);
+
                if (cp_ver != cpver_of_node(page))
-                       goto out;
+                       goto unlock_out;
 
                if (!is_fsync_dnode(page))
                        goto next;
@@ -129,24 +132,23 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head)
                                                        FI_INC_LINK);
                } else {
                        if (IS_INODE(page) && is_dent_dnode(page)) {
-                               if (recover_inode_page(sbi, page)) {
-                                       err = -ENOMEM;
-                                       goto out;
-                               }
+                               err = recover_inode_page(sbi, page);
+                               if (err)
+                                       goto unlock_out;
                        }
 
                        /* add this fsync inode to the list */
                        entry = kmem_cache_alloc(fsync_entry_slab, GFP_NOFS);
                        if (!entry) {
                                err = -ENOMEM;
-                               goto out;
+                               goto unlock_out;
                        }
 
                        entry->inode = f2fs_iget(sbi->sb, ino_of_node(page));
                        if (IS_ERR(entry->inode)) {
                                err = PTR_ERR(entry->inode);
                                kmem_cache_free(fsync_entry_slab, entry);
-                               goto out;
+                               goto unlock_out;
                        }
 
                        list_add_tail(&entry->list, head);
@@ -154,16 +156,20 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head)
                }
                if (IS_INODE(page)) {
                        err = recover_inode(entry->inode, page);
-                       if (err)
-                               goto out;
+                       if (err == -ENOENT) {
+                               goto next;
+                       } else if (err) {
+                               err = -EINVAL;
+                               goto unlock_out;
+                       }
                }
 next:
                /* check next segment */
                blkaddr = next_blkaddr_of_node(page);
-               ClearPageUptodate(page);
        }
-out:
+unlock_out:
        unlock_page(page);
+out:
        __free_pages(page, 0);
        return err;
 }
@@ -232,13 +238,15 @@ static void check_index_in_prev_nodes(struct f2fs_sb_info *sbi,
        iput(inode);
 }
 
-static void do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
+static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
                                        struct page *page, block_t blkaddr)
 {
        unsigned int start, end;
        struct dnode_of_data dn;
        struct f2fs_summary sum;
        struct node_info ni;
+       int err = 0;
+       int ilock;
 
        start = start_bidx_of_node(ofs_of_node(page));
        if (IS_INODE(page))
@@ -246,9 +254,14 @@ static void do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
        else
                end = start + ADDRS_PER_BLOCK;
 
+       ilock = mutex_lock_op(sbi);
        set_new_dnode(&dn, inode, NULL, NULL, 0);
-       if (get_dnode_of_data(&dn, start, 0))
-               return;
+
+       err = get_dnode_of_data(&dn, start, ALLOC_NODE);
+       if (err) {
+               mutex_unlock_op(sbi, ilock);
+               return err;
+       }
 
        wait_on_page_writeback(dn.node_page);
 
@@ -293,14 +306,17 @@ static void do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
 
        recover_node_page(sbi, dn.node_page, &sum, &ni, blkaddr);
        f2fs_put_dnode(&dn);
+       mutex_unlock_op(sbi, ilock);
+       return 0;
 }
 
-static void recover_data(struct f2fs_sb_info *sbi,
+static int recover_data(struct f2fs_sb_info *sbi,
                                struct list_head *head, int type)
 {
        unsigned long long cp_ver = le64_to_cpu(sbi->ckpt->checkpoint_ver);
        struct curseg_info *curseg;
        struct page *page;
+       int err = 0;
        block_t blkaddr;
 
        /* get node pages in the current segment */
@@ -310,23 +326,29 @@ static void recover_data(struct f2fs_sb_info *sbi,
        /* read node page */
        page = alloc_page(GFP_NOFS | __GFP_ZERO);
        if (IS_ERR(page))
-               return;
+               return -ENOMEM;
+
        lock_page(page);
 
        while (1) {
                struct fsync_inode_entry *entry;
 
-               if (f2fs_readpage(sbi, page, blkaddr, READ_SYNC))
+               err = f2fs_readpage(sbi, page, blkaddr, READ_SYNC);
+               if (err)
                        goto out;
 
+               lock_page(page);
+
                if (cp_ver != cpver_of_node(page))
-                       goto out;
+                       goto unlock_out;
 
                entry = get_fsync_inode(head, ino_of_node(page));
                if (!entry)
                        goto next;
 
-               do_recover_data(sbi, entry->inode, page, blkaddr);
+               err = do_recover_data(sbi, entry->inode, page, blkaddr);
+               if (err)
+                       goto out;
 
                if (entry->blkaddr == blkaddr) {
                        iput(entry->inode);
@@ -336,28 +358,32 @@ static void recover_data(struct f2fs_sb_info *sbi,
 next:
                /* check next segment */
                blkaddr = next_blkaddr_of_node(page);
-               ClearPageUptodate(page);
        }
-out:
+unlock_out:
        unlock_page(page);
+out:
        __free_pages(page, 0);
 
-       allocate_new_segments(sbi);
+       if (!err)
+               allocate_new_segments(sbi);
+       return err;
 }
 
-void recover_fsync_data(struct f2fs_sb_info *sbi)
+int recover_fsync_data(struct f2fs_sb_info *sbi)
 {
        struct list_head inode_list;
+       int err;
 
        fsync_entry_slab = f2fs_kmem_cache_create("f2fs_fsync_inode_entry",
                        sizeof(struct fsync_inode_entry), NULL);
        if (unlikely(!fsync_entry_slab))
-               return;
+               return -ENOMEM;
 
        INIT_LIST_HEAD(&inode_list);
 
        /* step #1: find fsynced inode numbers */
-       if (find_fsync_dnodes(sbi, &inode_list))
+       err = find_fsync_dnodes(sbi, &inode_list);
+       if (err)
                goto out;
 
        if (list_empty(&inode_list))
@@ -365,11 +391,12 @@ void recover_fsync_data(struct f2fs_sb_info *sbi)
 
        /* step #2: recover data */
        sbi->por_doing = 1;
-       recover_data(sbi, &inode_list, CURSEG_WARM_NODE);
+       err = recover_data(sbi, &inode_list, CURSEG_WARM_NODE);
        sbi->por_doing = 0;
        BUG_ON(!list_empty(&inode_list));
 out:
        destroy_fsync_dnodes(sbi, &inode_list);
        kmem_cache_destroy(fsync_entry_slab);
        write_checkpoint(sbi, false);
+       return err;
 }
index 777f17e..d8e84e4 100644 (file)
@@ -18,6 +18,7 @@
 #include "f2fs.h"
 #include "segment.h"
 #include "node.h"
+#include <trace/events/f2fs.h>
 
 /*
  * This function balances dirty node and dentry pages.
@@ -49,9 +50,20 @@ static void __locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno,
 
        if (dirty_type == DIRTY) {
                struct seg_entry *sentry = get_seg_entry(sbi, segno);
+               enum dirty_type t = DIRTY_HOT_DATA;
+
                dirty_type = sentry->type;
+
                if (!test_and_set_bit(segno, dirty_i->dirty_segmap[dirty_type]))
                        dirty_i->nr_dirty[dirty_type]++;
+
+               /* Only one bitmap should be set */
+               for (; t <= DIRTY_COLD_NODE; t++) {
+                       if (t == dirty_type)
+                               continue;
+                       if (test_and_clear_bit(segno, dirty_i->dirty_segmap[t]))
+                               dirty_i->nr_dirty[t]--;
+               }
        }
 }
 
@@ -64,13 +76,16 @@ static void __remove_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno,
                dirty_i->nr_dirty[dirty_type]--;
 
        if (dirty_type == DIRTY) {
-               struct seg_entry *sentry = get_seg_entry(sbi, segno);
-               dirty_type = sentry->type;
-               if (test_and_clear_bit(segno,
-                                       dirty_i->dirty_segmap[dirty_type]))
-                       dirty_i->nr_dirty[dirty_type]--;
-               clear_bit(segno, dirty_i->victim_segmap[FG_GC]);
-               clear_bit(segno, dirty_i->victim_segmap[BG_GC]);
+               enum dirty_type t = DIRTY_HOT_DATA;
+
+               /* clear all the bitmaps */
+               for (; t <= DIRTY_COLD_NODE; t++)
+                       if (test_and_clear_bit(segno, dirty_i->dirty_segmap[t]))
+                               dirty_i->nr_dirty[t]--;
+
+               if (get_valid_blocks(sbi, segno, sbi->segs_per_sec) == 0)
+                       clear_bit(GET_SECNO(sbi, segno),
+                                               dirty_i->victim_secmap);
        }
 }
 
@@ -296,13 +311,12 @@ static void write_sum_page(struct f2fs_sb_info *sbi,
        f2fs_put_page(page, 1);
 }
 
-static unsigned int check_prefree_segments(struct f2fs_sb_info *sbi,
-                                       int ofs_unit, int type)
+static unsigned int check_prefree_segments(struct f2fs_sb_info *sbi, int type)
 {
        struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
        unsigned long *prefree_segmap = dirty_i->dirty_segmap[PRE];
-       unsigned int segno, next_segno, i;
-       int ofs = 0;
+       unsigned int segno;
+       unsigned int ofs = 0;
 
        /*
         * If there is not enough reserved sections,
@@ -318,28 +332,46 @@ static unsigned int check_prefree_segments(struct f2fs_sb_info *sbi,
        if (IS_NODESEG(type))
                return NULL_SEGNO;
 next:
-       segno = find_next_bit(prefree_segmap, TOTAL_SEGS(sbi), ofs++);
-       ofs = ((segno / ofs_unit) * ofs_unit) + ofs_unit;
+       segno = find_next_bit(prefree_segmap, TOTAL_SEGS(sbi), ofs);
+       ofs += sbi->segs_per_sec;
+
        if (segno < TOTAL_SEGS(sbi)) {
+               int i;
+
                /* skip intermediate segments in a section */
-               if (segno % ofs_unit)
+               if (segno % sbi->segs_per_sec)
                        goto next;
 
-               /* skip if whole section is not prefree */
-               next_segno = find_next_zero_bit(prefree_segmap,
-                                               TOTAL_SEGS(sbi), segno + 1);
-               if (next_segno - segno < ofs_unit)
+               /* skip if the section is currently used */
+               if (sec_usage_check(sbi, GET_SECNO(sbi, segno)))
                        goto next;
 
+               /* skip if whole section is not prefree */
+               for (i = 1; i < sbi->segs_per_sec; i++)
+                       if (!test_bit(segno + i, prefree_segmap))
+                               goto next;
+
                /* skip if whole section was not free at the last checkpoint */
-               for (i = 0; i < ofs_unit; i++)
-                       if (get_seg_entry(sbi, segno)->ckpt_valid_blocks)
+               for (i = 0; i < sbi->segs_per_sec; i++)
+                       if (get_seg_entry(sbi, segno + i)->ckpt_valid_blocks)
                                goto next;
+
                return segno;
        }
        return NULL_SEGNO;
 }
 
+static int is_next_segment_free(struct f2fs_sb_info *sbi, int type)
+{
+       struct curseg_info *curseg = CURSEG_I(sbi, type);
+       unsigned int segno = curseg->segno;
+       struct free_segmap_info *free_i = FREE_I(sbi);
+
+       if (segno + 1 < TOTAL_SEGS(sbi) && (segno + 1) % sbi->segs_per_sec)
+               return !test_bit(segno + 1, free_i->free_segmap);
+       return 0;
+}
+
 /*
  * Find a new segment from the free segments bitmap to right order
  * This function should be returned with success, otherwise BUG
@@ -348,9 +380,8 @@ static void get_new_segment(struct f2fs_sb_info *sbi,
                        unsigned int *newseg, bool new_sec, int dir)
 {
        struct free_segmap_info *free_i = FREE_I(sbi);
-       unsigned int total_secs = sbi->total_sections;
        unsigned int segno, secno, zoneno;
-       unsigned int total_zones = sbi->total_sections / sbi->secs_per_zone;
+       unsigned int total_zones = TOTAL_SECS(sbi) / sbi->secs_per_zone;
        unsigned int hint = *newseg / sbi->segs_per_sec;
        unsigned int old_zoneno = GET_ZONENO_FROM_SEGNO(sbi, *newseg);
        unsigned int left_start = hint;
@@ -363,16 +394,17 @@ static void get_new_segment(struct f2fs_sb_info *sbi,
        if (!new_sec && ((*newseg + 1) % sbi->segs_per_sec)) {
                segno = find_next_zero_bit(free_i->free_segmap,
                                        TOTAL_SEGS(sbi), *newseg + 1);
-               if (segno < TOTAL_SEGS(sbi))
+               if (segno - *newseg < sbi->segs_per_sec -
+                                       (*newseg % sbi->segs_per_sec))
                        goto got_it;
        }
 find_other_zone:
-       secno = find_next_zero_bit(free_i->free_secmap, total_secs, hint);
-       if (secno >= total_secs) {
+       secno = find_next_zero_bit(free_i->free_secmap, TOTAL_SECS(sbi), hint);
+       if (secno >= TOTAL_SECS(sbi)) {
                if (dir == ALLOC_RIGHT) {
                        secno = find_next_zero_bit(free_i->free_secmap,
-                                               total_secs, 0);
-                       BUG_ON(secno >= total_secs);
+                                                       TOTAL_SECS(sbi), 0);
+                       BUG_ON(secno >= TOTAL_SECS(sbi));
                } else {
                        go_left = 1;
                        left_start = hint - 1;
@@ -387,8 +419,8 @@ find_other_zone:
                        continue;
                }
                left_start = find_next_zero_bit(free_i->free_secmap,
-                                               total_secs, 0);
-               BUG_ON(left_start >= total_secs);
+                                                       TOTAL_SECS(sbi), 0);
+               BUG_ON(left_start >= TOTAL_SECS(sbi));
                break;
        }
        secno = left_start;
@@ -561,20 +593,20 @@ static void allocate_segment_by_default(struct f2fs_sb_info *sbi,
                                                int type, bool force)
 {
        struct curseg_info *curseg = CURSEG_I(sbi, type);
-       unsigned int ofs_unit;
 
        if (force) {
                new_curseg(sbi, type, true);
                goto out;
        }
 
-       ofs_unit = need_SSR(sbi) ? 1 : sbi->segs_per_sec;
-       curseg->next_segno = check_prefree_segments(sbi, ofs_unit, type);
+       curseg->next_segno = check_prefree_segments(sbi, type);
 
        if (curseg->next_segno != NULL_SEGNO)
                change_curseg(sbi, type, false);
        else if (type == CURSEG_WARM_NODE)
                new_curseg(sbi, type, false);
+       else if (curseg->alloc_type == LFS && is_next_segment_free(sbi, type))
+               new_curseg(sbi, type, false);
        else if (need_SSR(sbi) && get_ssr_segment(sbi, type))
                change_curseg(sbi, type, true);
        else
@@ -656,10 +688,16 @@ static void do_submit_bio(struct f2fs_sb_info *sbi,
        if (type >= META_FLUSH)
                rw = WRITE_FLUSH_FUA;
 
+       if (btype == META)
+               rw |= REQ_META;
+
        if (sbi->bio[btype]) {
                struct bio_private *p = sbi->bio[btype]->bi_private;
                p->sbi = sbi;
                sbi->bio[btype]->bi_end_io = f2fs_end_io_write;
+
+               trace_f2fs_do_submit_bio(sbi->sb, btype, sync, sbi->bio[btype]);
+
                if (type == META_FLUSH) {
                        DECLARE_COMPLETION_ONSTACK(wait);
                        p->is_sync = true;
@@ -696,7 +734,7 @@ static void submit_write_page(struct f2fs_sb_info *sbi, struct page *page,
                do_submit_bio(sbi, type, false);
 alloc_new:
        if (sbi->bio[type] == NULL) {
-               sbi->bio[type] = f2fs_bio_alloc(bdev, bio_get_nr_vecs(bdev));
+               sbi->bio[type] = f2fs_bio_alloc(bdev, max_hw_blocks(sbi));
                sbi->bio[type]->bi_sector = SECTOR_FROM_BLOCK(sbi, blk_addr);
                /*
                 * The end_io will be assigned at the sumbission phase.
@@ -714,6 +752,7 @@ alloc_new:
        sbi->last_block_in_bio[type] = blk_addr;
 
        up_write(&sbi->bio_sem);
+       trace_f2fs_submit_write_page(page, blk_addr, type);
 }
 
 static bool __has_curseg_space(struct f2fs_sb_info *sbi, int type)
@@ -1390,7 +1429,7 @@ static int build_sit_info(struct f2fs_sb_info *sbi)
        }
 
        if (sbi->segs_per_sec > 1) {
-               sit_i->sec_entries = vzalloc(sbi->total_sections *
+               sit_i->sec_entries = vzalloc(TOTAL_SECS(sbi) *
                                        sizeof(struct sec_entry));
                if (!sit_i->sec_entries)
                        return -ENOMEM;
@@ -1403,10 +1442,9 @@ static int build_sit_info(struct f2fs_sb_info *sbi)
        bitmap_size = __bitmap_size(sbi, SIT_BITMAP);
        src_bitmap = __bitmap_ptr(sbi, SIT_BITMAP);
 
-       dst_bitmap = kzalloc(bitmap_size, GFP_KERNEL);
+       dst_bitmap = kmemdup(src_bitmap, bitmap_size, GFP_KERNEL);
        if (!dst_bitmap)
                return -ENOMEM;
-       memcpy(dst_bitmap, src_bitmap, bitmap_size);
 
        /* init SIT information */
        sit_i->s_ops = &default_salloc_ops;
@@ -1442,7 +1480,7 @@ static int build_free_segmap(struct f2fs_sb_info *sbi)
        if (!free_i->free_segmap)
                return -ENOMEM;
 
-       sec_bitmap_size = f2fs_bitmap_size(sbi->total_sections);
+       sec_bitmap_size = f2fs_bitmap_size(TOTAL_SECS(sbi));
        free_i->free_secmap = kmalloc(sec_bitmap_size, GFP_KERNEL);
        if (!free_i->free_secmap)
                return -ENOMEM;
@@ -1559,14 +1597,13 @@ static void init_dirty_segmap(struct f2fs_sb_info *sbi)
        }
 }
 
-static int init_victim_segmap(struct f2fs_sb_info *sbi)
+static int init_victim_secmap(struct f2fs_sb_info *sbi)
 {
        struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
-       unsigned int bitmap_size = f2fs_bitmap_size(TOTAL_SEGS(sbi));
+       unsigned int bitmap_size = f2fs_bitmap_size(TOTAL_SECS(sbi));
 
-       dirty_i->victim_segmap[FG_GC] = kzalloc(bitmap_size, GFP_KERNEL);
-       dirty_i->victim_segmap[BG_GC] = kzalloc(bitmap_size, GFP_KERNEL);
-       if (!dirty_i->victim_segmap[FG_GC] || !dirty_i->victim_segmap[BG_GC])
+       dirty_i->victim_secmap = kzalloc(bitmap_size, GFP_KERNEL);
+       if (!dirty_i->victim_secmap)
                return -ENOMEM;
        return 0;
 }
@@ -1593,7 +1630,7 @@ static int build_dirty_segmap(struct f2fs_sb_info *sbi)
        }
 
        init_dirty_segmap(sbi);
-       return init_victim_segmap(sbi);
+       return init_victim_secmap(sbi);
 }
 
 /*
@@ -1680,18 +1717,10 @@ static void discard_dirty_segmap(struct f2fs_sb_info *sbi,
        mutex_unlock(&dirty_i->seglist_lock);
 }
 
-void reset_victim_segmap(struct f2fs_sb_info *sbi)
-{
-       unsigned int bitmap_size = f2fs_bitmap_size(TOTAL_SEGS(sbi));
-       memset(DIRTY_I(sbi)->victim_segmap[FG_GC], 0, bitmap_size);
-}
-
-static void destroy_victim_segmap(struct f2fs_sb_info *sbi)
+static void destroy_victim_secmap(struct f2fs_sb_info *sbi)
 {
        struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
-
-       kfree(dirty_i->victim_segmap[FG_GC]);
-       kfree(dirty_i->victim_segmap[BG_GC]);
+       kfree(dirty_i->victim_secmap);
 }
 
 static void destroy_dirty_segmap(struct f2fs_sb_info *sbi)
@@ -1706,7 +1735,7 @@ static void destroy_dirty_segmap(struct f2fs_sb_info *sbi)
        for (i = 0; i < NR_DIRTY_TYPE; i++)
                discard_dirty_segmap(sbi, i);
 
-       destroy_victim_segmap(sbi);
+       destroy_victim_secmap(sbi);
        SM_I(sbi)->dirty_info = NULL;
        kfree(dirty_i);
 }
index 552dadb..062424a 100644 (file)
@@ -8,10 +8,13 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
+#include <linux/blkdev.h>
+
 /* constant macro */
 #define NULL_SEGNO                     ((unsigned int)(~0))
+#define NULL_SECNO                     ((unsigned int)(~0))
 
-/* V: Logical segment # in volume, R: Relative segment # in main area */
+/* L: Logical segment # in volume, R: Relative segment # in main area */
 #define GET_L2R_SEGNO(free_i, segno)   (segno - free_i->start_segno)
 #define GET_R2L_SEGNO(free_i, segno)   (segno + free_i->start_segno)
 
        ((t == CURSEG_HOT_NODE) || (t == CURSEG_COLD_NODE) ||           \
        (t == CURSEG_WARM_NODE))
 
-#define IS_CURSEG(sbi, segno)                                          \
-       ((segno == CURSEG_I(sbi, CURSEG_HOT_DATA)->segno) ||    \
-        (segno == CURSEG_I(sbi, CURSEG_WARM_DATA)->segno) ||   \
-        (segno == CURSEG_I(sbi, CURSEG_COLD_DATA)->segno) ||   \
-        (segno == CURSEG_I(sbi, CURSEG_HOT_NODE)->segno) ||    \
-        (segno == CURSEG_I(sbi, CURSEG_WARM_NODE)->segno) ||   \
-        (segno == CURSEG_I(sbi, CURSEG_COLD_NODE)->segno))
+#define IS_CURSEG(sbi, seg)                                            \
+       ((seg == CURSEG_I(sbi, CURSEG_HOT_DATA)->segno) ||      \
+        (seg == CURSEG_I(sbi, CURSEG_WARM_DATA)->segno) ||     \
+        (seg == CURSEG_I(sbi, CURSEG_COLD_DATA)->segno) ||     \
+        (seg == CURSEG_I(sbi, CURSEG_HOT_NODE)->segno) ||      \
+        (seg == CURSEG_I(sbi, CURSEG_WARM_NODE)->segno) ||     \
+        (seg == CURSEG_I(sbi, CURSEG_COLD_NODE)->segno))
 
 #define IS_CURSEC(sbi, secno)                                          \
        ((secno == CURSEG_I(sbi, CURSEG_HOT_DATA)->segno /              \
 #define f2fs_bitmap_size(nr)                   \
        (BITS_TO_LONGS(nr) * sizeof(unsigned long))
 #define TOTAL_SEGS(sbi)        (SM_I(sbi)->main_segments)
+#define TOTAL_SECS(sbi)        (sbi->total_sections)
 
 #define SECTOR_FROM_BLOCK(sbi, blk_addr)                               \
        (blk_addr << ((sbi)->log_blocksize - F2FS_LOG_SECTOR_SIZE))
+#define SECTOR_TO_BLOCK(sbi, sectors)                                  \
+       (sectors >> ((sbi)->log_blocksize - F2FS_LOG_SECTOR_SIZE))
 
 /* during checkpoint, bio_private is used to synchronize the last bio */
 struct bio_private {
@@ -213,7 +219,7 @@ struct dirty_seglist_info {
        unsigned long *dirty_segmap[NR_DIRTY_TYPE];
        struct mutex seglist_lock;              /* lock for segment bitmaps */
        int nr_dirty[NR_DIRTY_TYPE];            /* # of dirty segments */
-       unsigned long *victim_segmap[2];        /* BG_GC, FG_GC */
+       unsigned long *victim_secmap;           /* background GC victims */
 };
 
 /* victim selection function for cleaning and SSR */
@@ -464,8 +470,7 @@ static inline bool has_not_enough_free_secs(struct f2fs_sb_info *sbi, int freed)
 
 static inline int utilization(struct f2fs_sb_info *sbi)
 {
-       return (long int)valid_user_blocks(sbi) * 100 /
-                       (long int)sbi->user_block_count;
+       return div_u64(valid_user_blocks(sbi) * 100, sbi->user_block_count);
 }
 
 /*
@@ -616,3 +621,17 @@ static inline block_t sum_blk_addr(struct f2fs_sb_info *sbi, int base, int type)
                le32_to_cpu(F2FS_CKPT(sbi)->cp_pack_total_block_count)
                                - (base + 1) + type;
 }
+
+static inline bool sec_usage_check(struct f2fs_sb_info *sbi, unsigned int secno)
+{
+       if (IS_CURSEC(sbi, secno) || (sbi->cur_victim_sec == secno))
+               return true;
+       return false;
+}
+
+static inline unsigned int max_hw_blocks(struct f2fs_sb_info *sbi)
+{
+       struct block_device *bdev = sbi->sb->s_bdev;
+       struct request_queue *q = bdev_get_queue(bdev);
+       return SECTOR_TO_BLOCK(sbi, queue_max_sectors(q));
+}
index 62e0177..8555f7d 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/init.h>
 #include <linux/fs.h>
 #include <linux/statfs.h>
-#include <linux/proc_fs.h>
 #include <linux/buffer_head.h>
 #include <linux/backing-dev.h>
 #include <linux/kthread.h>
 #include <linux/seq_file.h>
 #include <linux/random.h>
 #include <linux/exportfs.h>
+#include <linux/blkdev.h>
 #include <linux/f2fs_fs.h>
 
 #include "f2fs.h"
 #include "node.h"
+#include "segment.h"
 #include "xattr.h"
 
+#define CREATE_TRACE_POINTS
+#include <trace/events/f2fs.h>
+
 static struct kmem_cache *f2fs_inode_cachep;
 
 enum {
@@ -94,6 +98,20 @@ static struct inode *f2fs_alloc_inode(struct super_block *sb)
        return &fi->vfs_inode;
 }
 
+static int f2fs_drop_inode(struct inode *inode)
+{
+       /*
+        * This is to avoid a deadlock condition like below.
+        * writeback_single_inode(inode)
+        *  - f2fs_write_data_page
+        *    - f2fs_gc -> iput -> evict
+        *       - inode_wait_for_writeback(inode)
+        */
+       if (!inode_unhashed(inode) && inode->i_state & I_SYNC)
+               return 0;
+       return generic_drop_inode(inode);
+}
+
 static void f2fs_i_callback(struct rcu_head *head)
 {
        struct inode *inode = container_of(head, struct inode, i_rcu);
@@ -132,13 +150,18 @@ int f2fs_sync_fs(struct super_block *sb, int sync)
 {
        struct f2fs_sb_info *sbi = F2FS_SB(sb);
 
+       trace_f2fs_sync_fs(sb, sync);
+
        if (!sbi->s_dirty && !get_pages(sbi, F2FS_DIRTY_NODES))
                return 0;
 
-       if (sync)
+       if (sync) {
+               mutex_lock(&sbi->gc_mutex);
                write_checkpoint(sbi, false);
-       else
+               mutex_unlock(&sbi->gc_mutex);
+       } else {
                f2fs_balance_fs(sbi);
+       }
 
        return 0;
 }
@@ -180,7 +203,7 @@ static int f2fs_statfs(struct dentry *dentry, struct kstatfs *buf)
        buf->f_files = sbi->total_node_count;
        buf->f_ffree = sbi->total_node_count - valid_inode_count(sbi);
 
-       buf->f_namelen = F2FS_MAX_NAME_LEN;
+       buf->f_namelen = F2FS_NAME_LEN;
        buf->f_fsid.val[0] = (u32)id;
        buf->f_fsid.val[1] = (u32)(id >> 32);
 
@@ -223,6 +246,7 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
 
 static struct super_operations f2fs_sops = {
        .alloc_inode    = f2fs_alloc_inode,
+       .drop_inode     = f2fs_drop_inode,
        .destroy_inode  = f2fs_destroy_inode,
        .write_inode    = f2fs_write_inode,
        .show_options   = f2fs_show_options,
@@ -457,6 +481,7 @@ static void init_sb_info(struct f2fs_sb_info *sbi)
        sbi->root_ino_num = le32_to_cpu(raw_super->root_ino);
        sbi->node_ino_num = le32_to_cpu(raw_super->node_ino);
        sbi->meta_ino_num = le32_to_cpu(raw_super->meta_ino);
+       sbi->cur_victim_sec = NULL_SECNO;
 
        for (i = 0; i < NR_COUNT_TYPE; i++)
                atomic_set(&sbi->nr_pages[i], 0);
@@ -473,7 +498,7 @@ static int validate_superblock(struct super_block *sb,
        if (!*raw_super_buf) {
                f2fs_msg(sb, KERN_ERR, "unable to read %s superblock",
                                super);
-               return 1;
+               return -EIO;
        }
 
        *raw_super = (struct f2fs_super_block *)
@@ -485,7 +510,7 @@ static int validate_superblock(struct super_block *sb,
 
        f2fs_msg(sb, KERN_ERR, "Can't find a valid F2FS filesystem "
                                "in %s superblock", super);
-       return 1;
+       return -EINVAL;
 }
 
 static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
@@ -508,9 +533,12 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
                goto free_sbi;
        }
 
-       if (validate_superblock(sb, &raw_super, &raw_super_buf, 0)) {
+       err = validate_superblock(sb, &raw_super, &raw_super_buf, 0);
+       if (err) {
                brelse(raw_super_buf);
-               if (validate_superblock(sb, &raw_super, &raw_super_buf, 1))
+               /* check secondary superblock when primary failed */
+               err = validate_superblock(sb, &raw_super, &raw_super_buf, 1);
+               if (err)
                        goto free_sb_buf;
        }
        /* init some FS parameters */
@@ -525,7 +553,8 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
        set_opt(sbi, POSIX_ACL);
 #endif
        /* parse mount options */
-       if (parse_options(sb, sbi, (char *)data))
+       err = parse_options(sb, sbi, (char *)data);
+       if (err)
                goto free_sb_buf;
 
        sb->s_maxbytes = max_file_size(le32_to_cpu(raw_super->log_blocksize));
@@ -547,11 +576,11 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
        sbi->raw_super = raw_super;
        sbi->raw_super_buf = raw_super_buf;
        mutex_init(&sbi->gc_mutex);
-       mutex_init(&sbi->write_inode);
        mutex_init(&sbi->writepages);
        mutex_init(&sbi->cp_mutex);
-       for (i = 0; i < NR_LOCK_TYPE; i++)
+       for (i = 0; i < NR_GLOBAL_LOCKS; i++)
                mutex_init(&sbi->fs_lock[i]);
+       mutex_init(&sbi->node_write);
        sbi->por_doing = 0;
        spin_lock_init(&sbi->stat_lock);
        init_rwsem(&sbi->bio_sem);
@@ -638,8 +667,12 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
        }
 
        /* recover fsynced data */
-       if (!test_opt(sbi, DISABLE_ROLL_FORWARD))
-               recover_fsync_data(sbi);
+       if (!test_opt(sbi, DISABLE_ROLL_FORWARD)) {
+               err = recover_fsync_data(sbi);
+               if (err)
+                       f2fs_msg(sb, KERN_ERR,
+                               "Cannot recover all fsync data errno=%ld", err);
+       }
 
        /* After POR, we can run background GC thread */
        err = start_gc_thread(sbi);
@@ -650,6 +683,14 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
        if (err)
                goto fail;
 
+       if (test_opt(sbi, DISCARD)) {
+               struct request_queue *q = bdev_get_queue(sb->s_bdev);
+               if (!blk_queue_discard(q))
+                       f2fs_msg(sb, KERN_WARNING,
+                                       "mounting with \"discard\" option, but "
+                                       "the device does not support discard");
+       }
+
        return 0;
 fail:
        stop_gc_thread(sbi);
index 8038c04..0b02dce 100644 (file)
@@ -307,27 +307,30 @@ int f2fs_setxattr(struct inode *inode, int name_index, const char *name,
        int error, found, free, newsize;
        size_t name_len;
        char *pval;
+       int ilock;
 
        if (name == NULL)
                return -EINVAL;
-       name_len = strlen(name);
 
        if (value == NULL)
                value_len = 0;
 
-       if (name_len > 255 || value_len > MAX_VALUE_LEN)
+       name_len = strlen(name);
+
+       if (name_len > F2FS_NAME_LEN || value_len > MAX_VALUE_LEN)
                return -ERANGE;
 
        f2fs_balance_fs(sbi);
 
-       mutex_lock_op(sbi, NODE_NEW);
+       ilock = mutex_lock_op(sbi);
+
        if (!fi->i_xattr_nid) {
                /* Allocate new attribute block */
                struct dnode_of_data dn;
 
                if (!alloc_nid(sbi, &fi->i_xattr_nid)) {
-                       mutex_unlock_op(sbi, NODE_NEW);
-                       return -ENOSPC;
+                       error = -ENOSPC;
+                       goto exit;
                }
                set_new_dnode(&dn, inode, NULL, NULL, fi->i_xattr_nid);
                mark_inode_dirty(inode);
@@ -336,8 +339,8 @@ int f2fs_setxattr(struct inode *inode, int name_index, const char *name,
                if (IS_ERR(page)) {
                        alloc_nid_failed(sbi, fi->i_xattr_nid);
                        fi->i_xattr_nid = 0;
-                       mutex_unlock_op(sbi, NODE_NEW);
-                       return PTR_ERR(page);
+                       error = PTR_ERR(page);
+                       goto exit;
                }
 
                alloc_nid_done(sbi, fi->i_xattr_nid);
@@ -349,8 +352,8 @@ int f2fs_setxattr(struct inode *inode, int name_index, const char *name,
                /* The inode already has an extended attribute block. */
                page = get_node_page(sbi, fi->i_xattr_nid);
                if (IS_ERR(page)) {
-                       mutex_unlock_op(sbi, NODE_NEW);
-                       return PTR_ERR(page);
+                       error = PTR_ERR(page);
+                       goto exit;
                }
 
                base_addr = page_address(page);
@@ -432,12 +435,13 @@ int f2fs_setxattr(struct inode *inode, int name_index, const char *name,
                inode->i_ctime = CURRENT_TIME;
                clear_inode_flag(fi, FI_ACL_MODE);
        }
-       f2fs_write_inode(inode, NULL);
-       mutex_unlock_op(sbi, NODE_NEW);
+       update_inode_page(inode);
+       mutex_unlock_op(sbi, ilock);
 
        return 0;
 cleanup:
        f2fs_put_page(page, 1);
-       mutex_unlock_op(sbi, NODE_NEW);
+exit:
+       mutex_unlock_op(sbi, ilock);
        return error;
 }
index f9a12f6..df6fab8 100644 (file)
@@ -139,7 +139,7 @@ struct f2fs_extent {
        __le32 len;             /* lengh of the extent */
 } __packed;
 
-#define F2FS_MAX_NAME_LEN      256
+#define F2FS_NAME_LEN          255
 #define ADDRS_PER_INODE         923    /* Address Pointers in an Inode */
 #define ADDRS_PER_BLOCK         1018   /* Address Pointers in a Direct Block */
 #define NIDS_PER_BLOCK          1018   /* Node IDs in an Indirect Block */
@@ -165,7 +165,8 @@ struct f2fs_inode {
        __le32 i_flags;                 /* file attributes */
        __le32 i_pino;                  /* parent inode number */
        __le32 i_namelen;               /* file name length */
-       __u8 i_name[F2FS_MAX_NAME_LEN]; /* file name for SPOR */
+       __u8 i_name[F2FS_NAME_LEN];     /* file name for SPOR */
+       __u8 i_reserved2;               /* for backward compatibility */
 
        struct f2fs_extent i_ext;       /* caching a largest extent */
 
@@ -362,10 +363,10 @@ struct f2fs_summary_block {
 typedef __le32 f2fs_hash_t;
 
 /* One directory entry slot covers 8bytes-long file name */
-#define F2FS_NAME_LEN          8
-#define F2FS_NAME_LEN_BITS     3
+#define F2FS_SLOT_LEN          8
+#define F2FS_SLOT_LEN_BITS     3
 
-#define GET_DENTRY_SLOTS(x)    ((x + F2FS_NAME_LEN - 1) >> F2FS_NAME_LEN_BITS)
+#define GET_DENTRY_SLOTS(x)    ((x + F2FS_SLOT_LEN - 1) >> F2FS_SLOT_LEN_BITS)
 
 /* the number of dentry in a block */
 #define NR_DENTRY_IN_BLOCK     214
@@ -377,10 +378,10 @@ typedef __le32    f2fs_hash_t;
 #define SIZE_OF_DENTRY_BITMAP  ((NR_DENTRY_IN_BLOCK + BITS_PER_BYTE - 1) / \
                                        BITS_PER_BYTE)
 #define SIZE_OF_RESERVED       (PAGE_SIZE - ((SIZE_OF_DIR_ENTRY + \
-                               F2FS_NAME_LEN) * \
+                               F2FS_SLOT_LEN) * \
                                NR_DENTRY_IN_BLOCK + SIZE_OF_DENTRY_BITMAP))
 
-/* One directory entry slot representing F2FS_NAME_LEN-sized file name */
+/* One directory entry slot representing F2FS_SLOT_LEN-sized file name */
 struct f2fs_dir_entry {
        __le32 hash_code;       /* hash code of file name */
        __le32 ino;             /* inode number */
@@ -394,7 +395,7 @@ struct f2fs_dentry_block {
        __u8 dentry_bitmap[SIZE_OF_DENTRY_BITMAP];
        __u8 reserved[SIZE_OF_RESERVED];
        struct f2fs_dir_entry dentry[NR_DENTRY_IN_BLOCK];
-       __u8 filename[NR_DENTRY_IN_BLOCK][F2FS_NAME_LEN];
+       __u8 filename[NR_DENTRY_IN_BLOCK][F2FS_SLOT_LEN];
 } __packed;
 
 /* file types used in inode_info->flags */
diff --git a/include/trace/events/f2fs.h b/include/trace/events/f2fs.h
new file mode 100644 (file)
index 0000000..52ae548
--- /dev/null
@@ -0,0 +1,682 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM f2fs
+
+#if !defined(_TRACE_F2FS_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_F2FS_H
+
+#include <linux/tracepoint.h>
+
+#define show_dev(entry)                MAJOR(entry->dev), MINOR(entry->dev)
+#define show_dev_ino(entry)    show_dev(entry), (unsigned long)entry->ino
+
+#define show_block_type(type)                                          \
+       __print_symbolic(type,                                          \
+               { NODE,         "NODE" },                               \
+               { DATA,         "DATA" },                               \
+               { META,         "META" },                               \
+               { META_FLUSH,   "META_FLUSH" })
+
+#define show_bio_type(type)                                            \
+       __print_symbolic(type,                                          \
+               { READ,         "READ" },                               \
+               { READA,        "READAHEAD" },                          \
+               { READ_SYNC,    "READ_SYNC" },                          \
+               { WRITE,        "WRITE" },                              \
+               { WRITE_SYNC,   "WRITE_SYNC" },                         \
+               { WRITE_FLUSH,  "WRITE_FLUSH" },                        \
+               { WRITE_FUA,    "WRITE_FUA" })
+
+#define show_data_type(type)                                           \
+       __print_symbolic(type,                                          \
+               { CURSEG_HOT_DATA,      "Hot DATA" },                   \
+               { CURSEG_WARM_DATA,     "Warm DATA" },                  \
+               { CURSEG_COLD_DATA,     "Cold DATA" },                  \
+               { CURSEG_HOT_NODE,      "Hot NODE" },                   \
+               { CURSEG_WARM_NODE,     "Warm NODE" },                  \
+               { CURSEG_COLD_NODE,     "Cold NODE" },                  \
+               { NO_CHECK_TYPE,        "No TYPE" })
+
+#define show_gc_type(type)                                             \
+       __print_symbolic(type,                                          \
+               { FG_GC,        "Foreground GC" },                      \
+               { BG_GC,        "Background GC" })
+
+#define show_alloc_mode(type)                                          \
+       __print_symbolic(type,                                          \
+               { LFS,  "LFS-mode" },                                   \
+               { SSR,  "SSR-mode" })
+
+#define show_victim_policy(type)                                       \
+       __print_symbolic(type,                                          \
+               { GC_GREEDY,    "Greedy" },                             \
+               { GC_CB,        "Cost-Benefit" })
+
+struct victim_sel_policy;
+
+DECLARE_EVENT_CLASS(f2fs__inode,
+
+       TP_PROTO(struct inode *inode),
+
+       TP_ARGS(inode),
+
+       TP_STRUCT__entry(
+               __field(dev_t,  dev)
+               __field(ino_t,  ino)
+               __field(ino_t,  pino)
+               __field(umode_t, mode)
+               __field(loff_t, size)
+               __field(unsigned int, nlink)
+               __field(blkcnt_t, blocks)
+               __field(__u8,   advise)
+       ),
+
+       TP_fast_assign(
+               __entry->dev    = inode->i_sb->s_dev;
+               __entry->ino    = inode->i_ino;
+               __entry->pino   = F2FS_I(inode)->i_pino;
+               __entry->mode   = inode->i_mode;
+               __entry->nlink  = inode->i_nlink;
+               __entry->size   = inode->i_size;
+               __entry->blocks = inode->i_blocks;
+               __entry->advise = F2FS_I(inode)->i_advise;
+       ),
+
+       TP_printk("dev = (%d,%d), ino = %lu, pino = %lu, i_mode = 0x%hx, "
+               "i_size = %lld, i_nlink = %u, i_blocks = %llu, i_advise = 0x%x",
+               show_dev_ino(__entry),
+               (unsigned long)__entry->pino,
+               __entry->mode,
+               __entry->size,
+               (unsigned int)__entry->nlink,
+               (unsigned long long)__entry->blocks,
+               (unsigned char)__entry->advise)
+);
+
+DECLARE_EVENT_CLASS(f2fs__inode_exit,
+
+       TP_PROTO(struct inode *inode, int ret),
+
+       TP_ARGS(inode, ret),
+
+       TP_STRUCT__entry(
+               __field(dev_t,  dev)
+               __field(ino_t,  ino)
+               __field(int,    ret)
+       ),
+
+       TP_fast_assign(
+               __entry->dev    = inode->i_sb->s_dev;
+               __entry->ino    = inode->i_ino;
+               __entry->ret    = ret;
+       ),
+
+       TP_printk("dev = (%d,%d), ino = %lu, ret = %d",
+               show_dev_ino(__entry),
+               __entry->ret)
+);
+
+DEFINE_EVENT(f2fs__inode, f2fs_sync_file_enter,
+
+       TP_PROTO(struct inode *inode),
+
+       TP_ARGS(inode)
+);
+
+TRACE_EVENT(f2fs_sync_file_exit,
+
+       TP_PROTO(struct inode *inode, bool need_cp, int datasync, int ret),
+
+       TP_ARGS(inode, need_cp, datasync, ret),
+
+       TP_STRUCT__entry(
+               __field(dev_t,  dev)
+               __field(ino_t,  ino)
+               __field(bool,   need_cp)
+               __field(int,    datasync)
+               __field(int,    ret)
+       ),
+
+       TP_fast_assign(
+               __entry->dev            = inode->i_sb->s_dev;
+               __entry->ino            = inode->i_ino;
+               __entry->need_cp        = need_cp;
+               __entry->datasync       = datasync;
+               __entry->ret            = ret;
+       ),
+
+       TP_printk("dev = (%d,%d), ino = %lu, checkpoint is %s, "
+               "datasync = %d, ret = %d",
+               show_dev_ino(__entry),
+               __entry->need_cp ? "needed" : "not needed",
+               __entry->datasync,
+               __entry->ret)
+);
+
+TRACE_EVENT(f2fs_sync_fs,
+
+       TP_PROTO(struct super_block *sb, int wait),
+
+       TP_ARGS(sb, wait),
+
+       TP_STRUCT__entry(
+               __field(dev_t,  dev)
+               __field(int,    dirty)
+               __field(int,    wait)
+       ),
+
+       TP_fast_assign(
+               __entry->dev    = sb->s_dev;
+               __entry->dirty  = F2FS_SB(sb)->s_dirty;
+               __entry->wait   = wait;
+       ),
+
+       TP_printk("dev = (%d,%d), superblock is %s, wait = %d",
+               show_dev(__entry),
+               __entry->dirty ? "dirty" : "not dirty",
+               __entry->wait)
+);
+
+DEFINE_EVENT(f2fs__inode, f2fs_iget,
+
+       TP_PROTO(struct inode *inode),
+
+       TP_ARGS(inode)
+);
+
+DEFINE_EVENT(f2fs__inode_exit, f2fs_iget_exit,
+
+       TP_PROTO(struct inode *inode, int ret),
+
+       TP_ARGS(inode, ret)
+);
+
+DEFINE_EVENT(f2fs__inode, f2fs_evict_inode,
+
+       TP_PROTO(struct inode *inode),
+
+       TP_ARGS(inode)
+);
+
+DEFINE_EVENT(f2fs__inode_exit, f2fs_new_inode,
+
+       TP_PROTO(struct inode *inode, int ret),
+
+       TP_ARGS(inode, ret)
+);
+
+TRACE_EVENT(f2fs_unlink_enter,
+
+       TP_PROTO(struct inode *dir, struct dentry *dentry),
+
+       TP_ARGS(dir, dentry),
+
+       TP_STRUCT__entry(
+               __field(dev_t,  dev)
+               __field(ino_t,  ino)
+               __field(loff_t, size)
+               __field(blkcnt_t, blocks)
+               __field(const char *,   name)
+       ),
+
+       TP_fast_assign(
+               __entry->dev    = dir->i_sb->s_dev;
+               __entry->ino    = dir->i_ino;
+               __entry->size   = dir->i_size;
+               __entry->blocks = dir->i_blocks;
+               __entry->name   = dentry->d_name.name;
+       ),
+
+       TP_printk("dev = (%d,%d), dir ino = %lu, i_size = %lld, "
+               "i_blocks = %llu, name = %s",
+               show_dev_ino(__entry),
+               __entry->size,
+               (unsigned long long)__entry->blocks,
+               __entry->name)
+);
+
+DEFINE_EVENT(f2fs__inode_exit, f2fs_unlink_exit,
+
+       TP_PROTO(struct inode *inode, int ret),
+
+       TP_ARGS(inode, ret)
+);
+
+DEFINE_EVENT(f2fs__inode, f2fs_truncate,
+
+       TP_PROTO(struct inode *inode),
+
+       TP_ARGS(inode)
+);
+
+TRACE_EVENT(f2fs_truncate_data_blocks_range,
+
+       TP_PROTO(struct inode *inode, nid_t nid, unsigned int ofs, int free),
+
+       TP_ARGS(inode, nid,  ofs, free),
+
+       TP_STRUCT__entry(
+               __field(dev_t,  dev)
+               __field(ino_t,  ino)
+               __field(nid_t,  nid)
+               __field(unsigned int,   ofs)
+               __field(int,    free)
+       ),
+
+       TP_fast_assign(
+               __entry->dev    = inode->i_sb->s_dev;
+               __entry->ino    = inode->i_ino;
+               __entry->nid    = nid;
+               __entry->ofs    = ofs;
+               __entry->free   = free;
+       ),
+
+       TP_printk("dev = (%d,%d), ino = %lu, nid = %u, offset = %u, freed = %d",
+               show_dev_ino(__entry),
+               (unsigned int)__entry->nid,
+               __entry->ofs,
+               __entry->free)
+);
+
+DECLARE_EVENT_CLASS(f2fs__truncate_op,
+
+       TP_PROTO(struct inode *inode, u64 from),
+
+       TP_ARGS(inode, from),
+
+       TP_STRUCT__entry(
+               __field(dev_t,  dev)
+               __field(ino_t,  ino)
+               __field(loff_t, size)
+               __field(blkcnt_t, blocks)
+               __field(u64,    from)
+       ),
+
+       TP_fast_assign(
+               __entry->dev    = inode->i_sb->s_dev;
+               __entry->ino    = inode->i_ino;
+               __entry->size   = inode->i_size;
+               __entry->blocks = inode->i_blocks;
+               __entry->from   = from;
+       ),
+
+       TP_printk("dev = (%d,%d), ino = %lu, i_size = %lld, i_blocks = %llu, "
+               "start file offset = %llu",
+               show_dev_ino(__entry),
+               __entry->size,
+               (unsigned long long)__entry->blocks,
+               (unsigned long long)__entry->from)
+);
+
+DEFINE_EVENT(f2fs__truncate_op, f2fs_truncate_blocks_enter,
+
+       TP_PROTO(struct inode *inode, u64 from),
+
+       TP_ARGS(inode, from)
+);
+
+DEFINE_EVENT(f2fs__inode_exit, f2fs_truncate_blocks_exit,
+
+       TP_PROTO(struct inode *inode, int ret),
+
+       TP_ARGS(inode, ret)
+);
+
+DEFINE_EVENT(f2fs__truncate_op, f2fs_truncate_inode_blocks_enter,
+
+       TP_PROTO(struct inode *inode, u64 from),
+
+       TP_ARGS(inode, from)
+);
+
+DEFINE_EVENT(f2fs__inode_exit, f2fs_truncate_inode_blocks_exit,
+
+       TP_PROTO(struct inode *inode, int ret),
+
+       TP_ARGS(inode, ret)
+);
+
+DECLARE_EVENT_CLASS(f2fs__truncate_node,
+
+       TP_PROTO(struct inode *inode, nid_t nid, block_t blk_addr),
+
+       TP_ARGS(inode, nid, blk_addr),
+
+       TP_STRUCT__entry(
+               __field(dev_t,  dev)
+               __field(ino_t,  ino)
+               __field(nid_t,  nid)
+               __field(block_t,        blk_addr)
+       ),
+
+       TP_fast_assign(
+               __entry->dev            = inode->i_sb->s_dev;
+               __entry->ino            = inode->i_ino;
+               __entry->nid            = nid;
+               __entry->blk_addr       = blk_addr;
+       ),
+
+       TP_printk("dev = (%d,%d), ino = %lu, nid = %u, block_address = 0x%llx",
+               show_dev_ino(__entry),
+               (unsigned int)__entry->nid,
+               (unsigned long long)__entry->blk_addr)
+);
+
+DEFINE_EVENT(f2fs__truncate_node, f2fs_truncate_nodes_enter,
+
+       TP_PROTO(struct inode *inode, nid_t nid, block_t blk_addr),
+
+       TP_ARGS(inode, nid, blk_addr)
+);
+
+DEFINE_EVENT(f2fs__inode_exit, f2fs_truncate_nodes_exit,
+
+       TP_PROTO(struct inode *inode, int ret),
+
+       TP_ARGS(inode, ret)
+);
+
+DEFINE_EVENT(f2fs__truncate_node, f2fs_truncate_node,
+
+       TP_PROTO(struct inode *inode, nid_t nid, block_t blk_addr),
+
+       TP_ARGS(inode, nid, blk_addr)
+);
+
+TRACE_EVENT(f2fs_truncate_partial_nodes,
+
+       TP_PROTO(struct inode *inode, nid_t nid[], int depth, int err),
+
+       TP_ARGS(inode, nid, depth, err),
+
+       TP_STRUCT__entry(
+               __field(dev_t,  dev)
+               __field(ino_t,  ino)
+               __field(nid_t,  nid[3])
+               __field(int,    depth)
+               __field(int,    err)
+       ),
+
+       TP_fast_assign(
+               __entry->dev    = inode->i_sb->s_dev;
+               __entry->ino    = inode->i_ino;
+               __entry->nid[0] = nid[0];
+               __entry->nid[1] = nid[1];
+               __entry->nid[2] = nid[2];
+               __entry->depth  = depth;
+               __entry->err    = err;
+       ),
+
+       TP_printk("dev = (%d,%d), ino = %lu, "
+               "nid[0] = %u, nid[1] = %u, nid[2] = %u, depth = %d, err = %d",
+               show_dev_ino(__entry),
+               (unsigned int)__entry->nid[0],
+               (unsigned int)__entry->nid[1],
+               (unsigned int)__entry->nid[2],
+               __entry->depth,
+               __entry->err)
+);
+
+TRACE_EVENT_CONDITION(f2fs_readpage,
+
+       TP_PROTO(struct page *page, sector_t blkaddr, int type),
+
+       TP_ARGS(page, blkaddr, type),
+
+       TP_CONDITION(page->mapping),
+
+       TP_STRUCT__entry(
+               __field(dev_t,  dev)
+               __field(ino_t,  ino)
+               __field(pgoff_t,        index)
+               __field(sector_t,       blkaddr)
+               __field(int,    type)
+       ),
+
+       TP_fast_assign(
+               __entry->dev            = page->mapping->host->i_sb->s_dev;
+               __entry->ino            = page->mapping->host->i_ino;
+               __entry->index          = page->index;
+               __entry->blkaddr        = blkaddr;
+               __entry->type           = type;
+       ),
+
+       TP_printk("dev = (%d,%d), ino = %lu, page_index = 0x%lx, "
+               "blkaddr = 0x%llx, bio_type = %s",
+               show_dev_ino(__entry),
+               (unsigned long)__entry->index,
+               (unsigned long long)__entry->blkaddr,
+               show_bio_type(__entry->type))
+);
+
+TRACE_EVENT(f2fs_get_data_block,
+       TP_PROTO(struct inode *inode, sector_t iblock,
+                               struct buffer_head *bh, int ret),
+
+       TP_ARGS(inode, iblock, bh, ret),
+
+       TP_STRUCT__entry(
+               __field(dev_t,  dev)
+               __field(ino_t,  ino)
+               __field(sector_t,       iblock)
+               __field(sector_t,       bh_start)
+               __field(size_t, bh_size)
+               __field(int,    ret)
+       ),
+
+       TP_fast_assign(
+               __entry->dev            = inode->i_sb->s_dev;
+               __entry->ino            = inode->i_ino;
+               __entry->iblock         = iblock;
+               __entry->bh_start       = bh->b_blocknr;
+               __entry->bh_size        = bh->b_size;
+               __entry->ret            = ret;
+       ),
+
+       TP_printk("dev = (%d,%d), ino = %lu, file offset = %llu, "
+               "start blkaddr = 0x%llx, len = 0x%llx bytes, err = %d",
+               show_dev_ino(__entry),
+               (unsigned long long)__entry->iblock,
+               (unsigned long long)__entry->bh_start,
+               (unsigned long long)__entry->bh_size,
+               __entry->ret)
+);
+
+TRACE_EVENT(f2fs_get_victim,
+
+       TP_PROTO(struct super_block *sb, int type, int gc_type,
+                       struct victim_sel_policy *p, unsigned int pre_victim,
+                       unsigned int prefree, unsigned int free),
+
+       TP_ARGS(sb, type, gc_type, p, pre_victim, prefree, free),
+
+       TP_STRUCT__entry(
+               __field(dev_t,  dev)
+               __field(int,    type)
+               __field(int,    gc_type)
+               __field(int,    alloc_mode)
+               __field(int,    gc_mode)
+               __field(unsigned int,   victim)
+               __field(unsigned int,   ofs_unit)
+               __field(unsigned int,   pre_victim)
+               __field(unsigned int,   prefree)
+               __field(unsigned int,   free)
+       ),
+
+       TP_fast_assign(
+               __entry->dev            = sb->s_dev;
+               __entry->type           = type;
+               __entry->gc_type        = gc_type;
+               __entry->alloc_mode     = p->alloc_mode;
+               __entry->gc_mode        = p->gc_mode;
+               __entry->victim         = p->min_segno;
+               __entry->ofs_unit       = p->ofs_unit;
+               __entry->pre_victim     = pre_victim;
+               __entry->prefree        = prefree;
+               __entry->free           = free;
+       ),
+
+       TP_printk("dev = (%d,%d), type = %s, policy = (%s, %s, %s), victim = %u "
+               "ofs_unit = %u, pre_victim_secno = %d, prefree = %u, free = %u",
+               show_dev(__entry),
+               show_data_type(__entry->type),
+               show_gc_type(__entry->gc_type),
+               show_alloc_mode(__entry->alloc_mode),
+               show_victim_policy(__entry->gc_mode),
+               __entry->victim,
+               __entry->ofs_unit,
+               (int)__entry->pre_victim,
+               __entry->prefree,
+               __entry->free)
+);
+
+TRACE_EVENT(f2fs_fallocate,
+
+       TP_PROTO(struct inode *inode, int mode,
+                               loff_t offset, loff_t len, int ret),
+
+       TP_ARGS(inode, mode, offset, len, ret),
+
+       TP_STRUCT__entry(
+               __field(dev_t,  dev)
+               __field(ino_t,  ino)
+               __field(int,    mode)
+               __field(loff_t, offset)
+               __field(loff_t, len)
+               __field(loff_t, size)
+               __field(blkcnt_t, blocks)
+               __field(int,    ret)
+       ),
+
+       TP_fast_assign(
+               __entry->dev    = inode->i_sb->s_dev;
+               __entry->ino    = inode->i_ino;
+               __entry->mode   = mode;
+               __entry->offset = offset;
+               __entry->len    = len;
+               __entry->size   = inode->i_size;
+               __entry->blocks = inode->i_blocks;
+               __entry->ret    = ret;
+       ),
+
+       TP_printk("dev = (%d,%d), ino = %lu, mode = %x, offset = %lld, "
+               "len = %lld,  i_size = %lld, i_blocks = %llu, ret = %d",
+               show_dev_ino(__entry),
+               __entry->mode,
+               (unsigned long long)__entry->offset,
+               (unsigned long long)__entry->len,
+               (unsigned long long)__entry->size,
+               (unsigned long long)__entry->blocks,
+               __entry->ret)
+);
+
+TRACE_EVENT(f2fs_reserve_new_block,
+
+       TP_PROTO(struct inode *inode, nid_t nid, unsigned int ofs_in_node),
+
+       TP_ARGS(inode, nid, ofs_in_node),
+
+       TP_STRUCT__entry(
+               __field(dev_t,  dev)
+               __field(nid_t, nid)
+               __field(unsigned int, ofs_in_node)
+       ),
+
+       TP_fast_assign(
+               __entry->dev    = inode->i_sb->s_dev;
+               __entry->nid    = nid;
+               __entry->ofs_in_node = ofs_in_node;
+       ),
+
+       TP_printk("dev = (%d,%d), nid = %u, ofs_in_node = %u",
+               show_dev(__entry),
+               (unsigned int)__entry->nid,
+               __entry->ofs_in_node)
+);
+
+TRACE_EVENT(f2fs_do_submit_bio,
+
+       TP_PROTO(struct super_block *sb, int btype, bool sync, struct bio *bio),
+
+       TP_ARGS(sb, btype, sync, bio),
+
+       TP_STRUCT__entry(
+               __field(dev_t,  dev)
+               __field(int,    btype)
+               __field(bool,   sync)
+               __field(sector_t,       sector)
+               __field(unsigned int,   size)
+       ),
+
+       TP_fast_assign(
+               __entry->dev            = sb->s_dev;
+               __entry->btype          = btype;
+               __entry->sync           = sync;
+               __entry->sector         = bio->bi_sector;
+               __entry->size           = bio->bi_size;
+       ),
+
+       TP_printk("dev = (%d,%d), type = %s, io = %s, sector = %lld, size = %u",
+               show_dev(__entry),
+               show_block_type(__entry->btype),
+               __entry->sync ? "sync" : "no sync",
+               (unsigned long long)__entry->sector,
+               __entry->size)
+);
+
+TRACE_EVENT(f2fs_submit_write_page,
+
+       TP_PROTO(struct page *page, block_t blk_addr, int type),
+
+       TP_ARGS(page, blk_addr, type),
+
+       TP_STRUCT__entry(
+               __field(dev_t,  dev)
+               __field(ino_t,  ino)
+               __field(int, type)
+               __field(pgoff_t, index)
+               __field(block_t, block)
+       ),
+
+       TP_fast_assign(
+               __entry->dev    = page->mapping->host->i_sb->s_dev;
+               __entry->ino    = page->mapping->host->i_ino;
+               __entry->type   = type;
+               __entry->index  = page->index;
+               __entry->block  = blk_addr;
+       ),
+
+       TP_printk("dev = (%d,%d), ino = %lu, %s, index = %lu, blkaddr = 0x%llx",
+               show_dev_ino(__entry),
+               show_block_type(__entry->type),
+               (unsigned long)__entry->index,
+               (unsigned long long)__entry->block)
+);
+
+TRACE_EVENT(f2fs_write_checkpoint,
+
+       TP_PROTO(struct super_block *sb, bool is_umount, char *msg),
+
+       TP_ARGS(sb, is_umount, msg),
+
+       TP_STRUCT__entry(
+               __field(dev_t,  dev)
+               __field(bool,   is_umount)
+               __field(char *, msg)
+       ),
+
+       TP_fast_assign(
+               __entry->dev            = sb->s_dev;
+               __entry->is_umount      = is_umount;
+               __entry->msg            = msg;
+       ),
+
+       TP_printk("dev = (%d,%d), checkpoint for %s, state = %s",
+               show_dev(__entry),
+               __entry->is_umount ? "clean umount" : "consistency",
+               __entry->msg)
+);
+
+#endif /* _TRACE_F2FS_H */
+
+ /* This part must be outside protection */
+#include <trace/define_trace.h>