Received: by 10.223.164.197 with SMTP id h5csp684756wrb; Sat, 4 Nov 2017 22:47:27 -0700 (PDT) X-Google-Smtp-Source: ABhQp+T3MSmlNTUq/344QfCmEeWBGDlLDKpqLnuwITafrA1pYW3JZL5dQAvWCB2OzIvhNHhlHTtt X-Received: by 10.159.196.151 with SMTP id c23mr11344049plo.276.1509860847777; Sat, 04 Nov 2017 22:47:27 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1509860847; cv=none; d=google.com; s=arc-20160816; b=IHLJCwSYlqDpME9kKRXLV9Qm+7HovObya33ju4e2EU6GDmscVAD2HHRBYh3QSVfnH9 E7iDtdNymZE/nCM/b5mcbNHRV6TP94X8liwanGk4KdSOYZSZoUBkZTChXrvIyGTxCKqF Kt/ElNJO61BCKhOJdkSlEOVS74Il93+0DVDA2ZySiKs5tO5F+OIQb8xxrZmWuHH48VI2 u4T6sdtqDv9uRhCiR5/eV4vzpIxq4yreMxWfAu1rI6WhfK2oBWqKjHZNZ22v5Kh6HzkW qzCZSncKdmwAn0tdV/JJt9Z9okuQg1Laqr2yyraEIbaJ22ongXUk+181OgBuFjx8e5PZ Tguw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:arc-authentication-results; bh=0c4yrLbOxy8hpU2psihAkNViFPFOA+FUvFwMiEB9l+4=; b=EFgzQlz8teHpu3AnXxD8UPbCYkdcWer1KBAtvCzV4hUUj6b0UaqWBSDztlmYRlJ1AW 0jJJ/5sPhX1B0tTbbRrb6jZmLnd4D442eZfFOlkrbkUlX+vutHi1JFYfIzA2lzreSBDm f81FovjPNQ0MsV688AcMZFOTM3W2TyvmNmey772Zs16FnMvJFSNslzwYOnLzzl0bO83M NEz2PL2v/kbkw0R/sr0Z2NlFgY1ymSkRuPQUAkxZenudWxNlpLCIFhbyeHOqsROgGyqK 3hlcORW/y83XyMcJasCVZG3Ue6QTeh+v+uWPTrkrjcoHUzcuJVF8D1LMELlwicdJnTNe 04qg== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=exchange.microsoft.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id w5si9540334pgm.393.2017.11.04.22.47.03; Sat, 04 Nov 2017 22:47:27 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=exchange.microsoft.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752368AbdKEFqA (ORCPT + 96 others); Sun, 5 Nov 2017 01:46:00 -0400 Received: from a2nlsmtp01-02.prod.iad2.secureserver.net ([198.71.225.36]:51994 "EHLO a2nlsmtp01-02.prod.iad2.secureserver.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750733AbdKEFpw (ORCPT ); Sun, 5 Nov 2017 01:45:52 -0400 Received: from linuxonhyperv.com ([107.180.71.197]) by : HOSTING RELAY : with SMTP id BDjVeX8UmOdJ4BDjVeZkF2; Sat, 04 Nov 2017 22:44:51 -0700 x-originating-ip: 107.180.71.197 Received: from longli by linuxonhyperv.com with local (Exim 4.89) (envelope-from ) id 1eBDjV-0006FI-2r; Sat, 04 Nov 2017 22:44:33 -0700 From: Long Li To: Steve French , linux-cifs@vger.kernel.org, samba-technical@lists.samba.org, linux-kernel@vger.kernel.org, linux-rdma@vger.kernel.org, Christoph Hellwig , Tom Talpey , Matthew Wilcox , Stephen Hemminger Cc: Long Li Subject: [Patch v6 14/22] CIFS: SMBD: Implement function to receive data via RDMA receive Date: Sat, 4 Nov 2017 22:43:56 -0700 Message-Id: <20171105054404.23886-15-longli@exchange.microsoft.com> X-Mailer: git-send-email 2.14.1 In-Reply-To: <20171105054404.23886-1-longli@exchange.microsoft.com> References: <20171105054404.23886-1-longli@exchange.microsoft.com> X-CMAE-Envelope: MS4wfHInzG9HoganxEji0XFIN7xoEuqKZa4XBlKSa/qrrDpMlkjOy4Z5A7Ighy6xCM4m6M/04xKXnffq7FwVkSJPO7Lh1rXP736G8O9KiQZ/Fm6tC1TSfCbJ J5uMJrpbgS8+Ym0vO/kd2gcgqvrqmeEJWE/Pn9ryOx9WguD764fehIRX3HKtWU8p19AmC4O8wv4yBX7NCAbsrby5ocIU+/I6A3JVQsocjHCt9LDVnEz9jCwW C7kmmEcOTy/TFfG7FxFej/WG9ZoSqOQDf1duLJAGR6lUfQP/tAJSB3YotLZ/rcpsFtMiRMd+w7jBwhFwytx7MYJHH7qUtbHhDIOk0vtIXH6dy0QOnq+CBl9Z cSLai0b/G9AOynjKKJhX/kB5Vg8XAeZNDimRyLAiiqNJYCJBb6xBjoFUUNqKoIFXr1gjl3Q8QUVkNf/r6JlsMkmHxhHVkrXoEyFPaq6CPGHa00yEHI1/mrEi GomLwswJfCyTBmTu3Xn5+CwYNlnWGs9L3FTVog== Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Long Li On the receive path, the transport maintains receive buffers and a reassembly queue for transferring payload via RDMA recv. There is data copy in the transport on recv when it copies the payload to upper layer. The transport recognizes the RFC1002 header length use in the SMB upper layer payloads in CIFS. Because this length is mainly used for TCP and not applicable to RDMA, it is handled as a out-of-band information and is never sent over the wire, and the trasnport behaves like TCP to upper layer by processing and exposing the length correctly on data payloads. Signed-off-by: Long Li --- fs/cifs/smbdirect.c | 228 ++++++++++++++++++++++++++++++++++++++++++++++++++++ fs/cifs/smbdirect.h | 3 + 2 files changed, 231 insertions(+) diff --git a/fs/cifs/smbdirect.c b/fs/cifs/smbdirect.c index 5952276..1e7f5df 100644 --- a/fs/cifs/smbdirect.c +++ b/fs/cifs/smbdirect.c @@ -14,6 +14,7 @@ * the GNU General Public License for more details. */ #include +#include #include "smbdirect.h" #include "cifs_debug.h" @@ -179,6 +180,8 @@ static void smbd_destroy_rdma_work(struct work_struct *work) log_rdma_event(INFO, "wait for all recv to finish\n"); wake_up_interruptible(&info->wait_reassembly_queue); + wait_event(info->wait_smbd_recv_pending, + info->smbd_recv_pending == 0); log_rdma_event(INFO, "wait for all send posted to IB to finish\n"); wait_event(info->wait_send_pending, @@ -1655,6 +1658,9 @@ struct smbd_connection *_smbd_get_connection( queue_delayed_work(info->workqueue, &info->idle_timer_work, info->keep_alive_interval*HZ); + init_waitqueue_head(&info->wait_smbd_recv_pending); + info->smbd_recv_pending = 0; + init_waitqueue_head(&info->wait_send_pending); atomic_set(&info->send_pending, 0); @@ -1721,3 +1727,225 @@ struct smbd_connection *smbd_get_connection( } return ret; } + +/* + * Receive data from receive reassembly queue + * All the incoming data packets are placed in reassembly queue + * buf: the buffer to read data into + * size: the length of data to read + * return value: actual data read + * Note: this implementation copies the data from reassebmly queue to receive + * buffers used by upper layer. This is not the optimal code path. A better way + * to do it is to not have upper layer allocate its receive buffers but rather + * borrow the buffer from reassembly queue, and return it after data is + * consumed. But this will require more changes to upper layer code, and also + * need to consider packet boundaries while they still being reassembled. + */ +int smbd_recv_buf(struct smbd_connection *info, char *buf, unsigned int size) +{ + struct smbd_response *response; + struct smbd_data_transfer *data_transfer; + int to_copy, to_read, data_read, offset; + u32 data_length, remaining_data_length, data_offset; + int rc; + unsigned long flags; + +again: + if (info->transport_status != SMBD_CONNECTED) { + log_read(ERR, "disconnected\n"); + return -ENODEV; + } + + /* + * 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 queeu at the same time + */ + log_read(INFO, "size=%d info->reassembly_data_length=%d\n", size, + info->reassembly_data_length); + if (info->reassembly_data_length >= size) { + int queue_length; + int queue_removed = 0; + + /* + * Need to make sure reassembly_data_length is read before + * reading reassembly_queue_length and calling + * _get_first_reassembly. 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 = info->reassembly_queue_length; + data_read = 0; + to_read = size; + offset = info->first_entry_offset; + while (data_read < size) { + response = _get_first_reassembly(info); + data_transfer = smbd_response_payload(response); + 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 (response->first_segment && size == 4) { + unsigned int rfc1002_len = + data_length + remaining_data_length; + *((__be32 *)buf) = cpu_to_be32(rfc1002_len); + data_read = 4; + response->first_segment = false; + log_read(INFO, "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) + spin_lock_irqsave( + &info->reassembly_queue_lock, + flags); + list_del(&response->list); + queue_removed++; + if (!queue_length) + spin_unlock_irqrestore( + &info->reassembly_queue_lock, + flags); + + info->count_reassembly_queue--; + info->count_dequeue_reassembly_queue++; + put_receive_buffer(info, response, true); + offset = 0; + log_read(INFO, "put_receive_buffer offset=0\n"); + } else + offset += to_copy; + + to_read -= to_copy; + data_read += to_copy; + + log_read(INFO, "_get_first_reassembly memcpy %d bytes " + "data_transfer_length-offset=%d after that " + "to_read=%d data_read=%d offset=%d\n", + to_copy, data_length - offset, + to_read, data_read, offset); + } + + spin_lock_irqsave(&info->reassembly_queue_lock, flags); + info->reassembly_data_length -= data_read; + info->reassembly_queue_length -= queue_removed; + spin_unlock_irqrestore(&info->reassembly_queue_lock, flags); + + info->first_entry_offset = offset; + log_read(INFO, "returning to thread data_read=%d " + "reassembly_data_length=%d first_entry_offset=%d\n", + data_read, info->reassembly_data_length, + info->first_entry_offset); +read_rfc1002_done: + return data_read; + } + + log_read(INFO, "wait_event on more data\n"); + rc = wait_event_interruptible( + info->wait_reassembly_queue, + info->reassembly_data_length >= size || + info->transport_status != SMBD_CONNECTED); + /* Don't return any data if interrupted */ + if (rc) + return -ENODEV; + + goto again; +} + +/* + * Receive a page from receive reassembly queue + * page: the page to read data into + * to_read: the length of data to read + * return value: actual data read + */ +int smbd_recv_page(struct smbd_connection *info, + struct page *page, unsigned int to_read) +{ + int ret; + char *to_address; + + /* make sure we have the page ready for read */ + ret = wait_event_interruptible( + info->wait_reassembly_queue, + info->reassembly_data_length >= to_read || + info->transport_status != SMBD_CONNECTED); + if (ret) + return 0; + + /* now we can read from reassembly queue and not sleep */ + to_address = kmap_atomic(page); + + log_read(INFO, "reading from page=%p address=%p to_read=%d\n", + page, to_address, to_read); + + ret = smbd_recv_buf(info, to_address, to_read); + kunmap_atomic(to_address); + + return ret; +} + +/* + * Receive data from transport + * msg: a msghdr point to the buffer, can be ITER_KVEC or ITER_BVEC + * return: total bytes read, or 0. SMB Direct will not do partial read. + */ +int smbd_recv(struct smbd_connection *info, struct msghdr *msg) +{ + char *buf; + struct page *page; + unsigned int to_read; + int rc; + + info->smbd_recv_pending++; + + switch (msg->msg_iter.type) { + case READ | ITER_KVEC: + buf = msg->msg_iter.kvec->iov_base; + to_read = msg->msg_iter.kvec->iov_len; + rc = smbd_recv_buf(info, buf, to_read); + break; + + case READ | ITER_BVEC: + page = msg->msg_iter.bvec->bv_page; + to_read = msg->msg_iter.bvec->bv_len; + rc = smbd_recv_page(info, page, to_read); + break; + + default: + /* It's a bug in upper layer to get there */ + cifs_dbg(VFS, "CIFS: invalid msg type %d\n", + msg->msg_iter.type); + rc = -EIO; + } + + info->smbd_recv_pending--; + wake_up(&info->wait_smbd_recv_pending); + + /* SMBDirect will read it all or nothing */ + if (rc > 0) + msg->msg_iter.count = 0; + return rc; +} diff --git a/fs/cifs/smbdirect.h b/fs/cifs/smbdirect.h index 1707bbc..c1e2d3d 100644 --- a/fs/cifs/smbdirect.h +++ b/fs/cifs/smbdirect.h @@ -88,6 +88,9 @@ struct smbd_connection { int fragment_reassembly_remaining; /* Activity accoutning */ + /* Pending reqeusts issued from upper layer */ + int smbd_recv_pending; + wait_queue_head_t wait_smbd_recv_pending; atomic_t send_pending; wait_queue_head_t wait_send_pending; -- 2.7.4 From 1582940517121649967@xxx Thu Nov 02 08:01:55 +0000 2017 X-GM-THRID: 1582940517121649967 X-Gmail-Labels: Inbox,Category Forums,HistoricalUnread