diff options
author | Lars Ellenberg <lars.ellenberg@linbit.com> | 2011-05-02 04:45:05 -0400 |
---|---|---|
committer | Philipp Reisner <philipp.reisner@linbit.com> | 2012-11-08 10:53:00 -0500 |
commit | f3dfa40a67c354a5886c5ae53a9c5d3a2c6fd06e (patch) | |
tree | e85ab6fe143681814b395ed5ece180df8d090201 /drivers/block/drbd/drbd_receiver.c | |
parent | 88104ca458dff8ed7db935936b91b9af4422c9cd (diff) |
drbd: fix race when forcefully disconnecting
If a forced disconnect hits a restarting receiver right after it passed
its final "if (C_DISCONNECTING)" test in drbdd_init(), but before it was
actually restarted by drbd_thread_setup, we could be left with a
connection stuck in C_DISCONNECTING, never reaching C_STANDALONE,
which would be necessary to take it down or reconfigure it.
Move the last cleanup into w_after_conn_state_ch(), and do an additional
state change request in conn_try_disconnect(), just in case.
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.c | 14 |
1 files changed, 1 insertions, 13 deletions
diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 9c8bcce0e684..956cdda93430 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c | |||
@@ -4213,20 +4213,8 @@ static void drbd_disconnect(struct drbd_tconn *tconn) | |||
4213 | 4213 | ||
4214 | spin_unlock_irq(&tconn->req_lock); | 4214 | spin_unlock_irq(&tconn->req_lock); |
4215 | 4215 | ||
4216 | if (oc == C_DISCONNECTING) { | 4216 | if (oc == C_DISCONNECTING) |
4217 | struct net_conf *old_conf; | ||
4218 | |||
4219 | mutex_lock(&tconn->net_conf_update); | ||
4220 | old_conf = tconn->net_conf; | ||
4221 | rcu_assign_pointer(tconn->net_conf, NULL); | ||
4222 | conn_free_crypto(tconn); | ||
4223 | mutex_unlock(&tconn->net_conf_update); | ||
4224 | |||
4225 | synchronize_rcu(); | ||
4226 | kfree(old_conf); | ||
4227 | |||
4228 | conn_request_state(tconn, NS(conn, C_STANDALONE), CS_VERBOSE | CS_HARD); | 4217 | conn_request_state(tconn, NS(conn, C_STANDALONE), CS_VERBOSE | CS_HARD); |
4229 | } | ||
4230 | } | 4218 | } |
4231 | 4219 | ||
4232 | static int drbd_disconnected(int vnr, void *p, void *data) | 4220 | static int drbd_disconnected(int vnr, void *p, void *data) |