Patch "cifs: Fix FALLOC_FL_PUNCH_HOLE support" has been added to the 6.6-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    cifs: Fix FALLOC_FL_PUNCH_HOLE support

to the 6.6-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     cifs-fix-falloc_fl_punch_hole-support.patch
and it can be found in the queue-6.6 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit 0b99565ef0f8c7477e54fff2c50ed5ae773d71fc
Author: David Howells <dhowells@xxxxxxxxxx>
Date:   Fri Aug 23 14:22:42 2024 +0100

    cifs: Fix FALLOC_FL_PUNCH_HOLE support
    
    [ 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@xxxxxxxxxx>
    cc: Steve French <sfrench@xxxxxxxxx>
    cc: Paulo Alcantara <pc@xxxxxxxxxxxxx>
    cc: Shyam Prasad N <nspmangalore@xxxxxxxxx>
    cc: Jeff Layton <jlayton@xxxxxxxxxx>
    cc: linux-cifs@xxxxxxxxxxxxxxx
    cc: netfs@xxxxxxxxxxxxxxx
    Signed-off-by: Steve French <stfrench@xxxxxxxxxxxxx>
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
index 66cfce456263b..012d6ec12a691 100644
--- a/fs/smb/client/smb2ops.c
+++ b/fs/smb/client/smb2ops.c
@@ -3251,6 +3251,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;
@@ -3282,6 +3283,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);




[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux