summaryrefslogtreecommitdiff
path: root/source3/smbd
diff options
context:
space:
mode:
authorVolker Lendecke <vlendec@samba.org>2006-08-16 10:36:19 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 11:38:39 -0500
commit0be131725ff90e48d4f9696b80b35b740575fb2c (patch)
tree4720d524c85b85a12277c6a3e34900f9f894b00d /source3/smbd
parent5615d534595013eb8749037d16efd726e728c330 (diff)
downloadsamba-0be131725ff90e48d4f9696b80b35b740575fb2c.tar.gz
samba-0be131725ff90e48d4f9696b80b35b740575fb2c.tar.bz2
samba-0be131725ff90e48d4f9696b80b35b740575fb2c.zip
r17569: Make 'max smbd processes' more robust. Counting on the child to decrement a
tdb entry is not the most reliable way to count children correctly. This increments the number of children after a fork and decrements it upon SIGCLD. I'm keeping a list of children just for consistency checks, so that we at least get a debug level 0 message if something goes wrong. Volker (This used to be commit eb45de167d24d07a218307ec5a48c0029ec097c6)
Diffstat (limited to 'source3/smbd')
-rw-r--r--source3/smbd/process.c58
-rw-r--r--source3/smbd/server.c100
2 files changed, 78 insertions, 80 deletions
diff --git a/source3/smbd/process.c b/source3/smbd/process.c
index f8c66d93ea..a202c1fa87 100644
--- a/source3/smbd/process.c
+++ b/source3/smbd/process.c
@@ -1032,60 +1032,6 @@ static int construct_reply(char *inbuf,char *outbuf,int size,int bufsize)
}
/****************************************************************************
- Keep track of the number of running smbd's. This functionality is used to
- 'hard' limit Samba overhead on resource constrained systems.
-****************************************************************************/
-
-static BOOL process_count_update_successful = False;
-
-static int32 increment_smbd_process_count(void)
-{
- int32 total_smbds;
-
- if (lp_max_smbd_processes()) {
- total_smbds = 0;
- if (tdb_change_int32_atomic(conn_tdb_ctx(), "INFO/total_smbds", &total_smbds, 1) == -1)
- return 1;
- process_count_update_successful = True;
- return total_smbds + 1;
- }
- return 1;
-}
-
-void decrement_smbd_process_count(void)
-{
- int32 total_smbds;
-
- if (lp_max_smbd_processes() && process_count_update_successful) {
- total_smbds = 1;
- tdb_change_int32_atomic(conn_tdb_ctx(), "INFO/total_smbds", &total_smbds, -1);
- }
-}
-
-static BOOL smbd_process_limit(void)
-{
- int32 total_smbds;
-
- if (lp_max_smbd_processes()) {
-
- /* Always add one to the smbd process count, as exit_server() always
- * subtracts one.
- */
-
- if (!conn_tdb_ctx()) {
- DEBUG(0,("smbd_process_limit: max smbd processes parameter set with status parameter not \
-set. Ignoring max smbd restriction.\n"));
- return False;
- }
-
- total_smbds = increment_smbd_process_count();
- return total_smbds > lp_max_smbd_processes();
- }
- else
- return False;
-}
-
-/****************************************************************************
Process an smb from the client
****************************************************************************/
@@ -1103,8 +1049,8 @@ static void process_smb(char *inbuf, char *outbuf)
deny parameters before doing any parsing of the packet
passed to us by the client. This prevents attacks on our
parsing code from hosts not in the hosts allow list */
- if (smbd_process_limit() ||
- !check_access(smbd_server_fd(), lp_hostsallow(-1), lp_hostsdeny(-1))) {
+ if (!check_access(smbd_server_fd(), lp_hostsallow(-1),
+ lp_hostsdeny(-1))) {
/* send a negative session response "not listening on calling name" */
static unsigned char buf[5] = {0x83, 0, 0, 1, 0x81};
DEBUG( 1, ( "Connection denied from %s\n", client_addr() ) );
diff --git a/source3/smbd/server.c b/source3/smbd/server.c
index edde12465f..460e2cc44b 100644
--- a/source3/smbd/server.c
+++ b/source3/smbd/server.c
@@ -36,6 +36,7 @@ extern struct auth_context *negprot_global_auth_context;
extern pstring user_socket_options;
extern SIG_ATOMIC_T got_sig_term;
extern SIG_ATOMIC_T reload_after_sighup;
+static SIG_ATOMIC_T got_sig_cld;
#ifdef WITH_DFS
extern int dcelogin_atmost_once;
@@ -93,6 +94,15 @@ static void sig_hup(int sig)
}
/****************************************************************************
+ Catch a sigcld
+****************************************************************************/
+static void sig_cld(int sig)
+{
+ got_sig_cld = 1;
+ sys_select_signal(SIGCLD);
+}
+
+/****************************************************************************
Send a SIGTERM to our process group.
*****************************************************************************/
@@ -189,6 +199,54 @@ static void msg_inject_fault(int msg_type, struct process_id src,
}
#endif /* DEVELOPER */
+struct child_pid {
+ struct child_pid *prev, *next;
+ pid_t pid;
+};
+
+static struct child_pid *children;
+static int num_children;
+
+static void add_child_pid(pid_t pid)
+{
+ struct child_pid *child;
+
+ if (lp_max_smbd_processes() == 0) {
+ /* Don't bother with the child list if we don't care anyway */
+ return;
+ }
+
+ child = SMB_MALLOC_P(struct child_pid);
+ if (child == NULL) {
+ DEBUG(0, ("Could not add child struct -- malloc failed\n"));
+ return;
+ }
+ child->pid = pid;
+ DLIST_ADD(children, child);
+ num_children += 1;
+}
+
+static void remove_child_pid(pid_t pid)
+{
+ struct child_pid *child;
+
+ if (lp_max_smbd_processes() == 0) {
+ /* Don't bother with the child list if we don't care anyway */
+ return;
+ }
+
+ for (child = children; child != NULL; child = child->next) {
+ if (child->pid == pid) {
+ struct child_pid *tmp = child;
+ DLIST_REMOVE(children, child);
+ SAFE_FREE(tmp);
+ num_children -= 1;
+ return;
+ }
+ }
+
+ DEBUG(0, ("Could not find child %d -- ignoring\n", (int)pid));
+}
/****************************************************************************
Have we reached the process limit ?
@@ -201,27 +259,7 @@ static BOOL allowable_number_of_smbd_processes(void)
if (!max_processes)
return True;
- {
- TDB_CONTEXT *tdb = conn_tdb_ctx();
- int32 val;
- if (!tdb) {
- DEBUG(0,("allowable_number_of_smbd_processes: can't open connection tdb.\n" ));
- return False;
- }
-
- val = tdb_fetch_int32(tdb, "INFO/total_smbds");
- if (val == -1 && (tdb_error(tdb) != TDB_ERR_NOEXIST)) {
- DEBUG(0,("allowable_number_of_smbd_processes: can't fetch INFO/total_smbds. Error %s\n",
- tdb_errorstr(tdb) ));
- return False;
- }
- if (val > max_processes) {
- DEBUG(0,("allowable_number_of_smbd_processes: number of processes (%d) is over allowed limit (%d)\n",
- val, max_processes ));
- return False;
- }
- }
- return True;
+ return num_children < max_processes;
}
/****************************************************************************
@@ -255,7 +293,7 @@ static BOOL open_sockets_smbd(BOOL is_daemon, BOOL interactive, const char *smb_
#endif
/* Stop zombies */
- CatchChild();
+ CatchSignal(SIGCLD, sig_cld);
FD_ZERO(&listen_set);
@@ -392,6 +430,15 @@ static BOOL open_sockets_smbd(BOOL is_daemon, BOOL interactive, const char *smb_
/* Ensure we respond to PING and DEBUG messages from the main smbd. */
message_dispatch();
+ if (got_sig_cld) {
+ pid_t pid;
+ got_sig_cld = False;
+
+ while ((pid = sys_waitpid(-1, NULL, WNOHANG)) > 0) {
+ remove_child_pid(pid);
+ }
+ }
+
memcpy((char *)&lfds, (char *)&listen_set,
sizeof(listen_set));
@@ -421,6 +468,7 @@ static BOOL open_sockets_smbd(BOOL is_daemon, BOOL interactive, const char *smb_
for( ; num > 0; num--) {
struct sockaddr addr;
socklen_t in_addrlen = sizeof(addr);
+ pid_t child = 0;
s = -1;
for(i = 0; i < num_sockets; i++) {
@@ -451,7 +499,8 @@ static BOOL open_sockets_smbd(BOOL is_daemon, BOOL interactive, const char *smb_
return True;
if (allowable_number_of_smbd_processes() &&
- smbd_server_fd() != -1 && sys_fork()==0) {
+ smbd_server_fd() != -1 &&
+ ((child = sys_fork())==0)) {
/* Child code ... */
/* close the listening socket(s) */
@@ -499,6 +548,10 @@ static BOOL open_sockets_smbd(BOOL is_daemon, BOOL interactive, const char *smb_
smbd_set_server_fd(-1);
+ if (child != 0) {
+ add_child_pid(child);
+ }
+
/* Force parent to check log size after
* spawning child. Fix from
* klausr@ITAP.Physik.Uni-Stuttgart.De. The
@@ -640,7 +693,6 @@ static void exit_server_common(enum server_exit_reason how,
yield_connection(NULL,"");
respond_to_all_remaining_local_messages();
- decrement_smbd_process_count();
#ifdef WITH_DFS
if (dcelogin_atmost_once) {