summaryrefslogtreecommitdiff
path: root/source4/smbd
diff options
context:
space:
mode:
authorGary Lockyer <gary@catalyst.net.nz>2017-09-15 07:09:23 +1200
committerAndrew Bartlett <abartlet@samba.org>2017-10-19 05:33:09 +0200
commitb852ad044b98c0c574c3420956e153055d46136d (patch)
tree4246355fbade866ba399d3e6266b7572df953b09 /source4/smbd
parent6d7a8d80cdc9ee996ff503d8834037001cf233d9 (diff)
downloadsamba-b852ad044b98c0c574c3420956e153055d46136d.tar.gz
source4/smbd: refactor the process model for prefork
Refactor the process model code to allow the addition of a prefork process model. - Add a process context to contain process model specific state - Add a service details structure to allow service to indicate which process model options they can support. In the new code the services advertise the features they support to the process model. The process model context is plumbed through to allow the process model to keep track of the supported options, and any state the process model may require. Signed-off-by: Gary Lockyer <gary@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abartlet@samba.org> Reviewed-by: Garming Sam <garming@catalyst.net.nz>
Diffstat (limited to 'source4/smbd')
-rw-r--r--source4/smbd/process_model.h15
-rw-r--r--source4/smbd/process_single.c21
-rw-r--r--source4/smbd/process_standard.c32
-rw-r--r--source4/smbd/service.c11
-rw-r--r--source4/smbd/service.h18
-rw-r--r--source4/smbd/service_named_pipe.c6
-rw-r--r--source4/smbd/service_stream.c23
-rw-r--r--source4/smbd/service_stream.h1
-rw-r--r--source4/smbd/service_task.c20
-rw-r--r--source4/smbd/service_task.h1
10 files changed, 105 insertions, 43 deletions
diff --git a/source4/smbd/process_model.h b/source4/smbd/process_model.h
index d7bf3c87c7b..656a7f2e29c 100644
--- a/source4/smbd/process_model.h
+++ b/source4/smbd/process_model.h
@@ -51,8 +51,8 @@ struct model_ops {
void (*)(struct tevent_context *,
struct loadparm_context *,
struct socket_context *,
- struct server_id , void *),
- void *);
+ struct server_id , void *, void *),
+ void *, void *);
/* function to create a task */
void (*new_task)(struct tevent_context *,
@@ -60,13 +60,16 @@ struct model_ops {
const char *service_name,
void (*)(struct tevent_context *,
struct loadparm_context *, struct server_id,
- void *),
+ void *, void *),
void *,
- int);
+ const struct service_details*,
+ const int);
/* function to terminate a connection or task */
- void (*terminate)(struct tevent_context *, struct loadparm_context *lp_ctx,
- const char *reason);
+ void (*terminate)(struct tevent_context *,
+ struct loadparm_context *lp_ctx,
+ const char *reason,
+ void * process_context);
/* function to set a title for the connection or task */
void (*set_title)(struct tevent_context *, const char *title);
diff --git a/source4/smbd/process_single.c b/source4/smbd/process_single.c
index 54169e9b0cc..1027415a555 100644
--- a/source4/smbd/process_single.c
+++ b/source4/smbd/process_single.c
@@ -44,8 +44,10 @@ static void single_accept_connection(struct tevent_context *ev,
void (*new_conn)(struct tevent_context *,
struct loadparm_context *,
struct socket_context *,
- struct server_id , void *),
- void *private_data)
+ struct server_id, void *,
+ void *),
+ void *private_data,
+ void *process_context)
{
NTSTATUS status;
struct socket_context *connected_socket;
@@ -79,7 +81,8 @@ static void single_accept_connection(struct tevent_context *ev,
* combination of pid/fd should be unique system-wide
*/
new_conn(ev, lp_ctx, connected_socket,
- cluster_id(pid, socket_get_fd(connected_socket)), private_data);
+ cluster_id(pid, socket_get_fd(connected_socket)), private_data,
+ process_context);
}
/*
@@ -88,8 +91,11 @@ static void single_accept_connection(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 (*new_task)(struct tevent_context *,
+ struct loadparm_context *,
+ struct server_id, void *, void *),
void *private_data,
+ const struct service_details *service_details,
int from_parent_fd)
{
pid_t pid = getpid();
@@ -105,12 +111,15 @@ static void single_new_task(struct tevent_context *ev,
* Using the pid unaltered makes debugging of which process
* owns the messaging socket easier.
*/
- new_task(ev, lp_ctx, cluster_id(pid, taskid++), private_data);
+ new_task(ev, lp_ctx, cluster_id(pid, taskid++), private_data, NULL);
}
/* called when a task goes down */
-static void single_terminate(struct tevent_context *ev, struct loadparm_context *lp_ctx, const char *reason)
+static void single_terminate(struct tevent_context *ev,
+ struct loadparm_context *lp_ctx,
+ const char *reason,
+ void *process_context)
{
DEBUG(3,("single_terminate: reason[%s]\n",reason));
}
diff --git a/source4/smbd/process_standard.c b/source4/smbd/process_standard.c
index c6cbfc23eda..431134e03ca 100644
--- a/source4/smbd/process_standard.c
+++ b/source4/smbd/process_standard.c
@@ -222,13 +222,18 @@ static struct standard_child_state *setup_standard_child_pipe(struct tevent_cont
/*
called when a listening socket becomes readable.
*/
-static void standard_accept_connection(struct tevent_context *ev,
- struct loadparm_context *lp_ctx,
- struct socket_context *sock,
- void (*new_conn)(struct tevent_context *,
- struct loadparm_context *, struct socket_context *,
- struct server_id , void *),
- void *private_data)
+static void standard_accept_connection(
+ struct tevent_context *ev,
+ struct loadparm_context *lp_ctx,
+ struct socket_context *sock,
+ void (*new_conn)(struct tevent_context *,
+ struct loadparm_context *,
+ struct socket_context *,
+ struct server_id,
+ void *,
+ void *),
+ void *private_data,
+ void *process_context)
{
NTSTATUS status;
struct socket_context *sock2;
@@ -340,7 +345,8 @@ static void standard_accept_connection(struct tevent_context *ev,
talloc_free(s);
/* setup this new connection. Cluster ID is PID based for this process model */
- new_conn(ev, lp_ctx, sock2, cluster_id(pid, 0), private_data);
+ new_conn(ev, lp_ctx, sock2, cluster_id(pid, 0), private_data,
+ NULL);
/* we can't return to the top level here, as that event context is gone,
so we now process events in the new event context until there are no
@@ -357,8 +363,9 @@ static void standard_accept_connection(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 (*new_task)(struct tevent_context *, struct loadparm_context *lp_ctx, struct server_id , void *, void *),
void *private_data,
+ const struct service_details *service_details,
int new_from_parent_fd)
{
pid_t pid;
@@ -438,11 +445,11 @@ static void standard_new_task(struct tevent_context *ev,
setproctitle("task %s server_id[%d]", service_name, (int)pid);
/* setup this new task. Cluster ID is PID based for this process model */
- new_task(ev, lp_ctx, cluster_id(pid, 0), private_data);
+ new_task(ev, lp_ctx, cluster_id(pid, 0), private_data, NULL);
/* we can't return to the top level here, as that event context is gone,
so we now process events in the new event context until there are no
- more to process */
+ more to process */
tevent_loop_wait(ev);
talloc_free(ev);
@@ -452,7 +459,8 @@ static void standard_new_task(struct tevent_context *ev,
/* called when a task goes down */
_NORETURN_ static void standard_terminate(struct tevent_context *ev, struct loadparm_context *lp_ctx,
- const char *reason)
+ const char *reason,
+ void *process_context)
{
DEBUG(2,("standard_terminate: reason[%s]\n",reason));
diff --git a/source4/smbd/service.c b/source4/smbd/service.c
index 61ed684d00f..9a77ca80b70 100644
--- a/source4/smbd/service.c
+++ b/source4/smbd/service.c
@@ -30,6 +30,7 @@
static struct registered_server {
struct registered_server *next, *prev;
const char *service_name;
+ struct service_details *service_details;
void (*task_init)(struct task_server *);
} *registered_servers;
@@ -38,13 +39,17 @@ static struct registered_server {
*/
NTSTATUS register_server_service(TALLOC_CTX *ctx,
const char *name,
- void (*task_init)(struct task_server *))
+ void (*task_init) (struct task_server *),
+ struct service_details *details)
{
struct registered_server *srv;
srv = talloc(ctx, struct registered_server);
NT_STATUS_HAVE_NO_MEMORY(srv);
srv->service_name = name;
srv->task_init = task_init;
+ srv->service_details =
+ talloc_memdup(ctx, details, sizeof(struct service_details));
+ NT_STATUS_HAVE_NO_MEMORY(srv->service_details);
DLIST_ADD_END(registered_servers, srv);
return NT_STATUS_OK;
}
@@ -64,7 +69,9 @@ static NTSTATUS server_service_init(const char *name,
if (strcasecmp(name, srv->service_name) == 0) {
return task_server_startup(event_context, lp_ctx,
srv->service_name,
- model_ops, srv->task_init,
+ model_ops,
+ srv->task_init,
+ srv->service_details,
from_parent_fd);
}
}
diff --git a/source4/smbd/service.h b/source4/smbd/service.h
index 23a9e6315b9..2d11f142aed 100644
--- a/source4/smbd/service.h
+++ b/source4/smbd/service.h
@@ -23,8 +23,26 @@
#ifndef __SERVICE_H__
#define __SERVICE_H__
+
#include "smbd/service_stream.h"
#include "smbd/service_task.h"
+
+struct service_details {
+ /*
+ * Prevent the standard process model from forking a new worker
+ * process when accepting a new connection. Do this when the service
+ * relies on shared state, or the over-head of forking would be a
+ * significant part of the response time
+ */
+ bool inhibit_fork_on_accept;
+ /*
+ * Prevent the pre-fork process model from pre-forking any worker
+ * processes. In this mode pre-fork is equivalent to standard with
+ * inhibit_fork_on_accept set.
+ */
+ bool inhibit_pre_fork;
+};
+
#include "smbd/service_proto.h"
#endif /* __SERVICE_H__ */
diff --git a/source4/smbd/service_named_pipe.c b/source4/smbd/service_named_pipe.c
index c7e31bc4718..744f9421717 100644
--- a/source4/smbd/service_named_pipe.c
+++ b/source4/smbd/service_named_pipe.c
@@ -188,7 +188,8 @@ NTSTATUS tstream_setup_named_pipe(TALLOC_CTX *mem_ctx,
const struct model_ops *model_ops,
const struct stream_server_ops *stream_ops,
const char *pipe_name,
- void *private_data)
+ void *private_data,
+ void *process_context)
{
char *dirname;
struct named_pipe_socket *pipe_sock;
@@ -248,7 +249,8 @@ NTSTATUS tstream_setup_named_pipe(TALLOC_CTX *mem_ctx,
pipe_sock->pipe_path,
NULL,
NULL,
- pipe_sock);
+ pipe_sock,
+ process_context);
if (!NT_STATUS_IS_OK(status)) {
goto fail;
}
diff --git a/source4/smbd/service_stream.c b/source4/smbd/service_stream.c
index 917a1876e07..3f4a04ccf84 100644
--- a/source4/smbd/service_stream.c
+++ b/source4/smbd/service_stream.c
@@ -44,6 +44,7 @@ struct stream_socket {
const struct model_ops *model_ops;
struct socket_context *sock;
void *private_data;
+ void *process_context;
};
@@ -55,6 +56,7 @@ void stream_terminate_connection(struct stream_connection *srv_conn, const char
struct tevent_context *event_ctx = srv_conn->event.ctx;
const struct model_ops *model_ops = srv_conn->model_ops;
struct loadparm_context *lp_ctx = srv_conn->lp_ctx;
+ void *process_context = srv_conn->process_context;
TALLOC_CTX *frame = NULL;
if (!reason) reason = "unknown reason";
@@ -89,8 +91,7 @@ void stream_terminate_connection(struct stream_connection *srv_conn, const char
srv_conn->event.fde = NULL;
imessaging_cleanup(srv_conn->msg_ctx);
TALLOC_FREE(srv_conn);
- model_ops->terminate(event_ctx, lp_ctx, reason);
-
+ model_ops->terminate(event_ctx, lp_ctx, reason, process_context);
TALLOC_FREE(frame);
}
@@ -138,7 +139,8 @@ NTSTATUS stream_new_connection_merge(struct tevent_context *ev,
const struct stream_server_ops *stream_ops,
struct imessaging_context *msg_ctx,
void *private_data,
- struct stream_connection **_srv_conn)
+ struct stream_connection **_srv_conn,
+ void *process_context)
{
struct stream_connection *srv_conn;
@@ -154,6 +156,7 @@ NTSTATUS stream_new_connection_merge(struct tevent_context *ev,
srv_conn->event.ctx = ev;
srv_conn->lp_ctx = lp_ctx;
srv_conn->event.fde = NULL;
+ srv_conn->process_context = process_context;
*_srv_conn = srv_conn;
return NT_STATUS_OK;
@@ -166,7 +169,9 @@ NTSTATUS stream_new_connection_merge(struct tevent_context *ev,
static void stream_new_connection(struct tevent_context *ev,
struct loadparm_context *lp_ctx,
struct socket_context *sock,
- struct server_id server_id, void *private_data)
+ struct server_id server_id,
+ void *private_data,
+ void *process_context)
{
struct stream_socket *stream_socket = talloc_get_type(private_data, struct stream_socket);
struct stream_connection *srv_conn;
@@ -186,6 +191,7 @@ static void stream_new_connection(struct tevent_context *ev,
srv_conn->ops = stream_socket->ops;
srv_conn->event.ctx = ev;
srv_conn->lp_ctx = lp_ctx;
+ srv_conn->process_context = process_context;
if (!socket_check_access(sock, "smbd", lpcfg_hosts_allow(NULL, lpcfg_default_service(lp_ctx)), lpcfg_hosts_deny(NULL, lpcfg_default_service(lp_ctx)))) {
stream_terminate_connection(srv_conn, "denied by access rules");
@@ -258,8 +264,9 @@ static void stream_accept_handler(struct tevent_context *ev, struct tevent_fd *f
connection. When done, it calls stream_new_connection()
with the newly created socket */
stream_socket->model_ops->accept_connection(ev, stream_socket->lp_ctx,
- stream_socket->sock,
- stream_new_connection, stream_socket);
+ stream_socket->sock,
+ stream_new_connection, stream_socket,
+ stream_socket->process_context);
}
/*
@@ -279,7 +286,8 @@ NTSTATUS stream_setup_socket(TALLOC_CTX *mem_ctx,
const char *sock_addr,
uint16_t *port,
const char *socket_options,
- void *private_data)
+ void *private_data,
+ void *process_context)
{
NTSTATUS status;
struct stream_socket *stream_socket;
@@ -385,6 +393,7 @@ NTSTATUS stream_setup_socket(TALLOC_CTX *mem_ctx,
stream_socket->ops = stream_ops;
stream_socket->event_ctx = event_context;
stream_socket->model_ops = model_ops;
+ stream_socket->process_context = process_context;
return NT_STATUS_OK;
}
diff --git a/source4/smbd/service_stream.h b/source4/smbd/service_stream.h
index a7d3def6eae..81bf2754beb 100644
--- a/source4/smbd/service_stream.h
+++ b/source4/smbd/service_stream.h
@@ -62,6 +62,7 @@ struct stream_connection {
uint processing;
const char *terminate;
+ void *process_context;
};
diff --git a/source4/smbd/service_task.c b/source4/smbd/service_task.c
index e0e98f644e1..1d33a43e919 100644
--- a/source4/smbd/service_task.c
+++ b/source4/smbd/service_task.c
@@ -50,8 +50,8 @@ void task_server_terminate(struct task_server *task, const char *reason, bool fa
imessaging_cleanup(task->msg_ctx);
- model_ops->terminate(event_ctx, task->lp_ctx, reason);
-
+ model_ops->terminate(event_ctx, task->lp_ctx, reason,
+ task->process_context);
/* don't free this above, it might contain the 'reason' being printed */
talloc_free(task);
}
@@ -67,9 +67,11 @@ struct task_state {
called by the process model code when the new task starts up. This then calls
the server specific startup code
*/
-static void task_server_callback(struct tevent_context *event_ctx,
+static void task_server_callback(struct tevent_context *event_ctx,
struct loadparm_context *lp_ctx,
- struct server_id server_id, void *private_data)
+ struct server_id server_id,
+ void *private_data,
+ void *context)
{
struct task_state *state = talloc_get_type(private_data, struct task_state);
struct task_server *task;
@@ -81,6 +83,7 @@ static void task_server_callback(struct tevent_context *event_ctx,
task->model_ops = state->model_ops;
task->server_id = server_id;
task->lp_ctx = lp_ctx;
+ task->process_context = context;
task->msg_ctx = imessaging_init(task,
task->lp_ctx,
@@ -97,11 +100,12 @@ static void task_server_callback(struct tevent_context *event_ctx,
/*
startup a task based server
*/
-NTSTATUS task_server_startup(struct tevent_context *event_ctx,
+NTSTATUS task_server_startup(struct tevent_context *event_ctx,
struct loadparm_context *lp_ctx,
- const char *service_name,
- const struct model_ops *model_ops,
+ const char *service_name,
+ const struct model_ops *model_ops,
void (*task_init)(struct task_server *),
+ const struct service_details *service_details,
int from_parent_fd)
{
struct task_state *state;
@@ -113,7 +117,7 @@ NTSTATUS task_server_startup(struct tevent_context *event_ctx,
state->model_ops = model_ops;
state->model_ops->new_task(event_ctx, lp_ctx, service_name,
- task_server_callback, state,
+ task_server_callback, state, service_details,
from_parent_fd);
return NT_STATUS_OK;
diff --git a/source4/smbd/service_task.h b/source4/smbd/service_task.h
index ded4590daff..2499dc1ddaf 100644
--- a/source4/smbd/service_task.h
+++ b/source4/smbd/service_task.h
@@ -31,6 +31,7 @@ struct task_server {
struct loadparm_context *lp_ctx;
struct server_id server_id;
void *private_data;
+ void *process_context;
};