From: Stefan Metzmacher Date: Mon, 13 Oct 2025 16:49:30 +0000 (+0200) Subject: smb: server: make use of smbdirect_connection_recvmsg() X-Git-Tag: v7.1-rc1~128^2~27 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=73489efddadc53dbdd4270569c0c00492ace9801;p=thirdparty%2Fkernel%2Flinux.git smb: server: make use of smbdirect_connection_recvmsg() 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 Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index fbc9d31cde053..9f13f96978cd3 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -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)