Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753220AbdHBURH (ORCPT ); Wed, 2 Aug 2017 16:17:07 -0400 Received: from a2nlsmtp01-03.prod.iad2.secureserver.net ([198.71.225.37]:50870 "EHLO a2nlsmtp01-03.prod.iad2.secureserver.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753019AbdHBUMZ (ORCPT ); Wed, 2 Aug 2017 16:12:25 -0400 x-originating-ip: 107.180.71.197 From: Long Li To: Steve French , linux-cifs@vger.kernel.org, samba-technical@lists.samba.org, linux-kernel@vger.kernel.org Cc: Long Li Subject: [[PATCH v1] 21/37] [CIFS] SMBD: Implement API for upper layer to receive data Date: Wed, 2 Aug 2017 13:10:32 -0700 Message-Id: <1501704648-20159-22-git-send-email-longli@exchange.microsoft.com> X-Mailer: git-send-email 1.7.1 In-Reply-To: <1501704648-20159-1-git-send-email-longli@exchange.microsoft.com> References: <1501704648-20159-1-git-send-email-longli@exchange.microsoft.com> X-CMAE-Envelope: MS4wfJzJqxxyELfUPnhAhTmldre6xss+33ppDHdXq/FvwBjK8wkc84D4KMXYvHrfoxthBPKf7VQ+U7/8sPIzq1kIaPh+0s4ewgSpQwqdxvaHgQ0wgtBrlR+R jUE1Y7wE1jp6jeOOed350RUhNxkjJURBnwlHo7bElPfPJK1LLIr/kqkydsZi33mh2E+unhTEUDd/qVw9MTedymCu7uzXnyO7Fk6rhKMaV6M88NZ1oGT+1PJx tMXUP/5azO86XiNKy6FhNZQrLHq/V2wtxGc3EleYyYRMgvb6QCR54bfukXk2/NVRQ8MZSx27X8WrC+okltk4dX7mYcWrOrBOZnSfs2NZtZI= Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 5147 Lines: 155 From: Long Li With reassembly queue in place, implement the API for upper layer to recevie data. This call may sleep if there is not enough data in the reassembly queue. Signed-off-by: Long Li --- fs/cifs/cifsrdma.c | 110 +++++++++++++++++++++++++++++++++++++++++++++++++++++ fs/cifs/cifsrdma.h | 5 +++ 2 files changed, 115 insertions(+) diff --git a/fs/cifs/cifsrdma.c b/fs/cifs/cifsrdma.c index 1d3fd26..e5f6300 100644 --- a/fs/cifs/cifsrdma.c +++ b/fs/cifs/cifsrdma.c @@ -1316,6 +1316,116 @@ struct cifs_rdma_info* cifs_create_rdma_session( } /* + * Read 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 + */ +int cifs_rdma_read(struct cifs_rdma_info *info, char *buf, unsigned int size) +{ + struct cifs_rdma_response *response; + struct smbd_data_transfer *data_transfer; + unsigned long flags; + int to_copy, to_read, data_read, offset; + u32 data_length, remaining_data_length, data_offset; + +again: + // the transport is disconnected? + if (info->transport_status != CIFS_RDMA_CONNECTED) { + log_cifs_read("disconnected\n"); + + /* + * If upper layer code is reading SMB packet length + * return 0 to indicate transport is disconnected and + * trigger a reconnect. + */ + spin_lock_irqsave(&info->reassembly_queue_lock, flags); + response = _get_first_reassembly(info); + if (response && response->first_segment && size==4) { + memset(buf, 0, size); + spin_unlock_irqrestore(&info->reassembly_queue_lock, flags); + return size; + } + spin_unlock_irqrestore(&info->reassembly_queue_lock, flags); + return 0; + } + + spin_lock_irqsave(&info->reassembly_queue_lock, flags); + log_cifs_read("size=%d info->reassembly_data_length=%d\n", size, + atomic_read(&info->reassembly_data_length)); + if (atomic_read(&info->reassembly_data_length) >= size) { + data_read = 0; + to_read = size; + offset = info->first_entry_offset; + while(data_read < size) { + response = _get_first_reassembly(info); + data_transfer = (struct smbd_data_transfer *) response->packet; + + 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); + + // this is for reading rfc1002 length + 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_cifs_read("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) { + list_del(&response->list); + info->count_reassembly_queue--; + info->count_dequeue_reassembly_queue++; + put_receive_buffer(info, response); + offset = 0; + log_cifs_read("put_receive_buffer offset=0\n"); + } else + offset += to_copy; + + to_read -= to_copy; + data_read += to_copy; + + log_cifs_read("_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); + } + atomic_sub(data_read, &info->reassembly_data_length); + info->first_entry_offset = offset; + log_cifs_read("returning to thread data_read=%d " + "reassembly_data_length=%d first_entry_offset=%d\n", + data_read, atomic_read(&info->reassembly_data_length), + info->first_entry_offset); +read_rfc1002_done: + spin_unlock_irqrestore(&info->reassembly_queue_lock, flags); + return data_read; + } + + spin_unlock_irqrestore(&info->reassembly_queue_lock, flags); + log_cifs_read("wait_event on more data\n"); + wait_event( + info->wait_reassembly_queue, + atomic_read(&info->reassembly_data_length) >= size || + info->transport_status != CIFS_RDMA_CONNECTED); + goto again; +} + +/* * Write data to transport * Each rqst is transported as a SMBDirect payload * rqst: the data to write diff --git a/fs/cifs/cifsrdma.h b/fs/cifs/cifsrdma.h index b26e3b7..8891e21 100644 --- a/fs/cifs/cifsrdma.h +++ b/fs/cifs/cifsrdma.h @@ -89,6 +89,8 @@ struct cifs_rdma_info { // total data length of reassembly queue atomic_t reassembly_data_length; + // the offset to first buffer in reassembly queue + int first_entry_offset; wait_queue_head_t wait_send_queue; @@ -210,5 +212,8 @@ struct cifs_rdma_response { struct cifs_rdma_info* cifs_create_rdma_session( struct TCP_Server_Info *server, struct sockaddr *dstaddr); +// SMBDirect interface for carrying upper layer CIFS I/O +int cifs_rdma_read( + struct cifs_rdma_info *rdma, char *buf, unsigned int to_read); int cifs_rdma_write(struct cifs_rdma_info *rdma, struct smb_rqst *rqst); #endif -- 2.7.4