diff options
| author | Frank Sorenson <sorenson@redhat.com> | 2026-08-26 20:57:38 -0500 |
|---|---|---|
| committer | Paulo Alcantara <pc@manguebit.org> | 2026-08-30 14:05:38 -0300 |
| commit | fe39cd9d48f2346605f3746e0cc19e89d5f373eb (patch) | |
| tree | 7d28c79d4aca0bc49afec35daede293e5c415118 /fs | |
| parent | 1dac61e2c29d1a71784604b48cf3b1234a65ec29 (diff) | |
| download | linux-next-fe39cd9d48f2346605f3746e0cc19e89d5f373eb.tar.gz linux-next-fe39cd9d48f2346605f3746e0cc19e89d5f373eb.zip | |
cifs: don't update i_size in cifs_do_truncate without a cached handle
If find_writable_file() returns null, cifs_file_flush will return
0 without issuing set_file_size, and the outer 'if (!rc)' block
will set i_size to 0 before telling the server to truncate. If
the cifs_open() then fails, the inode will have size 0, while
the server file is unchanged.
Move the netfs_resize_file() and cifs_setsize() into the 'if
(cfile)', so they only run after a successful set_file_size.
In the no-handle else branch, evict stale pages with
truncate_inode_pages before the O_TRUNC open to dispose of old
cache pages, and let the open response set the i_size.
Fixes: 110fee6b9bb5 ("smb: client: fix missing timestamp updates with O_TRUNC")
Cc: stable@vger.kernel.org
Signed-off-by: Frank Sorenson <sorenson@redhat.com>
Acked-by: David Howells <dhowells@redhat.com>
Signed-off-by: Paulo Alcantara <pc@manguebit.org>
Diffstat (limited to 'fs')
| -rw-r--r-- | fs/smb/client/file.c | 24 |
1 files changed, 20 insertions, 4 deletions
diff --git a/fs/smb/client/file.c b/fs/smb/client/file.c index 389083f9ce00..100acc76e9be 100644 --- a/fs/smb/client/file.c +++ b/fs/smb/client/file.c @@ -1012,10 +1012,26 @@ static int cifs_do_truncate(const unsigned int xid, struct dentry *dentry) server = tcon->ses->server; rc = server->ops->set_file_size(xid, tcon, cfile, 0, false); - } - if (!rc) { - netfs_resize_file(&cinode->netfs, 0, true); - cifs_setsize(inode, 0); + if (!rc) { + inode_lock(inode); + filemap_invalidate_lock(inode->i_mapping); + netfs_resize_file(&cinode->netfs, 0, true); + cifs_setsize(inode, 0); + filemap_invalidate_unlock(inode->i_mapping); + inode_unlock(inode); + cifs_invalidate_cache(inode, 0); + } + } else { + /* + * No cached handle; evict stale pages so they can't + * be served after the file is later extended; let + * the server's O_TRUNC open response set the i_size + */ + inode_lock(inode); + filemap_invalidate_lock(inode->i_mapping); + truncate_inode_pages(inode->i_mapping, 0); + filemap_invalidate_unlock(inode->i_mapping); + inode_unlock(inode); cifs_invalidate_cache(inode, 0); } } |
