]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
smb: server: make use of smbdirect_connection_recvmsg()
authorStefan Metzmacher <metze@samba.org>
Mon, 13 Oct 2025 16:49:30 +0000 (18:49 +0200)
committerSteve French <stfrench@microsoft.com>
Thu, 16 Apr 2026 02:58:23 +0000 (21:58 -0500)
This is basically the same logic, it just operates on iov_iter_kvec()
instead of a raw buffer pointer. This allows us to use common
code between client and server.

We keep returning -EINTR instead of -ERESTARTSYS if
wait_event_interruptible() fails. I don't if this is
required, but changing it is a task for another patch.

Cc: Namjae Jeon <linkinjeon@kernel.org>
Cc: Steve French <smfrench@gmail.com>
Cc: Tom Talpey <tom@talpey.com>
Cc: linux-cifs@vger.kernel.org
Cc: samba-technical@lists.samba.org
Signed-off-by: Stefan Metzmacher <metze@samba.org>
Acked-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
fs/smb/server/transport_rdma.c

index fbc9d31cde0531bb7607008e3d17b03f9aa856e3..9f13f96978cd33c33d2092a0e84a77fa23a2de66 100644 (file)
@@ -214,12 +214,6 @@ static int smb_direct_post_send_data(struct smbdirect_socket *sc,
                                     struct kvec *iov, int niov,
                                     int remaining_data_length);
 
-static inline void
-*smbdirect_recv_io_payload(struct smbdirect_recv_io *recvmsg)
-{
-       return (void *)recvmsg->packet;
-}
-
 static void smb_direct_send_immediate_work(struct work_struct *work)
 {
        struct smbdirect_socket *sc =
@@ -607,121 +601,21 @@ static void smb_direct_negotiate_recv_work(struct work_struct *work)
 static int smb_direct_read(struct ksmbd_transport *t, char *buf,
                           unsigned int size, int unused)
 {
-       struct smbdirect_recv_io *recvmsg;
-       struct smbdirect_data_transfer *data_transfer;
-       int to_copy, to_read, data_read, offset;
-       u32 data_length, remaining_data_length, data_offset;
-       int rc;
        struct smb_direct_transport *st = SMBD_TRANS(t);
        struct smbdirect_socket *sc = &st->socket;
+       struct msghdr msg = { .msg_flags = 0, };
+       struct kvec iov = {
+               .iov_base = buf,
+               .iov_len = size,
+       };
+       int ret;
 
-again:
-       if (sc->status != SMBDIRECT_SOCKET_CONNECTED) {
-               pr_err("disconnected\n");
-               return -ENOTCONN;
-       }
-
-       /*
-        * No need to hold the reassembly queue lock all the time as we are
-        * the only one reading from the front of the queue. The transport
-        * may add more entries to the back of the queue at the same time
-        */
-       if (sc->recv_io.reassembly.data_length >= size) {
-               int queue_length;
-               int queue_removed = 0;
-               unsigned long flags;
-
-               /*
-                * Need to make sure reassembly_data_length is read before
-                * reading reassembly_queue_length and calling
-                * smbdirect_connection_reassembly_first_recv_io. This call is lock free
-                * as we never read at the end of the queue which are being
-                * updated in SOFTIRQ as more data is received
-                */
-               virt_rmb();
-               queue_length = sc->recv_io.reassembly.queue_length;
-               data_read = 0;
-               to_read = size;
-               offset = sc->recv_io.reassembly.first_entry_offset;
-               while (data_read < size) {
-                       recvmsg = smbdirect_connection_reassembly_first_recv_io(sc);
-                       data_transfer = smbdirect_recv_io_payload(recvmsg);
-                       data_length = le32_to_cpu(data_transfer->data_length);
-                       remaining_data_length =
-                               le32_to_cpu(data_transfer->remaining_data_length);
-                       data_offset = le32_to_cpu(data_transfer->data_offset);
-
-                       /*
-                        * The upper layer expects RFC1002 length at the
-                        * beginning of the payload. Return it to indicate
-                        * the total length of the packet. This minimize the
-                        * change to upper layer packet processing logic. This
-                        * will be eventually remove when an intermediate
-                        * transport layer is added
-                        */
-                       if (recvmsg->first_segment && size == 4) {
-                               unsigned int rfc1002_len =
-                                       data_length + remaining_data_length;
-                               *((__be32 *)buf) = cpu_to_be32(rfc1002_len);
-                               data_read = 4;
-                               recvmsg->first_segment = false;
-                               ksmbd_debug(RDMA,
-                                           "returning rfc1002 length %d\n",
-                                           rfc1002_len);
-                               goto read_rfc1002_done;
-                       }
-
-                       to_copy = min_t(int, data_length - offset, to_read);
-                       memcpy(buf + data_read, (char *)data_transfer + data_offset + offset,
-                              to_copy);
-
-                       /* move on to the next buffer? */
-                       if (to_copy == data_length - offset) {
-                               queue_length--;
-                               /*
-                                * No need to lock if we are not at the
-                                * end of the queue
-                                */
-                               if (queue_length) {
-                                       list_del(&recvmsg->list);
-                               } else {
-                                       spin_lock_irqsave(&sc->recv_io.reassembly.lock, flags);
-                                       list_del(&recvmsg->list);
-                                       spin_unlock_irqrestore(&sc->recv_io.reassembly.lock, flags);
-                               }
-                               queue_removed++;
-                               smbdirect_connection_put_recv_io(recvmsg);
-                               offset = 0;
-                       } else {
-                               offset += to_copy;
-                       }
-
-                       to_read -= to_copy;
-                       data_read += to_copy;
-               }
-
-               spin_lock_irqsave(&sc->recv_io.reassembly.lock, flags);
-               sc->recv_io.reassembly.data_length -= data_read;
-               sc->recv_io.reassembly.queue_length -= queue_removed;
-               spin_unlock_irqrestore(&sc->recv_io.reassembly.lock, flags);
-
-               sc->recv_io.reassembly.first_entry_offset = offset;
-               ksmbd_debug(RDMA,
-                           "returning to thread data_read=%d reassembly_data_length=%d first_entry_offset=%d\n",
-                           data_read, sc->recv_io.reassembly.data_length,
-                           sc->recv_io.reassembly.first_entry_offset);
-read_rfc1002_done:
-               return data_read;
-       }
-
-       ksmbd_debug(RDMA, "wait_event on more data\n");
-       rc = wait_event_interruptible(sc->recv_io.reassembly.wait_queue,
-                                     sc->recv_io.reassembly.data_length >= size ||
-                                      sc->status != SMBDIRECT_SOCKET_CONNECTED);
-       if (rc)
-               return -EINTR;
+       iov_iter_kvec(&msg.msg_iter, ITER_DEST, &iov, 1, size);
 
-       goto again;
+       ret = smbdirect_connection_recvmsg(sc, &msg, 0);
+       if (ret == -ERESTARTSYS)
+               ret = -EINTR;
+       return ret;
 }
 
 static int manage_credits_prior_sending(struct smbdirect_socket *sc)