mirror of https://gitee.com/openkylin/linux.git
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: Chao Yu <chao2.yu@samsung.com> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
This commit is contained in:
parent
b3980910f7
commit
c227f91273
|
@ -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)
|
||||||
{
|
{
|
||||||
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
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)
|
||||||
/* 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,
|
||||||
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,
|
||||||
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,
|
||||||
/* 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 {
|
||||||
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 {
|
||||||
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 {
|
||||||
/* 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)
|
||||||
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)
|
||||||
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 {
|
||||||
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 *);
|
||||||
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)
|
||||||
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)
|
||||||
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);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue