f2fs: record dirty status of regular/symlink inode
authorChao Yu <chao2.yu@samsung.com>
Wed, 16 Dec 2015 05:09:20 +0000 (13:09 +0800)
committerJaegeuk Kim <jaegeuk@kernel.org>
Wed, 16 Dec 2015 16:58:12 +0000 (08:58 -0800)
Maintain regular/symlink inode which has dirty pages in global dirty list
and record their total dirty pages count like the way of handling directory
inode.

Signed-off-by: Chao Yu <chao2.yu@samsung.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
fs/f2fs/checkpoint.c
fs/f2fs/data.c
fs/f2fs/dir.c
fs/f2fs/f2fs.h
fs/f2fs/inode.c
fs/f2fs/super.c

index 5008b872f3165c76b99519ca739c811a544844d2..a037bbd89dc64feb7dba48bdaa57f033aea5b449 100644 (file)
@@ -722,53 +722,51 @@ fail_no_cp:
        return -EINVAL;
 }
 
-static void __add_dirty_inode(struct inode *inode)
+static void __add_dirty_inode(struct inode *inode, enum inode_type type)
 {
        struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
        struct f2fs_inode_info *fi = F2FS_I(inode);
+       int flag = (type == DIR_INODE) ? FI_DIRTY_DIR : FI_DIRTY_FILE;
 
-       if (is_inode_flag_set(fi, FI_DIRTY_DIR))
+       if (is_inode_flag_set(fi, flag))
                return;
 
-       set_inode_flag(fi, FI_DIRTY_DIR);
-       list_add_tail(&fi->dirty_list, &sbi->dir_inode_list);
-       stat_inc_dirty_dir(sbi);
-       return;
+       set_inode_flag(fi, flag);
+       list_add_tail(&fi->dirty_list, &sbi->inode_list[type]);
+       if (type == DIR_INODE)
+               stat_inc_dirty_dir(sbi);
 }
 
-static void __remove_dirty_inode(struct inode *inode)
+static void __remove_dirty_inode(struct inode *inode, enum inode_type type)
 {
        struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
        struct f2fs_inode_info *fi = F2FS_I(inode);
+       int flag = (type == DIR_INODE) ? FI_DIRTY_DIR : FI_DIRTY_FILE;
 
        if (get_dirty_pages(inode) ||
-                       !is_inode_flag_set(F2FS_I(inode), FI_DIRTY_DIR))
+                       !is_inode_flag_set(F2FS_I(inode), flag))
                return;
 
        list_del_init(&fi->dirty_list);
-       clear_inode_flag(fi, FI_DIRTY_DIR);
-       stat_dec_dirty_dir(sbi);
+       clear_inode_flag(fi, flag);
+       if (type == DIR_INODE)
+               stat_dec_dirty_dir(sbi);
 }
 
 void update_dirty_page(struct inode *inode, struct page *page)
 {
        struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+       enum inode_type type = S_ISDIR(inode->i_mode) ? DIR_INODE : FILE_INODE;
 
        if (!S_ISDIR(inode->i_mode) && !S_ISREG(inode->i_mode) &&
                        !S_ISLNK(inode->i_mode))
                return;
 
-       if (!S_ISDIR(inode->i_mode)) {
-               inode_inc_dirty_pages(inode);
-               goto out;
-       }
-
-       spin_lock(&sbi->dir_inode_lock);
-       __add_dirty_inode(inode);
+       spin_lock(&sbi->inode_lock[type]);
+       __add_dirty_inode(inode, type);
        inode_inc_dirty_pages(inode);
-       spin_unlock(&sbi->dir_inode_lock);
+       spin_unlock(&sbi->inode_lock[type]);
 
-out:
        SetPagePrivate(page);
        f2fs_trace_pid(page);
 }
@@ -777,22 +775,24 @@ void add_dirty_dir_inode(struct inode *inode)
 {
        struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
 
-       spin_lock(&sbi->dir_inode_lock);
-       __add_dirty_inode(inode);
-       spin_unlock(&sbi->dir_inode_lock);
+       spin_lock(&sbi->inode_lock[DIR_INODE]);
+       __add_dirty_inode(inode, DIR_INODE);
+       spin_unlock(&sbi->inode_lock[DIR_INODE]);
 }
 
-void remove_dirty_dir_inode(struct inode *inode)
+void remove_dirty_inode(struct inode *inode)
 {
        struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
        struct f2fs_inode_info *fi = F2FS_I(inode);
+       enum inode_type type = S_ISDIR(inode->i_mode) ? DIR_INODE : FILE_INODE;
 
-       if (!S_ISDIR(inode->i_mode))
+       if (!S_ISDIR(inode->i_mode) && !S_ISREG(inode->i_mode) &&
+                       !S_ISLNK(inode->i_mode))
                return;
 
-       spin_lock(&sbi->dir_inode_lock);
-       __remove_dirty_inode(inode);
-       spin_unlock(&sbi->dir_inode_lock);
+       spin_lock(&sbi->inode_lock[type]);
+       __remove_dirty_inode(inode, type);
+       spin_unlock(&sbi->inode_lock[type]);
 
        /* Only from the recovery routine */
        if (is_inode_flag_set(fi, FI_DELAY_IPUT)) {
@@ -801,7 +801,7 @@ void remove_dirty_dir_inode(struct inode *inode)
        }
 }
 
-void sync_dirty_dir_inodes(struct f2fs_sb_info *sbi)
+void sync_dirty_inodes(struct f2fs_sb_info *sbi, enum inode_type type)
 {
        struct list_head *head;
        struct inode *inode;
@@ -810,16 +810,16 @@ retry:
        if (unlikely(f2fs_cp_error(sbi)))
                return;
 
-       spin_lock(&sbi->dir_inode_lock);
+       spin_lock(&sbi->inode_lock[type]);
 
-       head = &sbi->dir_inode_list;
+       head = &sbi->inode_list[type];
        if (list_empty(head)) {
-               spin_unlock(&sbi->dir_inode_lock);
+               spin_unlock(&sbi->inode_lock[type]);
                return;
        }
        fi = list_entry(head->next, struct f2fs_inode_info, dirty_list);
        inode = igrab(&fi->vfs_inode);
-       spin_unlock(&sbi->dir_inode_lock);
+       spin_unlock(&sbi->inode_lock[type]);
        if (inode) {
                filemap_fdatawrite(inode->i_mapping);
                iput(inode);
@@ -854,7 +854,7 @@ retry_flush_dents:
        /* write all the dirty dentry pages */
        if (get_pages(sbi, F2FS_DIRTY_DENTS)) {
                f2fs_unlock_all(sbi);
-               sync_dirty_dir_inodes(sbi);
+               sync_dirty_inodes(sbi, DIR_INODE);
                if (unlikely(f2fs_cp_error(sbi))) {
                        err = -EIO;
                        goto out;
index 90a2ffea875bfb703ac6c561a58e11658d0d0410..292a06cbea072a7504774e5e354c90347043cfbd 100644 (file)
@@ -1180,7 +1180,7 @@ out:
                f2fs_balance_fs(sbi);
        if (wbc->for_reclaim) {
                f2fs_submit_merged_bio(sbi, DATA, WRITE);
-               remove_dirty_dir_inode(inode);
+               remove_dirty_inode(inode);
        }
        return 0;
 
@@ -1372,7 +1372,7 @@ static int f2fs_write_data_pages(struct address_space *mapping,
        if (locked)
                mutex_unlock(&sbi->writepages);
 
-       remove_dirty_dir_inode(inode);
+       remove_dirty_inode(inode);
 
        wbc->nr_to_write = max((long)0, wbc->nr_to_write - diff);
        return ret;
index 6554fd5fce88f851f7b072311e07adf80153d0e3..3da58265c0d404fcc16484d6b8c6770d2b831c36 100644 (file)
@@ -444,7 +444,7 @@ error:
        /* once the failed inode becomes a bad inode, i_mode is S_IFREG */
        truncate_inode_pages(&inode->i_data, 0);
        truncate_blocks(inode, 0, false);
-       remove_dirty_dir_inode(inode);
+       remove_dirty_inode(inode);
        remove_inode_page(inode);
        return ERR_PTR(err);
 }
index 37cf04b3ff37902d12b8960ce44ba460e66e09ce..03a2b86a28ba4501f45b732edce1d65cfab1722d 100644 (file)
@@ -648,6 +648,7 @@ struct f2fs_sm_info {
 enum count_type {
        F2FS_WRITEBACK,
        F2FS_DIRTY_DENTS,
+       F2FS_DIRTY_DATA,
        F2FS_DIRTY_NODES,
        F2FS_DIRTY_META,
        F2FS_INMEM_PAGES,
@@ -696,6 +697,12 @@ struct f2fs_bio_info {
        struct rw_semaphore io_rwsem;   /* blocking op for bio */
 };
 
+enum inode_type {
+       DIR_INODE,                      /* for dirty dir inode */
+       FILE_INODE,                     /* for dirty regular/symlink inode */
+       NR_INODE_TYPE,
+};
+
 /* for inner inode cache management */
 struct inode_management {
        struct radix_tree_root ino_root;        /* ino entry array */
@@ -745,9 +752,9 @@ struct f2fs_sb_info {
        /* for orphan inode, use 0'th array */
        unsigned int max_orphans;               /* max orphan inodes */
 
-       /* for directory inode management */
-       struct list_head dir_inode_list;        /* dir inode list */
-       spinlock_t dir_inode_lock;              /* for dir inode list lock */
+       /* for inode management */
+       struct list_head inode_list[NR_INODE_TYPE];     /* dirty inode list */
+       spinlock_t inode_lock[NR_INODE_TYPE];   /* for dirty inode list lock */
 
        /* for extent tree cache */
        struct radix_tree_root extent_tree_root;/* cache extent cache entries */
@@ -1060,8 +1067,8 @@ static inline void inc_page_count(struct f2fs_sb_info *sbi, int count_type)
 static inline void inode_inc_dirty_pages(struct inode *inode)
 {
        atomic_inc(&F2FS_I(inode)->dirty_pages);
-       if (S_ISDIR(inode->i_mode))
-               inc_page_count(F2FS_I_SB(inode), F2FS_DIRTY_DENTS);
+       inc_page_count(F2FS_I_SB(inode), S_ISDIR(inode->i_mode) ?
+                               F2FS_DIRTY_DENTS : F2FS_DIRTY_DATA);
 }
 
 static inline void dec_page_count(struct f2fs_sb_info *sbi, int count_type)
@@ -1076,9 +1083,8 @@ static inline void inode_dec_dirty_pages(struct inode *inode)
                return;
 
        atomic_dec(&F2FS_I(inode)->dirty_pages);
-
-       if (S_ISDIR(inode->i_mode))
-               dec_page_count(F2FS_I_SB(inode), F2FS_DIRTY_DENTS);
+       dec_page_count(F2FS_I_SB(inode), S_ISDIR(inode->i_mode) ?
+                               F2FS_DIRTY_DENTS : F2FS_DIRTY_DATA);
 }
 
 static inline int get_pages(struct f2fs_sb_info *sbi, int count_type)
@@ -1417,6 +1423,7 @@ enum {
        FI_DATA_EXIST,          /* indicate data exists */
        FI_INLINE_DOTS,         /* indicate inline dot dentries */
        FI_DO_DEFRAG,           /* indicate defragment is running */
+       FI_DIRTY_FILE,          /* indicate regular/symlink has dirty pages */
 };
 
 static inline void set_inode_flag(struct f2fs_inode_info *fi, int flag)
@@ -1826,8 +1833,8 @@ int recover_orphan_inodes(struct f2fs_sb_info *);
 int get_valid_checkpoint(struct f2fs_sb_info *);
 void update_dirty_page(struct inode *, struct page *);
 void add_dirty_dir_inode(struct inode *);
-void remove_dirty_dir_inode(struct inode *);
-void sync_dirty_dir_inodes(struct f2fs_sb_info *);
+void remove_dirty_inode(struct inode *);
+void sync_dirty_inodes(struct f2fs_sb_info *, enum inode_type);
 void write_checkpoint(struct f2fs_sb_info *, struct cp_control *);
 void init_ino_entry_info(struct f2fs_sb_info *);
 int __init create_checkpoint_caches(void);
index 3d2fe595d07821fd4701c396e5947bfbd650d146..ec3fb32c472622dfb9085b15491dba34546be655 100644 (file)
@@ -327,7 +327,7 @@ void f2fs_evict_inode(struct inode *inode)
                goto out_clear;
 
        f2fs_bug_on(sbi, get_dirty_pages(inode));
-       remove_dirty_dir_inode(inode);
+       remove_dirty_inode(inode);
 
        f2fs_destroy_extent_tree(inode);
 
index bc1a8cd38bc8c61c9f57f09968483749bc389beb..5b596d6a8d24818ff6b9c223cbf2d02c80d3fd5f 100644 (file)
@@ -1339,8 +1339,10 @@ try_onemore:
                                le64_to_cpu(sbi->ckpt->valid_block_count);
        sbi->last_valid_block_count = sbi->total_valid_block_count;
        sbi->alloc_valid_block_count = 0;
-       INIT_LIST_HEAD(&sbi->dir_inode_list);
-       spin_lock_init(&sbi->dir_inode_lock);
+       for (i = 0; i < NR_INODE_TYPE; i++) {
+               INIT_LIST_HEAD(&sbi->inode_list[i]);
+               spin_lock_init(&sbi->inode_lock[i]);
+       }
 
        init_extent_cache_info(sbi);