diff options
author | Jaegeuk Kim <jaegeuk.kim@samsung.com> | 2013-04-30 11:33:27 +0900 |
---|---|---|
committer | Jaegeuk Kim <jaegeuk.kim@samsung.com> | 2013-05-08 19:54:08 +0900 |
commit | 531ad7d58c6476c5856653448b4c7d26427502b4 (patch) | |
tree | 6b890195ebfd773fa55ec580ce2248a2a47d5452 /fs/f2fs/super.c | |
parent | ac5d156c78a68b39955ee9b09498ba93831c77d7 (diff) | |
download | blackbird-op-linux-531ad7d58c6476c5856653448b4c7d26427502b4.tar.gz blackbird-op-linux-531ad7d58c6476c5856653448b4c7d26427502b4.zip |
f2fs: avoid deadlock during evict after f2fs_gc
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@samsung.com>
Diffstat (limited to 'fs/f2fs/super.c')
-rw-r--r-- | fs/f2fs/super.c | 15 |
1 files changed, 15 insertions, 0 deletions
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 5835aaf2fe2e..cd0e89a1ff8f 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -98,6 +98,20 @@ static struct inode *f2fs_alloc_inode(struct super_block *sb) return &fi->vfs_inode; } +static int f2fs_drop_inode(struct 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_unhashed(inode) && inode->i_state & I_SYNC) + return 0; + return generic_drop_inode(inode); +} + static void f2fs_i_callback(struct rcu_head *head) { struct inode *inode = container_of(head, struct inode, i_rcu); @@ -232,6 +246,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, |