Message ID | 166126007561.548536.12315282792952269215.stgit@warthog.procyon.org.uk (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | smb3: Fix missing locks and invalidation in fallocate | expand |
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 --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; }