From patchwork Tue Jul 10 13:13:48 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shirish Pargaonkar X-Patchwork-Id: 1177461 Return-Path: X-Original-To: patchwork-cifs-client@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by patchwork2.kernel.org (Postfix) with ESMTP id 26A73DFF34 for ; Tue, 10 Jul 2012 13:01:28 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755631Ab2GJNB1 (ORCPT ); Tue, 10 Jul 2012 09:01:27 -0400 Received: from mail-gh0-f174.google.com ([209.85.160.174]:44362 "EHLO mail-gh0-f174.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755589Ab2GJNB0 (ORCPT ); Tue, 10 Jul 2012 09:01:26 -0400 Received: by ghrr11 with SMTP id r11so11213270ghr.19 for ; Tue, 10 Jul 2012 06:01:26 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:x-mailer; bh=sNDOB7CFnIcM5ngDh2kM0TD7MX1xruCcIJsBgSUuYns=; b=urEC3Y+4Asr4vdOLIl8a22d1N2W5qU8O4SYEUQYPlPYMkxb036/vr74QJ6fpO0TqTM CXbRq6AS03O/xUVGTtTcUCF9/BXF934KS8Pm+nW3iQ6cEn25CZ2JWSZIoJcmGe/MddD0 l8QAKrnIXFL94OATYQKyzvkLEvQS9TZF4Yi5TcnCOr3obpd/ZoFuVvGIqbbtK5sygXzk L2NCwSvfCKOvtGtbN1aa79O4RhyvZIzRM5o6t4J2GacQG5es/WkshDKPdmEEGx6R+NEP wdWSd4aHeUrvuOcxcYbFY78lI3SqYZ30cIlZAclhNb2zQ+XrPgfHZ1tS53V2SdqsUWJa Dn4Q== Received: by 10.66.74.3 with SMTP id p3mr73387893pav.49.1341925285561; Tue, 10 Jul 2012 06:01:25 -0700 (PDT) Received: from localhost ([32.97.110.50]) by mx.google.com with ESMTPS id qp9sm29855303pbc.9.2012.07.10.06.01.24 (version=TLSv1/SSLv3 cipher=OTHER); Tue, 10 Jul 2012 06:01:25 -0700 (PDT) From: shirishpargaonkar@gmail.com To: smfrench@gmail.com Cc: linux-cifs@vger.kernel.org, tugosavi@in.ibm.com, Shirish Pargaonkar Subject: [PATCH] cifs: obtain file access during backup intent lookup Date: Tue, 10 Jul 2012 08:13:48 -0500 Message-Id: <1341926028-30845-1-git-send-email-shirishpargaonkar@gmail.com> X-Mailer: git-send-email 1.6.0.2 Sender: linux-cifs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org From: Shirish Pargaonkar path based querries can fail for lack of access, especially during lookup during open. open itself would actually succeed becasue of back up intent bit but querries (either path or file handle based) do not have a means to specifiy backup intent bit. So querry the file info during lookup using a file handle (based call) obtained by opening the file only for that purpose (and then closing the file). Add a file handle based call to obtain Index Number of a file in addition to an existing path based call. Signed-off-by: Shirish Pargaonkar Reported-by: Tushar Gosavi --- fs/cifs/cifsproto.h | 4 ++ fs/cifs/cifssmb.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++ fs/cifs/inode.c | 31 ++++++++++++++++++- 3 files changed, 113 insertions(+), 2 deletions(-) diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 0a6cbfe..3c63ee4 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -375,6 +375,10 @@ extern int CIFSGetSrvInodeNumber(const int xid, struct cifs_tcon *tcon, const unsigned char *searchName, __u64 *inode_number, const struct nls_table *nls_codepage, int remap_special_chars); +extern int CIFSGetFileSrvInodeNumber(const int xid, struct cifs_tcon *tcon, + u16 netfid, __u64 *inode_number, + const struct nls_table *nls_codepage, + int remap_special_chars); extern int cifs_lockv(const int xid, struct cifs_tcon *tcon, const __u16 netfid, const __u8 lock_type, const __u32 num_unlock, diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 5b40073..dcd4091 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -4621,6 +4621,86 @@ GetInodeNumOut: return rc; } +int +CIFSGetFileSrvInodeNumber(const int xid, struct cifs_tcon *tcon, + u16 netfid, __u64 *inode_number, + const struct nls_table *nls_codepage, int remap) +{ + int rc = 0; + struct smb_t2_qfi_req *pSMB = NULL; + struct smb_t2_qfi_rsp *pSMBr = NULL; + int bytes_returned; + __u16 params, byte_count; + + cFYI(1, "In %s", __func__); + if (tcon == NULL) + return -ENODEV; + +FileGetInodeNumberRetry: + rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + params = 2 /* level */ + 2 /* fid */; + pSMB->t2.TotalDataCount = 0; + pSMB->t2.MaxParameterCount = cpu_to_le16(4); + /* BB find exact max data count below from sess structure BB */ + pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize); + pSMB->t2.MaxSetupCount = 0; + pSMB->t2.Reserved = 0; + pSMB->t2.Flags = 0; + pSMB->t2.Timeout = 0; + pSMB->t2.Reserved2 = 0; + pSMB->t2.ParameterOffset = cpu_to_le16(offsetof( + struct smb_com_transaction2_qpi_req, InformationLevel) - 4); + pSMB->t2.DataCount = 0; + pSMB->t2.DataOffset = 0; + pSMB->t2.SetupCount = 1; + pSMB->t2.Reserved3 = 0; + pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION); + byte_count = params + 1 /* pad */ ; + pSMB->t2.TotalParameterCount = cpu_to_le16(params); + pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount; + pSMB->Fid = cpu_to_le16(netfid); + pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO); + inc_rfc1001_len(pSMB, byte_count); + pSMB->t2.ByteCount = cpu_to_le16(byte_count); + + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) { + cFYI(1, "error %d in QueryInternalInfo", rc); + } else { + /* decode response */ + rc = validate_t2((struct smb_t2_rsp *)pSMBr); + /* BB also check enough total bytes returned */ + if (rc || get_bcc(&pSMBr->hdr) < 2) + /* If rc should we check for EOPNOSUPP and + disable the srvino flag? or in caller? */ + rc = -EIO; /* bad smb */ + else { + __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); + __u16 count = le16_to_cpu(pSMBr->t2.DataCount); + struct file_internal_info *pfinfo; + /* BB Do we need a cast or hash here ? */ + if (count < 8) { + cFYI(1, "Illegal size ret in FileQryIntrnlInf"); + rc = -EIO; + goto FileGetInodeNumOut; + } + pfinfo = (struct file_internal_info *) + (data_offset + (char *) &pSMBr->hdr.Protocol); + *inode_number = le64_to_cpu(pfinfo->UniqueId); + } + } +FileGetInodeNumOut: + cifs_buf_release(pSMB); + if (rc == -EAGAIN) + goto FileGetInodeNumberRetry; + return rc; +} + /* parses DFS refferal V3 structure * caller is responsible for freeing target_nodes * returns: diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 745da3d..a7c07a0 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -604,7 +604,8 @@ int cifs_get_inode_info(struct inode **pinode, const unsigned char *full_path, FILE_ALL_INFO *pfindData, struct super_block *sb, int xid, const __u16 *pfid) { - int rc = 0, tmprc; + __u16 fid; + int rc = 0, rc2 = -EINVAL, tmprc, oplock = 0; struct cifs_tcon *pTcon; struct tcon_link *tlink; struct cifs_sb_info *cifs_sb = CIFS_SB(sb); @@ -640,6 +641,23 @@ int cifs_get_inode_info(struct inode **pinode, 0 /* not legacy */, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); + + /* + * This sequence of calls is meant for a lookup operation + * that would otherwise fail since query path info has no + * means to indicate backup intent. + */ + if (rc == -EACCES && *pinode == NULL && backup_cred(cifs_sb)) { + /* pfindData contains same info returned by qpathinfo */ + rc2 = CIFSSMBOpen(xid, pTcon, full_path, + FILE_OPEN, GENERIC_READ, + CREATE_OPEN_BACKUP_INTENT, &fid, &oplock, + pfindData, cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); + rc = rc2; + } + /* BB optimize code so we do not make the above call when server claims no NT SMB support and the above call failed at least once - set flag in tcon or mount */ @@ -683,7 +701,14 @@ int cifs_get_inode_info(struct inode **pinode, if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) { int rc1 = 0; - rc1 = CIFSGetSrvInodeNumber(xid, pTcon, + if (!rc2) + rc1 = CIFSGetFileSrvInodeNumber(xid, pTcon, + fid, &fattr.cf_uniqueid, + cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); + else + rc1 = CIFSGetSrvInodeNumber(xid, pTcon, full_path, &fattr.cf_uniqueid, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & @@ -699,6 +724,8 @@ int cifs_get_inode_info(struct inode **pinode, } else { fattr.cf_uniqueid = CIFS_I(*pinode)->uniqueid; } + if (!rc2) + CIFSSMBClose(xid, pTcon, fid); /* query for SFU type info if supported and needed */ if (fattr.cf_cifsattrs & ATTR_SYSTEM &&