LCOV - code coverage report
Current view: top level - source4/samba - process_prefork.c (source / functions) Hit Total Coverage
Test: coverage report for recycleplus df22b230 Lines: 225 285 78.9 %
Date: 2024-02-14 10:14:15 Functions: 16 18 88.9 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    process model: prefork (n client connections per process)
       5             : 
       6             :    Copyright (C) Andrew Tridgell 1992-2005
       7             :    Copyright (C) James J Myers 2003 <myersjj@samba.org>
       8             :    Copyright (C) Stefan (metze) Metzmacher 2004
       9             :    Copyright (C) Andrew Bartlett 2008 <abartlet@samba.org>
      10             :    Copyright (C) David Disseldorp 2008 <ddiss@sgi.com>
      11             : 
      12             :    This program is free software; you can redistribute it and/or modify
      13             :    it under the terms of the GNU General Public License as published by
      14             :    the Free Software Foundation; either version 3 of the License, or
      15             :    (at your option) any later version.
      16             : 
      17             :    This program is distributed in the hope that it will be useful,
      18             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      19             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      20             :    GNU General Public License for more details.
      21             : 
      22             :    You should have received a copy of the GNU General Public License
      23             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      24             : */
      25             : /*
      26             :  * The pre-fork process model distributes the server workload amongst several
      27             :  * designated worker threads (e.g. 'prefork-worker-ldap-0',
      28             :  * 'prefork-worker-ldap-1', etc). The number of worker threads is controlled
      29             :  * by the 'prefork children' conf setting. The worker threads are controlled
      30             :  * by a prefork master process (e.g. 'prefork-master-ldap'). The prefork master
      31             :  * doesn't handle the server workload (i.e. processing messages) itself, but is
      32             :  * responsible for restarting workers if they exit unexpectedly. The top-level
      33             :  * samba process is responsible for restarting the master process if it exits.
      34             :  */
      35             : #include "includes.h"
      36             : #include <unistd.h>
      37             : 
      38             : #include "lib/events/events.h"
      39             : #include "lib/messaging/messaging.h"
      40             : #include "lib/socket/socket.h"
      41             : #include "samba/process_model.h"
      42             : #include "cluster/cluster.h"
      43             : #include "param/param.h"
      44             : #include "ldb_wrap.h"
      45             : #include "lib/util/tfork.h"
      46             : #include "lib/messaging/irpc.h"
      47             : #include "lib/util/util_process.h"
      48             : #include "server_util.h"
      49             : 
      50             : #define min(a, b) (((a) < (b)) ? (a) : (b))
      51             : 
      52             : NTSTATUS process_model_prefork_init(void);
      53             : static void prefork_new_task(
      54             :     struct tevent_context *ev,
      55             :     struct loadparm_context *lp_ctx,
      56             :     const char *service_name,
      57             :     struct task_server *(*new_task_fn)(struct tevent_context *,
      58             :                                        struct loadparm_context *lp_ctx,
      59             :                                        struct server_id,
      60             :                                        void *,
      61             :                                        void *),
      62             :     void *private_data,
      63             :     const struct service_details *service_details,
      64             :     int from_parent_fd);
      65             : static void prefork_fork_worker(struct task_server *task,
      66             :                                 struct tevent_context *ev,
      67             :                                 struct tevent_context *ev2,
      68             :                                 struct loadparm_context *lp_ctx,
      69             :                                 const struct service_details *service_details,
      70             :                                 const char *service_name,
      71             :                                 int control_pipe[2],
      72             :                                 unsigned restart_delay,
      73             :                                 struct process_details *pd);
      74             : static void prefork_child_pipe_handler(struct tevent_context *ev,
      75             :                                        struct tevent_fd *fde,
      76             :                                        uint16_t flags,
      77             :                                        void *private_data);
      78             : static void setup_handlers(struct tevent_context *ev,
      79             :                            struct loadparm_context *lp_ctx,
      80             :                            int from_parent_fd);
      81             : 
      82             : /*
      83             :  * State needed to restart the master process or a worker process if they
      84             :  * terminate early.
      85             :  */
      86             : struct master_restart_context {
      87             :         struct task_server *(*new_task_fn)(struct tevent_context *,
      88             :                                            struct loadparm_context *lp_ctx,
      89             :                                            struct server_id,
      90             :                                            void *,
      91             :                                            void *);
      92             :         void *private_data;
      93             : };
      94             : 
      95             : struct worker_restart_context {
      96             :         unsigned int instance;
      97             :         struct task_server *task;
      98             :         struct tevent_context *ev2;
      99             :         int control_pipe[2];
     100             : };
     101             : 
     102             : struct restart_context {
     103             :         struct loadparm_context *lp_ctx;
     104             :         struct tfork *t;
     105             :         int from_parent_fd;
     106             :         const struct service_details *service_details;
     107             :         const char *service_name;
     108             :         unsigned restart_delay;
     109             :         struct master_restart_context *master;
     110             :         struct worker_restart_context *worker;
     111             : };
     112             : 
     113           0 : static void sighup_signal_handler(struct tevent_context *ev,
     114             :                                 struct tevent_signal *se,
     115             :                                 int signum, int count, void *siginfo,
     116             :                                 void *private_data)
     117             : {
     118           0 :         reopen_logs_internal();
     119           0 : }
     120             : 
     121          20 : static void sigterm_signal_handler(struct tevent_context *ev,
     122             :                                 struct tevent_signal *se,
     123             :                                 int signum, int count, void *siginfo,
     124             :                                 void *private_data)
     125             : {
     126             : #ifdef HAVE_GETPGRP
     127          20 :         if (getpgrp() == getpid()) {
     128             :                 /*
     129             :                  * We're the process group leader, send
     130             :                  * SIGTERM to our process group.
     131             :                  */
     132           0 :                 DBG_NOTICE("SIGTERM: killing children\n");
     133           0 :                 kill(-getpgrp(), SIGTERM);
     134             :         }
     135             : #endif
     136          20 :         DBG_NOTICE("Exiting pid %d on SIGTERM\n", getpid());
     137          20 :         TALLOC_FREE(ev);
     138          20 :         exit(127);
     139             : }
     140             : 
     141             : /*
     142             :   called when the process model is selected
     143             : */
     144          20 : static void prefork_model_init(void)
     145             : {
     146          20 : }
     147             : 
     148         580 : static void prefork_reload_after_fork(void)
     149             : {
     150             :         NTSTATUS status;
     151             : 
     152         580 :         ldb_wrap_fork_hook();
     153             :         /* Must be done after a fork() to reset messaging contexts. */
     154         580 :         status = imessaging_reinit_all();
     155         580 :         if (!NT_STATUS_IS_OK(status)) {
     156           0 :                 smb_panic("Failed to re-initialise imessaging after fork");
     157             :         }
     158         580 :         force_check_log_size();
     159         580 : }
     160             : 
     161             : /*
     162             :  * clean up any messaging associated with the old process.
     163             :  *
     164             :  */
     165         581 : static void irpc_cleanup(
     166             :         struct loadparm_context *lp_ctx,
     167             :         struct tevent_context *ev,
     168             :         pid_t pid)
     169             : {
     170         581 :         TALLOC_CTX *mem_ctx = talloc_new(NULL);
     171         581 :         struct imessaging_context *msg_ctx = NULL;
     172         581 :         NTSTATUS status = NT_STATUS_OK;
     173             : 
     174         581 :         if (mem_ctx == NULL) {
     175           0 :                 DBG_ERR("OOM cleaning up irpc\n");
     176           0 :                 return;
     177             :         }
     178         581 :         msg_ctx = imessaging_client_init(mem_ctx, lp_ctx, ev);
     179         581 :         if (msg_ctx == NULL) {
     180           0 :                 DBG_ERR("Unable to create imessaging_context\n");
     181           0 :                 TALLOC_FREE(mem_ctx);
     182           0 :                 return;
     183             :         }
     184         581 :         status = imessaging_process_cleanup(msg_ctx, pid);
     185         581 :         if (!NT_STATUS_IS_OK(status)) {
     186           0 :                 DBG_ERR("imessaging_process_cleanup returned (%s)\n",
     187             :                         nt_errstr(status));
     188           0 :                 TALLOC_FREE(mem_ctx);
     189           0 :                 return;
     190             :         }
     191             : 
     192         581 :         TALLOC_FREE(mem_ctx);
     193             : }
     194             : 
     195             : /*
     196             :  * handle EOF on the parent-to-all-children pipe in the child, i.e.
     197             :  * the parent has died and its end of the pipe has been closed.
     198             :  * The child handles this by exiting as well.
     199             :  */
     200         560 : static void prefork_pipe_handler(struct tevent_context *event_ctx,
     201             :                                  struct tevent_fd *fde, uint16_t flags,
     202             :                                  void *private_data)
     203             : {
     204         560 :         struct loadparm_context *lp_ctx = NULL;
     205             :         pid_t pid;
     206             : 
     207             :         /*
     208             :          * free the fde which removes the event and stops it firing again
     209             :          */
     210         560 :         TALLOC_FREE(fde);
     211             : 
     212             :         /*
     213             :          * Clean up any irpc end points this process had.
     214             :          */
     215         560 :         pid = getpid();
     216         560 :         lp_ctx = talloc_get_type_abort(private_data, struct loadparm_context);
     217         560 :         irpc_cleanup(lp_ctx, event_ctx, pid);
     218             : 
     219         560 :         DBG_NOTICE("Child %d exiting\n", getpid());
     220         560 :         TALLOC_FREE(event_ctx);
     221         560 :         exit(0);
     222             : }
     223             : 
     224             : 
     225             : /*
     226             :  * Called by the top-level samba process to create a new prefork master process
     227             :  */
     228         286 : static void prefork_fork_master(
     229             :     struct tevent_context *ev,
     230             :     struct loadparm_context *lp_ctx,
     231             :     const char *service_name,
     232             :     struct task_server *(*new_task_fn)(struct tevent_context *,
     233             :                                        struct loadparm_context *lp_ctx,
     234             :                                        struct server_id,
     235             :                                        void *,
     236             :                                        void *),
     237             :     void *private_data,
     238             :     const struct service_details *service_details,
     239             :     unsigned restart_delay,
     240             :     int from_parent_fd)
     241             : {
     242             :         pid_t pid;
     243         286 :         struct tfork* t = NULL;
     244             :         int i, num_children;
     245             : 
     246             :         struct tevent_context *ev2;
     247         286 :         struct task_server *task = NULL;
     248         286 :         struct process_details pd = initial_process_details;
     249         286 :         struct samba_tevent_trace_state *samba_tevent_trace_state = NULL;
     250             :         int control_pipe[2];
     251             : 
     252         286 :         t = tfork_create();
     253         572 :         if (t == NULL) {
     254           0 :                 smb_panic("failure in tfork\n");
     255             :         }
     256             : 
     257         572 :         DBG_NOTICE("Forking [%s] pre-fork master process\n", service_name);
     258         572 :         pid = tfork_child_pid(t);
     259         572 :         if (pid != 0) {
     260         286 :                 struct tevent_fd *fde = NULL;
     261         286 :                 int fd = tfork_event_fd(t);
     262         286 :                 struct restart_context *rc = NULL;
     263             : 
     264             :                 /* Register a pipe handler that gets called when the prefork
     265             :                  * master process terminates.
     266             :                  */
     267         286 :                 rc = talloc_zero(ev, struct restart_context);
     268         286 :                 if (rc == NULL) {
     269           0 :                         smb_panic("OOM allocating restart context\n");
     270             :                 }
     271         286 :                 rc->t = t;
     272         286 :                 rc->lp_ctx = lp_ctx;
     273         286 :                 rc->service_name = service_name;
     274         286 :                 rc->service_details = service_details;
     275         286 :                 rc->from_parent_fd = from_parent_fd;
     276         286 :                 rc->restart_delay = restart_delay;
     277         286 :                 rc->master = talloc_zero(rc, struct master_restart_context);
     278         286 :                 if (rc->master == NULL) {
     279           0 :                         smb_panic("OOM allocating master restart context\n");
     280             :                 }
     281             : 
     282         286 :                 rc->master->new_task_fn = new_task_fn;
     283         286 :                 rc->master->private_data = private_data;
     284             : 
     285         286 :                 fde = tevent_add_fd(
     286             :                     ev, ev, fd, TEVENT_FD_READ, prefork_child_pipe_handler, rc);
     287         286 :                 if (fde == NULL) {
     288           0 :                         smb_panic("Failed to add child pipe handler, "
     289             :                                   "after fork");
     290             :                 }
     291         286 :                 tevent_fd_set_auto_close(fde);
     292         286 :                 return;
     293             :         }
     294             : 
     295         286 :         pid = getpid();
     296             : 
     297         286 :         process_set_title("%s[master]", "task[%s] pre-fork master", service_name);
     298             : 
     299             :         /*
     300             :          * this will free all the listening sockets and all state that
     301             :          * is not associated with this new connection
     302             :          */
     303         286 :         if (tevent_re_initialise(ev) != 0) {
     304           0 :                 smb_panic("Failed to re-initialise tevent after fork");
     305             :         }
     306         286 :         prefork_reload_after_fork();
     307         286 :         setup_handlers(ev, lp_ctx, from_parent_fd);
     308             : 
     309         286 :         if (service_details->inhibit_pre_fork) {
     310         204 :                 task = new_task_fn(
     311             :                     ev, lp_ctx, cluster_id(pid, 0), private_data, NULL);
     312             :                 /*
     313             :                  * The task does not support pre-fork
     314             :                  */
     315         204 :                 if (task != NULL && service_details->post_fork != NULL) {
     316           0 :                         service_details->post_fork(task, &pd);
     317             :                 }
     318         204 :                 tevent_loop_wait(ev);
     319           0 :                 TALLOC_FREE(ev);
     320           0 :                 exit(0);
     321             :         }
     322             : 
     323             :         /*
     324             :          * This is now the child code. We need a completely new event_context
     325             :          * to work with
     326             :          */
     327          82 :         ev2 = s4_event_context_init(NULL);
     328             : 
     329          82 :         samba_tevent_trace_state = create_samba_tevent_trace_state(ev2);
     330          82 :         if (samba_tevent_trace_state == NULL) {
     331           0 :                 TALLOC_FREE(ev);
     332           0 :                 TALLOC_FREE(ev2);
     333           0 :                 exit(127);
     334             :         }
     335             : 
     336          82 :         tevent_set_trace_callback(ev2,
     337             :                                   samba_tevent_trace_callback,
     338             :                                   samba_tevent_trace_state);
     339             : 
     340             :         /* setup this new connection: process will bind to it's sockets etc
     341             :          *
     342             :          * While we can use ev for the child, which has been re-initialised
     343             :          * above we must run the new task under ev2 otherwise the children would
     344             :          * be listening on the sockets.  Also we don't want the top level
     345             :          * process accepting and handling requests, it's responsible for
     346             :          * monitoring and controlling the child work processes.
     347             :          */
     348          82 :         task = new_task_fn(ev2, lp_ctx, cluster_id(pid, 0), private_data, NULL);
     349          82 :         if (task == NULL) {
     350           0 :                 TALLOC_FREE(ev);
     351           0 :                 TALLOC_FREE(ev2);
     352           0 :                 exit(127);
     353             :         }
     354             : 
     355             :         /*
     356             :          * Register an irpc name that can be used by the samba-tool processes
     357             :          * command
     358             :          */
     359             :         {
     360          82 :                 struct talloc_ctx *ctx = talloc_new(NULL);
     361          82 :                 char *name = NULL;
     362          82 :                 if (ctx == NULL) {
     363           0 :                         DBG_ERR("Out of memory");
     364           0 :                         exit(127);
     365             :                 }
     366          82 :                 name = talloc_asprintf(ctx, "prefork-master-%s", service_name);
     367          82 :                 irpc_add_name(task->msg_ctx, name);
     368          82 :                 TALLOC_FREE(ctx);
     369             :         }
     370             : 
     371             :         {
     372             :                 int default_children;
     373          82 :                 default_children = lpcfg_prefork_children(lp_ctx);
     374          82 :                 num_children = lpcfg_parm_int(lp_ctx, NULL, "prefork children",
     375             :                                               service_name, default_children);
     376             :         }
     377          82 :         if (num_children == 0) {
     378           0 :                 DBG_WARNING("Number of pre-fork children for %s is zero, "
     379             :                             "NO worker processes will be started for %s\n",
     380             :                             service_name, service_name);
     381             :         }
     382          82 :         DBG_NOTICE("Forking %d %s worker processes\n",
     383             :                    num_children, service_name);
     384             : 
     385             :         /*
     386             :          * the prefork master creates its own control pipe, so the prefork
     387             :          * workers can detect if the master exits (in which case an EOF gets
     388             :          * written). (Whereas from_parent_fd is the control pipe from the
     389             :          * top-level process that the prefork master listens on)
     390             :          */
     391             :         {
     392             :                 int ret;
     393          82 :                 ret = pipe(control_pipe);
     394          82 :                 if (ret != 0) {
     395           0 :                         smb_panic("Unable to create worker control pipe\n");
     396             :                 }
     397          82 :                 smb_set_close_on_exec(control_pipe[0]);
     398          82 :                 smb_set_close_on_exec(control_pipe[1]);
     399             :         }
     400             : 
     401             :         /*
     402             :          * We are now free to spawn some worker processes
     403             :          */
     404         362 :         for (i=0; i < num_children; i++) {
     405         280 :                 prefork_fork_worker(task,
     406             :                                     ev,
     407             :                                     ev2,
     408             :                                     lp_ctx,
     409             :                                     service_details,
     410             :                                     service_name,
     411             :                                     control_pipe,
     412             :                                     0,
     413             :                                     &pd);
     414         280 :                 pd.instances++;
     415             :         }
     416             : 
     417             :         /* Don't listen on the sockets we just gave to the children */
     418          82 :         tevent_loop_wait(ev);
     419           0 :         TALLOC_FREE(ev);
     420             :         /* We need to keep ev2 until we're finished for the messaging to work */
     421           0 :         TALLOC_FREE(ev2);
     422           0 :         exit(0);
     423             : }
     424             : 
     425             : static void prefork_restart_fn(struct tevent_context *ev,
     426             :                                struct tevent_timer *te,
     427             :                                struct timeval tv,
     428             :                                void *private_data);
     429             : 
     430             : /*
     431             :  * Restarts a child process if it exits unexpectedly
     432             :  */
     433          21 : static bool prefork_restart(struct tevent_context *ev,
     434             :                             struct restart_context *rc)
     435             : {
     436          21 :         struct tevent_timer *te = NULL;
     437             : 
     438          21 :         if (rc->restart_delay > 0) {
     439           6 :                 DBG_ERR("Restarting [%s] pre-fork %s in (%d) seconds\n",
     440             :                         rc->service_name,
     441             :                         (rc->master == NULL) ? "worker" : "master",
     442             :                         rc->restart_delay);
     443             :         }
     444             : 
     445             :         /*
     446             :          * Always use an async timer event. If
     447             :          * rc->restart_delay is zero this is the
     448             :          * same as an immediate event and will be
     449             :          * called immediately we go back into the
     450             :          * event loop.
     451             :          */
     452          21 :         te = tevent_add_timer(ev,
     453             :                               ev,
     454             :                               tevent_timeval_current_ofs(rc->restart_delay, 0),
     455             :                               prefork_restart_fn,
     456             :                               rc);
     457          21 :         if (te == NULL) {
     458           0 :                 DBG_ERR("tevent_add_timer fail [%s] pre-fork event %s\n",
     459             :                         rc->service_name,
     460             :                         (rc->master == NULL) ? "worker" : "master");
     461             :                 /* Caller needs to free rc. */
     462           0 :                 return false;
     463             :         }
     464             :         /* Caller must not free rc - it's in use. */
     465          21 :         return true;
     466             : }
     467             : 
     468          21 : static void prefork_restart_fn(struct tevent_context *ev,
     469             :                                struct tevent_timer *te,
     470             :                                struct timeval tv,
     471             :                                void *private_data)
     472             : {
     473          21 :         unsigned max_backoff = 0;
     474          21 :         unsigned backoff = 0;
     475          21 :         unsigned default_value = 0;
     476          21 :         struct restart_context *rc = talloc_get_type(private_data,
     477             :                                         struct restart_context);
     478          21 :         unsigned restart_delay = rc->restart_delay;
     479             : 
     480          21 :         TALLOC_FREE(te);
     481             : 
     482             :         /*
     483             :          * If the child process is constantly exiting, then restarting it can
     484             :          * consume a lot of resources. In which case, we want to backoff a bit
     485             :          * before respawning it
     486             :          */
     487          21 :         default_value = lpcfg_prefork_backoff_increment(rc->lp_ctx);
     488          21 :         backoff = lpcfg_parm_int(rc->lp_ctx,
     489             :                                  NULL,
     490             :                                  "prefork backoff increment",
     491             :                                  rc->service_name,
     492             :                                  default_value);
     493             : 
     494          21 :         default_value = lpcfg_prefork_maximum_backoff(rc->lp_ctx);
     495          21 :         max_backoff = lpcfg_parm_int(rc->lp_ctx,
     496             :                                      NULL,
     497             :                                      "prefork maximum backoff",
     498             :                                      rc->service_name,
     499             :                                      default_value);
     500             : 
     501          21 :         restart_delay += backoff;
     502          21 :         restart_delay = min(restart_delay, max_backoff);
     503             : 
     504          21 :         if (rc->master != NULL) {
     505           6 :                 DBG_ERR("Restarting [%s] pre-fork master\n", rc->service_name);
     506           6 :                 prefork_fork_master(ev,
     507             :                                     rc->lp_ctx,
     508             :                                     rc->service_name,
     509           6 :                                     rc->master->new_task_fn,
     510           6 :                                     rc->master->private_data,
     511             :                                     rc->service_details,
     512             :                                     restart_delay,
     513             :                                     rc->from_parent_fd);
     514          15 :         } else if (rc->worker != NULL) {
     515          15 :                 struct process_details pd = initial_process_details;
     516          15 :                 DBG_ERR("Restarting [%s] pre-fork worker(%d)\n",
     517             :                         rc->service_name,
     518             :                         rc->worker->instance);
     519          15 :                 pd.instances = rc->worker->instance;
     520          15 :                 prefork_fork_worker(rc->worker->task,
     521             :                                     ev,
     522          15 :                                     rc->worker->ev2,
     523             :                                     rc->lp_ctx,
     524             :                                     rc->service_details,
     525             :                                     rc->service_name,
     526          15 :                                     rc->worker->control_pipe,
     527             :                                     restart_delay,
     528             :                                     &pd);
     529             :         }
     530             :         /* tfork allocates tfork structures with malloc */
     531          21 :         tfork_destroy(&rc->t);
     532          21 :         free(rc->t);
     533          21 :         TALLOC_FREE(rc);
     534          21 : }
     535             : 
     536             : /*
     537             :   handle EOF on the child pipe in the parent, so we know when a
     538             :   process terminates without using SIGCHLD or waiting on all possible pids.
     539             : 
     540             :   We need to ensure we do not ignore SIGCHLD because we need it to
     541             :   work to get a valid error code from samba_runcmd_*().
     542             :  */
     543          21 : static void prefork_child_pipe_handler(struct tevent_context *ev,
     544             :                                        struct tevent_fd *fde,
     545             :                                        uint16_t flags,
     546             :                                        void *private_data)
     547             : {
     548          21 :         struct restart_context *rc = NULL;
     549          21 :         int status = 0;
     550          21 :         pid_t pid = 0;
     551          21 :         bool rc_inuse = false;
     552             : 
     553             :         /* free the fde which removes the event and stops it firing again */
     554          21 :         TALLOC_FREE(fde);
     555             : 
     556             :         /* the child has closed the pipe, assume its dead */
     557             : 
     558          21 :         rc = talloc_get_type_abort(private_data, struct restart_context);
     559          21 :         pid = tfork_child_pid(rc->t);
     560          21 :         errno = 0;
     561             : 
     562          21 :         irpc_cleanup(rc->lp_ctx, ev, pid);
     563          21 :         status = tfork_status(&rc->t, false);
     564          21 :         if (status == -1) {
     565           0 :                 DBG_ERR("Parent %d, Child %d terminated, "
     566             :                         "unable to get status code from tfork\n",
     567             :                         getpid(), pid);
     568           0 :                 rc_inuse = prefork_restart(ev, rc);
     569          21 :         } else if (WIFEXITED(status)) {
     570          20 :                 status = WEXITSTATUS(status);
     571          20 :                 DBG_ERR("Parent %d, Child %d exited with status %d\n",
     572             :                          getpid(), pid,  status);
     573          20 :                 if (status != 0) {
     574          20 :                         rc_inuse = prefork_restart(ev, rc);
     575             :                 }
     576           1 :         } else if (WIFSIGNALED(status)) {
     577           1 :                 status = WTERMSIG(status);
     578           1 :                 DBG_ERR("Parent %d, Child %d terminated with signal %d\n",
     579             :                         getpid(), pid, status);
     580           1 :                 if (status == SIGABRT || status == SIGBUS || status == SIGFPE ||
     581           0 :                     status == SIGILL || status == SIGSYS || status == SIGSEGV ||
     582             :                     status == SIGKILL) {
     583             : 
     584           1 :                         rc_inuse = prefork_restart(ev, rc);
     585             :                 }
     586             :         }
     587          21 :         if (!rc_inuse) {
     588             :                 /* tfork allocates tfork structures with malloc */
     589           0 :                 tfork_destroy(&rc->t);
     590           0 :                 free(rc->t);
     591           0 :                 TALLOC_FREE(rc);
     592             :         }
     593          21 :         return;
     594             : }
     595             : 
     596             : /*
     597             :   called when a listening socket becomes readable.
     598             : */
     599       30392 : static void prefork_accept_connection(
     600             :         struct tevent_context *ev,
     601             :         struct loadparm_context *lp_ctx,
     602             :         struct socket_context *listen_socket,
     603             :         void (*new_conn)(struct tevent_context *,
     604             :                         struct loadparm_context *,
     605             :                         struct socket_context *,
     606             :                         struct server_id,
     607             :                         void *,
     608             :                         void *),
     609             :         void *private_data,
     610             :         void *process_context)
     611             : {
     612             :         NTSTATUS status;
     613             :         struct socket_context *connected_socket;
     614       30392 :         pid_t pid = getpid();
     615             : 
     616             :         /* accept an incoming connection. */
     617       30392 :         status = socket_accept(listen_socket, &connected_socket);
     618       30392 :         if (!NT_STATUS_IS_OK(status)) {
     619             :                 /*
     620             :                  * For prefork we can ignore STATUS_MORE_ENTRIES, as  once a
     621             :                  * connection becomes available all waiting processes are
     622             :                  * woken, but only one gets work to  process.
     623             :                  * AKA the thundering herd.
     624             :                  * In the short term this should not be an issue as the number
     625             :                  * of workers should be a small multiple of the number of cpus
     626             :                  * In the longer term socket_accept needs to implement a
     627             :                  * mutex/semaphore (like apache does) to serialise the accepts
     628             :                  */
     629       11051 :                 if (!NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
     630           0 :                         DBG_ERR("Worker process (%d), error in accept [%s]\n",
     631             :                                 getpid(), nt_errstr(status));
     632             :                 }
     633       11051 :                 return;
     634             :         }
     635             : 
     636       19341 :         talloc_steal(private_data, connected_socket);
     637             : 
     638       19341 :         new_conn(ev, lp_ctx, connected_socket,
     639       19341 :                  cluster_id(pid, socket_get_fd(connected_socket)),
     640             :                  private_data, process_context);
     641             : }
     642             : 
     643         580 : static void setup_handlers(
     644             :         struct tevent_context *ev,
     645             :         struct loadparm_context *lp_ctx,
     646             :         int from_parent_fd)
     647             : {
     648         580 :         struct tevent_fd *fde = NULL;
     649         580 :         struct tevent_signal *se = NULL;
     650             : 
     651         580 :         fde = tevent_add_fd(ev, ev, from_parent_fd, TEVENT_FD_READ,
     652             :                       prefork_pipe_handler, lp_ctx);
     653         580 :         if (fde == NULL) {
     654           0 :                 smb_panic("Failed to add fd handler after fork");
     655             :         }
     656             : 
     657         580 :         se = tevent_add_signal(ev,
     658             :                                ev,
     659             :                                SIGHUP,
     660             :                                0,
     661             :                                sighup_signal_handler,
     662             :                                NULL);
     663         580 :         if (se == NULL) {
     664           0 :                 smb_panic("Failed to add SIGHUP handler after fork");
     665             :         }
     666             : 
     667         580 :         se = tevent_add_signal(ev,
     668             :                                ev,
     669             :                                SIGTERM,
     670             :                                0,
     671             :                                sigterm_signal_handler,
     672             :                                NULL);
     673         580 :         if (se == NULL) {
     674           0 :                 smb_panic("Failed to add SIGTERM handler after fork");
     675             :         }
     676         580 : }
     677             : 
     678             : /*
     679             :  * Called by the prefork master to create a new prefork worker process
     680             :  */
     681         295 : static void prefork_fork_worker(struct task_server *task,
     682             :                                 struct tevent_context *ev,
     683             :                                 struct tevent_context *ev2,
     684             :                                 struct loadparm_context *lp_ctx,
     685             :                                 const struct service_details *service_details,
     686             :                                 const char *service_name,
     687             :                                 int control_pipe[2],
     688             :                                 unsigned restart_delay,
     689             :                                 struct process_details *pd)
     690             : {
     691         295 :         struct tfork *w = NULL;
     692             :         pid_t pid;
     693             : 
     694         295 :         w = tfork_create();
     695         589 :         if (w == NULL) {
     696           0 :                 smb_panic("failure in tfork\n");
     697             :         }
     698             : 
     699         589 :         pid = tfork_child_pid(w);
     700         589 :         if (pid != 0) {
     701         295 :                 struct tevent_fd *fde = NULL;
     702         295 :                 int fd = tfork_event_fd(w);
     703         295 :                 struct restart_context *rc = NULL;
     704             : 
     705             :                 /*
     706             :                  * we're the parent (prefork master), so store enough info to
     707             :                  * restart the worker/child if it exits unexpectedly
     708             :                  */
     709         295 :                 rc = talloc_zero(ev, struct restart_context);
     710         295 :                 if (rc == NULL) {
     711           0 :                         smb_panic("OOM allocating restart context\n");
     712             :                 }
     713         295 :                 rc->t = w;
     714         295 :                 rc->lp_ctx = lp_ctx;
     715         295 :                 rc->service_name = service_name;
     716         295 :                 rc->service_details = service_details;
     717         295 :                 rc->restart_delay = restart_delay;
     718         295 :                 rc->master = NULL;
     719         295 :                 rc->worker = talloc_zero(rc, struct worker_restart_context);
     720         295 :                 if (rc->worker == NULL) {
     721           0 :                         smb_panic("OOM allocating master restart context\n");
     722             :                 }
     723         295 :                 rc->worker->ev2 = ev2;
     724         295 :                 rc->worker->instance = pd->instances;
     725         295 :                 rc->worker->task = task;
     726         295 :                 rc->worker->control_pipe[0] = control_pipe[0];
     727         295 :                 rc->worker->control_pipe[1] = control_pipe[1];
     728             : 
     729         295 :                 fde = tevent_add_fd(
     730             :                     ev, ev, fd, TEVENT_FD_READ, prefork_child_pipe_handler, rc);
     731         295 :                 if (fde == NULL) {
     732           0 :                         smb_panic("Failed to add child pipe handler, "
     733             :                                   "after fork");
     734             :                 }
     735         295 :                 tevent_fd_set_auto_close(fde);
     736             :         } else {
     737             : 
     738             :                 /*
     739             :                  * we're the child (prefork-worker). We never write to the
     740             :                  * control pipe, but listen on the read end in case our parent
     741             :                  * (the pre-fork master) exits
     742             :                  */
     743         294 :                 close(control_pipe[1]);
     744         294 :                 setup_handlers(ev2, lp_ctx, control_pipe[0]);
     745             : 
     746             :                 /*
     747             :                  * tfork uses malloc
     748             :                  */
     749         294 :                 free(w);
     750             : 
     751         294 :                 TALLOC_FREE(ev);
     752             : 
     753         294 :                 process_set_title("%s(%d)",
     754             :                                   "task[%s] pre-forked worker(%d)",
     755             :                                   service_name,
     756             :                                   pd->instances);
     757             : 
     758         294 :                 prefork_reload_after_fork();
     759         294 :                 if (service_details->post_fork != NULL) {
     760         206 :                         service_details->post_fork(task, pd);
     761             :                 }
     762             :                 {
     763         294 :                         struct talloc_ctx *ctx = talloc_new(NULL);
     764         294 :                         char *name = NULL;
     765         294 :                         if (ctx == NULL) {
     766           0 :                                 smb_panic("OOM allocating talloc context\n");
     767             :                         }
     768         294 :                         name = talloc_asprintf(ctx,
     769             :                                                "prefork-worker-%s-%d",
     770             :                                                service_name,
     771             :                                                pd->instances);
     772         294 :                         irpc_add_name(task->msg_ctx, name);
     773         294 :                         TALLOC_FREE(ctx);
     774             :                 }
     775         294 :                 tevent_loop_wait(ev2);
     776           0 :                 talloc_free(ev2);
     777           0 :                 exit(0);
     778             :         }
     779         295 : }
     780             : /*
     781             :  * called to create a new server task
     782             :  */
     783         280 : static void prefork_new_task(
     784             :         struct tevent_context *ev,
     785             :         struct loadparm_context *lp_ctx,
     786             :         const char *service_name,
     787             :         struct task_server *(*new_task_fn)(struct tevent_context *,
     788             :                             struct loadparm_context *lp_ctx,
     789             :                             struct server_id , void *, void *),
     790             :         void *private_data,
     791             :         const struct service_details *service_details,
     792             :         int from_parent_fd)
     793             : {
     794         280 :         prefork_fork_master(ev,
     795             :                             lp_ctx,
     796             :                             service_name,
     797             :                             new_task_fn,
     798             :                             private_data,
     799             :                             service_details,
     800             :                             0,
     801             :                             from_parent_fd);
     802             : 
     803         280 : }
     804             : 
     805             : /*
     806             :  * called when a task terminates
     807             :  */
     808           0 : static void prefork_terminate_task(struct tevent_context *ev,
     809             :                                    struct loadparm_context *lp_ctx,
     810             :                                    const char *reason,
     811             :                                    bool fatal,
     812             :                                    void *process_context)
     813             : {
     814           0 :         DBG_DEBUG("called with reason[%s]\n", reason);
     815           0 :         TALLOC_FREE(ev);
     816           0 :         if (fatal == true) {
     817           0 :                 exit(127);
     818             :         } else {
     819           0 :                 exit(0);
     820             :         }
     821             : }
     822             : 
     823             : /*
     824             :  * called when a connection completes
     825             :  */
     826       19339 : static void prefork_terminate_connection(struct tevent_context *ev,
     827             :                                          struct loadparm_context *lp_ctx,
     828             :                                          const char *reason,
     829             :                                          void *process_context)
     830             : {
     831       19339 : }
     832             : 
     833             : /* called to set a title of a task or connection */
     834       19627 : static void prefork_set_title(struct tevent_context *ev, const char *title)
     835             : {
     836       19627 : }
     837             : 
     838             : static const struct model_ops prefork_ops = {
     839             :         .name                   = "prefork",
     840             :         .model_init             = prefork_model_init,
     841             :         .accept_connection      = prefork_accept_connection,
     842             :         .new_task               = prefork_new_task,
     843             :         .terminate_task         = prefork_terminate_task,
     844             :         .terminate_connection   = prefork_terminate_connection,
     845             :         .set_title              = prefork_set_title,
     846             : };
     847             : 
     848             : /*
     849             :  * initialise the prefork process model, registering ourselves with the
     850             :  * process model subsystem
     851             :  */
     852          57 : NTSTATUS process_model_prefork_init(void)
     853             : {
     854          57 :         return register_process_model(&prefork_ops);
     855             : }

Generated by: LCOV version 1.14