From: Qu Wenruo Date: Mon, 19 Jan 2015 07:42:41 +0000 (+0800) Subject: btrfs: Don't call btrfs_start_transaction() on frozen fs to avoid deadlock. X-Git-Url: http://git.cdn.openwrt.org/?a=commitdiff_plain;h=a53f4f8e9c8eb;p=openwrt%2Fstaging%2Fblogic.git btrfs: Don't call btrfs_start_transaction() on frozen fs to avoid deadlock. Commit 6b5fe46dfa52 (btrfs: do commit in sync_fs if there are pending changes) will call btrfs_start_transaction() in sync_fs(), to handle some operations needed to be done in next transaction. However this can cause deadlock if the filesystem is frozen, with the following sys_r+w output: [ 143.255932] Call Trace: [ 143.255936] [] schedule+0x29/0x70 [ 143.255939] [] __sb_start_write+0xb3/0x100 [ 143.255971] [] start_transaction+0x2e6/0x5a0 [btrfs] [ 143.255992] [] btrfs_start_transaction+0x1b/0x20 [btrfs] [ 143.256003] [] btrfs_sync_fs+0xca/0xd0 [btrfs] [ 143.256007] [] sync_fs_one_sb+0x20/0x30 [ 143.256011] [] iterate_supers+0xe1/0xf0 [ 143.256014] [] sys_sync+0x55/0x90 [ 143.256017] [] system_call_fastpath+0x12/0x17 [ 143.256111] Call Trace: [ 143.256114] [] schedule+0x29/0x70 [ 143.256119] [] rwsem_down_write_failed+0x1c5/0x2d0 [ 143.256123] [] call_rwsem_down_write_failed+0x13/0x20 [ 143.256131] [] thaw_super+0x28/0xc0 [ 143.256135] [] do_vfs_ioctl+0x3f5/0x540 [ 143.256187] [] SyS_ioctl+0x91/0xb0 [ 143.256213] [] system_call_fastpath+0x12/0x17 The reason is like the following: (Holding s_umount) VFS sync_fs staff: |- btrfs_sync_fs() |- btrfs_start_transaction() |- sb_start_intwrite() (Waiting thaw_fs to unfreeze) VFS thaw_fs staff: thaw_fs() (Waiting sync_fs to release s_umount) So deadlock happens. This can be easily triggered by fstest/generic/068 with inode_cache mount option. The fix is to check if the fs is frozen, if the fs is frozen, just return and waiting for the next transaction. Cc: David Sterba Reported-by: Gui Hecheng Signed-off-by: Qu Wenruo [enhanced comment, changed to SB_FREEZE_WRITE] Signed-off-by: David Sterba Signed-off-by: Chris Mason --- diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index c86fb5438454..6f49b2872a64 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -1000,6 +1000,16 @@ int btrfs_sync_fs(struct super_block *sb, int wait) */ if (fs_info->pending_changes == 0) return 0; + /* + * A non-blocking test if the fs is frozen. We must not + * start a new transaction here otherwise a deadlock + * happens. The pending operations are delayed to the + * next commit after thawing. + */ + if (__sb_start_write(sb, SB_FREEZE_WRITE, false)) + __sb_end_write(sb, SB_FREEZE_WRITE); + else + return 0; trans = btrfs_start_transaction(root, 0); } if (IS_ERR(trans))