_nfs42_proc_fallocate() raises i_size to offset + len on success, so that the cached size is not left stale when a delegation blocks the post-op attribute refresh. The helper is shared by all three fallocate modes, but DEALLOCATE always carries FALLOC_FL_KEEP_SIZE and never extends the file on the server, so punching a hole that reaches past EOF now wrongly enlarges the cached i_size. The post-op update would normally restore the size from the returned attributes, but nfs_update_inode() applies a differing size only when no delegation is held, and then only when no write is in flight or the new size is larger: if (new_isize != cur_isize && !have_delegation) { if (!nfs_have_writebacks(inode) || new_isize > cur_isize) i_size_write(inode, new_isize); } With a concurrent mmap writer (nrequests != 0) or any outstanding delegation, the shrinking server size is therefore ignored and the client keeps reporting a file larger than the server has, in violation of KEEP_SIZE, until some later revalidation without writebacks happens to fix it up. Skip the i_size bump for the DEALLOCATE procedure. ALLOCATE (mode 0) and ZERO_RANGE (which nfs42_fallocate() accepts only without FALLOC_FL_KEEP_SIZE) do extend the file when the range reaches past EOF, so they keep the update. Fixes: 35168eb947f2 ("NFS: fix eof updates after NFSv4.2 fallocate/zero-range") Cc: stable@vger.kernel.org Signed-off-by: Joseph Qi --- fs/nfs/nfs42proc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/nfs/nfs42proc.c b/fs/nfs/nfs42proc.c index ab86246fc364f..d76bface87f74 100644 --- a/fs/nfs/nfs42proc.c +++ b/fs/nfs/nfs42proc.c @@ -84,7 +84,9 @@ static int _nfs42_proc_fallocate(struct rpc_message *msg, struct file *filep, loff_t newsize = offset + len; spin_lock(&inode->i_lock); - if (newsize > i_size_read(inode)) + /* DEALLOCATE implies KEEP_SIZE, so don't extend i_size */ + if (msg->rpc_proc != &nfs4_procedures[NFSPROC4_CLNT_DEALLOCATE] && + newsize > i_size_read(inode)) i_size_write(inode, newsize); nfs_set_cache_invalid(inode, NFS_INO_INVALID_BLOCKS); if (nfs_should_remove_suid(inode)) -- 2.39.3