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@xxxxxxxxxxxxxxx> 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@xxxxxxxxxxxxxxx > Fixes: 7fe6fe95b9360 ("cifs: FALLOC_FL_INSERT_RANGE support") > Signed-off-by: David Howells <dhowells@xxxxxxxxxx> > Signed-off-by: Steve French <stfrench@xxxxxxxxxxxxx> > cc: Ronnie Sahlberg <lsahlber@xxxxxxxxxx> > --- > > 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; > } > > > -- Thanks, Steve
From b044b4dd604818efa3d7036d14b9750e3deb9bf3 Mon Sep 17 00:00:00 2001 From: David Howells via samba-technical <samba-technical@xxxxxxxxxxxxxxx> Date: Tue, 23 Aug 2022 14:07:55 +0100 Subject: [PATCH] smb3: fix temporary data corruption in insert range 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@xxxxxxxxxxxxxxx Fixes: 7fe6fe95b9360 ("cifs: FALLOC_FL_INSERT_RANGE support") Signed-off-by: David Howells <dhowells@xxxxxxxxxx> cc: Ronnie Sahlberg <lsahlber@xxxxxxxxxx> Signed-off-by: Steve French <stfrench@xxxxxxxxxxxxx> --- 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..7c941ce1e7a9 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; xid = get_xid(); - if (off >= i_size_read(inode)) { + inode_lock(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; } -- 2.34.1