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: 110fee6b9b ("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>
This commit is contained in:
Frank Sorenson 2026-08-26 20:57:38 -05:00 committed by Paulo Alcantara
parent 1dac61e2c2
commit fe39cd9d48

View File

@ -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);
}
}