mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson
synced 2025-08-31 22:23:05 +00:00
f2fs: flush inode metadata when checkpoint is doing
This patch registers all the inodes which have dirty metadata to sync when checkpoint is doing. Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
This commit is contained in:
parent
205b98221c
commit
0f18b462b2
@ -859,6 +859,34 @@ int sync_dirty_inodes(struct f2fs_sb_info *sbi, enum inode_type type)
|
|||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int f2fs_sync_inode_meta(struct f2fs_sb_info *sbi)
|
||||||
|
{
|
||||||
|
struct list_head *head = &sbi->inode_list[DIRTY_META];
|
||||||
|
struct inode *inode;
|
||||||
|
struct f2fs_inode_info *fi;
|
||||||
|
s64 total = get_pages(sbi, F2FS_DIRTY_IMETA);
|
||||||
|
|
||||||
|
while (total--) {
|
||||||
|
if (unlikely(f2fs_cp_error(sbi)))
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
spin_lock(&sbi->inode_lock[DIRTY_META]);
|
||||||
|
if (list_empty(head)) {
|
||||||
|
spin_unlock(&sbi->inode_lock[DIRTY_META]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
fi = list_entry(head->next, struct f2fs_inode_info,
|
||||||
|
gdirty_list);
|
||||||
|
inode = igrab(&fi->vfs_inode);
|
||||||
|
spin_unlock(&sbi->inode_lock[DIRTY_META]);
|
||||||
|
if (inode) {
|
||||||
|
update_inode_page(inode);
|
||||||
|
iput(inode);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Freeze all the FS-operations for checkpoint.
|
* Freeze all the FS-operations for checkpoint.
|
||||||
*/
|
*/
|
||||||
@ -885,6 +913,14 @@ static int block_operations(struct f2fs_sb_info *sbi)
|
|||||||
goto retry_flush_dents;
|
goto retry_flush_dents;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (get_pages(sbi, F2FS_DIRTY_IMETA)) {
|
||||||
|
f2fs_unlock_all(sbi);
|
||||||
|
err = f2fs_sync_inode_meta(sbi);
|
||||||
|
if (err)
|
||||||
|
goto out;
|
||||||
|
goto retry_flush_dents;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* POR: we should ensure that there are no dirty node pages
|
* POR: we should ensure that there are no dirty node pages
|
||||||
* until finishing nat/sit flush.
|
* until finishing nat/sit flush.
|
||||||
|
@ -47,6 +47,7 @@ static void update_general_status(struct f2fs_sb_info *sbi)
|
|||||||
si->ndirty_data = get_pages(sbi, F2FS_DIRTY_DATA);
|
si->ndirty_data = get_pages(sbi, F2FS_DIRTY_DATA);
|
||||||
si->ndirty_dirs = sbi->ndirty_inode[DIR_INODE];
|
si->ndirty_dirs = sbi->ndirty_inode[DIR_INODE];
|
||||||
si->ndirty_files = sbi->ndirty_inode[FILE_INODE];
|
si->ndirty_files = sbi->ndirty_inode[FILE_INODE];
|
||||||
|
si->ndirty_all = sbi->ndirty_inode[DIRTY_META];
|
||||||
si->inmem_pages = get_pages(sbi, F2FS_INMEM_PAGES);
|
si->inmem_pages = get_pages(sbi, F2FS_INMEM_PAGES);
|
||||||
si->wb_bios = atomic_read(&sbi->nr_wb_bios);
|
si->wb_bios = atomic_read(&sbi->nr_wb_bios);
|
||||||
si->total_count = (int)sbi->user_block_count / sbi->blocks_per_seg;
|
si->total_count = (int)sbi->user_block_count / sbi->blocks_per_seg;
|
||||||
@ -304,8 +305,8 @@ static int stat_show(struct seq_file *s, void *v)
|
|||||||
si->inmem_pages, si->wb_bios);
|
si->inmem_pages, si->wb_bios);
|
||||||
seq_printf(s, " - nodes: %4lld in %4d\n",
|
seq_printf(s, " - nodes: %4lld in %4d\n",
|
||||||
si->ndirty_node, si->node_pages);
|
si->ndirty_node, si->node_pages);
|
||||||
seq_printf(s, " - dents: %4lld in dirs:%4d\n",
|
seq_printf(s, " - dents: %4lld in dirs:%4d (%4d)\n",
|
||||||
si->ndirty_dent, si->ndirty_dirs);
|
si->ndirty_dent, si->ndirty_dirs, si->ndirty_all);
|
||||||
seq_printf(s, " - datas: %4lld in files:%4d\n",
|
seq_printf(s, " - datas: %4lld in files:%4d\n",
|
||||||
si->ndirty_data, si->ndirty_files);
|
si->ndirty_data, si->ndirty_files);
|
||||||
seq_printf(s, " - meta: %4lld in %4d\n",
|
seq_printf(s, " - meta: %4lld in %4d\n",
|
||||||
|
@ -442,7 +442,8 @@ struct f2fs_inode_info {
|
|||||||
nid_t i_xattr_nid; /* node id that contains xattrs */
|
nid_t i_xattr_nid; /* node id that contains xattrs */
|
||||||
unsigned long long xattr_ver; /* cp version of xattr modification */
|
unsigned long long xattr_ver; /* cp version of xattr modification */
|
||||||
|
|
||||||
struct list_head dirty_list; /* linked in global dirty list */
|
struct list_head dirty_list; /* dirty list for dirs and files */
|
||||||
|
struct list_head gdirty_list; /* linked in global dirty list */
|
||||||
struct list_head inmem_pages; /* inmemory pages managed by f2fs */
|
struct list_head inmem_pages; /* inmemory pages managed by f2fs */
|
||||||
struct mutex inmem_lock; /* lock for inmemory pages */
|
struct mutex inmem_lock; /* lock for inmemory pages */
|
||||||
struct extent_tree *extent_tree; /* cached extent_tree entry */
|
struct extent_tree *extent_tree; /* cached extent_tree entry */
|
||||||
@ -657,6 +658,7 @@ enum count_type {
|
|||||||
F2FS_DIRTY_NODES,
|
F2FS_DIRTY_NODES,
|
||||||
F2FS_DIRTY_META,
|
F2FS_DIRTY_META,
|
||||||
F2FS_INMEM_PAGES,
|
F2FS_INMEM_PAGES,
|
||||||
|
F2FS_DIRTY_IMETA,
|
||||||
NR_COUNT_TYPE,
|
NR_COUNT_TYPE,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -707,6 +709,7 @@ struct f2fs_bio_info {
|
|||||||
enum inode_type {
|
enum inode_type {
|
||||||
DIR_INODE, /* for dirty dir inode */
|
DIR_INODE, /* for dirty dir inode */
|
||||||
FILE_INODE, /* for dirty regular/symlink inode */
|
FILE_INODE, /* for dirty regular/symlink inode */
|
||||||
|
DIRTY_META, /* for all dirtied inode metadata */
|
||||||
NR_INODE_TYPE,
|
NR_INODE_TYPE,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1899,6 +1902,7 @@ static inline int f2fs_add_link(struct dentry *dentry, struct inode *inode)
|
|||||||
/*
|
/*
|
||||||
* super.c
|
* super.c
|
||||||
*/
|
*/
|
||||||
|
void f2fs_inode_synced(struct inode *);
|
||||||
int f2fs_commit_super(struct f2fs_sb_info *, bool);
|
int f2fs_commit_super(struct f2fs_sb_info *, bool);
|
||||||
int f2fs_sync_fs(struct super_block *, int);
|
int f2fs_sync_fs(struct super_block *, int);
|
||||||
extern __printf(3, 4)
|
extern __printf(3, 4)
|
||||||
@ -2010,6 +2014,7 @@ void add_ino_entry(struct f2fs_sb_info *, nid_t, int type);
|
|||||||
void remove_ino_entry(struct f2fs_sb_info *, nid_t, int type);
|
void remove_ino_entry(struct f2fs_sb_info *, nid_t, int type);
|
||||||
void release_ino_entry(struct f2fs_sb_info *, bool);
|
void release_ino_entry(struct f2fs_sb_info *, bool);
|
||||||
bool exist_written_data(struct f2fs_sb_info *, nid_t, int);
|
bool exist_written_data(struct f2fs_sb_info *, nid_t, int);
|
||||||
|
int f2fs_sync_inode_meta(struct f2fs_sb_info *);
|
||||||
int acquire_orphan_inode(struct f2fs_sb_info *);
|
int acquire_orphan_inode(struct f2fs_sb_info *);
|
||||||
void release_orphan_inode(struct f2fs_sb_info *);
|
void release_orphan_inode(struct f2fs_sb_info *);
|
||||||
void add_orphan_inode(struct f2fs_sb_info *, nid_t);
|
void add_orphan_inode(struct f2fs_sb_info *, nid_t);
|
||||||
@ -2078,7 +2083,7 @@ struct f2fs_stat_info {
|
|||||||
unsigned long long hit_total, total_ext;
|
unsigned long long hit_total, total_ext;
|
||||||
int ext_tree, zombie_tree, ext_node;
|
int ext_tree, zombie_tree, ext_node;
|
||||||
s64 ndirty_node, ndirty_dent, ndirty_meta, ndirty_data, inmem_pages;
|
s64 ndirty_node, ndirty_dent, ndirty_meta, ndirty_data, inmem_pages;
|
||||||
unsigned int ndirty_dirs, ndirty_files;
|
unsigned int ndirty_dirs, ndirty_files, ndirty_all;
|
||||||
int nats, dirty_nats, sits, dirty_sits, fnids;
|
int nats, dirty_nats, sits, dirty_sits, fnids;
|
||||||
int total_count, utilization;
|
int total_count, utilization;
|
||||||
int bg_gc, wb_bios;
|
int bg_gc, wb_bios;
|
||||||
|
@ -262,7 +262,7 @@ int update_inode(struct inode *inode, struct page *node_page)
|
|||||||
|
|
||||||
__set_inode_rdev(inode, ri);
|
__set_inode_rdev(inode, ri);
|
||||||
set_cold_node(inode, node_page);
|
set_cold_node(inode, node_page);
|
||||||
clear_inode_flag(inode, FI_DIRTY_INODE);
|
f2fs_inode_synced(inode);
|
||||||
|
|
||||||
/* deleted inode */
|
/* deleted inode */
|
||||||
if (inode->i_nlink == 0)
|
if (inode->i_nlink == 0)
|
||||||
@ -286,6 +286,7 @@ int update_inode_page(struct inode *inode)
|
|||||||
} else if (err != -ENOENT) {
|
} else if (err != -ENOENT) {
|
||||||
f2fs_stop_checkpoint(sbi, false);
|
f2fs_stop_checkpoint(sbi, false);
|
||||||
}
|
}
|
||||||
|
f2fs_inode_synced(inode);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
ret = update_inode(inode, node_page);
|
ret = update_inode(inode, node_page);
|
||||||
@ -360,6 +361,8 @@ void f2fs_evict_inode(struct inode *inode)
|
|||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (err)
|
||||||
|
update_inode_page(inode);
|
||||||
sb_end_intwrite(inode->i_sb);
|
sb_end_intwrite(inode->i_sb);
|
||||||
no_delete:
|
no_delete:
|
||||||
stat_dec_inline_xattr(inode);
|
stat_dec_inline_xattr(inode);
|
||||||
@ -381,6 +384,8 @@ void f2fs_evict_inode(struct inode *inode)
|
|||||||
!exist_written_data(sbi, inode->i_ino, ORPHAN_INO));
|
!exist_written_data(sbi, inode->i_ino, ORPHAN_INO));
|
||||||
out_clear:
|
out_clear:
|
||||||
fscrypt_put_encryption_info(inode, NULL);
|
fscrypt_put_encryption_info(inode, NULL);
|
||||||
|
|
||||||
|
f2fs_bug_on(sbi, is_inode_flag_set(inode, FI_DIRTY_INODE));
|
||||||
clear_inode(inode);
|
clear_inode(inode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -670,6 +670,7 @@ static void truncate_node(struct dnode_of_data *dn)
|
|||||||
if (dn->nid == dn->inode->i_ino) {
|
if (dn->nid == dn->inode->i_ino) {
|
||||||
remove_orphan_inode(sbi, dn->nid);
|
remove_orphan_inode(sbi, dn->nid);
|
||||||
dec_valid_inode_count(sbi);
|
dec_valid_inode_count(sbi);
|
||||||
|
f2fs_inode_synced(dn->inode);
|
||||||
} else {
|
} else {
|
||||||
sync_inode_page(dn);
|
sync_inode_page(dn);
|
||||||
}
|
}
|
||||||
|
@ -479,6 +479,8 @@ static inline bool has_not_enough_free_secs(struct f2fs_sb_info *sbi, int freed)
|
|||||||
int node_secs = get_blocktype_secs(sbi, F2FS_DIRTY_NODES);
|
int node_secs = get_blocktype_secs(sbi, F2FS_DIRTY_NODES);
|
||||||
int dent_secs = get_blocktype_secs(sbi, F2FS_DIRTY_DENTS);
|
int dent_secs = get_blocktype_secs(sbi, F2FS_DIRTY_DENTS);
|
||||||
|
|
||||||
|
node_secs += get_blocktype_secs(sbi, F2FS_DIRTY_IMETA);
|
||||||
|
|
||||||
if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING)))
|
if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING)))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -537,6 +537,7 @@ static struct inode *f2fs_alloc_inode(struct super_block *sb)
|
|||||||
fi->i_advise = 0;
|
fi->i_advise = 0;
|
||||||
init_rwsem(&fi->i_sem);
|
init_rwsem(&fi->i_sem);
|
||||||
INIT_LIST_HEAD(&fi->dirty_list);
|
INIT_LIST_HEAD(&fi->dirty_list);
|
||||||
|
INIT_LIST_HEAD(&fi->gdirty_list);
|
||||||
INIT_LIST_HEAD(&fi->inmem_pages);
|
INIT_LIST_HEAD(&fi->inmem_pages);
|
||||||
mutex_init(&fi->inmem_lock);
|
mutex_init(&fi->inmem_lock);
|
||||||
|
|
||||||
@ -547,6 +548,8 @@ static struct inode *f2fs_alloc_inode(struct super_block *sb)
|
|||||||
|
|
||||||
static int f2fs_drop_inode(struct inode *inode)
|
static int f2fs_drop_inode(struct inode *inode)
|
||||||
{
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is to avoid a deadlock condition like below.
|
* This is to avoid a deadlock condition like below.
|
||||||
* writeback_single_inode(inode)
|
* writeback_single_inode(inode)
|
||||||
@ -554,7 +557,7 @@ static int f2fs_drop_inode(struct inode *inode)
|
|||||||
* - f2fs_gc -> iput -> evict
|
* - f2fs_gc -> iput -> evict
|
||||||
* - inode_wait_for_writeback(inode)
|
* - inode_wait_for_writeback(inode)
|
||||||
*/
|
*/
|
||||||
if (!inode_unhashed(inode) && inode->i_state & I_SYNC) {
|
if ((!inode_unhashed(inode) && inode->i_state & I_SYNC)) {
|
||||||
if (!inode->i_nlink && !is_bad_inode(inode)) {
|
if (!inode->i_nlink && !is_bad_inode(inode)) {
|
||||||
/* to avoid evict_inode call simultaneously */
|
/* to avoid evict_inode call simultaneously */
|
||||||
atomic_inc(&inode->i_count);
|
atomic_inc(&inode->i_count);
|
||||||
@ -581,7 +584,20 @@ static int f2fs_drop_inode(struct inode *inode)
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return generic_drop_inode(inode);
|
|
||||||
|
ret = generic_drop_inode(inode);
|
||||||
|
if (is_inode_flag_set(inode, FI_DIRTY_INODE)) {
|
||||||
|
if (ret)
|
||||||
|
inode->i_state |= I_WILL_FREE;
|
||||||
|
spin_unlock(&inode->i_lock);
|
||||||
|
|
||||||
|
update_inode_page(inode);
|
||||||
|
|
||||||
|
spin_lock(&inode->i_lock);
|
||||||
|
if (ret)
|
||||||
|
inode->i_state &= ~I_WILL_FREE;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -591,7 +607,40 @@ static int f2fs_drop_inode(struct inode *inode)
|
|||||||
*/
|
*/
|
||||||
static void f2fs_dirty_inode(struct inode *inode, int flags)
|
static void f2fs_dirty_inode(struct inode *inode, int flags)
|
||||||
{
|
{
|
||||||
|
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
||||||
|
|
||||||
|
if (inode->i_ino == F2FS_NODE_INO(sbi) ||
|
||||||
|
inode->i_ino == F2FS_META_INO(sbi))
|
||||||
|
return;
|
||||||
|
|
||||||
|
spin_lock(&sbi->inode_lock[DIRTY_META]);
|
||||||
|
if (is_inode_flag_set(inode, FI_DIRTY_INODE)) {
|
||||||
|
spin_unlock(&sbi->inode_lock[DIRTY_META]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
set_inode_flag(inode, FI_DIRTY_INODE);
|
set_inode_flag(inode, FI_DIRTY_INODE);
|
||||||
|
list_add_tail(&F2FS_I(inode)->gdirty_list,
|
||||||
|
&sbi->inode_list[DIRTY_META]);
|
||||||
|
inc_page_count(sbi, F2FS_DIRTY_IMETA);
|
||||||
|
spin_unlock(&sbi->inode_lock[DIRTY_META]);
|
||||||
|
stat_inc_dirty_inode(sbi, DIRTY_META);
|
||||||
|
}
|
||||||
|
|
||||||
|
void f2fs_inode_synced(struct inode *inode)
|
||||||
|
{
|
||||||
|
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
||||||
|
|
||||||
|
spin_lock(&sbi->inode_lock[DIRTY_META]);
|
||||||
|
if (!is_inode_flag_set(inode, FI_DIRTY_INODE)) {
|
||||||
|
spin_unlock(&sbi->inode_lock[DIRTY_META]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
list_del_init(&F2FS_I(inode)->gdirty_list);
|
||||||
|
clear_inode_flag(inode, FI_DIRTY_INODE);
|
||||||
|
dec_page_count(sbi, F2FS_DIRTY_IMETA);
|
||||||
|
spin_unlock(&sbi->inode_lock[DIRTY_META]);
|
||||||
|
stat_dec_dirty_inode(F2FS_I_SB(inode), DIRTY_META);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void f2fs_i_callback(struct rcu_head *head)
|
static void f2fs_i_callback(struct rcu_head *head)
|
||||||
@ -1757,6 +1806,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
free_kobj:
|
free_kobj:
|
||||||
|
f2fs_sync_inode_meta(sbi);
|
||||||
kobject_del(&sbi->s_kobj);
|
kobject_del(&sbi->s_kobj);
|
||||||
kobject_put(&sbi->s_kobj);
|
kobject_put(&sbi->s_kobj);
|
||||||
wait_for_completion(&sbi->s_kobj_unregister);
|
wait_for_completion(&sbi->s_kobj_unregister);
|
||||||
|
Loading…
Reference in New Issue
Block a user