aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/fs/cifs/smb2pdu.c
diff options
context:
space:
mode:
authorSteve French <stfrench@microsoft.com>2019-12-02 21:46:54 -0600
committerSteve French <stfrench@microsoft.com>2019-12-03 15:48:02 -0600
commit43f8a6a74ee2442b9410ed297f5d4c77e7cb5ace (patch)
tree0eabdc6fb77016e544ea32569722114e67b8a6b9 /fs/cifs/smb2pdu.c
parentsmb3: remove unused flag passed into close functions (diff)
downloadwireguard-linux-43f8a6a74ee2442b9410ed297f5d4c77e7cb5ace.tar.xz
wireguard-linux-43f8a6a74ee2442b9410ed297f5d4c77e7cb5ace.zip
smb3: query attributes on file close
Since timestamps on files on most servers can be updated at close, and since timestamps on our dentries default to one second we can have stale timestamps in some common cases (e.g. open, write, close, stat, wait one second, stat - will show different mtime for the first and second stat). The SMB2/SMB3 protocol allows querying timestamps at close so add the code to request timestamp and attr information (which is cheap for the server to provide) to be returned when a file is closed (it is not needed for the many paths that call SMB2_close that are from compounded query infos and close nor is it needed for some of the cases where a directory close immediately follows a directory open. Signed-off-by: Steve French <stfrench@microsoft.com> Acked-by: Ronnie Sahlberg <lsahlber@redhat.com> Reviewed-by: Aurelien Aptel <aaptel@suse.com> Reviewed-by: Pavel Shilovsky <pshilov@microsoft.com>
Diffstat (limited to 'fs/cifs/smb2pdu.c')
-rw-r--r--fs/cifs/smb2pdu.c38
1 files changed, 30 insertions, 8 deletions
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index cec53eb8a6da..187a5ce68806 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -2932,7 +2932,7 @@ SMB2_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
int
SMB2_close_init(struct cifs_tcon *tcon, struct smb_rqst *rqst,
- u64 persistent_fid, u64 volatile_fid)
+ u64 persistent_fid, u64 volatile_fid, bool query_attrs)
{
struct smb2_close_req *req;
struct kvec *iov = rqst->rq_iov;
@@ -2945,6 +2945,10 @@ SMB2_close_init(struct cifs_tcon *tcon, struct smb_rqst *rqst,
req->PersistentFileId = persistent_fid;
req->VolatileFileId = volatile_fid;
+ if (query_attrs)
+ req->Flags = SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB;
+ else
+ req->Flags = 0;
iov[0].iov_base = (char *)req;
iov[0].iov_len = total_len;
@@ -2959,8 +2963,9 @@ SMB2_close_free(struct smb_rqst *rqst)
}
int
-SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
- u64 persistent_fid, u64 volatile_fid)
+__SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
+ u64 persistent_fid, u64 volatile_fid,
+ struct smb2_file_network_open_info *pbuf)
{
struct smb_rqst rqst;
struct smb2_close_rsp *rsp = NULL;
@@ -2970,6 +2975,7 @@ SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
int resp_buftype = CIFS_NO_BUFFER;
int rc = 0;
int flags = 0;
+ bool query_attrs = false;
cifs_dbg(FYI, "Close\n");
@@ -2984,8 +2990,13 @@ SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
rqst.rq_iov = iov;
rqst.rq_nvec = 1;
+ /* check if need to ask server to return timestamps in close response */
+ if (pbuf)
+ query_attrs = true;
+
trace_smb3_close_enter(xid, persistent_fid, tcon->tid, ses->Suid);
- rc = SMB2_close_init(tcon, &rqst, persistent_fid, volatile_fid);
+ rc = SMB2_close_init(tcon, &rqst, persistent_fid, volatile_fid,
+ query_attrs);
if (rc)
goto close_exit;
@@ -2997,14 +3008,18 @@ SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
trace_smb3_close_err(xid, persistent_fid, tcon->tid, ses->Suid,
rc);
goto close_exit;
- } else
+ } else {
trace_smb3_close_done(xid, persistent_fid, tcon->tid,
ses->Suid);
+ /*
+ * Note that have to subtract 4 since struct network_open_info
+ * has a final 4 byte pad that close response does not have
+ */
+ if (pbuf)
+ memcpy(pbuf, (char *)&rsp->CreationTime, sizeof(*pbuf) - 4);
+ }
atomic_dec(&tcon->num_remote_opens);
-
- /* BB FIXME - decode close response, update inode for caching */
-
close_exit:
SMB2_close_free(&rqst);
free_rsp_buf(resp_buftype, rsp);
@@ -3023,6 +3038,13 @@ close_exit:
}
int
+SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
+ u64 persistent_fid, u64 volatile_fid)
+{
+ return __SMB2_close(xid, tcon, persistent_fid, volatile_fid, NULL);
+}
+
+int
smb2_validate_iov(unsigned int offset, unsigned int buffer_length,
struct kvec *iov, unsigned int min_buf_size)
{