From: Sachin Prabhu <sprabhu@redhat.com>
To: gregkh@linuxfoundation.org, pshilov@microsoft.com,
smfrench@gmail.com, stable@vger.kernel.org
Subject: Re: FAILED: patch "[PATCH] Introduce cifs_copy_file_range()" failed to apply to 4.10-stable tree
Date: Mon, 10 Apr 2017 15:23:56 +0100 [thread overview]
Message-ID: <1491834236.8507.1.camel@redhat.com> (raw)
In-Reply-To: <149183407518197@kroah.com>
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
>
prev parent reply other threads:[~2017-04-10 14:23 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
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 message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1491834236.8507.1.camel@redhat.com \
--to=sprabhu@redhat.com \
--cc=gregkh@linuxfoundation.org \
--cc=pshilov@microsoft.com \
--cc=smfrench@gmail.com \
--cc=stable@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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).