2 Unix SMB/CIFS implementation.
5 Copyright (C) Simo Sorce <idra@samba.org> 2011
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "system/time.h"
23 #include "system/shmem.h"
24 #include "system/filesys.h"
25 #include "server_prefork.h"
26 #include "../lib/util/util.h"
27 #include "../lib/util/tevent_unix.h"
36 prefork_main_fn_t
*main_fn
;
40 struct pf_worker_data
*pool
;
44 prefork_sigchld_fn_t
*sigchld_fn
;
48 static bool prefork_setup_sigchld_handler(struct tevent_context
*ev_ctx
,
49 struct prefork_pool
*pfp
);
51 static int prefork_pool_destructor(struct prefork_pool
*pfp
)
53 anonymous_shared_free(pfp
->pool
);
57 bool prefork_create_pool(TALLOC_CTX
*mem_ctx
,
58 struct tevent_context
*ev_ctx
,
59 struct messaging_context
*msg_ctx
,
60 int listen_fd_size
, int *listen_fds
,
61 int min_children
, int max_children
,
62 prefork_main_fn_t
*main_fn
, void *private_data
,
63 struct prefork_pool
**pf_pool
)
65 struct prefork_pool
*pfp
;
67 time_t now
= time(NULL
);
73 pfp
= talloc_zero(mem_ctx
, struct prefork_pool
);
75 DEBUG(1, ("Out of memory!\n"));
78 pfp
->listen_fd_size
= listen_fd_size
;
79 pfp
->listen_fds
= talloc_array(pfp
, int, listen_fd_size
);
80 if (!pfp
->listen_fds
) {
81 DEBUG(1, ("Out of memory!\n"));
84 for (i
= 0; i
< listen_fd_size
; i
++) {
85 pfp
->listen_fds
[i
] = listen_fds
[i
];
87 pfp
->main_fn
= main_fn
;
88 pfp
->private_data
= private_data
;
90 pfp
->lock_fd
= create_unlink_tmp(NULL
);
91 if (pfp
->lock_fd
== -1) {
92 DEBUG(1, ("Failed to create prefork lock fd!\n"));
97 pfp
->pool_size
= max_children
;
98 data_size
= sizeof(struct pf_worker_data
) * max_children
;
100 pfp
->pool
= anonymous_shared_allocate(data_size
);
101 if (pfp
->pool
== NULL
) {
102 DEBUG(1, ("Failed to mmap memory for prefork pool!\n"));
106 talloc_set_destructor(pfp
, prefork_pool_destructor
);
108 for (i
= 0; i
< min_children
; i
++) {
110 pfp
->pool
[i
].allowed_clients
= 1;
111 pfp
->pool
[i
].started
= now
;
116 DEBUG(1, ("Failed to prefork child n. %d !\n", i
));
119 case 0: /* THE CHILD */
121 pfp
->pool
[i
].status
= PF_WORKER_IDLE
;
122 ret
= pfp
->main_fn(ev_ctx
, msg_ctx
,
123 &pfp
->pool
[i
], i
+ 1,
130 default: /* THE PARENT */
131 pfp
->pool
[i
].pid
= pid
;
136 ok
= prefork_setup_sigchld_handler(ev_ctx
, pfp
);
138 DEBUG(1, ("Failed to setup SIGCHLD Handler!\n"));
147 /* Provide the new max children number in new_max
148 * (must be larger than current max).
149 * Returns: 0 if all fine
150 * ENOSPC if mremap fails to expand
151 * EINVAL if new_max is invalid
153 int prefork_expand_pool(struct prefork_pool
*pfp
, int new_max
)
155 struct prefork_pool
*pool
;
160 if (new_max
<= pfp
->pool_size
) {
164 old_size
= sizeof(struct pf_worker_data
) * pfp
->pool_size
;
165 new_size
= sizeof(struct pf_worker_data
) * new_max
;
167 pool
= anonymous_shared_resize(&pfp
->pool
, new_size
, false);
170 DEBUG(3, ("Failed to mremap memory (%d: %s)!\n",
171 ret
, strerror(ret
)));
175 memset(&pool
[pfp
->pool_size
], 0, new_size
- old_size
);
177 pfp
->pool_size
= new_max
;
182 int prefork_add_children(struct tevent_context
*ev_ctx
,
183 struct messaging_context
*msg_ctx
,
184 struct prefork_pool
*pfp
,
188 time_t now
= time(NULL
);
192 for (i
= 0, j
= 0; i
< pfp
->pool_size
&& j
< num_children
; i
++) {
194 if (pfp
->pool
[i
].status
!= PF_WORKER_NONE
) {
198 pfp
->pool
[i
].allowed_clients
= 1;
199 pfp
->pool
[i
].started
= now
;
204 DEBUG(1, ("Failed to prefork child n. %d !\n", j
));
207 case 0: /* THE CHILD */
209 pfp
->pool
[i
].status
= PF_WORKER_IDLE
;
210 ret
= pfp
->main_fn(ev_ctx
, msg_ctx
,
211 &pfp
->pool
[i
], i
+ 1,
217 pfp
->pool
[i
].status
= PF_WORKER_EXITING
;
220 default: /* THE PARENT */
221 pfp
->pool
[i
].pid
= pid
;
227 DEBUG(5, ("Added %d children!\n", j
));
232 struct prefork_oldest
{
237 /* sort in inverse order */
238 static int prefork_sort_oldest(const void *ap
, const void *bp
)
240 const struct prefork_oldest
*a
= (const struct prefork_oldest
*)ap
;
241 const struct prefork_oldest
*b
= (const struct prefork_oldest
*)bp
;
243 if (a
->started
== b
->started
) {
246 if (a
->started
< b
->started
) {
252 int prefork_retire_children(struct prefork_pool
*pfp
,
253 int num_children
, time_t age_limit
)
255 time_t now
= time(NULL
);
256 struct prefork_oldest
*oldest
;
259 oldest
= talloc_array(pfp
, struct prefork_oldest
, pfp
->pool_size
);
264 for (i
= 0; i
< pfp
->pool_size
; i
++) {
266 if (pfp
->pool
[i
].status
== PF_WORKER_IDLE
) {
267 oldest
[i
].started
= pfp
->pool
[i
].started
;
269 oldest
[i
].started
= now
;
273 qsort(oldest
, pfp
->pool_size
,
274 sizeof(struct prefork_oldest
),
275 prefork_sort_oldest
);
277 for (i
= 0, j
= 0; i
< pfp
->pool_size
&& j
< num_children
; i
++) {
278 if (pfp
->pool
[i
].status
== PF_WORKER_IDLE
&&
279 pfp
->pool
[i
].started
<= age_limit
) {
280 /* tell the child it's time to give up */
281 DEBUG(5, ("Retiring pid %d!\n", pfp
->pool
[i
].pid
));
282 pfp
->pool
[i
].cmds
= PF_SRV_MSG_EXIT
;
283 kill(pfp
->pool
[i
].pid
, SIGHUP
);
291 int prefork_count_active_children(struct prefork_pool
*pfp
, int *total
)
297 for (i
= 0; i
< pfp
->pool_size
; i
++) {
298 if (pfp
->pool
[i
].status
== PF_WORKER_NONE
) {
304 if (pfp
->pool
[i
].num_clients
== 0) {
315 static void prefork_cleanup_loop(struct prefork_pool
*pfp
)
321 /* TODO: should we use a process group id wait instead of looping ? */
322 for (i
= 0; i
< pfp
->pool_size
; i
++) {
323 if (pfp
->pool
[i
].status
== PF_WORKER_NONE
||
324 pfp
->pool
[i
].pid
== 0) {
328 pid
= sys_waitpid(pfp
->pool
[i
].pid
, &status
, WNOHANG
);
331 if (pfp
->pool
[i
].status
!= PF_WORKER_EXITING
) {
332 DEBUG(3, ("Child (%d) terminated abnormally:"
333 " %d\n", (int)pid
, status
));
335 DEBUG(10, ("Child (%d) terminated with status:"
336 " %d\n", (int)pid
, status
));
340 * this makes status = PF_WORK_NONE */
341 memset(&pfp
->pool
[i
], 0,
342 sizeof(struct pf_worker_data
));
348 void prefork_increase_allowed_clients(struct prefork_pool
*pfp
, int max
)
352 for (i
= 0; i
< pfp
->pool_size
; i
++) {
353 if (pfp
->pool
[i
].status
== PF_WORKER_NONE
) {
357 if (pfp
->pool
[i
].allowed_clients
< max
) {
358 pfp
->pool
[i
].allowed_clients
++;
363 void prefork_reset_allowed_clients(struct prefork_pool
*pfp
)
367 for (i
= 0; i
< pfp
->pool_size
; i
++) {
368 pfp
->pool
[i
].allowed_clients
= 1;
372 void prefork_send_signal_to_all(struct prefork_pool
*pfp
, int signal_num
)
376 for (i
= 0; i
< pfp
->pool_size
; i
++) {
377 if (pfp
->pool
[i
].status
== PF_WORKER_NONE
) {
381 kill(pfp
->pool
[i
].pid
, signal_num
);
385 static void prefork_sigchld_handler(struct tevent_context
*ev_ctx
,
386 struct tevent_signal
*se
,
387 int signum
, int count
,
388 void *siginfo
, void *pvt
)
390 struct prefork_pool
*pfp
;
392 pfp
= talloc_get_type_abort(pvt
, struct prefork_pool
);
394 /* run the cleanup function to make sure all dead children are
395 * properly and timely retired. */
396 prefork_cleanup_loop(pfp
);
398 if (pfp
->sigchld_fn
) {
399 pfp
->sigchld_fn(ev_ctx
, pfp
, pfp
->sigchld_data
);
403 static bool prefork_setup_sigchld_handler(struct tevent_context
*ev_ctx
,
404 struct prefork_pool
*pfp
)
406 struct tevent_signal
*se
;
408 se
= tevent_add_signal(ev_ctx
, pfp
, SIGCHLD
, 0,
409 prefork_sigchld_handler
, pfp
);
411 DEBUG(0, ("Failed to setup SIGCHLD handler!\n"));
418 void prefork_set_sigchld_callback(struct prefork_pool
*pfp
,
419 prefork_sigchld_fn_t
*sigchld_fn
,
422 pfp
->sigchld_fn
= sigchld_fn
;
423 pfp
->sigchld_data
= private_data
;
426 /* ==== Functions used by children ==== */
428 static SIG_ATOMIC_T pf_alarm
;
430 static void pf_alarm_cb(int signum
)
438 * pf - the worker shared data structure
439 * lock_fd - the file descriptor used for locking
440 * timeout - expressed in seconds:
442 * 0 timeouts immediately
443 * N seconds before timing out
446 * negative errno on fatal error
447 * 0 on success to acquire lock
448 * -1 on timeout/lock held by other
449 * -2 on server msg to terminate
450 * ERRNO on other errors
453 static int prefork_grab_lock(struct pf_worker_data
*pf
,
454 int lock_fd
, int timeout
)
460 if (pf
->cmds
== PF_SRV_MSG_EXIT
) {
467 CatchSignal(SIGALRM
, pf_alarm_cb
);
480 lock
.l_type
= F_WRLCK
;
481 lock
.l_whence
= SEEK_SET
;
483 ret
= fcntl(lock_fd
, op
, &lock
);
488 if (pf
->cmds
== PF_SRV_MSG_EXIT
) {
499 /* lock held by other proc */
511 } while (timeout
!= 0);
514 /* We have the Lock */
515 pf
->status
= PF_WORKER_ACCEPTING
;
521 CatchSignal(SIGALRM
, SIG_IGN
);
525 DEBUG(1, ("Failed to get lock (%d, %s)!\n",
526 ret
, strerror(ret
)));
533 * pf - the worker shared data structure
534 * lock_fd - the file descriptor used for locking
535 * timeout - expressed in seconds:
537 * 0 timeouts immediately
538 * N seconds before timing out
541 * negative errno on fatal error
542 * 0 on success to release lock
547 static int prefork_release_lock(struct pf_worker_data
*pf
,
548 int lock_fd
, int timeout
)
557 CatchSignal(SIGALRM
, pf_alarm_cb
);
569 lock
.l_type
= F_UNLCK
;
570 lock
.l_whence
= SEEK_SET
;
572 ret
= fcntl(lock_fd
, op
, &lock
);
586 } while (timeout
!= 0);
591 CatchSignal(SIGALRM
, SIG_IGN
);
595 DEBUG(1, ("Failed to release lock (%d, %s)!\n",
596 ret
, strerror(ret
)));
601 /* ==== async code ==== */
603 #define PF_ASYNC_LOCK_GRAB 0x01
604 #define PF_ASYNC_LOCK_RELEASE 0x02
605 #define PF_ASYNC_ACTION_MASK 0x03
606 #define PF_ASYNC_LOCK_DONE 0x04
608 struct pf_lock_state
{
609 struct pf_worker_data
*pf
;
614 static void prefork_lock_handler(struct tevent_context
*ev
,
615 struct tevent_timer
*te
,
616 struct timeval curtime
, void *pvt
);
618 static struct tevent_req
*prefork_lock_send(TALLOC_CTX
*mem_ctx
,
619 struct tevent_context
*ev
,
620 struct pf_worker_data
*pf
,
621 int lock_fd
, int action
)
623 struct tevent_req
*req
;
624 struct pf_lock_state
*state
;
626 req
= tevent_req_create(mem_ctx
, &state
, struct pf_lock_state
);
632 state
->lock_fd
= lock_fd
;
633 state
->flags
= action
;
635 /* try once immediately */
636 prefork_lock_handler(ev
, NULL
, tevent_timeval_zero(), req
);
637 if (state
->flags
& PF_ASYNC_LOCK_DONE
) {
638 tevent_req_post(req
, ev
);
644 static void prefork_lock_handler(struct tevent_context
*ev
,
645 struct tevent_timer
*te
,
646 struct timeval curtime
, void *pvt
)
648 struct tevent_req
*req
;
649 struct pf_lock_state
*state
;
654 req
= talloc_get_type_abort(pvt
, struct tevent_req
);
655 state
= tevent_req_data(req
, struct pf_lock_state
);
657 if (state
->pf
->num_clients
> 0) {
661 switch (state
->flags
& PF_ASYNC_ACTION_MASK
) {
662 case PF_ASYNC_LOCK_GRAB
:
663 ret
= prefork_grab_lock(state
->pf
, state
->lock_fd
, timeout
);
665 case PF_ASYNC_LOCK_RELEASE
:
666 ret
= prefork_release_lock(state
->pf
, state
->lock_fd
, timeout
);
675 state
->flags
|= PF_ASYNC_LOCK_DONE
;
676 tevent_req_done(req
);
680 tv
= tevent_timeval_zero();
682 tv
= tevent_timeval_current_ofs(0, 100000);
684 te
= tevent_add_timer(ev
, state
, tv
,
685 prefork_lock_handler
, req
);
686 tevent_req_nomem(te
, req
);
689 /* server tells us to stop */
690 state
->flags
|= PF_ASYNC_LOCK_DONE
;
691 tevent_req_error(req
, -2);
694 state
->flags
|= PF_ASYNC_LOCK_DONE
;
695 tevent_req_error(req
, ret
);
700 static int prefork_lock_recv(struct tevent_req
*req
)
704 if (!tevent_req_is_unix_error(req
, &ret
)) {
708 tevent_req_received(req
);
712 struct pf_listen_state
{
713 struct tevent_context
*ev
;
714 struct pf_worker_data
*pf
;
723 struct tsocket_address
*srv_addr
;
724 struct tsocket_address
*cli_addr
;
729 static void prefork_listen_lock_done(struct tevent_req
*subreq
);
730 static void prefork_listen_accept_handler(struct tevent_context
*ev
,
731 struct tevent_fd
*fde
,
732 uint16_t flags
, void *pvt
);
733 static void prefork_listen_release_done(struct tevent_req
*subreq
);
735 struct tevent_req
*prefork_listen_send(TALLOC_CTX
*mem_ctx
,
736 struct tevent_context
*ev
,
737 struct pf_worker_data
*pf
,
742 struct tevent_req
*req
, *subreq
;
743 struct pf_listen_state
*state
;
745 req
= tevent_req_create(mem_ctx
, &state
, struct pf_listen_state
);
752 state
->lock_fd
= lock_fd
;
753 state
->listen_fd_size
= listen_fd_size
;
754 state
->listen_fds
= listen_fds
;
755 state
->accept_fd
= -1;
758 subreq
= prefork_lock_send(state
, state
->ev
, state
->pf
,
759 state
->lock_fd
, PF_ASYNC_LOCK_GRAB
);
760 if (tevent_req_nomem(subreq
, req
)) {
761 return tevent_req_post(req
, ev
);
764 tevent_req_set_callback(subreq
, prefork_listen_lock_done
, req
);
768 struct pf_listen_ctx
{
770 struct tevent_req
*req
;
774 static void prefork_listen_lock_done(struct tevent_req
*subreq
)
776 struct tevent_req
*req
;
777 struct pf_listen_state
*state
;
778 struct pf_listen_ctx
*ctx
;
779 struct tevent_fd
*fde
;
784 req
= tevent_req_callback_data(subreq
, struct tevent_req
);
785 state
= tevent_req_data(req
, struct pf_listen_state
);
787 ret
= prefork_lock_recv(subreq
);
789 tevent_req_error(req
, ret
);
793 fde_ctx
= talloc_new(state
);
794 if (tevent_req_nomem(fde_ctx
, req
)) {
798 /* next step, accept */
799 for (i
= 0; i
< state
->listen_fd_size
; i
++) {
800 ctx
= talloc(fde_ctx
, struct pf_listen_ctx
);
801 if (tevent_req_nomem(ctx
, req
)) {
804 ctx
->fde_ctx
= fde_ctx
;
806 ctx
->listen_fd
= state
->listen_fds
[i
];
808 fde
= tevent_add_fd(state
->ev
, fde_ctx
,
809 ctx
->listen_fd
, TEVENT_FD_READ
,
810 prefork_listen_accept_handler
, ctx
);
811 if (tevent_req_nomem(fde
, req
)) {
817 static void prefork_listen_accept_handler(struct tevent_context
*ev
,
818 struct tevent_fd
*fde
,
819 uint16_t flags
, void *pvt
)
821 struct pf_listen_state
*state
;
822 struct tevent_req
*req
, *subreq
;
823 struct pf_listen_ctx
*ctx
;
824 struct sockaddr_storage addr
;
830 ctx
= talloc_get_type_abort(pvt
, struct pf_listen_ctx
);
831 state
= tevent_req_data(ctx
->req
, struct pf_listen_state
);
834 addrlen
= sizeof(addr
);
835 sd
= accept(ctx
->listen_fd
, (struct sockaddr
*)&addr
, &addrlen
);
837 if (errno
== EINTR
) {
842 DEBUG(6, ("Accept failed! (%d, %s)\n", err
, strerror(err
)));
845 /* do not track the listen fds anymore */
847 talloc_free(ctx
->fde_ctx
);
854 state
->accept_fd
= sd
;
856 ret
= tsocket_address_bsd_from_sockaddr(state
,
857 (struct sockaddr
*)(void *)&addr
,
858 addrlen
, &state
->cli_addr
);
860 state
->error
= errno
;
865 addrlen
= sizeof(addr
);
866 ret
= getsockname(sd
, (struct sockaddr
*)(void *)&addr
, &addrlen
);
868 state
->error
= errno
;
872 ret
= tsocket_address_bsd_from_sockaddr(state
,
873 (struct sockaddr
*)(void *)&addr
,
874 addrlen
, &state
->srv_addr
);
876 state
->error
= errno
;
881 /* release lock now */
882 subreq
= prefork_lock_send(state
, state
->ev
, state
->pf
,
883 state
->lock_fd
, PF_ASYNC_LOCK_RELEASE
);
884 if (tevent_req_nomem(subreq
, req
)) {
887 tevent_req_set_callback(subreq
, prefork_listen_release_done
, req
);
890 static void prefork_listen_release_done(struct tevent_req
*subreq
)
892 struct tevent_req
*req
;
895 req
= tevent_req_callback_data(subreq
, struct tevent_req
);
897 ret
= prefork_lock_recv(subreq
);
899 tevent_req_error(req
, ret
);
903 tevent_req_done(req
);
906 int prefork_listen_recv(struct tevent_req
*req
,
907 TALLOC_CTX
*mem_ctx
, int *fd
,
908 struct tsocket_address
**srv_addr
,
909 struct tsocket_address
**cli_addr
)
911 struct pf_listen_state
*state
;
914 state
= tevent_req_data(req
, struct pf_listen_state
);
919 tevent_req_is_unix_error(req
, &ret
);
923 if (state
->accept_fd
!= -1) {
924 close(state
->accept_fd
);
927 *fd
= state
->accept_fd
;
928 *srv_addr
= talloc_move(mem_ctx
, &state
->srv_addr
);
929 *cli_addr
= talloc_move(mem_ctx
, &state
->cli_addr
);
930 state
->pf
->status
= PF_WORKER_BUSY
;
931 state
->pf
->num_clients
++;
934 tevent_req_received(req
);