aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/cifsfs.c
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2015-12-03 06:59:50 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2015-12-07 23:11:33 -0500
commit04b38d601239b4d9be641b412cf4b7456a041c67 (patch)
tree196b5fa72848de2a98e09af86099d99da70f2833 /fs/cifs/cifsfs.c
parentacc15575e78e534c12549d8057a692f490a50f61 (diff)
vfs: pull btrfs clone API to vfs layer
The btrfs clone ioctls are now adopted by other file systems, with NFS and CIFS already having support for them, and XFS being under active development. To avoid growth of various slightly incompatible implementations, add one to the VFS. Note that clones are different from file copies in several ways: - they are atomic vs other writers - they support whole file clones - they support 64-bit legth clones - they do not allow partial success (aka short writes) - clones are expected to be a fast metadata operation Because of that it would be rather cumbersome to try to piggyback them on top of the recent clone_file_range infrastructure. The converse isn't true and the clone_file_range system call could try clone file range as a first attempt to copy, something that further patches will enable. Based on earlier work from Peng Tao. Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/cifs/cifsfs.c')
-rw-r--r--fs/cifs/cifsfs.c63
1 files changed, 63 insertions, 0 deletions
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index cbc0f4bca0c0..e9b978f2e114 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -914,6 +914,61 @@ const struct inode_operations cifs_symlink_inode_ops = {
914#endif 914#endif
915}; 915};
916 916
917static int cifs_clone_file_range(struct file *src_file, loff_t off,
918 struct file *dst_file, loff_t destoff, u64 len)
919{
920 struct inode *src_inode = file_inode(src_file);
921 struct inode *target_inode = file_inode(dst_file);
922 struct cifsFileInfo *smb_file_src = src_file->private_data;
923 struct cifsFileInfo *smb_file_target = dst_file->private_data;
924 struct cifs_tcon *src_tcon = tlink_tcon(smb_file_src->tlink);
925 struct cifs_tcon *target_tcon = tlink_tcon(smb_file_target->tlink);
926 unsigned int xid;
927 int rc;
928
929 cifs_dbg(FYI, "clone range\n");
930
931 xid = get_xid();
932
933 if (!src_file->private_data || !dst_file->private_data) {
934 rc = -EBADF;
935 cifs_dbg(VFS, "missing cifsFileInfo on copy range src file\n");
936 goto out;
937 }
938
939 /*
940 * Note: cifs case is easier than btrfs since server responsible for
941 * checks for proper open modes and file type and if it wants
942 * server could even support copy of range where source = target
943 */
944 lock_two_nondirectories(target_inode, src_inode);
945
946 if (len == 0)
947 len = src_inode->i_size - off;
948
949 cifs_dbg(FYI, "about to flush pages\n");
950 /* should we flush first and last page first */
951 truncate_inode_pages_range(&target_inode->i_data, destoff,
952 PAGE_CACHE_ALIGN(destoff + len)-1);
953
954 if (target_tcon->ses->server->ops->duplicate_extents)
955 rc = target_tcon->ses->server->ops->duplicate_extents(xid,
956 smb_file_src, smb_file_target, off, len, destoff);
957 else
958 rc = -EOPNOTSUPP;
959
960 /* force revalidate of size and timestamps of target file now
961 that target is updated on the server */
962 CIFS_I(target_inode)->time = 0;
963out_unlock:
964 /* although unlocking in the reverse order from locking is not
965 strictly necessary here it is a little cleaner to be consistent */
966 unlock_two_nondirectories(src_inode, target_inode);
967out:
968 free_xid(xid);
969 return rc;
970}
971
917const struct file_operations cifs_file_ops = { 972const struct file_operations cifs_file_ops = {
918 .read_iter = cifs_loose_read_iter, 973 .read_iter = cifs_loose_read_iter,
919 .write_iter = cifs_file_write_iter, 974 .write_iter = cifs_file_write_iter,
@@ -926,6 +981,7 @@ const struct file_operations cifs_file_ops = {
926 .splice_read = generic_file_splice_read, 981 .splice_read = generic_file_splice_read,
927 .llseek = cifs_llseek, 982 .llseek = cifs_llseek,
928 .unlocked_ioctl = cifs_ioctl, 983 .unlocked_ioctl = cifs_ioctl,
984 .clone_file_range = cifs_clone_file_range,
929 .setlease = cifs_setlease, 985 .setlease = cifs_setlease,
930 .fallocate = cifs_fallocate, 986 .fallocate = cifs_fallocate,
931}; 987};
@@ -942,6 +998,8 @@ const struct file_operations cifs_file_strict_ops = {
942 .splice_read = generic_file_splice_read, 998 .splice_read = generic_file_splice_read,
943 .llseek = cifs_llseek, 999 .llseek = cifs_llseek,
944 .unlocked_ioctl = cifs_ioctl, 1000 .unlocked_ioctl = cifs_ioctl,
1001 .clone_file_range = cifs_clone_file_range,
1002 .clone_file_range = cifs_clone_file_range,
945 .setlease = cifs_setlease, 1003 .setlease = cifs_setlease,
946 .fallocate = cifs_fallocate, 1004 .fallocate = cifs_fallocate,
947}; 1005};
@@ -958,6 +1016,7 @@ const struct file_operations cifs_file_direct_ops = {
958 .mmap = cifs_file_mmap, 1016 .mmap = cifs_file_mmap,
959 .splice_read = generic_file_splice_read, 1017 .splice_read = generic_file_splice_read,
960 .unlocked_ioctl = cifs_ioctl, 1018 .unlocked_ioctl = cifs_ioctl,
1019 .clone_file_range = cifs_clone_file_range,
961 .llseek = cifs_llseek, 1020 .llseek = cifs_llseek,
962 .setlease = cifs_setlease, 1021 .setlease = cifs_setlease,
963 .fallocate = cifs_fallocate, 1022 .fallocate = cifs_fallocate,
@@ -974,6 +1033,7 @@ const struct file_operations cifs_file_nobrl_ops = {
974 .splice_read = generic_file_splice_read, 1033 .splice_read = generic_file_splice_read,
975 .llseek = cifs_llseek, 1034 .llseek = cifs_llseek,
976 .unlocked_ioctl = cifs_ioctl, 1035 .unlocked_ioctl = cifs_ioctl,
1036 .clone_file_range = cifs_clone_file_range,
977 .setlease = cifs_setlease, 1037 .setlease = cifs_setlease,
978 .fallocate = cifs_fallocate, 1038 .fallocate = cifs_fallocate,
979}; 1039};
@@ -989,6 +1049,7 @@ const struct file_operations cifs_file_strict_nobrl_ops = {
989 .splice_read = generic_file_splice_read, 1049 .splice_read = generic_file_splice_read,
990 .llseek = cifs_llseek, 1050 .llseek = cifs_llseek,
991 .unlocked_ioctl = cifs_ioctl, 1051 .unlocked_ioctl = cifs_ioctl,
1052 .clone_file_range = cifs_clone_file_range,
992 .setlease = cifs_setlease, 1053 .setlease = cifs_setlease,
993 .fallocate = cifs_fallocate, 1054 .fallocate = cifs_fallocate,
994}; 1055};
@@ -1004,6 +1065,7 @@ const struct file_operations cifs_file_direct_nobrl_ops = {
1004 .mmap = cifs_file_mmap, 1065 .mmap = cifs_file_mmap,
1005 .splice_read = generic_file_splice_read, 1066 .splice_read = generic_file_splice_read,
1006 .unlocked_ioctl = cifs_ioctl, 1067 .unlocked_ioctl = cifs_ioctl,
1068 .clone_file_range = cifs_clone_file_range,
1007 .llseek = cifs_llseek, 1069 .llseek = cifs_llseek,
1008 .setlease = cifs_setlease, 1070 .setlease = cifs_setlease,
1009 .fallocate = cifs_fallocate, 1071 .fallocate = cifs_fallocate,
@@ -1014,6 +1076,7 @@ const struct file_operations cifs_dir_ops = {
1014 .release = cifs_closedir, 1076 .release = cifs_closedir,
1015 .read = generic_read_dir, 1077 .read = generic_read_dir,
1016 .unlocked_ioctl = cifs_ioctl, 1078 .unlocked_ioctl = cifs_ioctl,
1079 .clone_file_range = cifs_clone_file_range,
1017 .llseek = generic_file_llseek, 1080 .llseek = generic_file_llseek,
1018}; 1081};
1019 1082