stable.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* FAILED: patch "[PATCH] Introduce cifs_copy_file_range()" failed to apply to 4.10-stable tree
@ 2017-04-10 14:21 gregkh
  2017-04-10 14:23 ` Sachin Prabhu
  0 siblings, 1 reply; 2+ messages in thread
From: gregkh @ 2017-04-10 14:21 UTC (permalink / raw)
  To: sprabhu, pshilov, smfrench, stable; +Cc: stable


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@vger.kernel.org>.

thanks,

greg k-h

------------------ original commit in Linus's tree ------------------

>From 620d8745b35daaf507186c26b40c7ea02aed131e Mon Sep 17 00:00:00 2001
From: Sachin Prabhu <sprabhu@redhat.com>
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@redhat.com>
Reviewed-by: Pavel Shilovsky <pshilov@microsoft.com>
CC: Stable  <stable@vger.kernel.org>
Signed-off-by: Steve French <smfrench@gmail.com>

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

^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: FAILED: patch "[PATCH] Introduce cifs_copy_file_range()" failed to apply to 4.10-stable tree
  2017-04-10 14:21 FAILED: patch "[PATCH] Introduce cifs_copy_file_range()" failed to apply to 4.10-stable tree gregkh
@ 2017-04-10 14:23 ` Sachin Prabhu
  0 siblings, 0 replies; 2+ messages in thread
From: Sachin Prabhu @ 2017-04-10 14:23 UTC (permalink / raw)
  To: gregkh, pshilov, smfrench, stable

On Mon, 2017-04-10 at 16:21 +0200, gregkh@linuxfoundation.org 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@vger.kernel.org>.
> 
> 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@redhat.com>
> 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@redhat.com>
> Reviewed-by: Pavel Shilovsky <pshilov@microsoft.com>
> CC: Stable  <stable@vger.kernel.org>
> Signed-off-by: Steve French <smfrench@gmail.com>
> 
> 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
> 

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2017-04-10 14:23 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-04-10 14:21 FAILED: patch "[PATCH] Introduce cifs_copy_file_range()" failed to apply to 4.10-stable tree gregkh
2017-04-10 14:23 ` Sachin Prabhu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).