From 6800fdbb81130b79c2e077e9a7fcbe2d5e0813cb Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 31 Mar 2010 17:40:30 -0700 Subject: Make smbd_lock_socket/smbd_unlock_socket recursive with a ref_count. As these always call exit_server, make that part of the function. Use _internal functions for the echo client. Metze please check ! Jeremy. --- source3/smbd/globals.h | 10 ++++-- source3/smbd/process.c | 78 ++++++++++++++++++++++------------------------ source3/smbd/reply.c | 17 +++------- source3/smbd/smb2_read.c | 8 +++++ source3/smbd/smb2_server.c | 2 +- source3/smbd/smb2_write.c | 9 ++++++ 6 files changed, 68 insertions(+), 56 deletions(-) (limited to 'source3/smbd') diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h index 6e5262a991..3b58cb4ef3 100644 --- a/source3/smbd/globals.h +++ b/source3/smbd/globals.h @@ -153,8 +153,8 @@ struct smbd_smb2_tcon; DATA_BLOB negprot_spnego(void); -bool smbd_lock_socket(struct smbd_server_connection *sconn); -bool smbd_unlock_socket(struct smbd_server_connection *sconn); +void smbd_lock_socket(struct smbd_server_connection *sconn); +void smbd_unlock_socket(struct smbd_server_connection *sconn); NTSTATUS smb2_signing_sign_pdu(DATA_BLOB session_key, struct iovec *vector, @@ -452,6 +452,12 @@ struct smbd_server_connection { * fde for the trusted_fd */ struct fd_event *trusted_fde; + + /* + * Reference count for the fcntl lock to + * allow recursive locks. + */ + int ref_count; } echo_handler; uint64_t num_requests; diff --git a/source3/smbd/process.c b/source3/smbd/process.c index dd120f9bd2..40c85d4a62 100644 --- a/source3/smbd/process.c +++ b/source3/smbd/process.c @@ -40,7 +40,7 @@ extern bool global_machine_password_needs_changing; static void construct_reply_common(struct smb_request *req, const char *inbuf, char *outbuf); -bool smbd_lock_socket(struct smbd_server_connection *sconn) +static bool smbd_lock_socket_internal(struct smbd_server_connection *sconn) { bool ok; @@ -48,6 +48,12 @@ bool smbd_lock_socket(struct smbd_server_connection *sconn) return true; } + smbd_server_conn->smb1.echo_handler.ref_count++; + + if (smbd_server_conn->smb1.echo_handler.ref_count > 1) { + return true; + } + DEBUG(10,("pid[%d] wait for socket lock\n", (int)sys_getpid())); ok = fcntl_lock(smbd_server_conn->smb1.echo_handler.socket_lock_fd, @@ -61,7 +67,14 @@ bool smbd_lock_socket(struct smbd_server_connection *sconn) return true; } -bool smbd_unlock_socket(struct smbd_server_connection *sconn) +void smbd_lock_socket(struct smbd_server_connection *sconn) +{ + if (!smbd_lock_socket_internal(sconn)) { + exit_server_cleanly("failed to lock socket"); + } +} + +static bool smbd_unlock_socket_internal(struct smbd_server_connection *sconn) { bool ok; @@ -69,6 +82,12 @@ bool smbd_unlock_socket(struct smbd_server_connection *sconn) return true; } + smbd_server_conn->smb1.echo_handler.ref_count--; + + if (smbd_server_conn->smb1.echo_handler.ref_count > 0) { + return true; + } + ok = fcntl_lock(smbd_server_conn->smb1.echo_handler.socket_lock_fd, SMB_F_SETLKW, 0, 0, F_UNLCK); if (!ok) { @@ -80,6 +99,13 @@ bool smbd_unlock_socket(struct smbd_server_connection *sconn) return true; } +void smbd_unlock_socket(struct smbd_server_connection *sconn) +{ + if (!smbd_unlock_socket_internal(sconn)) { + exit_server_cleanly("failed to unlock socket"); + } +} + /* Accessor function for smb_read_error for smbd functions. */ /**************************************************************************** @@ -95,12 +121,8 @@ bool srv_send_smb(int fd, char *buffer, size_t nwritten=0; ssize_t ret; char *buf_out = buffer; - bool ok; - ok = smbd_lock_socket(smbd_server_conn); - if (!ok) { - exit_server_cleanly("failed to lock socket"); - } + smbd_lock_socket(smbd_server_conn); if (do_signing) { /* Sign the outgoing packet if required. */ @@ -132,11 +154,7 @@ bool srv_send_smb(int fd, char *buffer, out: SMB_PERFCOUNT_END(pcd); - ok = smbd_unlock_socket(smbd_server_conn); - if (!ok) { - exit_server_cleanly("failed to unlock socket"); - } - + smbd_unlock_socket(smbd_server_conn); return true; } @@ -2174,22 +2192,14 @@ static void smbd_server_connection_read_handler( NTSTATUS status; uint32_t seqnum; - bool ok; - bool from_client = (smbd_server_fd() == fd)?true:false; if (from_client) { - ok = smbd_lock_socket(conn); - if (!ok) { - exit_server_cleanly("failed to lock socket"); - } + smbd_lock_socket(conn); if (!fd_is_readable(smbd_server_fd())) { DEBUG(10,("the echo listener was faster\n")); - ok = smbd_unlock_socket(conn); - if (!ok) { - exit_server_cleanly("failed to unlock"); - } + smbd_unlock_socket(conn); return; } @@ -2201,10 +2211,7 @@ static void smbd_server_connection_read_handler( &encrypted, &inbuf_len, &seqnum, false /* trusted channel */); - ok = smbd_unlock_socket(conn); - if (!ok) { - exit_server_cleanly("failed to unlock"); - } + smbd_unlock_socket(conn); } else { /* TODO: make this completely nonblocking */ status = receive_smb_talloc(mem_ctx, fd, @@ -2321,20 +2328,11 @@ static int client_get_tcp_info(struct sockaddr_storage *server, */ static bool keepalive_fn(const struct timeval *now, void *private_data) { - bool ok; bool ret; - ok = smbd_lock_socket(smbd_server_conn); - if (!ok) { - exit_server_cleanly("failed to lock socket"); - } - + smbd_lock_socket(smbd_server_conn); ret = send_keepalive(smbd_server_fd()); - - ok = smbd_unlock_socket(smbd_server_conn); - if (!ok) { - exit_server_cleanly("failed to unlock socket"); - } + smbd_unlock_socket(smbd_server_conn); if (!ret) { DEBUG( 2, ( "Keepalive failed - exiting.\n" ) ); @@ -2574,7 +2572,7 @@ static void smbd_echo_reader(struct tevent_context *ev, bool ok; bool encrypted = false; - ok = smbd_lock_socket(sconn); + ok = smbd_lock_socket_internal(sconn); if (!ok) { DEBUG(0, ("%s: failed to lock socket\n", __location__)); @@ -2584,7 +2582,7 @@ static void smbd_echo_reader(struct tevent_context *ev, if (!fd_is_readable(smbd_server_fd())) { DEBUG(10,("echo_handler[%d] the parent smbd was faster\n", (int)sys_getpid())); - ok = smbd_unlock_socket(sconn); + ok = smbd_unlock_socket_internal(sconn); if (!ok) { DEBUG(1, ("%s: failed to unlock socket in\n", __location__)); @@ -2618,7 +2616,7 @@ static void smbd_echo_reader(struct tevent_context *ev, exit(1); } - ok = smbd_unlock_socket(sconn); + ok = smbd_unlock_socket_internal(sconn); if (!ok) { DEBUG(1, ("%s: failed to unlock socket in\n", __location__)); diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index c34e7f8b06..e2aca3793a 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -2895,22 +2895,15 @@ static void sendfile_short_send(files_struct *fsp, static void reply_readbraw_error(void) { - bool ok; char header[4]; SIVAL(header,0,0); - ok = smbd_lock_socket(smbd_server_conn); - if (!ok) { - exit_server_cleanly("failed to lock socket"); - } + smbd_lock_socket(smbd_server_conn); if (write_data(smbd_server_fd(),header,4) != 4) { fail_readraw(); } - ok = smbd_unlock_socket(smbd_server_conn); - if (!ok) { - exit_server_cleanly("failed to unlock socket"); - } + smbd_unlock_socket(smbd_server_conn); } /**************************************************************************** @@ -3462,10 +3455,6 @@ static void send_file_readX(connection_struct *conn, struct smb_request *req, goto nosendfile_read; } - if (smbd_server_conn->smb1.echo_handler.trusted_fde) { - goto nosendfile_read; - } - #if defined(WITH_SENDFILE) /* * We can only use sendfile on a non-chained packet @@ -3714,7 +3703,9 @@ void reply_read_and_X(struct smb_request *req) goto out; } + smbd_lock_socket(smbd_server_conn); send_file_readX(conn, req, fsp, startpos, smb_maxcnt); + smbd_unlock_socket(smbd_server_conn); out: END_PROFILE(SMBreadX); diff --git a/source3/smbd/smb2_read.c b/source3/smbd/smb2_read.c index 3f316e0b71..674fa2b71f 100644 --- a/source3/smbd/smb2_read.c +++ b/source3/smbd/smb2_read.c @@ -275,6 +275,14 @@ static struct tevent_req *smbd_smb2_read_send(TALLOC_CTX *mem_ctx, SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock); + DEBUG(10,("smbd_smb2_read: file %s handle [0x%016llX] offset=%llu " + "len=%llu returned %lld\n", + fsp_str_dbg(fsp), + (unsigned long long)in_file_id_volatile, + (unsigned long long)in_offset, + (unsigned long long)in_length, + (long long)nread)); + if (nread < 0) { DEBUG(5,("smbd_smb2_read: read_file[%s] nread[%lld]\n", fsp_str_dbg(fsp), (long long)nread)); diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c index 1d95d4be3f..c64f82f407 100644 --- a/source3/smbd/smb2_server.c +++ b/source3/smbd/smb2_server.c @@ -1566,7 +1566,7 @@ static void smbd_smb2_request_incoming(struct tevent_req *subreq) return; } - status = smbd_smb2_request_setup_out(req, creds_requested); + status = smbd_smb2_request_setup_out(req, 5); if (!NT_STATUS_IS_OK(status)) { smbd_server_connection_terminate(sconn, nt_errstr(status)); return; diff --git a/source3/smbd/smb2_write.c b/source3/smbd/smb2_write.c index fa209fafc7..17d562affa 100644 --- a/source3/smbd/smb2_write.c +++ b/source3/smbd/smb2_write.c @@ -266,6 +266,15 @@ static struct tevent_req *smbd_smb2_write_send(TALLOC_CTX *mem_ctx, in_offset, in_data.length); + + DEBUG(10,("smbd_smb2_write: file %s handle [0x%016llX] offset=%llu " + "len=%llu returned %lld\n", + fsp_str_dbg(fsp), + (unsigned long long)in_file_id_volatile, + (unsigned long long)in_offset, + (unsigned long long)in_data.length, + (long long)nwritten)); + if (((nwritten == 0) && (in_data.length != 0)) || (nwritten < 0)) { DEBUG(5,("smbd_smb2_write: write_file[%s] disk full\n", fsp_str_dbg(fsp))); -- cgit