From patchwork Wed Aug 8 05:07:45 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ronnie Sahlberg X-Patchwork-Id: 10559509 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 3BC281390 for ; Wed, 8 Aug 2018 05:08:04 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 2893429C5B for ; Wed, 8 Aug 2018 05:08:04 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 1901D29C66; Wed, 8 Aug 2018 05:08:04 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 6086829C5B for ; Wed, 8 Aug 2018 05:08:03 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726744AbeHHHZv (ORCPT ); Wed, 8 Aug 2018 03:25:51 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:48220 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1726733AbeHHHZu (ORCPT ); Wed, 8 Aug 2018 03:25:50 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 11FA27D84D; Wed, 8 Aug 2018 05:08:01 +0000 (UTC) Received: from test1135.test.redhat.com (vpn2-54-73.bne.redhat.com [10.64.54.73]) by smtp.corp.redhat.com (Postfix) with ESMTP id 14B4C2027047; Wed, 8 Aug 2018 05:07:59 +0000 (UTC) From: Ronnie Sahlberg To: linux-cifs Cc: Steve French Subject: [PATCH 1/5] cifs: update receive_encrypted_standard to handle compounded responses Date: Wed, 8 Aug 2018 15:07:45 +1000 Message-Id: <20180808050749.26562-2-lsahlber@redhat.com> In-Reply-To: <20180808050749.26562-1-lsahlber@redhat.com> References: <20180808050749.26562-1-lsahlber@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.2]); Wed, 08 Aug 2018 05:08:01 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.2]); Wed, 08 Aug 2018 05:08:01 +0000 (UTC) for IP:'10.11.54.4' DOMAIN:'int-mx04.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'lsahlber@redhat.com' RCPT:'' Sender: linux-cifs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Signed-off-by: Ronnie Sahlberg --- fs/cifs/cifsglob.h | 5 +++- fs/cifs/connect.c | 82 ++++++++++++++++++++++++++++++++--------------------- fs/cifs/smb2ops.c | 61 +++++++++++++++++++++++++++++++++------ fs/cifs/transport.c | 2 -- 4 files changed, 107 insertions(+), 43 deletions(-) diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 41803d374da0..0c9ab62c3df4 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -76,6 +76,9 @@ #define SMB_ECHO_INTERVAL_MAX 600 #define SMB_ECHO_INTERVAL_DEFAULT 60 +/* maximum number of PDUs in one compound */ +#define MAX_COMPOUND 5 + /* * Default number of credits to keep available for SMB3. * This value is chosen somewhat arbitrarily. The Windows client @@ -458,7 +461,7 @@ struct smb_version_operations { struct smb_rqst *, struct smb_rqst *); int (*is_transform_hdr)(void *buf); int (*receive_transform)(struct TCP_Server_Info *, - struct mid_q_entry **); + struct mid_q_entry **, char **, int *); enum securityEnum (*select_sectype)(struct TCP_Server_Info *, enum securityEnum); int (*next_header)(char *); diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index d9bd10d295a9..20564ea71dd5 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -850,13 +850,14 @@ cifs_handle_standard(struct TCP_Server_Info *server, struct mid_q_entry *mid) static int cifs_demultiplex_thread(void *p) { - int length; + int i, num_mids, length; struct TCP_Server_Info *server = p; unsigned int pdu_length; unsigned int next_offset; char *buf = NULL; struct task_struct *task_to_wake = NULL; - struct mid_q_entry *mid_entry; + struct mid_q_entry *mids[MAX_COMPOUND]; + char *bufs[MAX_COMPOUND]; current->flags |= PF_MEMALLOC; cifs_dbg(FYI, "Demultiplex PID: %d\n", task_pid_nr(current)); @@ -923,58 +924,75 @@ cifs_demultiplex_thread(void *p) server->pdu_size = next_offset; } - mid_entry = NULL; + memset(mids, 0, sizeof(mids)); + memset(bufs, 0, sizeof(bufs)); + num_mids = 0; + if (server->ops->is_transform_hdr && server->ops->receive_transform && server->ops->is_transform_hdr(buf)) { length = server->ops->receive_transform(server, - &mid_entry); + mids, + bufs, + &num_mids); } else { - mid_entry = server->ops->find_mid(server, buf); + mids[0] = server->ops->find_mid(server, buf); + bufs[0] = buf; + if (mids[0]) + num_mids = 1; - if (!mid_entry || !mid_entry->receive) - length = standard_receive3(server, mid_entry); + if (!mids[0] || !mids[0]->receive) + length = standard_receive3(server, mids[0]); else - length = mid_entry->receive(server, mid_entry); + length = mids[0]->receive(server, mids[0]); } if (length < 0) { - if (mid_entry) - cifs_mid_q_entry_release(mid_entry); + for (i = 0; i < num_mids; i++) + if (mids[i]) + cifs_mid_q_entry_release(mids[i]); continue; } if (server->large_buf) buf = server->bigbuf; + //qqq server->lstrp = jiffies; - if (mid_entry != NULL) { - mid_entry->resp_buf_size = server->pdu_size; - if ((mid_entry->mid_flags & MID_WAIT_CANCELLED) && - mid_entry->mid_state == MID_RESPONSE_RECEIVED && - server->ops->handle_cancelled_mid) - server->ops->handle_cancelled_mid( - mid_entry->resp_buf, - server); - if (!mid_entry->multiRsp || mid_entry->multiEnd) - mid_entry->callback(mid_entry); + for (i = 0; i < num_mids; i++) { + if (mids[i] != NULL) { + mids[i]->resp_buf_size = server->pdu_size; + if ((mids[i]->mid_flags & MID_WAIT_CANCELLED) && + mids[i]->mid_state == MID_RESPONSE_RECEIVED && + server->ops->handle_cancelled_mid) + server->ops->handle_cancelled_mid( + mids[i]->resp_buf, + server); - cifs_mid_q_entry_release(mid_entry); - } else if (server->ops->is_oplock_break && - server->ops->is_oplock_break(buf, server)) { - cifs_dbg(FYI, "Received oplock break\n"); - } else { - cifs_dbg(VFS, "No task to wake, unknown frame received! NumMids %d\n", - atomic_read(&midCount)); - cifs_dump_mem("Received Data is: ", buf, - HEADER_SIZE(server)); + if (!mids[i]->multiRsp || mids[i]->multiEnd) + mids[i]->callback(mids[i]); + + cifs_mid_q_entry_release(mids[i]); + } else if (server->ops->is_oplock_break && + server->ops->is_oplock_break(bufs[i], + server)) { + cifs_dbg(FYI, "Received oplock break\n"); + } else { + cifs_dbg(VFS, "No task to wake, unknown frame " + "received! NumMids %d\n", + atomic_read(&midCount)); + cifs_dump_mem("Received Data is: ", bufs[i], + HEADER_SIZE(server)); #ifdef CONFIG_CIFS_DEBUG2 - if (server->ops->dump_detail) - server->ops->dump_detail(buf, server); - cifs_dump_mids(server); + if (server->ops->dump_detail) + server->ops->dump_detail(bufs[i], + server); + cifs_dump_mids(server); #endif /* CIFS_DEBUG2 */ + } } + if (pdu_length > server->pdu_size) { if (!allocate_buffers(server)) continue; diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index ebc13ebebddf..5f3f27e33244 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -2942,13 +2942,20 @@ receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid) static int receive_encrypted_standard(struct TCP_Server_Info *server, - struct mid_q_entry **mid) + struct mid_q_entry **mids, char **bufs, + int *num_mids) { - int length; + int ret, length; char *buf = server->smallbuf; + char *tmpbuf; + struct smb2_sync_hdr *shdr; unsigned int pdu_length = server->pdu_size; unsigned int buf_size; struct mid_q_entry *mid_entry; + int next_is_large; + char *next_buffer = NULL; + + *num_mids = 0; /* switch to large buffer if too big for a small one */ if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE) { @@ -2969,24 +2976,61 @@ receive_encrypted_standard(struct TCP_Server_Info *server, if (length) return length; + next_is_large = server->large_buf; + one_more: + shdr = (struct smb2_sync_hdr *)buf; + if (shdr->NextCommand) { + if (next_is_large) { + tmpbuf = server->bigbuf; + next_buffer = (char *)cifs_buf_get(); + } else { + tmpbuf = server->smallbuf; + next_buffer = (char *)cifs_small_buf_get(); + } + memcpy(next_buffer, + tmpbuf + le32_to_cpu(shdr->NextCommand), + pdu_length - le32_to_cpu(shdr->NextCommand)); + } + mid_entry = smb2_find_mid(server, buf); if (mid_entry == NULL) cifs_dbg(FYI, "mid not found\n"); else { cifs_dbg(FYI, "mid found\n"); mid_entry->decrypted = true; + mid_entry->resp_buf_size = server->pdu_size; } - *mid = mid_entry; + if (*num_mids >= MAX_COMPOUND) { + cifs_dbg(VFS, "too many PDUs in compound\n"); + return -1; + } + bufs[*num_mids] = buf; + mids[(*num_mids)++] = mid_entry; if (mid_entry && mid_entry->handle) - return mid_entry->handle(server, mid_entry); + ret = mid_entry->handle(server, mid_entry); + else + ret = cifs_handle_standard(server, mid_entry); + + if (ret == 0 && shdr->NextCommand) { + pdu_length -= le32_to_cpu(shdr->NextCommand); + server->large_buf = next_is_large; + if (next_is_large) { + server->bigbuf = next_buffer; + } else { + server->smallbuf = next_buffer; + } + buf += le32_to_cpu(shdr->NextCommand); + goto one_more; + } - return cifs_handle_standard(server, mid_entry); + return ret; } static int -smb3_receive_transform(struct TCP_Server_Info *server, struct mid_q_entry **mid) +smb3_receive_transform(struct TCP_Server_Info *server, + struct mid_q_entry **mids, char **bufs, int *num_mids) { char *buf = server->smallbuf; unsigned int pdu_length = server->pdu_size; @@ -3009,10 +3053,11 @@ smb3_receive_transform(struct TCP_Server_Info *server, struct mid_q_entry **mid) return -ECONNABORTED; } + /* TODO: add support for compounds containing READ. */ if (pdu_length > CIFSMaxBufSize + MAX_HEADER_SIZE(server)) - return receive_encrypted_read(server, mid); + return receive_encrypted_read(server, &mids[0]); - return receive_encrypted_standard(server, mid); + return receive_encrypted_standard(server, mids, bufs, num_mids); } int diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index c53c0908d4c6..78f96fa3d7d9 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -383,8 +383,6 @@ __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst, return rc; } -#define MAX_COMPOUND 5 - static int smb_send_rqst(struct TCP_Server_Info *server, int num_rqst, struct smb_rqst *rqst, int flags)