diff options
| -rw-r--r-- | drivers/block/drbd/drbd_int.h | 7 | ||||
| -rw-r--r-- | drivers/block/drbd/drbd_main.c | 16 | ||||
| -rw-r--r-- | drivers/block/drbd/drbd_nl.c | 6 |
3 files changed, 29 insertions, 0 deletions
diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 79c69ebb0653..5136510ec8be 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h | |||
| @@ -850,6 +850,13 @@ enum { | |||
| 850 | AL_SUSPENDED, /* Activity logging is currently suspended. */ | 850 | AL_SUSPENDED, /* Activity logging is currently suspended. */ |
| 851 | AHEAD_TO_SYNC_SOURCE, /* Ahead -> SyncSource queued */ | 851 | AHEAD_TO_SYNC_SOURCE, /* Ahead -> SyncSource queued */ |
| 852 | STATE_SENT, /* Do not change state/UUIDs while this is set */ | 852 | STATE_SENT, /* Do not change state/UUIDs while this is set */ |
| 853 | |||
| 854 | CALLBACK_PENDING, /* Whether we have a call_usermodehelper(, UMH_WAIT_PROC) | ||
| 855 | * pending, from drbd worker context. | ||
| 856 | * If set, bdi_write_congested() returns true, | ||
| 857 | * so shrink_page_list() would not recurse into, | ||
| 858 | * and potentially deadlock on, this drbd worker. | ||
| 859 | */ | ||
| 853 | }; | 860 | }; |
| 854 | 861 | ||
| 855 | struct drbd_bitmap; /* opaque for drbd_conf */ | 862 | struct drbd_bitmap; /* opaque for drbd_conf */ |
diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 5bebe8d8ace3..41ccb580d5ac 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c | |||
| @@ -3553,6 +3553,22 @@ static int drbd_congested(void *congested_data, int bdi_bits) | |||
| 3553 | goto out; | 3553 | goto out; |
| 3554 | } | 3554 | } |
| 3555 | 3555 | ||
| 3556 | if (test_bit(CALLBACK_PENDING, &mdev->flags)) { | ||
| 3557 | r |= (1 << BDI_async_congested); | ||
| 3558 | /* Without good local data, we would need to read from remote, | ||
| 3559 | * and that would need the worker thread as well, which is | ||
| 3560 | * currently blocked waiting for that usermode helper to | ||
| 3561 | * finish. | ||
| 3562 | */ | ||
| 3563 | if (!get_ldev_if_state(mdev, D_UP_TO_DATE)) | ||
| 3564 | r |= (1 << BDI_sync_congested); | ||
| 3565 | else | ||
| 3566 | put_ldev(mdev); | ||
| 3567 | r &= bdi_bits; | ||
| 3568 | reason = 'c'; | ||
| 3569 | goto out; | ||
| 3570 | } | ||
| 3571 | |||
| 3556 | if (get_ldev(mdev)) { | 3572 | if (get_ldev(mdev)) { |
| 3557 | q = bdev_get_queue(mdev->ldev->backing_bdev); | 3573 | q = bdev_get_queue(mdev->ldev->backing_bdev); |
| 3558 | r = bdi_congested(&q->backing_dev_info, bdi_bits); | 3574 | r = bdi_congested(&q->backing_dev_info, bdi_bits); |
diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index 40a1c4f07190..03fc853be2b9 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c | |||
| @@ -147,6 +147,9 @@ int drbd_khelper(struct drbd_conf *mdev, char *cmd) | |||
| 147 | char *argv[] = {usermode_helper, cmd, mb, NULL }; | 147 | char *argv[] = {usermode_helper, cmd, mb, NULL }; |
| 148 | int ret; | 148 | int ret; |
| 149 | 149 | ||
| 150 | if (current == mdev->worker.task) | ||
| 151 | set_bit(CALLBACK_PENDING, &mdev->flags); | ||
| 152 | |||
| 150 | snprintf(mb, 12, "minor-%d", mdev_to_minor(mdev)); | 153 | snprintf(mb, 12, "minor-%d", mdev_to_minor(mdev)); |
| 151 | 154 | ||
| 152 | if (get_net_conf(mdev)) { | 155 | if (get_net_conf(mdev)) { |
| @@ -189,6 +192,9 @@ int drbd_khelper(struct drbd_conf *mdev, char *cmd) | |||
| 189 | usermode_helper, cmd, mb, | 192 | usermode_helper, cmd, mb, |
| 190 | (ret >> 8) & 0xff, ret); | 193 | (ret >> 8) & 0xff, ret); |
| 191 | 194 | ||
| 195 | if (current == mdev->worker.task) | ||
| 196 | clear_bit(CALLBACK_PENDING, &mdev->flags); | ||
| 197 | |||
| 192 | if (ret < 0) /* Ignore any ERRNOs we got. */ | 198 | if (ret < 0) /* Ignore any ERRNOs we got. */ |
| 193 | ret = 0; | 199 | ret = 0; |
| 194 | 200 | ||
