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 /* Get process name. */
308 strcpy(rpub
->proc_name
, ip
->proc_name
);
310 /* Build command settings. */
312 rp
->r_script
[0]= '\0';
315 /* Initialize vm call mask bitmap. */
316 calls
= SRV_OR_USR(rp
, SRV_VC
, USR_VC
) == ALL_C
? all_c
: no_c
;
317 fill_call_mask(calls
, NR_VM_CALLS
, rpub
->vm_call_mask
, VM_RQ_BASE
, TRUE
);
319 /* Scheduling parameters. */
320 rp
->r_scheduler
= SRV_OR_USR(rp
, SRV_SCH
, USR_SCH
);
321 rp
->r_priority
= SRV_OR_USR(rp
, SRV_Q
, USR_Q
);
322 rp
->r_quantum
= SRV_OR_USR(rp
, SRV_QT
, USR_QT
);
324 /* Get some settings from the boot image table. */
325 rpub
->endpoint
= ip
->endpoint
;
327 /* Set some defaults. */
328 rp
->r_old_rp
= NULL
; /* no old version yet */
329 rp
->r_new_rp
= NULL
; /* no new version yet */
330 rp
->r_prev_rp
= NULL
; /* no prev replica yet */
331 rp
->r_next_rp
= NULL
; /* no next replica yet */
332 rp
->r_uid
= 0; /* root */
333 rp
->r_check_tm
= 0; /* not checked yet */
334 getuptime(&rp
->r_alive_tm
); /* currently alive */
335 rp
->r_stop_tm
= 0; /* not exiting yet */
336 rp
->r_restarts
= 0; /* no restarts so far */
337 rp
->r_period
= 0; /* no period yet */
338 rp
->r_exec
= NULL
; /* no in-memory copy yet */
341 /* Mark as in use and active. */
342 rp
->r_flags
= RS_IN_USE
| RS_ACTIVE
;
343 rproc_ptr
[_ENDPOINT_P(rpub
->endpoint
)]= rp
;
347 /* - Step 2: allow every system service in the boot image to run. */
348 nr_uncaught_init_srvs
= 0;
349 for (i
=0; boot_image_priv_table
[i
].endpoint
!= NULL_BOOT_NR
; i
++) {
350 boot_image_priv
= &boot_image_priv_table
[i
];
352 /* System services only. */
353 if(iskerneln(_ENDPOINT_P(boot_image_priv
->endpoint
))) {
357 /* Lookup the corresponding slot in the system process table. */
358 rp
= &rproc
[boot_image_priv
- boot_image_priv_table
];
361 /* RS/VM are already running as we speak. */
362 if(boot_image_priv
->endpoint
== RS_PROC_NR
||
363 boot_image_priv
->endpoint
== VM_PROC_NR
) {
364 if ((s
= init_service(rp
, SEF_INIT_FRESH
)) != OK
) {
365 panic("unable to initialize %d: %d", boot_image_priv
->endpoint
, s
);
370 /* Allow the service to run. */
371 if ((s
= sched_init_proc(rp
)) != OK
) {
372 panic("unable to initialize scheduling: %d", s
);
374 if ((s
= sys_privctl(rpub
->endpoint
, SYS_PRIV_ALLOW
, NULL
)) != OK
) {
375 panic("unable to initialize privileges: %d", s
);
378 /* Initialize service. We assume every service will always get
379 * back to us here at boot time.
381 if(boot_image_priv
->flags
& SYS_PROC
) {
382 if ((s
= init_service(rp
, SEF_INIT_FRESH
)) != OK
) {
383 panic("unable to initialize service: %d", s
);
385 if(rpub
->sys_flags
& SF_SYNCH_BOOT
) {
386 /* Catch init ready message now to synchronize. */
387 catch_boot_init_ready(rpub
->endpoint
);
390 /* Catch init ready message later. */
391 nr_uncaught_init_srvs
++;
396 /* - Step 3: let every system service complete initialization by
397 * catching all the init ready messages left.
399 while(nr_uncaught_init_srvs
) {
400 catch_boot_init_ready(ANY
);
401 nr_uncaught_init_srvs
--;
404 /* - Step 4: all the system services in the boot image are now running.
405 * Complete the initialization of the system process table in collaboration
406 * with other system services.
408 for (i
=0; boot_image_priv_table
[i
].endpoint
!= NULL_BOOT_NR
; i
++) {
409 boot_image_priv
= &boot_image_priv_table
[i
];
411 /* System services only. */
412 if(iskerneln(_ENDPOINT_P(boot_image_priv
->endpoint
))) {
416 /* Lookup the corresponding slot in the system process table. */
417 rp
= &rproc
[boot_image_priv
- boot_image_priv_table
];
420 /* Get pid from PM. */
421 rp
->r_pid
= getnpid(rpub
->endpoint
);
422 if(rp
->r_pid
== -1) {
423 panic("unable to get pid");
427 /* Set alarm to periodically check service status. */
428 if (OK
!= (s
=sys_setalarm(RS_DELTA_T
, 0)))
429 panic("couldn't set alarm: %d", s
);
432 /* Now create a new RS instance and let the current
433 * instance live update into the replica. Clone RS' own slot first.
435 rp
= rproc_ptr
[_ENDPOINT_P(RS_PROC_NR
)];
436 if((s
= clone_slot(rp
, &replica_rp
)) != OK
) {
437 panic("unable to clone current RS instance: %d", s
);
440 /* Fork a new RS instance with root:operator. */
441 pid
= srv_fork(0, 0);
443 panic("unable to fork a new RS instance");
445 replica_pid
= pid
? pid
: getpid();
446 replica_endpoint
= getnprocnr(replica_pid
);
447 replica_rp
->r_pid
= replica_pid
;
448 replica_rp
->r_pub
->endpoint
= replica_endpoint
;
451 /* New RS instance running. */
453 /* Live update the old instance into the new one. */
454 s
= update_service(&rp
, &replica_rp
, RS_SWAP
);
456 panic("unable to live update RS: %d", s
);
460 /* Clean up the old RS instance, the new instance will take over. */
463 /* Ask VM to pin memory for the new RS instance. */
464 if((s
= vm_memctl(RS_PROC_NR
, VM_RS_MEM_PIN
)) != OK
) {
465 panic("unable to pin memory for the new RS instance: %d", s
);
469 /* Old RS instance running. */
471 /* Set up privileges for the new instance and let it run. */
472 s
= sys_privctl(replica_endpoint
, SYS_PRIV_SET_SYS
, &(replica_rp
->r_priv
));
474 panic("unable to set privileges for the new RS instance: %d", s
);
476 if ((s
= sched_init_proc(replica_rp
)) != OK
) {
477 panic("unable to initialize RS replica scheduling: %d", s
);
479 s
= sys_privctl(replica_endpoint
, SYS_PRIV_YIELD
, NULL
);
481 panic("unable to yield control to the new RS instance: %d", s
);
485 #endif /* USE_LIVEUPDATE */
490 /*===========================================================================*
491 * sef_cb_signal_handler *
492 *===========================================================================*/
493 static void sef_cb_signal_handler(int signo
)
495 /* Check for known signals, ignore anything else. */
506 /*===========================================================================*
507 * sef_cb_signal_manager *
508 *===========================================================================*/
509 static int sef_cb_signal_manager(endpoint_t target
, int signo
)
511 /* Process system signal on behalf of the kernel. */
514 struct rprocpub
*rpub
;
518 if(rs_isokendpt(target
, &target_p
) != OK
|| rproc_ptr
[target_p
] == NULL
) {
520 printf("RS: ignoring spurious signal %d for process %d\n",
522 return OK
; /* clear the signal */
524 rp
= rproc_ptr
[target_p
];
527 /* Don't bother if a termination signal has already been processed. */
528 if((rp
->r_flags
& RS_TERMINATED
) && !(rp
->r_flags
& RS_EXITING
)) {
529 return EDEADEPT
; /* process is gone */
532 /* Ignore external signals for inactive service instances. */
533 if( !(rp
->r_flags
& RS_ACTIVE
) && !(rp
->r_flags
& RS_EXITING
)) {
535 printf("RS: ignoring signal %d for inactive %s\n",
536 signo
, srv_to_string(rp
));
537 return OK
; /* clear the signal */
541 printf("RS: %s got %s signal %d\n", srv_to_string(rp
),
542 SIGS_IS_TERMINATION(signo
) ? "termination" : "non-termination",signo
);
544 /* Print stacktrace if necessary. */
545 if(SIGS_IS_STACKTRACE(signo
)) {
546 sys_sysctl_stacktrace(target
);
549 /* In case of termination signal handle the event. */
550 if(SIGS_IS_TERMINATION(signo
)) {
551 rp
->r_flags
|= RS_TERMINATED
;
552 terminate_service(rp
);
554 return EDEADEPT
; /* process is now gone */
557 /* Translate every non-termination signal into a message. */
558 m
.m_type
= SIGS_SIGNAL_RECEIVED
;
559 m
.SIGS_SIG_NUM
= signo
;
560 asynsend3(rpub
->endpoint
, &m
, AMF_NOREPLY
);
562 return OK
; /* signal has been delivered */
565 /*===========================================================================*
566 * boot_image_info_lookup *
567 *===========================================================================*/
568 static void boot_image_info_lookup(endpoint
, image
, ip
, pp
, sp
, dp
)
570 struct boot_image
*image
;
571 struct boot_image
**ip
;
572 struct boot_image_priv
**pp
;
573 struct boot_image_sys
**sp
;
574 struct boot_image_dev
**dp
;
576 /* Lookup entries in boot image tables. */
579 /* When requested, locate the corresponding entry in the boot image table
580 * or panic if not found.
583 for (i
=0; i
< NR_BOOT_PROCS
; i
++) {
584 if(image
[i
].endpoint
== endpoint
) {
589 if(i
== NR_BOOT_PROCS
) {
590 panic("boot image table lookup failed");
594 /* When requested, locate the corresponding entry in the boot image priv table
595 * or panic if not found.
598 for (i
=0; boot_image_priv_table
[i
].endpoint
!= NULL_BOOT_NR
; i
++) {
599 if(boot_image_priv_table
[i
].endpoint
== endpoint
) {
600 *pp
= &boot_image_priv_table
[i
];
604 if(i
== NULL_BOOT_NR
) {
605 panic("boot image priv table lookup failed");
609 /* When requested, locate the corresponding entry in the boot image sys table
610 * or resort to the default entry if not found.
613 for (i
=0; boot_image_sys_table
[i
].endpoint
!= DEFAULT_BOOT_NR
; i
++) {
614 if(boot_image_sys_table
[i
].endpoint
== endpoint
) {
615 *sp
= &boot_image_sys_table
[i
];
619 if(boot_image_sys_table
[i
].endpoint
== DEFAULT_BOOT_NR
) {
620 *sp
= &boot_image_sys_table
[i
]; /* accept the default entry */
624 /* When requested, locate the corresponding entry in the boot image dev table
625 * or resort to the default entry if not found.
628 for (i
=0; boot_image_dev_table
[i
].endpoint
!= DEFAULT_BOOT_NR
; i
++) {
629 if(boot_image_dev_table
[i
].endpoint
== endpoint
) {
630 *dp
= &boot_image_dev_table
[i
];
634 if(boot_image_dev_table
[i
].endpoint
== DEFAULT_BOOT_NR
) {
635 *dp
= &boot_image_dev_table
[i
]; /* accept the default entry */
640 /*===========================================================================*
641 * catch_boot_init_ready *
642 *===========================================================================*/
643 static void catch_boot_init_ready(endpoint
)
646 /* Block and catch an init ready message from the given source. */
653 /* Receive init ready message. */
654 if ((r
= sef_receive_status(endpoint
, &m
, &ipc_status
)) != OK
) {
655 panic("unable to receive init reply: %d", r
);
657 if(m
.m_type
!= RS_INIT
) {
658 panic("unexpected reply from service: %d", m
.m_source
);
660 result
= m
.RS_INIT_RESULT
;
661 rp
= rproc_ptr
[_ENDPOINT_P(m
.m_source
)];
665 panic("unable to complete init for service: %d", m
.m_source
);
668 /* Send a reply to unblock the service. */
670 reply(m
.m_source
, rp
, &m
);
672 /* Mark the slot as no longer initializing. */
673 rp
->r_flags
&= ~RS_INITIALIZING
;
675 getuptime(&rp
->r_alive_tm
);
678 /*===========================================================================*
680 *===========================================================================*/
681 static void get_work(m_ptr
, status_ptr
)
682 message
*m_ptr
; /* pointer to message */
683 int *status_ptr
; /* pointer to status */
686 if (OK
!= (r
=sef_receive_status(ANY
, m_ptr
, status_ptr
)))
687 panic("sef_receive_status failed: %d", r
);