mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	NFSv42: Copy offload should update the file size when appropriate
If the result of a copy offload or clone operation is to grow the
destination file size, then we should update it. The reason is that when
a client holds a delegation, it is authoritative for the file size.
Fixes: 16abd2a0c1 ("NFSv4.2: fix client's attribute cache management for copy_file_range")
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
			
			
This commit is contained in:
		
							parent
							
								
									09252177d5
								
							
						
					
					
						commit
						94d202d5ca
					
				
					 1 changed files with 32 additions and 9 deletions
				
			
		| 
						 | 
					@ -269,6 +269,33 @@ static int process_copy_commit(struct file *dst, loff_t pos_dst,
 | 
				
			||||||
	return status;
 | 
						return status;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * nfs42_copy_dest_done - perform inode cache updates after clone/copy offload
 | 
				
			||||||
 | 
					 * @inode: pointer to destination inode
 | 
				
			||||||
 | 
					 * @pos: destination offset
 | 
				
			||||||
 | 
					 * @len: copy length
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Punch a hole in the inode page cache, so that the NFS client will
 | 
				
			||||||
 | 
					 * know to retrieve new data.
 | 
				
			||||||
 | 
					 * Update the file size if necessary, and then mark the inode as having
 | 
				
			||||||
 | 
					 * invalid cached values for change attribute, ctime, mtime and space used.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void nfs42_copy_dest_done(struct inode *inode, loff_t pos, loff_t len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						loff_t newsize = pos + len;
 | 
				
			||||||
 | 
						loff_t end = newsize - 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						truncate_pagecache_range(inode, pos, end);
 | 
				
			||||||
 | 
						spin_lock(&inode->i_lock);
 | 
				
			||||||
 | 
						if (newsize > i_size_read(inode))
 | 
				
			||||||
 | 
							i_size_write(inode, newsize);
 | 
				
			||||||
 | 
						nfs_set_cache_invalid(inode, NFS_INO_INVALID_CHANGE |
 | 
				
			||||||
 | 
										     NFS_INO_INVALID_CTIME |
 | 
				
			||||||
 | 
										     NFS_INO_INVALID_MTIME |
 | 
				
			||||||
 | 
										     NFS_INO_INVALID_BLOCKS);
 | 
				
			||||||
 | 
						spin_unlock(&inode->i_lock);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static ssize_t _nfs42_proc_copy(struct file *src,
 | 
					static ssize_t _nfs42_proc_copy(struct file *src,
 | 
				
			||||||
				struct nfs_lock_context *src_lock,
 | 
									struct nfs_lock_context *src_lock,
 | 
				
			||||||
				struct file *dst,
 | 
									struct file *dst,
 | 
				
			||||||
| 
						 | 
					@ -362,14 +389,8 @@ static ssize_t _nfs42_proc_copy(struct file *src,
 | 
				
			||||||
			goto out;
 | 
								goto out;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	truncate_pagecache_range(dst_inode, pos_dst,
 | 
						nfs42_copy_dest_done(dst_inode, pos_dst, res->write_res.count);
 | 
				
			||||||
				 pos_dst + res->write_res.count);
 | 
					
 | 
				
			||||||
	spin_lock(&dst_inode->i_lock);
 | 
					 | 
				
			||||||
	nfs_set_cache_invalid(
 | 
					 | 
				
			||||||
		dst_inode, NFS_INO_REVAL_PAGECACHE | NFS_INO_REVAL_FORCED |
 | 
					 | 
				
			||||||
				   NFS_INO_INVALID_SIZE | NFS_INO_INVALID_ATTR |
 | 
					 | 
				
			||||||
				   NFS_INO_INVALID_DATA);
 | 
					 | 
				
			||||||
	spin_unlock(&dst_inode->i_lock);
 | 
					 | 
				
			||||||
	spin_lock(&src_inode->i_lock);
 | 
						spin_lock(&src_inode->i_lock);
 | 
				
			||||||
	nfs_set_cache_invalid(src_inode, NFS_INO_REVAL_PAGECACHE |
 | 
						nfs_set_cache_invalid(src_inode, NFS_INO_REVAL_PAGECACHE |
 | 
				
			||||||
						 NFS_INO_REVAL_FORCED |
 | 
											 NFS_INO_REVAL_FORCED |
 | 
				
			||||||
| 
						 | 
					@ -1055,8 +1076,10 @@ static int _nfs42_proc_clone(struct rpc_message *msg, struct file *src_f,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	status = nfs4_call_sync(server->client, server, msg,
 | 
						status = nfs4_call_sync(server->client, server, msg,
 | 
				
			||||||
				&args.seq_args, &res.seq_res, 0);
 | 
									&args.seq_args, &res.seq_res, 0);
 | 
				
			||||||
	if (status == 0)
 | 
						if (status == 0) {
 | 
				
			||||||
 | 
							nfs42_copy_dest_done(dst_inode, dst_offset, count);
 | 
				
			||||||
		status = nfs_post_op_update_inode(dst_inode, res.dst_fattr);
 | 
							status = nfs_post_op_update_inode(dst_inode, res.dst_fattr);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	kfree(res.dst_fattr);
 | 
						kfree(res.dst_fattr);
 | 
				
			||||||
	return status;
 | 
						return status;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue