f2fs: separate out iostat feature
[linux-2.6-microblaze.git] / fs / f2fs / checkpoint.c
index be5415a..3962cfe 100644 (file)
@@ -18,6 +18,7 @@
 #include "f2fs.h"
 #include "node.h"
 #include "segment.h"
+#include "iostat.h"
 #include <trace/events/f2fs.h>
 
 #define DEFAULT_CHECKPOINT_IOPRIO (IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 3))
@@ -444,7 +445,7 @@ static int f2fs_set_meta_page_dirty(struct page *page)
        if (!PageDirty(page)) {
                __set_page_dirty_nobuffers(page);
                inc_page_count(F2FS_P_SB(page), F2FS_DIRTY_META);
-               f2fs_set_page_private(page, 0);
+               set_page_private_reference(page);
                return 1;
        }
        return 0;
@@ -465,16 +466,29 @@ static void __add_ino_entry(struct f2fs_sb_info *sbi, nid_t ino,
                                                unsigned int devidx, int type)
 {
        struct inode_management *im = &sbi->im[type];
-       struct ino_entry *e, *tmp;
+       struct ino_entry *e = NULL, *new = NULL;
 
-       tmp = f2fs_kmem_cache_alloc(ino_entry_slab, GFP_NOFS);
+       if (type == FLUSH_INO) {
+               rcu_read_lock();
+               e = radix_tree_lookup(&im->ino_root, ino);
+               rcu_read_unlock();
+       }
+
+retry:
+       if (!e)
+               new = f2fs_kmem_cache_alloc(ino_entry_slab,
+                                               GFP_NOFS, true, NULL);
 
        radix_tree_preload(GFP_NOFS | __GFP_NOFAIL);
 
        spin_lock(&im->ino_lock);
        e = radix_tree_lookup(&im->ino_root, ino);
        if (!e) {
-               e = tmp;
+               if (!new) {
+                       spin_unlock(&im->ino_lock);
+                       goto retry;
+               }
+               e = new;
                if (unlikely(radix_tree_insert(&im->ino_root, ino, e)))
                        f2fs_bug_on(sbi, 1);
 
@@ -492,8 +506,8 @@ static void __add_ino_entry(struct f2fs_sb_info *sbi, nid_t ino,
        spin_unlock(&im->ino_lock);
        radix_tree_preload_end();
 
-       if (e != tmp)
-               kmem_cache_free(ino_entry_slab, tmp);
+       if (new && e != new)
+               kmem_cache_free(ino_entry_slab, new);
 }
 
 static void __remove_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type)
@@ -719,6 +733,7 @@ int f2fs_recover_orphan_inodes(struct f2fs_sb_info *sbi)
                orphan_blk = (struct f2fs_orphan_block *)page_address(page);
                for (j = 0; j < le32_to_cpu(orphan_blk->entry_count); j++) {
                        nid_t ino = le32_to_cpu(orphan_blk->ino[j]);
+
                        err = recover_orphan_inode(sbi, ino);
                        if (err) {
                                f2fs_put_page(page, 1);
@@ -1017,7 +1032,7 @@ void f2fs_update_dirty_page(struct inode *inode, struct page *page)
        inode_inc_dirty_pages(inode);
        spin_unlock(&sbi->inode_lock[type]);
 
-       f2fs_set_page_private(page, 0);
+       set_page_private_reference(page);
 }
 
 void f2fs_remove_dirty_inode(struct inode *inode)
@@ -1456,7 +1471,7 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
                        orphan_blocks);
 
        if (__remain_node_summaries(cpc->reason))
-               ckpt->cp_pack_total_block_count = cpu_to_le32(F2FS_CP_PACKS+
+               ckpt->cp_pack_total_block_count = cpu_to_le32(F2FS_CP_PACKS +
                                cp_payload_blks + data_sum_blocks +
                                orphan_blocks + NR_CURSEG_NODE_TYPE);
        else
@@ -1638,8 +1653,11 @@ int f2fs_write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
 
        /* write cached NAT/SIT entries to NAT/SIT area */
        err = f2fs_flush_nat_entries(sbi, cpc);
-       if (err)
+       if (err) {
+               f2fs_err(sbi, "f2fs_flush_nat_entries failed err:%d, stop checkpoint", err);
+               f2fs_bug_on(sbi, !f2fs_cp_error(sbi));
                goto stop;
+       }
 
        f2fs_flush_sit_entries(sbi, cpc);
 
@@ -1647,10 +1665,13 @@ int f2fs_write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
        f2fs_save_inmem_curseg(sbi);
 
        err = do_checkpoint(sbi, cpc);
-       if (err)
+       if (err) {
+               f2fs_err(sbi, "do_checkpoint failed err:%d, stop checkpoint", err);
+               f2fs_bug_on(sbi, !f2fs_cp_error(sbi));
                f2fs_release_discard_addrs(sbi);
-       else
+       } else {
                f2fs_clear_prefree_segments(sbi, cpc);
+       }
 
        f2fs_restore_inmem_curseg(sbi);
 stop:
@@ -1818,7 +1839,11 @@ int f2fs_issue_checkpoint(struct f2fs_sb_info *sbi)
        llist_add(&req.llnode, &cprc->issue_list);
        atomic_inc(&cprc->queued_ckpt);
 
-       /* update issue_list before we wake up issue_checkpoint thread */
+       /*
+        * update issue_list before we wake up issue_checkpoint thread,
+        * this smp_mb() pairs with another barrier in ___wait_event(),
+        * see more details in comments of waitqueue_active().
+        */
        smp_mb();
 
        if (waitqueue_active(&cprc->ckpt_wait_queue))