[PATCH v4 1/2] cifs: don't update i_size in cifs_do_truncate() without a cached handle
Frank Sorenson <[email protected]>
| Newsgroups | org.kernel.vger.linux-cifs,org.kernel.vger.stable |
|---|---|
| Message-ID | <[email protected]> |
If find_writable_file() returns NULL, cifs_file_flush() returns 0
without issuing set_file_size, and the outer if (!rc) block sets i_size
to 0 before the server is told to truncate. If the subsequent
cifs_open() fails, the inode is stranded at size 0 while the server
file is unchanged.
Move netfs_resize_file() and cifs_setsize() inside the if (cfile) arm
so they only run after a successful set_file_size(). In the no-handle
else branch, call truncate_inode_pages() to evict stale pages before
the O_TRUNC open: cifs_invalidate_cache() is fscache-only and does not
touch the VFS page cache, so without it old pages persist and may be
served as stale data after a later file extension.
Fixes: 110fee6b9bb5 ("smb: client: fix missing timestamp updates with O_TRUNC")
Cc: [email protected]
Cc: Paulo Alcantara <[email protected]>
Signed-off-by: Frank Sorenson <[email protected]>
---
fs/smb/client/file.c | 18 ++++++++++++++----
1 file changed, 14 insertions(+), 4 deletions(-)
diff --git a/fs/smb/client/file.c b/fs/smb/client/file.c
index 389083f9ce00..05aeb9d94ffe 100644
--- a/fs/smb/client/file.c
+++ b/fs/smb/client/file.c
@@ -1012,10 +1012,20 @@ 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) {
+ netfs_resize_file(&cinode->netfs, 0, true);
+ cifs_setsize(inode, 0);
+ cifs_invalidate_cache(inode, 0);
+ }
+ } else {
+ /*
+ * No cached handle; the server truncates as part of the
+ * O_TRUNC open request that follows. Evict stale pages
+ * from the page cache now so they cannot be served as
+ * stale data after the file is later extended; i_size is
+ * updated from the server's open response.
+ */
+ truncate_inode_pages(inode->i_mapping, 0);
cifs_invalidate_cache(inode, 0);
}
}
--
2.55.0