[PATCH] Fix bug 9412 - SMB2 server doesn't support recvfile.
Stefan (metze) Metzmacher
metze at samba.org
Fri Apr 5 01:20:08 MDT 2013
Hi Jeremy,
>> I think we should add some protection to req->sconn->smb2.recv_queue,
>> when we do a short read we should place a dummy tevent_req into the
>> recv_queue,
>> which blocks the socket, and remove it when the socket is drained or
>> recvfile is done.
>>
>> next to smb1req->unread_bytes we could setup smb2req->recvfile_blocker;
>>
>> struct smbd_smb2_recvfile_blocker {
>> uint8_t dummy;
>> };
>>
>> static void smbd_smb2_recvfile_blocker_trigger(struct tevent_req *req,
>> void *private_data)
>> {
>> return;
>> }
>>
>> ...
>> struct smbd_smb2_recvfile_blocker *recvfile_blocker;
>> smb2req->recvfile_blocker = tevent_req_create(smb2req, &recvfile_blocker,
>> smbd_smb2_recvfile_blocker);
>> if (smb2req->recvfile_blocker == NULL) {
>> ...
>> }
>> ok = tevent_queue_add(smb2req->sconn->smb2.recv_queue,
>> ...event_context,
>> smb2req->recvfile_blocker,
>> smbd_smb2_recvfile_blocker_trigger,
>> NULL);
>>
>> smbd_smb2_request_error_ex() would then also do
>> TALLOC_FREE(smb2req->recvfile_blocker);
>> after drain_socket() and even if unread_bytes was 0.
>
> Ok, I see the paranoia behind doing it :-), but is it really
> neccessary ? Under what circumstances would we need this ?
>
> The SMB1 recvfile code doesn't do this, and if the stream
> gets out of sync it's really obvious immediately.
The whole SMB2 socket handling is different from the SMB1 one,
the SMB2 code is a lot more async and the socket is non-blocking.
Maybe we could let smbd_smb2_request_read_done() keep 'subreq'
if state->doing_receivefile is true, we need to remember this
in smb2req.
As the socket is non-blocking, we need to make sure recvfile()
doesn't get EAGAIN. We could extent the tstream_readv_pdu code
to handle an iovec with iov_len != 0 and iov_base == NULL.
This could be used to wait until the whole request arrived
in the kernel, by checking tstream_pending_bytes().
Or we have to mark the socket blocking during for recvfile() and
drain_socket().
>>> + } else {
>>> + /*
>>> + * Either this is a receivefile write so we've
>>> + * done a short read, or if not we have all the data.
>>> + * Either way, we're done and the caller will handle
>>> + * and short read case by looking at the
>>> + * state->doing_receivefile value.
>>> + */
>>> + *_vector = NULL;
>>> + *_count = 0;
>>> + }
>>
>> Shouldn't the caller take a look at smb1req->unread_bytes?
>> state->doing_receivefile is not visible to the caller.
>
> smb1req->unread_bytes isn't set up until all the
> smbd_smb2_request_next_vector() calls are finished,
> and smbd_smb2_request_read_done() is called.
>
> smbd_smb2_request_read_done() has full access to
> struct smbd_smb2_request_read_state *state
> and so uses state->doing_receivefile to then set
> up smb1req->unread_bytes.
>
> I guess I don't fully understand the comment here.
> state->doing_receivefile is a temporary state whilst
> we're deciding if we can do a recvfile, and the permanent
> state that tells the callers that we are doing a
> recveivefile is smb1req->unread_bytes.
Maybe you can change "caller" into "caller (smbd_smb2_request_read_done)".
From just reading the comment it was not clear to me what 'caller' was
referring to.
BTW: I just found the attached patch in one of my branches again,
which should improve the splice recvfile implementation.
But with this junkcode test:
https://gitweb.samba.org/?p=metze/misc/junkcode.git;a=commitdiff;h=43121900e96a0f779e110ed162c1db766eace4e6
https://gitweb.samba.org/?p=metze/misc/junkcode.git;a=blob;f=splice/splice2.c
I'm getting this on my thinkpad x230
metze at SERNOX11:~/devel/junkcode/metze/splice$ time ./splice2 'rw'
104857600000 65536
rw: i[1600000] total_size[104857600000] buffer_size[65536 => 65536]
real 0m5.545s
user 0m0.100s
sys 0m5.420s
metze at SERNOX11:~/devel/junkcode/metze/splice$ time ./splice2 'splice'
104857600000 65536
splice: i[1600000] total_size[104857600000] buffer_size[65536 => 65536]
real 0m10.455s
user 0m0.072s
sys 0m10.301s
metze at SERNOX11:~/devel/junkcode/metze/splice$ time ./splice2 'splice'
104857600000 1048576
splice: i[100000] total_size[104857600000] buffer_size[1048576 => 1048576]
real 0m10.673s
user 0m0.004s
sys 0m10.613s
metze at SERNOX11:~/devel/junkcode/metze/splice$ time ./splice2 'rw'
104857600000 1048576
rw: i[100000] total_size[104857600000] buffer_size[1048576 => 1048576]
real 0m5.779s
user 0m0.000s
sys 0m5.752s
metze at SERNOX11:~/devel/junkcode/metze/splice$ time ./splice2 'rw'
104857600000 10485760
rw: i[10000] total_size[104857600000] buffer_size[10485760 => 10485760]
real 0m11.966s
user 0m0.000s
sys 0m11.909s
The results are really look strange to me...
metze
-------------- next part --------------
A non-text attachment was scrubbed...
Name: tmp.diff
Type: text/x-diff
Size: 1621 bytes
Desc: not available
URL: <http://lists.samba.org/pipermail/samba-technical/attachments/20130405/999cec4a/attachment.diff>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 261 bytes
Desc: OpenPGP digital signature
URL: <http://lists.samba.org/pipermail/samba-technical/attachments/20130405/999cec4a/attachment.pgp>
More information about the samba-technical
mailing list