From patchwork Mon Jun 11 22:01:07 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ronnie Sahlberg X-Patchwork-Id: 10458921 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 455D26020F for ; Mon, 11 Jun 2018 22:01:41 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 33272285E8 for ; Mon, 11 Jun 2018 22:01:41 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 280FE285EB; Mon, 11 Jun 2018 22:01:41 +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 6A1F7285E8 for ; Mon, 11 Jun 2018 22:01:40 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932893AbeFKWBk (ORCPT ); Mon, 11 Jun 2018 18:01:40 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:38608 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S932230AbeFKWBj (ORCPT ); Mon, 11 Jun 2018 18:01:39 -0400 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.rdu2.redhat.com [10.11.54.5]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 107DABB428; Mon, 11 Jun 2018 22:01:39 +0000 (UTC) Received: from test1135.test.redhat.com (vpn2-54-65.bne.redhat.com [10.64.54.65]) by smtp.corp.redhat.com (Postfix) with ESMTP id 2E9B364003; Mon, 11 Jun 2018 22:01:37 +0000 (UTC) From: Ronnie Sahlberg To: linux-cifs Cc: Steve French Subject: [PATCH 10/10] cifs: update smb2_queryfs() to use compounding Date: Tue, 12 Jun 2018 08:01:07 +1000 Message-Id: <20180611220107.17468-11-lsahlber@redhat.com> In-Reply-To: <20180611220107.17468-1-lsahlber@redhat.com> References: <20180611220107.17468-1-lsahlber@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.11.54.5 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Mon, 11 Jun 2018 22:01:39 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Mon, 11 Jun 2018 22:01:39 +0000 (UTC) for IP:'10.11.54.5' DOMAIN:'int-mx05.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 Change smb2_queryfs() to use a Create/QueryInfo/Close compound request. Signed-off-by: Ronnie Sahlberg --- fs/cifs/smb2ops.c | 105 +++++++++++++++++++++++++++++++++++++++++++++++++--- fs/cifs/smb2pdu.c | 35 +++++++++--------- fs/cifs/smb2pdu.h | 4 ++ fs/cifs/smb2proto.h | 7 ++++ fs/cifs/transport.c | 2 +- 5 files changed, 129 insertions(+), 24 deletions(-) diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 5a8fa42c2fa9..b247eb5fa1c9 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -1345,15 +1345,65 @@ smb2_oplock_response(struct cifs_tcon *tcon, struct cifs_fid *fid, CIFS_CACHE_READ(cinode) ? 1 : 0); } +static void +smb2_set_related(struct smb_rqst *rqst) +{ + struct smb2_sync_hdr *shdr; + + shdr = (struct smb2_sync_hdr *)(rqst->rq_iov[0].iov_base); + shdr->Flags |= SMB2_FLAGS_RELATED_OPERATIONS; +} + +char smb2_padding[7] = {0, 0, 0, 0, 0, 0, 0}; + +static void +smb2_set_next_command(struct smb_rqst *rqst) +{ + struct smb2_sync_hdr *shdr; + unsigned long len = smb2_rqst_len(rqst); + + /* SMB headers in a compound are 8 byte aligned. */ + if (len & 7) { + rqst->rq_iov[rqst->rq_nvec].iov_base = smb2_padding; + rqst->rq_iov[rqst->rq_nvec].iov_len = 8 - (len & 7); + rqst->rq_nvec++; + len = smb2_rqst_len(rqst); + } + + shdr = (struct smb2_sync_hdr *)(rqst->rq_iov[0].iov_base); + shdr->NextCommand = cpu_to_le32(len); +} + static int smb2_queryfs(const unsigned int xid, struct cifs_tcon *tcon, struct kstatfs *buf) { - int rc; + struct smb2_query_info_rsp *rsp; + struct smb2_fs_full_size_info *info = NULL; + struct smb_rqst rqst[3]; + int resp_buftype[3]; + struct kvec rsp_iov[3]; + struct kvec open_iov[5]; /* 4 + potential padding. */ + struct kvec qi_iov[1]; + struct kvec close_iov[1]; + struct cifs_ses *ses = tcon->ses; __le16 srch_path = 0; /* Null - open root of share */ u8 oplock = SMB2_OPLOCK_LEVEL_NONE; struct cifs_open_parms oparms; struct cifs_fid fid; + int flags = 0; + int rc; + + if (smb3_encryption_required(tcon)) + flags |= CIFS_TRANSFORM_REQ; + + memset(rqst, 0, sizeof(rqst)); + memset(resp_buftype, 0, sizeof(resp_buftype)); + memset(rsp_iov, 0, sizeof(rsp_iov)); + + memset(&open_iov, 0, sizeof(open_iov)); + rqst[0].rq_iov = open_iov; + rqst[0].rq_nvec = 4; oparms.tcon = tcon; oparms.desired_access = FILE_READ_ATTRIBUTES; @@ -1362,13 +1412,56 @@ smb2_queryfs(const unsigned int xid, struct cifs_tcon *tcon, oparms.fid = &fid; oparms.reconnect = false; - rc = SMB2_open(xid, &oparms, &srch_path, &oplock, NULL, NULL, NULL); + rc = SMB2_open_init(tcon, &rqst[0], &oplock, &oparms, &srch_path); if (rc) - return rc; + goto qfs_exit; + smb2_set_next_command(&rqst[0]); + + memset(&qi_iov, 0, sizeof(qi_iov)); + rqst[1].rq_iov = qi_iov; + rqst[1].rq_nvec = 1; + + rc = SMB2_query_info_init(tcon, &rqst[1], COMPOUND_FID, COMPOUND_FID, + FS_FULL_SIZE_INFORMATION, + SMB2_O_INFO_FILESYSTEM, 0, + sizeof(struct smb2_fs_full_size_info)); + if (rc) + goto qfs_exit; + smb2_set_next_command(&rqst[1]); + smb2_set_related(&rqst[1]); + + memset(&close_iov, 0, sizeof(close_iov)); + rqst[2].rq_iov = close_iov; + rqst[2].rq_nvec = 1; + + rc = SMB2_close_init(tcon, &rqst[2], COMPOUND_FID, COMPOUND_FID); + if (rc) + goto qfs_exit; + smb2_set_related(&rqst[2]); + + rc = compound_send_recv(xid, ses, flags, 3, rqst, + resp_buftype, rsp_iov); + if (rc) + goto qfs_exit; + + rsp = (struct smb2_query_info_rsp *)rsp_iov[1].iov_base; buf->f_type = SMB2_MAGIC_NUMBER; - rc = SMB2_QFS_info(xid, tcon, fid.persistent_fid, fid.volatile_fid, - buf); - SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid); + info = (struct smb2_fs_full_size_info *)( + le16_to_cpu(rsp->OutputBufferOffset) + (char *)rsp); + rc = smb2_validate_iov(le16_to_cpu(rsp->OutputBufferOffset), + le32_to_cpu(rsp->OutputBufferLength), + &rsp_iov[1], + sizeof(struct smb2_fs_full_size_info)); + if (!rc) + smb2_copy_fs_info_to_kstatfs(info, buf); + +qfs_exit: + SMB2_open_free(&rqst[0]); + SMB2_query_info_free(&rqst[1]); + SMB2_close_free(&rqst[2]); + free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base); + free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base); + free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base); return rc; } diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index b7325bbc0bf5..129c3a55f28d 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -80,7 +80,7 @@ static const int smb2_req_struct_sizes[NUMBER_OF_SMB2_COMMANDS] = { /* SMB2_OPLOCK_BREAK */ 24 /* BB this is 36 for LEASE_BREAK variant */ }; -static int smb3_encryption_required(const struct cifs_tcon *tcon) +int smb3_encryption_required(const struct cifs_tcon *tcon) { if (!tcon) return 0; @@ -2040,7 +2040,8 @@ SMB2_open_free(struct smb_rqst *rqst) { cifs_small_buf_release(rqst->rq_iov[0].iov_base); for (i = 1; i < rqst->rq_nvec; i++) - kfree(rqst->rq_iov[i].iov_base); + if (rqst->rq_iov[i].iov_base != smb2_padding) + kfree(rqst->rq_iov[i].iov_base); } int @@ -2387,9 +2388,9 @@ SMB2_close(const unsigned int xid, struct cifs_tcon *tcon, return SMB2_close_flags(xid, tcon, persistent_fid, volatile_fid, 0); } -static int -validate_iov(unsigned int offset, unsigned int buffer_length, - struct kvec *iov, unsigned int min_buf_size) +int +smb2_validate_iov(unsigned int offset, unsigned int buffer_length, + struct kvec *iov, unsigned int min_buf_size) { unsigned int smb_len = iov->iov_len; char *end_of_smb = smb_len + (char *)iov->iov_base; @@ -2433,7 +2434,7 @@ validate_and_copy_iov(unsigned int offset, unsigned int buffer_length, if (!data) return -EINVAL; - rc = validate_iov(offset, buffer_length, iov, minbufsize); + rc = smb2_validate_iov(offset, buffer_length, iov, minbufsize); if (rc) return rc; @@ -3505,9 +3506,9 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon, goto qdir_exit; } - rc = validate_iov(le16_to_cpu(rsp->OutputBufferOffset), - le32_to_cpu(rsp->OutputBufferLength), &rsp_iov, - info_buf_size); + rc = smb2_validate_iov(le16_to_cpu(rsp->OutputBufferOffset), + le32_to_cpu(rsp->OutputBufferLength), &rsp_iov, + info_buf_size); if (rc) goto qdir_exit; @@ -3809,9 +3810,9 @@ SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon, return rc; } -static void -copy_fs_info_to_kstatfs(struct smb2_fs_full_size_info *pfs_inf, - struct kstatfs *kst) +void +smb2_copy_fs_info_to_kstatfs(struct smb2_fs_full_size_info *pfs_inf, + struct kstatfs *kst) { kst->f_bsize = le32_to_cpu(pfs_inf->BytesPerSector) * le32_to_cpu(pfs_inf->SectorsPerAllocationUnit); @@ -3894,11 +3895,11 @@ SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon, info = (struct smb2_fs_full_size_info *)( le16_to_cpu(rsp->OutputBufferOffset) + (char *)rsp); - rc = validate_iov(le16_to_cpu(rsp->OutputBufferOffset), - le32_to_cpu(rsp->OutputBufferLength), &rsp_iov, - sizeof(struct smb2_fs_full_size_info)); + rc = smb2_validate_iov(le16_to_cpu(rsp->OutputBufferOffset), + le32_to_cpu(rsp->OutputBufferLength), &rsp_iov, + sizeof(struct smb2_fs_full_size_info)); if (!rc) - copy_fs_info_to_kstatfs(info, fsdata); + smb2_copy_fs_info_to_kstatfs(info, fsdata); qfsinf_exit: free_rsp_buf(resp_buftype, rsp_iov.iov_base); @@ -3955,7 +3956,7 @@ SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon, rsp_len = le32_to_cpu(rsp->OutputBufferLength); offset = le16_to_cpu(rsp->OutputBufferOffset); - rc = validate_iov(offset, rsp_len, &rsp_iov, min_len); + rc = smb2_validate_iov(offset, rsp_len, &rsp_iov, min_len); if (rc) goto qfsattr_exit; diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h index a345560001ce..41afebbcbabc 100644 --- a/fs/cifs/smb2pdu.h +++ b/fs/cifs/smb2pdu.h @@ -153,6 +153,8 @@ struct smb2_transform_hdr { * */ +#define COMPOUND_FID 0xFFFFFFFFFFFFFFFFULL + #define SMB2_ERROR_STRUCTURE_SIZE2 cpu_to_le16(9) struct smb2_err_rsp { @@ -1346,4 +1348,6 @@ struct smb2_file_eof_info { /* encoding of request for level 10 */ __le64 EndOfFile; /* new end of file value */ } __packed; /* level 20 Set */ +extern char smb2_padding[7]; + #endif /* _SMB2PDU_H */ diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h index 8c6057a91bc4..ed2e6e587901 100644 --- a/fs/cifs/smb2proto.h +++ b/fs/cifs/smb2proto.h @@ -219,6 +219,13 @@ extern int smb3_validate_negotiate(const unsigned int, struct cifs_tcon *); extern enum securityEnum smb2_select_sectype(struct TCP_Server_Info *, enum securityEnum); +extern int smb3_encryption_required(const struct cifs_tcon *tcon); +extern int smb2_validate_iov(unsigned int offset, unsigned int buffer_length, + struct kvec *iov, unsigned int min_buf_size); +extern void smb2_copy_fs_info_to_kstatfs( + struct smb2_fs_full_size_info *pfs_inf, + struct kstatfs *kst); +extern unsigned long smb2_rqst_len(struct smb_rqst *rqst); #ifdef CONFIG_CIFS_SMB311 extern int smb311_crypto_shash_allocate(struct TCP_Server_Info *server); extern int smb311_update_preauth_hash(struct cifs_ses *ses, diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 7987045cd4b3..cec2a6526003 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -201,7 +201,7 @@ smb_send_kvec(struct TCP_Server_Info *server, struct msghdr *smb_msg, return 0; } -static unsigned long +unsigned long smb2_rqst_len(struct smb_rqst *rqst) { unsigned int i;