1
2 #include "inc.h"
3
4 /*===========================================================================*
5 * rupdate_clear_upds *
6 *===========================================================================*/
rupdate_clear_upds()7 void rupdate_clear_upds()
8 {
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,
12 if(prev_rpupd) {
13 rupdate_upd_clear(prev_rpupd);
14 }
15 );
16 rupdate_upd_clear(rupdate.last_rpupd);
17 RUPDATE_CLEAR();
18 }
19
20 /*===========================================================================*
21 * rupdate_add_upd *
22 *===========================================================================*/
rupdate_add_upd(struct rprocupd * rpupd)23 void rupdate_add_upd(struct rprocupd* rpupd)
24 {
25 /* Add an update descriptor to the update chain. */
26 struct rprocupd *prev_rpupd, *walk_rpupd;
27 endpoint_t ep;
28 int lu_flags;
29
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.
34 */
35
36 ep = rpupd->rp->r_pub->endpoint;
37
38 assert(rpupd->next_rpupd == NULL);
39 assert(rpupd->prev_rpupd == NULL);
40
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;
49
50 /* Perform the insertion. */
51 if (prev_rpupd == NULL) {
52 rpupd->next_rpupd = rupdate.first_rpupd;
53 rupdate.first_rpupd = rupdate.curr_rpupd = rpupd;
54 } else {
55 rpupd->next_rpupd = prev_rpupd->next_rpupd;
56 rpupd->prev_rpupd = prev_rpupd;
57 prev_rpupd->next_rpupd = rpupd;
58 }
59
60 if (rpupd->next_rpupd != NULL)
61 rpupd->next_rpupd->prev_rpupd = rpupd;
62 else
63 rupdate.last_rpupd = rpupd;
64
65 rupdate.num_rpupds++;
66
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);
69 if(lu_flags) {
70 RUPDATE_ITER(rupdate.first_rpupd, prev_rpupd, walk_rpupd,
71 walk_rpupd->lu_flags |= lu_flags;
72 walk_rpupd->init_flags |= lu_flags;
73 );
74 }
75
76 /* Set VM/RS update descriptor pointers. */
77 if(!rupdate.vm_rpupd && (lu_flags & SEF_LU_INCLUDES_VM)) {
78 rupdate.vm_rpupd = rpupd;
79 }
80 else if(!rupdate.rs_rpupd && (lu_flags & SEF_LU_INCLUDES_RS)) {
81 rupdate.rs_rpupd = rpupd;
82 }
83 }
84
85 /*===========================================================================*
86 * rupdate_set_new_upd_flags *
87 *===========================================================================*/
rupdate_set_new_upd_flags(struct rprocupd * rpupd)88 void rupdate_set_new_upd_flags(struct rprocupd* rpupd)
89 {
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;
94 }
95
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;
101 }
102
103 if(UPD_IS_PREPARING_ONLY(rpupd)) {
104 return;
105 }
106
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;
111 }
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;
115 }
116 }
117
118 /*===========================================================================*
119 * rupdate_upd_init *
120 *===========================================================================*/
rupdate_upd_init(struct rprocupd * rpupd,struct rproc * rp)121 void rupdate_upd_init(struct rprocupd* rpupd, struct rproc *rp)
122 {
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;
129 rpupd->rp = rp;
130 }
131
132 /*===========================================================================*
133 * rupdate_upd_clear *
134 *===========================================================================*/
rupdate_upd_clear(struct rprocupd * rpupd)135 void rupdate_upd_clear(struct rprocupd* rpupd)
136 {
137 /* Clear an update descriptor. */
138 if(rpupd->rp->r_new_rp) {
139 cleanup_service(rpupd->rp->r_new_rp);
140 }
141 if(rpupd->prepare_state_data_gid != GRANT_INVALID) {
142 cpf_revoke(rpupd->prepare_state_data_gid);
143 }
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);
147 }
148 if(rpupd->prepare_state_data.eval_gid != GRANT_INVALID) {
149 cpf_revoke(rpupd->prepare_state_data.eval_gid);
150 }
151 if(rpupd->prepare_state_data.ipcf_els) {
152 free(rpupd->prepare_state_data.ipcf_els);
153 }
154 if(rpupd->prepare_state_data.eval_addr) {
155 free(rpupd->prepare_state_data.eval_addr);
156 }
157 }
158 rupdate_upd_init(rpupd,NULL);
159 }
160
161 /*===========================================================================*
162 * rupdate_upd_move *
163 *===========================================================================*/
rupdate_upd_move(struct rproc * src_rp,struct rproc * dst_rp)164 void rupdate_upd_move(struct rproc* src_rp, struct rproc* dst_rp)
165 {
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;
173 }
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;
180 }
181
182 /*===========================================================================*
183 * request_prepare_update_service_debug *
184 *===========================================================================*/
request_prepare_update_service_debug(char * file,int line,struct rproc * rp,int state)185 void request_prepare_update_service_debug(char *file, int line,
186 struct rproc *rp, int state)
187 {
188 /* Request a service to prepare/cancel the update. */
189 message m;
190 struct rprocpub *rpub;
191 int no_reply;
192
193 rpub = rp->r_pub;
194
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;
202 }
203 else {
204 assert(!rp->r_new_rp);
205 }
206
207 m.m_rs_update.flags = rpupd->lu_flags;
208 m.m_rs_update.state_data_gid = rpupd->prepare_state_data_gid;
209
210 if(rs_verbose)
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);
213 }
214 else {
215 if(rs_verbose)
216 printf("RS: %s being requested to cancel the update at %s:%d\n",
217 srv_to_string(rp), file, line);
218 }
219
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);
225 }
226
227 /*===========================================================================*
228 * srv_update *
229 *===========================================================================*/
srv_update(endpoint_t src_e,endpoint_t dst_e,int sys_upd_flags)230 int srv_update(endpoint_t src_e, endpoint_t dst_e, int sys_upd_flags)
231 {
232 int r = OK;
233
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.
239 */
240 if(src_e == VM_PROC_NR) {
241 if(rs_verbose)
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);
245 }
246 else if(!RUPDATE_IS_UPD_VM_MULTI() || RUPDATE_IS_VM_INIT_DONE()) {
247 if(rs_verbose)
248 printf("RS: executing vm_update(%d, %d)\n", src_e, dst_e);
249 r = vm_update(src_e, dst_e, sys_upd_flags);
250 }
251 else {
252 if(rs_verbose)
253 printf("RS: skipping srv_update(%d, %d)\n", src_e, dst_e);
254 }
255
256 return r;
257 }
258
259 /*===========================================================================*
260 * update_service *
261 *===========================================================================*/
update_service(src_rpp,dst_rpp,swap_flag,sys_upd_flags)262 int update_service(src_rpp, dst_rpp, swap_flag, sys_upd_flags)
263 struct rproc **src_rpp;
264 struct rproc **dst_rpp;
265 int swap_flag;
266 int sys_upd_flags;
267 {
268 /* Update an existing service. */
269 int r;
270 struct rproc *src_rp;
271 struct rproc *dst_rp;
272 struct rprocpub *src_rpub;
273 struct rprocpub *dst_rpub;
274 int pid;
275 endpoint_t endpoint;
276
277 src_rp = *src_rpp;
278 dst_rp = *dst_rpp;
279 src_rpub = src_rp->r_pub;
280 dst_rpub = dst_rp->r_pub;
281
282 if(rs_verbose)
283 printf("RS: %s updating into %s\n",
284 srv_to_string(src_rp), srv_to_string(dst_rp));
285
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) {
289 return r;
290 }
291 }
292
293 /* Swap slots here as well. */
294 pid = src_rp->r_pid;
295 endpoint = src_rpub->endpoint;
296
297 swap_slot(&src_rp, &dst_rp);
298
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;
303 dst_rp->r_pid = pid;
304 dst_rp->r_pub->endpoint = endpoint;
305 rproc_ptr[_ENDPOINT_P(dst_rp->r_pub->endpoint)] = dst_rp;
306
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);
312
313 /* Adjust input pointers. */
314 *src_rpp = src_rp;
315 *dst_rpp = dst_rp;
316
317 /* Make the new version active. */
318 activate_service(dst_rp, src_rp);
319
320 if(rs_verbose)
321 printf("RS: %s updated into %s\n",
322 srv_to_string(src_rp), srv_to_string(dst_rp));
323
324 return OK;
325 }
326
327 /*===========================================================================*
328 * rollback_service *
329 *===========================================================================*/
rollback_service(struct rproc ** new_rpp,struct rproc ** old_rpp)330 void rollback_service(struct rproc **new_rpp, struct rproc **old_rpp)
331 {
332 /* Rollback an updated service. */
333 struct rproc *rp;
334 int r = OK;
335
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;
339 char name[20];
340 int priv_flags, init_flags;
341
342 r = sys_whoami(&me, name, sizeof(name), &priv_flags, &init_flags);
343 assert(r == OK);
344 if(me != RS_PROC_NR) {
345 r = vm_update((*new_rpp)->r_pub->endpoint, (*old_rpp)->r_pub->endpoint, SF_VM_ROLLBACK);
346 if(rs_verbose)
347 printf("RS: %s performed rollback\n", srv_to_string(*new_rpp));
348 }
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)
352 rp->r_check_tm = 0;
353 }
354 else {
355 int swap_flag = ((*new_rpp)->r_flags & RS_INIT_PENDING ? RS_DONTSWAP : RS_SWAP);
356 if(rs_verbose)
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);
361 }
362 r = update_service(new_rpp, old_rpp, swap_flag, SF_VM_ROLLBACK);
363 }
364
365 assert(r == OK); /* can't fail */
366 }
367
368 /*===========================================================================*
369 * update_period *
370 *===========================================================================*/
update_period(message * m_ptr)371 void update_period(message *m_ptr)
372 {
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;
376 message m;
377 struct rprocupd *rpupd;
378 struct rproc *rp;
379 struct rprocpub *rpub;
380
381 rpupd = rupdate.curr_rpupd;
382 rp = rpupd->rp;
383 rpub = rp->r_pub;
384
385 /* See if a timeout has occurred. */
386 has_update_timed_out = (rpupd->prepare_maxtime > 0) && (now - rpupd->prepare_tm > rpupd->prepare_maxtime);
387
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.
391 */
392 if(has_update_timed_out) {
393 printf("RS: update failed: maximum prepare time reached\n");
394 end_update(EINTR, RS_CANCEL);
395 }
396 }
397
398 /*===========================================================================*
399 * start_update_prepare *
400 *===========================================================================*/
start_update_prepare(int allow_retries)401 int start_update_prepare(int allow_retries)
402 {
403 /* Start the preparation phase of the update process. */
404 struct rprocupd *prev_rpupd, *rpupd;
405 struct rproc *rp, *new_rp;
406 int r;
407
408 if(!RUPDATE_IS_UPD_SCHEDULED()) {
409 return EINVAL;
410 }
411 if(!rs_is_idle()) {
412 printf("RS: not idle now, try again\n");
413 if(!allow_retries) {
414 abort_update_proc(EAGAIN);
415 }
416 return EAGAIN;
417 }
418
419 if(rs_verbose)
420 printf("RS: starting the preparation phase of the update process\n");
421
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));
426 }
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));
430 }
431
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.
435 */
436 if(RUPDATE_IS_UPD_VM_MULTI()) {
437 RUPDATE_ITER(rupdate.first_rpupd, prev_rpupd, rpupd,
438 if(!UPD_IS_PREPARING_ONLY(rpupd)) {
439 rp = rpupd->rp;
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;
448 }
449 }
450 }
451 );
452 }
453
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);
458 return ESRCH;
459 }
460
461 return OK;
462 }
463
464 /*===========================================================================*
465 * start_update_prepare_next *
466 *===========================================================================*/
start_update_prepare_next()467 struct rprocupd* start_update_prepare_next()
468 {
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;
472
473 if(!RUPDATE_IS_UPDATING()) {
474 rpupd = rupdate.first_rpupd;
475 }
476 else {
477 rpupd = rupdate.curr_rpupd->next_rpupd;
478 }
479 if(!rpupd) {
480 return NULL;
481 }
482
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.
492 */
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 */
498 rp = walk_rpupd->rp;
499 new_rp = rp->r_new_rp;
500 assert(rp && new_rp);
501 if (rs_verbose)
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);
507 );
508 }
509
510 rupdate.flags |= RS_UPDATING;
511
512 while(1) {
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. */
517 break;
518 }
519 if(!rupdate.curr_rpupd->next_rpupd) {
520 /* Continue only if there are services left. */
521 break;
522 }
523 rpupd = rupdate.curr_rpupd->next_rpupd;
524 }
525
526 return rpupd;
527 }
528
529 /*===========================================================================*
530 * start_update *
531 *===========================================================================*/
start_update()532 int start_update()
533 {
534 /* Start the update phase of the update process. */
535 struct rprocupd *prev_rpupd, *rpupd;
536 int r, init_ready_pending=0;
537
538 if(rs_verbose)
539 printf("RS: starting a %s-component update process\n",
540 RUPDATE_IS_UPD_MULTI() ? "multi" : "single");
541
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;
549
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);
554 }
555 );
556
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.
560 */
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);
566 if(r != OK) {
567 return r;
568 }
569 if(!RUPDATE_IS_UPD_VM_MULTI() || rpupd == rupdate.vm_rpupd) {
570 r = complete_srv_update(rpupd);
571 if(r != OK) {
572 return r;
573 }
574 }
575 }
576 );
577
578 /* End update if there is nothing more to do. */
579 if (!init_ready_pending) {
580 end_update(OK, 0);
581 return OK;
582 }
583
584 /* Handle multi-component live updates including VM. */
585 if(RUPDATE_IS_UPD_VM_MULTI()) {
586 message m;
587 /* Check VM initialization, assume failure after timeout. */
588 if (rs_verbose)
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;
594 m.m_type = RS_INIT;
595 m.m_rs_init.result = r;
596 }
597 do_init_ready(&m);
598 /* If initialization was successfull, complete the update. */
599 if(r == OK) {
600 /* Reply and unblock VM immediately. */
601 m.m_type = OK;
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);
607 if(r != OK) {
608 return r;
609 }
610 }
611 );
612 }
613 }
614
615 return OK;
616 }
617
618 /*===========================================================================*
619 * start_srv_update *
620 *===========================================================================*/
start_srv_update(struct rprocupd * rpupd)621 int start_srv_update(struct rprocupd *rpupd)
622 {
623 /* Start updating a single service given its update descriptor. */
624 struct rproc *old_rp, *new_rp;
625 int r, sys_upd_flags = 0;
626
627 old_rp = rpupd->rp;
628 new_rp = old_rp->r_new_rp;
629 assert(old_rp && new_rp);
630
631 if(rs_verbose)
632 printf("RS: %s starting the %s\n", srv_to_string(old_rp), srv_upd_to_string(rpupd));
633
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;
639 }
640
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);
644 if(r != OK) {
645 end_update(r, RS_REPLY);
646 printf("RS: update failed: error %d\n", r);
647 return r;
648 }
649 }
650
651 return OK;
652 }
653
654 /*===========================================================================*
655 * complete_srv_update *
656 *===========================================================================*/
complete_srv_update(struct rprocupd * rpupd)657 int complete_srv_update(struct rprocupd *rpupd)
658 {
659 /* Complete update of a service given its update descriptor. */
660 struct rproc *old_rp, *new_rp;
661 int r;
662
663 old_rp = rpupd->rp;
664 new_rp = old_rp->r_new_rp;
665 assert(old_rp && new_rp);
666
667 if(rs_verbose)
668 printf("RS: %s completing the %s\n", srv_to_string(old_rp), srv_upd_to_string(rpupd));
669
670 new_rp->r_flags &= ~RS_INIT_PENDING;
671
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);
675 if(r != OK) {
676 panic("unable to initialize the new RS instance: %d", r);
677 }
678 if(rs_verbose)
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);
681 if(r != OK) {
682 panic("unable to yield control to the new RS instance: %d", r);
683 }
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");
688 return ERESTART;
689 }
690
691 /* Let the new version run. */
692 r = run_service(new_rp, SEF_INIT_LU, rpupd->init_flags);
693 if(r != OK) {
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);
698 return r;
699 }
700
701 return OK;
702 }
703
704 /*===========================================================================*
705 * abort_update_proc *
706 *===========================================================================*/
abort_update_proc(int reason)707 int abort_update_proc(int reason)
708 {
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.
712 */
713 int is_updating = RUPDATE_IS_UPDATING();
714 assert(reason != OK);
715
716 if(!is_updating && !RUPDATE_IS_UPD_SCHEDULED()) {
717 return EINVAL;
718 }
719
720 if(rs_verbose)
721 printf("RS: aborting the %s update process prematurely\n",
722 is_updating ? "in-progress" : "scheduled");
723
724 if(!is_updating) {
725 rupdate_clear_upds();
726 return OK;
727 }
728
729 if(rupdate.flags & RS_INITIALIZING) {
730 /* Pretend the current service under update failed to initialize. */
731 end_update(reason, RS_REPLY);
732 }
733 else {
734 /* Pretend the current service under update failed to prepare. */
735 end_update(reason, RS_CANCEL);
736 }
737
738 return OK;
739 }
740
741 /*===========================================================================*
742 * end_update_curr *
743 *===========================================================================*/
end_update_curr(struct rprocupd * rpupd,int result,int reply_flag)744 static void end_update_curr(struct rprocupd *rpupd, int result, int reply_flag)
745 {
746 /* Execute the requested action on the current service under update. */
747 struct rproc *old_rp, *new_rp;
748 assert(rpupd == rupdate.curr_rpupd);
749
750 old_rp = rpupd->rp;
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);
756 }
757 end_srv_update(rpupd, result, reply_flag);
758 }
759
760 /*===========================================================================*
761 * end_update_before_prepare *
762 *===========================================================================*/
end_update_before_prepare(struct rprocupd * rpupd,int result)763 static void end_update_before_prepare(struct rprocupd *rpupd, int result)
764 {
765 /* The service is still waiting for the update. Cleanup the new version and
766 * keep the old version running.
767 */
768 struct rproc *old_rp, *new_rp;
769 assert(result != OK);
770
771 old_rp = rpupd->rp;
772 new_rp = old_rp->r_new_rp;
773 assert(old_rp && new_rp);
774 cleanup_service(new_rp);
775 }
776
777 /*===========================================================================*
778 * end_update_prepare_done *
779 *===========================================================================*/
end_update_prepare_done(struct rprocupd * rpupd,int result)780 static void end_update_prepare_done(struct rprocupd *rpupd, int result)
781 {
782 /* The service is blocked after preparing for the update. Unblock it
783 * and cleanup the new version.
784 */
785 assert(!RUPDATE_IS_INITIALIZING());
786 assert(result != OK);
787 assert(!(rpupd->rp->r_flags & RS_INITIALIZING));
788
789 end_srv_update(rpupd, result, RS_REPLY);
790 }
791
792 /*===========================================================================*
793 * end_update_initializing *
794 *===========================================================================*/
end_update_initializing(struct rprocupd * rpupd,int result)795 static void end_update_initializing(struct rprocupd *rpupd, int result)
796 {
797 /* The service is initializing after a live udate. Cleanup the version that
798 * has to die out and let the other version run.
799 */
800 struct rproc *old_rp, *new_rp;
801
802 old_rp = rpupd->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);
809 }
810 end_srv_update(rpupd, result, RS_REPLY);
811 }
812
813 /*===========================================================================*
814 * end_update_rev_iter *
815 *===========================================================================*/
end_update_rev_iter(int result,int reply_flag,struct rprocupd * skip_rpupd,struct rprocupd * only_rpupd)816 static void end_update_rev_iter(int result, int reply_flag,
817 struct rprocupd *skip_rpupd, struct rprocupd *only_rpupd)
818 {
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;
822
823 is_after_curr = 1;
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;
836 }
837 else {
838 is_before_prepare = is_after_curr;
839 is_prepare_done = is_before_curr;
840 is_initializing = 0;
841 }
842 if((!skip_rpupd || rpupd != skip_rpupd) && (!only_rpupd || rpupd == only_rpupd)) {
843 /* Analyze different cases. */
844 if(is_curr) {
845 end_update_curr(rpupd, result, reply_flag);
846 }
847 else if(is_before_prepare) {
848 end_update_before_prepare(rpupd, result);
849 }
850 else if(is_prepare_done) {
851 end_update_prepare_done(rpupd, result);
852 }
853 else {
854 assert(is_initializing);
855 end_update_initializing(rpupd, result);
856 }
857 }
858 }
859 );
860 }
861
862 /*===========================================================================*
863 * end_update_debug *
864 *===========================================================================*/
end_update_debug(char * file,int line,int result,int reply_flag)865 void end_update_debug(char *file, int line,
866 int result, int reply_flag)
867 {
868 /* End an in-progress update process. */
869 struct rprocupd *prev_rpupd, *rpupd, *rpupd_it;
870 struct rproc *rp, *old_rp, *new_rp;
871 int i, r, slot_nr;
872
873 assert(RUPDATE_IS_UPDATING());
874
875 if(rs_verbose)
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),
878 file, line);
879
880 /* If the new instance of RS is active and the update failed, ending
881 * the update couldn't be any easier.
882 */
883 if(result != OK && RUPDATE_IS_RS_INIT_DONE()) {
884 if(rs_verbose)
885 printf("RS: update failed, new RS instance will now exit\n");
886 exit(1);
887 }
888
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);
894 }
895 rpupd->rp->r_flags &= ~RS_PREPARE_DONE;
896 }
897 );
898
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);
903 }
904
905 /* End the update and complete initialization in case of success. */
906 RUPDATE_ITER(rupdate.first_rpupd, prev_rpupd, rpupd,
907 if(prev_rpupd) {
908 rupdate_upd_clear(prev_rpupd);
909 }
910 if(result == OK && !UPD_IS_PREPARING_ONLY(rpupd)) {
911 /* The rp pointer points to the new instance in this case. */
912 new_rp = rpupd->rp;
913 end_srv_init(new_rp);
914 }
915 );
916 late_reply(rupdate.last_rpupd->rp, result);
917 rupdate_upd_clear(rupdate.last_rpupd);
918 RUPDATE_CLEAR();
919
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);
926 }
927 }
928
929 /*===========================================================================*
930 * end_srv_update *
931 *===========================================================================*/
end_srv_update(struct rprocupd * rpupd,int result,int reply_flag)932 void end_srv_update(struct rprocupd *rpupd, int result, int reply_flag)
933 {
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.
942 */
943 struct rproc *old_rp, *new_rp, *exiting_rp, *surviving_rp;
944 struct rproc **rps;
945
946 struct rprocpub *rpub;
947 int nr_rps, i;
948
949 old_rp = rpupd->rp;
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.
955 */
956 reply_flag = RS_CANCEL;
957 }
958
959 if(rs_verbose)
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));
962
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();
969
970 /* Keep track of the surviving process in the update descriptor from now on. */
971 rpupd->rp = surviving_rp;
972
973 /* Unlink the two versions. */
974 old_rp->r_new_rp = NULL;
975 new_rp->r_old_rp = NULL;
976
977 /* Mark the version that has to survive as no longer updating and
978 * reply when asked to.
979 */
980 surviving_rp->r_flags &= ~(RS_UPDATING|RS_PREPARE_DONE|RS_INIT_DONE|RS_INIT_PENDING);
981 if(reply_flag == RS_REPLY) {
982 message m;
983 m.m_type = result;
984 reply(surviving_rp->r_pub->endpoint, surviving_rp, &m);
985 }
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);
989 }
990 }
991
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)) {
996 message m;
997 m.m_type = EDEADEPT;
998 rps[i]->r_flags |= RS_CLEANUP_DETACH;
999 cleanup_service(rps[i]);
1000 reply(rps[i]->r_pub->endpoint, rps[i], &m);
1001 }
1002 else {
1003 cleanup_service(rps[i]);
1004 }
1005 }
1006
1007 if(rs_verbose)
1008 printf("RS: %s ended the %s\n", srv_to_string(surviving_rp),
1009 srv_upd_to_string(rpupd));
1010 }
1011
1012