The branch, v3-6-test has been updated via 151bea2 s3:smb2_server: keep compound_related on struct smbd_smb2_request via bd377e8 Based on metze's fix for Bug 8407 - SMB2 server can return requests out-of-order when processing a compound request. via 90e4b68 s3:smb2_server: make sure we prefer responses over requests on the client socket from 7d2006c Fix bug 8433, segfault in iconv.c
http://gitweb.samba.org/?p=samba.git;a=shortlog;h=v3-6-test - Log ----------------------------------------------------------------- commit 151bea2cc30f5a3e3cfaafd9e080f0d510f9563e Author: Stefan Metzmacher <me...@samba.org> Date: Thu Aug 25 23:33:41 2011 +0200 s3:smb2_server: keep compound_related on struct smbd_smb2_request metze (cherry picked from commit 0d450d166bab952daf37d922e5c2e5cac16f1cc3) The last 3 patches address bug #8407 (SMB2 server can return requests out-of-order when processing a compound request). commit bd377e89a6bc5fa20485bf9614c06159c9785cdf Author: Jeremy Allison <j...@samba.org> Date: Fri Aug 26 14:23:26 2011 -0700 Based on metze's fix for Bug 8407 - SMB2 server can return requests out-of-order when processing a compound request. (cherry picked from commit 726b4685aa25b0b3b4470bfec5d514fb2db7a95e) commit 90e4b68a3b0e46c238753e66ededa16de3104302 Author: Stefan Metzmacher <me...@samba.org> Date: Fri Aug 5 20:34:43 2011 +0200 s3:smb2_server: make sure we prefer responses over requests on the client socket metze Autobuild-User: Stefan Metzmacher <me...@samba.org> Autobuild-Date: Fri Aug 12 16:46:43 CEST 2011 on sn-devel-104 (cherry picked from commit 42cde0480bd6a5e2dddaa66917e1fa71e6a4edcd) ----------------------------------------------------------------------- Summary of changes: source3/smbd/globals.h | 2 + source3/smbd/smb2_server.c | 107 +++++++++++++++++++++++++++++++++++++------- 2 files changed, 93 insertions(+), 16 deletions(-) Changeset truncated at 500 lines: diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h index 58e03a5..abeaed4 100644 --- a/source3/smbd/globals.h +++ b/source3/smbd/globals.h @@ -358,6 +358,7 @@ struct smbd_smb2_request { bool do_signing; bool async; bool cancelled; + bool compound_related; /* fake smb1 request. */ struct smb_request *smb1req; @@ -601,6 +602,7 @@ struct smbd_server_connection { uint32_t credits_granted; uint32_t max_credits; struct bitmap *credits_bitmap; + bool compound_related_in_progress; } smb2; }; diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c index 0cc80ed..d7a40ed 100644 --- a/source3/smbd/smb2_server.c +++ b/source3/smbd/smb2_server.c @@ -357,7 +357,6 @@ static NTSTATUS smbd_smb2_request_validate(struct smbd_smb2_request *req) { int count; int idx; - bool compound_related = false; count = req->in.vector_count; @@ -405,7 +404,7 @@ static NTSTATUS smbd_smb2_request_validate(struct smbd_smb2_request *req) * compounded requests */ if (flags & SMB2_HDR_FLAG_CHAINED) { - compound_related = true; + req->compound_related = true; } } else if (idx > 4) { #if 0 @@ -418,13 +417,13 @@ static NTSTATUS smbd_smb2_request_validate(struct smbd_smb2_request *req) * all other requests should match the 2nd one */ if (flags & SMB2_HDR_FLAG_CHAINED) { - if (!compound_related) { + if (!req->compound_related) { req->next_status = NT_STATUS_INVALID_PARAMETER; return NT_STATUS_OK; } } else { - if (compound_related) { + if (req->compound_related) { req->next_status = NT_STATUS_INVALID_PARAMETER; return NT_STATUS_OK; @@ -884,6 +883,20 @@ NTSTATUS smbd_smb2_request_pending_queue(struct smbd_smb2_request *req, if (!NT_STATUS_IS_OK(status)) { return status; } + + /* + * We're splitting off the last SMB2 + * request in a compound set, and the + * smb2_send_async_interim_response() + * call above just sent all the replies + * for the previous SMB2 requests in + * this compound set. So we're no longer + * in the "compound_related_in_progress" + * state, and this is no longer a compound + * request. + */ + req->compound_related = false; + req->sconn->smb2.compound_related_in_progress = false; } /* Don't return an intermediate packet on a pipe read/write. */ @@ -1175,6 +1188,10 @@ NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req) req->compat_chain_fsp = NULL; } + if (req->compound_related) { + req->sconn->smb2.compound_related_in_progress = true; + } + switch (opcode) { case SMB2_OP_NEGPROT: /* This call needs to be run as root */ @@ -1621,6 +1638,10 @@ static NTSTATUS smbd_smb2_request_reply(struct smbd_smb2_request *req) return NT_STATUS_OK; } + if (req->compound_related) { + req->sconn->smb2.compound_related_in_progress = false; + } + smb2_setup_nbt_length(req->out.vector, req->out.vector_count); /* Set credit for this operation (zero credits if this @@ -1671,6 +1692,8 @@ static NTSTATUS smbd_smb2_request_reply(struct smbd_smb2_request *req) return NT_STATUS_OK; } +static NTSTATUS smbd_smb2_request_next_incoming(struct smbd_server_connection *sconn); + void smbd_smb2_request_dispatch_immediate(struct tevent_context *ctx, struct tevent_immediate *im, void *private_data) @@ -1693,6 +1716,12 @@ void smbd_smb2_request_dispatch_immediate(struct tevent_context *ctx, smbd_server_connection_terminate(sconn, nt_errstr(status)); return; } + + status = smbd_smb2_request_next_incoming(sconn); + if (!NT_STATUS_IS_OK(status)) { + smbd_server_connection_terminate(sconn, nt_errstr(status)); + return; + } } static void smbd_smb2_request_writev_done(struct tevent_req *subreq) @@ -1702,17 +1731,24 @@ static void smbd_smb2_request_writev_done(struct tevent_req *subreq) struct smbd_server_connection *sconn = req->sconn; int ret; int sys_errno; + NTSTATUS status; ret = tstream_writev_queue_recv(subreq, &sys_errno); TALLOC_FREE(subreq); TALLOC_FREE(req); if (ret == -1) { - NTSTATUS status = map_nt_error_from_unix(sys_errno); + status = map_nt_error_from_unix(sys_errno); DEBUG(2,("smbd_smb2_request_writev_done: client write error %s\n", nt_errstr(status))); smbd_server_connection_terminate(sconn, nt_errstr(status)); return; } + + status = smbd_smb2_request_next_incoming(sconn); + if (!NT_STATUS_IS_OK(status)) { + smbd_server_connection_terminate(sconn, nt_errstr(status)); + return; + } } NTSTATUS smbd_smb2_request_done_ex(struct smbd_smb2_request *req, @@ -2317,12 +2353,55 @@ static NTSTATUS smbd_smb2_request_read_recv(struct tevent_req *req, static void smbd_smb2_request_incoming(struct tevent_req *subreq); +static NTSTATUS smbd_smb2_request_next_incoming(struct smbd_server_connection *sconn) +{ + size_t max_send_queue_len; + size_t cur_send_queue_len; + struct tevent_req *subreq; + + if (sconn->smb2.compound_related_in_progress) { + /* + * Can't read another until the related + * compound is done. + */ + return NT_STATUS_OK; + } + + if (tevent_queue_length(sconn->smb2.recv_queue) > 0) { + /* + * if there is already a smbd_smb2_request_read + * pending, we are done. + */ + return NT_STATUS_OK; + } + + max_send_queue_len = MAX(1, sconn->smb2.max_credits/16); + cur_send_queue_len = tevent_queue_length(sconn->smb2.send_queue); + + if (cur_send_queue_len > max_send_queue_len) { + /* + * if we have a lot of requests to send, + * we wait until they are on the wire until we + * ask for the next request. + */ + return NT_STATUS_OK; + } + + /* ask for the next request */ + subreq = smbd_smb2_request_read_send(sconn, sconn->smb2.event_ctx, sconn); + if (subreq == NULL) { + return NT_STATUS_NO_MEMORY; + } + tevent_req_set_callback(subreq, smbd_smb2_request_incoming, sconn); + + return NT_STATUS_OK; +} + void smbd_smb2_first_negprot(struct smbd_server_connection *sconn, const uint8_t *inbuf, size_t size) { NTSTATUS status; struct smbd_smb2_request *req = NULL; - struct tevent_req *subreq; DEBUG(10,("smbd_smb2_first_negprot: packet length %u\n", (unsigned int)size)); @@ -2351,13 +2430,11 @@ void smbd_smb2_first_negprot(struct smbd_server_connection *sconn, return; } - /* ask for the next request */ - subreq = smbd_smb2_request_read_send(sconn, sconn->smb2.event_ctx, sconn); - if (subreq == NULL) { - smbd_server_connection_terminate(sconn, "no memory for reading"); + status = smbd_smb2_request_next_incoming(sconn); + if (!NT_STATUS_IS_OK(status)) { + smbd_server_connection_terminate(sconn, nt_errstr(status)); return; } - tevent_req_set_callback(subreq, smbd_smb2_request_incoming, sconn); sconn->num_requests++; } @@ -2409,13 +2486,11 @@ static void smbd_smb2_request_incoming(struct tevent_req *subreq) } next: - /* ask for the next request (this constructs the main loop) */ - subreq = smbd_smb2_request_read_send(sconn, sconn->smb2.event_ctx, sconn); - if (subreq == NULL) { - smbd_server_connection_terminate(sconn, "no memory for reading"); + status = smbd_smb2_request_next_incoming(sconn); + if (!NT_STATUS_IS_OK(status)) { + smbd_server_connection_terminate(sconn, nt_errstr(status)); return; } - tevent_req_set_callback(subreq, smbd_smb2_request_incoming, sconn); sconn->num_requests++; -- Samba Shared Repository