xref: /minix/minix/servers/rs/update.c (revision 0a6a1f1d)
1 
2 #include "inc.h"
3 
4 /*===========================================================================*
5  *			      rupdate_clear_upds			     *
6  *===========================================================================*/
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  *===========================================================================*/
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  *===========================================================================*/
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  *===========================================================================*/
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  *===========================================================================*/
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  *===========================================================================*/
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  *===========================================================================*/
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  *===========================================================================*/
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  *===========================================================================*/
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  *===========================================================================*/
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  *===========================================================================*/
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  *===========================================================================*/
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  *===========================================================================*/
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  *===========================================================================*/
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  *===========================================================================*/
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  *===========================================================================*/
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  *===========================================================================*/
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  *===========================================================================*/
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  *===========================================================================*/
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  *===========================================================================*/
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  *===========================================================================*/
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  *===========================================================================*/
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  *===========================================================================*/
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  *===========================================================================*/
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