summaryrefslogtreecommitdiff
path: root/fs/cifs/ioctl.c
diff options
context:
space:
mode:
authorSachin Prabhu <sprabhu@redhat.com>2017-02-10 13:33:51 +0300
committerSteve French <smfrench@gmail.com>2017-04-07 16:04:41 +0300
commit620d8745b35daaf507186c26b40c7ea02aed131e (patch)
treea634c2ac96c3920c979869e66eb28ff032406a51 /fs/cifs/ioctl.c
parent312bbc5946c4b73dfc1d64c1dd5b0f9df8016587 (diff)
downloadlinux-620d8745b35daaf507186c26b40c7ea02aed131e.tar.xz
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>
Diffstat (limited to 'fs/cifs/ioctl.c')
-rw-r--r--fs/cifs/ioctl.c60
1 files changed, 2 insertions, 58 deletions
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);