cifsd: add support for FSCTL_DUPLICATE_EXTENTS_TO_FILE
authorNamjae Jeon <namjae.jeon@samsung.com>
Tue, 18 May 2021 01:37:59 +0000 (10:37 +0900)
committerNamjae Jeon <namjae.jeon@samsung.com>
Tue, 18 May 2021 01:38:41 +0000 (10:38 +0900)
Add support for FSCTL_DUPLICATE_EXTENTS_TO_FILE in smb2 ioctl.

Reviewed-by: Hyunchul Lee <hyc.lee@gmail.com>
Signed-off-by: Namjae Jeon <namjae.jeon@samsung.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
fs/cifsd/smb2pdu.c
fs/cifsd/smb2pdu.h
fs/cifsd/smbfsctl.h
fs/cifsd/vfs.c
fs/cifsd/vfs.h

index 3fd266a..e5d3a57 100644 (file)
@@ -4622,7 +4622,8 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work,
                                               FILE_PERSISTENT_ACLS |
                                               FILE_UNICODE_ON_DISK |
                                               FILE_CASE_PRESERVED_NAMES |
-                                              FILE_CASE_SENSITIVE_SEARCH);
+                                              FILE_CASE_SENSITIVE_SEARCH |
+                                              FILE_SUPPORTS_BLOCK_REFCOUNTING);
 
                info->Attributes |= cpu_to_le32(server_conf.share_fake_fscaps);
 
@@ -7330,6 +7331,55 @@ int smb2_ioctl(struct ksmbd_work *work)
                nbytes = sizeof(struct reparse_data_buffer);
                break;
        }
+       case FSCTL_DUPLICATE_EXTENTS_TO_FILE:
+       {
+               struct ksmbd_file *fp_in, *fp_out = NULL;
+               struct duplicate_extents_to_file *dup_ext;
+               loff_t src_off, dst_off, length, cloned;
+
+               dup_ext = (struct duplicate_extents_to_file *)&req->Buffer[0];
+
+               fp_in = ksmbd_lookup_fd_slow(work, dup_ext->VolatileFileHandle,
+                               dup_ext->PersistentFileHandle);
+               if (!fp_in) {
+                       ksmbd_err("not found file handle in duplicate extent to file\n");
+                       ret = -ENOENT;
+                       goto out;
+               }
+
+               fp_out = ksmbd_lookup_fd_fast(work, id);
+               if (!fp_out) {
+                       ksmbd_err("not found fp\n");
+                       ret = -ENOENT;
+                       goto dup_ext_out;
+               }
+
+               src_off = le64_to_cpu(dup_ext->SourceFileOffset);
+               dst_off = le64_to_cpu(dup_ext->TargetFileOffset);
+               length = le64_to_cpu(dup_ext->ByteCount);
+               cloned = vfs_clone_file_range(fp_in->filp, src_off, fp_out->filp,
+                               dst_off, length, 0);
+               if (cloned == -EXDEV || cloned == -EOPNOTSUPP) {
+                       ret = -EOPNOTSUPP;
+                       goto dup_ext_out;
+               } else if (cloned != length) {
+                       cloned = ksmbd_vfs_copy_file_range(fp_in->filp, src_off,
+                                       fp_out->filp, dst_off, length);
+                       if (cloned != length) {
+                               if (cloned < 0)
+                                       ret = cloned;
+                               else
+                                       ret = -EINVAL;
+                       }
+               }
+
+dup_ext_out:
+               ksmbd_fd_put(work, fp_in);
+               ksmbd_fd_put(work, fp_out);
+               if (ret < 0)
+                       goto out;
+               break;
+       }
        default:
                ksmbd_debug(SMB, "not implemented yet ioctl command 0x%x\n",
                                cnt_code);
index c5c3261..1a8da21 100644 (file)
@@ -851,6 +851,14 @@ struct smb2_write_rsp {
 
 #define SMB2_0_IOCTL_IS_FSCTL 0x00000001
 
+struct duplicate_extents_to_file {
+       __u64 PersistentFileHandle; /* source file handle, opaque endianness */
+       __u64 VolatileFileHandle;
+       __le64 SourceFileOffset;
+       __le64 TargetFileOffset;
+       __le64 ByteCount;  /* Bytes to be copied */
+} __packed;
+
 struct smb2_ioctl_req {
        struct smb2_hdr hdr;
        __le16 StructureSize; /* Must be 57 */
index 908c4e6..b98418a 100644 (file)
@@ -64,6 +64,7 @@
 #define FSCTL_SET_SHORT_NAME_BEHAVIOR 0x000901B4 /* BB add struct */
 #define FSCTL_QUERY_ALLOCATED_RANGES 0x000940CF /* BB add struct */
 #define FSCTL_SET_DEFECT_MANAGEMENT  0x00098134 /* BB add struct */
+#define FSCTL_DUPLICATE_EXTENTS_TO_FILE 0x00098344
 #define FSCTL_SIS_LINK_FILES         0x0009C104
 #define FSCTL_PIPE_PEEK              0x0011400C /* BB add struct */
 #define FSCTL_PIPE_TRANSCEIVE        0x0011C017 /* BB add struct */
index 29f31db..cdbb844 100644 (file)
@@ -1789,7 +1789,7 @@ int ksmbd_vfs_xattr_stream_name(char *stream_name, char **xattr_stream_name,
        return 0;
 }
 
-static int ksmbd_vfs_copy_file_range(struct file *file_in, loff_t pos_in,
+int ksmbd_vfs_copy_file_range(struct file *file_in, loff_t pos_in,
                struct file *file_out, loff_t pos_out, size_t len)
 {
        struct inode *inode_in = file_inode(file_in);
index 0163be4..2d19e2b 100644 (file)
@@ -218,7 +218,8 @@ int ksmbd_vfs_copy_file_ranges(struct ksmbd_work *work,
                struct srv_copychunk *chunks, unsigned int chunk_count,
                unsigned int *chunk_count_written,
                unsigned int *chunk_size_written, loff_t  *total_size_written);
-
+int ksmbd_vfs_copy_file_range(struct file *file_in, loff_t pos_in,
+               struct file *file_out, loff_t pos_out, size_t len);
 ssize_t ksmbd_vfs_listxattr(struct dentry *dentry, char **list);
 ssize_t ksmbd_vfs_getxattr(struct dentry *dentry, char *xattr_name,
                char **xattr_buf);