The increase/decrease of bio counter is on the I/O path, so we should use io_schedule() instead of schedule(), or the deadlock might be triggered by the pending I/O in the plug list. io_schedule() can help us because it will flush all the pending I/O before the task is going to sleep.
Signed-off-by: Miao Xie <mi...@cn.fujitsu.com> --- Changelog v2 -> v3: - New patch to fix possible deadlock caused by the pending bios in the plug list when the io submitters were going to sleep. Changelog v1 -> v2: - None. --- fs/btrfs/dev-replace.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c index fa27b4e..894796a 100644 --- a/fs/btrfs/dev-replace.c +++ b/fs/btrfs/dev-replace.c @@ -928,16 +928,23 @@ void btrfs_bio_counter_sub(struct btrfs_fs_info *fs_info, s64 amount) wake_up(&fs_info->replace_wait); } +#define btrfs_wait_event_io(wq, condition) \ +do { \ + if (condition) \ + break; \ + (void)___wait_event(wq, condition, TASK_UNINTERRUPTIBLE, 0, 0, \ + io_schedule()); \ +} while (0) + void btrfs_bio_counter_inc_blocked(struct btrfs_fs_info *fs_info) { - DEFINE_WAIT(wait); again: percpu_counter_inc(&fs_info->bio_counter); if (test_bit(BTRFS_FS_STATE_DEV_REPLACING, &fs_info->fs_state)) { btrfs_bio_counter_dec(fs_info); - wait_event(fs_info->replace_wait, - !test_bit(BTRFS_FS_STATE_DEV_REPLACING, - &fs_info->fs_state)); + btrfs_wait_event_io(fs_info->replace_wait, + !test_bit(BTRFS_FS_STATE_DEV_REPLACING, + &fs_info->fs_state)); goto again; } -- 1.9.3 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html