legionxiong opened a new issue, #3405:
URL: https://github.com/apache/brpc/issues/3405

   ## Description
   
   There is a race when an RDMA connection falls back to TCP. The fallback is
   represented by two separate fields:
   
   - `RdmaEndpoint::_state = FALLBACK_TCP`
   - `Socket::_rdma_state = RDMA_OFF`
   
   Some fallback paths publish these fields in the following order:
   
   ```cpp
   ep->_state = FALLBACK_TCP;
   s->_rdma_state = Socket::RDMA_OFF;
   ```
   
   Meanwhile, the TCP event path uses `RdmaEndpoint::_state` to decide whether 
it
   can dispatch normal TCP reads:
   
   ```cpp
   void RdmaEndpoint::OnNewDataFromTcp(Socket* socket) {
       // ...
       if (ep->_state == FALLBACK_TCP) {
           InputMessenger::OnNewMessages(socket);
           return;
       }
   }
   ```
   
   `InputMessenger::OnNewMessages()` can eventually call `Socket::DoRead()`,
   which requires the socket-level RDMA state to have already transitioned to
   `RDMA_OFF`:
   
   ```cpp
   CHECK(_rdma_state == RDMA_OFF);
   ```
   
   A concurrent TCP event can therefore observe `FALLBACK_TCP` before
   `_rdma_state` has been updated and trigger the CHECK.
   
   In addition, `RdmaEndpoint::_state` is currently a non-atomic field despite
   being accessed by the RDMA handshake bthread, TCP event handling, and RDMA
   completion handling.
   
   ## Observed failure
   
   The process aborts at:
   
   ```cpp
   ssize_t Socket::DoRead(size_t size_hint) {
       // ...
       CHECK(_rdma_state == RDMA_OFF);
       return _read_buf.append_from_file_descriptor(fd(), size_hint);
   }
   ```
   
   The affected downstream binary was built from a branch containing commit
   `53359cb6`.
   
   ## Race sequence
   
   ```mermaid
   sequenceDiagram
       participant H as RDMA handshake bthread
       participant E as TCP event bthread
       participant M as InputMessenger
       participant S as Socket::DoRead
   
       Note over H: RDMA negotiation fails<br/>and starts TCP fallback
   
       H->>H: ep->_state = FALLBACK_TCP
       Note over H,E: H may be descheduled here
   
       E->>E: OnNewDataFromTcp(socket)
       E->>E: observe ep->_state == FALLBACK_TCP
       E->>M: InputMessenger::OnNewMessages(socket)
       M->>S: Socket::DoRead(size_hint)
       S->>S: CHECK(_rdma_state == RDMA_OFF)
       Note over S: _rdma_state may still be RDMA_UNKNOWN/RDMA_ON<br/>CHECK 
fails and the process aborts
   
       H->>H: s->_rdma_state = RDMA_OFF
       Note over H: This update happens too late
   ```
   
   Equivalent thread interleaving:
   
   ```text
   RDMA handshake bthread                 TCP event bthread
   ----------------------                 -----------------
   ep->_state = FALLBACK_TCP;
   
                < context switch >
   
                                          OnNewDataFromTcp(socket);
                                          if (ep->_state == FALLBACK_TCP) {
                                              
InputMessenger::OnNewMessages(socket);
                                                -> Socket::DoRead();
                                                -> CHECK(_rdma_state == 
RDMA_OFF);
                                                   // failure
                                          }
   
   s->_rdma_state = RDMA_OFF;
   ```
   
   `TryReadOnTcp()` itself is not the problematic ordering path. When it is
   called by the handshake bthread after both assignments, program order is
   preserved. The race is caused by an independently scheduled
   `OnNewDataFromTcp()` invocation observing the partially published fallback
   state.
   
   ## Expected behavior
   
   Once a TCP event observes `RdmaEndpoint::_state == FALLBACK_TCP`, the
   corresponding `Socket::_rdma_state` must already be visible as `RDMA_OFF`.
   
   TCP fallback must not expose an intermediate state in which:
   
   ```text
   RdmaEndpoint::_state == FALLBACK_TCP
   Socket::_rdma_state != RDMA_OFF
   ```
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to