+++ /dev/null
-From eb9c3d155197ad243b223f434bd2019955cde685 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Fri, 23 Aug 2024 14:22:42 +0100
-Subject: cifs: Fix FALLOC_FL_PUNCH_HOLE support
-
-From: David Howells <dhowells@redhat.com>
-
-[ Upstream commit 416871f4fb84bc96822562e654941d5625a25bf8 ]
-
-The cifs filesystem doesn't quite emulate FALLOC_FL_PUNCH_HOLE correctly
-(note that due to lack of protocol support, it can't actually implement it
-directly). Whilst it will (partially) invalidate dirty folios in the
-pagecache, it doesn't write them back first, and so the EOF marker on the
-server may be lower than inode->i_size.
-
-This presents a problem, however, as if the punched hole invalidates the
-tail of the locally cached dirty data, writeback won't know it needs to
-move the EOF over to account for the hole punch (which isn't supposed to
-move the EOF). We could just write zeroes over the punched out region of
-the pagecache and write that back - but this is supposed to be a
-deallocatory operation.
-
-Fix this by manually moving the EOF over on the server after the operation
-if the hole punched would corrupt it.
-
-Note that the FSCTL_SET_ZERO_DATA RPC and the setting of the EOF should
-probably be compounded to stop a third party interfering (or, at least,
-massively reduce the chance).
-
-This was reproducible occasionally by using fsx with the following script:
-
- truncate 0x0 0x375e2 0x0
- punch_hole 0x2f6d3 0x6ab5 0x375e2
- truncate 0x0 0x3a71f 0x375e2
- mapread 0xee05 0xcf12 0x3a71f
- write 0x2078e 0x5604 0x3a71f
- write 0x3ebdf 0x1421 0x3a71f *
- punch_hole 0x379d0 0x8630 0x40000 *
- mapread 0x2aaa2 0x85b 0x40000
- fallocate 0x1b401 0x9ada 0x40000
- read 0x15f2 0x7d32 0x40000
- read 0x32f37 0x7a3b 0x40000 *
-
-The second "write" should extend the EOF to 0x40000, and the "punch_hole"
-should operate inside of that - but that depends on whether the VM gets in
-and writes back the data first. If it doesn't, the file ends up 0x3a71f in
-size, not 0x40000.
-
-Fixes: 31742c5a3317 ("enable fallocate punch hole ("fallocate -p") for SMB3")
-Signed-off-by: David Howells <dhowells@redhat.com>
-cc: Steve French <sfrench@samba.org>
-cc: Paulo Alcantara <pc@manguebit.com>
-cc: Shyam Prasad N <nspmangalore@gmail.com>
-cc: Jeff Layton <jlayton@kernel.org>
-cc: linux-cifs@vger.kernel.org
-cc: netfs@lists.linux.dev
-Signed-off-by: Steve French <stfrench@microsoft.com>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- fs/smb/client/smb2ops.c | 22 ++++++++++++++++++++++
- 1 file changed, 22 insertions(+)
-
-diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
-index 2291081653a85..a3c4af2fb6897 100644
---- a/fs/smb/client/smb2ops.c
-+++ b/fs/smb/client/smb2ops.c
-@@ -3510,6 +3510,7 @@ static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon,
- struct inode *inode = file_inode(file);
- struct cifsFileInfo *cfile = file->private_data;
- struct file_zero_data_information fsctl_buf;
-+ unsigned long long end = offset + len, i_size, remote_i_size;
- long rc;
- unsigned int xid;
- __u8 set_sparse = 1;
-@@ -3541,6 +3542,27 @@ static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon,
- (char *)&fsctl_buf,
- sizeof(struct file_zero_data_information),
- CIFSMaxBufSize, NULL, NULL);
-+
-+ if (rc)
-+ goto unlock;
-+
-+ /* If there's dirty data in the buffer that would extend the EOF if it
-+ * were written, then we need to move the EOF marker over to the lower
-+ * of the high end of the hole and the proposed EOF. The problem is
-+ * that we locally hole-punch the tail of the dirty data, the proposed
-+ * EOF update will end up in the wrong place.
-+ */
-+ i_size = i_size_read(inode);
-+ remote_i_size = netfs_inode(inode)->remote_i_size;
-+ if (end > remote_i_size && i_size > remote_i_size) {
-+ unsigned long long extend_to = umin(end, i_size);
-+ rc = SMB2_set_eof(xid, tcon, cfile->fid.persistent_fid,
-+ cfile->fid.volatile_fid, cfile->pid, extend_to);
-+ if (rc >= 0)
-+ netfs_inode(inode)->remote_i_size = extend_to;
-+ }
-+
-+unlock:
- filemap_invalidate_unlock(inode->i_mapping);
- out:
- inode_unlock(inode);
---
-2.43.0
-