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 286 : setproctitle("task[%s] pre-fork master", service_name);
297 : /*
298 : * We must fit within 15 chars of text or we will truncate, so
299 : * we put the constant part last
300 : */
301 286 : prctl_set_comment("%s[master]", service_name);
302 :
303 : /*
304 : * this will free all the listening sockets and all state that
305 : * is not associated with this new connection
306 : */
307 286 : if (tevent_re_initialise(ev) != 0) {
308 0 : smb_panic("Failed to re-initialise tevent after fork");
309 : }
310 286 : prefork_reload_after_fork();
311 286 : setup_handlers(ev, lp_ctx, from_parent_fd);
312 :
313 286 : if (service_details->inhibit_pre_fork) {
314 204 : task = new_task_fn(
315 : ev, lp_ctx, cluster_id(pid, 0), private_data, NULL);
316 : /*
317 : * The task does not support pre-fork
318 : */
319 204 : if (task != NULL && service_details->post_fork != NULL) {
320 0 : service_details->post_fork(task, &pd);
321 : }
322 204 : tevent_loop_wait(ev);
323 0 : TALLOC_FREE(ev);
324 0 : exit(0);
325 : }
326 :
327 : /*
328 : * This is now the child code. We need a completely new event_context
329 : * to work with
330 : */
331 82 : ev2 = s4_event_context_init(NULL);
332 :
333 82 : samba_tevent_trace_state = create_samba_tevent_trace_state(ev2);
334 82 : if (samba_tevent_trace_state == NULL) {
335 0 : TALLOC_FREE(ev);
336 0 : TALLOC_FREE(ev2);
337 0 : exit(127);
338 : }
339 :
340 82 : tevent_set_trace_callback(ev2,
341 : samba_tevent_trace_callback,
342 : samba_tevent_trace_state);
343 :
344 : /* setup this new connection: process will bind to it's sockets etc
345 : *
346 : * While we can use ev for the child, which has been re-initialised
347 : * above we must run the new task under ev2 otherwise the children would
348 : * be listening on the sockets. Also we don't want the top level
349 : * process accepting and handling requests, it's responsible for
350 : * monitoring and controlling the child work processes.
351 : */
352 82 : task = new_task_fn(ev2, lp_ctx, cluster_id(pid, 0), private_data, NULL);
353 82 : if (task == NULL) {
354 0 : TALLOC_FREE(ev);
355 0 : TALLOC_FREE(ev2);
356 0 : exit(127);
357 : }
358 :
359 : /*
360 : * Register an irpc name that can be used by the samba-tool processes
361 : * command
362 : */
363 : {
364 82 : struct talloc_ctx *ctx = talloc_new(NULL);
365 82 : char *name = NULL;
366 82 : if (ctx == NULL) {
367 0 : DBG_ERR("Out of memory");
368 0 : exit(127);
369 : }
370 82 : name = talloc_asprintf(ctx, "prefork-master-%s", service_name);
371 82 : irpc_add_name(task->msg_ctx, name);
372 82 : TALLOC_FREE(ctx);
373 : }
374 :
375 : {
376 : int default_children;
377 82 : default_children = lpcfg_prefork_children(lp_ctx);
378 82 : num_children = lpcfg_parm_int(lp_ctx, NULL, "prefork children",
379 : service_name, default_children);
380 : }
381 82 : if (num_children == 0) {
382 0 : DBG_WARNING("Number of pre-fork children for %s is zero, "
383 : "NO worker processes will be started for %s\n",
384 : service_name, service_name);
385 : }
386 82 : DBG_NOTICE("Forking %d %s worker processes\n",
387 : num_children, service_name);
388 :
389 : /*
390 : * the prefork master creates its own control pipe, so the prefork
391 : * workers can detect if the master exits (in which case an EOF gets
392 : * written). (Whereas from_parent_fd is the control pipe from the
393 : * top-level process that the prefork master listens on)
394 : */
395 : {
396 : int ret;
397 82 : ret = pipe(control_pipe);
398 82 : if (ret != 0) {
399 0 : smb_panic("Unable to create worker control pipe\n");
400 : }
401 82 : smb_set_close_on_exec(control_pipe[0]);
402 82 : smb_set_close_on_exec(control_pipe[1]);
403 : }
404 :
405 : /*
406 : * We are now free to spawn some worker processes
407 : */
408 362 : for (i=0; i < num_children; i++) {
409 280 : prefork_fork_worker(task,
410 : ev,
411 : ev2,
412 : lp_ctx,
413 : service_details,
414 : service_name,
415 : control_pipe,
416 : 0,
417 : &pd);
418 280 : pd.instances++;
419 : }
420 :
421 : /* Don't listen on the sockets we just gave to the children */
422 82 : tevent_loop_wait(ev);
423 0 : TALLOC_FREE(ev);
424 : /* We need to keep ev2 until we're finished for the messaging to work */
425 0 : TALLOC_FREE(ev2);
426 0 : exit(0);
427 : }
428 :
429 : static void prefork_restart_fn(struct tevent_context *ev,
430 : struct tevent_timer *te,
431 : struct timeval tv,
432 : void *private_data);
433 :
434 : /*
435 : * Restarts a child process if it exits unexpectedly
436 : */
437 21 : static bool prefork_restart(struct tevent_context *ev,
438 : struct restart_context *rc)
439 : {
440 21 : struct tevent_timer *te = NULL;
441 :
442 21 : if (rc->restart_delay > 0) {
443 6 : DBG_ERR("Restarting [%s] pre-fork %s in (%d) seconds\n",
444 : rc->service_name,
445 : (rc->master == NULL) ? "worker" : "master",
446 : rc->restart_delay);
447 : }
448 :
449 : /*
450 : * Always use an async timer event. If
451 : * rc->restart_delay is zero this is the
452 : * same as an immediate event and will be
453 : * called immediately we go back into the
454 : * event loop.
455 : */
456 21 : te = tevent_add_timer(ev,
457 : ev,
458 : tevent_timeval_current_ofs(rc->restart_delay, 0),
459 : prefork_restart_fn,
460 : rc);
461 21 : if (te == NULL) {
462 0 : DBG_ERR("tevent_add_timer fail [%s] pre-fork event %s\n",
463 : rc->service_name,
464 : (rc->master == NULL) ? "worker" : "master");
465 : /* Caller needs to free rc. */
466 0 : return false;
467 : }
468 : /* Caller must not free rc - it's in use. */
469 21 : return true;
470 : }
471 :
472 21 : static void prefork_restart_fn(struct tevent_context *ev,
473 : struct tevent_timer *te,
474 : struct timeval tv,
475 : void *private_data)
476 : {
477 21 : unsigned max_backoff = 0;
478 21 : unsigned backoff = 0;
479 21 : unsigned default_value = 0;
480 21 : struct restart_context *rc = talloc_get_type(private_data,
481 : struct restart_context);
482 21 : unsigned restart_delay = rc->restart_delay;
483 :
484 21 : TALLOC_FREE(te);
485 :
486 : /*
487 : * If the child process is constantly exiting, then restarting it can
488 : * consume a lot of resources. In which case, we want to backoff a bit
489 : * before respawning it
490 : */
491 21 : default_value = lpcfg_prefork_backoff_increment(rc->lp_ctx);
492 21 : backoff = lpcfg_parm_int(rc->lp_ctx,
493 : NULL,
494 : "prefork backoff increment",
495 : rc->service_name,
496 : default_value);
497 :
498 21 : default_value = lpcfg_prefork_maximum_backoff(rc->lp_ctx);
499 21 : max_backoff = lpcfg_parm_int(rc->lp_ctx,
500 : NULL,
501 : "prefork maximum backoff",
502 : rc->service_name,
503 : default_value);
504 :
505 21 : restart_delay += backoff;
506 21 : restart_delay = min(restart_delay, max_backoff);
507 :
508 21 : if (rc->master != NULL) {
509 6 : DBG_ERR("Restarting [%s] pre-fork master\n", rc->service_name);
510 18 : prefork_fork_master(ev,
511 : rc->lp_ctx,
512 : rc->service_name,
513 6 : rc->master->new_task_fn,
514 6 : rc->master->private_data,
515 : rc->service_details,
516 : restart_delay,
517 : rc->from_parent_fd);
518 15 : } else if (rc->worker != NULL) {
519 15 : struct process_details pd = initial_process_details;
520 15 : DBG_ERR("Restarting [%s] pre-fork worker(%d)\n",
521 : rc->service_name,
522 : rc->worker->instance);
523 15 : pd.instances = rc->worker->instance;
524 30 : prefork_fork_worker(rc->worker->task,
525 : ev,
526 15 : rc->worker->ev2,
527 : rc->lp_ctx,
528 : rc->service_details,
529 : rc->service_name,
530 15 : rc->worker->control_pipe,
531 : restart_delay,
532 : &pd);
533 : }
534 : /* tfork allocates tfork structures with malloc */
535 21 : tfork_destroy(&rc->t);
536 21 : free(rc->t);
537 21 : TALLOC_FREE(rc);
538 21 : }
539 :
540 : /*
541 : handle EOF on the child pipe in the parent, so we know when a
542 : process terminates without using SIGCHLD or waiting on all possible pids.
543 :
544 : We need to ensure we do not ignore SIGCHLD because we need it to
545 : work to get a valid error code from samba_runcmd_*().
546 : */
547 21 : static void prefork_child_pipe_handler(struct tevent_context *ev,
548 : struct tevent_fd *fde,
549 : uint16_t flags,
550 : void *private_data)
551 : {
552 21 : struct restart_context *rc = NULL;
553 21 : int status = 0;
554 21 : pid_t pid = 0;
555 21 : bool rc_inuse = false;
556 :
557 : /* free the fde which removes the event and stops it firing again */
558 21 : TALLOC_FREE(fde);
559 :
560 : /* the child has closed the pipe, assume its dead */
561 :
562 21 : rc = talloc_get_type_abort(private_data, struct restart_context);
563 21 : pid = tfork_child_pid(rc->t);
564 21 : errno = 0;
565 :
566 21 : irpc_cleanup(rc->lp_ctx, ev, pid);
567 21 : status = tfork_status(&rc->t, false);
568 21 : if (status == -1) {
569 0 : DBG_ERR("Parent %d, Child %d terminated, "
570 : "unable to get status code from tfork\n",
571 : getpid(), pid);
572 0 : rc_inuse = prefork_restart(ev, rc);
573 21 : } else if (WIFEXITED(status)) {
574 20 : status = WEXITSTATUS(status);
575 20 : DBG_ERR("Parent %d, Child %d exited with status %d\n",
576 : getpid(), pid, status);
577 20 : if (status != 0) {
578 20 : rc_inuse = prefork_restart(ev, rc);
579 : }
580 1 : } else if (WIFSIGNALED(status)) {
581 1 : status = WTERMSIG(status);
582 1 : DBG_ERR("Parent %d, Child %d terminated with signal %d\n",
583 : getpid(), pid, status);
584 1 : if (status == SIGABRT || status == SIGBUS || status == SIGFPE ||
585 0 : status == SIGILL || status == SIGSYS || status == SIGSEGV ||
586 : status == SIGKILL) {
587 :
588 1 : rc_inuse = prefork_restart(ev, rc);
589 : }
590 : }
591 21 : if (!rc_inuse) {
592 : /* tfork allocates tfork structures with malloc */
593 0 : tfork_destroy(&rc->t);
594 0 : free(rc->t);
595 0 : TALLOC_FREE(rc);
596 : }
597 21 : return;
598 : }
599 :
600 : /*
601 : called when a listening socket becomes readable.
602 : */
603 30176 : static void prefork_accept_connection(
604 : struct tevent_context *ev,
605 : struct loadparm_context *lp_ctx,
606 : struct socket_context *listen_socket,
607 : void (*new_conn)(struct tevent_context *,
608 : struct loadparm_context *,
609 : struct socket_context *,
610 : struct server_id,
611 : void *,
612 : void *),
613 : void *private_data,
614 : void *process_context)
615 : {
616 : NTSTATUS status;
617 : struct socket_context *connected_socket;
618 30176 : pid_t pid = getpid();
619 :
620 : /* accept an incoming connection. */
621 30176 : status = socket_accept(listen_socket, &connected_socket);
622 30176 : if (!NT_STATUS_IS_OK(status)) {
623 : /*
624 : * For prefork we can ignore STATUS_MORE_ENTRIES, as once a
625 : * connection becomes available all waiting processes are
626 : * woken, but only one gets work to process.
627 : * AKA the thundering herd.
628 : * In the short term this should not be an issue as the number
629 : * of workers should be a small multiple of the number of cpus
630 : * In the longer term socket_accept needs to implement a
631 : * mutex/semaphore (like apache does) to serialise the accepts
632 : */
633 11072 : if (!NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
634 0 : DBG_ERR("Worker process (%d), error in accept [%s]\n",
635 : getpid(), nt_errstr(status));
636 : }
637 11072 : return;
638 : }
639 :
640 19104 : talloc_steal(private_data, connected_socket);
641 :
642 19104 : new_conn(ev, lp_ctx, connected_socket,
643 19104 : cluster_id(pid, socket_get_fd(connected_socket)),
644 : private_data, process_context);
645 : }
646 :
647 580 : static void setup_handlers(
648 : struct tevent_context *ev,
649 : struct loadparm_context *lp_ctx,
650 : int from_parent_fd)
651 : {
652 580 : struct tevent_fd *fde = NULL;
653 580 : struct tevent_signal *se = NULL;
654 :
655 580 : fde = tevent_add_fd(ev, ev, from_parent_fd, TEVENT_FD_READ,
656 : prefork_pipe_handler, lp_ctx);
657 580 : if (fde == NULL) {
658 0 : smb_panic("Failed to add fd handler after fork");
659 : }
660 :
661 580 : se = tevent_add_signal(ev,
662 : ev,
663 : SIGHUP,
664 : 0,
665 : sighup_signal_handler,
666 : NULL);
667 580 : if (se == NULL) {
668 0 : smb_panic("Failed to add SIGHUP handler after fork");
669 : }
670 :
671 580 : se = tevent_add_signal(ev,
672 : ev,
673 : SIGTERM,
674 : 0,
675 : sigterm_signal_handler,
676 : NULL);
677 580 : if (se == NULL) {
678 0 : smb_panic("Failed to add SIGTERM handler after fork");
679 : }
680 580 : }
681 :
682 : /*
683 : * Called by the prefork master to create a new prefork worker process
684 : */
685 295 : static void prefork_fork_worker(struct task_server *task,
686 : struct tevent_context *ev,
687 : struct tevent_context *ev2,
688 : struct loadparm_context *lp_ctx,
689 : const struct service_details *service_details,
690 : const char *service_name,
691 : int control_pipe[2],
692 : unsigned restart_delay,
693 : struct process_details *pd)
694 : {
695 295 : struct tfork *w = NULL;
696 : pid_t pid;
697 :
698 295 : w = tfork_create();
699 589 : if (w == NULL) {
700 0 : smb_panic("failure in tfork\n");
701 : }
702 :
703 589 : pid = tfork_child_pid(w);
704 589 : if (pid != 0) {
705 295 : struct tevent_fd *fde = NULL;
706 295 : int fd = tfork_event_fd(w);
707 295 : struct restart_context *rc = NULL;
708 :
709 : /*
710 : * we're the parent (prefork master), so store enough info to
711 : * restart the worker/child if it exits unexpectedly
712 : */
713 295 : rc = talloc_zero(ev, struct restart_context);
714 295 : if (rc == NULL) {
715 0 : smb_panic("OOM allocating restart context\n");
716 : }
717 295 : rc->t = w;
718 295 : rc->lp_ctx = lp_ctx;
719 295 : rc->service_name = service_name;
720 295 : rc->service_details = service_details;
721 295 : rc->restart_delay = restart_delay;
722 295 : rc->master = NULL;
723 295 : rc->worker = talloc_zero(rc, struct worker_restart_context);
724 295 : if (rc->worker == NULL) {
725 0 : smb_panic("OOM allocating master restart context\n");
726 : }
727 295 : rc->worker->ev2 = ev2;
728 295 : rc->worker->instance = pd->instances;
729 295 : rc->worker->task = task;
730 295 : rc->worker->control_pipe[0] = control_pipe[0];
731 295 : rc->worker->control_pipe[1] = control_pipe[1];
732 :
733 295 : fde = tevent_add_fd(
734 : ev, ev, fd, TEVENT_FD_READ, prefork_child_pipe_handler, rc);
735 295 : if (fde == NULL) {
736 0 : smb_panic("Failed to add child pipe handler, "
737 : "after fork");
738 : }
739 295 : tevent_fd_set_auto_close(fde);
740 : } else {
741 :
742 : /*
743 : * we're the child (prefork-worker). We never write to the
744 : * control pipe, but listen on the read end in case our parent
745 : * (the pre-fork master) exits
746 : */
747 294 : close(control_pipe[1]);
748 294 : setup_handlers(ev2, lp_ctx, control_pipe[0]);
749 :
750 : /*
751 : * tfork uses malloc
752 : */
753 294 : free(w);
754 :
755 294 : TALLOC_FREE(ev);
756 294 : setproctitle("task[%s] pre-forked worker(%d)",
757 : service_name,
758 : pd->instances);
759 : /*
760 : * We must fit within 15 chars of text or we will truncate, so
761 : * we put child number last
762 : */
763 294 : prctl_set_comment("%s(%d)",
764 : service_name,
765 : pd->instances);
766 294 : prefork_reload_after_fork();
767 294 : if (service_details->post_fork != NULL) {
768 206 : service_details->post_fork(task, pd);
769 : }
770 : {
771 294 : struct talloc_ctx *ctx = talloc_new(NULL);
772 294 : char *name = NULL;
773 294 : if (ctx == NULL) {
774 0 : smb_panic("OOM allocating talloc context\n");
775 : }
776 294 : name = talloc_asprintf(ctx,
777 : "prefork-worker-%s-%d",
778 : service_name,
779 : pd->instances);
780 294 : irpc_add_name(task->msg_ctx, name);
781 294 : TALLOC_FREE(ctx);
782 : }
783 294 : tevent_loop_wait(ev2);
784 0 : talloc_free(ev2);
785 0 : exit(0);
786 : }
787 295 : }
788 : /*
789 : * called to create a new server task
790 : */
791 280 : static void prefork_new_task(
792 : struct tevent_context *ev,
793 : struct loadparm_context *lp_ctx,
794 : const char *service_name,
795 : struct task_server *(*new_task_fn)(struct tevent_context *,
796 : struct loadparm_context *lp_ctx,
797 : struct server_id , void *, void *),
798 : void *private_data,
799 : const struct service_details *service_details,
800 : int from_parent_fd)
801 : {
802 280 : prefork_fork_master(ev,
803 : lp_ctx,
804 : service_name,
805 : new_task_fn,
806 : private_data,
807 : service_details,
808 : 0,
809 : from_parent_fd);
810 :
811 280 : }
812 :
813 : /*
814 : * called when a task terminates
815 : */
816 0 : static void prefork_terminate_task(struct tevent_context *ev,
817 : struct loadparm_context *lp_ctx,
818 : const char *reason,
819 : bool fatal,
820 : void *process_context)
821 : {
822 0 : DBG_DEBUG("called with reason[%s]\n", reason);
823 0 : TALLOC_FREE(ev);
824 0 : if (fatal == true) {
825 0 : exit(127);
826 : } else {
827 0 : exit(0);
828 : }
829 : }
830 :
831 : /*
832 : * called when a connection completes
833 : */
834 19102 : static void prefork_terminate_connection(struct tevent_context *ev,
835 : struct loadparm_context *lp_ctx,
836 : const char *reason,
837 : void *process_context)
838 : {
839 19102 : }
840 :
841 : /* called to set a title of a task or connection */
842 19390 : static void prefork_set_title(struct tevent_context *ev, const char *title)
843 : {
844 19390 : }
845 :
846 : static const struct model_ops prefork_ops = {
847 : .name = "prefork",
848 : .model_init = prefork_model_init,
849 : .accept_connection = prefork_accept_connection,
850 : .new_task = prefork_new_task,
851 : .terminate_task = prefork_terminate_task,
852 : .terminate_connection = prefork_terminate_connection,
853 : .set_title = prefork_set_title,
854 : };
855 :
856 : /*
857 : * initialise the prefork process model, registering ourselves with the
858 : * process model subsystem
859 : */
860 55 : NTSTATUS process_model_prefork_init(void)
861 : {
862 55 : return register_process_model(&prefork_ops);
863 : }
|