4 /*===========================================================================*
6 *===========================================================================*/
7 void rupdate_clear_upds()
9 /* Clear the update chain and the global update descriptor. */
10 struct rprocupd
*prev_rpupd
, *rpupd
;
11 RUPDATE_ITER(rupdate
.first_rpupd
, prev_rpupd
, rpupd
,
13 rupdate_upd_clear(prev_rpupd
);
16 rupdate_upd_clear(rupdate
.last_rpupd
);
20 /*===========================================================================*
22 *===========================================================================*/
23 void rupdate_add_upd(struct rprocupd
* rpupd
)
25 /* Add an update descriptor to the update chain. */
26 struct rprocupd
*prev_rpupd
, *walk_rpupd
;
30 /* In order to allow multicomponent-with-VM live updates to be processed
31 * correctly, we perform partial sorting on the chain: RS is to be last (if
32 * present), VM is to be right before it (if present), and all the other
33 * processes are to be at the start of the chain.
36 ep
= rpupd
->rp
->r_pub
->endpoint
;
38 assert(rpupd
->next_rpupd
== NULL
);
39 assert(rpupd
->prev_rpupd
== NULL
);
41 /* Determine what element to insert after, if not at the head. */
42 prev_rpupd
= rupdate
.last_rpupd
;
43 if (prev_rpupd
!= NULL
&& ep
!= RS_PROC_NR
&&
44 prev_rpupd
->rp
->r_pub
->endpoint
== RS_PROC_NR
)
45 prev_rpupd
= prev_rpupd
->prev_rpupd
;
46 if (prev_rpupd
!= NULL
&& ep
!= RS_PROC_NR
&& ep
!= VM_PROC_NR
&&
47 prev_rpupd
->rp
->r_pub
->endpoint
== VM_PROC_NR
)
48 prev_rpupd
= prev_rpupd
->prev_rpupd
;
50 /* Perform the insertion. */
51 if (prev_rpupd
== NULL
) {
52 rpupd
->next_rpupd
= rupdate
.first_rpupd
;
53 rupdate
.first_rpupd
= rupdate
.curr_rpupd
= rpupd
;
55 rpupd
->next_rpupd
= prev_rpupd
->next_rpupd
;
56 rpupd
->prev_rpupd
= prev_rpupd
;
57 prev_rpupd
->next_rpupd
= rpupd
;
60 if (rpupd
->next_rpupd
!= NULL
)
61 rpupd
->next_rpupd
->prev_rpupd
= rpupd
;
63 rupdate
.last_rpupd
= rpupd
;
67 /* Propagate relevant flags from the new descriptor. */
68 lu_flags
= rpupd
->lu_flags
& (SEF_LU_INCLUDES_VM
|SEF_LU_INCLUDES_RS
|SEF_LU_MULTI
);
70 RUPDATE_ITER(rupdate
.first_rpupd
, prev_rpupd
, walk_rpupd
,
71 walk_rpupd
->lu_flags
|= lu_flags
;
72 walk_rpupd
->init_flags
|= lu_flags
;
76 /* Set VM/RS update descriptor pointers. */
77 if(!rupdate
.vm_rpupd
&& (lu_flags
& SEF_LU_INCLUDES_VM
)) {
78 rupdate
.vm_rpupd
= rpupd
;
80 else if(!rupdate
.rs_rpupd
&& (lu_flags
& SEF_LU_INCLUDES_RS
)) {
81 rupdate
.rs_rpupd
= rpupd
;
85 /*===========================================================================*
86 * rupdate_set_new_upd_flags *
87 *===========================================================================*/
88 void rupdate_set_new_upd_flags(struct rprocupd
* rpupd
)
90 /* Set multi-component update flags. */
91 if(rupdate
.num_rpupds
> 0) {
92 rpupd
->lu_flags
|= SEF_LU_MULTI
;
93 rpupd
->init_flags
|= SEF_LU_MULTI
;
96 /* Propagate relevant flags from last service under update (if any). */
97 if(rupdate
.last_rpupd
) {
98 int lu_flags
= rupdate
.last_rpupd
->lu_flags
& (SEF_LU_INCLUDES_VM
|SEF_LU_INCLUDES_RS
);
99 rpupd
->lu_flags
|= lu_flags
;
100 rpupd
->init_flags
|= lu_flags
;
103 if(UPD_IS_PREPARING_ONLY(rpupd
)) {
107 /* Set VM/RS update flags. */
108 if(rpupd
->rp
->r_pub
->endpoint
== VM_PROC_NR
) {
109 rpupd
->lu_flags
|= SEF_LU_INCLUDES_VM
;
110 rpupd
->init_flags
|= SEF_LU_INCLUDES_VM
;
112 else if(rpupd
->rp
->r_pub
->endpoint
== RS_PROC_NR
) {
113 rpupd
->lu_flags
|= SEF_LU_INCLUDES_RS
;
114 rpupd
->init_flags
|= SEF_LU_INCLUDES_RS
;
118 /*===========================================================================*
120 *===========================================================================*/
121 void rupdate_upd_init(struct rprocupd
* rpupd
, struct rproc
*rp
)
123 /* Initialize an update descriptor for a given service. */
124 memset(rpupd
, 0, sizeof(*(rpupd
)));
125 rpupd
->prepare_state_data_gid
= GRANT_INVALID
;
126 rpupd
->prepare_state_data
.ipcf_els_gid
= GRANT_INVALID
;
127 rpupd
->prepare_state_data
.eval_gid
= GRANT_INVALID
;
128 rpupd
->state_endpoint
= NONE
;
132 /*===========================================================================*
133 * rupdate_upd_clear *
134 *===========================================================================*/
135 void rupdate_upd_clear(struct rprocupd
* rpupd
)
137 /* Clear an update descriptor. */
138 if(rpupd
->rp
->r_new_rp
) {
139 cleanup_service(rpupd
->rp
->r_new_rp
);
141 if(rpupd
->prepare_state_data_gid
!= GRANT_INVALID
) {
142 cpf_revoke(rpupd
->prepare_state_data_gid
);
144 if(rpupd
->prepare_state_data
.size
> 0) {
145 if(rpupd
->prepare_state_data
.ipcf_els_gid
!= GRANT_INVALID
) {
146 cpf_revoke(rpupd
->prepare_state_data
.ipcf_els_gid
);
148 if(rpupd
->prepare_state_data
.eval_gid
!= GRANT_INVALID
) {
149 cpf_revoke(rpupd
->prepare_state_data
.eval_gid
);
151 if(rpupd
->prepare_state_data
.ipcf_els
) {
152 free(rpupd
->prepare_state_data
.ipcf_els
);
154 if(rpupd
->prepare_state_data
.eval_addr
) {
155 free(rpupd
->prepare_state_data
.eval_addr
);
158 rupdate_upd_init(rpupd
,NULL
);
161 /*===========================================================================*
163 *===========================================================================*/
164 void rupdate_upd_move(struct rproc
* src_rp
, struct rproc
* dst_rp
)
166 /* Move an update descriptor from one service instance to another. */
167 dst_rp
->r_upd
= src_rp
->r_upd
;
168 dst_rp
->r_upd
.rp
= dst_rp
;
169 if(src_rp
->r_new_rp
) {
170 assert(!dst_rp
->r_new_rp
);
171 dst_rp
->r_new_rp
= src_rp
->r_new_rp
;
172 dst_rp
->r_new_rp
->r_old_rp
= dst_rp
;
174 if(dst_rp
->r_upd
.prev_rpupd
) dst_rp
->r_upd
.prev_rpupd
->next_rpupd
= &dst_rp
->r_upd
;
175 if(dst_rp
->r_upd
.next_rpupd
) dst_rp
->r_upd
.next_rpupd
->prev_rpupd
= &dst_rp
->r_upd
;
176 if(rupdate
.first_rpupd
== &src_rp
->r_upd
) rupdate
.first_rpupd
= &dst_rp
->r_upd
;
177 if(rupdate
.last_rpupd
== &src_rp
->r_upd
) rupdate
.last_rpupd
= &dst_rp
->r_upd
;
178 rupdate_upd_init(&src_rp
->r_upd
, NULL
);
179 src_rp
->r_new_rp
= NULL
;
182 /*===========================================================================*
183 * request_prepare_update_service_debug *
184 *===========================================================================*/
185 void request_prepare_update_service_debug(char *file
, int line
,
186 struct rproc
*rp
, int state
)
188 /* Request a service to prepare/cancel the update. */
190 struct rprocpub
*rpub
;
195 if(state
!= SEF_LU_STATE_NULL
) {
196 struct rprocupd
*rpupd
= &rp
->r_upd
;
197 rpupd
->prepare_tm
= getticks();
198 if(!UPD_IS_PREPARING_ONLY(rpupd
)) {
199 assert(rp
->r_new_rp
);
200 rp
->r_flags
|= RS_UPDATING
;
201 rp
->r_new_rp
->r_flags
|= RS_UPDATING
;
204 assert(!rp
->r_new_rp
);
207 m
.m_rs_update
.flags
= rpupd
->lu_flags
;
208 m
.m_rs_update
.state_data_gid
= rpupd
->prepare_state_data_gid
;
211 printf("RS: %s being requested to prepare for the %s at %s:%d\n",
212 srv_to_string(rp
), srv_upd_to_string(rpupd
), file
, line
);
216 printf("RS: %s being requested to cancel the update at %s:%d\n",
217 srv_to_string(rp
), file
, line
);
220 /* Request to prepare for the update or cancel the update. */
221 m
.m_type
= RS_LU_PREPARE
;
222 m
.m_rs_update
.state
= state
;
223 no_reply
= !(rp
->r_flags
& RS_PREPARE_DONE
);
224 rs_asynsend(rp
, &m
, no_reply
);
227 /*===========================================================================*
229 *===========================================================================*/
230 int srv_update(endpoint_t src_e
, endpoint_t dst_e
, int sys_upd_flags
)
234 /* Ask VM to swap the slots of the two processes and tell the kernel to
235 * do the same. If VM is being updated, only perform the kernel
236 * part of the call. The new instance of VM will do the rest at
237 * initialization time. If a multi-component update includes VM, let VM
238 * handle updates at state transfer time and rollbacks afterwards.
240 if(src_e
== VM_PROC_NR
) {
242 printf("RS: executing sys_update(%d, %d)\n", src_e
, dst_e
);
243 r
= sys_update(src_e
, dst_e
,
244 sys_upd_flags
& SF_VM_ROLLBACK
? SYS_UPD_ROLLBACK
: 0);
246 else if(!RUPDATE_IS_UPD_VM_MULTI() || RUPDATE_IS_VM_INIT_DONE()) {
248 printf("RS: executing vm_update(%d, %d)\n", src_e
, dst_e
);
249 r
= vm_update(src_e
, dst_e
, sys_upd_flags
);
253 printf("RS: skipping srv_update(%d, %d)\n", src_e
, dst_e
);
259 /*===========================================================================*
261 *===========================================================================*/
262 int update_service(src_rpp
, dst_rpp
, swap_flag
, sys_upd_flags
)
263 struct rproc
**src_rpp
;
264 struct rproc
**dst_rpp
;
268 /* Update an existing service. */
270 struct rproc
*src_rp
;
271 struct rproc
*dst_rp
;
272 struct rprocpub
*src_rpub
;
273 struct rprocpub
*dst_rpub
;
279 src_rpub
= src_rp
->r_pub
;
280 dst_rpub
= dst_rp
->r_pub
;
283 printf("RS: %s updating into %s\n",
284 srv_to_string(src_rp
), srv_to_string(dst_rp
));
286 /* Swap the slots of the two processes when asked to. */
287 if(swap_flag
== RS_SWAP
) {
288 if((r
= srv_update(src_rpub
->endpoint
, dst_rpub
->endpoint
, sys_upd_flags
)) != OK
) {
293 /* Swap slots here as well. */
295 endpoint
= src_rpub
->endpoint
;
297 swap_slot(&src_rp
, &dst_rp
);
299 /* Reassign pids and endpoints. */
300 src_rp
->r_pid
= dst_rp
->r_pid
;
301 src_rp
->r_pub
->endpoint
= dst_rp
->r_pub
->endpoint
;
302 rproc_ptr
[_ENDPOINT_P(src_rp
->r_pub
->endpoint
)] = src_rp
;
304 dst_rp
->r_pub
->endpoint
= endpoint
;
305 rproc_ptr
[_ENDPOINT_P(dst_rp
->r_pub
->endpoint
)] = dst_rp
;
307 /* Update in-RS priv structs */
308 if ((r
= sys_getpriv(&src_rp
->r_priv
, src_rp
->r_pub
->endpoint
)) != OK
)
309 panic("RS: update: could not update RS copies of priv of src: %d\n", r
);
310 if ((r
= sys_getpriv(&dst_rp
->r_priv
, dst_rp
->r_pub
->endpoint
)) != OK
)
311 panic("RS: update: could not update RS copies of priv of dst: %d\n", r
);
313 /* Adjust input pointers. */
317 /* Make the new version active. */
318 activate_service(dst_rp
, src_rp
);
321 printf("RS: %s updated into %s\n",
322 srv_to_string(src_rp
), srv_to_string(dst_rp
));
327 /*===========================================================================*
329 *===========================================================================*/
330 void rollback_service(struct rproc
**new_rpp
, struct rproc
**old_rpp
)
332 /* Rollback an updated service. */
336 /* RS is special, we may only need to swap the slots to rollback. */
337 if((*old_rpp
)->r_pub
->endpoint
== RS_PROC_NR
) {
338 endpoint_t me
= NONE
;
340 int priv_flags
, init_flags
;
342 r
= sys_whoami(&me
, name
, sizeof(name
), &priv_flags
, &init_flags
);
344 if(me
!= RS_PROC_NR
) {
345 r
= vm_update((*new_rpp
)->r_pub
->endpoint
, (*old_rpp
)->r_pub
->endpoint
, SF_VM_ROLLBACK
);
347 printf("RS: %s performed rollback\n", srv_to_string(*new_rpp
));
349 /* Since we may now have missed heartbeat replies, resend requests. */
350 for (rp
= BEG_RPROC_ADDR
; rp
< END_RPROC_ADDR
; rp
++)
351 if (rp
->r_flags
& RS_ACTIVE
)
355 int swap_flag
= ((*new_rpp
)->r_flags
& RS_INIT_PENDING
? RS_DONTSWAP
: RS_SWAP
);
357 printf("RS: %s performs rollback\n", srv_to_string(*new_rpp
));
358 if(swap_flag
== RS_SWAP
) {
359 /* Freeze the new instance to rollback safely. */
360 sys_privctl((*new_rpp
)->r_pub
->endpoint
, SYS_PRIV_DISALLOW
, NULL
);
362 r
= update_service(new_rpp
, old_rpp
, swap_flag
, SF_VM_ROLLBACK
);
365 assert(r
== OK
); /* can't fail */
368 /*===========================================================================*
370 *===========================================================================*/
371 void update_period(message
*m_ptr
)
373 /* Periodically check the status of the update (preparation phase). */
374 clock_t now
= m_ptr
->m_notify
.timestamp
;
375 short has_update_timed_out
;
377 struct rprocupd
*rpupd
;
379 struct rprocpub
*rpub
;
381 rpupd
= rupdate
.curr_rpupd
;
385 /* See if a timeout has occurred. */
386 has_update_timed_out
= (rpupd
->prepare_maxtime
> 0) && (now
- rpupd
->prepare_tm
> rpupd
->prepare_maxtime
);
388 /* If an update timed out, end the update process and notify
389 * the old version that the update has been canceled. From now on, the old
390 * version will continue executing.
392 if(has_update_timed_out
) {
393 printf("RS: update failed: maximum prepare time reached\n");
394 end_update(EINTR
, RS_CANCEL
);
398 /*===========================================================================*
399 * start_update_prepare *
400 *===========================================================================*/
401 int start_update_prepare(int allow_retries
)
403 /* Start the preparation phase of the update process. */
404 struct rprocupd
*prev_rpupd
, *rpupd
;
405 struct rproc
*rp
, *new_rp
;
408 if(!RUPDATE_IS_UPD_SCHEDULED()) {
412 printf("RS: not idle now, try again\n");
414 abort_update_proc(EAGAIN
);
420 printf("RS: starting the preparation phase of the update process\n");
422 if(rupdate
.rs_rpupd
) {
423 assert(rupdate
.rs_rpupd
== rupdate
.last_rpupd
);
424 assert(rupdate
.rs_rpupd
->rp
->r_pub
->endpoint
== RS_PROC_NR
);
425 assert(!UPD_IS_PREPARING_ONLY(rupdate
.rs_rpupd
));
427 if(rupdate
.vm_rpupd
) {
428 assert(rupdate
.vm_rpupd
->rp
->r_pub
->endpoint
== VM_PROC_NR
);
429 assert(!UPD_IS_PREPARING_ONLY(rupdate
.vm_rpupd
));
432 /* If a multi-component update includes VM, fill information about old
433 * and new endpoints, as well as update flags. VM needs this to complete
434 * the update internally at state transfer time.
436 if(RUPDATE_IS_UPD_VM_MULTI()) {
437 RUPDATE_ITER(rupdate
.first_rpupd
, prev_rpupd
, rpupd
,
438 if(!UPD_IS_PREPARING_ONLY(rpupd
)) {
440 new_rp
= rp
->r_new_rp
;
441 assert(rp
&& new_rp
);
442 rp
->r_pub
->old_endpoint
= rpupd
->state_endpoint
;
443 rp
->r_pub
->new_endpoint
= rp
->r_pub
->endpoint
;
444 if(rpupd
!= rupdate
.vm_rpupd
&& rpupd
!= rupdate
.rs_rpupd
) {
445 rp
->r_pub
->sys_flags
|= SF_VM_UPDATE
;
446 if(rpupd
->lu_flags
& SEF_LU_NOMMAP
) {
447 rp
->r_pub
->sys_flags
|= SF_VM_NOMMAP
;
454 /* Request the first service to prepare for the update. */
455 if(start_update_prepare_next() == NULL
) {
456 /* If we are done already, end the update now. */
457 end_update(OK
, RS_REPLY
);
464 /*===========================================================================*
465 * start_update_prepare_next *
466 *===========================================================================*/
467 struct rprocupd
* start_update_prepare_next()
469 /* Request the next service in the update chain to prepare for the update. */
470 struct rprocupd
*rpupd
, *prev_rpupd
, *walk_rpupd
;
471 struct rproc
*rp
, *new_rp
;
473 if(!RUPDATE_IS_UPDATING()) {
474 rpupd
= rupdate
.first_rpupd
;
477 rpupd
= rupdate
.curr_rpupd
->next_rpupd
;
483 if (RUPDATE_IS_UPD_VM_MULTI() && rpupd
== rupdate
.vm_rpupd
) {
484 /* We are doing a multicomponent live update that includes VM, and all
485 * services are now ready (and thereby stopped) except VM and possibly
486 * RS. This is the last point in time, and therefore also the best, that
487 * we can ask the (old) VM instance to do stuff for us, before we ask it
488 * to get ready as well: preallocate and pin memory, and copy over
489 * memory-mapped regions. Do this now, for all services except VM
490 * itself. In particular, also do it for RS, as we know that RS (yes,
491 * this service) is not going to create problems from here on.
493 RUPDATE_ITER(rupdate
.first_rpupd
, prev_rpupd
, walk_rpupd
,
494 if (UPD_IS_PREPARING_ONLY(walk_rpupd
))
495 continue; /* skip prepare-only processes */
496 if (walk_rpupd
== rupdate
.vm_rpupd
)
497 continue; /* skip VM */
499 new_rp
= rp
->r_new_rp
;
500 assert(rp
&& new_rp
);
502 printf("RS: preparing VM for %s -> %s\n", srv_to_string(rp
),
503 srv_to_string(new_rp
));
504 /* Ask VM to prepare the new instance based on the old instance. */
505 vm_prepare(rp
->r_pub
->new_endpoint
, new_rp
->r_pub
->endpoint
,
506 rp
->r_pub
->sys_flags
);
510 rupdate
.flags
|= RS_UPDATING
;
513 rupdate
.curr_rpupd
= rpupd
;
514 request_prepare_update_service(rupdate
.curr_rpupd
->rp
, rupdate
.curr_rpupd
->prepare_state
);
515 if(!UPD_IS_PREPARING_ONLY(rpupd
)) {
516 /* Continue only if the current service requires a prepare-only update. */
519 if(!rupdate
.curr_rpupd
->next_rpupd
) {
520 /* Continue only if there are services left. */
523 rpupd
= rupdate
.curr_rpupd
->next_rpupd
;
529 /*===========================================================================*
531 *===========================================================================*/
534 /* Start the update phase of the update process. */
535 struct rprocupd
*prev_rpupd
, *rpupd
;
536 int r
, init_ready_pending
=0;
539 printf("RS: starting a %s-component update process\n",
540 RUPDATE_IS_UPD_MULTI() ? "multi" : "single");
542 assert(RUPDATE_IS_UPDATING());
543 assert(rupdate
.num_rpupds
> 0);
544 assert(rupdate
.num_init_ready_pending
== 0);
545 assert(rupdate
.first_rpupd
);
546 assert(rupdate
.last_rpupd
);
547 assert(rupdate
.curr_rpupd
== rupdate
.last_rpupd
);
548 rupdate
.flags
|= RS_INITIALIZING
;
550 /* Cancel the update for the prepare-only services now. */
551 RUPDATE_ITER(rupdate
.first_rpupd
, prev_rpupd
, rpupd
,
552 if(UPD_IS_PREPARING_ONLY(rpupd
)) {
553 request_prepare_update_service(rpupd
->rp
, SEF_LU_STATE_NULL
);
557 /* Iterate over all the processes scheduled for the update. Update each
558 * service and initialize the new instance. If VM is part of a
559 * multi-component live update, initialize VM first.
561 RUPDATE_ITER(rupdate
.first_rpupd
, prev_rpupd
, rpupd
,
562 rupdate
.curr_rpupd
= rpupd
;
563 if(!UPD_IS_PREPARING_ONLY(rpupd
)) {
564 init_ready_pending
=1;
565 r
= start_srv_update(rpupd
);
569 if(!RUPDATE_IS_UPD_VM_MULTI() || rpupd
== rupdate
.vm_rpupd
) {
570 r
= complete_srv_update(rpupd
);
578 /* End update if there is nothing more to do. */
579 if (!init_ready_pending
) {
584 /* Handle multi-component live updates including VM. */
585 if(RUPDATE_IS_UPD_VM_MULTI()) {
587 /* Check VM initialization, assume failure after timeout. */
589 printf("RS: waiting for VM to initialize...\n");
590 r
= rs_receive_ticks(VM_PROC_NR
, &m
, NULL
, UPD_INIT_MAXTIME(rupdate
.vm_rpupd
));
591 if(r
!= OK
|| m
.m_type
!= RS_INIT
|| m
.m_rs_init
.result
!= OK
) {
592 r
= (r
== OK
&& m
.m_type
== RS_INIT
? m
.m_rs_init
.result
: EINTR
);
593 m
.m_source
= VM_PROC_NR
;
595 m
.m_rs_init
.result
= r
;
598 /* If initialization was successfull, complete the update. */
600 /* Reply and unblock VM immediately. */
602 reply(VM_PROC_NR
, NULL
, &m
);
603 /* Initialize other services. */
604 RUPDATE_ITER(rupdate
.first_rpupd
, prev_rpupd
, rpupd
,
605 if(!UPD_IS_PREPARING_ONLY(rpupd
) && rpupd
!= rupdate
.vm_rpupd
) {
606 r
= complete_srv_update(rpupd
);
618 /*===========================================================================*
620 *===========================================================================*/
621 int start_srv_update(struct rprocupd
*rpupd
)
623 /* Start updating a single service given its update descriptor. */
624 struct rproc
*old_rp
, *new_rp
;
625 int r
, sys_upd_flags
= 0;
628 new_rp
= old_rp
->r_new_rp
;
629 assert(old_rp
&& new_rp
);
632 printf("RS: %s starting the %s\n", srv_to_string(old_rp
), srv_upd_to_string(rpupd
));
634 rupdate
.num_init_ready_pending
++;
635 new_rp
->r_flags
|= RS_INITIALIZING
;
636 new_rp
->r_flags
|= RS_INIT_PENDING
;
637 if(rpupd
->lu_flags
& SEF_LU_NOMMAP
) {
638 sys_upd_flags
|= SF_VM_NOMMAP
;
641 /* Perform the update, skip for RS. */
642 if(old_rp
->r_pub
->endpoint
!= RS_PROC_NR
) {
643 r
= update_service(&old_rp
, &new_rp
, RS_SWAP
, sys_upd_flags
);
645 end_update(r
, RS_REPLY
);
646 printf("RS: update failed: error %d\n", r
);
654 /*===========================================================================*
655 * complete_srv_update *
656 *===========================================================================*/
657 int complete_srv_update(struct rprocupd
*rpupd
)
659 /* Complete update of a service given its update descriptor. */
660 struct rproc
*old_rp
, *new_rp
;
664 new_rp
= old_rp
->r_new_rp
;
665 assert(old_rp
&& new_rp
);
668 printf("RS: %s completing the %s\n", srv_to_string(old_rp
), srv_upd_to_string(rpupd
));
670 new_rp
->r_flags
&= ~RS_INIT_PENDING
;
672 /* If RS itself is updating, yield control to the new version immediately. */
673 if(old_rp
->r_pub
->endpoint
== RS_PROC_NR
) {
674 r
= init_service(new_rp
, SEF_INIT_LU
, rpupd
->init_flags
);
676 panic("unable to initialize the new RS instance: %d", r
);
679 printf("RS: %s is the new RS instance we'll yield control to\n", srv_to_string(new_rp
));
680 r
= sys_privctl(new_rp
->r_pub
->endpoint
, SYS_PRIV_YIELD
, NULL
);
682 panic("unable to yield control to the new RS instance: %d", r
);
684 /* If we get this far, the new version failed to initialize. Rollback. */
685 rollback_service(&new_rp
, &old_rp
);
686 end_update(ERESTART
, RS_REPLY
);
687 printf("RS: update failed: state transfer failed for the new RS instance\n");
691 /* Let the new version run. */
692 r
= run_service(new_rp
, SEF_INIT_LU
, rpupd
->init_flags
);
694 /* Something went wrong. Rollback. */
695 rollback_service(&new_rp
, &old_rp
);
696 end_update(r
, RS_REPLY
);
697 printf("RS: update failed: error %d\n", r
);
704 /*===========================================================================*
705 * abort_update_proc *
706 *===========================================================================*/
707 int abort_update_proc(int reason
)
709 /* This function is called to abort a scheduled/in-progress update process
710 * indiscriminately. If the update is in progress, simply pretend the
711 * current service is causing premature termination of the update.
713 int is_updating
= RUPDATE_IS_UPDATING();
714 assert(reason
!= OK
);
716 if(!is_updating
&& !RUPDATE_IS_UPD_SCHEDULED()) {
721 printf("RS: aborting the %s update process prematurely\n",
722 is_updating
? "in-progress" : "scheduled");
725 rupdate_clear_upds();
729 if(rupdate
.flags
& RS_INITIALIZING
) {
730 /* Pretend the current service under update failed to initialize. */
731 end_update(reason
, RS_REPLY
);
734 /* Pretend the current service under update failed to prepare. */
735 end_update(reason
, RS_CANCEL
);
741 /*===========================================================================*
743 *===========================================================================*/
744 static void end_update_curr(struct rprocupd
*rpupd
, int result
, int reply_flag
)
746 /* Execute the requested action on the current service under update. */
747 struct rproc
*old_rp
, *new_rp
;
748 assert(rpupd
== rupdate
.curr_rpupd
);
751 new_rp
= old_rp
->r_new_rp
;
752 assert(old_rp
&& new_rp
);
753 if(result
!= OK
&& SRV_IS_UPDATING_AND_INITIALIZING(new_rp
) && rpupd
!= rupdate
.rs_rpupd
) {
754 /* Rollback in case of failures at initialization time. */
755 rollback_service(&new_rp
, &old_rp
);
757 end_srv_update(rpupd
, result
, reply_flag
);
760 /*===========================================================================*
761 * end_update_before_prepare *
762 *===========================================================================*/
763 static void end_update_before_prepare(struct rprocupd
*rpupd
, int result
)
765 /* The service is still waiting for the update. Cleanup the new version and
766 * keep the old version running.
768 struct rproc
*old_rp
, *new_rp
;
769 assert(result
!= OK
);
772 new_rp
= old_rp
->r_new_rp
;
773 assert(old_rp
&& new_rp
);
774 cleanup_service(new_rp
);
777 /*===========================================================================*
778 * end_update_prepare_done *
779 *===========================================================================*/
780 static void end_update_prepare_done(struct rprocupd
*rpupd
, int result
)
782 /* The service is blocked after preparing for the update. Unblock it
783 * and cleanup the new version.
785 assert(!RUPDATE_IS_INITIALIZING());
786 assert(result
!= OK
);
787 assert(!(rpupd
->rp
->r_flags
& RS_INITIALIZING
));
789 end_srv_update(rpupd
, result
, RS_REPLY
);
792 /*===========================================================================*
793 * end_update_initializing *
794 *===========================================================================*/
795 static void end_update_initializing(struct rprocupd
*rpupd
, int result
)
797 /* The service is initializing after a live udate. Cleanup the version that
798 * has to die out and let the other version run.
800 struct rproc
*old_rp
, *new_rp
;
803 new_rp
= old_rp
->r_new_rp
;
804 assert(old_rp
&& new_rp
);
805 assert(SRV_IS_UPDATING_AND_INITIALIZING(new_rp
));
806 if(result
!= OK
&& rpupd
!= rupdate
.rs_rpupd
) {
807 /* Rollback in case of failures at initialization time. */
808 rollback_service(&new_rp
, &old_rp
);
810 end_srv_update(rpupd
, result
, RS_REPLY
);
813 /*===========================================================================*
814 * end_update_rev_iter *
815 *===========================================================================*/
816 static void end_update_rev_iter(int result
, int reply_flag
,
817 struct rprocupd
*skip_rpupd
, struct rprocupd
*only_rpupd
)
819 /* End the update for all the requested services. */
820 struct rprocupd
*prev_rpupd
, *rpupd
;
821 short is_curr
, is_before_curr
, is_after_curr
;
824 RUPDATE_REV_ITER(rupdate
.last_rpupd
, prev_rpupd
, rpupd
,
825 is_curr
= (rupdate
.curr_rpupd
== rpupd
);
826 is_after_curr
= is_after_curr
&& !is_curr
;
827 if(!UPD_IS_PREPARING_ONLY(rpupd
)) {
828 short is_before_prepare
;
829 short is_prepare_done
;
830 short is_initializing
;
831 is_before_curr
= !is_curr
&& !is_after_curr
;
832 if(RUPDATE_IS_INITIALIZING()) {
833 is_before_prepare
= 0;
834 is_prepare_done
= is_after_curr
;
835 is_initializing
= is_before_curr
;
838 is_before_prepare
= is_after_curr
;
839 is_prepare_done
= is_before_curr
;
842 if((!skip_rpupd
|| rpupd
!= skip_rpupd
) && (!only_rpupd
|| rpupd
== only_rpupd
)) {
843 /* Analyze different cases. */
845 end_update_curr(rpupd
, result
, reply_flag
);
847 else if(is_before_prepare
) {
848 end_update_before_prepare(rpupd
, result
);
850 else if(is_prepare_done
) {
851 end_update_prepare_done(rpupd
, result
);
854 assert(is_initializing
);
855 end_update_initializing(rpupd
, result
);
862 /*===========================================================================*
864 *===========================================================================*/
865 void end_update_debug(char *file
, int line
,
866 int result
, int reply_flag
)
868 /* End an in-progress update process. */
869 struct rprocupd
*prev_rpupd
, *rpupd
, *rpupd_it
;
870 struct rproc
*rp
, *old_rp
, *new_rp
;
873 assert(RUPDATE_IS_UPDATING());
876 printf("RS: %s ending the update: result=%d, reply=%d at %s:%d\n",
877 srv_to_string(rupdate
.curr_rpupd
->rp
), result
, (reply_flag
==RS_REPLY
),
880 /* If the new instance of RS is active and the update failed, ending
881 * the update couldn't be any easier.
883 if(result
!= OK
&& RUPDATE_IS_RS_INIT_DONE()) {
885 printf("RS: update failed, new RS instance will now exit\n");
889 /* Handle prepare-only services first: simply cancel the update. */
890 RUPDATE_ITER(rupdate
.first_rpupd
, prev_rpupd
, rpupd
,
891 if(UPD_IS_PREPARING_ONLY(rpupd
)) {
892 if(!RUPDATE_IS_INITIALIZING()) {
893 request_prepare_update_service(rpupd
->rp
, SEF_LU_STATE_NULL
);
895 rpupd
->rp
->r_flags
&= ~RS_PREPARE_DONE
;
899 /* Handle all the other services now, VM always last to support rollback. */
900 end_update_rev_iter(result
, reply_flag
, rupdate
.vm_rpupd
, NULL
);
901 if(rupdate
.vm_rpupd
) {
902 end_update_rev_iter(result
, reply_flag
, NULL
, rupdate
.vm_rpupd
);
905 /* End the update and complete initialization in case of success. */
906 RUPDATE_ITER(rupdate
.first_rpupd
, prev_rpupd
, rpupd
,
908 rupdate_upd_clear(prev_rpupd
);
910 if(result
== OK
&& !UPD_IS_PREPARING_ONLY(rpupd
)) {
911 /* The rp pointer points to the new instance in this case. */
913 end_srv_init(new_rp
);
916 late_reply(rupdate
.last_rpupd
->rp
, result
);
917 rupdate_upd_clear(rupdate
.last_rpupd
);
920 /* Clear all the old/new endpoints and update flags in the public entries. */
921 for(slot_nr
= 0; slot_nr
< NR_SYS_PROCS
; slot_nr
++) {
922 rp
= &rproc
[slot_nr
];
923 rp
->r_pub
->old_endpoint
= NONE
;
924 rp
->r_pub
->new_endpoint
= NONE
;
925 rp
->r_pub
->sys_flags
&= ~(SF_VM_UPDATE
|SF_VM_ROLLBACK
|SF_VM_NOMMAP
);
929 /*===========================================================================*
931 *===========================================================================*/
932 void end_srv_update(struct rprocupd
*rpupd
, int result
, int reply_flag
)
934 /* End the update for the given service. There are two possibilities:
935 * 1) the update succeeded. In that case, cleanup the old version and mark the
936 * new version as no longer under update.
937 * 2) the update failed. In that case, cleanup the new version and mark the old
938 * version as no longer under update. Eventual late ready to update
939 * messages (if any) will simply be ignored and the service can
940 * continue executing. In addition, reset the check timestamp, so that if the
941 * service has a period, a status request will be forced in the next period.
943 struct rproc
*old_rp
, *new_rp
, *exiting_rp
, *surviving_rp
;
946 struct rprocpub
*rpub
;
950 new_rp
= old_rp
->r_new_rp
;
951 assert(old_rp
&& new_rp
);
952 if(result
== OK
&& new_rp
->r_pub
->endpoint
== VM_PROC_NR
&& RUPDATE_IS_UPD_MULTI()) {
953 /* VM has already been replied to in case of multi-component live update.
954 * Send an update cancel message to trigger cleanup.
956 reply_flag
= RS_CANCEL
;
960 printf("RS: ending update from %s to %s with result=%d, reply=%d\n",
961 srv_to_string(old_rp
), srv_to_string(new_rp
), result
, (reply_flag
==RS_REPLY
));
963 /* Decide which version has to die out and which version has to survive. */
964 surviving_rp
= (result
== OK
? new_rp
: old_rp
);
965 exiting_rp
= (result
== OK
? old_rp
: new_rp
);
966 surviving_rp
->r_flags
&= ~RS_INITIALIZING
;
967 surviving_rp
->r_check_tm
= 0;
968 surviving_rp
->r_alive_tm
= getticks();
970 /* Keep track of the surviving process in the update descriptor from now on. */
971 rpupd
->rp
= surviving_rp
;
973 /* Unlink the two versions. */
974 old_rp
->r_new_rp
= NULL
;
975 new_rp
->r_old_rp
= NULL
;
977 /* Mark the version that has to survive as no longer updating and
978 * reply when asked to.
980 surviving_rp
->r_flags
&= ~(RS_UPDATING
|RS_PREPARE_DONE
|RS_INIT_DONE
|RS_INIT_PENDING
);
981 if(reply_flag
== RS_REPLY
) {
984 reply(surviving_rp
->r_pub
->endpoint
, surviving_rp
, &m
);
986 else if(reply_flag
== RS_CANCEL
) {
987 if(!(surviving_rp
->r_flags
& RS_TERMINATED
)) {
988 request_prepare_update_service(surviving_rp
, SEF_LU_STATE_NULL
);
992 /* Cleanup or detach the version that has to die out. */
993 get_service_instances(exiting_rp
, &rps
, &nr_rps
);
994 for(i
=0;i
<nr_rps
;i
++) {
995 if(rps
[i
] == old_rp
&& (rpupd
->lu_flags
& SEF_LU_DETACHED
)) {
998 rps
[i
]->r_flags
|= RS_CLEANUP_DETACH
;
999 cleanup_service(rps
[i
]);
1000 reply(rps
[i
]->r_pub
->endpoint
, rps
[i
], &m
);
1003 cleanup_service(rps
[i
]);
1008 printf("RS: %s ended the %s\n", srv_to_string(surviving_rp
),
1009 srv_upd_to_string(rpupd
));