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 28 : static void prefork_model_init(void)
145 : {
146 28 : }
147 :
148 808 : static void prefork_reload_after_fork(void)
149 : {
150 60 : NTSTATUS status;
151 :
152 808 : ldb_wrap_fork_hook();
153 : /* Must be done after a fork() to reset messaging contexts. */
154 808 : status = imessaging_reinit_all();
155 808 : if (!NT_STATUS_IS_OK(status)) {
156 0 : smb_panic("Failed to re-initialise imessaging after fork");
157 : }
158 808 : force_check_log_size();
159 808 : }
160 :
161 : /*
162 : * clean up any messaging associated with the old process.
163 : *
164 : */
165 809 : static void irpc_cleanup(
166 : struct loadparm_context *lp_ctx,
167 : struct tevent_context *ev,
168 : pid_t pid)
169 : {
170 809 : TALLOC_CTX *mem_ctx = talloc_new(NULL);
171 809 : struct imessaging_context *msg_ctx = NULL;
172 809 : NTSTATUS status = NT_STATUS_OK;
173 :
174 809 : if (mem_ctx == NULL) {
175 0 : DBG_ERR("OOM cleaning up irpc\n");
176 0 : return;
177 : }
178 809 : msg_ctx = imessaging_client_init(mem_ctx, lp_ctx, ev);
179 809 : 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 809 : status = imessaging_process_cleanup(msg_ctx, pid);
185 809 : 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 809 : 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 788 : static void prefork_pipe_handler(struct tevent_context *event_ctx,
201 : struct tevent_fd *fde, uint16_t flags,
202 : void *private_data)
203 : {
204 788 : struct loadparm_context *lp_ctx = NULL;
205 60 : pid_t pid;
206 :
207 : /*
208 : * free the fde which removes the event and stops it firing again
209 : */
210 788 : TALLOC_FREE(fde);
211 :
212 : /*
213 : * Clean up any irpc end points this process had.
214 : */
215 788 : pid = getpid();
216 788 : lp_ctx = talloc_get_type_abort(private_data, struct loadparm_context);
217 788 : irpc_cleanup(lp_ctx, event_ctx, pid);
218 :
219 788 : DBG_NOTICE("Child %d exiting\n", getpid());
220 788 : TALLOC_FREE(event_ctx);
221 788 : exit(0);
222 : }
223 :
224 :
225 : /*
226 : * Called by the top-level samba process to create a new prefork master process
227 : */
228 398 : 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 28 : pid_t pid;
243 398 : struct tfork* t = NULL;
244 28 : int i, num_children;
245 :
246 28 : struct tevent_context *ev2;
247 398 : struct task_server *task = NULL;
248 398 : struct process_details pd = initial_process_details;
249 398 : struct samba_tevent_trace_state *samba_tevent_trace_state = NULL;
250 28 : int control_pipe[2];
251 :
252 398 : t = tfork_create();
253 796 : if (t == NULL) {
254 0 : smb_panic("failure in tfork\n");
255 : }
256 :
257 796 : DBG_NOTICE("Forking [%s] pre-fork master process\n", service_name);
258 796 : pid = tfork_child_pid(t);
259 796 : if (pid != 0) {
260 398 : struct tevent_fd *fde = NULL;
261 398 : int fd = tfork_event_fd(t);
262 398 : struct restart_context *rc = NULL;
263 :
264 : /* Register a pipe handler that gets called when the prefork
265 : * master process terminates.
266 : */
267 398 : rc = talloc_zero(ev, struct restart_context);
268 398 : if (rc == NULL) {
269 0 : smb_panic("OOM allocating restart context\n");
270 : }
271 398 : rc->t = t;
272 398 : rc->lp_ctx = lp_ctx;
273 398 : rc->service_name = service_name;
274 398 : rc->service_details = service_details;
275 398 : rc->from_parent_fd = from_parent_fd;
276 398 : rc->restart_delay = restart_delay;
277 398 : rc->master = talloc_zero(rc, struct master_restart_context);
278 398 : if (rc->master == NULL) {
279 0 : smb_panic("OOM allocating master restart context\n");
280 : }
281 :
282 398 : rc->master->new_task_fn = new_task_fn;
283 398 : rc->master->private_data = private_data;
284 :
285 398 : fde = tevent_add_fd(
286 : ev, ev, fd, TEVENT_FD_READ, prefork_child_pipe_handler, rc);
287 398 : if (fde == NULL) {
288 0 : smb_panic("Failed to add child pipe handler, "
289 : "after fork");
290 : }
291 398 : tevent_fd_set_auto_close(fde);
292 398 : return;
293 : }
294 :
295 398 : pid = getpid();
296 :
297 398 : 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 398 : if (tevent_re_initialise(ev) != 0) {
304 0 : smb_panic("Failed to re-initialise tevent after fork");
305 : }
306 398 : prefork_reload_after_fork();
307 398 : setup_handlers(ev, lp_ctx, from_parent_fd);
308 :
309 398 : if (service_details->inhibit_pre_fork) {
310 287 : 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 287 : if (task != NULL && service_details->post_fork != NULL) {
316 0 : service_details->post_fork(task, &pd);
317 : }
318 287 : if (task != NULL && service_details->before_loop != NULL) {
319 0 : service_details->before_loop(task);
320 : }
321 287 : tevent_loop_wait(ev);
322 0 : TALLOC_FREE(ev);
323 0 : exit(0);
324 : }
325 :
326 : /*
327 : * This is now the child code. We need a completely new event_context
328 : * to work with
329 : */
330 111 : ev2 = s4_event_context_init(NULL);
331 :
332 111 : samba_tevent_trace_state = create_samba_tevent_trace_state(ev2);
333 111 : if (samba_tevent_trace_state == NULL) {
334 0 : TALLOC_FREE(ev);
335 0 : TALLOC_FREE(ev2);
336 0 : exit(127);
337 : }
338 :
339 111 : tevent_set_trace_callback(ev2,
340 : samba_tevent_trace_callback,
341 : samba_tevent_trace_state);
342 :
343 : /* setup this new connection: process will bind to it's sockets etc
344 : *
345 : * While we can use ev for the child, which has been re-initialised
346 : * above we must run the new task under ev2 otherwise the children would
347 : * be listening on the sockets. Also we don't want the top level
348 : * process accepting and handling requests, it's responsible for
349 : * monitoring and controlling the child work processes.
350 : */
351 111 : task = new_task_fn(ev2, lp_ctx, cluster_id(pid, 0), private_data, NULL);
352 111 : if (task == NULL) {
353 0 : TALLOC_FREE(ev);
354 0 : TALLOC_FREE(ev2);
355 0 : exit(127);
356 : }
357 :
358 : /*
359 : * Register an irpc name that can be used by the samba-tool processes
360 : * command
361 : */
362 : {
363 111 : struct talloc_ctx *ctx = talloc_new(NULL);
364 111 : char *name = NULL;
365 111 : if (ctx == NULL) {
366 0 : DBG_ERR("Out of memory\n");
367 0 : exit(127);
368 : }
369 111 : name = talloc_asprintf(ctx, "prefork-master-%s", service_name);
370 111 : irpc_add_name(task->msg_ctx, name);
371 111 : TALLOC_FREE(ctx);
372 : }
373 :
374 : {
375 8 : int default_children;
376 111 : default_children = lpcfg_prefork_children(lp_ctx);
377 111 : num_children = lpcfg_parm_int(lp_ctx, NULL, "prefork children",
378 : service_name, default_children);
379 : }
380 111 : if (num_children == 0) {
381 0 : DBG_WARNING("Number of pre-fork children for %s is zero, "
382 : "NO worker processes will be started for %s\n",
383 : service_name, service_name);
384 : }
385 111 : DBG_NOTICE("Forking %d %s worker processes\n",
386 : num_children, service_name);
387 :
388 : /*
389 : * the prefork master creates its own control pipe, so the prefork
390 : * workers can detect if the master exits (in which case an EOF gets
391 : * written). (Whereas from_parent_fd is the control pipe from the
392 : * top-level process that the prefork master listens on)
393 : */
394 : {
395 8 : int ret;
396 111 : ret = pipe(control_pipe);
397 111 : if (ret != 0) {
398 0 : smb_panic("Unable to create worker control pipe\n");
399 : }
400 111 : smb_set_close_on_exec(control_pipe[0]);
401 111 : smb_set_close_on_exec(control_pipe[1]);
402 : }
403 :
404 : /*
405 : * Note, we call this before the first
406 : * prefork_fork_worker() in order to have
407 : * a stable order of:
408 : * task_init(master) -> before_loop(master)
409 : * -> post_fork(worker) -> before_loop(worker)
410 : *
411 : * Otherwise we would have different behaviors
412 : * between the first prefork_fork_worker() loop
413 : * and restarting of died workers
414 : */
415 111 : if (task != NULL && service_details->before_loop != NULL) {
416 29 : struct task_server *task_copy = NULL;
417 :
418 : /*
419 : * We need to use ev as parent in order to
420 : * keep everything alive during the loop
421 : */
422 29 : task_copy = talloc(ev, struct task_server);
423 29 : if (task_copy == NULL) {
424 0 : TALLOC_FREE(ev);
425 0 : TALLOC_FREE(ev2);
426 0 : exit(127);
427 : }
428 29 : *task_copy = *task;
429 :
430 : /*
431 : * In order to allow the before_loop() hook
432 : * to register messages or event handlers,
433 : * we need to fix up task->event_ctx
434 : * and create a new task->msg_ctx
435 : */
436 29 : task_copy->event_ctx = ev;
437 29 : task_copy->msg_ctx = imessaging_init(task_copy,
438 : task_copy->lp_ctx,
439 : task_copy->server_id,
440 : task_copy->event_ctx);
441 29 : if (task_copy->msg_ctx == NULL) {
442 0 : TALLOC_FREE(ev);
443 0 : TALLOC_FREE(ev2);
444 0 : exit(127);
445 : }
446 29 : service_details->before_loop(task_copy);
447 : }
448 :
449 : /*
450 : * We are now free to spawn some worker processes
451 : */
452 507 : for (i=0; i < num_children; i++) {
453 396 : prefork_fork_worker(task,
454 : ev,
455 : ev2,
456 : lp_ctx,
457 : service_details,
458 : service_name,
459 : control_pipe,
460 : 0,
461 : &pd);
462 396 : pd.instances++;
463 : }
464 :
465 : /*
466 : * Make sure the messaging context
467 : * used by the workers is no longer
468 : * active on ev2, otherwise we
469 : * would have memory leaks, because
470 : * we queue incoming messages
471 : * and never process them via ev2.
472 : */
473 111 : imessaging_dgm_unref_ev(ev2);
474 :
475 : /* Don't listen on the sockets we just gave to the children */
476 111 : tevent_loop_wait(ev);
477 0 : imessaging_dgm_unref_ev(ev);
478 0 : TALLOC_FREE(ev);
479 : /* We need to keep ev2 until we're finished for the messaging to work */
480 0 : TALLOC_FREE(ev2);
481 0 : exit(0);
482 : }
483 :
484 : static void prefork_restart_fn(struct tevent_context *ev,
485 : struct tevent_timer *te,
486 : struct timeval tv,
487 : void *private_data);
488 :
489 : /*
490 : * Restarts a child process if it exits unexpectedly
491 : */
492 21 : static bool prefork_restart(struct tevent_context *ev,
493 : struct restart_context *rc)
494 : {
495 21 : struct tevent_timer *te = NULL;
496 :
497 21 : if (rc->restart_delay > 0) {
498 6 : DBG_ERR("Restarting [%s] pre-fork %s in (%d) seconds\n",
499 : rc->service_name,
500 : (rc->master == NULL) ? "worker" : "master",
501 : rc->restart_delay);
502 : }
503 :
504 : /*
505 : * Always use an async timer event. If
506 : * rc->restart_delay is zero this is the
507 : * same as an immediate event and will be
508 : * called immediately we go back into the
509 : * event loop.
510 : */
511 21 : te = tevent_add_timer(ev,
512 : ev,
513 : tevent_timeval_current_ofs(rc->restart_delay, 0),
514 : prefork_restart_fn,
515 : rc);
516 21 : if (te == NULL) {
517 0 : DBG_ERR("tevent_add_timer fail [%s] pre-fork event %s\n",
518 : rc->service_name,
519 : (rc->master == NULL) ? "worker" : "master");
520 : /* Caller needs to free rc. */
521 0 : return false;
522 : }
523 : /* Caller must not free rc - it's in use. */
524 21 : return true;
525 : }
526 :
527 21 : static void prefork_restart_fn(struct tevent_context *ev,
528 : struct tevent_timer *te,
529 : struct timeval tv,
530 : void *private_data)
531 : {
532 21 : unsigned max_backoff = 0;
533 21 : unsigned backoff = 0;
534 21 : unsigned default_value = 0;
535 21 : struct restart_context *rc = talloc_get_type(private_data,
536 : struct restart_context);
537 21 : unsigned restart_delay = rc->restart_delay;
538 :
539 21 : TALLOC_FREE(te);
540 :
541 : /*
542 : * If the child process is constantly exiting, then restarting it can
543 : * consume a lot of resources. In which case, we want to backoff a bit
544 : * before respawning it
545 : */
546 21 : default_value = lpcfg_prefork_backoff_increment(rc->lp_ctx);
547 21 : backoff = lpcfg_parm_int(rc->lp_ctx,
548 : NULL,
549 : "prefork backoff increment",
550 : rc->service_name,
551 : default_value);
552 :
553 21 : default_value = lpcfg_prefork_maximum_backoff(rc->lp_ctx);
554 21 : max_backoff = lpcfg_parm_int(rc->lp_ctx,
555 : NULL,
556 : "prefork maximum backoff",
557 : rc->service_name,
558 : default_value);
559 :
560 21 : restart_delay += backoff;
561 21 : restart_delay = min(restart_delay, max_backoff);
562 :
563 21 : if (rc->master != NULL) {
564 6 : DBG_ERR("Restarting [%s] pre-fork master\n", rc->service_name);
565 6 : prefork_fork_master(ev,
566 : rc->lp_ctx,
567 : rc->service_name,
568 6 : rc->master->new_task_fn,
569 6 : rc->master->private_data,
570 : rc->service_details,
571 : restart_delay,
572 : rc->from_parent_fd);
573 15 : } else if (rc->worker != NULL) {
574 15 : struct process_details pd = initial_process_details;
575 15 : DBG_ERR("Restarting [%s] pre-fork worker(%d)\n",
576 : rc->service_name,
577 : rc->worker->instance);
578 15 : pd.instances = rc->worker->instance;
579 15 : prefork_fork_worker(rc->worker->task,
580 : ev,
581 15 : rc->worker->ev2,
582 : rc->lp_ctx,
583 : rc->service_details,
584 : rc->service_name,
585 15 : rc->worker->control_pipe,
586 : restart_delay,
587 : &pd);
588 : }
589 : /* tfork allocates tfork structures with malloc */
590 21 : tfork_destroy(&rc->t);
591 21 : free(rc->t);
592 21 : TALLOC_FREE(rc);
593 21 : }
594 :
595 : /*
596 : handle EOF on the child pipe in the parent, so we know when a
597 : process terminates without using SIGCHLD or waiting on all possible pids.
598 :
599 : We need to ensure we do not ignore SIGCHLD because we need it to
600 : work to get a valid error code from samba_runcmd_*().
601 : */
602 21 : static void prefork_child_pipe_handler(struct tevent_context *ev,
603 : struct tevent_fd *fde,
604 : uint16_t flags,
605 : void *private_data)
606 : {
607 21 : struct restart_context *rc = NULL;
608 21 : int status = 0;
609 21 : pid_t pid = 0;
610 21 : bool rc_inuse = false;
611 :
612 : /* free the fde which removes the event and stops it firing again */
613 21 : TALLOC_FREE(fde);
614 :
615 : /* the child has closed the pipe, assume its dead */
616 :
617 21 : rc = talloc_get_type_abort(private_data, struct restart_context);
618 21 : pid = tfork_child_pid(rc->t);
619 21 : errno = 0;
620 :
621 21 : irpc_cleanup(rc->lp_ctx, ev, pid);
622 21 : status = tfork_status(&rc->t, false);
623 21 : if (status == -1) {
624 0 : DBG_ERR("Parent %d, Child %d terminated, "
625 : "unable to get status code from tfork\n",
626 : getpid(), pid);
627 0 : rc_inuse = prefork_restart(ev, rc);
628 21 : } else if (WIFEXITED(status)) {
629 20 : status = WEXITSTATUS(status);
630 20 : DBG_ERR("Parent %d, Child %d exited with status %d\n",
631 : getpid(), pid, status);
632 20 : if (status != 0) {
633 20 : rc_inuse = prefork_restart(ev, rc);
634 : }
635 1 : } else if (WIFSIGNALED(status)) {
636 1 : status = WTERMSIG(status);
637 1 : DBG_ERR("Parent %d, Child %d terminated with signal %d\n",
638 : getpid(), pid, status);
639 1 : if (status == SIGABRT || status == SIGBUS || status == SIGFPE ||
640 0 : status == SIGILL || status == SIGSYS || status == SIGSEGV ||
641 : status == SIGKILL) {
642 :
643 1 : rc_inuse = prefork_restart(ev, rc);
644 : }
645 : }
646 21 : if (!rc_inuse) {
647 : /* tfork allocates tfork structures with malloc */
648 0 : tfork_destroy(&rc->t);
649 0 : free(rc->t);
650 0 : TALLOC_FREE(rc);
651 : }
652 21 : return;
653 : }
654 :
655 : /*
656 : called when a listening socket becomes readable.
657 : */
658 79213 : static void prefork_accept_connection(
659 : struct tevent_context *ev,
660 : struct loadparm_context *lp_ctx,
661 : struct socket_context *listen_socket,
662 : void (*new_conn)(struct tevent_context *,
663 : struct loadparm_context *,
664 : struct socket_context *,
665 : struct server_id,
666 : void *,
667 : void *),
668 : void *private_data,
669 : void *process_context)
670 : {
671 4019 : NTSTATUS status;
672 4019 : struct socket_context *connected_socket;
673 79213 : pid_t pid = getpid();
674 :
675 : /* accept an incoming connection. */
676 79213 : status = socket_accept(listen_socket, &connected_socket);
677 79213 : if (!NT_STATUS_IS_OK(status)) {
678 : /*
679 : * For prefork we can ignore STATUS_MORE_ENTRIES, as once a
680 : * connection becomes available all waiting processes are
681 : * woken, but only one gets work to process.
682 : * AKA the thundering herd.
683 : * In the short term this should not be an issue as the number
684 : * of workers should be a small multiple of the number of cpus
685 : * In the longer term socket_accept needs to implement a
686 : * mutex/semaphore (like apache does) to serialise the accepts
687 : */
688 30192 : if (!NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
689 0 : DBG_ERR("Worker process (%d), error in accept [%s]\n",
690 : getpid(), nt_errstr(status));
691 : }
692 30192 : return;
693 : }
694 :
695 49021 : talloc_steal(private_data, connected_socket);
696 :
697 49021 : new_conn(ev, lp_ctx, connected_socket,
698 49021 : cluster_id(pid, socket_get_fd(connected_socket)),
699 : private_data, process_context);
700 : }
701 :
702 808 : static void setup_handlers(
703 : struct tevent_context *ev,
704 : struct loadparm_context *lp_ctx,
705 : int from_parent_fd)
706 : {
707 808 : struct tevent_fd *fde = NULL;
708 808 : struct tevent_signal *se = NULL;
709 :
710 808 : fde = tevent_add_fd(ev, ev, from_parent_fd, TEVENT_FD_READ,
711 : prefork_pipe_handler, lp_ctx);
712 808 : if (fde == NULL) {
713 0 : smb_panic("Failed to add fd handler after fork");
714 : }
715 :
716 808 : se = tevent_add_signal(ev,
717 : ev,
718 : SIGHUP,
719 : 0,
720 : sighup_signal_handler,
721 : NULL);
722 808 : if (se == NULL) {
723 0 : smb_panic("Failed to add SIGHUP handler after fork");
724 : }
725 :
726 808 : se = tevent_add_signal(ev,
727 : ev,
728 : SIGTERM,
729 : 0,
730 : sigterm_signal_handler,
731 : NULL);
732 808 : if (se == NULL) {
733 0 : smb_panic("Failed to add SIGTERM handler after fork");
734 : }
735 808 : }
736 :
737 : /*
738 : * Called by the prefork master to create a new prefork worker process
739 : */
740 411 : static void prefork_fork_worker(struct task_server *task,
741 : struct tevent_context *ev,
742 : struct tevent_context *ev2,
743 : struct loadparm_context *lp_ctx,
744 : const struct service_details *service_details,
745 : const char *service_name,
746 : int control_pipe[2],
747 : unsigned restart_delay,
748 : struct process_details *pd)
749 : {
750 411 : struct tfork *w = NULL;
751 32 : pid_t pid;
752 :
753 411 : w = tfork_create();
754 821 : if (w == NULL) {
755 0 : smb_panic("failure in tfork\n");
756 : }
757 :
758 821 : pid = tfork_child_pid(w);
759 821 : if (pid != 0) {
760 411 : struct tevent_fd *fde = NULL;
761 411 : int fd = tfork_event_fd(w);
762 411 : struct restart_context *rc = NULL;
763 :
764 : /*
765 : * we're the parent (prefork master), so store enough info to
766 : * restart the worker/child if it exits unexpectedly
767 : */
768 411 : rc = talloc_zero(ev, struct restart_context);
769 411 : if (rc == NULL) {
770 0 : smb_panic("OOM allocating restart context\n");
771 : }
772 411 : rc->t = w;
773 411 : rc->lp_ctx = lp_ctx;
774 411 : rc->service_name = service_name;
775 411 : rc->service_details = service_details;
776 411 : rc->restart_delay = restart_delay;
777 411 : rc->master = NULL;
778 411 : rc->worker = talloc_zero(rc, struct worker_restart_context);
779 411 : if (rc->worker == NULL) {
780 0 : smb_panic("OOM allocating master restart context\n");
781 : }
782 411 : rc->worker->ev2 = ev2;
783 411 : rc->worker->instance = pd->instances;
784 411 : rc->worker->task = task;
785 411 : rc->worker->control_pipe[0] = control_pipe[0];
786 411 : rc->worker->control_pipe[1] = control_pipe[1];
787 :
788 411 : fde = tevent_add_fd(
789 : ev, ev, fd, TEVENT_FD_READ, prefork_child_pipe_handler, rc);
790 411 : if (fde == NULL) {
791 0 : smb_panic("Failed to add child pipe handler, "
792 : "after fork");
793 : }
794 411 : tevent_fd_set_auto_close(fde);
795 : } else {
796 :
797 : /*
798 : * we're the child (prefork-worker). We never write to the
799 : * control pipe, but listen on the read end in case our parent
800 : * (the pre-fork master) exits
801 : */
802 410 : close(control_pipe[1]);
803 410 : setup_handlers(ev2, lp_ctx, control_pipe[0]);
804 :
805 : /*
806 : * tfork uses malloc
807 : */
808 410 : free(w);
809 :
810 410 : imessaging_dgm_unref_ev(ev);
811 410 : TALLOC_FREE(ev);
812 :
813 410 : process_set_title("%s(%d)",
814 : "task[%s] pre-forked worker(%d)",
815 : service_name,
816 : pd->instances);
817 :
818 410 : prefork_reload_after_fork();
819 410 : if (service_details->post_fork != NULL) {
820 290 : service_details->post_fork(task, pd);
821 : }
822 : {
823 410 : struct talloc_ctx *ctx = talloc_new(NULL);
824 410 : char *name = NULL;
825 410 : if (ctx == NULL) {
826 0 : smb_panic("OOM allocating talloc context\n");
827 : }
828 410 : name = talloc_asprintf(ctx,
829 : "prefork-worker-%s-%d",
830 : service_name,
831 : pd->instances);
832 410 : irpc_add_name(task->msg_ctx, name);
833 410 : TALLOC_FREE(ctx);
834 : }
835 410 : if (service_details->before_loop != NULL) {
836 109 : service_details->before_loop(task);
837 : }
838 410 : tevent_loop_wait(ev2);
839 0 : imessaging_dgm_unref_ev(ev2);
840 0 : talloc_free(ev2);
841 0 : exit(0);
842 : }
843 411 : }
844 : /*
845 : * called to create a new server task
846 : */
847 392 : static void prefork_new_task(
848 : struct tevent_context *ev,
849 : struct loadparm_context *lp_ctx,
850 : const char *service_name,
851 : struct task_server *(*new_task_fn)(struct tevent_context *,
852 : struct loadparm_context *lp_ctx,
853 : struct server_id , void *, void *),
854 : void *private_data,
855 : const struct service_details *service_details,
856 : int from_parent_fd)
857 : {
858 392 : prefork_fork_master(ev,
859 : lp_ctx,
860 : service_name,
861 : new_task_fn,
862 : private_data,
863 : service_details,
864 : 0,
865 : from_parent_fd);
866 :
867 392 : }
868 :
869 : /*
870 : * called when a task terminates
871 : */
872 0 : static void prefork_terminate_task(struct tevent_context *ev,
873 : struct loadparm_context *lp_ctx,
874 : const char *reason,
875 : bool fatal,
876 : void *process_context)
877 : {
878 0 : DBG_DEBUG("called with reason[%s]\n", reason);
879 0 : TALLOC_FREE(ev);
880 0 : if (fatal == true) {
881 0 : exit(127);
882 : } else {
883 0 : exit(0);
884 : }
885 : }
886 :
887 : /*
888 : * called when a connection completes
889 : */
890 49019 : static void prefork_terminate_connection(struct tevent_context *ev,
891 : struct loadparm_context *lp_ctx,
892 : const char *reason,
893 : void *process_context)
894 : {
895 49019 : }
896 :
897 : /* called to set a title of a task or connection */
898 49419 : static void prefork_set_title(struct tevent_context *ev, const char *title)
899 : {
900 49419 : }
901 :
902 : static const struct model_ops prefork_ops = {
903 : .name = "prefork",
904 : .model_init = prefork_model_init,
905 : .accept_connection = prefork_accept_connection,
906 : .new_task = prefork_new_task,
907 : .terminate_task = prefork_terminate_task,
908 : .terminate_connection = prefork_terminate_connection,
909 : .set_title = prefork_set_title,
910 : };
911 :
912 : /*
913 : * initialise the prefork process model, registering ourselves with the
914 : * process model subsystem
915 : */
916 68 : NTSTATUS process_model_prefork_init(void)
917 : {
918 68 : return register_process_model(&prefork_ops);
919 : }
|