diff options
author | Philipp Reisner <philipp.reisner@linbit.com> | 2013-03-27 09:08:40 -0400 |
---|---|---|
committer | Jens Axboe <axboe@kernel.dk> | 2013-03-28 12:10:25 -0400 |
commit | 2bd5ed5d6713594eb2b4d234d01217d506279c7d (patch) | |
tree | afdeb5ec00f0103f8bb43fea389e3cb18ee958c3 /drivers | |
parent | bb45185de2e90af63a7bc48855de6f870cc216fc (diff) |
drbd: Fix disconnect to keep the peer disk state if connection breaks during operation
The issue was that if the connection broke while we did the
gracefull state change to C_DISCONNECTING (C_TEARDOWN), then
we returned a success code from the state engine. (SS_CW_NO_NEED)
The result of that is that we missed to call the fence-peer
script in such a case.
Fixed that by introducing a new error code (SS_OUTDATE_WO_CONN).
This one should never reach back into user space.
Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com>
Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/block/drbd/drbd_nl.c | 7 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_state.c | 14 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_strings.c | 1 |
3 files changed, 13 insertions, 9 deletions
diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index 56bafdcd943e..39e9a91a8f31 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c | |||
@@ -2198,8 +2198,11 @@ static enum drbd_state_rv conn_try_disconnect(struct drbd_tconn *tconn, bool for | |||
2198 | return SS_SUCCESS; | 2198 | return SS_SUCCESS; |
2199 | case SS_PRIMARY_NOP: | 2199 | case SS_PRIMARY_NOP: |
2200 | /* Our state checking code wants to see the peer outdated. */ | 2200 | /* Our state checking code wants to see the peer outdated. */ |
2201 | rv = conn_request_state(tconn, NS2(conn, C_DISCONNECTING, | 2201 | rv = conn_request_state(tconn, NS2(conn, C_DISCONNECTING, pdsk, D_OUTDATED), 0); |
2202 | pdsk, D_OUTDATED), CS_VERBOSE); | 2202 | |
2203 | if (rv == SS_OUTDATE_WO_CONN) /* lost connection before graceful disconnect succeeded */ | ||
2204 | rv = conn_request_state(tconn, NS(conn, C_DISCONNECTING), CS_VERBOSE); | ||
2205 | |||
2203 | break; | 2206 | break; |
2204 | case SS_CW_FAILED_BY_PEER: | 2207 | case SS_CW_FAILED_BY_PEER: |
2205 | /* The peer probably wants to see us outdated. */ | 2208 | /* The peer probably wants to see us outdated. */ |
diff --git a/drivers/block/drbd/drbd_state.c b/drivers/block/drbd/drbd_state.c index 22e259f34370..90c5be2b1d30 100644 --- a/drivers/block/drbd/drbd_state.c +++ b/drivers/block/drbd/drbd_state.c | |||
@@ -642,6 +642,10 @@ is_valid_soft_transition(union drbd_state os, union drbd_state ns, struct drbd_t | |||
642 | && os.conn < C_WF_REPORT_PARAMS) | 642 | && os.conn < C_WF_REPORT_PARAMS) |
643 | rv = SS_NEED_CONNECTION; /* No NetworkFailure -> SyncTarget etc... */ | 643 | rv = SS_NEED_CONNECTION; /* No NetworkFailure -> SyncTarget etc... */ |
644 | 644 | ||
645 | if (ns.conn == C_DISCONNECTING && ns.pdsk == D_OUTDATED && | ||
646 | os.conn < C_CONNECTED && os.pdsk > D_OUTDATED) | ||
647 | rv = SS_OUTDATE_WO_CONN; | ||
648 | |||
645 | return rv; | 649 | return rv; |
646 | } | 650 | } |
647 | 651 | ||
@@ -1748,13 +1752,9 @@ _conn_rq_cond(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state | |||
1748 | if (test_and_clear_bit(CONN_WD_ST_CHG_FAIL, &tconn->flags)) | 1752 | if (test_and_clear_bit(CONN_WD_ST_CHG_FAIL, &tconn->flags)) |
1749 | return SS_CW_FAILED_BY_PEER; | 1753 | return SS_CW_FAILED_BY_PEER; |
1750 | 1754 | ||
1751 | rv = tconn->cstate != C_WF_REPORT_PARAMS ? SS_CW_NO_NEED : SS_UNKNOWN_ERROR; | 1755 | rv = conn_is_valid_transition(tconn, mask, val, 0); |
1752 | 1756 | if (rv == SS_SUCCESS && tconn->cstate == C_WF_REPORT_PARAMS) | |
1753 | if (rv == SS_UNKNOWN_ERROR) | 1757 | rv = SS_UNKNOWN_ERROR; /* continue waiting */ |
1754 | rv = conn_is_valid_transition(tconn, mask, val, 0); | ||
1755 | |||
1756 | if (rv == SS_SUCCESS) | ||
1757 | rv = SS_UNKNOWN_ERROR; /* cont waiting, otherwise fail. */ | ||
1758 | 1758 | ||
1759 | return rv; | 1759 | return rv; |
1760 | } | 1760 | } |
diff --git a/drivers/block/drbd/drbd_strings.c b/drivers/block/drbd/drbd_strings.c index 9a664bd27404..58e08ff2b2ce 100644 --- a/drivers/block/drbd/drbd_strings.c +++ b/drivers/block/drbd/drbd_strings.c | |||
@@ -89,6 +89,7 @@ static const char *drbd_state_sw_errors[] = { | |||
89 | [-SS_LOWER_THAN_OUTDATED] = "Disk state is lower than outdated", | 89 | [-SS_LOWER_THAN_OUTDATED] = "Disk state is lower than outdated", |
90 | [-SS_IN_TRANSIENT_STATE] = "In transient state, retry after next state change", | 90 | [-SS_IN_TRANSIENT_STATE] = "In transient state, retry after next state change", |
91 | [-SS_CONCURRENT_ST_CHG] = "Concurrent state changes detected and aborted", | 91 | [-SS_CONCURRENT_ST_CHG] = "Concurrent state changes detected and aborted", |
92 | [-SS_OUTDATE_WO_CONN] = "Need a connection for a graceful disconnect/outdate peer", | ||
92 | [-SS_O_VOL_PEER_PRI] = "Other vol primary on peer not allowed by config", | 93 | [-SS_O_VOL_PEER_PRI] = "Other vol primary on peer not allowed by config", |
93 | }; | 94 | }; |
94 | 95 | ||