From patchwork Wed Apr 18 01:45:14 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ronnie Sahlberg X-Patchwork-Id: 10347115 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 AC3D160542 for ; Wed, 18 Apr 2018 01:45:25 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id A2C3428474 for ; Wed, 18 Apr 2018 01:45:25 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 97BFF28477; Wed, 18 Apr 2018 01:45:25 +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 1CAFA28474 for ; Wed, 18 Apr 2018 01:45:24 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752757AbeDRBpY (ORCPT ); Tue, 17 Apr 2018 21:45:24 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:47742 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1751248AbeDRBpX (ORCPT ); Tue, 17 Apr 2018 21:45: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 29D198D76C; Wed, 18 Apr 2018 01:45:23 +0000 (UTC) Received: from test1190.test.redhat.com (vpn2-54-111.bne.redhat.com [10.64.54.111]) by smtp.corp.redhat.com (Postfix) with ESMTP id 420202026DFD; Wed, 18 Apr 2018 01:45:21 +0000 (UTC) From: Ronnie Sahlberg To: linux-cifs Cc: Steve French Subject: [PATCH] cifs: use FsFullSizeInfo in qfs since it is quota aware Date: Wed, 18 Apr 2018 11:45:14 +1000 Message-Id: <20180418014514.26919-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, 18 Apr 2018 01:45:23 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.2]); Wed, 18 Apr 2018 01:45:23 +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 RHBZ:1505772 In SMB2 we already query FsFullSizeInfo for queryfs since this infolevel is quota-aware. SMB1 used FsSizeInfo but this infolevel does not provide info about quota and thus it will cause 'df' and similar commands to show the wrong amount of data for the share if quotas have been set. This patch changes cifs_queryfs() to first try FsFullSizeInfo and only fallback to FsSizeInfo if FsFullSizeInfo is not available. This makes SMB1 'df' show the correct amounts for quota enabled shares. Reported-by: Xiaoli Feng Signed-off-by: Ronnie Sahlberg --- fs/cifs/cifspdu.h | 8 ++++++ fs/cifs/cifsproto.h | 2 ++ fs/cifs/cifssmb.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++ fs/cifs/smb1ops.c | 6 ++++ 4 files changed, 96 insertions(+) diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index 1ce733f3582f..097b55f22250 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -2153,6 +2153,14 @@ struct aliasInfo92 { typedef struct { __le64 TotalAllocationUnits; + __le64 CallerAvailableUnits; + __le64 ActualAvailableUnits; + __le32 SectorsPerAllocationUnit; + __le32 BytesPerSector; +} __attribute__((packed)) FILE_SYSTEM_FULL_INFO; /* size info, level 0x3ef */ + +typedef struct { + __le64 TotalAllocationUnits; __le64 FreeAllocationUnits; __le32 SectorsPerAllocationUnit; __le32 BytesPerSector; diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 365a414a75e9..f9b4dbbd1039 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -298,6 +298,8 @@ extern int parse_dfs_referrals(struct get_dfs_referral_rsp *rsp, u32 rsp_size, extern void reset_cifs_unix_caps(unsigned int xid, struct cifs_tcon *tcon, struct cifs_sb_info *cifs_sb, struct smb_vol *vol); +extern int CIFSSMBQFSFullInfo(const unsigned int xid, struct cifs_tcon *tcon, + struct kstatfs *FSData); extern int CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon, struct kstatfs *FSData); extern int SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon, diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 6d3e40d7029c..b9e921eee4f0 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -5015,6 +5015,86 @@ SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon, } int +CIFSSMBQFSFullInfo(const unsigned int xid, struct cifs_tcon *tcon, + struct kstatfs *FSData) +{ +/* level 0x3ef SMB_QUERY_FILE_SYSTEM_FULL_INFO */ + TRANSACTION2_QFSI_REQ *pSMB = NULL; + TRANSACTION2_QFSI_RSP *pSMBr = NULL; + FILE_SYSTEM_FULL_INFO *response_data; + int rc = 0; + int bytes_returned = 0; + __u16 params, byte_count; + + cifs_dbg(FYI, "In QFSFullInfo\n"); +QFSInfoRetry: + rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + params = 2; /* level */ + pSMB->TotalDataCount = 0; + pSMB->MaxParameterCount = cpu_to_le16(2); + pSMB->MaxDataCount = cpu_to_le16(1000); + pSMB->MaxSetupCount = 0; + pSMB->Reserved = 0; + pSMB->Flags = 0; + pSMB->Timeout = 0; + pSMB->Reserved2 = 0; + byte_count = params + 1 /* pad */ ; + pSMB->TotalParameterCount = cpu_to_le16(params); + pSMB->ParameterCount = pSMB->TotalParameterCount; + pSMB->ParameterOffset = cpu_to_le16(offsetof( + struct smb_com_transaction2_qfsi_req, InformationLevel) - 4); + pSMB->DataCount = 0; + pSMB->DataOffset = 0; + pSMB->SetupCount = 1; + pSMB->Reserved3 = 0; + pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); + pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_FULL_SIZE_INFO); + inc_rfc1001_len(pSMB, byte_count); + pSMB->ByteCount = cpu_to_le16(byte_count); + + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) { + cifs_dbg(FYI, "Send error in QFSFullInfo = %d\n", rc); + } else { /* decode response */ + rc = validate_t2((struct smb_t2_rsp *)pSMBr); + + if (rc || get_bcc(&pSMBr->hdr) < 24) + rc = -EIO; /* bad smb */ + else { + __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); + + response_data = + (FILE_SYSTEM_FULL_INFO + *) (((char *) &pSMBr->hdr.Protocol) + + data_offset); + FSData->f_bsize = + le32_to_cpu(response_data->BytesPerSector) * + le32_to_cpu(response_data-> + SectorsPerAllocationUnit); + FSData->f_blocks = + le64_to_cpu(response_data->TotalAllocationUnits); + FSData->f_bfree = FSData->f_bavail = + le64_to_cpu(response_data->CallerAvailableUnits); + cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n", + (unsigned long long)FSData->f_blocks, + (unsigned long long)FSData->f_bfree, + FSData->f_bsize); + } + } + cifs_buf_release(pSMB); + + if (rc == -EAGAIN) + goto QFSInfoRetry; + + return rc; +} + +int CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon, struct kstatfs *FSData) { diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c index aff8ce8ba34d..da723e2c1d85 100644 --- a/fs/cifs/smb1ops.c +++ b/fs/cifs/smb1ops.c @@ -900,6 +900,12 @@ cifs_queryfs(const unsigned int xid, struct cifs_tcon *tcon, rc = CIFSSMBQFSPosixInfo(xid, tcon, buf); /* + * Try FsFullSizeInformation (as it is quota aware) + */ + if (rc && (tcon->ses->capabilities & CAP_NT_SMBS)) + rc = CIFSSMBQFSFullInfo(xid, tcon, buf); + + /* * Only need to call the old QFSInfo if failed on newer one, * e.g. by OS/2. **/