From: Stefan Metzmacher Date: Thu, 14 Aug 2025 17:41:12 +0000 (+0200) Subject: smb: client: fix smbdirect keep alive handling to match the documentation X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=ac31755c7a649786a9e11c6288513f5f4c1d30c9;p=users%2Fjedix%2Flinux-maple.git smb: client: fix smbdirect keep alive handling to match the documentation We setup the first timer with the negotiate timeout and set KEEP_ALIVE_PENDING, so that the expired timer disconnects. On every incoming message we need to reset the timer to the keepalive interval (120s). On SMBDIRECT_FLAG_RESPONSE_REQUESTED we need to schedule a response instead of setting KEEP_ALIVE_PENDING. Doing both would mean we would also set SMBDIRECT_FLAG_RESPONSE_REQUESTED in that response. If both ends would do that we'd play ping pong in a busy loop. If we move to KEEP_ALIVE_SENT and send the keepalive request with SMBDIRECT_FLAG_RESPONSE_REQUESTED, we need to setup the timer with keepalive timeout (5s) in order to disconnect if no incoming message reset the timer. The fired timer sets KEEP_ALIVE_PENDING and also setup timer with keepalive timeout (5s) in order to disconnect if no incoming message reset the timer. We do that before queueing the send_immediate_work and have that timer in case we didn't reach the send code that typically sets the timer to keepalive timeout. Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Acked-by: Namjae Jeon Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index d53e39e91e10..5863dc7e021a 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -610,6 +610,14 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) response->sge.length, DMA_FROM_DEVICE); + /* + * Reset timer to the keepalive interval in + * order to trigger our next keepalive message. + */ + info->keep_alive_requested = KEEP_ALIVE_NONE; + mod_delayed_work(info->workqueue, &info->idle_timer_work, + msecs_to_jiffies(sp->keepalive_interval_msec)); + switch (sc->recv_io.expected) { /* SMBD negotiation response */ case SMBDIRECT_EXPECT_NEGOTIATE_REP: @@ -684,11 +692,11 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) le32_to_cpu(data_transfer->data_length), le32_to_cpu(data_transfer->remaining_data_length)); - /* Send a KEEP_ALIVE response right away if requested */ - info->keep_alive_requested = KEEP_ALIVE_NONE; + /* Send an immediate response right away if requested */ if (le16_to_cpu(data_transfer->flags) & SMBDIRECT_FLAG_RESPONSE_REQUESTED) { - info->keep_alive_requested = KEEP_ALIVE_PENDING; + log_keep_alive(INFO, "schedule send of immediate response\n"); + queue_work(info->workqueue, &info->send_immediate_work); } /* @@ -987,8 +995,17 @@ static int manage_credits_prior_sending(struct smbd_connection *info) */ static int manage_keep_alive_before_sending(struct smbd_connection *info) { + struct smbdirect_socket *sc = &info->socket; + struct smbdirect_socket_parameters *sp = &sc->parameters; + if (info->keep_alive_requested == KEEP_ALIVE_PENDING) { info->keep_alive_requested = KEEP_ALIVE_SENT; + /* + * Now use the keepalive timeout (instead of keepalive interval) + * in order to wait for a response + */ + mod_delayed_work(info->workqueue, &info->idle_timer_work, + msecs_to_jiffies(sp->keepalive_timeout_msec)); return 1; } return 0; @@ -999,7 +1016,6 @@ static int smbd_post_send(struct smbd_connection *info, struct smbdirect_send_io *request) { struct smbdirect_socket *sc = &info->socket; - struct smbdirect_socket_parameters *sp = &sc->parameters; struct ib_send_wr send_wr; int rc, i; @@ -1028,10 +1044,7 @@ static int smbd_post_send(struct smbd_connection *info, log_rdma_send(ERR, "ib_post_send failed rc=%d\n", rc); smbd_disconnect_rdma_connection(info); rc = -EAGAIN; - } else - /* Reset timer for idle connection after packet is sent */ - mod_delayed_work(info->workqueue, &info->idle_timer_work, - msecs_to_jiffies(sp->keepalive_interval_msec)); + } return rc; } @@ -1486,12 +1499,18 @@ static void idle_connection_timer(struct work_struct *work) return; } + if (sc->status != SMBDIRECT_SOCKET_CONNECTED) + return; + + /* + * Now use the keepalive timeout (instead of keepalive interval) + * in order to wait for a response + */ + info->keep_alive_requested = KEEP_ALIVE_PENDING; + mod_delayed_work(info->workqueue, &info->idle_timer_work, + msecs_to_jiffies(sp->keepalive_timeout_msec)); log_keep_alive(INFO, "schedule send of empty idle message\n"); queue_work(info->workqueue, &info->send_immediate_work); - - /* Setup the next idle timeout work */ - queue_delayed_work(info->workqueue, &info->idle_timer_work, - msecs_to_jiffies(sp->keepalive_interval_msec)); } /* @@ -1881,8 +1900,13 @@ static struct smbd_connection *_smbd_get_connection( INIT_WORK(&info->send_immediate_work, send_immediate_empty_message); INIT_DELAYED_WORK(&info->idle_timer_work, idle_connection_timer); - queue_delayed_work(info->workqueue, &info->idle_timer_work, - msecs_to_jiffies(sp->keepalive_interval_msec)); + /* + * start with the negotiate timeout and KEEP_ALIVE_PENDING + * so that the timer will cause a disconnect. + */ + info->keep_alive_requested = KEEP_ALIVE_PENDING; + mod_delayed_work(info->workqueue, &info->idle_timer_work, + msecs_to_jiffies(sp->negotiate_timeout_msec)); INIT_WORK(&sc->recv_io.posted.refill_work, smbd_post_send_credits);