aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/smb2ops.c
diff options
context:
space:
mode:
authorSteve French <smfrench@gmail.com>2013-11-14 01:05:36 -0500
committerSteve French <smfrench@gmail.com>2013-11-14 01:05:36 -0500
commit41c1358e9181ab1ebd773905b3fa8039b61aa0e9 (patch)
tree144d08d6758ac33212c200421a973120910c6fc8 /fs/cifs/smb2ops.c
parent2c957ddf30897787e39462ac56cdc4bf21eb0465 (diff)
CIFS: SMB2/SMB3 Copy offload support (refcopy) phase 1
This first patch adds the ability for us to do a server side copy (ie fast copy offloaded to the server to perform, aka refcopy) "cp --reflink" of one file to another located on the same server. This is much faster than traditional copy (which requires reading and writing over the network and extra memcpys). This first version is not going to be copy files larger than about 1MB (to Samba) until I add support for multiple chunks and for autoconfiguring the chunksize. It includes: 1) processing of the ioctl 2) marshalling and sending the SMB2/SMB3 fsctl over the network 3) simple parsing of the response It does not include yet (these will be in followon patches to come soon): 1) support for multiple chunks 2) support for autoconfiguring and remembering the chunksize 3) Support for the older style copychunk which Samba 4.1 server supports (because this requires write permission on the target file, which cp does not give you, apparently per-posix). This may require a distinct tool (other than cp) and other ioctl to implement. Reviewed-by: Pavel Shilovsky <piastry@etersoft.ru> Signed-off-by: Steve French <smfrench@gmail.com>
Diffstat (limited to 'fs/cifs/smb2ops.c')
-rw-r--r--fs/cifs/smb2ops.c82
1 files changed, 82 insertions, 0 deletions
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index c571be8cb76e..11dde4b24f8a 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -494,6 +494,85 @@ smb2_close_file(const unsigned int xid, struct cifs_tcon *tcon,
494} 494}
495 495
496static int 496static int
497SMB2_request_res_key(const unsigned int xid, struct cifs_tcon *tcon,
498 u64 persistent_fid, u64 volatile_fid,
499 struct copychunk_ioctl *pcchunk)
500{
501 int rc;
502 unsigned int ret_data_len;
503 struct resume_key_req *res_key;
504
505 rc = SMB2_ioctl(xid, tcon, persistent_fid, volatile_fid,
506 FSCTL_SRV_REQUEST_RESUME_KEY, true /* is_fsctl */,
507 NULL, 0 /* no input */,
508 (char **)&res_key, &ret_data_len);
509
510 if (rc) {
511 cifs_dbg(VFS, "refcpy ioctl error %d getting resume key\n", rc);
512 goto req_res_key_exit;
513 }
514 if (ret_data_len < sizeof(struct resume_key_req)) {
515 cifs_dbg(VFS, "Invalid refcopy resume key length\n");
516 rc = -EINVAL;
517 goto req_res_key_exit;
518 }
519 memcpy(pcchunk->SourceKey, res_key->ResumeKey, COPY_CHUNK_RES_KEY_SIZE);
520
521req_res_key_exit:
522 kfree(res_key);
523 return rc;
524}
525
526static int
527smb2_clone_range(const unsigned int xid,
528 struct cifsFileInfo *srcfile,
529 struct cifsFileInfo *trgtfile, u64 src_off,
530 u64 len, u64 dest_off)
531{
532 int rc;
533 unsigned int ret_data_len;
534 struct copychunk_ioctl *pcchunk;
535 char *retbuf = NULL;
536
537 pcchunk = kmalloc(sizeof(struct copychunk_ioctl), GFP_KERNEL);
538
539 if (pcchunk == NULL)
540 return -ENOMEM;
541
542 cifs_dbg(FYI, "in smb2_clone_range - about to call request res key\n");
543 /* Request a key from the server to identify the source of the copy */
544 rc = SMB2_request_res_key(xid, tlink_tcon(srcfile->tlink),
545 srcfile->fid.persistent_fid,
546 srcfile->fid.volatile_fid, pcchunk);
547
548 /* Note: request_res_key sets res_key null only if rc !=0 */
549 if (rc)
550 return rc;
551
552 /* For now array only one chunk long, will make more flexible later */
553 pcchunk->ChunkCount = __constant_cpu_to_le32(1);
554 pcchunk->Reserved = 0;
555 pcchunk->SourceOffset = cpu_to_le64(src_off);
556 pcchunk->TargetOffset = cpu_to_le64(dest_off);
557 pcchunk->Length = cpu_to_le32(len);
558 pcchunk->Reserved2 = 0;
559
560 /* Request that server copy to target from src file identified by key */
561 rc = SMB2_ioctl(xid, tlink_tcon(trgtfile->tlink),
562 trgtfile->fid.persistent_fid,
563 trgtfile->fid.volatile_fid, FSCTL_SRV_COPYCHUNK_WRITE,
564 true /* is_fsctl */, (char *)pcchunk,
565 sizeof(struct copychunk_ioctl), &retbuf, &ret_data_len);
566
567 /* BB need to special case rc = EINVAL to alter chunk size */
568
569 cifs_dbg(FYI, "rc %d data length out %d\n", rc, ret_data_len);
570
571 kfree(pcchunk);
572 return rc;
573}
574
575static int
497smb2_flush_file(const unsigned int xid, struct cifs_tcon *tcon, 576smb2_flush_file(const unsigned int xid, struct cifs_tcon *tcon,
498 struct cifs_fid *fid) 577 struct cifs_fid *fid)
499{ 578{
@@ -1017,6 +1096,7 @@ struct smb_version_operations smb20_operations = {
1017 .set_oplock_level = smb2_set_oplock_level, 1096 .set_oplock_level = smb2_set_oplock_level,
1018 .create_lease_buf = smb2_create_lease_buf, 1097 .create_lease_buf = smb2_create_lease_buf,
1019 .parse_lease_buf = smb2_parse_lease_buf, 1098 .parse_lease_buf = smb2_parse_lease_buf,
1099 .clone_range = smb2_clone_range,
1020}; 1100};
1021 1101
1022struct smb_version_operations smb21_operations = { 1102struct smb_version_operations smb21_operations = {
@@ -1090,6 +1170,7 @@ struct smb_version_operations smb21_operations = {
1090 .set_oplock_level = smb21_set_oplock_level, 1170 .set_oplock_level = smb21_set_oplock_level,
1091 .create_lease_buf = smb2_create_lease_buf, 1171 .create_lease_buf = smb2_create_lease_buf,
1092 .parse_lease_buf = smb2_parse_lease_buf, 1172 .parse_lease_buf = smb2_parse_lease_buf,
1173 .clone_range = smb2_clone_range,
1093}; 1174};
1094 1175
1095struct smb_version_operations smb30_operations = { 1176struct smb_version_operations smb30_operations = {
@@ -1165,6 +1246,7 @@ struct smb_version_operations smb30_operations = {
1165 .set_oplock_level = smb3_set_oplock_level, 1246 .set_oplock_level = smb3_set_oplock_level,
1166 .create_lease_buf = smb3_create_lease_buf, 1247 .create_lease_buf = smb3_create_lease_buf,
1167 .parse_lease_buf = smb3_parse_lease_buf, 1248 .parse_lease_buf = smb3_parse_lease_buf,
1249 .clone_range = smb2_clone_range,
1168}; 1250};
1169 1251
1170struct smb_version_values smb20_values = { 1252struct smb_version_values smb20_values = {