FAILED: patch "[PATCH] Introduce cifs_copy_file_range()" failed to apply to 4.9-stable tree
[email protected]
maintainerThe patch below does not apply to the 4.9-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 <[email protected]>.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
Quoted 1 line
From
620d8745b35daaf507186c26b40c7ea02aed131eMon Sep 17 00:00:00 2001
From: Sachin Prabhu <[email protected]>
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.
fs/cifs/cifsfs.c +87 -0
@@ -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, };
fs/cifs/cifsfs.h +5 -0
@@ -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;
fs/cifs/cifsglob.h +3 -3
@@ -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);
fs/cifs/ioctl.c +2 -58
72 lines not on this page · raw message
fs/cifs/smb2ops.c +13 -7
@@ -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