struct kfilnd_transaction *tn;
int rc;
- if (kfilnd_peer_set_check_hello_pending(kp)) {
+ /* Only one thread may progress state from NONE -> INIT */
+ if (atomic_cmpxchg(&kp->kp_hello_state, KP_HELLO_NONE, KP_HELLO_INIT) !=
+ KP_HELLO_NONE) {
CDEBUG(D_NET, "Hello already pending to peer %s(%px)\n",
libcfs_nid2str(kp->kp_nid), kp);
return 0;
if (IS_ERR(tn)) {
rc = PTR_ERR(tn);
CERROR("Failed to allocate transaction struct: rc=%d\n", rc);
- kfilnd_peer_clear_hello_pending(kp);
+ atomic_set(&kp->kp_hello_state, KP_HELLO_NONE);
return rc;
}
kp->kp_hello_ts = ktime_get_seconds();
+ atomic_set(&kp->kp_hello_state, KP_HELLO_SENDING);
+
kfilnd_tn_event_handler(tn, TN_EVENT_TX_HELLO, 0);
return 0;
#define CFS_KFI_FAIL_WAIT_SEND_COMP1 0xF115
#define CFS_KFI_FAIL_WAIT_SEND_COMP2 0xF116
#define CFS_KFI_FAIL_WAIT_SEND_COMP3 0xF117
+#define CFS_KFI_REPLAY_IDLE_EVENT 0xF118
/* Maximum number of transaction keys supported. */
#define KFILND_EP_KEY_BITS 16U
u16 kp_version;
u32 kp_local_session_key;
u32 kp_remote_session_key;
- atomic_t kp_hello_pending;
+ atomic_t kp_hello_state;
time64_t kp_hello_ts;
atomic_t kp_state;
};
return atomic_read(&kp->kp_remove_peer) > 0;
}
-/* Sets kp_hello_sending
- * Returns true if it was already set
- * Returns false otherwise
+/* Values for kp_hello_state. Valid transitions:
+ * NONE -> INIT
+ * INIT -> NONE (only when fail to allocate kfilnd_tn for hello req)
+ * INIT -> SENDING
+ * SENDING -> NONE
*/
-static inline bool kfilnd_peer_set_check_hello_pending(struct kfilnd_peer *kp)
-{
- return (atomic_cmpxchg(&kp->kp_hello_pending, 0, 1) == 1);
-}
+#define KP_HELLO_NONE 0 /* There is no hello request being sent */
+#define KP_HELLO_INIT 1 /* Hello request is initializing */
+#define KP_HELLO_SENDING 2 /* Hello request TN is in the state machine */
-static inline void kfilnd_peer_clear_hello_pending(struct kfilnd_peer *kp)
+/* If kp_hello_state is SENDING then set to NONE */
+static inline void kfilnd_peer_clear_hello_state(struct kfilnd_peer *kp)
{
- atomic_set(&kp->kp_hello_pending, 0);
+ atomic_cmpxchg(&kp->kp_hello_state, KP_HELLO_SENDING, KP_HELLO_NONE);
}
static inline bool kfilnd_peer_is_new_peer(struct kfilnd_peer *kp)
static inline bool kfilnd_peer_needs_hello(struct kfilnd_peer *kp,
bool proactive_handshake)
{
- if (atomic_read(&kp->kp_hello_pending) == 0) {
+ int hello_state = atomic_read(&kp->kp_hello_state);
+
+ if (hello_state == KP_HELLO_NONE) {
if (atomic_read(&kp->kp_state) != KP_STATE_UPTODATE)
return true;
else if (proactive_handshake &&
lnet_get_lnd_timeout() * 2,
ktime_get_seconds()))
return true;
- } else if (ktime_before(kp->kp_hello_ts + lnet_get_lnd_timeout(),
+ } else if (hello_state == KP_HELLO_SENDING &&
+ ktime_before(kp->kp_hello_ts + lnet_get_lnd_timeout(),
ktime_get_seconds())) {
/* Sent hello but never received reply */
CDEBUG(D_NET,
libcfs_nid2str(kp->kp_nid), kp, kp->kp_addr,
ktime_sub(ktime_get_seconds(), kp->kp_hello_ts));
- kfilnd_peer_clear_hello_pending(kp);
+ kfilnd_peer_clear_hello_state(kp);
return true;
}
kp->kp_nid = nid;
atomic_set(&kp->kp_rx_base, 0);
atomic_set(&kp->kp_remove_peer, 0);
- atomic_set(&kp->kp_hello_pending, 0);
+ atomic_set(&kp->kp_hello_state, KP_HELLO_NONE);
atomic_set(&kp->kp_state, KP_STATE_NEW);
kp->kp_local_session_key = kfilnd_dev_get_session_key(dev);
kp->kp_hello_ts = ktime_get_seconds();
CDEBUG(D_NET, "kp %s(%p):0x%llx is up-to-date\n",
libcfs_nid2str(kp->kp_nid), kp, kp->kp_addr);
- /* Clear kp_hello_pending if we've received the hello response,
+ /* Clear kp_hello_state if we've received the hello response,
* otherwise this is an incoming hello request and we may have our
* own hello request to this peer still outstanding
*/
if (msg->type == KFILND_MSG_HELLO_RSP)
- kfilnd_peer_clear_hello_pending(kp);
+ kfilnd_peer_clear_hello_state(kp);
}
goto out;
}
+ if (CFS_FAIL_CHECK_VALUE(CFS_KFI_REPLAY_IDLE_EVENT, event))
+ return -EAGAIN;
+
switch (event) {
case TN_EVENT_INIT_IMMEDIATE:
case TN_EVENT_TX_HELLO:
libcfs_nid2str(tn->tn_kp->kp_nid),
tn->tn_target_addr, rc);
if (event == TN_EVENT_TX_HELLO)
- kfilnd_peer_clear_hello_pending(tn->tn_kp);
+ kfilnd_peer_clear_hello_state(tn->tn_kp);
kfilnd_tn_status_update(tn, rc,
LNET_MSG_STATUS_LOCAL_ERROR);
}
*/
kfilnd_peer_tn_failed(tn->tn_kp, status, false);
if (tn->msg_type == KFILND_MSG_HELLO_REQ)
- kfilnd_peer_clear_hello_pending(tn->tn_kp);
+ kfilnd_peer_clear_hello_state(tn->tn_kp);
break;
case TN_EVENT_TX_OK: