aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block/drbd/drbd_receiver.c
diff options
context:
space:
mode:
authorLars Ellenberg <lars.ellenberg@linbit.com>2010-10-16 06:13:47 -0400
committerPhilipp Reisner <philipp.reisner@linbit.com>2010-10-22 09:46:11 -0400
commit82f59cc6353889b426cf13b6596d5a3d100fa09e (patch)
tree6d5a678516334f0a37a56a509b84322a0352719b /drivers/block/drbd/drbd_receiver.c
parent3beec1d446fba335f07787636920892dd3b2c658 (diff)
drbd: fix potential deadlock on detach
If we have contention in drbd_al_begin_iod (heavy randon IO), an administrative request to detach the disk may deadlock for similar reasons as the recently fixed deadlock if detaching because of IO-error. The approach taken here is to either go through the intermediate cleanup state D_FAILED, or first lock out application io, don't just go directly to D_DISKLESS. We need an additional state bit (WAS_IO_ERROR) to distinguish the -> D_FAILED because of IO-error from other failures. Sanitize D_ATTACHING -> D_FAILED to D_ATTACHING -> D_DISKLESS. If only attaching, ldev may be missing still, but would be referenced from within the after_state_ch for -> D_FAILED, potentially dereferencing a NULL pointer. Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com> Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
Diffstat (limited to 'drivers/block/drbd/drbd_receiver.c')
-rw-r--r--drivers/block/drbd/drbd_receiver.c2
1 files changed, 1 insertions, 1 deletions
diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c
index 6ec922c623a1..04a823b01da5 100644
--- a/drivers/block/drbd/drbd_receiver.c
+++ b/drivers/block/drbd/drbd_receiver.c
@@ -3363,7 +3363,7 @@ static int receive_state(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned
3363 if (ns.conn == C_MASK) { 3363 if (ns.conn == C_MASK) {
3364 ns.conn = C_CONNECTED; 3364 ns.conn = C_CONNECTED;
3365 if (mdev->state.disk == D_NEGOTIATING) { 3365 if (mdev->state.disk == D_NEGOTIATING) {
3366 drbd_force_state(mdev, NS(disk, D_DISKLESS)); 3366 drbd_force_state(mdev, NS(disk, D_FAILED));
3367 } else if (peer_state.disk == D_NEGOTIATING) { 3367 } else if (peer_state.disk == D_NEGOTIATING) {
3368 dev_err(DEV, "Disk attach process on the peer node was aborted.\n"); 3368 dev_err(DEV, "Disk attach process on the peer node was aborted.\n");
3369 peer_state.disk = D_DISKLESS; 3369 peer_state.disk = D_DISKLESS;