forked from mirrors/linux
		
	ovl: add reflink/copyfile/dedup support
Since set of arguments are so similar, handle in a common helper. Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
This commit is contained in:
		
							parent
							
								
									f7c72396d0
								
							
						
					
					
						commit
						8ede205541
					
				
					 1 changed files with 87 additions and 0 deletions
				
			
		| 
						 | 
					@ -389,6 +389,89 @@ static long ovl_compat_ioctl(struct file *file, unsigned int cmd,
 | 
				
			||||||
	return ovl_ioctl(file, cmd, arg);
 | 
						return ovl_ioctl(file, cmd, arg);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum ovl_copyop {
 | 
				
			||||||
 | 
						OVL_COPY,
 | 
				
			||||||
 | 
						OVL_CLONE,
 | 
				
			||||||
 | 
						OVL_DEDUPE,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static ssize_t ovl_copyfile(struct file *file_in, loff_t pos_in,
 | 
				
			||||||
 | 
								    struct file *file_out, loff_t pos_out,
 | 
				
			||||||
 | 
								    u64 len, unsigned int flags, enum ovl_copyop op)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct inode *inode_out = file_inode(file_out);
 | 
				
			||||||
 | 
						struct fd real_in, real_out;
 | 
				
			||||||
 | 
						const struct cred *old_cred;
 | 
				
			||||||
 | 
						ssize_t ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = ovl_real_fdget(file_out, &real_out);
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = ovl_real_fdget(file_in, &real_in);
 | 
				
			||||||
 | 
						if (ret) {
 | 
				
			||||||
 | 
							fdput(real_out);
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						old_cred = ovl_override_creds(file_inode(file_out)->i_sb);
 | 
				
			||||||
 | 
						switch (op) {
 | 
				
			||||||
 | 
						case OVL_COPY:
 | 
				
			||||||
 | 
							ret = vfs_copy_file_range(real_in.file, pos_in,
 | 
				
			||||||
 | 
										  real_out.file, pos_out, len, flags);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case OVL_CLONE:
 | 
				
			||||||
 | 
							ret = vfs_clone_file_range(real_in.file, pos_in,
 | 
				
			||||||
 | 
										   real_out.file, pos_out, len);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case OVL_DEDUPE:
 | 
				
			||||||
 | 
							ret = vfs_dedupe_file_range_one(real_in.file, pos_in,
 | 
				
			||||||
 | 
											real_out.file, pos_out, len);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						revert_creds(old_cred);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Update size */
 | 
				
			||||||
 | 
						ovl_copyattr(ovl_inode_real(inode_out), inode_out);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fdput(real_in);
 | 
				
			||||||
 | 
						fdput(real_out);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static ssize_t ovl_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)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return ovl_copyfile(file_in, pos_in, file_out, pos_out, len, flags,
 | 
				
			||||||
 | 
								    OVL_COPY);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int ovl_clone_file_range(struct file *file_in, loff_t pos_in,
 | 
				
			||||||
 | 
									struct file *file_out, loff_t pos_out, u64 len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return ovl_copyfile(file_in, pos_in, file_out, pos_out, len, 0,
 | 
				
			||||||
 | 
								    OVL_CLONE);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int ovl_dedupe_file_range(struct file *file_in, loff_t pos_in,
 | 
				
			||||||
 | 
									 struct file *file_out, loff_t pos_out, u64 len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Don't copy up because of a dedupe request, this wouldn't make sense
 | 
				
			||||||
 | 
						 * most of the time (data would be duplicated instead of deduplicated).
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (!ovl_inode_upper(file_inode(file_in)) ||
 | 
				
			||||||
 | 
						    !ovl_inode_upper(file_inode(file_out)))
 | 
				
			||||||
 | 
							return -EPERM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ovl_copyfile(file_in, pos_in, file_out, pos_out, len, 0,
 | 
				
			||||||
 | 
								    OVL_DEDUPE);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const struct file_operations ovl_file_operations = {
 | 
					const struct file_operations ovl_file_operations = {
 | 
				
			||||||
	.open		= ovl_open,
 | 
						.open		= ovl_open,
 | 
				
			||||||
	.release	= ovl_release,
 | 
						.release	= ovl_release,
 | 
				
			||||||
| 
						 | 
					@ -400,4 +483,8 @@ const struct file_operations ovl_file_operations = {
 | 
				
			||||||
	.fallocate	= ovl_fallocate,
 | 
						.fallocate	= ovl_fallocate,
 | 
				
			||||||
	.unlocked_ioctl	= ovl_ioctl,
 | 
						.unlocked_ioctl	= ovl_ioctl,
 | 
				
			||||||
	.compat_ioctl	= ovl_compat_ioctl,
 | 
						.compat_ioctl	= ovl_compat_ioctl,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						.copy_file_range	= ovl_copy_file_range,
 | 
				
			||||||
 | 
						.clone_file_range	= ovl_clone_file_range,
 | 
				
			||||||
 | 
						.dedupe_file_range	= ovl_dedupe_file_range,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue