]> git.hungrycats.org Git - linux/commitdiff
Btrfs: fix possible deadlock caused by pending I/O in plug list
authorMiao Xie <miaox@cn.fujitsu.com>
Tue, 25 Nov 2014 11:30:05 +0000 (19:30 +0800)
committerZygo Blaxell <zblaxell@serenity.furryterror.org>
Wed, 3 Dec 2014 15:15:23 +0000 (10:15 -0500)
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@cn.fujitsu.com>
(cherry picked from commit 670abc8e2ee652a411979ed930d72a17fd37b179)

fs/btrfs/dev-replace.c

index d738ff8ab81c7b6a515412dd3ed72698f1e9f005..58d7b66e93ed004faf5d4c021cc28cf2d86b3583 100644 (file)
@@ -917,16 +917,23 @@ void btrfs_bio_counter_dec(struct btrfs_fs_info *fs_info)
                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;
        }