Skip to content

Commit 628921c

Browse files
Jaegeuk KimHashcode
authored andcommitted
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>
1 parent cc116a2 commit 628921c

File tree

3 files changed

+26
-2
lines changed

3 files changed

+26
-2
lines changed

fs/f2fs/data.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -577,6 +577,7 @@ static int f2fs_write_data_pages(struct address_space *mapping,
577577
{
578578
struct inode *inode = mapping->host;
579579
struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
580+
bool locked = false;
580581
int ret;
581582
long excess_nrtw = 0, desired_nrtw;
582583

@@ -590,10 +591,12 @@ static int f2fs_write_data_pages(struct address_space *mapping,
590591
wbc->nr_to_write = desired_nrtw;
591592
}
592593

593-
if (!S_ISDIR(inode->i_mode))
594+
if (!S_ISDIR(inode->i_mode)) {
594595
mutex_lock(&sbi->writepages);
596+
locked = true;
597+
}
595598
ret = write_cache_pages(mapping, wbc, __f2fs_writepage, mapping);
596-
if (!S_ISDIR(inode->i_mode))
599+
if (locked)
597600
mutex_unlock(&sbi->writepages);
598601
f2fs_submit_bio(sbi, DATA, (wbc->sync_mode == WB_SYNC_ALL));
599602

fs/f2fs/namei.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode)
7272
unlock_new_inode(inode);
7373
fail:
7474
trace_f2fs_new_inode(inode, err);
75+
make_bad_inode(inode);
7576
iput(inode);
7677
if (nid_free)
7778
alloc_nid_failed(sbi, ino);
@@ -155,6 +156,7 @@ static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
155156
out:
156157
clear_nlink(inode);
157158
unlock_new_inode(inode);
159+
make_bad_inode(inode);
158160
iput(inode);
159161
alloc_nid_failed(sbi, ino);
160162
return err;
@@ -190,6 +192,7 @@ static int f2fs_link(struct dentry *old_dentry, struct inode *dir,
190192
return 0;
191193
out:
192194
clear_inode_flag(F2FS_I(inode), FI_INC_LINK);
195+
make_bad_inode(inode);
193196
iput(inode);
194197
return err;
195198
}
@@ -295,6 +298,7 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry,
295298
out:
296299
clear_nlink(inode);
297300
unlock_new_inode(inode);
301+
make_bad_inode(inode);
298302
iput(inode);
299303
alloc_nid_failed(sbi, inode->i_ino);
300304
return err;
@@ -335,6 +339,7 @@ static int f2fs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
335339
clear_inode_flag(F2FS_I(inode), FI_INC_LINK);
336340
clear_nlink(inode);
337341
unlock_new_inode(inode);
342+
make_bad_inode(inode);
338343
iput(inode);
339344
alloc_nid_failed(sbi, inode->i_ino);
340345
return err;
@@ -382,6 +387,7 @@ static int f2fs_mknod(struct inode *dir, struct dentry *dentry,
382387
out:
383388
clear_nlink(inode);
384389
unlock_new_inode(inode);
390+
make_bad_inode(inode);
385391
iput(inode);
386392
alloc_nid_failed(sbi, inode->i_ino);
387393
return err;

fs/f2fs/super.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,20 @@ static struct inode *f2fs_alloc_inode(struct super_block *sb)
9898
return &fi->vfs_inode;
9999
}
100100

101+
static int f2fs_drop_inode(struct inode *inode)
102+
{
103+
/*
104+
* This is to avoid a deadlock condition like below.
105+
* writeback_single_inode(inode)
106+
* - f2fs_write_data_page
107+
* - f2fs_gc -> iput -> evict
108+
* - inode_wait_for_writeback(inode)
109+
*/
110+
if (!inode_unhashed(inode) && inode->i_state & I_SYNC)
111+
return 0;
112+
return generic_drop_inode(inode);
113+
}
114+
101115
static void f2fs_i_callback(struct rcu_head *head)
102116
{
103117
struct inode *inode = container_of(head, struct inode, i_rcu);
@@ -216,6 +230,7 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
216230

217231
static struct super_operations f2fs_sops = {
218232
.alloc_inode = f2fs_alloc_inode,
233+
.drop_inode = f2fs_drop_inode,
219234
.destroy_inode = f2fs_destroy_inode,
220235
.write_inode = f2fs_write_inode,
221236
.show_options = f2fs_show_options,

0 commit comments

Comments
 (0)