Re: FAILED: patch "[PATCH] Introduce cifs_copy_file_range()" failed to apply to 4.10-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Mon, 2017-04-10 at 16:21 +0200, gregkh@xxxxxxxxxxxxxxxxxxx wrote:
> The patch below does not apply to the 4.10-stable tree.
> If someone wants it applied there, or to any other stable or longterm
> tree, then please email the backport, including the original git
> commit
> id to <stable@xxxxxxxxxxxxxxx>.
> 
> thanks,
> 
> greg k-h

Hello Greg,

We found a regression in this patch too so would prefer to not have
this backported for now.

Sachin Prabhu
> 
> ------------------ original commit in Linus's tree ------------------
> 
> From 620d8745b35daaf507186c26b40c7ea02aed131e Mon Sep 17 00:00:00
> 2001
> From: Sachin Prabhu <sprabhu@xxxxxxxxxx>
> Date: Fri, 10 Feb 2017 16:03:51 +0530
> Subject: [PATCH] Introduce cifs_copy_file_range()
> 
> The earlier changes to copy range for cifs unintentionally disabled
> the more
> common form of server side copy.
> 
> The patch introduces the file_operations helper
> cifs_copy_file_range()
> which is used by the syscall copy_file_range. The new file operations
> helper allows us to perform server side copies for SMB2.0 and 2.1
> servers as well as SMB 3.0+ servers which do not support the ioctl
> FSCTL_DUPLICATE_EXTENTS_TO_FILE.
> 
> The new helper uses the ioctl FSCTL_SRV_COPYCHUNK_WRITE to perform
> server side copies. The helper is called by vfs_copy_file_range()
> only
> once an attempt to clone the file using the ioctl
> FSCTL_DUPLICATE_EXTENTS_TO_FILE has failed.
> 
> Signed-off-by: Sachin Prabhu <sprabhu@xxxxxxxxxx>
> Reviewed-by: Pavel Shilovsky <pshilov@xxxxxxxxxxxxx>
> CC: Stable  <stable@xxxxxxxxxxxxxxx>
> Signed-off-by: Steve French <smfrench@xxxxxxxxx>
> 
> diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
> index 15e1db8738ae..dd3f5fabfdf6 100644
> --- a/fs/cifs/cifsfs.c
> +++ b/fs/cifs/cifsfs.c
> @@ -972,6 +972,86 @@ static int cifs_clone_file_range(struct file
> *src_file, loff_t off,
>  	return rc;
>  }
>  
> +ssize_t cifs_file_copychunk_range(unsigned int xid,
> +				struct file *src_file, loff_t off,
> +				struct file *dst_file, loff_t
> destoff,
> +				size_t len, unsigned int flags)
> +{
> +	struct inode *src_inode = file_inode(src_file);
> +	struct inode *target_inode = file_inode(dst_file);
> +	struct cifsFileInfo *smb_file_src;
> +	struct cifsFileInfo *smb_file_target;
> +	struct cifs_tcon *src_tcon;
> +	struct cifs_tcon *target_tcon;
> +	ssize_t rc;
> +
> +	cifs_dbg(FYI, "copychunk range\n");
> +
> +	if (src_inode == target_inode) {
> +		rc = -EINVAL;
> +		goto out;
> +	}
> +
> +	if (!src_file->private_data || !dst_file->private_data) {
> +		rc = -EBADF;
> +		cifs_dbg(VFS, "missing cifsFileInfo on copy range
> src file\n");
> +		goto out;
> +	}
> +
> +	rc = -EXDEV;
> +	smb_file_target = dst_file->private_data;
> +	smb_file_src = src_file->private_data;
> +	src_tcon = tlink_tcon(smb_file_src->tlink);
> +	target_tcon = tlink_tcon(smb_file_target->tlink);
> +
> +	if (src_tcon->ses != target_tcon->ses) {
> +		cifs_dbg(VFS, "source and target of copy not on same
> server\n");
> +		goto out;
> +	}
> +
> +	/*
> +	 * Note: cifs case is easier than btrfs since server
> responsible for
> +	 * checks for proper open modes and file type and if it
> wants
> +	 * server could even support copy of range where source =
> target
> +	 */
> +	lock_two_nondirectories(target_inode, src_inode);
> +
> +	cifs_dbg(FYI, "about to flush pages\n");
> +	/* should we flush first and last page first */
> +	truncate_inode_pages(&target_inode->i_data, 0);
> +
> +	if (target_tcon->ses->server->ops->copychunk_range)
> +		rc = target_tcon->ses->server->ops-
> >copychunk_range(xid,
> +			smb_file_src, smb_file_target, off, len,
> destoff);
> +	else
> +		rc = -EOPNOTSUPP;
> +
> +	/* force revalidate of size and timestamps of target file
> now
> +	 * that target is updated on the server
> +	 */
> +	CIFS_I(target_inode)->time = 0;
> +	/* although unlocking in the reverse order from locking is
> not
> +	 * strictly necessary here it is a little cleaner to be
> consistent
> +	 */
> +	unlock_two_nondirectories(src_inode, target_inode);
> +
> +out:
> +	return rc;
> +}
> +
> +static ssize_t cifs_copy_file_range(struct file *src_file, loff_t
> off,
> +				struct file *dst_file, loff_t
> destoff,
> +				size_t len, unsigned int flags)
> +{
> +	unsigned int xid = get_xid();
> +	ssize_t rc;
> +
> +	rc = cifs_file_copychunk_range(xid, src_file, off, dst_file,
> destoff,
> +					len, flags);
> +	free_xid(xid);
> +	return rc;
> +}
> +
>  const struct file_operations cifs_file_ops = {
>  	.read_iter = cifs_loose_read_iter,
>  	.write_iter = cifs_file_write_iter,
> @@ -984,6 +1064,7 @@ const struct file_operations cifs_file_ops = {
>  	.splice_read = generic_file_splice_read,
>  	.llseek = cifs_llseek,
>  	.unlocked_ioctl	= cifs_ioctl,
> +	.copy_file_range = cifs_copy_file_range,
>  	.clone_file_range = cifs_clone_file_range,
>  	.setlease = cifs_setlease,
>  	.fallocate = cifs_fallocate,
> @@ -1001,6 +1082,7 @@ const struct file_operations
> cifs_file_strict_ops = {
>  	.splice_read = generic_file_splice_read,
>  	.llseek = cifs_llseek,
>  	.unlocked_ioctl	= cifs_ioctl,
> +	.copy_file_range = cifs_copy_file_range,
>  	.clone_file_range = cifs_clone_file_range,
>  	.setlease = cifs_setlease,
>  	.fallocate = cifs_fallocate,
> @@ -1018,6 +1100,7 @@ const struct file_operations
> cifs_file_direct_ops = {
>  	.mmap = cifs_file_mmap,
>  	.splice_read = generic_file_splice_read,
>  	.unlocked_ioctl  = cifs_ioctl,
> +	.copy_file_range = cifs_copy_file_range,
>  	.clone_file_range = cifs_clone_file_range,
>  	.llseek = cifs_llseek,
>  	.setlease = cifs_setlease,
> @@ -1035,6 +1118,7 @@ const struct file_operations
> cifs_file_nobrl_ops = {
>  	.splice_read = generic_file_splice_read,
>  	.llseek = cifs_llseek,
>  	.unlocked_ioctl	= cifs_ioctl,
> +	.copy_file_range = cifs_copy_file_range,
>  	.clone_file_range = cifs_clone_file_range,
>  	.setlease = cifs_setlease,
>  	.fallocate = cifs_fallocate,
> @@ -1051,6 +1135,7 @@ const struct file_operations
> cifs_file_strict_nobrl_ops = {
>  	.splice_read = generic_file_splice_read,
>  	.llseek = cifs_llseek,
>  	.unlocked_ioctl	= cifs_ioctl,
> +	.copy_file_range = cifs_copy_file_range,
>  	.clone_file_range = cifs_clone_file_range,
>  	.setlease = cifs_setlease,
>  	.fallocate = cifs_fallocate,
> @@ -1067,6 +1152,7 @@ const struct file_operations
> cifs_file_direct_nobrl_ops = {
>  	.mmap = cifs_file_mmap,
>  	.splice_read = generic_file_splice_read,
>  	.unlocked_ioctl  = cifs_ioctl,
> +	.copy_file_range = cifs_copy_file_range,
>  	.clone_file_range = cifs_clone_file_range,
>  	.llseek = cifs_llseek,
>  	.setlease = cifs_setlease,
> @@ -1078,6 +1164,7 @@ const struct file_operations cifs_dir_ops = {
>  	.release = cifs_closedir,
>  	.read    = generic_read_dir,
>  	.unlocked_ioctl  = cifs_ioctl,
> +	.copy_file_range = cifs_copy_file_range,
>  	.clone_file_range = cifs_clone_file_range,
>  	.llseek = generic_file_llseek,
>  };
> diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
> index da717fee3026..30bf89b1fd9a 100644
> --- a/fs/cifs/cifsfs.h
> +++ b/fs/cifs/cifsfs.h
> @@ -139,6 +139,11 @@ extern ssize_t	cifs_listxattr(struct
> dentry *, char *, size_t);
>  # define cifs_listxattr NULL
>  #endif
>  
> +extern ssize_t cifs_file_copychunk_range(unsigned int xid,
> +					struct file *src_file,
> loff_t off,
> +					struct file *dst_file,
> loff_t destoff,
> +					size_t len, unsigned int
> flags);
> +
>  extern long cifs_ioctl(struct file *filep, unsigned int cmd,
> unsigned long arg);
>  #ifdef CONFIG_CIFS_NFSD_EXPORT
>  extern const struct export_operations cifs_export_ops;
> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
> index 57c594827cb3..d07f13a63369 100644
> --- a/fs/cifs/cifsglob.h
> +++ b/fs/cifs/cifsglob.h
> @@ -408,10 +408,10 @@ struct smb_version_operations {
>  	char * (*create_lease_buf)(u8 *, u8);
>  	/* parse lease context buffer and return oplock/epoch info
> */
>  	__u8 (*parse_lease_buf)(void *, unsigned int *);
> -	int (*copychunk_range)(const unsigned int,
> +	ssize_t (*copychunk_range)(const unsigned int,
>  			struct cifsFileInfo *src_file,
> -			struct cifsFileInfo *target_file, u64
> src_off, u64 len,
> -			u64 dest_off);
> +			struct cifsFileInfo *target_file,
> +			u64 src_off, u64 len, u64 dest_off);
>  	int (*duplicate_extents)(const unsigned int, struct
> cifsFileInfo *src,
>  			struct cifsFileInfo *target_file, u64
> src_off, u64 len,
>  			u64 dest_off);
> diff --git a/fs/cifs/ioctl.c b/fs/cifs/ioctl.c
> index 9bf0f94fae63..265c45fe4ea5 100644
> --- a/fs/cifs/ioctl.c
> +++ b/fs/cifs/ioctl.c
> @@ -34,63 +34,6 @@
>  #include "cifs_ioctl.h"
>  #include <linux/btrfs.h>
>  
> -static int cifs_file_copychunk_range(unsigned int xid, struct file
> *src_file,
> -			  struct file *dst_file)
> -{
> -	struct inode *src_inode = file_inode(src_file);
> -	struct inode *target_inode = file_inode(dst_file);
> -	struct cifsFileInfo *smb_file_src;
> -	struct cifsFileInfo *smb_file_target;
> -	struct cifs_tcon *src_tcon;
> -	struct cifs_tcon *target_tcon;
> -	int rc;
> -
> -	cifs_dbg(FYI, "ioctl copychunk range\n");
> -
> -	if (!src_file->private_data || !dst_file->private_data) {
> -		rc = -EBADF;
> -		cifs_dbg(VFS, "missing cifsFileInfo on copy range
> src file\n");
> -		goto out;
> -	}
> -
> -	rc = -EXDEV;
> -	smb_file_target = dst_file->private_data;
> -	smb_file_src = src_file->private_data;
> -	src_tcon = tlink_tcon(smb_file_src->tlink);
> -	target_tcon = tlink_tcon(smb_file_target->tlink);
> -
> -	if (src_tcon->ses != target_tcon->ses) {
> -		cifs_dbg(VFS, "source and target of copy not on same
> server\n");
> -		goto out;
> -	}
> -
> -	/*
> -	 * Note: cifs case is easier than btrfs since server
> responsible for
> -	 * checks for proper open modes and file type and if it
> wants
> -	 * server could even support copy of range where source =
> target
> -	 */
> -	lock_two_nondirectories(target_inode, src_inode);
> -
> -	cifs_dbg(FYI, "about to flush pages\n");
> -	/* should we flush first and last page first */
> -	truncate_inode_pages(&target_inode->i_data, 0);
> -
> -	if (target_tcon->ses->server->ops->copychunk_range)
> -		rc = target_tcon->ses->server->ops-
> >copychunk_range(xid,
> -			smb_file_src, smb_file_target, 0, src_inode-
> >i_size, 0);
> -	else
> -		rc = -EOPNOTSUPP;
> -
> -	/* force revalidate of size and timestamps of target file
> now
> -	   that target is updated on the server */
> -	CIFS_I(target_inode)->time = 0;
> -	/* although unlocking in the reverse order from locking is
> not
> -	   strictly necessary here it is a little cleaner to be
> consistent */
> -	unlock_two_nondirectories(src_inode, target_inode);
> -out:
> -	return rc;
> -}
> -
>  static long cifs_ioctl_copychunk(unsigned int xid, struct file
> *dst_file,
>  			unsigned long srcfd)
>  {
> @@ -129,7 +72,8 @@ static long cifs_ioctl_copychunk(unsigned int xid,
> struct file *dst_file,
>  	if (S_ISDIR(src_inode->i_mode))
>  		goto out_fput;
>  
> -	rc = cifs_file_copychunk_range(xid, src_file.file,
> dst_file);
> +	rc = cifs_file_copychunk_range(xid, src_file.file, 0,
> dst_file, 0,
> +					src_inode->i_size, 0);
>  
>  out_fput:
>  	fdput(src_file);
> diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
> index 3f12e0992b9b..063e59d543f9 100644
> --- a/fs/cifs/smb2ops.c
> +++ b/fs/cifs/smb2ops.c
> @@ -592,7 +592,7 @@ SMB2_request_res_key(const unsigned int xid,
> struct cifs_tcon *tcon,
>  	return rc;
>  }
>  
> -static int
> +static ssize_t
>  smb2_copychunk_range(const unsigned int xid,
>  			struct cifsFileInfo *srcfile,
>  			struct cifsFileInfo *trgtfile, u64 src_off,
> @@ -605,6 +605,7 @@ smb2_copychunk_range(const unsigned int xid,
>  	struct cifs_tcon *tcon;
>  	int chunks_copied = 0;
>  	bool chunk_sizes_updated = false;
> +	ssize_t bytes_written, total_bytes_written = 0;
>  
>  	pcchunk = kmalloc(sizeof(struct copychunk_ioctl),
> GFP_KERNEL);
>  
> @@ -669,14 +670,16 @@ smb2_copychunk_range(const unsigned int xid,
>  			}
>  			chunks_copied++;
>  
> -			src_off += le32_to_cpu(retbuf-
> >TotalBytesWritten);
> -			dest_off += le32_to_cpu(retbuf-
> >TotalBytesWritten);
> -			len -= le32_to_cpu(retbuf-
> >TotalBytesWritten);
> +			bytes_written = le32_to_cpu(retbuf-
> >TotalBytesWritten);
> +			src_off += bytes_written;
> +			dest_off += bytes_written;
> +			len -= bytes_written;
> +			total_bytes_written += bytes_written;
>  
> -			cifs_dbg(FYI, "Chunks %d PartialChunk %d
> Total %d\n",
> +			cifs_dbg(FYI, "Chunks %d PartialChunk %d
> Total %zu\n",
>  				le32_to_cpu(retbuf->ChunksWritten),
>  				le32_to_cpu(retbuf-
> >ChunkBytesWritten),
> -				le32_to_cpu(retbuf-
> >TotalBytesWritten));
> +				bytes_written);
>  		} else if (rc == -EINVAL) {
>  			if (ret_data_len != sizeof(struct
> copychunk_ioctl_rsp))
>  				goto cchunk_out;
> @@ -713,7 +716,10 @@ smb2_copychunk_range(const unsigned int xid,
>  cchunk_out:
>  	kfree(pcchunk);
>  	kfree(retbuf);
> -	return rc;
> +	if (rc)
> +		return rc;
> +	else
> +		return total_bytes_written;
>  }
>  
>  static int
> 




[Index of Archives]     [Linux Kernel]     [Kernel Development Newbies]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Hiking]     [Linux Kernel]     [Linux SCSI]