Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

cifs: Fix setting of zero_point after DIO write

At the moment, at the end of a DIO write, cifs calls netfs_resize_file() to
adjust the size of the file if it needs it. This will reduce the
zero_point (the point above which we assume a read will just return zeros)
if it's more than the new i_size, but won't increase it.

With DIO writes, however, we definitely want to increase it as we have
clobbered the local pagecache and then written some data that's not
available locally.

Fix cifs to make the zero_point above the end of a DIO or unbuffered write.

This fixes corruption seen occasionally with the generic/708 xfs-test. In
that case, the read-back of some of the written data is being
short-circuited and replaced with zeroes.

Fixes: 3ee1a1fc3981 ("cifs: Cut over to using netfslib")
Cc: stable@vger.kernel.org
Reported-by: Steve French <sfrench@samba.org>
Signed-off-by: David Howells <dhowells@redhat.com>
Reviewed-by: Paulo Alcantara (Red Hat) <pc@manguebit.com>
cc: Jeff Layton <jlayton@kernel.org>
cc: linux-cifs@vger.kernel.org
cc: netfs@lists.linux.dev
cc: linux-fsdevel@vger.kernel.org
Signed-off-by: Steve French <stfrench@microsoft.com>

authored by

David Howells and committed by
Steve French
61ea6b3a d2c5eb57

+9 -4
+9 -4
fs/smb/client/file.c
··· 2358 2358 bool was_async) 2359 2359 { 2360 2360 struct netfs_io_request *wreq = wdata->rreq; 2361 - loff_t new_server_eof; 2361 + struct netfs_inode *ictx = netfs_inode(wreq->inode); 2362 + loff_t wrend; 2362 2363 2363 2364 if (result > 0) { 2364 - new_server_eof = wdata->subreq.start + wdata->subreq.transferred + result; 2365 + wrend = wdata->subreq.start + wdata->subreq.transferred + result; 2365 2366 2366 - if (new_server_eof > netfs_inode(wreq->inode)->remote_i_size) 2367 - netfs_resize_file(netfs_inode(wreq->inode), new_server_eof, true); 2367 + if (wrend > ictx->zero_point && 2368 + (wdata->rreq->origin == NETFS_UNBUFFERED_WRITE || 2369 + wdata->rreq->origin == NETFS_DIO_WRITE)) 2370 + ictx->zero_point = wrend; 2371 + if (wrend > ictx->remote_i_size) 2372 + netfs_resize_file(ictx, wrend, true); 2368 2373 } 2369 2374 2370 2375 netfs_write_subrequest_terminated(&wdata->subreq, result, was_async);