The Samba-Bugzilla – Attachment 9494 Details for
Bug 10298
smb2_server processing overhead
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Patches for v4-0-test
tmp40.diff (text/plain), 42.50 KB, created by
Stefan Metzmacher
on 2013-11-29 09:51:47 UTC
(
hide
)
Description:
Patches for v4-0-test
Filename:
MIME Type:
Creator:
Stefan Metzmacher
Created:
2013-11-29 09:51:47 UTC
Size:
42.50 KB
patch
obsolete
>From f1b0ab3f4b2c830af037502a3581090762e6642e Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Mon, 14 Oct 2013 16:42:55 +0200 >Subject: [PATCH 1/6] s3:smb2_server: fix drain_socket error handling > >smbd_smb2_request_error_ex() should return NTSTATUS and the caller >will terminate the connection. > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: David Disseldorp <ddiss@samba.org> >(cherry picked from commit 9393e28df59954414313bfae70ffb796d3e332fe) >--- > source3/smbd/smb2_server.c | 20 +++++++++++++++++--- > 1 file changed, 17 insertions(+), 3 deletions(-) > >diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c >index 525b81b..c3a78d29 100644 >--- a/source3/smbd/smb2_server.c >+++ b/source3/smbd/smb2_server.c >@@ -2644,10 +2644,24 @@ NTSTATUS smbd_smb2_request_error_ex(struct smbd_smb2_request *req, > > if (unread_bytes) { > /* Recvfile error. Drain incoming socket. */ >- size_t ret = drain_socket(req->sconn->sock, unread_bytes); >+ size_t ret; >+ >+ errno = 0; >+ ret = drain_socket(req->sconn->sock, unread_bytes); > if (ret != unread_bytes) { >- smbd_server_connection_terminate(req->sconn, >- "Failed to drain SMB2 socket\n"); >+ NTSTATUS error; >+ >+ if (errno == 0) { >+ error = NT_STATUS_IO_DEVICE_ERROR; >+ } else { >+ error = map_nt_error_from_unix_common(errno); >+ } >+ >+ DEBUG(2, ("Failed to drain %u bytes from SMB2 socket: " >+ "ret[%u] errno[%d] => %s\n", >+ (unsigned)unread_bytes, >+ (unsigned)ret, errno, nt_errstr(error))); >+ return error; > } > } > >-- >1.7.9.5 > > >From 56e461fbd2387cf1b4c288beb7fd91ed8bd5c4b7 Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Mon, 14 Oct 2013 10:33:57 +0200 >Subject: [PATCH 2/6] s3:smb2_server: for performance reasons we use tevent_fd > and readv/writev directly > >Going via tevent_req_create/talloc_free at multiple layer costs >too much cpu cycles per request. > >I tested downloading a 16GB (sparse) file with smbclient -b1 -mNT1, >and -mSMB2_02. Using smb2 max read = 64512, which means smb1 and smb2 >will use the same read size. > >I build with -O3 -g and compared the results with valgrind --tool=callgrind. > >With -mNT1 the server uses about 2.000.000.000 cpu cycles. > >This patch reduces the userspace cpu cycles for -mSMB2_02 >from about ~ 8.000.000.000 down to ~ 4.000.000.000. > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: David Disseldorp <ddiss@samba.org> >(cherry picked from commit 4244a2686cddcdc754c284df884ae497afa4053a) >--- > source3/smbd/globals.h | 28 +- > source3/smbd/smb2_server.c | 812 ++++++++++++++++++++------------------------ > 2 files changed, 402 insertions(+), 438 deletions(-) > >diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h >index c7badbc..b008968 100644 >--- a/source3/smbd/globals.h >+++ b/source3/smbd/globals.h >@@ -466,12 +466,22 @@ NTSTATUS smbXsrv_open_global_traverse( > > NTSTATUS smbXsrv_open_cleanup(uint64_t persistent_id); > >+struct smbd_smb2_send_queue { >+ struct smbd_smb2_send_queue *prev, *next; >+ >+ struct iovec *vector; >+ int count; >+ >+ TALLOC_CTX *mem_ctx; >+}; > > struct smbd_smb2_request { > struct smbd_smb2_request *prev, *next; > > struct smbd_server_connection *sconn; > >+ struct smbd_smb2_send_queue queue_entry; >+ > /* the session the request operates on, maybe NULL */ > struct smbXsrv_session *session; > uint64_t last_session_id; >@@ -739,9 +749,21 @@ struct smbd_server_connection { > } locks; > } smb1; > struct { >- struct tevent_queue *recv_queue; >- struct tevent_queue *send_queue; >- struct tstream_context *stream; >+ struct smbd_smb2_request_read_state { >+ struct smbd_smb2_request *req; >+ struct { >+ uint8_t nbt[NBT_HDR_SIZE]; >+ bool done; >+ } hdr; >+ struct iovec vector; >+ bool doing_receivefile; >+ size_t min_recv_size; >+ size_t pktlen; >+ uint8_t *pktbuf; >+ } request_read_state; >+ struct smbd_smb2_send_queue *send_queue; >+ size_t send_queue_len; >+ struct tevent_fd *fde; > bool negprot_2ff; > struct { > /* The event that makes us process our blocking lock queue */ >diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c >index c3a78d29..bc83b3f 100644 >--- a/source3/smbd/smb2_server.c >+++ b/source3/smbd/smb2_server.c >@@ -30,6 +30,13 @@ > #include "../librpc/gen_ndr/krb5pac.h" > #include "auth.h" > >+static void smbd_smb2_connection_handler(struct tevent_context *ev, >+ struct tevent_fd *fde, >+ uint16_t flags, >+ void *private_data); >+static NTSTATUS smbd_smb2_io_handler(struct smbd_server_connection *sconn, >+ uint16_t fde_flags); >+ > #define OUTVEC_ALLOC_SIZE (SMB2_HDR_BODY + 9) > > static const struct smbd_smb2_dispatch_table { >@@ -196,20 +203,9 @@ bool smbd_is_smb2_header(const uint8_t *inbuf, size_t size) > > static NTSTATUS smbd_initialize_smb2(struct smbd_server_connection *sconn) > { >- NTSTATUS status; >- int ret; >- > TALLOC_FREE(sconn->smb1.fde); > >- sconn->smb2.recv_queue = tevent_queue_create(sconn, "smb2 recv queue"); >- if (sconn->smb2.recv_queue == NULL) { >- return NT_STATUS_NO_MEMORY; >- } >- >- sconn->smb2.send_queue = tevent_queue_create(sconn, "smb2 send queue"); >- if (sconn->smb2.send_queue == NULL) { >- return NT_STATUS_NO_MEMORY; >- } >+ sconn->smb2.send_queue = NULL; > > sconn->smb2.seqnum_low = 0; > sconn->smb2.seqnum_range = 1; >@@ -221,11 +217,14 @@ static NTSTATUS smbd_initialize_smb2(struct smbd_server_connection *sconn) > return NT_STATUS_NO_MEMORY; > } > >- ret = tstream_bsd_existing_socket(sconn, sconn->sock, >- &sconn->smb2.stream); >- if (ret == -1) { >- status = map_nt_error_from_unix(errno); >- return status; >+ sconn->smb2.fde = tevent_add_fd(sconn->ev_ctx, >+ sconn, >+ sconn->sock, >+ TEVENT_FD_READ, >+ smbd_smb2_connection_handler, >+ sconn); >+ if (sconn->smb2.fde == NULL) { >+ return NT_STATUS_NO_MEMORY; > } > > /* Ensure child is set to non-blocking mode */ >@@ -1151,10 +1150,9 @@ static struct smbd_smb2_request *dup_smb2_req(const struct smbd_smb2_request *re > return newreq; > } > >-static void smbd_smb2_request_writev_done(struct tevent_req *subreq); >- > static NTSTATUS smb2_send_async_interim_response(const struct smbd_smb2_request *req) > { >+ struct smbd_server_connection *sconn = req->sconn; > struct smbXsrv_connection *conn = req->sconn->conn; > int first_idx = 1; > struct iovec *firsttf = NULL; >@@ -1218,50 +1216,27 @@ static NTSTATUS smb2_send_async_interim_response(const struct smbd_smb2_request > } > } > >- nreq->subreq = tstream_writev_queue_send(nreq, >- nreq->sconn->ev_ctx, >- nreq->sconn->smb2.stream, >- nreq->sconn->smb2.send_queue, >- nreq->out.vector, >- nreq->out.vector_count); >+ nreq->queue_entry.mem_ctx = nreq; >+ nreq->queue_entry.vector = nreq->out.vector; >+ nreq->queue_entry.count = nreq->out.vector_count; >+ DLIST_ADD_END(nreq->sconn->smb2.send_queue, &nreq->queue_entry, NULL); >+ nreq->sconn->smb2.send_queue_len++; > >- if (nreq->subreq == NULL) { >- return NT_STATUS_NO_MEMORY; >+ status = smbd_smb2_io_handler(sconn, TEVENT_FD_WRITE); >+ if (!NT_STATUS_IS_OK(status)) { >+ return status; > } > >- tevent_req_set_callback(nreq->subreq, >- smbd_smb2_request_writev_done, >- nreq); >- > return NT_STATUS_OK; > } > > struct smbd_smb2_request_pending_state { > struct smbd_server_connection *sconn; >+ struct smbd_smb2_send_queue queue_entry; > uint8_t buf[NBT_HDR_SIZE + SMB2_TF_HDR_SIZE + SMB2_HDR_BODY + 0x08 + 1]; > struct iovec vector[1 + SMBD_SMB2_NUM_IOV_PER_REQ]; > }; > >-static void smbd_smb2_request_pending_writev_done(struct tevent_req *subreq) >-{ >- struct smbd_smb2_request_pending_state *state = >- tevent_req_callback_data(subreq, >- struct smbd_smb2_request_pending_state); >- struct smbd_server_connection *sconn = state->sconn; >- int ret; >- int sys_errno; >- >- ret = tstream_writev_queue_recv(subreq, &sys_errno); >- TALLOC_FREE(subreq); >- if (ret == -1) { >- NTSTATUS status = map_nt_error_from_unix(sys_errno); >- smbd_server_connection_terminate(sconn, nt_errstr(status)); >- return; >- } >- >- TALLOC_FREE(state); >-} >- > static void smbd_smb2_request_pending_timer(struct tevent_context *ev, > struct tevent_timer *te, > struct timeval current_time, >@@ -1393,6 +1368,7 @@ static void smbd_smb2_request_pending_timer(struct tevent_context *ev, > struct smbd_smb2_request *req = > talloc_get_type_abort(private_data, > struct smbd_smb2_request); >+ struct smbd_server_connection *sconn = req->sconn; > struct smbd_smb2_request_pending_state *state = NULL; > uint8_t *outhdr = NULL; > const uint8_t *inhdr = NULL; >@@ -1407,7 +1383,7 @@ static void smbd_smb2_request_pending_timer(struct tevent_context *ev, > uint64_t nonce_high = 0; > uint64_t nonce_low = 0; > uint64_t async_id = 0; >- struct tevent_req *subreq = NULL; >+ NTSTATUS status; > > TALLOC_FREE(req->async_te); > >@@ -1533,7 +1509,6 @@ static void smbd_smb2_request_pending_timer(struct tevent_context *ev, > } > > if (req->do_encryption) { >- NTSTATUS status; > struct smbXsrv_session *x = req->session; > struct smbXsrv_connection *conn = x->connection; > DATA_BLOB encryption_key = x->global->encryption_key; >@@ -1548,7 +1523,6 @@ static void smbd_smb2_request_pending_timer(struct tevent_context *ev, > return; > } > } else if (req->do_signing) { >- NTSTATUS status; > struct smbXsrv_session *x = req->session; > struct smbXsrv_connection *conn = x->connection; > DATA_BLOB signing_key = x->global->channels[0].signing_key; >@@ -1564,20 +1538,18 @@ static void smbd_smb2_request_pending_timer(struct tevent_context *ev, > } > } > >- subreq = tstream_writev_queue_send(state, >- state->sconn->ev_ctx, >- state->sconn->smb2.stream, >- state->sconn->smb2.send_queue, >- state->vector, >- ARRAY_SIZE(state->vector)); >- if (subreq == NULL) { >- smbd_server_connection_terminate(state->sconn, >- nt_errstr(NT_STATUS_NO_MEMORY)); >+ state->queue_entry.mem_ctx = state; >+ state->queue_entry.vector = state->vector; >+ state->queue_entry.count = ARRAY_SIZE(state->vector); >+ DLIST_ADD_END(sconn->smb2.send_queue, &state->queue_entry, NULL); >+ sconn->smb2.send_queue_len++; >+ >+ status = smbd_smb2_io_handler(sconn, TEVENT_FD_WRITE); >+ if (!NT_STATUS_IS_OK(status)) { >+ smbd_server_connection_terminate(sconn, >+ nt_errstr(status)); > return; > } >- tevent_req_set_callback(subreq, >- smbd_smb2_request_pending_writev_done, >- state); > } > > static NTSTATUS smbd_smb2_request_process_cancel(struct smbd_smb2_request *req) >@@ -2277,12 +2249,13 @@ NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req) > > static NTSTATUS smbd_smb2_request_reply(struct smbd_smb2_request *req) > { >+ struct smbd_server_connection *sconn = req->sconn; > struct smbXsrv_connection *conn = req->sconn->conn; >- struct tevent_req *subreq; > int first_idx = 1; > struct iovec *firsttf = SMBD_SMB2_IDX_TF_IOV(req,out,first_idx); > struct iovec *outhdr = SMBD_SMB2_OUT_HDR_IOV(req); > struct iovec *outdyn = SMBD_SMB2_OUT_DYN_IOV(req); >+ NTSTATUS status; > > req->subreq = NULL; > TALLOC_FREE(req->async_te); >@@ -2346,7 +2319,6 @@ static NTSTATUS smbd_smb2_request_reply(struct smbd_smb2_request *req) > { > int last_idx = req->current_idx - SMBD_SMB2_NUM_IOV_PER_REQ; > struct iovec *lasthdr = SMBD_SMB2_IDX_HDR_IOV(req,out,last_idx); >- NTSTATUS status; > > /* > * As we are sure the header of the last request in the >@@ -2416,8 +2388,6 @@ static NTSTATUS smbd_smb2_request_reply(struct smbd_smb2_request *req) > * now check if we need to sign the current response > */ > if (firsttf->iov_len == SMB2_TF_HDR_SIZE) { >- NTSTATUS status; >- > status = smb2_signing_encrypt_pdu(req->first_key, > conn->protocol, > firsttf, >@@ -2426,7 +2396,6 @@ static NTSTATUS smbd_smb2_request_reply(struct smbd_smb2_request *req) > return status; > } > } else if (req->do_signing) { >- NTSTATUS status; > struct smbXsrv_session *x = req->session; > DATA_BLOB signing_key = x->global->channels[0].signing_key; > >@@ -2448,22 +2417,23 @@ static NTSTATUS smbd_smb2_request_reply(struct smbd_smb2_request *req) > req->out.vector_count -= 1; > } > >- subreq = tstream_writev_queue_send(req, >- req->sconn->ev_ctx, >- req->sconn->smb2.stream, >- req->sconn->smb2.send_queue, >- req->out.vector, >- req->out.vector_count); >- if (subreq == NULL) { >- return NT_STATUS_NO_MEMORY; >- } >- tevent_req_set_callback(subreq, smbd_smb2_request_writev_done, req); > /* > * We're done with this request - > * move it off the "being processed" queue. > */ > DLIST_REMOVE(req->sconn->smb2.requests, req); > >+ req->queue_entry.mem_ctx = req; >+ req->queue_entry.vector = req->out.vector; >+ req->queue_entry.count = req->out.vector_count; >+ DLIST_ADD_END(req->sconn->smb2.send_queue, &req->queue_entry, NULL); >+ req->sconn->smb2.send_queue_len++; >+ >+ status = smbd_smb2_io_handler(sconn, TEVENT_FD_WRITE); >+ if (!NT_STATUS_IS_OK(status)) { >+ return status; >+ } >+ > return NT_STATUS_OK; > } > >@@ -2499,33 +2469,6 @@ void smbd_smb2_request_dispatch_immediate(struct tevent_context *ctx, > } > } > >-static void smbd_smb2_request_writev_done(struct tevent_req *subreq) >-{ >- struct smbd_smb2_request *req = tevent_req_callback_data(subreq, >- struct smbd_smb2_request); >- 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) { >- 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, > NTSTATUS status, > DATA_BLOB body, DATA_BLOB *dyn, >@@ -2699,12 +2642,11 @@ NTSTATUS smbd_smb2_request_error_ex(struct smbd_smb2_request *req, > > struct smbd_smb2_send_oplock_break_state { > struct smbd_server_connection *sconn; >+ struct smbd_smb2_send_queue queue_entry; > uint8_t buf[NBT_HDR_SIZE + SMB2_TF_HDR_SIZE + SMB2_HDR_BODY + 0x18]; > struct iovec vector[1+SMBD_SMB2_NUM_IOV_PER_REQ]; > }; > >-static void smbd_smb2_oplock_break_writev_done(struct tevent_req *subreq); >- > NTSTATUS smbd_smb2_send_oplock_break(struct smbd_server_connection *sconn, > struct smbXsrv_session *session, > struct smbXsrv_tcon *tcon, >@@ -2713,7 +2655,6 @@ NTSTATUS smbd_smb2_send_oplock_break(struct smbd_server_connection *sconn, > { > struct smbd_smb2_send_oplock_break_state *state; > struct smbXsrv_connection *conn = sconn->conn; >- struct tevent_req *subreq; > uint8_t *tf; > size_t tf_len; > uint8_t *hdr; >@@ -2724,6 +2665,7 @@ NTSTATUS smbd_smb2_send_oplock_break(struct smbd_server_connection *sconn, > bool do_encryption = session->global->encryption_required; > uint64_t nonce_high = 0; > uint64_t nonce_low = 0; >+ NTSTATUS status; > > if (tcon->global->encryption_required) { > do_encryption = true; >@@ -2804,7 +2746,6 @@ NTSTATUS smbd_smb2_send_oplock_break(struct smbd_server_connection *sconn, > smb2_setup_nbt_length(state->vector, 1 + SMBD_SMB2_NUM_IOV_PER_REQ); > > if (do_encryption) { >- NTSTATUS status; > DATA_BLOB encryption_key = session->global->encryption_key; > > status = smb2_signing_encrypt_pdu(encryption_key, >@@ -2816,63 +2757,20 @@ NTSTATUS smbd_smb2_send_oplock_break(struct smbd_server_connection *sconn, > } > } > >- subreq = tstream_writev_queue_send(state, >- sconn->ev_ctx, >- sconn->smb2.stream, >- sconn->smb2.send_queue, >- state->vector, >- ARRAY_SIZE(state->vector)); >- if (subreq == NULL) { >- return NT_STATUS_NO_MEMORY; >- } >- tevent_req_set_callback(subreq, >- smbd_smb2_oplock_break_writev_done, >- state); >- >- return NT_STATUS_OK; >-} >- >-static void smbd_smb2_oplock_break_writev_done(struct tevent_req *subreq) >-{ >- struct smbd_smb2_send_oplock_break_state *state = >- tevent_req_callback_data(subreq, >- struct smbd_smb2_send_oplock_break_state); >- struct smbd_server_connection *sconn = state->sconn; >- int ret; >- int sys_errno; >+ state->queue_entry.mem_ctx = state; >+ state->queue_entry.vector = state->vector; >+ state->queue_entry.count = ARRAY_SIZE(state->vector); >+ DLIST_ADD_END(state->sconn->smb2.send_queue, &state->queue_entry, NULL); >+ state->sconn->smb2.send_queue_len++; > >- ret = tstream_writev_queue_recv(subreq, &sys_errno); >- TALLOC_FREE(subreq); >- if (ret == -1) { >- NTSTATUS status = map_nt_error_from_unix(sys_errno); >- smbd_server_connection_terminate(sconn, nt_errstr(status)); >- return; >+ status = smbd_smb2_io_handler(sconn, TEVENT_FD_WRITE); >+ if (!NT_STATUS_IS_OK(status)) { >+ return status; > } > >- TALLOC_FREE(state); >+ return NT_STATUS_OK; > } > >-struct smbd_smb2_request_read_state { >- struct tevent_context *ev; >- struct smbd_server_connection *sconn; >- struct smbd_smb2_request *smb2_req; >- struct { >- uint8_t nbt[NBT_HDR_SIZE]; >- bool done; >- } hdr; >- bool doing_receivefile; >- size_t min_recv_size; >- size_t pktlen; >- uint8_t *pktbuf; >-}; >- >-static int smbd_smb2_request_next_vector(struct tstream_context *stream, >- void *private_data, >- TALLOC_CTX *mem_ctx, >- struct iovec **_vector, >- size_t *_count); >-static void smbd_smb2_request_read_done(struct tevent_req *subreq); >- > static size_t get_min_receive_file_size(struct smbd_smb2_request *smb2_req) > { > if (smb2_req->do_signing) { >@@ -2884,43 +2782,6 @@ static size_t get_min_receive_file_size(struct smbd_smb2_request *smb2_req) > return (size_t)lp_min_receive_file_size(); > } > >-static struct tevent_req *smbd_smb2_request_read_send(TALLOC_CTX *mem_ctx, >- struct tevent_context *ev, >- struct smbd_server_connection *sconn) >-{ >- struct tevent_req *req; >- struct smbd_smb2_request_read_state *state; >- struct tevent_req *subreq; >- >- req = tevent_req_create(mem_ctx, &state, >- struct smbd_smb2_request_read_state); >- if (req == NULL) { >- return NULL; >- } >- state->ev = ev; >- state->sconn = sconn; >- >- state->smb2_req = smbd_smb2_request_allocate(state); >- if (tevent_req_nomem(state->smb2_req, req)) { >- return tevent_req_post(req, ev); >- } >- state->smb2_req->sconn = sconn; >- state->min_recv_size = get_min_receive_file_size(state->smb2_req); >- >- subreq = tstream_readv_pdu_queue_send(state->smb2_req, >- state->ev, >- state->sconn->smb2.stream, >- state->sconn->smb2.recv_queue, >- smbd_smb2_request_next_vector, >- state); >- if (tevent_req_nomem(subreq, req)) { >- return tevent_req_post(req, ev); >- } >- tevent_req_set_callback(subreq, smbd_smb2_request_read_done, req); >- >- return req; >-} >- > static bool is_smb2_recvfile_write(struct smbd_smb2_request_read_state *state) > { > uint32_t flags; >@@ -2962,226 +2823,22 @@ static bool is_smb2_recvfile_write(struct smbd_smb2_request_read_state *state) > return true; > } > >-static int smbd_smb2_request_next_vector(struct tstream_context *stream, >- void *private_data, >- TALLOC_CTX *mem_ctx, >- struct iovec **_vector, >- size_t *_count) >-{ >- struct smbd_smb2_request_read_state *state = >- talloc_get_type_abort(private_data, >- struct smbd_smb2_request_read_state); >- struct iovec *vector = NULL; >- size_t min_recvfile_size = UINT32_MAX; >- >- if (state->pktlen > 0) { >- if (state->doing_receivefile && !is_smb2_recvfile_write(state)) { >- /* >- * Not a possible receivefile write. >- * Read the rest of the data. >- */ >- state->doing_receivefile = false; >- vector = talloc_array(mem_ctx, struct iovec, 1); >- if (vector == NULL) { >- return -1; >- } >- vector[0].iov_base = (void *)(state->pktbuf + >- SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN); >- vector[0].iov_len = (state->pktlen - >- SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN); >- *_vector = vector; >- *_count = 1; >- } 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 >- * smbd_smb2_request_read_done() will handle >- * and short read case by looking at the >- * state->doing_receivefile value. >- */ >- *_vector = NULL; >- *_count = 0; >- } >- return 0; >- } >- >- if (!state->hdr.done) { >- /* >- * first we need to get the NBT header >- */ >- vector = talloc_array(mem_ctx, struct iovec, 1); >- if (vector == NULL) { >- return -1; >- } >- >- vector[0].iov_base = (void *)state->hdr.nbt; >- vector[0].iov_len = NBT_HDR_SIZE; >- >- *_vector = vector; >- *_count = 1; >- >- state->hdr.done = true; >- return 0; >- } >- >- /* >- * Now we analyze the NBT header >- */ >- state->pktlen = smb2_len(state->hdr.nbt); >- >- if (state->pktlen == 0) { >- /* if there're no remaining bytes, we're done */ >- *_vector = NULL; >- *_count = 0; >- return 0; >- } >- >- state->pktbuf = talloc_array(state->smb2_req, uint8_t, state->pktlen); >- if (state->pktbuf == NULL) { >- return -1; >- } >- >- vector = talloc_array(mem_ctx, struct iovec, 1); >- if (vector == NULL) { >- return -1; >- } >- >- vector[0].iov_base = (void *)state->pktbuf; >- >- if (state->min_recv_size != 0) { >- min_recvfile_size = SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN; >- min_recvfile_size += state->min_recv_size; >- } >- >- if (state->pktlen > min_recvfile_size) { >- /* >- * Might be a receivefile write. Read the SMB2 HEADER + >- * SMB2_WRITE header first. Set 'doing_receivefile' >- * as we're *attempting* receivefile write. If this >- * turns out not to be a SMB2_WRITE request or otherwise >- * not suitable then we'll just read the rest of the data >- * the next time this function is called. >- */ >- vector[0].iov_len = SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN; >- state->doing_receivefile = true; >- } else { >- vector[0].iov_len = state->pktlen; >- } >- >- *_vector = vector; >- *_count = 1; >- return 0; >-} >- >-static void smbd_smb2_request_read_done(struct tevent_req *subreq) >-{ >- struct tevent_req *req = >- tevent_req_callback_data(subreq, >- struct tevent_req); >- struct smbd_smb2_request_read_state *state = >- tevent_req_data(req, >- struct smbd_smb2_request_read_state); >- int ret; >- int sys_errno; >- NTSTATUS status; >- NTTIME now; >- >- ret = tstream_readv_pdu_queue_recv(subreq, &sys_errno); >- TALLOC_FREE(subreq); >- if (ret == -1) { >- status = map_nt_error_from_unix(sys_errno); >- tevent_req_nterror(req, status); >- return; >- } >- >- if (state->hdr.nbt[0] != 0x00) { >- DEBUG(1,("smbd_smb2_request_read_done: ignore NBT[0x%02X] msg\n", >- state->hdr.nbt[0])); >- >- ZERO_STRUCT(state->hdr); >- TALLOC_FREE(state->pktbuf); >- state->pktlen = 0; >- >- subreq = tstream_readv_pdu_queue_send(state->smb2_req, >- state->ev, >- state->sconn->smb2.stream, >- state->sconn->smb2.recv_queue, >- smbd_smb2_request_next_vector, >- state); >- if (tevent_req_nomem(subreq, req)) { >- return; >- } >- tevent_req_set_callback(subreq, smbd_smb2_request_read_done, req); >- return; >- } >- >- state->smb2_req->request_time = timeval_current(); >- now = timeval_to_nttime(&state->smb2_req->request_time); >- >- status = smbd_smb2_inbuf_parse_compound(state->smb2_req->sconn->conn, >- now, >- state->pktbuf, >- state->pktlen, >- state->smb2_req, >- &state->smb2_req->in.vector, >- &state->smb2_req->in.vector_count); >- if (tevent_req_nterror(req, status)) { >- return; >- } >- >- if (state->doing_receivefile) { >- state->smb2_req->smb1req = talloc_zero(state->smb2_req, >- struct smb_request); >- if (tevent_req_nomem(state->smb2_req->smb1req, req)) { >- return; >- } >- state->smb2_req->smb1req->unread_bytes = >- state->pktlen - SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN; >- } >- >- state->smb2_req->current_idx = 1; >- >- tevent_req_done(req); >-} >- >-static NTSTATUS smbd_smb2_request_read_recv(struct tevent_req *req, >- TALLOC_CTX *mem_ctx, >- struct smbd_smb2_request **_smb2_req) >-{ >- struct smbd_smb2_request_read_state *state = >- tevent_req_data(req, >- struct smbd_smb2_request_read_state); >- NTSTATUS status; >- >- if (tevent_req_is_nterror(req, &status)) { >- tevent_req_received(req); >- return status; >- } >- >- *_smb2_req = talloc_move(mem_ctx, &state->smb2_req); >- tevent_req_received(req); >- return NT_STATUS_OK; >-} >- >-static void smbd_smb2_request_incoming(struct tevent_req *subreq); >- > static NTSTATUS smbd_smb2_request_next_incoming(struct smbd_server_connection *sconn) > { >+ struct smbd_smb2_request_read_state *state = &sconn->smb2.request_read_state; > size_t max_send_queue_len; > size_t cur_send_queue_len; >- struct tevent_req *subreq; > >- if (tevent_queue_length(sconn->smb2.recv_queue) > 0) { >+ if (state->req != NULL) { > /* >- * if there is already a smbd_smb2_request_read >+ * if there is already a tstream_readv_pdu > * 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); >+ cur_send_queue_len = sconn->smb2.send_queue_len; > > if (cur_send_queue_len > max_send_queue_len) { > /* >@@ -3193,11 +2850,15 @@ static NTSTATUS smbd_smb2_request_next_incoming(struct smbd_server_connection *s > } > > /* ask for the next request */ >- subreq = smbd_smb2_request_read_send(sconn, sconn->ev_ctx, sconn); >- if (subreq == NULL) { >+ ZERO_STRUCTP(state); >+ state->req = smbd_smb2_request_allocate(sconn); >+ if (state->req == NULL) { > return NT_STATUS_NO_MEMORY; > } >- tevent_req_set_callback(subreq, smbd_smb2_request_incoming, sconn); >+ state->req->sconn = sconn; >+ state->min_recv_size = get_min_receive_file_size(state->req); >+ >+ TEVENT_FD_READABLE(sconn->smb2.fde); > > return NT_STATUS_OK; > } >@@ -3250,47 +2911,304 @@ void smbd_smb2_first_negprot(struct smbd_server_connection *sconn, > sconn->num_requests++; > } > >-static void smbd_smb2_request_incoming(struct tevent_req *subreq) >+static int socket_error_from_errno(int ret, >+ int sys_errno, >+ bool *retry) > { >- struct smbd_server_connection *sconn = tevent_req_callback_data(subreq, >- struct smbd_server_connection); >- NTSTATUS status; >+ *retry = false; >+ >+ if (ret >= 0) { >+ return 0; >+ } >+ >+ if (ret != -1) { >+ return EIO; >+ } >+ >+ if (sys_errno == 0) { >+ return EIO; >+ } >+ >+ if (sys_errno == EINTR) { >+ *retry = true; >+ return sys_errno; >+ } >+ >+ if (sys_errno == EINPROGRESS) { >+ *retry = true; >+ return sys_errno; >+ } >+ >+ if (sys_errno == EAGAIN) { >+ *retry = true; >+ return sys_errno; >+ } >+ >+ /* ENOMEM is retryable on Solaris/illumos, and possibly other systems. */ >+ if (sys_errno == ENOMEM) { >+ *retry = true; >+ return sys_errno; >+ } >+ >+#ifdef EWOULDBLOCK >+ if (sys_errno == EWOULDBLOCK) { >+ *retry = true; >+ return sys_errno; >+ } >+#endif >+ >+ return sys_errno; >+} >+ >+static NTSTATUS smbd_smb2_flush_send_queue(struct smbd_server_connection *sconn) >+{ >+ int ret; >+ int err; >+ bool retry; >+ >+ if (sconn->smb2.send_queue == NULL) { >+ TEVENT_FD_NOT_WRITEABLE(sconn->smb2.fde); >+ return NT_STATUS_OK; >+ } >+ >+ while (sconn->smb2.send_queue != NULL) { >+ struct smbd_smb2_send_queue *e = sconn->smb2.send_queue; >+ >+ ret = writev(sconn->sock, e->vector, e->count); >+ if (ret == 0) { >+ /* propagate end of file */ >+ return NT_STATUS_INTERNAL_ERROR; >+ } >+ err = socket_error_from_errno(ret, errno, &retry); >+ if (retry) { >+ /* retry later */ >+ TEVENT_FD_WRITEABLE(sconn->smb2.fde); >+ return NT_STATUS_OK; >+ } >+ if (err != 0) { >+ return map_nt_error_from_unix_common(err); >+ } >+ while (ret > 0) { >+ if (ret < e->vector[0].iov_len) { >+ uint8_t *base; >+ base = (uint8_t *)e->vector[0].iov_base; >+ base += ret; >+ e->vector[0].iov_base = (void *)base; >+ e->vector[0].iov_len -= ret; >+ break; >+ } >+ ret -= e->vector[0].iov_len; >+ e->vector += 1; >+ e->count -= 1; >+ } >+ >+ /* >+ * there're maybe some empty vectors at the end >+ * which we need to skip, otherwise we would get >+ * ret == 0 from the readv() call and return EPIPE >+ */ >+ while (e->count > 0) { >+ if (e->vector[0].iov_len > 0) { >+ break; >+ } >+ e->vector += 1; >+ e->count -= 1; >+ } >+ >+ if (e->count > 0) { >+ /* we have more to write */ >+ TEVENT_FD_WRITEABLE(sconn->smb2.fde); >+ return NT_STATUS_OK; >+ } >+ >+ sconn->smb2.send_queue_len--; >+ DLIST_REMOVE(sconn->smb2.send_queue, e); >+ talloc_free(e->mem_ctx); >+ } >+ >+ return NT_STATUS_OK; >+} >+ >+static NTSTATUS smbd_smb2_io_handler(struct smbd_server_connection *sconn, >+ uint16_t fde_flags) >+{ >+ struct smbd_smb2_request_read_state *state = &sconn->smb2.request_read_state; > struct smbd_smb2_request *req = NULL; >+ size_t min_recvfile_size = UINT32_MAX; >+ int ret; >+ int err; >+ bool retry; >+ NTSTATUS status; >+ NTTIME now; >+ >+ if (fde_flags & TEVENT_FD_WRITE) { >+ status = smbd_smb2_flush_send_queue(sconn); >+ if (!NT_STATUS_IS_OK(status)) { >+ return status; >+ } >+ } >+ >+ if (!(fde_flags & TEVENT_FD_READ)) { >+ return NT_STATUS_OK; >+ } >+ >+ if (state->req == NULL) { >+ TEVENT_FD_NOT_READABLE(sconn->smb2.fde); >+ return NT_STATUS_OK; >+ } >+ >+again: >+ if (!state->hdr.done) { >+ state->hdr.done = true; >+ >+ state->vector.iov_base = (void *)state->hdr.nbt; >+ state->vector.iov_len = NBT_HDR_SIZE; >+ } >+ >+ ret = readv(sconn->sock, &state->vector, 1); >+ if (ret == 0) { >+ /* propagate end of file */ >+ return NT_STATUS_END_OF_FILE; >+ } >+ err = socket_error_from_errno(ret, errno, &retry); >+ if (retry) { >+ /* retry later */ >+ TEVENT_FD_READABLE(sconn->smb2.fde); >+ return NT_STATUS_OK; >+ } >+ if (err != 0) { >+ return map_nt_error_from_unix_common(err); >+ } >+ >+ if (ret < state->vector.iov_len) { >+ uint8_t *base; >+ base = (uint8_t *)state->vector.iov_base; >+ base += ret; >+ state->vector.iov_base = (void *)base; >+ state->vector.iov_len -= ret; >+ /* we have more to read */ >+ TEVENT_FD_READABLE(sconn->smb2.fde); >+ return NT_STATUS_OK; >+ } >+ >+ if (state->pktlen > 0) { >+ if (state->doing_receivefile && !is_smb2_recvfile_write(state)) { >+ /* >+ * Not a possible receivefile write. >+ * Read the rest of the data. >+ */ >+ state->doing_receivefile = false; >+ state->vector.iov_base = (void *)(state->pktbuf + >+ SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN); >+ state->vector.iov_len = (state->pktlen - >+ SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN); >+ goto again; >+ } >+ >+ /* >+ * Either this is a receivefile write so we've >+ * done a short read, or if not we have all the data. >+ */ >+ goto got_full; >+ } >+ >+ /* >+ * Now we analyze the NBT header >+ */ >+ state->pktlen = smb2_len(state->hdr.nbt); >+ if (state->pktlen == 0) { >+ goto got_full; >+ } >+ >+ state->pktbuf = talloc_array(state->req, uint8_t, state->pktlen); >+ if (state->pktbuf == NULL) { >+ return NT_STATUS_NO_MEMORY; >+ } >+ >+ state->vector.iov_base = (void *)state->pktbuf; >+ >+ if (state->min_recv_size != 0) { >+ min_recvfile_size = SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN; >+ min_recvfile_size += state->min_recv_size; >+ } >+ >+ if (state->pktlen > min_recvfile_size) { >+ /* >+ * Might be a receivefile write. Read the SMB2 HEADER + >+ * SMB2_WRITE header first. Set 'doing_receivefile' >+ * as we're *attempting* receivefile write. If this >+ * turns out not to be a SMB2_WRITE request or otherwise >+ * not suitable then we'll just read the rest of the data >+ * the next time this function is called. >+ */ >+ state->vector.iov_len = SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN; >+ state->doing_receivefile = true; >+ } else { >+ state->vector.iov_len = state->pktlen; >+ } >+ >+ goto again; >+ >+got_full: >+ >+ if (state->hdr.nbt[0] != 0x00) { >+ DEBUG(1,("ignore NBT[0x%02X] msg\n", >+ state->hdr.nbt[0])); >+ >+ req = state->req; >+ ZERO_STRUCTP(state); >+ state->req = req; >+ state->min_recv_size = get_min_receive_file_size(state->req); >+ req = NULL; >+ goto again; >+ } >+ >+ req = state->req; >+ state->req = NULL; >+ >+ req->request_time = timeval_current(); >+ now = timeval_to_nttime(&req->request_time); > >- status = smbd_smb2_request_read_recv(subreq, sconn, &req); >- TALLOC_FREE(subreq); >+ status = smbd_smb2_inbuf_parse_compound(req->sconn->conn, >+ now, >+ state->pktbuf, >+ state->pktlen, >+ req, >+ &req->in.vector, >+ &req->in.vector_count); > if (!NT_STATUS_IS_OK(status)) { >- DEBUG(2,("smbd_smb2_request_incoming: client read error %s\n", >- nt_errstr(status))); >- smbd_server_connection_terminate(sconn, nt_errstr(status)); >- return; >+ return status; >+ } >+ >+ if (state->doing_receivefile) { >+ req->smb1req = talloc_zero(req, struct smb_request); >+ if (req->smb1req == NULL) { >+ return NT_STATUS_NO_MEMORY; >+ } >+ req->smb1req->unread_bytes = >+ state->pktlen - SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN; > } > >- DEBUG(10,("smbd_smb2_request_incoming: idx[%d] of %d vectors\n", >+ ZERO_STRUCTP(state); >+ >+ req->current_idx = 1; >+ >+ DEBUG(10,("smbd_smb2_request idx[%d] of %d vectors\n", > req->current_idx, req->in.vector_count)); > > status = smbd_smb2_request_validate(req); > if (!NT_STATUS_IS_OK(status)) { >- smbd_server_connection_terminate(sconn, nt_errstr(status)); >- return; >+ return status; > } > > status = smbd_smb2_request_setup_out(req); > if (!NT_STATUS_IS_OK(status)) { >- smbd_server_connection_terminate(sconn, nt_errstr(status)); >- return; >+ return status; > } > > status = smbd_smb2_request_dispatch(req); > if (!NT_STATUS_IS_OK(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; >+ return status; > } > > sconn->num_requests++; >@@ -3307,4 +3225,28 @@ static void smbd_smb2_request_incoming(struct tevent_req *subreq) > change_to_root_user(); > check_log_size(); > } >+ >+ status = smbd_smb2_request_next_incoming(sconn); >+ if (!NT_STATUS_IS_OK(status)) { >+ return status; >+ } >+ >+ return NT_STATUS_OK; >+} >+ >+static void smbd_smb2_connection_handler(struct tevent_context *ev, >+ struct tevent_fd *fde, >+ uint16_t flags, >+ void *private_data) >+{ >+ struct smbd_server_connection *sconn = >+ talloc_get_type_abort(private_data, >+ struct smbd_server_connection); >+ NTSTATUS status; >+ >+ status = smbd_smb2_io_handler(sconn, flags); >+ if (!NT_STATUS_IS_OK(status)) { >+ smbd_server_connection_terminate(sconn, nt_errstr(status)); >+ return; >+ } > } >-- >1.7.9.5 > > >From f0fbe1ef49695eeed1eec706767986733cbcb3e7 Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Sat, 12 Oct 2013 02:40:12 +0200 >Subject: [PATCH 3/6] s3:smb2_server: use tevent_req_notify_callback() in > smbd_smb2_request_pending_queue() > >If the request is already done we can avoid one iteration >of tevent_loop_once(), which means we avoids one >talloc_stackframe_pool/talloc_free pair. > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: David Disseldorp <ddiss@samba.org> >(cherry picked from commit acfd4b068a5b99ac1d3fe716afff34cb7d2a0147) >--- > source3/smbd/smb2_server.c | 7 +++++++ > 1 file changed, 7 insertions(+) > >diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c >index bc83b3f..9b5503a 100644 >--- a/source3/smbd/smb2_server.c >+++ b/source3/smbd/smb2_server.c >@@ -1252,6 +1252,13 @@ NTSTATUS smbd_smb2_request_pending_queue(struct smbd_smb2_request *req, > uint32_t flags; > > if (!tevent_req_is_in_progress(subreq)) { >+ /* >+ * This is a performance optimization, >+ * it avoids one tevent_loop iteration, >+ * which means we avoid one >+ * talloc_stackframe_pool/talloc_free pair. >+ */ >+ tevent_req_notify_callback(subreq); > return NT_STATUS_OK; > } > >-- >1.7.9.5 > > >From fadc6c079ca6057f07c5398b58209e3eccf4ad47 Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Wed, 16 Oct 2013 09:15:12 +0200 >Subject: [PATCH 4/6] s3:smb2_server: allocate smbd_smb2_request on > talloc_tos() > >This matches the behavior for smb1 requests >and avoids an additional malloc() per request. > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: David Disseldorp <ddiss@samba.org> >(cherry picked from commit 9d33a3f3e814e2924a423496ccc133c6c73fcd12) >--- > source3/smbd/smb2_server.c | 4 +++- > 1 file changed, 3 insertions(+), 1 deletion(-) > >diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c >index 9b5503a..6aca5d1 100644 >--- a/source3/smbd/smb2_server.c >+++ b/source3/smbd/smb2_server.c >@@ -269,7 +269,7 @@ static struct smbd_smb2_request *smbd_smb2_request_allocate(TALLOC_CTX *mem_ctx) > /* Enable this to find subtle valgrind errors. */ > mem_pool = talloc_init("smbd_smb2_request_allocate"); > #else >- mem_pool = talloc_pool(mem_ctx, 8192); >+ mem_pool = talloc_tos(); > #endif > if (mem_pool == NULL) { > return NULL; >@@ -281,7 +281,9 @@ static struct smbd_smb2_request *smbd_smb2_request_allocate(TALLOC_CTX *mem_ctx) > return NULL; > } > talloc_reparent(mem_pool, mem_ctx, req); >+#if 0 > TALLOC_FREE(mem_pool); >+#endif > > req->last_session_id = UINT64_MAX; > req->last_tid = UINT32_MAX; >-- >1.7.9.5 > > >From f11e9afab15abe2df4176de5f5c9a5c5c2214f77 Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Mon, 14 Oct 2013 14:18:26 +0200 >Subject: [PATCH 5/6] s3:smb2_server: generate a header blob for the sendfile > path > >We need to pass the NBT header, SMB2 header and SMB2 Read header >as header blob to SMB_VFS_SENDFILE(). This allows the usage >of MSG_SEND or other tricks to avoid multiple TCP packets >on the wire. > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: David Disseldorp <ddiss@samba.org> >(cherry picked from commit 36efaac2597d2d36826c02f23be15e7323b09784) >--- > source3/smbd/globals.h | 1 + > source3/smbd/smb2_read.c | 10 ++++++---- > source3/smbd/smb2_server.c | 34 +++++++++++++++++++++++++++++++++- > 3 files changed, 40 insertions(+), 5 deletions(-) > >diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h >index b008968..f1378f2 100644 >--- a/source3/smbd/globals.h >+++ b/source3/smbd/globals.h >@@ -469,6 +469,7 @@ NTSTATUS smbXsrv_open_cleanup(uint64_t persistent_id); > struct smbd_smb2_send_queue { > struct smbd_smb2_send_queue *prev, *next; > >+ DATA_BLOB *sendfile_header; > struct iovec *vector; > int count; > >diff --git a/source3/smbd/smb2_read.c b/source3/smbd/smb2_read.c >index 41adb03..d6d3d90 100644 >--- a/source3/smbd/smb2_read.c >+++ b/source3/smbd/smb2_read.c >@@ -166,6 +166,7 @@ struct smbd_smb2_read_state { > uint32_t in_length; > uint64_t in_offset; > uint32_t in_minimum; >+ DATA_BLOB out_headers; > DATA_BLOB out_data; > uint32_t out_remaining; > }; >@@ -180,10 +181,10 @@ static int smb2_sendfile_send_data(struct smbd_smb2_read_state *state) > ssize_t nread; > > nread = SMB_VFS_SENDFILE(fsp->conn->sconn->sock, >- fsp, >- NULL, >- in_offset, >- in_length); >+ fsp, >+ state->smb2req->queue_entry.sendfile_header, >+ in_offset, >+ in_length); > DEBUG(10,("smb2_sendfile_send_data: SMB_VFS_SENDFILE returned %d on file %s\n", > (int)nread, > fsp_str_dbg(fsp) )); >@@ -301,6 +302,7 @@ static NTSTATUS schedule_smb2_sendfile_read(struct smbd_smb2_request *smb2req, > } > *state_copy = *state; > talloc_set_destructor(state_copy, smb2_sendfile_send_data); >+ state->smb2req->queue_entry.sendfile_header = &state_copy->out_headers; > return NT_STATUS_OK; > } > >diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c >index 6aca5d1..a46bb2f 100644 >--- a/source3/smbd/smb2_server.c >+++ b/source3/smbd/smb2_server.c >@@ -2680,7 +2680,7 @@ NTSTATUS smbd_smb2_send_oplock_break(struct smbd_server_connection *sconn, > do_encryption = true; > } > >- state = talloc(sconn, struct smbd_smb2_send_oplock_break_state); >+ state = talloc_zero(sconn, struct smbd_smb2_send_oplock_break_state); > if (state == NULL) { > return NT_STATUS_NO_MEMORY; > } >@@ -2983,6 +2983,38 @@ static NTSTATUS smbd_smb2_flush_send_queue(struct smbd_server_connection *sconn) > while (sconn->smb2.send_queue != NULL) { > struct smbd_smb2_send_queue *e = sconn->smb2.send_queue; > >+ if (e->sendfile_header != NULL) { >+ size_t size = 0; >+ size_t i = 0; >+ uint8_t *buf; >+ >+ for (i=0; i < e->count; i++) { >+ size += e->vector[i].iov_len; >+ } >+ >+ buf = talloc_array(e->mem_ctx, uint8_t, size); >+ if (buf == NULL) { >+ return NT_STATUS_NO_MEMORY; >+ } >+ >+ size = 0; >+ for (i=0; i < e->count; i++) { >+ memcpy(buf+size, >+ e->vector[i].iov_base, >+ e->vector[i].iov_len); >+ size += e->vector[i].iov_len; >+ } >+ >+ e->sendfile_header->data = buf; >+ e->sendfile_header->length = size; >+ e->count = 0; >+ >+ sconn->smb2.send_queue_len--; >+ DLIST_REMOVE(sconn->smb2.send_queue, e); >+ talloc_free(e->mem_ctx); >+ continue; >+ } >+ > ret = writev(sconn->sock, e->vector, e->count); > if (ret == 0) { > /* propagate end of file */ >-- >1.7.9.5 > > >From 25b59622fd60fbae6606b0cae7802cd55babcf93 Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Tue, 19 Nov 2013 05:21:05 +0100 >Subject: [PATCH 6/6] s3:smb2_server: avoid calling set_current_user_info() > for each request > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: David Disseldorp <ddiss@samba.org> > >Autobuild-User(master): Stefan Metzmacher <metze@samba.org> >Autobuild-Date(master): Wed Nov 27 16:31:44 CET 2013 on sn-devel-104 >(cherry picked from commit 3cc0651d9feda00b6a04f84b76744b2acc3a0446) >--- > source3/smbd/globals.h | 2 +- > source3/smbd/process.c | 5 ++--- > source3/smbd/smb2_server.c | 9 ++++++--- > 3 files changed, 9 insertions(+), 7 deletions(-) > >diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h >index f1378f2..b5b7d8d 100644 >--- a/source3/smbd/globals.h >+++ b/source3/smbd/globals.h >@@ -366,6 +366,7 @@ struct smbXsrv_connection { > * this session_table is used for SMB1 and SMB2, > */ > struct smbXsrv_session_table *session_table; >+ uint64_t last_session_id; > /* > * this tcon_table is only used for SMB1. > */ >@@ -730,7 +731,6 @@ struct smbd_server_connection { > * Set by us for CORE protocol. > */ > int max_send; >- uint64_t last_session_tag; > } sessions; > struct smb_signing_state *signing_state; > >diff --git a/source3/smbd/process.c b/source3/smbd/process.c >index 8add79d..3bf10de 100644 >--- a/source3/smbd/process.c >+++ b/source3/smbd/process.c >@@ -1434,10 +1434,10 @@ static connection_struct *switch_message(uint8 type, struct smb_request *req) > } > } > >- if (session_tag != sconn->smb1.sessions.last_session_tag) { >+ if (session_tag != sconn->conn->last_session_id) { > struct user_struct *vuser = NULL; > >- sconn->smb1.sessions.last_session_tag = session_tag; >+ sconn->conn->last_session_id = session_tag; > if (session) { > vuser = session->compat; > } >@@ -3593,7 +3593,6 @@ void smbd_process(struct tevent_context *ev_ctx, > > sconn->smb1.sessions.done_sesssetup = false; > sconn->smb1.sessions.max_send = BUFFER_SIZE; >- sconn->smb1.sessions.last_session_tag = UID_FIELD_INVALID; > > if (!init_dptrs(sconn)) { > exit_server("init_dptrs() failed"); >diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c >index a46bb2f..b4c291e5 100644 >--- a/source3/smbd/smb2_server.c >+++ b/source3/smbd/smb2_server.c >@@ -1749,9 +1749,12 @@ static NTSTATUS smbd_smb2_request_check_session(struct smbd_smb2_request *req) > return NT_STATUS_INVALID_HANDLE; > } > >- set_current_user_info(session_info->unix_info->sanitized_username, >- session_info->unix_info->unix_name, >- session_info->info->domain_name); >+ if (in_session_id != req->sconn->conn->last_session_id) { >+ req->sconn->conn->last_session_id = in_session_id; >+ set_current_user_info(session_info->unix_info->sanitized_username, >+ session_info->unix_info->unix_name, >+ session_info->info->domain_name); >+ } > > return NT_STATUS_OK; > } >-- >1.7.9.5 >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Raw
Flags:
jra
:
review+
Actions:
View
Attachments on
bug 10298
:
9493
| 9494