summaryrefslogtreecommitdiffstats
path: root/fs/cifs
diff options
context:
space:
mode:
authorRonnie Sahlberg <lsahlber@redhat.com>2019-07-19 08:12:11 +1000
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2019-07-26 09:10:51 +0200
commit8f85f239ad9e07d4fccd832e381801a8403f970d (patch)
tree1630ba60952d4cc58351bd4f866f25c6f110302d /fs/cifs
parentb14228f7e98e2638ced1207a324dcfccba624a78 (diff)
downloadlinux-stable-8f85f239ad9e07d4fccd832e381801a8403f970d.tar.gz
linux-stable-8f85f239ad9e07d4fccd832e381801a8403f970d.tar.bz2
linux-stable-8f85f239ad9e07d4fccd832e381801a8403f970d.zip
cifs: flush before set-info if we have writeable handles
commit aa081859b10c5d8b19f5c525c78883a59d73c2b8 upstream. Servers can defer destaging any data and updating the mtime until close(). This means that if we do a setinfo to modify the mtime while other handles are open for write the server may overwrite our setinfo timestamps when if flushes the file on close() of the writeable handle. To solve this we add an explicit flush when the mtime is about to be updated. This fixes "cp -p" to preserve mtime when copying a file onto an SMB2 share. CC: Stable <stable@vger.kernel.org> Signed-off-by: Ronnie Sahlberg <lsahlber@redhat.com> Reviewed-by: Pavel Shilovsky <pshilov@microsoft.com> Signed-off-by: Steve French <stfrench@microsoft.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'fs/cifs')
-rw-r--r--fs/cifs/inode.c16
1 files changed, 16 insertions, 0 deletions
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index d7cc62252634..efaf7a3631ba 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -2408,6 +2408,8 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
struct inode *inode = d_inode(direntry);
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
struct cifsInodeInfo *cifsInode = CIFS_I(inode);
+ struct cifsFileInfo *wfile;
+ struct cifs_tcon *tcon;
char *full_path = NULL;
int rc = -EACCES;
__u32 dosattr = 0;
@@ -2454,6 +2456,20 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
mapping_set_error(inode->i_mapping, rc);
rc = 0;
+ if (attrs->ia_valid & ATTR_MTIME) {
+ rc = cifs_get_writable_file(cifsInode, false, &wfile);
+ if (!rc) {
+ tcon = tlink_tcon(wfile->tlink);
+ rc = tcon->ses->server->ops->flush(xid, tcon, &wfile->fid);
+ cifsFileInfo_put(wfile);
+ if (rc)
+ return rc;
+ } else if (rc != -EBADF)
+ return rc;
+ else
+ rc = 0;
+ }
+
if (attrs->ia_valid & ATTR_SIZE) {
rc = cifs_set_file_size(inode, attrs, xid, full_path);
if (rc != 0)