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

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
Loading
Loading
Loading
Loading
+33 −33
Original line number Diff line number Diff line
@@ -722,53 +722,51 @@ int get_valid_checkpoint(struct f2fs_sb_info *sbi)
	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);
	set_inode_flag(fi, flag);
	list_add_tail(&fi->dirty_list, &sbi->inode_list[type]);
	if (type == DIR_INODE)
		stat_inc_dirty_dir(sbi);
	return;
}

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);
	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 @@ void sync_dirty_dir_inodes(struct f2fs_sb_info *sbi)
	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 @@ static int block_operations(struct f2fs_sb_info *sbi)
	/* 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;
+2 −2
Original line number Diff line number Diff line
@@ -1180,7 +1180,7 @@ static int f2fs_write_data_page(struct page *page,
		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;
+1 −1
Original line number Diff line number Diff line
@@ -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 */
	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);
}
+17 −10
Original line number Diff line number Diff line
@@ -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);
+1 −1
Original line number Diff line number Diff line
@@ -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);

Loading