summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/smbd/process_model.h3
-rw-r--r--source4/smbd/process_single.c7
-rw-r--r--source4/smbd/process_standard.c30
-rw-r--r--source4/smbd/server.c73
-rw-r--r--source4/smbd/service.c17
-rw-r--r--source4/smbd/service_task.c9
6 files changed, 97 insertions, 42 deletions
diff --git a/source4/smbd/process_model.h b/source4/smbd/process_model.h
index 4399d3689fb..d7bf3c87c7b 100644
--- a/source4/smbd/process_model.h
+++ b/source4/smbd/process_model.h
@@ -61,7 +61,8 @@ struct model_ops {
void (*)(struct tevent_context *,
struct loadparm_context *, struct server_id,
void *),
- void *);
+ void *,
+ int);
/* function to terminate a connection or task */
void (*terminate)(struct tevent_context *, struct loadparm_context *lp_ctx,
diff --git a/source4/smbd/process_single.c b/source4/smbd/process_single.c
index f483e000be7..54169e9b0cc 100644
--- a/source4/smbd/process_single.c
+++ b/source4/smbd/process_single.c
@@ -85,11 +85,12 @@ static void single_accept_connection(struct tevent_context *ev,
/*
called to startup a new task
*/
-static void single_new_task(struct tevent_context *ev,
+static void single_new_task(struct tevent_context *ev,
struct loadparm_context *lp_ctx,
const char *service_name,
- void (*new_task)(struct tevent_context *, struct loadparm_context *, struct server_id, void *),
- void *private_data)
+ void (*new_task)(struct tevent_context *, struct loadparm_context *, struct server_id, void *),
+ void *private_data,
+ int from_parent_fd)
{
pid_t pid = getpid();
/* start our taskids at MAX_INT32, the first 2^31 tasks are is reserved for fd numbers */
diff --git a/source4/smbd/process_standard.c b/source4/smbd/process_standard.c
index 8d962d55130..c6cbfc23eda 100644
--- a/source4/smbd/process_standard.c
+++ b/source4/smbd/process_standard.c
@@ -42,22 +42,13 @@ struct standard_child_state {
NTSTATUS process_model_standard_init(TALLOC_CTX *);
-/* we hold a pipe open in the parent, and the any child
- processes wait for EOF on that pipe. This ensures that
- children die when the parent dies */
-static int child_pipe[2] = { -1, -1 };
+static int from_parent_fd;
/*
called when the process model is selected
*/
static void standard_model_init(void)
{
- int rc;
-
- rc = pipe(child_pipe);
- if (rc < 0) {
- smb_panic("Failed to initialize pipe!");
- }
}
static void sighup_signal_handler(struct tevent_context *ev,
@@ -312,17 +303,12 @@ static void standard_accept_connection(struct tevent_context *ev,
smb_panic("Failed to re-initialise imessaging after fork");
}
- fde = tevent_add_fd(ev, ev, child_pipe[0], TEVENT_FD_READ,
+ fde = tevent_add_fd(ev, ev, from_parent_fd, TEVENT_FD_READ,
standard_pipe_handler, NULL);
if (fde == NULL) {
smb_panic("Failed to add fd handler after fork");
}
- if (child_pipe[1] != -1) {
- close(child_pipe[1]);
- child_pipe[1] = -1;
- }
-
se = tevent_add_signal(ev,
ev,
SIGHUP,
@@ -368,11 +354,12 @@ static void standard_accept_connection(struct tevent_context *ev,
/*
called to create a new server task
*/
-static void standard_new_task(struct tevent_context *ev,
+static void standard_new_task(struct tevent_context *ev,
struct loadparm_context *lp_ctx,
const char *service_name,
void (*new_task)(struct tevent_context *, struct loadparm_context *lp_ctx, struct server_id , void *),
- void *private_data)
+ void *private_data,
+ int new_from_parent_fd)
{
pid_t pid;
NTSTATUS status;
@@ -384,6 +371,7 @@ static void standard_new_task(struct tevent_context *ev,
if (state == NULL) {
return;
}
+ from_parent_fd = new_from_parent_fd;
pid = fork();
@@ -421,15 +409,11 @@ static void standard_new_task(struct tevent_context *ev,
smb_panic("Failed to re-initialise imessaging after fork");
}
- fde = tevent_add_fd(ev, ev, child_pipe[0], TEVENT_FD_READ,
+ fde = tevent_add_fd(ev, ev, from_parent_fd, TEVENT_FD_READ,
standard_pipe_handler, NULL);
if (fde == NULL) {
smb_panic("Failed to add fd handler after fork");
}
- if (child_pipe[1] != -1) {
- close(child_pipe[1]);
- child_pipe[1] = -1;
- }
se = tevent_add_signal(ev,
ev,
diff --git a/source4/smbd/server.c b/source4/smbd/server.c
index 249391c0dff..66f2794a38a 100644
--- a/source4/smbd/server.c
+++ b/source4/smbd/server.c
@@ -43,6 +43,11 @@
#include "lib/util/samba_modules.h"
#include "nsswitch/winbind_client.h"
#include "libds/common/roles.h"
+#include "lib/util/tfork.h"
+
+#ifdef HAVE_PTHREAD
+#include <pthread.h>
+#endif
struct server_state {
struct tevent_context *event_ctx;
@@ -332,6 +337,20 @@ static int event_ctx_destructor(struct tevent_context *event_ctx)
return 0;
}
+#ifdef HAVE_PTHREAD
+static int to_children_fd = -1;
+static void atfork_prepare(void) {
+}
+static void atfork_parent(void) {
+}
+static void atfork_child(void) {
+ if (to_children_fd != -1) {
+ close(to_children_fd);
+ to_children_fd = -1;
+ }
+}
+#endif
+
/*
main server.
*/
@@ -608,12 +627,54 @@ static int binary_smbd_main(const char *binary_name,
DEBUG(0,("%s: using '%s' process model\n", binary_name, model));
- status = server_service_startup(state->event_ctx, cmdline_lp_ctx, model,
- lpcfg_server_services(cmdline_lp_ctx));
- if (!NT_STATUS_IS_OK(status)) {
- TALLOC_FREE(state);
- exit_daemon("Samba failed to start services",
- NT_STATUS_V(status));
+ {
+ int child_pipe[2];
+ int rc;
+ bool start_services = false;
+
+ rc = pipe(child_pipe);
+ if (rc < 0) {
+ TALLOC_FREE(state);
+ exit_daemon("Samba failed to open process control pipe",
+ errno);
+ }
+ smb_set_close_on_exec(child_pipe[0]);
+ smb_set_close_on_exec(child_pipe[1]);
+
+#ifdef HAVE_PTHREAD
+ to_children_fd = child_pipe[1];
+ pthread_atfork(atfork_prepare, atfork_parent,
+ atfork_child);
+ start_services = true;
+#else
+ pid_t pid;
+ struct tfork *t = NULL;
+ t = tfork_create();
+ if (t == NULL) {
+ exit_daemon(
+ "Samba unable to fork master process",
+ 0);
+ }
+ pid = tfork_child_pid(t);
+ if (pid == 0) {
+ start_services = false;
+ } else {
+ /* In the child process */
+ start_services = true;
+ close(child_pipe[1]);
+ }
+#endif
+ if (start_services) {
+ status = server_service_startup(
+ state->event_ctx, cmdline_lp_ctx, model,
+ lpcfg_server_services(cmdline_lp_ctx),
+ child_pipe[0]);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(state);
+ exit_daemon("Samba failed to start services",
+ NT_STATUS_V(status));
+ }
+ }
}
if (opt_daemon) {
diff --git a/source4/smbd/service.c b/source4/smbd/service.c
index 403ae74964b..61ed684d00f 100644
--- a/source4/smbd/service.c
+++ b/source4/smbd/service.c
@@ -56,13 +56,16 @@ NTSTATUS register_server_service(TALLOC_CTX *ctx,
static NTSTATUS server_service_init(const char *name,
struct tevent_context *event_context,
struct loadparm_context *lp_ctx,
- const struct model_ops *model_ops)
+ const struct model_ops *model_ops,
+ int from_parent_fd)
{
struct registered_server *srv;
for (srv=registered_servers; srv; srv=srv->next) {
if (strcasecmp(name, srv->service_name) == 0) {
- return task_server_startup(event_context, lp_ctx, srv->service_name,
- model_ops, srv->task_init);
+ return task_server_startup(event_context, lp_ctx,
+ srv->service_name,
+ model_ops, srv->task_init,
+ from_parent_fd);
}
}
return NT_STATUS_INVALID_SYSTEM_SERVICE;
@@ -72,9 +75,10 @@ static NTSTATUS server_service_init(const char *name,
/*
startup all of our server services
*/
-NTSTATUS server_service_startup(struct tevent_context *event_ctx,
+NTSTATUS server_service_startup(struct tevent_context *event_ctx,
struct loadparm_context *lp_ctx,
- const char *model, const char **server_services)
+ const char *model, const char **server_services,
+ int from_parent_fd)
{
int i;
const struct model_ops *model_ops;
@@ -93,7 +97,8 @@ NTSTATUS server_service_startup(struct tevent_context *event_ctx,
for (i=0;server_services[i];i++) {
NTSTATUS status;
- status = server_service_init(server_services[i], event_ctx, lp_ctx, model_ops);
+ status = server_service_init(server_services[i], event_ctx,
+ lp_ctx, model_ops, from_parent_fd);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0,("Failed to start service '%s' - %s\n",
server_services[i], nt_errstr(status)));
diff --git a/source4/smbd/service_task.c b/source4/smbd/service_task.c
index 34f73d9f4b2..e0e98f644e1 100644
--- a/source4/smbd/service_task.c
+++ b/source4/smbd/service_task.c
@@ -101,7 +101,8 @@ NTSTATUS task_server_startup(struct tevent_context *event_ctx,
struct loadparm_context *lp_ctx,
const char *service_name,
const struct model_ops *model_ops,
- void (*task_init)(struct task_server *))
+ void (*task_init)(struct task_server *),
+ int from_parent_fd)
{
struct task_state *state;
@@ -110,8 +111,10 @@ NTSTATUS task_server_startup(struct tevent_context *event_ctx,
state->task_init = task_init;
state->model_ops = model_ops;
-
- model_ops->new_task(event_ctx, lp_ctx, service_name, task_server_callback, state);
+
+ state->model_ops->new_task(event_ctx, lp_ctx, service_name,
+ task_server_callback, state,
+ from_parent_fd);
return NT_STATUS_OK;
}