From patchwork Sat Nov 16 07:14:19 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steve French X-Patchwork-Id: 3192341 Return-Path: X-Original-To: patchwork-cifs-client@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 1AF449F3AE for ; Sat, 16 Nov 2013 07:14:27 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 1A92A208F8 for ; Sat, 16 Nov 2013 07:14:26 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 09D70208B2 for ; Sat, 16 Nov 2013 07:14:25 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751237Ab3KPHOU (ORCPT ); Sat, 16 Nov 2013 02:14:20 -0500 Received: from mail-pd0-f177.google.com ([209.85.192.177]:62448 "EHLO mail-pd0-f177.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751208Ab3KPHOU (ORCPT ); Sat, 16 Nov 2013 02:14:20 -0500 Received: by mail-pd0-f177.google.com with SMTP id v10so4366724pde.36 for ; Fri, 15 Nov 2013 23:14:19 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:date:message-id:subject:from:to:content-type; bh=FROHjt2PixVMoMsv34o1hVC1SZHMgfqNf1byhkZTeZQ=; b=rHs3gJ9rlccMuQ+DgFOlucei84RHrukGYr5jERkGTiW1vZPBnEX39gJp60LUwZMSwW 9WPHYay0VcWC5wMglcECQCIpkJiwr0VMXSlmXSglHjHJ/L3PMFEv8zLPu9TJXETWKR1p A5eIzzupqEhXFBD4qOsny//FwRyou7kFXPeXRsD4Rs1+2SLVsDu5Y8Rk+JjTHcmbwk/J kIiPuF6Y5ji+HO7HZf+nJlsXMxA7KJX8PgLONmxm/0/+kf9R6cn+xChNfLS47SMW62BE Zu12iyB5W4J0QLl6tBmhzBaDgU2xmxck+dK0iZ/MRx+Puh9+dJOv3EeIs1hE9H+cE3an pCZg== MIME-Version: 1.0 X-Received: by 10.66.139.8 with SMTP id qu8mr10157531pab.157.1384586059290; Fri, 15 Nov 2013 23:14:19 -0800 (PST) Received: by 10.68.143.10 with HTTP; Fri, 15 Nov 2013 23:14:19 -0800 (PST) Date: Sat, 16 Nov 2013 01:14:19 -0600 Message-ID: Subject: [PATCH][CIFS] SMB2/SMB3 Copy offload support (refcopy) finishup From: Steve French To: "linux-cifs@vger.kernel.org" , David Disseldorp , samba-technical Sender: linux-cifs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org X-Spam-Status: No, score=-6.8 required=5.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, T_DKIM_INVALID, T_TVD_MIME_EPI,UNPARSEABLE_RELAY autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From 6474d967fc8228fff7579748f7219f6a8e443f30 Mon Sep 17 00:00:00 2001 From: Steve French Date: Sat, 16 Nov 2013 01:06:00 -0600 Subject: [PATCH] CIFS: SMB2/SMB3 Copy offload support (refcopy) finish up This patch extends the ability of copychunk (refcopy) to handle servers with smaller than usual maximum chunk sizes and also to handle files bigger than the maximum chunk sizes Signed-off-by: Steve French --- fs/cifs/smb2ops.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++------- fs/cifs/smb2pdu.c | 2 +- 2 files changed, 79 insertions(+), 12 deletions(-) goto ioctl_exit; From 6474d967fc8228fff7579748f7219f6a8e443f30 Mon Sep 17 00:00:00 2001 From: Steve French Date: Sat, 16 Nov 2013 01:06:00 -0600 Subject: [PATCH] CIFS: SMB2/SMB3 Copy offload support (refcopy) finish up This patch extends the ability of copychunk (refcopy) to handle servers with smaller than usual maximum chunk sizes and also to handle files bigger than the maximum chunk sizes Signed-off-by: Steve French --- fs/cifs/smb2ops.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++------- fs/cifs/smb2pdu.c | 2 +- 2 files changed, 79 insertions(+), 12 deletions(-) diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 11dde4b..7a21447 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -532,7 +532,10 @@ smb2_clone_range(const unsigned int xid, int rc; unsigned int ret_data_len; struct copychunk_ioctl *pcchunk; - char *retbuf = NULL; + struct copychunk_ioctl_rsp *retbuf = NULL; + struct cifs_tcon *tcon; + int chunks_copied = 0; + bool chunk_sizes_updated = false; pcchunk = kmalloc(sizeof(struct copychunk_ioctl), GFP_KERNEL); @@ -552,22 +555,86 @@ smb2_clone_range(const unsigned int xid, /* For now array only one chunk long, will make more flexible later */ pcchunk->ChunkCount = __constant_cpu_to_le32(1); pcchunk->Reserved = 0; - pcchunk->SourceOffset = cpu_to_le64(src_off); - pcchunk->TargetOffset = cpu_to_le64(dest_off); - pcchunk->Length = cpu_to_le32(len); pcchunk->Reserved2 = 0; + tcon = tlink_tcon(trgtfile->tlink); + + while (len > 0) { + pcchunk->SourceOffset = cpu_to_le64(src_off); + pcchunk->TargetOffset = cpu_to_le64(dest_off); + pcchunk->Length = + cpu_to_le32(min_t(u32, len, tcon->max_bytes_chunk)); + /* Request that server copy to target from src file identified by key */ - rc = SMB2_ioctl(xid, tlink_tcon(trgtfile->tlink), - trgtfile->fid.persistent_fid, + rc = SMB2_ioctl(xid, tcon, trgtfile->fid.persistent_fid, trgtfile->fid.volatile_fid, FSCTL_SRV_COPYCHUNK_WRITE, true /* is_fsctl */, (char *)pcchunk, - sizeof(struct copychunk_ioctl), &retbuf, &ret_data_len); - - /* BB need to special case rc = EINVAL to alter chunk size */ - - cifs_dbg(FYI, "rc %d data length out %d\n", rc, ret_data_len); + sizeof(struct copychunk_ioctl), (char **)&retbuf, + &ret_data_len); + if (rc == 0) { + if (ret_data_len != sizeof(struct copychunk_ioctl_rsp)) + goto cchunk_out; + if (retbuf->TotalBytesWritten == 0) { + cifs_dbg(FYI, "no bytes copied\n"); + goto cchunk_out; + } + /* + * Check if server claimed to write more than we asked + */ + if (le32_to_cpu(retbuf->TotalBytesWritten) > + le32_to_cpu(pcchunk->Length)) { + cifs_dbg(VFS, "invalid copy chunk response\n"); + rc = -EIO; + goto cchunk_out; + } + if (le32_to_cpu(retbuf->ChunksWritten) != 1) { + cifs_dbg(VFS, "invalid num chunks written\n"); + rc = -EIO; + goto cchunk_out; + } + chunks_copied++; + + src_off += le32_to_cpu(retbuf->TotalBytesWritten); + dest_off += le32_to_cpu(retbuf->TotalBytesWritten); + len -= le32_to_cpu(retbuf->TotalBytesWritten); + + cifs_dbg(FYI, "Chunks %d PartialChunk %d Total %d\n", + le32_to_cpu(retbuf->ChunksWritten), + le32_to_cpu(retbuf->ChunkBytesWritten), + le32_to_cpu(retbuf->TotalBytesWritten)); + } else if (rc == -EINVAL) { + if (ret_data_len != sizeof(struct copychunk_ioctl_rsp)) + goto cchunk_out; + + cifs_dbg(FYI, "MaxChunks %d BytesChunk %d MaxCopy %d\n", + le32_to_cpu(retbuf->ChunksWritten), + le32_to_cpu(retbuf->ChunkBytesWritten), + le32_to_cpu(retbuf->TotalBytesWritten)); + + /* + * Check if this is the first request using these sizes, + * (ie check if copy succeed once with original sizes + * and check if the server gave us different sizes after + * we already updated max sizes on previous request). + * if not then why is the server returning an error now + */ + if ((chunks_copied != 0) || chunk_sizes_updated) + goto cchunk_out; + + /* Check that server is not asking us to grow size */ + if (le32_to_cpu(retbuf->ChunkBytesWritten) < + tcon->max_bytes_chunk) + tcon->max_bytes_chunk = + le32_to_cpu(retbuf->ChunkBytesWritten); + else + goto cchunk_out; /* server gave us bogus size */ + + /* No need to change MaxChunks since already set to 1 */ + chunk_sizes_updated = true; + } + } +cchunk_out: kfree(pcchunk); return rc; } diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index d65270c..c5915dc 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -1214,7 +1214,7 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, rc = SendReceive2(xid, ses, iov, num_iovecs, &resp_buftype, 0); rsp = (struct smb2_ioctl_rsp *)iov[0].iov_base; - if (rc != 0) { + if ((rc != 0) && (rc != -EINVAL)) { if (tcon) cifs_stats_fail_inc(tcon, SMB2_IOCTL_HE); goto ioctl_exit; -- 1.8.3.1