[PATCH v2 027/127] smb: smbdirect: introduce smbdirect_connection_recv_io_refill_work()
Stefan Metzmacher
metze at samba.org
Wed Oct 29 13:20:05 UTC 2025
This is basically a copy of smbd_post_send_credits() in the client
and smb_direct_post_recv_credits() in the server.
There are several improvements compared to the existing functions:
1. We calculate the number of missing posted buffers by getting the
difference between recv_io.credits.target and recv_io.posted.count.
Instead of the difference between recv_io.credits.target
and recv_io.credits.count, because recv_io.credits.count is
only updated once a message is send to the peer.
It was not really a problem before, because we have
a fixed number smbdirect_recv_io buffers, so the
loop terminated when smbdirect_connection_get_recv_io()
returns NULL.
But using recv_io.posted.count makes it easier to
understand.
2. In order to tell the peer about the newly posted buffer
and grant the credits, we only trigger the send immediate
when we're not granting only the last possible credit.
This is mostly a difference relative to the servers
smb_direct_post_recv_credits() implementation,
which should avoid useless ping pong messages.
Cc: Steve French <smfrench at gmail.com>
Cc: Tom Talpey <tom at talpey.com>
Cc: Long Li <longli at microsoft.com>
Cc: Namjae Jeon <linkinjeon at kernel.org>
Cc: linux-cifs at vger.kernel.org
Cc: samba-technical at lists.samba.org
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Signed-off-by: Steve French <stfrench at microsoft.com>
---
.../common/smbdirect/smbdirect_connection.c | 92 +++++++++++++++++++
1 file changed, 92 insertions(+)
diff --git a/fs/smb/common/smbdirect/smbdirect_connection.c b/fs/smb/common/smbdirect/smbdirect_connection.c
index 959b0c49857f..95e212877e9f 100644
--- a/fs/smb/common/smbdirect/smbdirect_connection.c
+++ b/fs/smb/common/smbdirect/smbdirect_connection.c
@@ -881,6 +881,98 @@ static int smbdirect_connection_post_recv_io(struct smbdirect_recv_io *msg)
return ret;
}
+__maybe_unused /* this is temporary while this file is included in orders */
+static void smbdirect_connection_recv_io_refill_work(struct work_struct *work)
+{
+ struct smbdirect_socket *sc =
+ container_of(work, struct smbdirect_socket, recv_io.posted.refill_work);
+ int missing;
+ int posted = 0;
+
+ if (unlikely(sc->first_error))
+ return;
+
+ /*
+ * Find out how much smbdirect_recv_io buffers we should post.
+ *
+ * Note that sc->recv_io.credits.target is the value
+ * from the peer and it can in theory change over time,
+ * but it is forced to be at least 1 and at max
+ * sp->recv_credit_max.
+ *
+ * So it can happen that missing will be lower than 0,
+ * which means the peer has recently lowered its desired
+ * tarted, while be already granted a higher number of credits.
+ *
+ * Note 'posted' is the number of smbdirect_recv_io buffers
+ * posted within this function, while sc->recv_io.posted.count
+ * is the overall value of posted smbdirect_recv_io buffers.
+ *
+ * We try to post as much buffers as missing, but
+ * this is limited if a lot of smbdirect_recv_io buffers
+ * are still in the sc->recv_io.reassembly.list instead of
+ * the sc->recv_io.free.list.
+ *
+ */
+ missing = (int)sc->recv_io.credits.target - atomic_read(&sc->recv_io.posted.count);
+ while (posted < missing) {
+ struct smbdirect_recv_io *recv_io;
+ int ret;
+
+ /*
+ * It's ok if smbdirect_connection_get_recv_io()
+ * returns NULL, it means smbdirect_recv_io structures
+ * are still be in the reassembly.list.
+ */
+ recv_io = smbdirect_connection_get_recv_io(sc);
+ if (!recv_io)
+ break;
+
+ recv_io->first_segment = false;
+
+ ret = smbdirect_connection_post_recv_io(recv_io);
+ if (ret) {
+ smbdirect_log_rdma_recv(sc, SMBDIRECT_LOG_ERR,
+ "smbdirect_connection_post_recv_io failed rc=%d (%s)\n",
+ ret, errname(ret));
+ smbdirect_connection_put_recv_io(recv_io);
+ return;
+ }
+
+ atomic_inc(&sc->recv_io.posted.count);
+ posted += 1;
+ }
+
+ /* If nothing was posted we're done */
+ if (posted == 0)
+ return;
+
+ /*
+ * If we posted at least one smbdirect_recv_io buffer,
+ * we need to inform the peer about it and grant
+ * additional credits.
+ *
+ * However there is one case where we don't want to
+ * do that.
+ *
+ * If only a single credit was missing before
+ * reaching the requested target, we should not
+ * post an immediate send, as that would cause
+ * endless ping pong once a keep alive exchange
+ * is started.
+ *
+ * However if sc->recv_io.credits.target is only 1,
+ * the peer has no credit left and we need to
+ * grant the credit anyway.
+ */
+ if (missing == 1 && sc->recv_io.credits.target != 1)
+ return;
+
+ smbdirect_log_keep_alive(sc, SMBDIRECT_LOG_INFO,
+ "schedule send of an empty message\n");
+ queue_work(sc->workqueue, &sc->idle.immediate_work);
+}
+
static bool smbdirect_map_sges_single_page(struct smbdirect_map_sges *state,
struct page *page, size_t off, size_t len)
{
--
2.43.0
More information about the samba-technical
mailing list