]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
[CIFS] Send SMB flush in cifs_fsync
authorSteve French <sfrench@us.ibm.com>
Sat, 21 Feb 2009 21:17:43 +0000 (21:17 +0000)
committerSteve French <sfrench@us.ibm.com>
Thu, 12 Mar 2009 01:36:20 +0000 (01:36 +0000)
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>
fs/cifs/CHANGES
fs/cifs/cifs_debug.c
fs/cifs/cifsglob.h
fs/cifs/cifspdu.h
fs/cifs/cifsproto.h
fs/cifs/cifssmb.c
fs/cifs/file.c

index 851388fafc7302dbae9d5b5f7f33da5101eed4cd..d43e0fe333980646ebf0338d1646f4578ec567f5 100644 (file)
@@ -6,7 +6,9 @@ the server to treat subsequent connections, especially those that
 are authenticated as guest, as reconnections, invalidating the earlier
 user's smb session.  This fix allows cifs to mount multiple times to the
 same server with different userids without risking invalidating earlier
-established security contexts.
+established security contexts.  fsync now sends SMB Flush operation
+to better ensure that we wait for server to write all of the data to
+server disk (not just write it over the network).
 
 Version 1.56
 ------------
index 490e34bbf27a66641c0bad3327e5bb22156a88af..877e4d9a1159d11203170ec463202187dd3a6466 100644 (file)
@@ -340,6 +340,8 @@ static int cifs_stats_proc_show(struct seq_file *m, void *v)
                                seq_printf(m, "\nWrites: %d Bytes: %lld",
                                        atomic_read(&tcon->num_writes),
                                        (long long)(tcon->bytes_written));
+                               seq_printf(m, "\nFlushes: %d",
+                                       atomic_read(&tcon->num_flushes));
                                seq_printf(m, "\nLocks: %d HardLinks: %d "
                                              "Symlinks: %d",
                                        atomic_read(&tcon->num_locks),
index e004f6db5fc87904e21d6ebc4eb0cb56ccc15d29..44ff94d37e18f6c21e3c9fd0e8e6217e25085592 100644 (file)
@@ -254,6 +254,7 @@ struct cifsTconInfo {
        atomic_t num_smbs_sent;
        atomic_t num_writes;
        atomic_t num_reads;
+       atomic_t num_flushes;
        atomic_t num_oplock_brks;
        atomic_t num_opens;
        atomic_t num_closes;
index b4e2e9f0ee3d754a4b3c879827a7bceb69ee8d9b..eda6e511fd3eeeb060c8c9d00b0b33b7730694d9 100644 (file)
@@ -43,6 +43,7 @@
 #define SMB_COM_CREATE_DIRECTORY      0x00 /* trivial response */
 #define SMB_COM_DELETE_DIRECTORY      0x01 /* trivial response */
 #define SMB_COM_CLOSE                 0x04 /* triv req/rsp, timestamp ignored */
+#define SMB_COM_FLUSH                 0x05 /* triv req/rsp */
 #define SMB_COM_DELETE                0x06 /* trivial response */
 #define SMB_COM_RENAME                0x07 /* trivial response */
 #define SMB_COM_QUERY_INFORMATION     0x08 /* aka getattr */
@@ -790,6 +791,12 @@ typedef struct smb_com_close_rsp {
        __u16 ByteCount;        /* bct = 0 */
 } __attribute__((packed)) CLOSE_RSP;
 
+typedef struct smb_com_flush_req {
+       struct smb_hdr hdr;     /* wct = 1 */
+       __u16 FileID;
+       __u16 ByteCount;        /* 0 */
+} __attribute__((packed)) FLUSH_REQ;
+
 typedef struct smb_com_findclose_req {
        struct smb_hdr hdr; /* wct = 1 */
        __u16 FileID;
index 083dfc57c7a3e53adf54f32e9af4c56a8c2eeb9f..596fc8689371bc8159b07818f1ecb71444f36486 100644 (file)
@@ -281,6 +281,9 @@ extern int CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon,
 extern int CIFSSMBClose(const int xid, struct cifsTconInfo *tcon,
                        const int smb_file_id);
 
+extern int CIFSSMBFlush(const int xid, struct cifsTconInfo *tcon,
+                       const int smb_file_id);
+
 extern int CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
                        const int netfid, unsigned int count,
                        const __u64 lseek, unsigned int *nbytes, char **buf,
index 939e2f76b9596203ab68276a59aad6fd8c36981e..4c344fe7a152da6a42333045c7403c134976ab8f 100644 (file)
@@ -1933,6 +1933,27 @@ CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
        return rc;
 }
 
+int
+CIFSSMBFlush(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
+{
+       int rc = 0;
+       FLUSH_REQ *pSMB = NULL;
+       cFYI(1, ("In CIFSSMBFlush"));
+
+       rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
+       if (rc)
+               return rc;
+
+       pSMB->FileID = (__u16) smb_file_id;
+       pSMB->ByteCount = 0;
+       rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
+       cifs_stats_inc(&tcon->num_flushes);
+       if (rc)
+               cERROR(1, ("Send error in Flush = %d", rc));
+
+       return rc;
+}
+
 int
 CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
              const char *fromName, const char *toName,
index 12bb656fbe75881354bdfe1550b453b90f3fa4a3..83b4741b6ad0f1c3719737dcbd470ed2636aa644 100644 (file)
@@ -1523,6 +1523,9 @@ int cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
 {
        int xid;
        int rc = 0;
+       struct cifsTconInfo *tcon;
+       struct cifsFileInfo *smbfile =
+               (struct cifsFileInfo *)file->private_data;
        struct inode *inode = file->f_path.dentry->d_inode;
 
        xid = GetXid();
@@ -1534,7 +1537,11 @@ int cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
        if (rc == 0) {
                rc = CIFS_I(inode)->write_behind_rc;
                CIFS_I(inode)->write_behind_rc = 0;
+               tcon = CIFS_SB(inode->i_sb)->tcon;
+               if (!rc && tcon && smbfile)
+                       rc = CIFSSMBFlush(xid, tcon, smbfile->netfid);
        }
+
        FreeXid(xid);
        return rc;
 }