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 : }
|