mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	vfs: no fallback for ->copy_file_range
Now that we have generic_copy_file_range(), remove it as a fallback case when offloads fail. This puts the responsibility for executing fallbacks on the filesystems that implement ->copy_file_range and allows us to add operational validity checks to generic_copy_file_range(). Rework vfs_copy_file_range() to call a new do_copy_file_range() helper to execute the copying callout, and move calls to generic_file_copy_range() into filesystem methods where they currently return failures. [Amir] overlayfs is not responsible of executing the fallback. It is the responsibility of the underlying filesystem. Signed-off-by: Dave Chinner <dchinner@redhat.com> Signed-off-by: Amir Goldstein <amir73il@gmail.com> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
This commit is contained in:
		
							parent
							
								
									f16acc9d9b
								
							
						
					
					
						commit
						64bf5ff58d
					
				
					 5 changed files with 73 additions and 18 deletions
				
			
		| 
						 | 
				
			
			@ -1889,9 +1889,9 @@ static int is_file_size_ok(struct inode *src_inode, struct inode *dst_inode,
 | 
			
		|||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static ssize_t ceph_copy_file_range(struct file *src_file, loff_t src_off,
 | 
			
		||||
				    struct file *dst_file, loff_t dst_off,
 | 
			
		||||
				    size_t len, unsigned int flags)
 | 
			
		||||
static ssize_t __ceph_copy_file_range(struct file *src_file, loff_t src_off,
 | 
			
		||||
				      struct file *dst_file, loff_t dst_off,
 | 
			
		||||
				      size_t len, unsigned int flags)
 | 
			
		||||
{
 | 
			
		||||
	struct inode *src_inode = file_inode(src_file);
 | 
			
		||||
	struct inode *dst_inode = file_inode(dst_file);
 | 
			
		||||
| 
						 | 
				
			
			@ -2100,6 +2100,21 @@ static ssize_t ceph_copy_file_range(struct file *src_file, loff_t src_off,
 | 
			
		|||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static ssize_t ceph_copy_file_range(struct file *src_file, loff_t src_off,
 | 
			
		||||
				    struct file *dst_file, loff_t dst_off,
 | 
			
		||||
				    size_t len, unsigned int flags)
 | 
			
		||||
{
 | 
			
		||||
	ssize_t ret;
 | 
			
		||||
 | 
			
		||||
	ret = __ceph_copy_file_range(src_file, src_off, dst_file, dst_off,
 | 
			
		||||
				     len, flags);
 | 
			
		||||
 | 
			
		||||
	if (ret == -EOPNOTSUPP)
 | 
			
		||||
		ret = generic_copy_file_range(src_file, src_off, dst_file,
 | 
			
		||||
					      dst_off, len, flags);
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const struct file_operations ceph_file_fops = {
 | 
			
		||||
	.open = ceph_open,
 | 
			
		||||
	.release = ceph_release,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1148,6 +1148,10 @@ static ssize_t cifs_copy_file_range(struct file *src_file, loff_t off,
 | 
			
		|||
	rc = cifs_file_copychunk_range(xid, src_file, off, dst_file, destoff,
 | 
			
		||||
					len, flags);
 | 
			
		||||
	free_xid(xid);
 | 
			
		||||
 | 
			
		||||
	if (rc == -EOPNOTSUPP)
 | 
			
		||||
		rc = generic_copy_file_range(src_file, off, dst_file,
 | 
			
		||||
					     destoff, len, flags);
 | 
			
		||||
	return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3112,9 +3112,9 @@ static long fuse_file_fallocate(struct file *file, int mode, loff_t offset,
 | 
			
		|||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static ssize_t fuse_copy_file_range(struct file *file_in, loff_t pos_in,
 | 
			
		||||
				    struct file *file_out, loff_t pos_out,
 | 
			
		||||
				    size_t len, unsigned int flags)
 | 
			
		||||
static ssize_t __fuse_copy_file_range(struct file *file_in, loff_t pos_in,
 | 
			
		||||
				      struct file *file_out, loff_t pos_out,
 | 
			
		||||
				      size_t len, unsigned int flags)
 | 
			
		||||
{
 | 
			
		||||
	struct fuse_file *ff_in = file_in->private_data;
 | 
			
		||||
	struct fuse_file *ff_out = file_out->private_data;
 | 
			
		||||
| 
						 | 
				
			
			@ -3194,6 +3194,21 @@ static ssize_t fuse_copy_file_range(struct file *file_in, loff_t pos_in,
 | 
			
		|||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static ssize_t fuse_copy_file_range(struct file *src_file, loff_t src_off,
 | 
			
		||||
				    struct file *dst_file, loff_t dst_off,
 | 
			
		||||
				    size_t len, unsigned int flags)
 | 
			
		||||
{
 | 
			
		||||
	ssize_t ret;
 | 
			
		||||
 | 
			
		||||
	ret = __fuse_copy_file_range(src_file, src_off, dst_file, dst_off,
 | 
			
		||||
				     len, flags);
 | 
			
		||||
 | 
			
		||||
	if (ret == -EOPNOTSUPP)
 | 
			
		||||
		ret = generic_copy_file_range(src_file, src_off, dst_file,
 | 
			
		||||
					      dst_off, len, flags);
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct file_operations fuse_file_operations = {
 | 
			
		||||
	.llseek		= fuse_file_llseek,
 | 
			
		||||
	.read_iter	= fuse_file_read_iter,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -129,9 +129,9 @@ nfs4_file_flush(struct file *file, fl_owner_t id)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_NFS_V4_2
 | 
			
		||||
static ssize_t nfs4_copy_file_range(struct file *file_in, loff_t pos_in,
 | 
			
		||||
				    struct file *file_out, loff_t pos_out,
 | 
			
		||||
				    size_t count, unsigned int flags)
 | 
			
		||||
static ssize_t __nfs4_copy_file_range(struct file *file_in, loff_t pos_in,
 | 
			
		||||
				      struct file *file_out, loff_t pos_out,
 | 
			
		||||
				      size_t count, unsigned int flags)
 | 
			
		||||
{
 | 
			
		||||
	if (!nfs_server_capable(file_inode(file_out), NFS_CAP_COPY))
 | 
			
		||||
		return -EOPNOTSUPP;
 | 
			
		||||
| 
						 | 
				
			
			@ -140,6 +140,20 @@ static ssize_t nfs4_copy_file_range(struct file *file_in, loff_t pos_in,
 | 
			
		|||
	return nfs42_proc_copy(file_in, pos_in, file_out, pos_out, count);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static ssize_t nfs4_copy_file_range(struct file *file_in, loff_t pos_in,
 | 
			
		||||
				    struct file *file_out, loff_t pos_out,
 | 
			
		||||
				    size_t count, unsigned int flags)
 | 
			
		||||
{
 | 
			
		||||
	ssize_t ret;
 | 
			
		||||
 | 
			
		||||
	ret = __nfs4_copy_file_range(file_in, pos_in, file_out, pos_out, count,
 | 
			
		||||
				     flags);
 | 
			
		||||
	if (ret == -EOPNOTSUPP)
 | 
			
		||||
		ret = generic_copy_file_range(file_in, pos_in, file_out,
 | 
			
		||||
					      pos_out, count, flags);
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static loff_t nfs4_file_llseek(struct file *filep, loff_t offset, int whence)
 | 
			
		||||
{
 | 
			
		||||
	loff_t ret;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1595,6 +1595,19 @@ ssize_t generic_copy_file_range(struct file *file_in, loff_t pos_in,
 | 
			
		|||
}
 | 
			
		||||
EXPORT_SYMBOL(generic_copy_file_range);
 | 
			
		||||
 | 
			
		||||
static ssize_t do_copy_file_range(struct file *file_in, loff_t pos_in,
 | 
			
		||||
				  struct file *file_out, loff_t pos_out,
 | 
			
		||||
				  size_t len, unsigned int flags)
 | 
			
		||||
{
 | 
			
		||||
	if (file_out->f_op->copy_file_range)
 | 
			
		||||
		return file_out->f_op->copy_file_range(file_in, pos_in,
 | 
			
		||||
						       file_out, pos_out,
 | 
			
		||||
						       len, flags);
 | 
			
		||||
 | 
			
		||||
	return generic_copy_file_range(file_in, pos_in, file_out, pos_out, len,
 | 
			
		||||
				       flags);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * copy_file_range() differs from regular file read and write in that it
 | 
			
		||||
 * specifically allows return partial success.  When it does so is up to
 | 
			
		||||
| 
						 | 
				
			
			@ -1655,15 +1668,9 @@ ssize_t vfs_copy_file_range(struct file *file_in, loff_t pos_in,
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (file_out->f_op->copy_file_range) {
 | 
			
		||||
		ret = file_out->f_op->copy_file_range(file_in, pos_in, file_out,
 | 
			
		||||
						      pos_out, len, flags);
 | 
			
		||||
		if (ret != -EOPNOTSUPP)
 | 
			
		||||
			goto done;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ret = generic_copy_file_range(file_in, pos_in, file_out, pos_out, len,
 | 
			
		||||
				      flags);
 | 
			
		||||
	ret = do_copy_file_range(file_in, pos_in, file_out, pos_out, len,
 | 
			
		||||
				flags);
 | 
			
		||||
	WARN_ON_ONCE(ret == -EOPNOTSUPP);
 | 
			
		||||
done:
 | 
			
		||||
	if (ret > 0) {
 | 
			
		||||
		fsnotify_access(file_in);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue