2012/7/10 <shirishpargaonkar@xxxxxxxxx>: > From: Shirish Pargaonkar <shirishpargaonkar@xxxxxxxxx> > > > 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 <shirishpargaonkar@xxxxxxxxx> > Reported-by: Tushar Gosavi <tugosavi@xxxxxxxxxx> > --- > 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; While the existing code uses the same "pSMB" names I suggest to follow kernel coding style for a new code. May be something like "req" and "rsp" more suitable? > + 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, This will cause merge conflicts with my smb2 changes - but I am not sure what Steve prefer to merge at first. > 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 && > -- > 1.6.0.2 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-cifs" in > the body of a message to majordomo@xxxxxxxxxxxxxxx > More majordomo info at http://vger.kernel.org/majordomo-info.html -- Best regards, Pavel Shilovsky. -- To unsubscribe from this list: send the line "unsubscribe linux-cifs" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html