Btrfs: fix deadlock on umount by umount_prepare interface
Subsystems (2)
RFC PATCH 2/2 Btrfs: fix deadlock on umount by umount_prepare interface
The reason the deadlock is that:
Task Btrfs-cleaner
umount()
down_write(&s->s_umount)
close_ctree()
wait for the end of
btrfs-cleaner
start_transaction
reserve space
shrink_delalloc()
writeback_inodes_sb_nr_if_idle()
down_read(&sb->s_umount)So, the deadlock has happened.
The safest way to fix this problem is to close the btrfs-cleaner before the umount is ready to continue. Since we have introduced umount_prepare interface into vfs before, we can fix this problem by it.
--- fs/btrfs/disk-io.c | 15 --------------- fs/btrfs/super.c | 22 ++++++++++++++++++++++ 2 files changed, 22 insertions(+), 15 deletions(-)
fs/btrfs/disk-io.c +0 -15
@@ -3017,21 +3017,6 @@ int close_ctree(struct btrfs_root *root)struct btrfs_fs_info *fs_info = root->fs_info;int ret; - fs_info->closing =1 ; -smp_mb (); - -/* pause restriper - we want to resume on mount */ -btrfs_pause_balance (root->fs_info); - -btrfs_scrub_cancel (root); - -/* wait for any defraggers to finish */ -wait_event (fs_info->transaction_wait, - (atomic_read (&fs_info->defrag_running) ==0 )); - -/* clear out the rbtree of defraggable inodes */ -btrfs_run_defrag_inodes (fs_info); -/* * Here come 2 situations when btrfs is broken to flip readonly: *
fs/btrfs/super.c +22 -0
@@ -145,6 +145,27 @@ void __btrfs_std_error(struct btrfs_fs_info *fs_info, const char *function,btrfs_handle_error (fs_info); } +static void btrfs_umount_prepare (struct super_block *sb) +{ +struct btrfs_root *root =btrfs_sb (sb)->tree_root; +struct btrfs_fs_info *fs_info = root->fs_info; + + fs_info->closing =1 ; +smp_mb (); + +/* pause restriper - we want to resume on mount */ +btrfs_pause_balance (root->fs_info); + +btrfs_scrub_cancel (root); + +/* wait for any defraggers to finish */ +wait_event (fs_info->transaction_wait, + (atomic_read (&fs_info->defrag_running) ==0 )); + +/* clear out the rbtree of defraggable inodes */ +btrfs_run_defrag_inodes (fs_info); +} +static void btrfs_put_super (struct super_block *sb) { (void )close_ctree (btrfs_sb (sb)->tree_root);
@@ -1312,6 +1333,7 @@ static void btrfs_fs_dirty_inode(struct inode *inode, int flags)static const struct super_operations btrfs_super_ops = { .drop_inode = btrfs_drop_inode, .evict_inode = btrfs_evict_inode, + .umount_prepare = btrfs_umount_prepare, .put_super = btrfs_put_super, .sync_fs = btrfs_sync_fs, .show_options = btrfs_show_options,
Signature · 1 line
1.7.6.5
Quoted 12 lines · Miao Xie
The reason the deadlock is that:
Task Btrfs-cleaner
umount()down_write(&s->s_umount) close_ctree() wait for the end of btrfs-cleaner start_transaction reserve space shrink_delalloc() writeback_inodes_sb_nr_if_idle() down_read(&sb->s_umount)
Quoted 1 line
So, the deadlock has happened.
Every time a deadlock involving writeback_inodes_sb...if_idle() comes up, I give the same response. If the s_umount is write locked, then the sb is not idle. IOWs, writeback_inodes_sb...if_idle() should be doing down_read_trylock(), not down_read().
Cheers,
Dave.
Signature · 2 lines
Dave Chinner [email protected]
Quoted 15 lines · Dave Chinner
Quoted 12 lines · Miao Xie
The reason the deadlock is that:
Task Btrfs-cleaner
umount()down_write(&s->s_umount) close_ctree() wait for the end of btrfs-cleaner start_transaction reserve space shrink_delalloc() writeback_inodes_sb_nr_if_idle() down_read(&sb->s_umount)Quoted 1 line
So, the deadlock has happened.
Quoted 4 lines
Every time a deadlock involving writeback_inodes_sb...if_idle() comes up, I give the same response. If the
s_umountis write locked, then the sb is not idle. IOWs, writeback_inodes_sb...if_idle() should be doingdown_read_trylock(), notdown_read().
Someone did this work several months ago, but those patches have not been applied until now, so...
https://lkml.org/lkml/2011/12/8/264
Thanks
Miao
Quoted 16 lines · Miao Xie
Quoted 15 lines · Dave Chinner
Quoted 13 lines · Miao Xie
The reason the deadlock is that:
Task Btrfs-cleaner
umount()down_write(&s->s_umount) close_ctree() wait for the end of btrfs-cleaner start_transaction reserve space shrink_delalloc() writeback_inodes_sb_nr_if_idle() down_read(&sb->s_umount)So, the deadlock has happened.
Quoted 7 lines
Quoted 4 lines
Every time a deadlock involving writeback_inodes_sb...if_idle() comes up, I give the same response. If the
s_umountis write locked, then the sb is not idle. IOWs, writeback_inodes_sb...if_idle() should be doingdown_read_trylock(), notdown_read().Someone did this work several months ago, but those patches have not been applied until now, so...
... work to get them into the current/next release.
Cheers,
Dave.
Signature · 2 lines
Dave Chinner [email protected]