From 6f85b3520325a67ee4ac33e75bbcdbc25c79ce69 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Mon, 20 May 2013 16:15:22 +0900 Subject: f2fs: avoid RECLAIM_FS-ON-W: deadlock This patch tries to avoid the following deadlock condition of which the reclaim path can trigger f2fs_balance_fs again. ================================= [ INFO: inconsistent lock state ] --------------------------------- inconsistent {RECLAIM_FS-ON-W} -> {IN-RECLAIM_FS-W} usage. kswapd0/41 [HC0[0]:SC0[0]:HE1:SE1] takes: (&sbi->gc_mutex){+.+.?.}, at: f2fs_balance_fs+0xe6/0x100 [f2fs] {RECLAIM_FS-ON-W} state was registered at: [] mark_held_locks+0xb9/0x140 [] lockdep_trace_alloc+0x85/0xf0 [] __alloc_pages_nodemask+0x7c/0x9b0 [] alloc_pages_current+0xb8/0x180 [] __page_cache_alloc+0xaf/0xd0 [] find_or_create_page+0x4c/0xb0 [] find_data_page+0x14e/0x210 [f2fs] [] f2fs_gc+0x9eb/0xd90 [f2fs] [] f2fs_balance_fs+0xee/0x100 [f2fs] [] f2fs_setattr+0x6c/0x200 [f2fs] [] notify_change+0x1db/0x3a0 [] do_truncate+0x60/0xa0 [] vfs_truncate+0x185/0x1b0 [] do_sys_truncate+0x5c/0xa0 [] SyS_truncate+0xe/0x10 [] system_call_fastpath+0x16/0x1b Signed-off-by: Jaegeuk Kim --- fs/f2fs/inode.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'fs/f2fs/inode.c') diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c index 91ac7f9d88eea..a18946e2a8b4d 100644 --- a/fs/f2fs/inode.c +++ b/fs/f2fs/inode.c @@ -130,8 +130,7 @@ make_now: inode->i_op = &f2fs_dir_inode_operations; inode->i_fop = &f2fs_dir_operations; inode->i_mapping->a_ops = &f2fs_dblock_aops; - mapping_set_gfp_mask(inode->i_mapping, GFP_HIGHUSER_MOVABLE | - __GFP_ZERO); + mapping_set_gfp_mask(inode->i_mapping, GFP_F2FS_ZERO); } else if (S_ISLNK(inode->i_mode)) { inode->i_op = &f2fs_symlink_inode_operations; inode->i_mapping->a_ops = &f2fs_dblock_aops; -- cgit v1.2.3 From b638f0c4b8fca9d2f82805a2d6601b09283e0d32 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Tue, 21 May 2013 10:17:56 +0900 Subject: f2fs: fix wrong condition check While an orphan inode has zero link_count, f2fs_gc is able to select the inode for foreground gc. - f2fs_gc - do_garbage_collect - gc_data_segment : f2fs_iget is failed : get_valid_blocks() != 0, so that retry --> here we got the infinite loop. This patch resolved this issue. Signed-off-by: Jaegeuk Kim --- fs/f2fs/inode.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'fs/f2fs/inode.c') diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c index a18946e2a8b4d..b44a4c1194eae 100644 --- a/fs/f2fs/inode.c +++ b/fs/f2fs/inode.c @@ -109,12 +109,6 @@ struct inode *f2fs_iget(struct super_block *sb, unsigned long ino) ret = do_read_inode(inode); if (ret) goto bad_inode; - - if (!sbi->por_doing && inode->i_nlink == 0) { - ret = -ENOENT; - goto bad_inode; - } - make_now: if (ino == F2FS_NODE_INO(sbi)) { inode->i_mapping->a_ops = &f2fs_node_aops; -- cgit v1.2.3 From b3783873cc2214542d3da9a1aa800b20919d5889 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Mon, 10 Jun 2013 09:17:01 +0900 Subject: f2fs: avoid freqeunt write_inode calls If update_inode is called, we don't need to do write_inode. So, let's use a *dirty* flag for each inode. Signed-off-by: Jaegeuk Kim --- fs/f2fs/f2fs.h | 1 + fs/f2fs/file.c | 1 + fs/f2fs/inode.c | 4 ++++ fs/f2fs/super.c | 12 ++++++++++++ 4 files changed, 18 insertions(+) (limited to 'fs/f2fs/inode.c') diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 27edf59ac12cd..a05aa65cfc2c4 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -856,6 +856,7 @@ static inline int f2fs_clear_bit(unsigned int nr, char *addr) /* used for f2fs_inode_info->flags */ enum { FI_NEW_INODE, /* indicate newly allocated inode */ + FI_DIRTY_INODE, /* indicate inode is dirty or not */ FI_INC_LINK, /* need to increment i_nlink */ FI_ACL_MODE, /* indicate acl mode */ FI_NO_ALLOC, /* should not allocate any blocks */ diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 2f649b8485219..fda226ff1849c 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -147,6 +147,7 @@ int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) } else { /* if there is no written node page, write its inode page */ while (!sync_node_pages(sbi, inode->i_ino, &wbc)) { + mark_inode_dirty_sync(inode); ret = f2fs_write_inode(inode, NULL); if (ret) goto out; diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c index b44a4c1194eae..2b2d45d19e3ea 100644 --- a/fs/f2fs/inode.c +++ b/fs/f2fs/inode.c @@ -192,6 +192,7 @@ void update_inode(struct inode *inode, struct page *node_page) set_cold_node(inode, node_page); set_page_dirty(node_page); + clear_inode_flag(F2FS_I(inode), FI_DIRTY_INODE); } int update_inode_page(struct inode *inode) @@ -217,6 +218,9 @@ int f2fs_write_inode(struct inode *inode, struct writeback_control *wbc) inode->i_ino == F2FS_META_INO(sbi)) return 0; + if (!is_inode_flag_set(F2FS_I(inode), FI_DIRTY_INODE)) + return 0; + if (wbc) f2fs_balance_fs(sbi); diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 4fdcdff45e6a1..ba56549bb2f35 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -112,6 +112,17 @@ static int f2fs_drop_inode(struct inode *inode) return generic_drop_inode(inode); } +/* + * f2fs_dirty_inode() is called from __mark_inode_dirty() + * + * We should call set_dirty_inode to write the dirty inode through write_inode. + */ +static void f2fs_dirty_inode(struct inode *inode, int flags) +{ + set_inode_flag(F2FS_I(inode), FI_DIRTY_INODE); + return; +} + static void f2fs_i_callback(struct rcu_head *head) { struct inode *inode = container_of(head, struct inode, i_rcu); @@ -249,6 +260,7 @@ static struct super_operations f2fs_sops = { .drop_inode = f2fs_drop_inode, .destroy_inode = f2fs_destroy_inode, .write_inode = f2fs_write_inode, + .dirty_inode = f2fs_dirty_inode, .show_options = f2fs_show_options, .evict_inode = f2fs_evict_inode, .put_super = f2fs_put_super, -- cgit v1.2.3