From fe39cd9d48f2346605f3746e0cc19e89d5f373eb Mon Sep 17 00:00:00 2001 From: Frank Sorenson Date: Wed, 26 Aug 2026 20:57:38 -0500 Subject: [PATCH] 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 Acked-by: David Howells Signed-off-by: Paulo Alcantara --- fs/smb/client/file.c | 24 ++++++++++++++++++++---- 1 file 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); } }