summaryrefslogtreecommitdiff
path: root/fs/cifs
diff options
context:
space:
mode:
authorJeff Layton <jlayton@redhat.com>2010-02-12 07:44:16 -0500
committerSteve French <sfrench@us.ibm.com>2010-03-06 04:38:02 +0000
commitbcd5357f430363376565d07ca542127d6d36602c (patch)
treed92d915029eb1b06946de9deb91e5ab7604efa84 /fs/cifs
parentdf2cf170c823ba779ca339e3ede347c87f4dc6a9 (diff)
cifs: add a CIFSSMBQFileInfo function
...to get inode attributes via filehandle instead of by path. In some places, we need to revalidate an inode on an open filehandle, but we can't necessarily guarantee that the dentry associated with it will still be valid. When we have an open filehandle already, it makes more sense to do a filehandle based operation anyway. Signed-off-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: Steve French <sfrench@us.ibm.com>
Diffstat (limited to 'fs/cifs')
-rw-r--r--fs/cifs/cifsproto.h2
-rw-r--r--fs/cifs/cifssmb.c64
2 files changed, 66 insertions, 0 deletions
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 88e2bc44ac5..bf2bff14c24 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -142,6 +142,8 @@ extern int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
extern int CIFSFindClose(const int, struct cifsTconInfo *tcon,
const __u16 search_handle);
+extern int CIFSSMBQFileInfo(const int xid, struct cifsTconInfo *tcon,
+ u16 netfid, FILE_ALL_INFO *pFindData);
extern int CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
const unsigned char *searchName,
FILE_ALL_INFO *findData,
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 9d17df3e076..4ed97825db3 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -3230,8 +3230,72 @@ QInfRetry:
return rc;
}
+int
+CIFSSMBQFileInfo(const int xid, struct cifsTconInfo *tcon,
+ u16 netfid, FILE_ALL_INFO *pFindData)
+{
+ struct smb_t2_qfi_req *pSMB = NULL;
+ struct smb_t2_qfi_rsp *pSMBr = NULL;
+ int rc = 0;
+ int bytes_returned;
+ __u16 params, byte_count;
+
+QFileInfoRetry:
+ 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_t2_qfi_req,
+ Fid) - 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->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
+ pSMB->Pad = 0;
+ pSMB->Fid = netfid;
+ pSMB->hdr.smb_buf_length += byte_count;
+
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+ if (rc) {
+ cFYI(1, ("Send error in QPathInfo = %d", rc));
+ } else { /* decode response */
+ rc = validate_t2((struct smb_t2_rsp *)pSMBr);
+ if (rc) /* BB add auto retry on EOPNOTSUPP? */
+ rc = -EIO;
+ else if (pSMBr->ByteCount < 40)
+ rc = -EIO; /* bad smb */
+ else if (pFindData) {
+ __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
+ memcpy((char *) pFindData,
+ (char *) &pSMBr->hdr.Protocol +
+ data_offset, sizeof(FILE_ALL_INFO));
+ } else
+ rc = -ENOMEM;
+ }
+ cifs_buf_release(pSMB);
+ if (rc == -EAGAIN)
+ goto QFileInfoRetry;
+ return rc;
+}
int
CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,