[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