2 Unix SMB/CIFS implementation.
4 process model: prefork (n client connections per process)
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>
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.
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.
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/>.
29 #include "lib/events/events.h"
30 #include "lib/messaging/messaging.h"
31 #include "lib/socket/socket.h"
32 #include "smbd/process_model.h"
33 #include "cluster/cluster.h"
34 #include "param/param.h"
36 #include "lib/util/tfork.h"
38 NTSTATUS
process_model_prefork_init(void);
40 static void sighup_signal_handler(struct tevent_context
*ev
,
41 struct tevent_signal
*se
,
42 int signum
, int count
, void *siginfo
,
45 debug_schedule_reopen_logs();
48 static void sigterm_signal_handler(struct tevent_context
*ev
,
49 struct tevent_signal
*se
,
50 int signum
, int count
, void *siginfo
,
54 if (getpgrp() == getpid()) {
56 * We're the process group leader, send
57 * SIGTERM to our process group.
59 DBG_NOTICE("SIGTERM: killing children\n");
60 kill(-getpgrp(), SIGTERM
);
63 DBG_NOTICE("Exiting pid %d on SIGTERM\n", getpid());
69 called when the process model is selected
71 static void prefork_model_init(void)
75 static void prefork_reload_after_fork(void)
80 /* Must be done after a fork() to reset messaging contexts. */
81 status
= imessaging_reinit_all();
82 if (!NT_STATUS_IS_OK(status
)) {
83 smb_panic("Failed to re-initialise imessaging after fork");
88 handle EOF on the parent-to-all-children pipe in the child
90 static void prefork_pipe_handler(struct tevent_context
*event_ctx
,
91 struct tevent_fd
*fde
, uint16_t flags
,
94 /* free the fde which removes the event and stops it firing again */
96 DBG_NOTICE("Child %d exiting\n", getpid());
97 talloc_free(event_ctx
);
102 handle EOF on the child pipe in the parent, so we know when a
103 process terminates without using SIGCHLD or waiting on all possible pids.
105 We need to ensure we do not ignore SIGCHLD because we need it to
106 work to get a valid error code from samba_runcmd_*().
108 static void prefork_child_pipe_handler(struct tevent_context
*ev
,
109 struct tevent_fd
*fde
,
113 struct tfork
*t
= NULL
;
117 /* free the fde which removes the event and stops it firing again */
120 /* the child has closed the pipe, assume its dead */
122 /* tfork allocates tfork structures with malloc */
123 t
= (struct tfork
*)private_data
;
124 pid
= tfork_child_pid(t
);
126 status
= tfork_status(&t
, false);
128 DBG_ERR("Parent %d, Child %d terminated, "
129 "unable to get status code from tfork\n",
131 } else if (WIFEXITED(status
)) {
132 status
= WEXITSTATUS(status
);
133 DBG_ERR("Parent %d, Child %d exited with status %d\n",
134 getpid(), pid
, status
);
135 } else if (WIFSIGNALED(status
)) {
136 status
= WTERMSIG(status
);
137 DBG_ERR("Parent %d, Child %d terminated with signal %d\n",
138 getpid(), pid
, status
);
140 /* tfork allocates tfork structures with malloc */
146 called when a listening socket becomes readable.
148 static void prefork_accept_connection(
149 struct tevent_context
*ev
,
150 struct loadparm_context
*lp_ctx
,
151 struct socket_context
*listen_socket
,
152 void (*new_conn
)(struct tevent_context
*,
153 struct loadparm_context
*,
154 struct socket_context
*,
159 void *process_context
)
162 struct socket_context
*connected_socket
;
163 pid_t pid
= getpid();
165 /* accept an incoming connection. */
166 status
= socket_accept(listen_socket
, &connected_socket
);
167 if (!NT_STATUS_IS_OK(status
)) {
169 * For prefork we can ignore STATUS_MORE_ENTRIES, as once a
170 * connection becomes available all waiting processes are
171 * woken, but only one gets work to process.
172 * AKA the thundering herd.
173 * In the short term this should not be an issue as the number
174 * of workers should be a small multiple of the number of cpus
175 * In the longer term socket_accept needs to implement a
176 * mutex/semaphore (like apache does) to serialise the accepts
178 if (!NT_STATUS_EQUAL(status
, STATUS_MORE_ENTRIES
)) {
179 DBG_ERR("Worker process (%d), error in accept [%s]\n",
180 getpid(), nt_errstr(status
));
185 talloc_steal(private_data
, connected_socket
);
187 new_conn(ev
, lp_ctx
, connected_socket
,
188 cluster_id(pid
, socket_get_fd(connected_socket
)),
189 private_data
, process_context
);
192 static void setup_handlers(struct tevent_context
*ev
, int from_parent_fd
) {
193 struct tevent_fd
*fde
= NULL
;
194 struct tevent_signal
*se
= NULL
;
196 fde
= tevent_add_fd(ev
, ev
, from_parent_fd
, TEVENT_FD_READ
,
197 prefork_pipe_handler
, NULL
);
199 smb_panic("Failed to add fd handler after fork");
202 se
= tevent_add_signal(ev
,
206 sighup_signal_handler
,
209 smb_panic("Failed to add SIGHUP handler after fork");
212 se
= tevent_add_signal(ev
,
216 sigterm_signal_handler
,
219 smb_panic("Failed to add SIGTERM handler after fork");
224 * called to create a new server task
226 static void prefork_new_task(
227 struct tevent_context
*ev
,
228 struct loadparm_context
*lp_ctx
,
229 const char *service_name
,
230 void (*new_task_fn
)(struct tevent_context
*,
231 struct loadparm_context
*lp_ctx
,
232 struct server_id
, void *, void *),
234 const struct service_details
*service_details
,
238 struct tfork
* t
= NULL
;
241 struct tevent_context
*ev2
;
245 smb_panic("failure in tfork\n");
248 pid
= tfork_child_pid(t
);
250 struct tevent_fd
*fde
= NULL
;
251 int fd
= tfork_event_fd(t
);
253 /* Register a pipe handler that gets called when the prefork
254 * master process terminates.
256 fde
= tevent_add_fd(ev
, ev
, fd
, TEVENT_FD_READ
,
257 prefork_child_pipe_handler
, t
);
259 smb_panic("Failed to add child pipe handler, "
262 tevent_fd_set_auto_close(fde
);
267 setproctitle("task[%s] pre-fork master", service_name
);
270 * this will free all the listening sockets and all state that
271 * is not associated with this new connection
273 if (tevent_re_initialise(ev
) != 0) {
274 smb_panic("Failed to re-initialise tevent after fork");
276 prefork_reload_after_fork();
277 setup_handlers(ev
, from_parent_fd
);
279 if (service_details
->inhibit_pre_fork
) {
280 new_task_fn(ev
, lp_ctx
, cluster_id(pid
, 0), private_data
, NULL
);
281 /* The task does not support pre-fork */
282 tevent_loop_wait(ev
);
288 * This is now the child code. We need a completely new event_context
291 ev2
= s4_event_context_init(NULL
);
293 /* setup this new connection: process will bind to it's sockets etc
295 * While we can use ev for the child, which has been re-initialised
296 * above we must run the new task under ev2 otherwise the children would
297 * be listening on the sockets. Also we don't want the top level
298 * process accepting and handling requests, it's responsible for
299 * monitoring and controlling the child work processes.
301 new_task_fn(ev2
, lp_ctx
, cluster_id(pid
, 0), private_data
, NULL
);
304 int default_children
;
305 default_children
= lpcfg_prefork_children(lp_ctx
);
306 num_children
= lpcfg_parm_int(lp_ctx
, NULL
, "prefork children",
307 service_name
, default_children
);
309 if (num_children
== 0) {
310 DBG_WARNING("Number of pre-fork children for %s is zero, "
311 "NO worker processes will be started for %s\n",
312 service_name
, service_name
);
314 DBG_NOTICE("Forking %d %s worker processes\n",
315 num_children
, service_name
);
316 /* We are now free to spawn some worker processes */
317 for (i
=0; i
< num_children
; i
++) {
318 struct tfork
* w
= NULL
;
322 smb_panic("failure in tfork\n");
325 pid
= tfork_child_pid(w
);
327 struct tevent_fd
*fde
= NULL
;
328 int fd
= tfork_event_fd(w
);
330 fde
= tevent_add_fd(ev
, ev
, fd
, TEVENT_FD_READ
,
331 prefork_child_pipe_handler
, w
);
333 smb_panic("Failed to add child pipe handler, "
336 tevent_fd_set_auto_close(fde
);
338 /* tfork uses malloc */
342 setproctitle("task[%s] pre-forked worker",
344 prefork_reload_after_fork();
345 setup_handlers(ev2
, from_parent_fd
);
346 tevent_loop_wait(ev2
);
352 /* Don't listen on the sockets we just gave to the children */
353 tevent_loop_wait(ev
);
355 /* We need to keep ev2 until we're finished for the messaging to work */
362 /* called when a task goes down */
363 static void prefork_terminate(struct tevent_context
*ev
,
364 struct loadparm_context
*lp_ctx
,
366 void *process_context
)
368 DBG_DEBUG("called with reason[%s]\n", reason
);
371 /* called to set a title of a task or connection */
372 static void prefork_set_title(struct tevent_context
*ev
, const char *title
)
376 static const struct model_ops prefork_ops
= {
378 .model_init
= prefork_model_init
,
379 .accept_connection
= prefork_accept_connection
,
380 .new_task
= prefork_new_task
,
381 .terminate
= prefork_terminate
,
382 .set_title
= prefork_set_title
,
386 * initialise the prefork process model, registering ourselves with the
387 * process model subsystem
389 NTSTATUS
process_model_prefork_init(void)
391 return register_process_model(&prefork_ops
);