Commit b298f223559e0205244f553ceef8c7df3674da74
1 parent
ebdcc81c71
Exists in
master
and in
7 other branches
[CIFS] Send SMB flush in cifs_fsync
In contrast to the now-obsolete smbfs, cifs does not send SMB_COM_FLUSH in response to an explicit fsync(2) to guarantee that all volatile data is written to stable storage on the server side, provided the server honors the request (which, to my knowledge, is true for Windows and Samba with 'strict sync' enabled). This patch modifies the cifs_fsync implementation to restore the fsync-behavior of smbfs by triggering SMB_COM_FLUSH after sending outstanding data on the client side to the server. Signed-off-by: Horst Reiterer <horst.reiterer@gmail.com> Acked-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: Steve French <sfrench@us.ibm.com>
Showing 7 changed files with 44 additions and 1 deletions Side-by-side Diff
fs/cifs/CHANGES
... | ... | @@ -6,7 +6,9 @@ |
6 | 6 | are authenticated as guest, as reconnections, invalidating the earlier |
7 | 7 | user's smb session. This fix allows cifs to mount multiple times to the |
8 | 8 | same server with different userids without risking invalidating earlier |
9 | -established security contexts. | |
9 | +established security contexts. fsync now sends SMB Flush operation | |
10 | +to better ensure that we wait for server to write all of the data to | |
11 | +server disk (not just write it over the network). | |
10 | 12 | |
11 | 13 | Version 1.56 |
12 | 14 | ------------ |
fs/cifs/cifs_debug.c
... | ... | @@ -340,6 +340,8 @@ |
340 | 340 | seq_printf(m, "\nWrites: %d Bytes: %lld", |
341 | 341 | atomic_read(&tcon->num_writes), |
342 | 342 | (long long)(tcon->bytes_written)); |
343 | + seq_printf(m, "\nFlushes: %d", | |
344 | + atomic_read(&tcon->num_flushes)); | |
343 | 345 | seq_printf(m, "\nLocks: %d HardLinks: %d " |
344 | 346 | "Symlinks: %d", |
345 | 347 | atomic_read(&tcon->num_locks), |
fs/cifs/cifsglob.h
fs/cifs/cifspdu.h
... | ... | @@ -43,6 +43,7 @@ |
43 | 43 | #define SMB_COM_CREATE_DIRECTORY 0x00 /* trivial response */ |
44 | 44 | #define SMB_COM_DELETE_DIRECTORY 0x01 /* trivial response */ |
45 | 45 | #define SMB_COM_CLOSE 0x04 /* triv req/rsp, timestamp ignored */ |
46 | +#define SMB_COM_FLUSH 0x05 /* triv req/rsp */ | |
46 | 47 | #define SMB_COM_DELETE 0x06 /* trivial response */ |
47 | 48 | #define SMB_COM_RENAME 0x07 /* trivial response */ |
48 | 49 | #define SMB_COM_QUERY_INFORMATION 0x08 /* aka getattr */ |
... | ... | @@ -789,6 +790,12 @@ |
789 | 790 | struct smb_hdr hdr; /* wct = 0 */ |
790 | 791 | __u16 ByteCount; /* bct = 0 */ |
791 | 792 | } __attribute__((packed)) CLOSE_RSP; |
793 | + | |
794 | +typedef struct smb_com_flush_req { | |
795 | + struct smb_hdr hdr; /* wct = 1 */ | |
796 | + __u16 FileID; | |
797 | + __u16 ByteCount; /* 0 */ | |
798 | +} __attribute__((packed)) FLUSH_REQ; | |
792 | 799 | |
793 | 800 | typedef struct smb_com_findclose_req { |
794 | 801 | struct smb_hdr hdr; /* wct = 1 */ |
fs/cifs/cifsproto.h
... | ... | @@ -281,6 +281,9 @@ |
281 | 281 | extern int CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, |
282 | 282 | const int smb_file_id); |
283 | 283 | |
284 | +extern int CIFSSMBFlush(const int xid, struct cifsTconInfo *tcon, | |
285 | + const int smb_file_id); | |
286 | + | |
284 | 287 | extern int CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, |
285 | 288 | const int netfid, unsigned int count, |
286 | 289 | const __u64 lseek, unsigned int *nbytes, char **buf, |
fs/cifs/cifssmb.c
... | ... | @@ -1934,6 +1934,27 @@ |
1934 | 1934 | } |
1935 | 1935 | |
1936 | 1936 | int |
1937 | +CIFSSMBFlush(const int xid, struct cifsTconInfo *tcon, int smb_file_id) | |
1938 | +{ | |
1939 | + int rc = 0; | |
1940 | + FLUSH_REQ *pSMB = NULL; | |
1941 | + cFYI(1, ("In CIFSSMBFlush")); | |
1942 | + | |
1943 | + rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB); | |
1944 | + if (rc) | |
1945 | + return rc; | |
1946 | + | |
1947 | + pSMB->FileID = (__u16) smb_file_id; | |
1948 | + pSMB->ByteCount = 0; | |
1949 | + rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0); | |
1950 | + cifs_stats_inc(&tcon->num_flushes); | |
1951 | + if (rc) | |
1952 | + cERROR(1, ("Send error in Flush = %d", rc)); | |
1953 | + | |
1954 | + return rc; | |
1955 | +} | |
1956 | + | |
1957 | +int | |
1937 | 1958 | CIFSSMBRename(const int xid, struct cifsTconInfo *tcon, |
1938 | 1959 | const char *fromName, const char *toName, |
1939 | 1960 | const struct nls_table *nls_codepage, int remap) |
fs/cifs/file.c
... | ... | @@ -1523,6 +1523,9 @@ |
1523 | 1523 | { |
1524 | 1524 | int xid; |
1525 | 1525 | int rc = 0; |
1526 | + struct cifsTconInfo *tcon; | |
1527 | + struct cifsFileInfo *smbfile = | |
1528 | + (struct cifsFileInfo *)file->private_data; | |
1526 | 1529 | struct inode *inode = file->f_path.dentry->d_inode; |
1527 | 1530 | |
1528 | 1531 | xid = GetXid(); |
1529 | 1532 | |
... | ... | @@ -1534,7 +1537,11 @@ |
1534 | 1537 | if (rc == 0) { |
1535 | 1538 | rc = CIFS_I(inode)->write_behind_rc; |
1536 | 1539 | CIFS_I(inode)->write_behind_rc = 0; |
1540 | + tcon = CIFS_SB(inode->i_sb)->tcon; | |
1541 | + if (!rc && tcon && smbfile) | |
1542 | + rc = CIFSSMBFlush(xid, tcon, smbfile->netfid); | |
1537 | 1543 | } |
1544 | + | |
1538 | 1545 | FreeXid(xid); |
1539 | 1546 | return rc; |
1540 | 1547 | } |