The branch, master has been updated via 3cc0651 s3:smb2_server: avoid calling set_current_user_info() for each request via 36efaac s3:smb2_server: generate a header blob for the sendfile path via 9d33a3f s3:smb2_server: allocate smbd_smb2_request on talloc_tos() via acfd4b0 s3:smb2_server: use tevent_req_notify_callback() in smbd_smb2_request_pending_queue() via 4244a26 s3:smb2_server: for performance reasons we use tevent_fd and readv/writev directly via 9393e28 s3:smb2_server: fix drain_socket error handling via 22ee3b4 smbd: Fix a typo from 0dc0415 smbd: Remove a "set but unused" variable
http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit 3cc0651d9feda00b6a04f84b76744b2acc3a0446 Author: Stefan Metzmacher <me...@samba.org> Date: Tue Nov 19 05:21:05 2013 +0100 s3:smb2_server: avoid calling set_current_user_info() for each request Signed-off-by: Stefan Metzmacher <me...@samba.org> Reviewed-by: David Disseldorp <dd...@samba.org> Autobuild-User(master): Stefan Metzmacher <me...@samba.org> Autobuild-Date(master): Wed Nov 27 16:31:44 CET 2013 on sn-devel-104 commit 36efaac2597d2d36826c02f23be15e7323b09784 Author: Stefan Metzmacher <me...@samba.org> Date: Mon Oct 14 14:18:26 2013 +0200 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 <me...@samba.org> Reviewed-by: David Disseldorp <dd...@samba.org> commit 9d33a3f3e814e2924a423496ccc133c6c73fcd12 Author: Stefan Metzmacher <me...@samba.org> Date: Wed Oct 16 09:15:12 2013 +0200 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 <me...@samba.org> Reviewed-by: David Disseldorp <dd...@samba.org> commit acfd4b068a5b99ac1d3fe716afff34cb7d2a0147 Author: Stefan Metzmacher <me...@samba.org> Date: Sat Oct 12 02:40:12 2013 +0200 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 <me...@samba.org> Reviewed-by: David Disseldorp <dd...@samba.org> commit 4244a2686cddcdc754c284df884ae497afa4053a Author: Stefan Metzmacher <me...@samba.org> Date: Mon Oct 14 10:33:57 2013 +0200 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 <me...@samba.org> Reviewed-by: David Disseldorp <dd...@samba.org> commit 9393e28df59954414313bfae70ffb796d3e332fe Author: Stefan Metzmacher <me...@samba.org> Date: Mon Oct 14 16:42:55 2013 +0200 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 <me...@samba.org> Reviewed-by: David Disseldorp <dd...@samba.org> commit 22ee3b472da68e3f1d202ace44e2adaca51211c0 Author: Volker Lendecke <v...@samba.org> Date: Wed Nov 27 10:08:20 2013 +0000 smbd: Fix a typo Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Stefan Metzmacher <me...@samba.org> ----------------------------------------------------------------------- Summary of changes: source3/smbd/globals.h | 31 ++- source3/smbd/notify_internal.c | 2 +- source3/smbd/process.c | 5 +- source3/smbd/smb2_read.c | 10 +- source3/smbd/smb2_server.c | 886 ++++++++++++++++++++-------------------- 5 files changed, 479 insertions(+), 455 deletions(-) Changeset truncated at 500 lines: diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h index 6beee59..94111b6 100644 --- a/source3/smbd/globals.h +++ b/source3/smbd/globals.h @@ -367,6 +367,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. */ @@ -467,12 +468,23 @@ 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; + + DATA_BLOB *sendfile_header; + 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; @@ -720,7 +732,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; @@ -740,9 +751,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/notify_internal.c b/source3/smbd/notify_internal.c index 2dc8674..994608c 100644 --- a/source3/smbd/notify_internal.c +++ b/source3/smbd/notify_internal.c @@ -21,7 +21,7 @@ /* this is the change notify database. It implements mechanisms for storing current change notify waiters in a tdb, and checking if a - given event matches any of the stored notify waiiters. + given event matches any of the stored notify waiters. */ #include "includes.h" diff --git a/source3/smbd/process.c b/source3/smbd/process.c index b8e01ba..09fe910 100644 --- a/source3/smbd/process.c +++ b/source3/smbd/process.c @@ -1436,10 +1436,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; } @@ -3596,7 +3596,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_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 1bebee1..768a9c8 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 */ @@ -270,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; @@ -282,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; @@ -1151,10 +1152,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 +1218,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, @@ -1277,6 +1254,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; } @@ -1393,6 +1377,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 +1392,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 +1518,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 +1532,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 +1547,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) @@ -1768,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; } @@ -2277,12 +2261,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 +2331,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 +2400,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 +2408,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 +2429,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 +2481,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, @@ -2644,10 +2599,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); -- Samba Shared Repository