[PATCH][CIFS] SMB2/SMB3 Copy offload support (refcopy) finishup

David Disseldorp ddiss at suse.de
Sat Nov 16 11:50:53 MST 2013


On Sat, 16 Nov 2013 01:14:19 -0600
Steve French <smfrench at gmail.com> wrote:

>  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,

The SMB2_request_res_key() error path above here should be fixed to free
pcchunk.

>  	/* 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 */

Comment should be indented here too.

> -	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;
> +			}

These two error cases should set rc non-zero, it may not be the last
copy-chunk for this clone.
...

> --- 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)) {

This should probably be FSCTL_SRV_COPYCHUNK[_WRITE] specific. See MS-SMB2
  3.3.4.4   Sending an Error Response
  When the server is responding with a failure to any command sent by the
  client, the response message MUST be constructed as described here. An
  error code other than one of the following indicates a failure:
  ... 

  STATUS_INVALID_PARAMETER in an FSCTL_SRV_COPYCHUNK or
  FSCTL_SRV_COPYCHUNK_WRITE response, when returning an
  SRV_COPYCHUNK_RESPONSE as described in section 3.3.5.15.6.2.


>  		if (tcon)
>  			cifs_stats_fail_inc(tcon, SMB2_IOCTL_HE);
>  		goto ioctl_exit;

Cheers, David


More information about the samba-technical mailing list