2011-08-12 23:24:17 +04:00
/*
Unix SMB / Netbios implementation .
Prefork Helpers
Copyright ( C ) Simo Sorce < idra @ samba . org > 2011
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 "lib/server_prefork.h"
# include "lib/server_prefork_util.h"
void pfh_daemon_config ( const char * daemon_name ,
struct pf_daemon_config * cfg ,
struct pf_daemon_config * default_cfg )
{
int min , max , rate , allow , life ;
min = lp_parm_int ( GLOBAL_SECTION_SNUM ,
daemon_name ,
" prefork_min_children " ,
default_cfg - > min_children ) ;
max = lp_parm_int ( GLOBAL_SECTION_SNUM ,
daemon_name ,
" prefork_max_children " ,
default_cfg - > max_children ) ;
rate = lp_parm_int ( GLOBAL_SECTION_SNUM ,
daemon_name ,
" prefork_spawn_rate " ,
default_cfg - > spawn_rate ) ;
allow = lp_parm_int ( GLOBAL_SECTION_SNUM ,
daemon_name ,
" prefork_max_allowed_clients " ,
default_cfg - > max_allowed_clients ) ;
life = lp_parm_int ( GLOBAL_SECTION_SNUM ,
daemon_name ,
" prefork_child_min_life " ,
default_cfg - > child_min_life ) ;
if ( max > cfg - > max_children & & cfg - > max_children ! = 0 ) {
cfg - > prefork_status | = PFH_NEW_MAX ;
}
cfg - > min_children = min ;
cfg - > max_children = max ;
cfg - > spawn_rate = rate ;
cfg - > max_allowed_clients = allow ;
cfg - > child_min_life = life ;
}
void pfh_manage_pool ( struct tevent_context * ev_ctx ,
struct messaging_context * msg_ctx ,
struct pf_daemon_config * cfg ,
struct prefork_pool * pool )
{
time_t now = time ( NULL ) ;
2011-08-17 02:20:51 +04:00
int total , avail ;
2011-08-12 23:24:17 +04:00
int ret , n ;
2011-08-17 23:21:12 +04:00
bool msg = false ;
2011-08-12 23:24:17 +04:00
if ( ( cfg - > prefork_status & PFH_NEW_MAX ) & &
! ( cfg - > prefork_status & PFH_ENOSPC ) ) {
ret = prefork_expand_pool ( pool , cfg - > max_children ) ;
if ( ret = = ENOSPC ) {
cfg - > prefork_status | = PFH_ENOSPC ;
}
cfg - > prefork_status & = ~ PFH_NEW_MAX ;
}
2011-08-17 02:20:51 +04:00
total = prefork_count_children ( pool , NULL ) ;
avail = prefork_count_allowed_connections ( pool ) ;
DEBUG ( 10 , ( " (Pre)Stats: children: %d, allowed connections: %d \n " ,
total , avail ) ) ;
2011-08-12 23:24:17 +04:00
2011-08-17 02:20:51 +04:00
if ( ( total < cfg - > max_children ) & & ( avail < cfg - > spawn_rate ) ) {
2011-08-12 23:24:17 +04:00
n = prefork_add_children ( ev_ctx , msg_ctx ,
pool , cfg - > spawn_rate ) ;
if ( n < cfg - > spawn_rate ) {
2011-08-17 02:20:51 +04:00
DEBUG ( 10 , ( " Attempted to add %d children but only "
" %d were actually added! \n " ,
2011-08-12 23:24:17 +04:00
cfg - > spawn_rate , n ) ) ;
}
2011-08-17 02:20:51 +04:00
} else if ( ( avail - cfg - > min_children ) > = cfg - > spawn_rate ) {
/* be a little slower in retiring children, to allow for
* double spikes of traffic to be handled more gracefully */
n = ( cfg - > spawn_rate / 2 ) + 1 ;
if ( n > cfg - > spawn_rate ) {
n = cfg - > spawn_rate ;
}
if ( ( total - n ) < cfg - > min_children ) {
n = total - cfg - > min_children ;
}
if ( n > = 0 ) {
2011-08-18 18:31:36 +04:00
prefork_retire_children ( msg_ctx , pool , n ,
2011-08-12 23:24:17 +04:00
now - cfg - > child_min_life ) ;
}
}
2011-08-17 02:20:51 +04:00
/* total/avail may have just been changed in the above if/else */
total = prefork_count_children ( pool , NULL ) ;
avail = prefork_count_allowed_connections ( pool ) ;
if ( ( total = = cfg - > max_children ) & & ( avail < cfg - > spawn_rate ) ) {
n = avail ;
while ( avail < cfg - > spawn_rate ) {
2011-08-12 23:24:17 +04:00
prefork_increase_allowed_clients ( pool ,
cfg - > max_allowed_clients ) ;
2011-08-17 02:20:51 +04:00
avail = prefork_count_allowed_connections ( pool ) ;
/* if avail didn't change do not loop forever */
if ( n = = avail ) break ;
n = avail ;
}
2011-08-17 23:21:12 +04:00
msg = true ;
2011-08-17 02:20:51 +04:00
} else if ( avail > total + cfg - > spawn_rate ) {
n = avail ;
while ( avail > total + cfg - > spawn_rate ) {
2011-08-12 23:24:17 +04:00
prefork_decrease_allowed_clients ( pool ) ;
2011-08-17 02:20:51 +04:00
avail = prefork_count_allowed_connections ( pool ) ;
/* if avail didn't change do not loop forever */
if ( n = = avail ) break ;
n = avail ;
}
2011-08-12 23:24:17 +04:00
}
2011-08-17 23:21:12 +04:00
/* send message to all children when we change maximum allowed
* connections , so that they can decide to start again to listen to
* sockets if they were already topping the number of allowed
* clients . Useful only when we increase allowed clients */
if ( msg ) {
prefork_warn_active_children ( msg_ctx , pool ) ;
}
2011-08-12 23:24:17 +04:00
DEBUG ( 10 , ( " Stats: children: %d, allowed connections: %d \n " ,
2011-08-17 02:20:51 +04:00
prefork_count_children ( pool , NULL ) ,
prefork_count_allowed_connections ( pool ) ) ) ;
2011-08-12 23:24:17 +04:00
}
2011-08-16 19:09:20 +04:00
void pfh_client_terminated ( struct pf_worker_data * pf )
{
if ( pf - > num_clients > = 0 ) {
pf - > num_clients - - ;
} else {
if ( pf - > status ! = PF_WORKER_EXITING ) {
DEBUG ( 1 , ( " Invalid num clients, stopping! \n " ) ) ;
}
pf - > status = PF_WORKER_EXITING ;
pf - > num_clients = - 1 ;
}
}
bool pfh_child_allowed_to_accept ( struct pf_worker_data * pf )
{
if ( pf - > status = = PF_WORKER_EXITING | |
pf - > status = = PF_WORKER_ACCEPTING ) {
return false ;
}
return ( pf - > num_clients < pf - > allowed_clients ) ;
}