Skip to content

Commit fa30a81

Browse files
committed
smb3: fix temporary data corruption in collapse range
collapse range doesn't discard the affected cached region so can risk temporarily corrupting the file data. This fixes xfstest generic/031 I also decided to merge a minor cleanup to this into the same patch (avoiding rereading inode size repeatedly unnecessarily) to make it clearer. Cc: stable@vger.kernel.org Fixes: 5476b5d ("cifs: add support for FALLOC_FL_COLLAPSE_RANGE") Reported-by: David Howells <dhowells@redhat.com> Tested-by: David Howells <dhowells@redhat.com> Reviewed-by: David Howells <dhowells@redhat.com> cc: Ronnie Sahlberg <lsahlber@redhat.com> Signed-off-by: Steve French <stfrench@microsoft.com>
1 parent c3a72bb commit fa30a81

1 file changed

Lines changed: 16 additions & 10 deletions

File tree

fs/cifs/smb2ops.c

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3669,41 +3669,47 @@ static long smb3_collapse_range(struct file *file, struct cifs_tcon *tcon,
36693669
{
36703670
int rc;
36713671
unsigned int xid;
3672-
struct inode *inode;
3672+
struct inode *inode = file_inode(file);
36733673
struct cifsFileInfo *cfile = file->private_data;
3674-
struct cifsInodeInfo *cifsi;
3674+
struct cifsInodeInfo *cifsi = CIFS_I(inode);
36753675
__le64 eof;
3676+
loff_t old_eof;
36763677

36773678
xid = get_xid();
36783679

3679-
inode = d_inode(cfile->dentry);
3680-
cifsi = CIFS_I(inode);
3680+
inode_lock(inode);
36813681

3682-
if (off >= i_size_read(inode) ||
3683-
off + len >= i_size_read(inode)) {
3682+
old_eof = i_size_read(inode);
3683+
if ((off >= old_eof) ||
3684+
off + len >= old_eof) {
36843685
rc = -EINVAL;
36853686
goto out;
36863687
}
36873688

3689+
filemap_invalidate_lock(inode->i_mapping);
36883690
filemap_write_and_wait(inode->i_mapping);
3691+
truncate_pagecache_range(inode, off, old_eof);
36893692

36903693
rc = smb2_copychunk_range(xid, cfile, cfile, off + len,
3691-
i_size_read(inode) - off - len, off);
3694+
old_eof - off - len, off);
36923695
if (rc < 0)
3693-
goto out;
3696+
goto out_2;
36943697

3695-
eof = cpu_to_le64(i_size_read(inode) - len);
3698+
eof = cpu_to_le64(old_eof - len);
36963699
rc = SMB2_set_eof(xid, tcon, cfile->fid.persistent_fid,
36973700
cfile->fid.volatile_fid, cfile->pid, &eof);
36983701
if (rc < 0)
3699-
goto out;
3702+
goto out_2;
37003703

37013704
rc = 0;
37023705

37033706
cifsi->server_eof = i_size_read(inode) - len;
37043707
truncate_setsize(inode, cifsi->server_eof);
37053708
fscache_resize_cookie(cifs_inode_cookie(inode), cifsi->server_eof);
3709+
out_2:
3710+
filemap_invalidate_unlock(inode->i_mapping);
37063711
out:
3712+
inode_unlock(inode);
37073713
free_xid(xid);
37083714
return rc;
37093715
}

0 commit comments

Comments
 (0)