Skip to content

Commit 43f8a6a

Browse files
committed
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 <[email protected]> Acked-by: Ronnie Sahlberg <[email protected]> Reviewed-by: Aurelien Aptel <[email protected]> Reviewed-by: Pavel Shilovsky <[email protected]>
1 parent 9e8fae2 commit 43f8a6a

File tree

7 files changed

+97
-15
lines changed

7 files changed

+97
-15
lines changed

fs/cifs/cifsglob.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,9 @@ struct smb_version_operations {
368368
/* close a file */
369369
void (*close)(const unsigned int, struct cifs_tcon *,
370370
struct cifs_fid *);
371+
/* close a file, returning file attributes and timestamps */
372+
void (*close_getattr)(const unsigned int xid, struct cifs_tcon *tcon,
373+
struct cifsFileInfo *pfile_info);
371374
/* send a flush request to the server */
372375
int (*flush)(const unsigned int, struct cifs_tcon *, struct cifs_fid *);
373376
/* async read from the server */

fs/cifs/file.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -496,7 +496,9 @@ void _cifsFileInfo_put(struct cifsFileInfo *cifs_file,
496496
unsigned int xid;
497497

498498
xid = get_xid();
499-
if (server->ops->close)
499+
if (server->ops->close_getattr)
500+
server->ops->close_getattr(xid, tcon, cifs_file);
501+
else if (server->ops->close)
500502
server->ops->close(xid, tcon, &cifs_file->fid);
501503
_free_xid(xid);
502504
}

fs/cifs/smb2inode.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,7 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
313313
rqst[num_rqst].rq_iov = close_iov;
314314
rqst[num_rqst].rq_nvec = 1;
315315
rc = SMB2_close_init(tcon, &rqst[num_rqst], COMPOUND_FID,
316-
COMPOUND_FID);
316+
COMPOUND_FID, false);
317317
smb2_set_related(&rqst[num_rqst]);
318318
if (rc)
319319
goto finished;

fs/cifs/smb2ops.c

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1178,7 +1178,7 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
11781178
memset(&close_iov, 0, sizeof(close_iov));
11791179
rqst[2].rq_iov = close_iov;
11801180
rqst[2].rq_nvec = 1;
1181-
rc = SMB2_close_init(tcon, &rqst[2], COMPOUND_FID, COMPOUND_FID);
1181+
rc = SMB2_close_init(tcon, &rqst[2], COMPOUND_FID, COMPOUND_FID, false);
11821182
smb2_set_related(&rqst[2]);
11831183

11841184
rc = compound_send_recv(xid, ses, flags, 3, rqst,
@@ -1332,6 +1332,45 @@ smb2_close_file(const unsigned int xid, struct cifs_tcon *tcon,
13321332
SMB2_close(xid, tcon, fid->persistent_fid, fid->volatile_fid);
13331333
}
13341334

1335+
static void
1336+
smb2_close_getattr(const unsigned int xid, struct cifs_tcon *tcon,
1337+
struct cifsFileInfo *cfile)
1338+
{
1339+
struct smb2_file_network_open_info file_inf;
1340+
struct inode *inode;
1341+
int rc;
1342+
1343+
rc = __SMB2_close(xid, tcon, cfile->fid.persistent_fid,
1344+
cfile->fid.volatile_fid, &file_inf);
1345+
if (rc)
1346+
return;
1347+
1348+
inode = d_inode(cfile->dentry);
1349+
1350+
spin_lock(&inode->i_lock);
1351+
CIFS_I(inode)->time = jiffies;
1352+
1353+
/* Creation time should not need to be updated on close */
1354+
if (file_inf.LastWriteTime)
1355+
inode->i_mtime = cifs_NTtimeToUnix(file_inf.LastWriteTime);
1356+
if (file_inf.ChangeTime)
1357+
inode->i_ctime = cifs_NTtimeToUnix(file_inf.ChangeTime);
1358+
if (file_inf.LastAccessTime)
1359+
inode->i_atime = cifs_NTtimeToUnix(file_inf.LastAccessTime);
1360+
1361+
/*
1362+
* i_blocks is not related to (i_size / i_blksize),
1363+
* but instead 512 byte (2**9) size is required for
1364+
* calculating num blocks.
1365+
*/
1366+
if (le64_to_cpu(file_inf.AllocationSize) > 4096)
1367+
inode->i_blocks =
1368+
(512 - 1 + le64_to_cpu(file_inf.AllocationSize)) >> 9;
1369+
1370+
/* End of file and Attributes should not have to be updated on close */
1371+
spin_unlock(&inode->i_lock);
1372+
}
1373+
13351374
static int
13361375
SMB2_request_res_key(const unsigned int xid, struct cifs_tcon *tcon,
13371376
u64 persistent_fid, u64 volatile_fid,
@@ -1512,7 +1551,7 @@ smb2_ioctl_query_info(const unsigned int xid,
15121551
rqst[2].rq_iov = close_iov;
15131552
rqst[2].rq_nvec = 1;
15141553

1515-
rc = SMB2_close_init(tcon, &rqst[2], COMPOUND_FID, COMPOUND_FID);
1554+
rc = SMB2_close_init(tcon, &rqst[2], COMPOUND_FID, COMPOUND_FID, false);
15161555
if (rc)
15171556
goto iqinf_exit;
15181557
smb2_set_related(&rqst[2]);
@@ -2241,7 +2280,7 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon,
22412280
rqst[2].rq_iov = close_iov;
22422281
rqst[2].rq_nvec = 1;
22432282

2244-
rc = SMB2_close_init(tcon, &rqst[2], COMPOUND_FID, COMPOUND_FID);
2283+
rc = SMB2_close_init(tcon, &rqst[2], COMPOUND_FID, COMPOUND_FID, false);
22452284
if (rc)
22462285
goto qic_exit;
22472286
smb2_set_related(&rqst[2]);
@@ -2654,7 +2693,7 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
26542693
rqst[2].rq_iov = close_iov;
26552694
rqst[2].rq_nvec = 1;
26562695

2657-
rc = SMB2_close_init(tcon, &rqst[2], COMPOUND_FID, COMPOUND_FID);
2696+
rc = SMB2_close_init(tcon, &rqst[2], COMPOUND_FID, COMPOUND_FID, false);
26582697
if (rc)
26592698
goto querty_exit;
26602699

@@ -4707,6 +4746,7 @@ struct smb_version_operations smb30_operations = {
47074746
.open = smb2_open_file,
47084747
.set_fid = smb2_set_fid,
47094748
.close = smb2_close_file,
4749+
.close_getattr = smb2_close_getattr,
47104750
.flush = smb2_flush_file,
47114751
.async_readv = smb2_async_readv,
47124752
.async_writev = smb2_async_writev,
@@ -4816,6 +4856,7 @@ struct smb_version_operations smb311_operations = {
48164856
.open = smb2_open_file,
48174857
.set_fid = smb2_set_fid,
48184858
.close = smb2_close_file,
4859+
.close_getattr = smb2_close_getattr,
48194860
.flush = smb2_flush_file,
48204861
.async_readv = smb2_async_readv,
48214862
.async_writev = smb2_async_writev,

fs/cifs/smb2pdu.c

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2932,7 +2932,7 @@ SMB2_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
29322932

29332933
int
29342934
SMB2_close_init(struct cifs_tcon *tcon, struct smb_rqst *rqst,
2935-
u64 persistent_fid, u64 volatile_fid)
2935+
u64 persistent_fid, u64 volatile_fid, bool query_attrs)
29362936
{
29372937
struct smb2_close_req *req;
29382938
struct kvec *iov = rqst->rq_iov;
@@ -2945,6 +2945,10 @@ SMB2_close_init(struct cifs_tcon *tcon, struct smb_rqst *rqst,
29452945

29462946
req->PersistentFileId = persistent_fid;
29472947
req->VolatileFileId = volatile_fid;
2948+
if (query_attrs)
2949+
req->Flags = SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB;
2950+
else
2951+
req->Flags = 0;
29482952
iov[0].iov_base = (char *)req;
29492953
iov[0].iov_len = total_len;
29502954

@@ -2959,8 +2963,9 @@ SMB2_close_free(struct smb_rqst *rqst)
29592963
}
29602964

29612965
int
2962-
SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
2963-
u64 persistent_fid, u64 volatile_fid)
2966+
__SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
2967+
u64 persistent_fid, u64 volatile_fid,
2968+
struct smb2_file_network_open_info *pbuf)
29642969
{
29652970
struct smb_rqst rqst;
29662971
struct smb2_close_rsp *rsp = NULL;
@@ -2970,6 +2975,7 @@ SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
29702975
int resp_buftype = CIFS_NO_BUFFER;
29712976
int rc = 0;
29722977
int flags = 0;
2978+
bool query_attrs = false;
29732979

29742980
cifs_dbg(FYI, "Close\n");
29752981

@@ -2984,8 +2990,13 @@ SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
29842990
rqst.rq_iov = iov;
29852991
rqst.rq_nvec = 1;
29862992

2993+
/* check if need to ask server to return timestamps in close response */
2994+
if (pbuf)
2995+
query_attrs = true;
2996+
29872997
trace_smb3_close_enter(xid, persistent_fid, tcon->tid, ses->Suid);
2988-
rc = SMB2_close_init(tcon, &rqst, persistent_fid, volatile_fid);
2998+
rc = SMB2_close_init(tcon, &rqst, persistent_fid, volatile_fid,
2999+
query_attrs);
29893000
if (rc)
29903001
goto close_exit;
29913002

@@ -2997,14 +3008,18 @@ SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
29973008
trace_smb3_close_err(xid, persistent_fid, tcon->tid, ses->Suid,
29983009
rc);
29993010
goto close_exit;
3000-
} else
3011+
} else {
30013012
trace_smb3_close_done(xid, persistent_fid, tcon->tid,
30023013
ses->Suid);
3014+
/*
3015+
* Note that have to subtract 4 since struct network_open_info
3016+
* has a final 4 byte pad that close response does not have
3017+
*/
3018+
if (pbuf)
3019+
memcpy(pbuf, (char *)&rsp->CreationTime, sizeof(*pbuf) - 4);
3020+
}
30033021

30043022
atomic_dec(&tcon->num_remote_opens);
3005-
3006-
/* BB FIXME - decode close response, update inode for caching */
3007-
30083023
close_exit:
30093024
SMB2_close_free(&rqst);
30103025
free_rsp_buf(resp_buftype, rsp);
@@ -3022,6 +3037,13 @@ SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
30223037
return rc;
30233038
}
30243039

3040+
int
3041+
SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
3042+
u64 persistent_fid, u64 volatile_fid)
3043+
{
3044+
return __SMB2_close(xid, tcon, persistent_fid, volatile_fid, NULL);
3045+
}
3046+
30253047
int
30263048
smb2_validate_iov(unsigned int offset, unsigned int buffer_length,
30273049
struct kvec *iov, unsigned int min_buf_size)

fs/cifs/smb2pdu.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1570,6 +1570,17 @@ struct smb2_file_eof_info { /* encoding of request for level 10 */
15701570
__le64 EndOfFile; /* new end of file value */
15711571
} __packed; /* level 20 Set */
15721572

1573+
struct smb2_file_network_open_info {
1574+
__le64 CreationTime;
1575+
__le64 LastAccessTime;
1576+
__le64 LastWriteTime;
1577+
__le64 ChangeTime;
1578+
__le64 AllocationSize;
1579+
__le64 EndOfFile;
1580+
__le32 Attributes;
1581+
__le32 Reserved;
1582+
} __packed; /* level 34 Query also similar returned in close rsp and open rsp */
1583+
15731584
extern char smb2_padding[7];
15741585

15751586
#endif /* _SMB2PDU_H */

fs/cifs/smb2proto.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,10 +155,13 @@ extern int SMB2_change_notify(const unsigned int xid, struct cifs_tcon *tcon,
155155
u64 persistent_fid, u64 volatile_fid, bool watch_tree,
156156
u32 completion_filter);
157157

158+
extern int __SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
159+
u64 persistent_fid, u64 volatile_fid,
160+
struct smb2_file_network_open_info *pbuf);
158161
extern int SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
159162
u64 persistent_file_id, u64 volatile_file_id);
160163
extern int SMB2_close_init(struct cifs_tcon *tcon, struct smb_rqst *rqst,
161-
u64 persistent_file_id, u64 volatile_file_id);
164+
u64 persistent_fid, u64 volatile_fid, bool query_attrs);
162165
extern void SMB2_close_free(struct smb_rqst *rqst);
163166
extern int SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon,
164167
u64 persistent_file_id, u64 volatile_file_id);

0 commit comments

Comments
 (0)