1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-23 17:34:34 +03:00
samba-mirror/source3/smbd/server_exit.c

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

263 lines
6.4 KiB
C
Raw Normal View History

/*
Unix SMB/CIFS implementation.
Main SMB server routines
Copyright (C) Andrew Tridgell 1992-1998
Copyright (C) Martin Pool 2002
Copyright (C) Jelmer Vernooij 2002-2003
Copyright (C) Volker Lendecke 1993-2007
Copyright (C) Jeremy Allison 1993-2007
Copyright (C) Andrew Bartlett 2010
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "includes.h"
#include "locking/share_mode_lock.h"
#include "smbd/smbd.h"
#include "smbd/globals.h"
#include "ntdomain.h"
#include "librpc/rpc/dcesrv_core.h"
#include "printing/notify.h"
#include "printing.h"
#include "serverid.h"
#include "messages.h"
#include "passdb.h"
#include "../lib/util/pidfile.h"
s3:smbprofile: Replace sysv shmem with tdb What? This patch gets rid of the central shared memory segment referenced by "profile_p". Instead, every smbd gets a static profile_area where it collects profiling data. Once a second, every smbd writes this profiling data into a record of its own in a "smbprofile.tdb". smbstatus -P does a tdb_traverse on this database and sums up what it finds. Why? At least in my perception sysv IPC has not the best reputation on earth. The code before this patch uses shmat(). Samba ages ago has developed a good abstraction of shared memory: It's called tdb. The main reason why I started this is that I have a request to become more flexible with profiling data. Samba should be able to collect data per share or per user, something which is almost impossible to do with a fixed structure. My idea is to for example install a profile area per share and every second marshall this into one tdb record indexed by share name. smbstatus -P would then also collect the data and either aggregate them or put them into individual per-share statistics. This flexibility in the data model is not really possible with one fixed structure. But isn't it slow? Well, I don't think so. I can't really prove it, but I do believe that on large boxes atomically incrementing a shared memory value for every SMB does show up due to NUMA effects. With this patch the hot code path is completely process-local. Once a second every smbd writes into a central tdb, this of course does atomic operations. But it's once a second, not on every SMB2 read. There's two places where I would like to improve things: With the current code all smbds wake up once a second. With 10,000 potentially idle smbds this will become noticable. That's why the current only starts the timer when something has changed. The second place is the tdb traverse: Right now traverse is blocking in the sense that when it has to switch hash chains it will block. With mutexes, this means a syscall. I have a traverse light in mind that works as follows: It assumes a locked hash chain and then walks the complete chain in one run without unlocking in between. This way the caller can do nonblocking locks in the first round and only do blocking locks in a second round. Also, a lot of syscall overhead will vanish. This way smbstatus -P will have almost zero impact on normal operations. Pair-Programmed-With: Stefan Metzmacher <metze@samba.org> Signed-off-by: Volker Lendecke <vl@samba.org> Signed-off-by: Stefan Metzmacher <metze@samba.org> Reviewed-by: Ralph Boehme <slow@samba.org>
2014-09-29 20:08:17 +04:00
#include "smbprofile.h"
#include "libcli/auth/netlogon_creds_cli.h"
#include "lib/gencache.h"
#include "rpc_server/rpc_config.h"
#include "lib/global_contexts.h"
static struct files_struct *log_writeable_file_fn(
struct files_struct *fsp, void *private_data)
{
bool *found = (bool *)private_data;
char *path;
if (!fsp->fsp_flags.can_write) {
return NULL;
}
if (!(*found)) {
DEBUG(0, ("Writable files open at exit:\n"));
*found = true;
}
path = talloc_asprintf(talloc_tos(), "%s/%s", fsp->conn->connectpath,
smb_fname_str_dbg(fsp->fsp_name));
if (path == NULL) {
DEBUGADD(0, ("<NOMEM>\n"));
}
DEBUGADD(0, ("%s\n", path));
TALLOC_FREE(path);
return NULL;
}
/****************************************************************************
Exit the server.
****************************************************************************/
/* Reasons for shutting down a server process. */
enum server_exit_reason { SERVER_EXIT_NORMAL, SERVER_EXIT_ABNORMAL };
static void exit_server_common(enum server_exit_reason how,
const char *reason) _NORETURN_;
static void exit_server_common(enum server_exit_reason how,
const char *reason)
{
struct smbXsrv_client *client = global_smbXsrv_client;
struct smbXsrv_connection *xconn = NULL;
struct smbd_server_connection *sconn = NULL;
NTSTATUS disconnect_status;
if (!exit_firsttime) {
exit(0);
}
exit_firsttime = false;
switch (how) {
case SERVER_EXIT_NORMAL:
disconnect_status = NT_STATUS_LOCAL_DISCONNECT;
break;
case SERVER_EXIT_ABNORMAL:
default:
disconnect_status = NT_STATUS_INTERNAL_ERROR;
break;
}
if (client != NULL) {
NTSTATUS status;
sconn = client->sconn;
xconn = client->connections;
/*
* Make sure we stop handling new multichannel
* connections early!
*
* From here, we're not able to handle them.
*/
status = smbXsrv_client_remove(client);
if (!NT_STATUS_IS_OK(status)) {
D_ERR("Server exit (%s)\n",
(reason ? reason : "normal exit"));
DBG_ERR("smbXsrv_client_remove() failed (%s)\n",
nt_errstr(status));
}
}
change_to_root_user();
smbd: disconnect/destroy all connections before calling smbXsrv_session_logoff_all() This means the pending requests are destroyed before tevent_context impersonation wrapper are destroyed. Otherwise, with a pending struct tevent_req that is a child of client->xconn like this in exit_server_common(): conn[ipv4:127.0.0.11:40745] reason[NT_STATUS_CONNECTION_RESET] at ../source3/smbd/smb2_server.c:4015 full talloc report on 'struct smbXsrv_connection' (total 6085 bytes in 43 blocks) struct smbd_smb2_request contains 648 bytes in 1 blocks (ref 0) 0x55ed41634740 struct smbd_smb2_request contains 3438 bytes in 32 blocks (ref 0) 0x55ed416331e0 struct tevent_req contains 1824 bytes in 20 blocks (ref 0) 0x55ed41635860 struct smb_filename contains 206 bytes in 2 blocks (ref 0) 0x55ed41635560 lease_v2_complex2.dat contains 22 bytes in 1 blocks (ref 0) 0x55ed4161b950 struct smbd_smb2_create_state contains 1386 bytes in 16 blocks (ref 0) 0x55ed41635a10 struct deferred_open_record contains 804 bytes in 12 blocks (ref 0) 0x55ed41633090 struct defer_open_state contains 764 bytes in 11 blocks (ref 0) 0x55ed41634f10 struct tevent_req contains 748 bytes in 10 blocks (ref 0) 0x55ed41636390 struct tevent_timer contains 96 bytes in 1 blocks (ref 0) 0x55ed41636ad0 struct dbwrap_watched_watch_state contains 420 bytes in 7 blocks (ref 0) 0x55ed41636540 struct tevent_req contains 296 bytes in 5 blocks (ref 0) 0x55ed41636700 struct messaging_filtered_read_state contains 64 bytes in 3 blocks (ref 0) 0x55ed416368b0 struct messaging_dgm_fde contains 8 bytes in 2 blocks (ref 0) 0x55ed41636950 reference to: struct messaging_dgm_fde_ev we crash when freeing the xconn as the the tevent_req child has a cleanup function that tries to access a (wrapped) tevent context that was already destroyed via smb1srv_tcon_disconnect_all() for SMB1 or smbXsrv_session_logoff_all() for SMB2 a few lines above. Signed-off-by: Stefan Metzmacher <metze@samba.org> Reviewed-by: Ralph Boehme <slow@samba.org>
2018-07-24 18:17:29 +03:00
/*
* Here we typically have just one connection
*/
for (; xconn != NULL; xconn = xconn->next) {
/*
* This is typically the disconnect for the only
* (or with multi-channel last) connection of the client.
*
* smbXsrv_connection_disconnect_transport() might be called already,
* but calling it again is a no-op.
*/
smbXsrv_connection_disconnect_transport(xconn, disconnect_status);
}
change_to_root_user();
if (sconn != NULL) {
if (lp_log_writeable_files_on_exit()) {
bool found = false;
files_forall(sconn, log_writeable_file_fn, &found);
}
}
change_to_root_user();
if (client != NULL) {
NTSTATUS status;
/*
* Note: this is a no-op for smb2 as
* conn->tcon_table is empty
*/
status = smb1srv_tcon_disconnect_all(client);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0,("Server exit (%s)\n",
(reason ? reason : "normal exit")));
DEBUG(0, ("exit_server_common: "
"smb1srv_tcon_disconnect_all() failed (%s) - "
"triggering cleanup\n", nt_errstr(status)));
}
status = smbXsrv_session_logoff_all(client);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0,("Server exit (%s)\n",
(reason ? reason : "normal exit")));
DEBUG(0, ("exit_server_common: "
"smbXsrv_session_logoff_all() failed (%s) - "
"triggering cleanup\n", nt_errstr(status)));
}
}
change_to_root_user();
if (client != NULL) {
struct smbXsrv_connection *xconn_next = NULL;
for (xconn = client->connections;
xconn != NULL;
xconn = xconn_next) {
xconn_next = xconn->next;
DLIST_REMOVE(client->connections, xconn);
TALLOC_FREE(xconn);
}
}
change_to_root_user();
#ifdef USE_DMAPI
/* Destroy Samba DMAPI session only if we are master smbd process */
if (am_parent) {
if (!dmapi_destroy_session()) {
DEBUG(0,("Unable to close Samba DMAPI session\n"));
}
}
#endif
/*
* we need to force the order of freeing the following,
* because smbd_msg_ctx is not a talloc child of smbd_server_conn.
*/
if (client != NULL) {
TALLOC_FREE(client->sconn);
}
sconn = NULL;
xconn = NULL;
client = NULL;
netlogon_creds_cli_close_global_db();
TALLOC_FREE(global_smbXsrv_client);
s3:smbprofile: Replace sysv shmem with tdb What? This patch gets rid of the central shared memory segment referenced by "profile_p". Instead, every smbd gets a static profile_area where it collects profiling data. Once a second, every smbd writes this profiling data into a record of its own in a "smbprofile.tdb". smbstatus -P does a tdb_traverse on this database and sums up what it finds. Why? At least in my perception sysv IPC has not the best reputation on earth. The code before this patch uses shmat(). Samba ages ago has developed a good abstraction of shared memory: It's called tdb. The main reason why I started this is that I have a request to become more flexible with profiling data. Samba should be able to collect data per share or per user, something which is almost impossible to do with a fixed structure. My idea is to for example install a profile area per share and every second marshall this into one tdb record indexed by share name. smbstatus -P would then also collect the data and either aggregate them or put them into individual per-share statistics. This flexibility in the data model is not really possible with one fixed structure. But isn't it slow? Well, I don't think so. I can't really prove it, but I do believe that on large boxes atomically incrementing a shared memory value for every SMB does show up due to NUMA effects. With this patch the hot code path is completely process-local. Once a second every smbd writes into a central tdb, this of course does atomic operations. But it's once a second, not on every SMB2 read. There's two places where I would like to improve things: With the current code all smbds wake up once a second. With 10,000 potentially idle smbds this will become noticable. That's why the current only starts the timer when something has changed. The second place is the tdb traverse: Right now traverse is blocking in the sense that when it has to switch hash chains it will block. With mutexes, this means a syscall. I have a traverse light in mind that works as follows: It assumes a locked hash chain and then walks the complete chain in one run without unlocking in between. This way the caller can do nonblocking locks in the first round and only do blocking locks in a second round. Also, a lot of syscall overhead will vanish. This way smbstatus -P will have almost zero impact on normal operations. Pair-Programmed-With: Stefan Metzmacher <metze@samba.org> Signed-off-by: Volker Lendecke <vl@samba.org> Signed-off-by: Stefan Metzmacher <metze@samba.org> Reviewed-by: Ralph Boehme <slow@samba.org>
2014-09-29 20:08:17 +04:00
smbprofile_dump();
global_messaging_context_free();
global_event_context_free();
TALLOC_FREE(smbd_memcache_ctx);
locking_end();
if (how != SERVER_EXIT_NORMAL) {
smb_panic(reason);
/* Notreached. */
exit(1);
} else {
DEBUG(3,("Server exit (%s)\n",
(reason ? reason : "normal exit")));
if (am_parent) {
pidfile_unlink(lp_pid_directory(), "smbd");
}
}
exit(0);
}
void smbd_exit_server(const char *const explanation)
{
exit_server_common(SERVER_EXIT_ABNORMAL, explanation);
}
void smbd_exit_server_cleanly(const char *const explanation)
{
exit_server_common(SERVER_EXIT_NORMAL, explanation);
}
/*
* reinit_after_fork() wrapper that should be called when forking from
* smbd.
*/
NTSTATUS smbd_reinit_after_fork(struct messaging_context *msg_ctx,
struct tevent_context *ev_ctx,
bool parent_longlived)
{
NTSTATUS ret;
am_parent = NULL;
ret = reinit_after_fork(msg_ctx, ev_ctx, parent_longlived);
initialize_password_db(true, ev_ctx);
return ret;
}