change log from v2: o slighly change the previous approach From 42e49df33bacafc20434e39fc127c9722c9f8691 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim <jaegeuk.kim@xxxxxxxxxxx> Date: Tue, 30 Apr 2013 11:33:27 +0900 Subject: [PATCH] f2fs: avoid deadlock during evict after f2fs_gc Cc: linux-fsdevel@xxxxxxxxxxxxxxx, linux-kernel@xxxxxxxxxxxxxxx, linux-f2fs-devel@xxxxxxxxxxxxxxxxxxxxx o Deadlock case #1 Thread 1: - writeback_sb_inodes - do_writepages - f2fs_write_data_pages - write_cache_pages - f2fs_write_data_page - f2fs_balance_fs - wait mutex_lock(gc_mutex) Thread 2: - f2fs_balance_fs - mutex_lock(gc_mutex) - f2fs_gc - f2fs_iget - wait iget_locked(inode->i_lock) Thread 3: - do_unlinkat - iput - lock(inode->i_lock) - evict - inode_wait_for_writeback o Deadlock case #2 Thread 1: - __writeback_single_inode : set I_SYNC - do_writepages - f2fs_write_data_page - f2fs_balance_fs - f2fs_gc - iput - evict - inode_wait_for_writeback(I_SYNC) In order to avoid this, even though iput is called with the zero-reference count, we need to stop the eviction procedure if the inode is on writeback. So this patch links f2fs_drop_inode which checks the I_SYNC flag. Signed-off-by: Jaegeuk Kim <jaegeuk.kim@xxxxxxxxxxx> --- fs/f2fs/f2fs.h | 1 + fs/f2fs/gc.c | 1 + fs/f2fs/super.c | 19 +++++++++++++++++++ 3 files changed, 21 insertions(+) diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 20aab02..beb3f06 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -846,6 +846,7 @@ enum { FI_INC_LINK, /* need to increment i_nlink */ FI_ACL_MODE, /* indicate acl mode */ FI_NO_ALLOC, /* should not allocate any blocks */ + FI_ON_GC, /* indicate inode is on gc */ }; static inline void set_inode_flag(struct f2fs_inode_info *fi, int flag) diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index 1496159..258b786 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -345,6 +345,7 @@ repeat: } new_ie->inode = inode; list_add_tail(&new_ie->list, ilist); + set_inode_flag(F2FS_I(inode), FI_ON_GC); } static void put_gc_inode(struct list_head *ilist) diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 5835aaf..6ac1f42 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -98,6 +98,24 @@ static struct inode *f2fs_alloc_inode(struct super_block *sb) return &fi->vfs_inode; } +static int f2fs_drop_inode(struct inode *inode) +{ + int drop = generic_drop_inode(inode); + + /* + * This is to avoid a deadlock condition like below. + * writeback_single_inode(inode) + * - f2fs_write_data_page + * - f2fs_gc -> iput -> evict + * - inode_wait_for_writeback(inode) + */ + if (inode->i_state & I_SYNC && + is_inode_flag_set(F2FS_I(inode), FI_ON_GC)) + drop = 0; + clear_inode_flag(F2FS_I(inode), FI_ON_GC); + return drop; +} + static void f2fs_i_callback(struct rcu_head *head) { struct inode *inode = container_of(head, struct inode, i_rcu); @@ -232,6 +250,7 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root) static struct super_operations f2fs_sops = { .alloc_inode = f2fs_alloc_inode, + .drop_inode = f2fs_drop_inode, .destroy_inode = f2fs_destroy_inode, .write_inode = f2fs_write_inode, .show_options = f2fs_show_options, -- 1.8.1.3.566.gaa39828 -- Jaegeuk Kim Samsung
Attachment:
signature.asc
Description: This is a digitally signed message part