2012/7/10 <[email protected]>:
> From: Shirish Pargaonkar <[email protected]>
>
>
> 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 <[email protected]>
> Reported-by: Tushar Gosavi <[email protected]>
> ---
> 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 [email protected]
> 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 [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html