diff mbox series

[5/5] smb3: fix temporary data corruption in insert range

Message ID 166126007561.548536.12315282792952269215.stgit@warthog.procyon.org.uk
State New
Headers show
Series smb3: Fix missing locks and invalidation in fallocate | expand

Commit Message

David Howells Aug. 23, 2022, 1:07 p.m. UTC
insert range doesn't discard the affected cached region
so can risk temporarily corrupting file data.

Also includes some minor cleanup (avoiding rereading
inode size repeatedly unnecessarily) to make it clearer.

Cc: stable@vger.kernel.org
Fixes: 7fe6fe95b9360 ("cifs: FALLOC_FL_INSERT_RANGE support")
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
cc: Ronnie Sahlberg <lsahlber@redhat.com>
---

 fs/cifs/smb2ops.c |   24 ++++++++++++++++--------
 1 file changed, 16 insertions(+), 8 deletions(-)

Comments

Steve French Aug. 24, 2022, 5:58 a.m. UTC | #1
lightly updated to move inode lock down one line and fix signed off

On Tue, Aug 23, 2022 at 8:24 AM David Howells via samba-technical
<samba-technical@lists.samba.org> wrote:
>
> insert range doesn't discard the affected cached region
> so can risk temporarily corrupting file data.
>
> Also includes some minor cleanup (avoiding rereading
> inode size repeatedly unnecessarily) to make it clearer.
>
> Cc: stable@vger.kernel.org
> Fixes: 7fe6fe95b9360 ("cifs: FALLOC_FL_INSERT_RANGE support")
> Signed-off-by: David Howells <dhowells@redhat.com>
> Signed-off-by: Steve French <stfrench@microsoft.com>
> cc: Ronnie Sahlberg <lsahlber@redhat.com>
> ---
>
>  fs/cifs/smb2ops.c |   24 ++++++++++++++++--------
>  1 file changed, 16 insertions(+), 8 deletions(-)
>
> diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
> index 5b5ddc1b4638..00c8d6a715c7 100644
> --- a/fs/cifs/smb2ops.c
> +++ b/fs/cifs/smb2ops.c
> @@ -3722,35 +3722,43 @@ static long smb3_insert_range(struct file *file, struct cifs_tcon *tcon,
>         struct cifsFileInfo *cfile = file->private_data;
>         struct inode *inode = file_inode(file);
>         __le64 eof;
> -       __u64  count;
> +       __u64  count, old_eof;
> +
> +       inode_lock(inode);
>
>         xid = get_xid();
>
> -       if (off >= i_size_read(inode)) {
> +       old_eof = i_size_read(inode);
> +       if (off >= old_eof) {
>                 rc = -EINVAL;
>                 goto out;
>         }
>
> -       count = i_size_read(inode) - off;
> -       eof = cpu_to_le64(i_size_read(inode) + len);
> +       count = old_eof - off;
> +       eof = cpu_to_le64(old_eof + len);
>
> +       filemap_invalidate_lock(inode->i_mapping);
>         filemap_write_and_wait(inode->i_mapping);
> +       truncate_pagecache_range(inode, off, old_eof);
>
>         rc = SMB2_set_eof(xid, tcon, cfile->fid.persistent_fid,
>                           cfile->fid.volatile_fid, cfile->pid, &eof);
>         if (rc < 0)
> -               goto out;
> +               goto out_2;
>
>         rc = smb2_copychunk_range(xid, cfile, cfile, off, count, off + len);
>         if (rc < 0)
> -               goto out;
> +               goto out_2;
>
> -       rc = smb3_zero_range(file, tcon, off, len, 1);
> +       rc = smb3_zero_data(file, tcon, off, len, xid);
>         if (rc < 0)
> -               goto out;
> +               goto out_2;
>
>         rc = 0;
> +out_2:
> +       filemap_invalidate_unlock(inode->i_mapping);
>   out:
> +       inode_unlock(inode);
>         free_xid(xid);
>         return rc;
>  }
>
>
>
diff mbox series

Patch

diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 5b5ddc1b4638..00c8d6a715c7 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -3722,35 +3722,43 @@  static long smb3_insert_range(struct file *file, struct cifs_tcon *tcon,
 	struct cifsFileInfo *cfile = file->private_data;
 	struct inode *inode = file_inode(file);
 	__le64 eof;
-	__u64  count;
+	__u64  count, old_eof;
+
+	inode_lock(inode);
 
 	xid = get_xid();
 
-	if (off >= i_size_read(inode)) {
+	old_eof = i_size_read(inode);
+	if (off >= old_eof) {
 		rc = -EINVAL;
 		goto out;
 	}
 
-	count = i_size_read(inode) - off;
-	eof = cpu_to_le64(i_size_read(inode) + len);
+	count = old_eof - off;
+	eof = cpu_to_le64(old_eof + len);
 
+	filemap_invalidate_lock(inode->i_mapping);
 	filemap_write_and_wait(inode->i_mapping);
+	truncate_pagecache_range(inode, off, old_eof);
 
 	rc = SMB2_set_eof(xid, tcon, cfile->fid.persistent_fid,
 			  cfile->fid.volatile_fid, cfile->pid, &eof);
 	if (rc < 0)
-		goto out;
+		goto out_2;
 
 	rc = smb2_copychunk_range(xid, cfile, cfile, off, count, off + len);
 	if (rc < 0)
-		goto out;
+		goto out_2;
 
-	rc = smb3_zero_range(file, tcon, off, len, 1);
+	rc = smb3_zero_data(file, tcon, off, len, xid);
 	if (rc < 0)
-		goto out;
+		goto out_2;
 
 	rc = 0;
+out_2:
+	filemap_invalidate_unlock(inode->i_mapping);
  out:
+	inode_unlock(inode);
 	free_xid(xid);
 	return rc;
 }