[PATCH RESEND] drbd: consider resync after peer forced Primary from Outdated/Outdated

Su Yue <[email protected]>
Newsgroups dev.linux.lists.drbd-dev
Message-ID <[email protected]>
When a node is force-promoted to Primary with --force while both nodes
are Outdated, it generates a new current data generation UUID.

If they are connected, the state change transition updates the peer disk
state to UpToDate. However, because if both nodes were Outdated,
the state machine does not automatically trigger a sync handshake
(the CONSIDER_RESYNC flag is only set if both disks were D_INCONSISTENT).

CONSIDER_RESYNC was only armed when both sides' previous disk state was
D_INCONSISTENT. When both disks are D_OUTDATED instead (e.g. after both
nodes were explicitly outdated and reconnected) and one side is then
force-promoted to Primary/D_UP_TO_DATE, only the promoted node redoes
the UUID handshake and moves to L_WF_BITMAP_S. The peer never arms
CONSIDER_RESYNC, stays in L_ESTABLISHED, and drops the
incoming bitmap in receive_bitmap() with "unexpected repl_state
(Established) in receive_bitmap". The two nodes then diverge
permanently: the Primary stuck at WFBitMapS/Consistent, the Secondary
falsely reporting UpToDate/UpToDate.

To reproduce:
====================================
ssh node2 drbdadm down drbd0
sleep 1
drbdadm down drbd0
sleep 1
drbdadm outdate drbd0 && drbdadm up drbd0
sleep 1
ssh node2 "drbdadm outdate drbd0 && drbdadm up drbd0 "
sleep 1
drbdadm status
echo "node2 drbdadm status:"
ssh node2 drbdadm status
drbdadm primary --force drbd0
drbdadm status
ssh node2 drbdadm status
====================================

Fix this by expanding the CONSIDER_RESYNC check in finish_state_change()
to also cover D_OUTDATED disk states when the peer is force-promoted to
Primary and UpToDate. This successfully triggers the subsequent handshake,
completing the resync and elevating both nodes disks to UpToDate cleanly.

Signed-off-by: Su Yue <[email protected]>
Reviewed-by: Heming Zhao <[email protected]>
Co-Authored-By: Claude Fable 5 <[email protected]>
Co-Authored-By: Gemini <[email protected]>
---
 drbd/drbd_state.c | 13 ++++++++++---
 1 file changed, 10 insertions(+), 3 deletions(-)

diff --git a/drbd/drbd_state.c b/drbd/drbd_state.c
index e7f9cab01c58..73cd2807d1fc 100644
--- a/drbd/drbd_state.c
+++ b/drbd/drbd_state.c
@@ -3147,9 +3147,16 @@ static void finish_state_change(struct drbd_resource *resource, const char *tag)
 					}
 				}
 
-				/* Peer was forced D_UP_TO_DATE & R_PRIMARY, consider to resync */
-				if (disk_state[OLD] == D_INCONSISTENT &&
-				    peer_disk_state[OLD] == D_INCONSISTENT && peer_disk_state[NEW] == D_UP_TO_DATE &&
+				/* Peer was forced D_UP_TO_DATE & R_PRIMARY, consider to resync.
+				 * Also cover D_OUTDATED, not just D_INCONSISTENT: e.g. after both
+				 * nodes were D_OUTDATED (both --outdate'd, then reconnected) and
+				 * one side is force-promoted to Primary/D_UP_TO_DATE, we still
+				 * need to redo the handshake here, or we get stuck: the newly
+				 * forced Primary moves on to L_WF_BITMAP_S and sends its bitmap,
+				 * while we never armed CONSIDER_RESYNC and stay in L_ESTABLISHED. */
+				if ((disk_state[OLD] == D_INCONSISTENT || disk_state[OLD] == D_OUTDATED) &&
+				    (peer_disk_state[OLD] == D_INCONSISTENT || peer_disk_state[OLD] == D_OUTDATED) &&
+				    peer_disk_state[NEW] == D_UP_TO_DATE &&
 				    peer_role[OLD] == R_SECONDARY && peer_role[NEW] == R_PRIMARY)
 					set_bit(CONSIDER_RESYNC, &peer_device->flags);
 
-- 
2.54.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.