From patchwork Thu Mar 22 04:24: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: 889229 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=linux-cifs-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 406D9b6T51z9s1c for ; Thu, 22 Mar 2018 15:25:23 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751902AbeCVEZX (ORCPT ); Thu, 22 Mar 2018 00:25:23 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:45360 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1751848AbeCVEZX (ORCPT ); Thu, 22 Mar 2018 00:25:23 -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 A6E69402333B; Thu, 22 Mar 2018 04:25:22 +0000 (UTC) Received: from test1190.test.redhat.com (vpn2-54-110.bne.redhat.com [10.64.54.110]) by smtp.corp.redhat.com (Postfix) with ESMTP id 30B342026980; Thu, 22 Mar 2018 04:25:20 +0000 (UTC) From: Ronnie Sahlberg To: linux-cifs Cc: Steve French Subject: [PATCH 16/16] cifs: update smb2_queryfs() to use compounding Date: Thu, 22 Mar 2018 15:24:07 +1100 Message-Id: <20180322042407.7599-17-lsahlber@redhat.com> In-Reply-To: <20180322042407.7599-1-lsahlber@redhat.com> References: <20180322042407.7599-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.6]); Thu, 22 Mar 2018 04:25:22 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.6]); Thu, 22 Mar 2018 04:25:22 +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 Change smb2_queryfs() to use a Create/QueryInfo/Close compound request. Signed-off-by: Ronnie Sahlberg Signed-off-by: Aurelien Aptel --- fs/cifs/smb2ops.c | 104 +++++++++++++++++++++++++++++++++++++++++++++++++--- fs/cifs/smb2pdu.c | 30 +++++++-------- fs/cifs/smb2pdu.h | 2 + fs/cifs/smb2proto.h | 5 +++ fs/cifs/transport.c | 2 +- 5 files changed, 121 insertions(+), 22 deletions(-) diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index dab8faade491..17c6617eb338 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -1282,15 +1282,64 @@ 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; +} + +static void +smb2_set_next_command(struct smb_rqst *rqst) +{ + struct smb2_sync_hdr *shdr; + unsigned long len = smb2_rqst_len(rqst); + static char padding[7] = {0, 0, 0, 0, 0, 0, 0}; + + /* SMB headers in a compound are 8 byte aligned. */ + if (len & 7) { + rqst->rq_iov[rqst->rq_nvec].iov_base = 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; @@ -1299,13 +1348,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); + 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 d077862f124c..e7dde1bf5ae9 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -2155,9 +2155,9 @@ SMB2_close(const unsigned int xid, struct cifs_tcon *tcon, return rc; } -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; @@ -2201,7 +2201,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; @@ -3234,9 +3234,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; @@ -3535,9 +3535,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); @@ -3617,11 +3617,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); @@ -3678,7 +3678,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 6bf243a45d64..a939413aab07 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 { diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h index b210a6fb9056..1e812ff2364b 100644 --- a/fs/cifs/smb2proto.h +++ b/fs/cifs/smb2proto.h @@ -216,6 +216,11 @@ 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 b959ac40976c..833552c9549e 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;