Commit c227f912 authored by Chao Yu's avatar Chao Yu Committed by Jaegeuk Kim

f2fs: record dirty status of regular/symlink inode

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: default avatarChao Yu <chao2.yu@samsung.com>
Signed-off-by: default avatarJaegeuk Kim <jaegeuk@kernel.org>
parent b3980910
...@@ -722,53 +722,51 @@ int get_valid_checkpoint(struct f2fs_sb_info *sbi) ...@@ -722,53 +722,51 @@ int get_valid_checkpoint(struct f2fs_sb_info *sbi)
return -EINVAL; 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_sb_info *sbi = F2FS_I_SB(inode);
struct f2fs_inode_info *fi = F2FS_I(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; return;
set_inode_flag(fi, FI_DIRTY_DIR); set_inode_flag(fi, flag);
list_add_tail(&fi->dirty_list, &sbi->dir_inode_list); list_add_tail(&fi->dirty_list, &sbi->inode_list[type]);
stat_inc_dirty_dir(sbi); if (type == DIR_INODE)
return; 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_sb_info *sbi = F2FS_I_SB(inode);
struct f2fs_inode_info *fi = F2FS_I(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) || if (get_dirty_pages(inode) ||
!is_inode_flag_set(F2FS_I(inode), FI_DIRTY_DIR)) !is_inode_flag_set(F2FS_I(inode), flag))
return; return;
list_del_init(&fi->dirty_list); list_del_init(&fi->dirty_list);
clear_inode_flag(fi, FI_DIRTY_DIR); clear_inode_flag(fi, flag);
stat_dec_dirty_dir(sbi); if (type == DIR_INODE)
stat_dec_dirty_dir(sbi);
} }
void update_dirty_page(struct inode *inode, struct page *page) void update_dirty_page(struct inode *inode, struct page *page)
{ {
struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 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) && if (!S_ISDIR(inode->i_mode) && !S_ISREG(inode->i_mode) &&
!S_ISLNK(inode->i_mode)) !S_ISLNK(inode->i_mode))
return; return;
if (!S_ISDIR(inode->i_mode)) { spin_lock(&sbi->inode_lock[type]);
inode_inc_dirty_pages(inode); __add_dirty_inode(inode, type);
goto out;
}
spin_lock(&sbi->dir_inode_lock);
__add_dirty_inode(inode);
inode_inc_dirty_pages(inode); inode_inc_dirty_pages(inode);
spin_unlock(&sbi->dir_inode_lock); spin_unlock(&sbi->inode_lock[type]);
out:
SetPagePrivate(page); SetPagePrivate(page);
f2fs_trace_pid(page); f2fs_trace_pid(page);
} }
...@@ -777,22 +775,24 @@ void add_dirty_dir_inode(struct inode *inode) ...@@ -777,22 +775,24 @@ void add_dirty_dir_inode(struct inode *inode)
{ {
struct f2fs_sb_info *sbi = F2FS_I_SB(inode); struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
spin_lock(&sbi->dir_inode_lock); spin_lock(&sbi->inode_lock[DIR_INODE]);
__add_dirty_inode(inode); __add_dirty_inode(inode, DIR_INODE);
spin_unlock(&sbi->dir_inode_lock); 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_sb_info *sbi = F2FS_I_SB(inode);
struct f2fs_inode_info *fi = F2FS_I(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; return;
spin_lock(&sbi->dir_inode_lock); spin_lock(&sbi->inode_lock[type]);
__remove_dirty_inode(inode); __remove_dirty_inode(inode, type);
spin_unlock(&sbi->dir_inode_lock); spin_unlock(&sbi->inode_lock[type]);
/* Only from the recovery routine */ /* Only from the recovery routine */
if (is_inode_flag_set(fi, FI_DELAY_IPUT)) { if (is_inode_flag_set(fi, FI_DELAY_IPUT)) {
...@@ -801,7 +801,7 @@ void remove_dirty_dir_inode(struct inode *inode) ...@@ -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 list_head *head;
struct inode *inode; struct inode *inode;
...@@ -810,16 +810,16 @@ void sync_dirty_dir_inodes(struct f2fs_sb_info *sbi) ...@@ -810,16 +810,16 @@ void sync_dirty_dir_inodes(struct f2fs_sb_info *sbi)
if (unlikely(f2fs_cp_error(sbi))) if (unlikely(f2fs_cp_error(sbi)))
return; 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)) { if (list_empty(head)) {
spin_unlock(&sbi->dir_inode_lock); spin_unlock(&sbi->inode_lock[type]);
return; return;
} }
fi = list_entry(head->next, struct f2fs_inode_info, dirty_list); fi = list_entry(head->next, struct f2fs_inode_info, dirty_list);
inode = igrab(&fi->vfs_inode); inode = igrab(&fi->vfs_inode);
spin_unlock(&sbi->dir_inode_lock); spin_unlock(&sbi->inode_lock[type]);
if (inode) { if (inode) {
filemap_fdatawrite(inode->i_mapping); filemap_fdatawrite(inode->i_mapping);
iput(inode); iput(inode);
...@@ -854,7 +854,7 @@ static int block_operations(struct f2fs_sb_info *sbi) ...@@ -854,7 +854,7 @@ static int block_operations(struct f2fs_sb_info *sbi)
/* write all the dirty dentry pages */ /* write all the dirty dentry pages */
if (get_pages(sbi, F2FS_DIRTY_DENTS)) { if (get_pages(sbi, F2FS_DIRTY_DENTS)) {
f2fs_unlock_all(sbi); f2fs_unlock_all(sbi);
sync_dirty_dir_inodes(sbi); sync_dirty_inodes(sbi, DIR_INODE);
if (unlikely(f2fs_cp_error(sbi))) { if (unlikely(f2fs_cp_error(sbi))) {
err = -EIO; err = -EIO;
goto out; goto out;
......
...@@ -1180,7 +1180,7 @@ static int f2fs_write_data_page(struct page *page, ...@@ -1180,7 +1180,7 @@ static int f2fs_write_data_page(struct page *page,
f2fs_balance_fs(sbi); f2fs_balance_fs(sbi);
if (wbc->for_reclaim) { if (wbc->for_reclaim) {
f2fs_submit_merged_bio(sbi, DATA, WRITE); f2fs_submit_merged_bio(sbi, DATA, WRITE);
remove_dirty_dir_inode(inode); remove_dirty_inode(inode);
} }
return 0; return 0;
...@@ -1372,7 +1372,7 @@ static int f2fs_write_data_pages(struct address_space *mapping, ...@@ -1372,7 +1372,7 @@ static int f2fs_write_data_pages(struct address_space *mapping,
if (locked) if (locked)
mutex_unlock(&sbi->writepages); 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); wbc->nr_to_write = max((long)0, wbc->nr_to_write - diff);
return ret; return ret;
......
...@@ -444,7 +444,7 @@ struct page *init_inode_metadata(struct inode *inode, struct inode *dir, ...@@ -444,7 +444,7 @@ struct page *init_inode_metadata(struct inode *inode, struct inode *dir,
/* once the failed inode becomes a bad inode, i_mode is S_IFREG */ /* once the failed inode becomes a bad inode, i_mode is S_IFREG */
truncate_inode_pages(&inode->i_data, 0); truncate_inode_pages(&inode->i_data, 0);
truncate_blocks(inode, 0, false); truncate_blocks(inode, 0, false);
remove_dirty_dir_inode(inode); remove_dirty_inode(inode);
remove_inode_page(inode); remove_inode_page(inode);
return ERR_PTR(err); return ERR_PTR(err);
} }
......
...@@ -648,6 +648,7 @@ struct f2fs_sm_info { ...@@ -648,6 +648,7 @@ struct f2fs_sm_info {
enum count_type { enum count_type {
F2FS_WRITEBACK, F2FS_WRITEBACK,
F2FS_DIRTY_DENTS, F2FS_DIRTY_DENTS,
F2FS_DIRTY_DATA,
F2FS_DIRTY_NODES, F2FS_DIRTY_NODES,
F2FS_DIRTY_META, F2FS_DIRTY_META,
F2FS_INMEM_PAGES, F2FS_INMEM_PAGES,
...@@ -696,6 +697,12 @@ struct f2fs_bio_info { ...@@ -696,6 +697,12 @@ struct f2fs_bio_info {
struct rw_semaphore io_rwsem; /* blocking op for bio */ 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 */ /* for inner inode cache management */
struct inode_management { struct inode_management {
struct radix_tree_root ino_root; /* ino entry array */ struct radix_tree_root ino_root; /* ino entry array */
...@@ -745,9 +752,9 @@ struct f2fs_sb_info { ...@@ -745,9 +752,9 @@ struct f2fs_sb_info {
/* for orphan inode, use 0'th array */ /* for orphan inode, use 0'th array */
unsigned int max_orphans; /* max orphan inodes */ unsigned int max_orphans; /* max orphan inodes */
/* for directory inode management */ /* for inode management */
struct list_head dir_inode_list; /* dir inode list */ struct list_head inode_list[NR_INODE_TYPE]; /* dirty inode list */
spinlock_t dir_inode_lock; /* for dir inode list lock */ spinlock_t inode_lock[NR_INODE_TYPE]; /* for dirty inode list lock */
/* for extent tree cache */ /* for extent tree cache */
struct radix_tree_root extent_tree_root;/* cache extent cache entries */ 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) ...@@ -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) static inline void inode_inc_dirty_pages(struct inode *inode)
{ {
atomic_inc(&F2FS_I(inode)->dirty_pages); atomic_inc(&F2FS_I(inode)->dirty_pages);
if (S_ISDIR(inode->i_mode)) inc_page_count(F2FS_I_SB(inode), S_ISDIR(inode->i_mode) ?
inc_page_count(F2FS_I_SB(inode), F2FS_DIRTY_DENTS); F2FS_DIRTY_DENTS : F2FS_DIRTY_DATA);
} }
static inline void dec_page_count(struct f2fs_sb_info *sbi, int count_type) 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) ...@@ -1076,9 +1083,8 @@ static inline void inode_dec_dirty_pages(struct inode *inode)
return; return;
atomic_dec(&F2FS_I(inode)->dirty_pages); atomic_dec(&F2FS_I(inode)->dirty_pages);
dec_page_count(F2FS_I_SB(inode), S_ISDIR(inode->i_mode) ?
if (S_ISDIR(inode->i_mode)) F2FS_DIRTY_DENTS : F2FS_DIRTY_DATA);
dec_page_count(F2FS_I_SB(inode), F2FS_DIRTY_DENTS);
} }
static inline int get_pages(struct f2fs_sb_info *sbi, int count_type) static inline int get_pages(struct f2fs_sb_info *sbi, int count_type)
...@@ -1417,6 +1423,7 @@ enum { ...@@ -1417,6 +1423,7 @@ enum {
FI_DATA_EXIST, /* indicate data exists */ FI_DATA_EXIST, /* indicate data exists */
FI_INLINE_DOTS, /* indicate inline dot dentries */ FI_INLINE_DOTS, /* indicate inline dot dentries */
FI_DO_DEFRAG, /* indicate defragment is running */ 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) 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 *); ...@@ -1826,8 +1833,8 @@ int recover_orphan_inodes(struct f2fs_sb_info *);
int get_valid_checkpoint(struct f2fs_sb_info *); int get_valid_checkpoint(struct f2fs_sb_info *);
void update_dirty_page(struct inode *, struct page *); void update_dirty_page(struct inode *, struct page *);
void add_dirty_dir_inode(struct inode *); void add_dirty_dir_inode(struct inode *);
void remove_dirty_dir_inode(struct inode *); void remove_dirty_inode(struct inode *);
void sync_dirty_dir_inodes(struct f2fs_sb_info *); void sync_dirty_inodes(struct f2fs_sb_info *, enum inode_type);
void write_checkpoint(struct f2fs_sb_info *, struct cp_control *); void write_checkpoint(struct f2fs_sb_info *, struct cp_control *);
void init_ino_entry_info(struct f2fs_sb_info *); void init_ino_entry_info(struct f2fs_sb_info *);
int __init create_checkpoint_caches(void); int __init create_checkpoint_caches(void);
......
...@@ -327,7 +327,7 @@ void f2fs_evict_inode(struct inode *inode) ...@@ -327,7 +327,7 @@ void f2fs_evict_inode(struct inode *inode)
goto out_clear; goto out_clear;
f2fs_bug_on(sbi, get_dirty_pages(inode)); f2fs_bug_on(sbi, get_dirty_pages(inode));
remove_dirty_dir_inode(inode); remove_dirty_inode(inode);
f2fs_destroy_extent_tree(inode); f2fs_destroy_extent_tree(inode);
......
...@@ -1339,8 +1339,10 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) ...@@ -1339,8 +1339,10 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
le64_to_cpu(sbi->ckpt->valid_block_count); le64_to_cpu(sbi->ckpt->valid_block_count);
sbi->last_valid_block_count = sbi->total_valid_block_count; sbi->last_valid_block_count = sbi->total_valid_block_count;
sbi->alloc_valid_block_count = 0; sbi->alloc_valid_block_count = 0;
INIT_LIST_HEAD(&sbi->dir_inode_list); for (i = 0; i < NR_INODE_TYPE; i++) {
spin_lock_init(&sbi->dir_inode_lock); INIT_LIST_HEAD(&sbi->inode_list[i]);
spin_lock_init(&sbi->inode_lock[i]);
}
init_extent_cache_info(sbi); init_extent_cache_info(sbi);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment