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 <miaox@xxxxxxxxxxxxxx>
---
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 majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html