1 /* Reincarnation Server. This servers starts new system services and detects
2 * they are exiting. In case of errors, system services can be restarted.
3 * The RS server periodically checks the status of all registered services
4 * services to see whether they are still alive. The system services are
5 * expected to periodically send a heartbeat message.
8 * Nov 22, 2009: rewrite of boot process (Cristiano Giuffrida)
9 * Jul 22, 2005: Created (Jorrit N. Herder)
13 #include "kernel/const.h"
14 #include "kernel/type.h"
15 #include "kernel/proc.h"
17 /* Declare some local functions. */
18 static void boot_image_info_lookup( endpoint_t endpoint
, struct
19 boot_image
*image
, struct boot_image
**ip
, struct boot_image_priv
**pp
,
20 struct boot_image_sys
**sp
, struct boot_image_dev
**dp
);
21 static void catch_boot_init_ready(endpoint_t endpoint
);
22 static void get_work(message
*m_ptr
, int *status_ptr
);
24 /* SEF functions and variables. */
25 static void sef_local_startup(void);
26 static int sef_cb_init_fresh(int type
, sef_init_info_t
*info
);
27 static void sef_cb_signal_handler(int signo
);
28 static int sef_cb_signal_manager(endpoint_t target
, int signo
);
31 /*===========================================================================*
33 *===========================================================================*/
36 /* This is the main routine of this service. The main loop consists of
37 * three major activities: getting new work, processing the work, and
38 * sending the reply. The loop never terminates, unless a panic occurs.
40 message m
; /* request message */
41 int ipc_status
; /* status code */
42 int call_nr
, who_e
,who_p
; /* call number and caller */
43 int result
; /* result to return */
46 /* SEF local startup. */
49 if (OK
!= (s
=sys_getmachine(&machine
)))
50 panic("couldn't get machine info: %d", s
);
52 if (OK
!= (s
=sys_getkinfo(&kinfo
)))
53 panic("couldn't get kernel kinfo: %d", s
);
55 /* Main loop - get work and do it, forever. */
58 /* Wait for request message. */
59 get_work(&m
, &ipc_status
);
61 if(rs_isokendpt(who_e
, &who_p
) != OK
) {
62 panic("message from bogus source: %d", who_e
);
67 /* Now determine what to do. Four types of requests are expected:
68 * - Heartbeat messages (notifications from registered system services)
69 * - System notifications (synchronous alarm)
70 * - User requests (control messages to manage system services)
71 * - Ready messages (reply messages from registered services)
74 /* Notification messages are control messages and do not need a reply.
75 * These include heartbeat messages and system notifications.
77 if (is_ipc_notify(ipc_status
)) {
80 do_period(&m
); /* check services status */
82 default: /* heartbeat notification */
83 if (rproc_ptr
[who_p
] != NULL
) { /* mark heartbeat time */
84 rproc_ptr
[who_p
]->r_alive_tm
= m
.NOTIFY_TIMESTAMP
;
86 printf("RS: warning: got unexpected notify message from %d\n",
92 /* If we get this far, this is a normal request.
93 * Handle the request and send a reply to the caller.
96 if (call_nr
!= COMMON_GETSYSINFO
&&
97 (call_nr
< RS_RQ_BASE
|| call_nr
>= RS_RQ_BASE
+0x100))
99 /* Ignore invalid requests. Do not try to reply. */
100 printf("RS: warning: got invalid request %d from endpoint %d\n",
101 call_nr
, m
.m_source
);
105 /* Handler functions are responsible for permission checking. */
108 case RS_UP
: result
= do_up(&m
); break;
109 case RS_DOWN
: result
= do_down(&m
); break;
110 case RS_REFRESH
: result
= do_refresh(&m
); break;
111 case RS_RESTART
: result
= do_restart(&m
); break;
112 case RS_SHUTDOWN
: result
= do_shutdown(&m
); break;
113 case RS_UPDATE
: result
= do_update(&m
); break;
114 case RS_CLONE
: result
= do_clone(&m
); break;
115 case RS_EDIT
: result
= do_edit(&m
); break;
116 case COMMON_GETSYSINFO
:
117 result
= do_getsysinfo(&m
); break;
118 case RS_LOOKUP
: result
= do_lookup(&m
); break;
119 /* Ready messages. */
120 case RS_INIT
: result
= do_init_ready(&m
); break;
121 case RS_LU_PREPARE
: result
= do_upd_ready(&m
); break;
123 printf("RS: warning: got unexpected request %d from %d\n",
124 m
.m_type
, m
.m_source
);
128 /* Finally send reply message, unless disabled. */
129 if (result
!= EDONTREPLY
) {
131 reply(who_e
, NULL
, &m
);
137 /*===========================================================================*
138 * sef_local_startup *
139 *===========================================================================*/
140 static void sef_local_startup()
142 /* Register init callbacks. */
143 sef_setcb_init_response(do_init_ready
);
144 sef_setcb_init_fresh(sef_cb_init_fresh
);
145 sef_setcb_init_restart(sef_cb_init_fail
);
147 /* Register live update callbacks. */
148 sef_setcb_lu_response(do_upd_ready
);
150 /* Register signal callbacks. */
151 sef_setcb_signal_handler(sef_cb_signal_handler
);
152 sef_setcb_signal_manager(sef_cb_signal_manager
);
154 /* Let SEF perform startup. */
158 /*===========================================================================*
159 * sef_cb_init_fresh *
160 *===========================================================================*/
161 static int sef_cb_init_fresh(int UNUSED(type
), sef_init_info_t
*UNUSED(info
))
163 /* Initialize the reincarnation server. */
164 struct boot_image
*ip
;
166 int nr_image_srvs
, nr_image_priv_srvs
, nr_uncaught_init_srvs
;
168 struct rprocpub
*rpub
;
169 struct boot_image image
[NR_BOOT_PROCS
];
170 struct boot_image_priv
*boot_image_priv
;
171 struct boot_image_sys
*boot_image_sys
;
172 struct boot_image_dev
*boot_image_dev
;
175 int all_c
[] = { ALL_C
, NULL_C
};
176 int no_c
[] = { NULL_C
};
178 /* See if we run in verbose mode. */
179 env_parse("rs_verbose", "d", 0, &rs_verbose
, 0, 1);
181 if ((s
= sys_getinfo(GET_HZ
, &system_hz
, sizeof(system_hz
), 0, 0)) != OK
)
182 panic("Cannot get system timer frequency\n");
184 /* Initialize the global init descriptor. */
185 rinit
.rproctab_gid
= cpf_grant_direct(ANY
, (vir_bytes
) rprocpub
,
186 sizeof(rprocpub
), CPF_READ
);
187 if(!GRANT_VALID(rinit
.rproctab_gid
)) {
188 panic("unable to create rprocpub table grant: %d", rinit
.rproctab_gid
);
191 /* Initialize some global variables. */
193 shutting_down
= FALSE
;
195 /* Get a copy of the boot image table. */
196 if ((s
= sys_getimage(image
)) != OK
) {
197 panic("unable to get copy of boot image table: %d", s
);
200 /* Determine the number of system services in the boot image table. */
202 for(i
=0;i
<NR_BOOT_PROCS
;i
++) {
205 /* System services only. */
206 if(iskerneln(_ENDPOINT_P(ip
->endpoint
))) {
212 /* Determine the number of entries in the boot image priv table and make sure
213 * it matches the number of system services in the boot image table.
215 nr_image_priv_srvs
= 0;
216 for (i
=0; boot_image_priv_table
[i
].endpoint
!= NULL_BOOT_NR
; i
++) {
217 boot_image_priv
= &boot_image_priv_table
[i
];
219 /* System services only. */
220 if(iskerneln(_ENDPOINT_P(boot_image_priv
->endpoint
))) {
223 nr_image_priv_srvs
++;
225 if(nr_image_srvs
!= nr_image_priv_srvs
) {
226 panic("boot image table and boot image priv table mismatch");
229 /* Reset the system process table. */
230 for (rp
=BEG_RPROC_ADDR
; rp
<END_RPROC_ADDR
; rp
++) {
232 rp
->r_pub
= &rprocpub
[rp
- rproc
];
233 rp
->r_pub
->in_use
= FALSE
;
236 /* Initialize the system process table in 4 steps, each of them following
237 * the appearance of system services in the boot image priv table.
238 * - Step 1: set priviliges, sys properties, and dev properties (if any)
239 * for every system service.
241 for (i
=0; boot_image_priv_table
[i
].endpoint
!= NULL_BOOT_NR
; i
++) {
242 boot_image_priv
= &boot_image_priv_table
[i
];
244 /* System services only. */
245 if(iskerneln(_ENDPOINT_P(boot_image_priv
->endpoint
))) {
249 /* Lookup the corresponding entries in other tables. */
250 boot_image_info_lookup(boot_image_priv
->endpoint
, image
,
251 &ip
, NULL
, &boot_image_sys
, &boot_image_dev
);
252 rp
= &rproc
[boot_image_priv
- boot_image_priv_table
];
259 strcpy(rpub
->label
, boot_image_priv
->label
);
261 /* Force a static priv id for system services in the boot image. */
262 rp
->r_priv
.s_id
= static_priv_id(
263 _ENDPOINT_P(boot_image_priv
->endpoint
));
265 /* Initialize privilege bitmaps and signal manager. */
266 rp
->r_priv
.s_flags
= boot_image_priv
->flags
; /* priv flags */
267 rp
->r_priv
.s_trap_mask
= SRV_OR_USR(rp
, SRV_T
, USR_T
); /* traps */
268 ipc_to
= SRV_OR_USR(rp
, SRV_M
, USR_M
); /* targets */
269 fill_send_mask(&rp
->r_priv
.s_ipc_to
, ipc_to
== ALL_M
);
270 rp
->r_priv
.s_sig_mgr
= SRV_OR_USR(rp
, SRV_SM
, USR_SM
); /* sig mgr */
271 rp
->r_priv
.s_bak_sig_mgr
= NONE
; /* backup sig mgr */
273 /* Initialize kernel call mask bitmap. */
274 calls
= SRV_OR_USR(rp
, SRV_KC
, USR_KC
) == ALL_C
? all_c
: no_c
;
275 fill_call_mask(calls
, NR_SYS_CALLS
,
276 rp
->r_priv
.s_k_call_mask
, KERNEL_CALL
, TRUE
);
278 /* Set the privilege structure. RS and VM are exceptions and are already
281 if(boot_image_priv
->endpoint
!= RS_PROC_NR
&&
282 boot_image_priv
->endpoint
!= VM_PROC_NR
) {
283 if ((s
= sys_privctl(ip
->endpoint
, SYS_PRIV_SET_SYS
, &(rp
->r_priv
)))
285 panic("unable to set privilege structure: %d", s
);
289 /* Synch the privilege structure with the kernel. */
290 if ((s
= sys_getpriv(&(rp
->r_priv
), ip
->endpoint
)) != OK
) {
291 panic("unable to synch privilege structure: %d", s
);
295 * Set sys properties.
297 rpub
->sys_flags
= boot_image_sys
->flags
; /* sys flags */
300 * Set dev properties.
302 rpub
->dev_flags
= boot_image_dev
->flags
; /* device flags */
303 rpub
->dev_nr
= boot_image_dev
->dev_nr
; /* major device number */
304 rpub
->dev_style
= boot_image_dev
->dev_style
; /* device style */
305 rpub
->dev_style2
= boot_image_dev
->dev_style2
; /* device style 2 */
307 /* Build command settings. This will also set the process name. */
308 strlcpy(rp
->r_cmd
, ip
->proc_name
, sizeof(rp
->r_cmd
));
309 rp
->r_script
[0]= '\0';
312 /* Initialize vm call mask bitmap. */
313 calls
= SRV_OR_USR(rp
, SRV_VC
, USR_VC
) == ALL_C
? all_c
: no_c
;
314 fill_call_mask(calls
, NR_VM_CALLS
, rpub
->vm_call_mask
, VM_RQ_BASE
, TRUE
);
316 /* Scheduling parameters. */
317 rp
->r_scheduler
= SRV_OR_USR(rp
, SRV_SCH
, USR_SCH
);
318 rp
->r_priority
= SRV_OR_USR(rp
, SRV_Q
, USR_Q
);
319 rp
->r_quantum
= SRV_OR_USR(rp
, SRV_QT
, USR_QT
);
321 /* Get some settings from the boot image table. */
322 rpub
->endpoint
= ip
->endpoint
;
324 /* Set some defaults. */
325 rp
->r_old_rp
= NULL
; /* no old version yet */
326 rp
->r_new_rp
= NULL
; /* no new version yet */
327 rp
->r_prev_rp
= NULL
; /* no prev replica yet */
328 rp
->r_next_rp
= NULL
; /* no next replica yet */
329 rp
->r_uid
= 0; /* root */
330 rp
->r_check_tm
= 0; /* not checked yet */
331 getuptime(&rp
->r_alive_tm
); /* currently alive */
332 rp
->r_stop_tm
= 0; /* not exiting yet */
333 rp
->r_restarts
= 0; /* no restarts so far */
334 rp
->r_period
= 0; /* no period yet */
335 rp
->r_exec
= NULL
; /* no in-memory copy yet */
338 /* Mark as in use and active. */
339 rp
->r_flags
= RS_IN_USE
| RS_ACTIVE
;
340 rproc_ptr
[_ENDPOINT_P(rpub
->endpoint
)]= rp
;
344 /* - Step 2: allow every system service in the boot image to run. */
345 nr_uncaught_init_srvs
= 0;
346 for (i
=0; boot_image_priv_table
[i
].endpoint
!= NULL_BOOT_NR
; i
++) {
347 boot_image_priv
= &boot_image_priv_table
[i
];
349 /* System services only. */
350 if(iskerneln(_ENDPOINT_P(boot_image_priv
->endpoint
))) {
354 /* Lookup the corresponding slot in the system process table. */
355 rp
= &rproc
[boot_image_priv
- boot_image_priv_table
];
358 /* RS/VM are already running as we speak. */
359 if(boot_image_priv
->endpoint
== RS_PROC_NR
||
360 boot_image_priv
->endpoint
== VM_PROC_NR
) {
361 if ((s
= init_service(rp
, SEF_INIT_FRESH
)) != OK
) {
362 panic("unable to initialize %d: %d", boot_image_priv
->endpoint
, s
);
367 /* Allow the service to run. */
368 if ((s
= sched_init_proc(rp
)) != OK
) {
369 panic("unable to initialize scheduling: %d", s
);
371 if ((s
= sys_privctl(rpub
->endpoint
, SYS_PRIV_ALLOW
, NULL
)) != OK
) {
372 panic("unable to initialize privileges: %d", s
);
375 /* Initialize service. We assume every service will always get
376 * back to us here at boot time.
378 if(boot_image_priv
->flags
& SYS_PROC
) {
379 if ((s
= init_service(rp
, SEF_INIT_FRESH
)) != OK
) {
380 panic("unable to initialize service: %d", s
);
382 if(rpub
->sys_flags
& SF_SYNCH_BOOT
) {
383 /* Catch init ready message now to synchronize. */
384 catch_boot_init_ready(rpub
->endpoint
);
387 /* Catch init ready message later. */
388 nr_uncaught_init_srvs
++;
393 /* - Step 3: let every system service complete initialization by
394 * catching all the init ready messages left.
396 while(nr_uncaught_init_srvs
) {
397 catch_boot_init_ready(ANY
);
398 nr_uncaught_init_srvs
--;
401 /* - Step 4: all the system services in the boot image are now running.
402 * Complete the initialization of the system process table in collaboration
403 * with other system services.
405 for (i
=0; boot_image_priv_table
[i
].endpoint
!= NULL_BOOT_NR
; i
++) {
406 boot_image_priv
= &boot_image_priv_table
[i
];
408 /* System services only. */
409 if(iskerneln(_ENDPOINT_P(boot_image_priv
->endpoint
))) {
413 /* Lookup the corresponding slot in the system process table. */
414 rp
= &rproc
[boot_image_priv
- boot_image_priv_table
];
417 /* Get pid from PM. */
418 rp
->r_pid
= getnpid(rpub
->endpoint
);
419 if(rp
->r_pid
== -1) {
420 panic("unable to get pid");
424 /* Set alarm to periodically check service status. */
425 if (OK
!= (s
=sys_setalarm(RS_DELTA_T
, 0)))
426 panic("couldn't set alarm: %d", s
);
429 /* Now create a new RS instance and let the current
430 * instance live update into the replica. Clone RS' own slot first.
432 rp
= rproc_ptr
[_ENDPOINT_P(RS_PROC_NR
)];
433 if((s
= clone_slot(rp
, &replica_rp
)) != OK
) {
434 panic("unable to clone current RS instance: %d", s
);
437 /* Fork a new RS instance with root:operator. */
438 pid
= srv_fork(0, 0);
440 panic("unable to fork a new RS instance");
442 replica_pid
= pid
? pid
: getpid();
443 replica_endpoint
= getnprocnr(replica_pid
);
444 replica_rp
->r_pid
= replica_pid
;
445 replica_rp
->r_pub
->endpoint
= replica_endpoint
;
448 /* New RS instance running. */
450 /* Live update the old instance into the new one. */
451 s
= update_service(&rp
, &replica_rp
, RS_SWAP
);
453 panic("unable to live update RS: %d", s
);
457 /* Clean up the old RS instance, the new instance will take over. */
460 /* Ask VM to pin memory for the new RS instance. */
461 if((s
= vm_memctl(RS_PROC_NR
, VM_RS_MEM_PIN
)) != OK
) {
462 panic("unable to pin memory for the new RS instance: %d", s
);
466 /* Old RS instance running. */
468 /* Set up privileges for the new instance and let it run. */
469 s
= sys_privctl(replica_endpoint
, SYS_PRIV_SET_SYS
, &(replica_rp
->r_priv
));
471 panic("unable to set privileges for the new RS instance: %d", s
);
473 if ((s
= sched_init_proc(replica_rp
)) != OK
) {
474 panic("unable to initialize RS replica scheduling: %d", s
);
476 s
= sys_privctl(replica_endpoint
, SYS_PRIV_YIELD
, NULL
);
478 panic("unable to yield control to the new RS instance: %d", s
);
482 #endif /* USE_LIVEUPDATE */
487 /*===========================================================================*
488 * sef_cb_signal_handler *
489 *===========================================================================*/
490 static void sef_cb_signal_handler(int signo
)
492 /* Check for known signals, ignore anything else. */
503 /*===========================================================================*
504 * sef_cb_signal_manager *
505 *===========================================================================*/
506 static int sef_cb_signal_manager(endpoint_t target
, int signo
)
508 /* Process system signal on behalf of the kernel. */
511 struct rprocpub
*rpub
;
515 if(rs_isokendpt(target
, &target_p
) != OK
|| rproc_ptr
[target_p
] == NULL
) {
517 printf("RS: ignoring spurious signal %d for process %d\n",
519 return OK
; /* clear the signal */
521 rp
= rproc_ptr
[target_p
];
524 /* Don't bother if a termination signal has already been processed. */
525 if((rp
->r_flags
& RS_TERMINATED
) && !(rp
->r_flags
& RS_EXITING
)) {
526 return EDEADEPT
; /* process is gone */
529 /* Ignore external signals for inactive service instances. */
530 if( !(rp
->r_flags
& RS_ACTIVE
) && !(rp
->r_flags
& RS_EXITING
)) {
532 printf("RS: ignoring signal %d for inactive %s\n",
533 signo
, srv_to_string(rp
));
534 return OK
; /* clear the signal */
538 printf("RS: %s got %s signal %d\n", srv_to_string(rp
),
539 SIGS_IS_TERMINATION(signo
) ? "termination" : "non-termination",signo
);
541 /* Print stacktrace if necessary. */
542 if(SIGS_IS_STACKTRACE(signo
)) {
543 sys_sysctl_stacktrace(target
);
546 /* In case of termination signal handle the event. */
547 if(SIGS_IS_TERMINATION(signo
)) {
548 rp
->r_flags
|= RS_TERMINATED
;
549 terminate_service(rp
);
551 return EDEADEPT
; /* process is now gone */
554 /* Translate every non-termination signal into a message. */
555 m
.m_type
= SIGS_SIGNAL_RECEIVED
;
556 m
.SIGS_SIG_NUM
= signo
;
557 asynsend3(rpub
->endpoint
, &m
, AMF_NOREPLY
);
559 return OK
; /* signal has been delivered */
562 /*===========================================================================*
563 * boot_image_info_lookup *
564 *===========================================================================*/
565 static void boot_image_info_lookup(endpoint
, image
, ip
, pp
, sp
, dp
)
567 struct boot_image
*image
;
568 struct boot_image
**ip
;
569 struct boot_image_priv
**pp
;
570 struct boot_image_sys
**sp
;
571 struct boot_image_dev
**dp
;
573 /* Lookup entries in boot image tables. */
576 /* When requested, locate the corresponding entry in the boot image table
577 * or panic if not found.
580 for (i
=0; i
< NR_BOOT_PROCS
; i
++) {
581 if(image
[i
].endpoint
== endpoint
) {
586 if(i
== NR_BOOT_PROCS
) {
587 panic("boot image table lookup failed");
591 /* When requested, locate the corresponding entry in the boot image priv table
592 * or panic if not found.
595 for (i
=0; boot_image_priv_table
[i
].endpoint
!= NULL_BOOT_NR
; i
++) {
596 if(boot_image_priv_table
[i
].endpoint
== endpoint
) {
597 *pp
= &boot_image_priv_table
[i
];
601 if(i
== NULL_BOOT_NR
) {
602 panic("boot image priv table lookup failed");
606 /* When requested, locate the corresponding entry in the boot image sys table
607 * or resort to the default entry if not found.
610 for (i
=0; boot_image_sys_table
[i
].endpoint
!= DEFAULT_BOOT_NR
; i
++) {
611 if(boot_image_sys_table
[i
].endpoint
== endpoint
) {
612 *sp
= &boot_image_sys_table
[i
];
616 if(boot_image_sys_table
[i
].endpoint
== DEFAULT_BOOT_NR
) {
617 *sp
= &boot_image_sys_table
[i
]; /* accept the default entry */
621 /* When requested, locate the corresponding entry in the boot image dev table
622 * or resort to the default entry if not found.
625 for (i
=0; boot_image_dev_table
[i
].endpoint
!= DEFAULT_BOOT_NR
; i
++) {
626 if(boot_image_dev_table
[i
].endpoint
== endpoint
) {
627 *dp
= &boot_image_dev_table
[i
];
631 if(boot_image_dev_table
[i
].endpoint
== DEFAULT_BOOT_NR
) {
632 *dp
= &boot_image_dev_table
[i
]; /* accept the default entry */
637 /*===========================================================================*
638 * catch_boot_init_ready *
639 *===========================================================================*/
640 static void catch_boot_init_ready(endpoint
)
643 /* Block and catch an init ready message from the given source. */
650 /* Receive init ready message. */
651 if ((r
= sef_receive_status(endpoint
, &m
, &ipc_status
)) != OK
) {
652 panic("unable to receive init reply: %d", r
);
654 if(m
.m_type
!= RS_INIT
) {
655 panic("unexpected reply from service: %d", m
.m_source
);
657 result
= m
.RS_INIT_RESULT
;
658 rp
= rproc_ptr
[_ENDPOINT_P(m
.m_source
)];
662 panic("unable to complete init for service: %d", m
.m_source
);
665 /* Send a reply to unblock the service. */
667 reply(m
.m_source
, rp
, &m
);
669 /* Mark the slot as no longer initializing. */
670 rp
->r_flags
&= ~RS_INITIALIZING
;
672 getuptime(&rp
->r_alive_tm
);
675 /*===========================================================================*
677 *===========================================================================*/
678 static void get_work(m_ptr
, status_ptr
)
679 message
*m_ptr
; /* pointer to message */
680 int *status_ptr
; /* pointer to status */
683 if (OK
!= (r
=sef_receive_status(ANY
, m_ptr
, status_ptr
)))
684 panic("sef_receive_status failed: %d", r
);