summaryrefslogtreecommitdiffstats
path: root/drivers/block/drbd
diff options
context:
space:
mode:
authorLars Ellenberg <lars.ellenberg@linbit.com>2018-12-20 11:23:37 -0500
committerJens Axboe <axboe@kernel.dk>2018-12-20 11:51:30 -0500
commitf708bd08ecbdc23d03aaedf5b3311ebe44cfdb50 (patch)
tree7596bad3868b3900bce55dfa4f0938dae538f594 /drivers/block/drbd
parenta2823ea92024e6cb8124bf49a055261a8508a795 (diff)
drbd: do not block when adjusting "disk-options" while IO is frozen
"suspending" IO is overloaded. It can mean "do not allow new requests" (obviously), but it also may mean "must not complete pending IO", for example while the fencing handlers do their arbitration. When adjusting disk options, we suspend io (disallow new requests), then wait for the activity-log to become unused (drain all IO completions), and possibly replace it with a new activity log of different size. If the other "suspend IO" aspect is active, pending IO completions won't happen, and we would block forever (unkillable drbdsetup process). Fix this by skipping the activity log adjustment if the "al-extents" setting did not change. Also, in case it did change, fail early without blocking if it looks like we would block forever. Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com> Signed-off-by: Jens Axboe <axboe@kernel.dk>
Diffstat (limited to 'drivers/block/drbd')
-rw-r--r--drivers/block/drbd/drbd_nl.c37
1 files changed, 29 insertions, 8 deletions
diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c
index 4b934e543e2d..1958eb33b643 100644
--- a/drivers/block/drbd/drbd_nl.c
+++ b/drivers/block/drbd/drbd_nl.c
@@ -1540,6 +1540,30 @@ static void sanitize_disk_conf(struct drbd_device *device, struct disk_conf *dis
1540 } 1540 }
1541} 1541}
1542 1542
1543static int disk_opts_check_al_size(struct drbd_device *device, struct disk_conf *dc)
1544{
1545 int err = -EBUSY;
1546
1547 if (device->act_log &&
1548 device->act_log->nr_elements == dc->al_extents)
1549 return 0;
1550
1551 drbd_suspend_io(device);
1552 /* If IO completion is currently blocked, we would likely wait
1553 * "forever" for the activity log to become unused. So we don't. */
1554 if (atomic_read(&device->ap_bio_cnt))
1555 goto out;
1556
1557 wait_event(device->al_wait, lc_try_lock(device->act_log));
1558 drbd_al_shrink(device);
1559 err = drbd_check_al_size(device, dc);
1560 lc_unlock(device->act_log);
1561 wake_up(&device->al_wait);
1562out:
1563 drbd_resume_io(device);
1564 return err;
1565}
1566
1543int drbd_adm_disk_opts(struct sk_buff *skb, struct genl_info *info) 1567int drbd_adm_disk_opts(struct sk_buff *skb, struct genl_info *info)
1544{ 1568{
1545 struct drbd_config_context adm_ctx; 1569 struct drbd_config_context adm_ctx;
@@ -1602,15 +1626,12 @@ int drbd_adm_disk_opts(struct sk_buff *skb, struct genl_info *info)
1602 } 1626 }
1603 } 1627 }
1604 1628
1605 drbd_suspend_io(device); 1629 err = disk_opts_check_al_size(device, new_disk_conf);
1606 wait_event(device->al_wait, lc_try_lock(device->act_log));
1607 drbd_al_shrink(device);
1608 err = drbd_check_al_size(device, new_disk_conf);
1609 lc_unlock(device->act_log);
1610 wake_up(&device->al_wait);
1611 drbd_resume_io(device);
1612
1613 if (err) { 1630 if (err) {
1631 /* Could be just "busy". Ignore?
1632 * Introduce dedicated error code? */
1633 drbd_msg_put_info(adm_ctx.reply_skb,
1634 "Try again without changing current al-extents setting");
1614 retcode = ERR_NOMEM; 1635 retcode = ERR_NOMEM;
1615 goto fail_unlock; 1636 goto fail_unlock;
1616 } 1637 }