xref: /minix3/minix/servers/rs/update.c (revision b5e2faaaaf60a8b9a02f8d72f64caa56a87eb312)
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;
27   int lu_flags;
28 
29   rpupd->prev_rpupd = rupdate.last_rpupd;
30   if(rupdate.num_rpupds == 0) {
31       rupdate.first_rpupd = rpupd;
32       rupdate.curr_rpupd = rpupd;
33   }
34   else {
35       rupdate.last_rpupd->next_rpupd = rpupd;
36   }
37   rupdate.last_rpupd = rpupd;
38   rupdate.num_rpupds++;
39 
40   /* Propagate relevant flags from the new descriptor. */
41   lu_flags = rpupd->lu_flags & (SEF_LU_INCLUDES_VM|SEF_LU_INCLUDES_RS|SEF_LU_UNSAFE|SEF_LU_MULTI);
42   if(lu_flags) {
43       RUPDATE_ITER(rupdate.first_rpupd, prev_rpupd, rpupd,
44           rpupd->lu_flags |= lu_flags;
45           rpupd->init_flags |= lu_flags;
46       );
47   }
48 
49   /* Set VM/RS update descriptor pointers. */
50   if(!rupdate.vm_rpupd && (lu_flags & SEF_LU_INCLUDES_VM)) {
51       rupdate.vm_rpupd = rupdate.last_rpupd;
52   }
53   else if(!rupdate.rs_rpupd && (lu_flags & SEF_LU_INCLUDES_RS)) {
54       rupdate.rs_rpupd = rupdate.last_rpupd;
55   }
56 }
57 
58 /*===========================================================================*
59  *			  rupdate_set_new_upd_flags  			     *
60  *===========================================================================*/
61 void rupdate_set_new_upd_flags(struct rprocupd* rpupd)
62 {
63   /* Set multi-component update flags. */
64   if(rupdate.num_rpupds > 0) {
65       rpupd->lu_flags |= SEF_LU_MULTI;
66       rpupd->init_flags |= SEF_LU_MULTI;
67   }
68 
69   /* Propagate relevant flags from last service under update (if any). */
70   if(rupdate.last_rpupd) {
71       int lu_flags = rupdate.last_rpupd->lu_flags & (SEF_LU_INCLUDES_VM|SEF_LU_INCLUDES_RS|SEF_LU_UNSAFE);
72       rpupd->lu_flags |= lu_flags;
73       rpupd->init_flags |= lu_flags;
74   }
75 
76   if(UPD_IS_PREPARING_ONLY(rpupd)) {
77       return;
78   }
79 
80   /* Set VM/RS update flags. */
81   if(rpupd->rp->r_pub->endpoint == VM_PROC_NR) {
82       rpupd->lu_flags |= SEF_LU_INCLUDES_VM;
83       rpupd->init_flags |= SEF_LU_INCLUDES_VM;
84   }
85   else if(rpupd->rp->r_pub->endpoint == RS_PROC_NR) {
86       rpupd->lu_flags |= SEF_LU_INCLUDES_RS;
87       rpupd->init_flags |= SEF_LU_INCLUDES_RS;
88   }
89 }
90 
91 /*===========================================================================*
92  *			      rupdate_upd_init  			     *
93  *===========================================================================*/
94 void rupdate_upd_init(struct rprocupd* rpupd, struct rproc *rp)
95 {
96   /* Initialize an update descriptor for a given service. */
97   memset(rpupd, 0, sizeof(*(rpupd)));
98   rpupd->prepare_state_data_gid = GRANT_INVALID;
99   rpupd->prepare_state_data.ipcf_els_gid = GRANT_INVALID;
100   rpupd->prepare_state_data.eval_gid = GRANT_INVALID;
101   rpupd->state_endpoint = NONE;
102   rpupd->rp = rp;
103 }
104 
105 /*===========================================================================*
106  *			      rupdate_upd_clear 			     *
107  *===========================================================================*/
108 void rupdate_upd_clear(struct rprocupd* rpupd)
109 {
110   /* Clear an update descriptor. */
111   if(rpupd->rp->r_new_rp) {
112       cleanup_service(rpupd->rp->r_new_rp);
113   }
114   if(rpupd->prepare_state_data_gid != GRANT_INVALID) {
115       cpf_revoke(rpupd->prepare_state_data_gid);
116   }
117   if(rpupd->prepare_state_data.size > 0) {
118       if(rpupd->prepare_state_data.ipcf_els_gid != GRANT_INVALID) {
119           cpf_revoke(rpupd->prepare_state_data.ipcf_els_gid);
120       }
121       if(rpupd->prepare_state_data.eval_gid != GRANT_INVALID) {
122           cpf_revoke(rpupd->prepare_state_data.eval_gid);
123       }
124       if(rpupd->prepare_state_data.ipcf_els) {
125           free(rpupd->prepare_state_data.ipcf_els);
126       }
127       if(rpupd->prepare_state_data.eval_addr) {
128           free(rpupd->prepare_state_data.eval_addr);
129       }
130   }
131   rupdate_upd_init(rpupd,NULL);
132 }
133 
134 /*===========================================================================*
135  *			       rupdate_upd_move 			     *
136  *===========================================================================*/
137 void rupdate_upd_move(struct rproc* src_rp, struct rproc* dst_rp)
138 {
139   /* Move an update descriptor from one service instance to another. */
140   dst_rp->r_upd = src_rp->r_upd;
141   dst_rp->r_upd.rp = dst_rp;
142   if(src_rp->r_new_rp) {
143       assert(!dst_rp->r_new_rp);
144       dst_rp->r_new_rp = src_rp->r_new_rp;
145       dst_rp->r_new_rp->r_old_rp = dst_rp;
146   }
147   if(dst_rp->r_upd.prev_rpupd) dst_rp->r_upd.prev_rpupd->next_rpupd = &dst_rp->r_upd;
148   if(dst_rp->r_upd.next_rpupd) dst_rp->r_upd.next_rpupd->prev_rpupd = &dst_rp->r_upd;
149   if(rupdate.first_rpupd == &src_rp->r_upd) rupdate.first_rpupd = &dst_rp->r_upd;
150   if(rupdate.last_rpupd == &src_rp->r_upd) rupdate.last_rpupd = &dst_rp->r_upd;
151   rupdate_upd_init(&src_rp->r_upd, NULL);
152   src_rp->r_new_rp = NULL;
153 }
154 
155 /*===========================================================================*
156  *		     request_prepare_update_service_debug		     *
157  *===========================================================================*/
158 void request_prepare_update_service_debug(char *file, int line,
159   struct rproc *rp, int state)
160 {
161   /* Request a service to prepare/cancel the update. */
162   message m;
163   struct rprocpub *rpub;
164   int no_reply;
165 
166   rpub = rp->r_pub;
167 
168   if(state != SEF_LU_STATE_NULL) {
169       struct rprocupd *rpupd = &rp->r_upd;
170       getticks(&rpupd->prepare_tm);
171       if(!UPD_IS_PREPARING_ONLY(rpupd)) {
172           assert(rp->r_new_rp);
173           rp->r_flags |= RS_UPDATING;
174           rp->r_new_rp->r_flags |= RS_UPDATING;
175       }
176       else {
177           assert(!rp->r_new_rp);
178       }
179 
180       m.m_rs_update.flags = rpupd->lu_flags;
181       m.m_rs_update.state_data_gid = rpupd->prepare_state_data_gid;
182 
183       if(rs_verbose)
184           printf("RS: %s being requested to prepare for the %s at %s:%d\n",
185               srv_to_string(rp), srv_upd_to_string(rpupd), file, line);
186   }
187   else {
188       if(rs_verbose)
189           printf("RS: %s being requested to cancel the update at %s:%d\n",
190               srv_to_string(rp), file, line);
191   }
192 
193   /* Request to prepare for the update or cancel the update. */
194   m.m_type = RS_LU_PREPARE;
195   m.m_rs_update.state = state;
196   no_reply = !(rp->r_flags & RS_PREPARE_DONE);
197   rs_asynsend(rp, &m, no_reply);
198 }
199 
200 /*===========================================================================*
201  *				 srv_update				     *
202  *===========================================================================*/
203 int srv_update(endpoint_t src_e, endpoint_t dst_e, int sys_upd_flags)
204 {
205   int r = OK;
206 
207   /* Ask VM to swap the slots of the two processes and tell the kernel to
208    * do the same. If VM is being updated, only perform the kernel
209    * part of the call. The new instance of VM will do the rest at
210    * initialization time. If a multi-component update includes VM, let VM
211    * handle updates at state transfer time and rollbacks afterwards.
212    */
213   if(src_e == VM_PROC_NR) {
214       if(rs_verbose)
215           printf("RS: executing sys_update(%d, %d)\n", src_e, dst_e);
216       r = sys_update(src_e, dst_e,
217           sys_upd_flags & SF_VM_ROLLBACK ? SYS_UPD_ROLLBACK : 0);
218   }
219   else if(!RUPDATE_IS_UPD_VM_MULTI() || RUPDATE_IS_VM_INIT_DONE()) {
220        if(rs_verbose)
221            printf("RS: executing vm_update(%d, %d)\n", src_e, dst_e);
222        r = vm_update(src_e, dst_e, sys_upd_flags);
223    }
224    else {
225        if(rs_verbose)
226            printf("RS: skipping srv_update(%d, %d)\n", src_e, dst_e);
227    }
228 
229   return r;
230 }
231 
232 /*===========================================================================*
233  *				update_service				     *
234  *===========================================================================*/
235 int update_service(src_rpp, dst_rpp, swap_flag, sys_upd_flags)
236 struct rproc **src_rpp;
237 struct rproc **dst_rpp;
238 int swap_flag;
239 int sys_upd_flags;
240 {
241 /* Update an existing service. */
242   int r;
243   struct rproc *src_rp;
244   struct rproc *dst_rp;
245   struct rprocpub *src_rpub;
246   struct rprocpub *dst_rpub;
247   int pid;
248   endpoint_t endpoint;
249 
250   src_rp = *src_rpp;
251   dst_rp = *dst_rpp;
252   src_rpub = src_rp->r_pub;
253   dst_rpub = dst_rp->r_pub;
254 
255   if(rs_verbose)
256       printf("RS: %s updating into %s\n",
257           srv_to_string(src_rp), srv_to_string(dst_rp));
258 
259   /* Swap the slots of the two processes when asked to. */
260   if(swap_flag == RS_SWAP) {
261       if((r = srv_update(src_rpub->endpoint, dst_rpub->endpoint, sys_upd_flags)) != OK) {
262           return r;
263       }
264   }
265 
266   /* Swap slots here as well. */
267   pid = src_rp->r_pid;
268   endpoint = src_rpub->endpoint;
269 
270   swap_slot(&src_rp, &dst_rp);
271 
272   /* Reassign pids and endpoints. */
273   src_rp->r_pid = dst_rp->r_pid;
274   src_rp->r_pub->endpoint = dst_rp->r_pub->endpoint;
275   rproc_ptr[_ENDPOINT_P(src_rp->r_pub->endpoint)] = src_rp;
276   dst_rp->r_pid = pid;
277   dst_rp->r_pub->endpoint = endpoint;
278   rproc_ptr[_ENDPOINT_P(dst_rp->r_pub->endpoint)] = dst_rp;
279 
280   /* Update in-RS priv structs */
281   if ((r = sys_getpriv(&src_rp->r_priv, src_rp->r_pub->endpoint)) != OK)
282     panic("RS: update: could not update RS copies of priv of src: %d\n", r);
283   if ((r = sys_getpriv(&dst_rp->r_priv, dst_rp->r_pub->endpoint)) != OK)
284     panic("RS: update: could not update RS copies of priv of dst: %d\n", r);
285 
286   /* Adjust input pointers. */
287   *src_rpp = src_rp;
288   *dst_rpp = dst_rp;
289 
290   /* Make the new version active. */
291   activate_service(dst_rp, src_rp);
292 
293   if(rs_verbose)
294       printf("RS: %s updated into %s\n",
295           srv_to_string(src_rp), srv_to_string(dst_rp));
296 
297   return OK;
298 }
299 
300 /*===========================================================================*
301  *			      rollback_service				     *
302  *===========================================================================*/
303 void rollback_service(struct rproc **new_rpp, struct rproc **old_rpp)
304 {
305   /* Rollback an updated service. */
306   struct rproc *rp;
307   int r = OK;
308 
309   /* RS is special, we may only need to swap the slots to rollback. */
310   if((*old_rpp)->r_pub->endpoint == RS_PROC_NR) {
311       endpoint_t me = NONE;
312       char name[20];
313       int priv_flags, init_flags;
314 
315       r = sys_whoami(&me, name, sizeof(name), &priv_flags, &init_flags);
316       assert(r == OK);
317       if(me != RS_PROC_NR) {
318           r = vm_update((*new_rpp)->r_pub->endpoint, (*old_rpp)->r_pub->endpoint, SF_VM_ROLLBACK);
319           if(rs_verbose)
320               printf("RS: %s performed rollback\n", srv_to_string(*new_rpp));
321       }
322       /* Since we may now have missed heartbeat replies, resend requests. */
323       for (rp = BEG_RPROC_ADDR; rp < END_RPROC_ADDR; rp++)
324           if (rp->r_flags & RS_ACTIVE)
325               rp->r_check_tm = 0;
326   }
327   else {
328       int swap_flag = ((*new_rpp)->r_flags & RS_INIT_PENDING ? RS_DONTSWAP : RS_SWAP);
329       if(rs_verbose)
330           printf("RS: %s performs rollback\n", srv_to_string(*new_rpp));
331       if(swap_flag == RS_SWAP) {
332           /* Freeze the new instance to rollback safely. */
333           sys_privctl((*new_rpp)->r_pub->endpoint, SYS_PRIV_DISALLOW, NULL);
334       }
335       r = update_service(new_rpp, old_rpp, swap_flag, SF_VM_ROLLBACK);
336   }
337 
338   assert(r == OK); /* can't fail */
339 }
340 
341 /*===========================================================================*
342  *				update_period				     *
343  *===========================================================================*/
344 void update_period(message *m_ptr)
345 {
346   /* Periodically check the status of the update (preparation phase). */
347   clock_t now = m_ptr->m_notify.timestamp;
348   short has_update_timed_out;
349   message m;
350   struct rprocupd *rpupd;
351   struct rproc *rp;
352   struct rprocpub *rpub;
353 
354   rpupd = rupdate.curr_rpupd;
355   rp = rpupd->rp;
356   rpub = rp->r_pub;
357 
358   /* See if a timeout has occurred. */
359   has_update_timed_out = (rpupd->prepare_maxtime > 0) && (now - rpupd->prepare_tm > rpupd->prepare_maxtime);
360 
361   /* If an update timed out, end the update process and notify
362    * the old version that the update has been canceled. From now on, the old
363    * version will continue executing.
364    */
365   if(has_update_timed_out) {
366       printf("RS: update failed: maximum prepare time reached\n");
367       end_update(EINTR, RS_CANCEL);
368   }
369 }
370 
371 /*===========================================================================*
372  *			    start_update_prepare			     *
373  *===========================================================================*/
374 int start_update_prepare(int allow_retries)
375 {
376   /* Start the preparation phase of the update process. */
377   struct rprocupd *prev_rpupd, *rpupd;
378   struct rproc *rp, *new_rp;
379   int r;
380 
381   if(!RUPDATE_IS_UPD_SCHEDULED()) {
382       return EINVAL;
383   }
384   if(!rs_is_idle()) {
385       printf("RS: not idle now, try again\n");
386       if(!allow_retries) {
387           abort_update_proc(EAGAIN);
388       }
389       return EAGAIN;
390   }
391 
392   if(rs_verbose)
393       printf("RS: starting the preparation phase of the update process\n");
394 
395   if(rupdate.rs_rpupd) {
396       assert(rupdate.rs_rpupd == rupdate.last_rpupd);
397       assert(rupdate.rs_rpupd->rp->r_pub->endpoint == RS_PROC_NR);
398       assert(!UPD_IS_PREPARING_ONLY(rupdate.rs_rpupd));
399   }
400   if(rupdate.vm_rpupd) {
401       assert(rupdate.vm_rpupd->rp->r_pub->endpoint == VM_PROC_NR);
402       assert(!UPD_IS_PREPARING_ONLY(rupdate.vm_rpupd));
403   }
404 
405   /* If a multi-component update includes VM, fill information about old
406    * and new endpoints, as well as update flags. VM needs this to complete
407    * the update internally at state transfer time.
408    */
409   if(RUPDATE_IS_UPD_VM_MULTI()) {
410       RUPDATE_ITER(rupdate.first_rpupd, prev_rpupd, rpupd,
411           if(!UPD_IS_PREPARING_ONLY(rpupd)) {
412               rp = rpupd->rp;
413               new_rp = rp->r_new_rp;
414               assert(rp && new_rp);
415               rp->r_pub->old_endpoint = rpupd->state_endpoint;
416               rp->r_pub->new_endpoint = rp->r_pub->endpoint;
417               if(rpupd != rupdate.vm_rpupd && rpupd != rupdate.rs_rpupd) {
418                   rp->r_pub->sys_flags |= SF_VM_UPDATE;
419                   if(rpupd->lu_flags & SEF_LU_NOMMAP) {
420                       rp->r_pub->sys_flags |= SF_VM_NOMMAP;
421                   }
422                   if(!(rpupd->lu_flags & SEF_LU_UNSAFE)) {
423                       if(rs_verbose)
424                           printf("RS: %s pinning memory\n", srv_to_string(rp));
425                       vm_memctl(rp->r_pub->new_endpoint, VM_RS_MEM_PIN, 0, 0);
426                       if(rs_verbose)
427                           printf("RS: %s pinning memory\n", srv_to_string(new_rp));
428                       vm_memctl(new_rp->r_pub->endpoint, VM_RS_MEM_PIN, 0, 0);
429                   }
430               }
431           }
432       );
433   }
434 
435   /* Request the first service to prepare for the update. */
436   if(start_update_prepare_next() == NULL) {
437       /* If we are done already, end the update now. */
438       end_update(OK, RS_REPLY);
439       return ESRCH;
440   }
441 
442   return OK;
443 }
444 
445 /*===========================================================================*
446  *			  start_update_prepare_next			     *
447  *===========================================================================*/
448 struct rprocupd* start_update_prepare_next()
449 {
450   /* Request the next service in the update chain to prepare for the update. */
451   struct rprocupd *rpupd = NULL;
452   if(!RUPDATE_IS_UPDATING()) {
453       rpupd = rupdate.first_rpupd;
454   }
455   else {
456       rpupd = rupdate.curr_rpupd->next_rpupd;
457   }
458   if(!rpupd) {
459       return NULL;
460   }
461   rupdate.flags |= RS_UPDATING;
462 
463   while(1) {
464       rupdate.curr_rpupd = rpupd;
465       request_prepare_update_service(rupdate.curr_rpupd->rp, rupdate.curr_rpupd->prepare_state);
466       if(!UPD_IS_PREPARING_ONLY(rpupd)) {
467           /* Continue only if the current service requires a prepare-only update. */
468           break;
469       }
470       if(!rupdate.curr_rpupd->next_rpupd) {
471           /* Continue only if there are services left. */
472           break;
473       }
474       rpupd = rupdate.curr_rpupd->next_rpupd;
475   }
476 
477   return rpupd;
478 }
479 
480 /*===========================================================================*
481  *				start_update				     *
482  *===========================================================================*/
483 int start_update()
484 {
485   /* Start the update phase of the update process. */
486   struct rprocupd *prev_rpupd, *rpupd;
487   int r, init_ready_pending=0;
488 
489   if(rs_verbose)
490       printf("RS: starting a %s-component update process\n",
491           RUPDATE_IS_UPD_MULTI() ? "multi" : "single");
492 
493   assert(RUPDATE_IS_UPDATING());
494   assert(rupdate.num_rpupds > 0);
495   assert(rupdate.num_init_ready_pending == 0);
496   assert(rupdate.first_rpupd);
497   assert(rupdate.last_rpupd);
498   assert(rupdate.curr_rpupd == rupdate.last_rpupd);
499   rupdate.flags |= RS_INITIALIZING;
500 
501   /* Cancel the update for the prepare-only services now. */
502   RUPDATE_ITER(rupdate.first_rpupd, prev_rpupd, rpupd,
503       if(UPD_IS_PREPARING_ONLY(rpupd)) {
504           request_prepare_update_service(rpupd->rp, SEF_LU_STATE_NULL);
505       }
506   );
507 
508   /* Iterate over all the processes scheduled for the update. Update each
509    * service and initialize the new instance. If VM is part of a
510    * multi-component live update, initialize VM first.
511    */
512   RUPDATE_ITER(rupdate.first_rpupd, prev_rpupd, rpupd,
513       rupdate.curr_rpupd = rpupd;
514       if(!UPD_IS_PREPARING_ONLY(rpupd)) {
515           init_ready_pending=1;
516           r = start_srv_update(rpupd);
517           if(r != OK) {
518               return r;
519           }
520           if(!RUPDATE_IS_UPD_VM_MULTI() || rpupd == rupdate.vm_rpupd) {
521               r = complete_srv_update(rpupd);
522               if(r != OK) {
523                   return r;
524               }
525           }
526       }
527   );
528 
529   /* End update if there is nothing more to do. */
530   if (!init_ready_pending) {
531       end_update(OK, 0);
532       return OK;
533   }
534 
535   /* Handle multi-component live updates including VM. */
536   if(RUPDATE_IS_UPD_VM_MULTI()) {
537       message m;
538       /* Check VM initialization, assume failure after timeout. */
539       if (rs_verbose)
540           printf("RS: waiting for VM to initialize...\n");
541       r = rs_receive_ticks(VM_PROC_NR, &m, NULL, UPD_INIT_MAXTIME(rupdate.vm_rpupd));
542       if(r != OK || m.m_type != RS_INIT || m.m_rs_init.result != OK) {
543           r = (r == OK && m.m_type == RS_INIT ? m.m_rs_init.result : EINTR);
544           m.m_source = VM_PROC_NR;
545           m.m_type = RS_INIT;
546           m.m_rs_init.result = r;
547       }
548       do_init_ready(&m);
549       /* If initialization was successfull, complete the update. */
550       if(r == OK) {
551           /* Reply and unblock VM immediately. */
552           m.m_type = OK;
553           reply(VM_PROC_NR, NULL, &m);
554           /* Initialize other services. */
555           RUPDATE_ITER(rupdate.first_rpupd, prev_rpupd, rpupd,
556               if(!UPD_IS_PREPARING_ONLY(rpupd) && rpupd != rupdate.vm_rpupd) {
557                   r = complete_srv_update(rpupd);
558                   if(r != OK) {
559                       return r;
560                   }
561               }
562           );
563       }
564   }
565 
566   return OK;
567 }
568 
569 /*===========================================================================*
570  *			      start_srv_update				     *
571  *===========================================================================*/
572 int start_srv_update(struct rprocupd *rpupd)
573 {
574   /* Start updating a single service given its update descriptor. */
575   struct rproc *old_rp, *new_rp;
576   int r, sys_upd_flags = 0;
577 
578   old_rp = rpupd->rp;
579   new_rp = old_rp->r_new_rp;
580   assert(old_rp && new_rp);
581 
582   if(rs_verbose)
583       printf("RS: %s starting the %s\n", srv_to_string(old_rp), srv_upd_to_string(rpupd));
584 
585   rupdate.num_init_ready_pending++;
586   new_rp->r_flags |= RS_INITIALIZING;
587   new_rp->r_flags |= RS_INIT_PENDING;
588   if(rpupd->lu_flags & SEF_LU_NOMMAP) {
589       sys_upd_flags |= SF_VM_NOMMAP;
590   }
591 
592   /* Perform the update, skip for RS. */
593   if(old_rp->r_pub->endpoint != RS_PROC_NR) {
594       r = update_service(&old_rp, &new_rp, RS_SWAP, sys_upd_flags);
595       if(r != OK) {
596           end_update(r, RS_REPLY);
597           printf("RS: update failed: error %d\n", r);
598           return r;
599       }
600   }
601 
602   return OK;
603 }
604 
605 /*===========================================================================*
606  *			   complete_srv_update				     *
607  *===========================================================================*/
608 int complete_srv_update(struct rprocupd *rpupd)
609 {
610   /* Complete update of a service given its update descriptor. */
611   struct rproc *old_rp, *new_rp;
612   int r;
613 
614   old_rp = rpupd->rp;
615   new_rp = old_rp->r_new_rp;
616   assert(old_rp && new_rp);
617 
618   if(rs_verbose)
619       printf("RS: %s completing the %s\n", srv_to_string(old_rp), srv_upd_to_string(rpupd));
620 
621   new_rp->r_flags &= ~RS_INIT_PENDING;
622 
623   /* If RS itself is updating, yield control to the new version immediately. */
624   if(old_rp->r_pub->endpoint == RS_PROC_NR) {
625       r = init_service(new_rp, SEF_INIT_LU, rpupd->init_flags);
626       if(r != OK) {
627           panic("unable to initialize the new RS instance: %d", r);
628       }
629       if(rs_verbose)
630       	  printf("RS: %s is the new RS instance we'll yield control to\n", srv_to_string(new_rp));
631       r = sys_privctl(new_rp->r_pub->endpoint, SYS_PRIV_YIELD, NULL);
632       if(r != OK) {
633           panic("unable to yield control to the new RS instance: %d", r);
634       }
635       /* If we get this far, the new version failed to initialize. Rollback. */
636       rollback_service(&new_rp, &old_rp);
637       end_update(ERESTART, RS_REPLY);
638       printf("RS: update failed: state transfer failed for the new RS instance\n");
639       return ERESTART;
640   }
641 
642   /* Let the new version run. */
643   r = run_service(new_rp, SEF_INIT_LU, rpupd->init_flags);
644   if(r != OK) {
645       /* Something went wrong. Rollback. */
646       rollback_service(&new_rp, &old_rp);
647       end_update(r, RS_REPLY);
648       printf("RS: update failed: error %d\n", r);
649       return r;
650   }
651 
652   return OK;
653 }
654 
655 /*===========================================================================*
656  *			    abort_update_proc				     *
657  *===========================================================================*/
658 int abort_update_proc(int reason)
659 {
660   /* This function is called to abort a scheduled/in-progress update process
661    * indiscriminately. If the update is in progress, simply pretend the
662    * current service is causing premature termination of the update.
663    */
664   int is_updating = RUPDATE_IS_UPDATING();
665   assert(reason != OK);
666 
667   if(!is_updating && !RUPDATE_IS_UPD_SCHEDULED()) {
668       return EINVAL;
669   }
670 
671   if(rs_verbose)
672       printf("RS: aborting the %s update process prematurely\n",
673           is_updating ? "in-progress" : "scheduled");
674 
675   if(!is_updating) {
676       rupdate_clear_upds();
677       return OK;
678   }
679 
680   if(rupdate.flags & RS_INITIALIZING) {
681       /* Pretend the current service under update failed to initialize. */
682       end_update(reason, RS_REPLY);
683   }
684   else {
685       /* Pretend the current service under update failed to prepare. */
686       end_update(reason, RS_CANCEL);
687   }
688 
689   return OK;
690 }
691 
692 /*===========================================================================*
693  *			    end_update_curr				     *
694  *===========================================================================*/
695 static void end_update_curr(struct rprocupd *rpupd, int result, int reply_flag)
696 {
697   /* Execute the requested action on the current service under update. */
698   struct rproc *old_rp, *new_rp;
699   assert(rpupd == rupdate.curr_rpupd);
700 
701   old_rp = rpupd->rp;
702   new_rp = old_rp->r_new_rp;
703   assert(old_rp && new_rp);
704   if(result != OK && SRV_IS_UPDATING_AND_INITIALIZING(new_rp) && rpupd != rupdate.rs_rpupd) {
705       /* Rollback in case of failures at initialization time. */
706       rollback_service(&new_rp, &old_rp);
707   }
708   end_srv_update(rpupd, result, reply_flag);
709 }
710 
711 /*===========================================================================*
712  *			end_update_before_prepare			     *
713  *===========================================================================*/
714 static void end_update_before_prepare(struct rprocupd *rpupd, int result)
715 {
716   /* The service is still waiting for the update. Cleanup the new version and
717    * keep the old version running.
718    */
719   struct rproc *old_rp, *new_rp;
720   assert(result != OK);
721 
722   old_rp = rpupd->rp;
723   new_rp = old_rp->r_new_rp;
724   assert(old_rp && new_rp);
725   cleanup_service(new_rp);
726 }
727 
728 /*===========================================================================*
729  *			 end_update_prepare_done			     *
730  *===========================================================================*/
731 static void end_update_prepare_done(struct rprocupd *rpupd, int result)
732 {
733   /* The service is blocked after preparing for the update. Unblock it
734    * and cleanup the new version.
735    */
736   assert(!RUPDATE_IS_INITIALIZING());
737   assert(result != OK);
738   assert(!(rpupd->rp->r_flags & RS_INITIALIZING));
739 
740   end_srv_update(rpupd, result, RS_REPLY);
741 }
742 
743 /*===========================================================================*
744  *			 end_update_initializing			     *
745  *===========================================================================*/
746 static void end_update_initializing(struct rprocupd *rpupd, int result)
747 {
748   /* The service is initializing after a live udate. Cleanup the version that
749    * has to die out and let the other version run.
750    */
751   struct rproc *old_rp, *new_rp;
752 
753   old_rp = rpupd->rp;
754   new_rp = old_rp->r_new_rp;
755   assert(old_rp && new_rp);
756   assert(SRV_IS_UPDATING_AND_INITIALIZING(new_rp));
757   if(result != OK && rpupd != rupdate.rs_rpupd) {
758       /* Rollback in case of failures at initialization time. */
759       rollback_service(&new_rp, &old_rp);
760   }
761   end_srv_update(rpupd, result, RS_REPLY);
762 }
763 
764 /*===========================================================================*
765  *			    end_update_rev_iter				     *
766  *===========================================================================*/
767 static void end_update_rev_iter(int result, int reply_flag,
768     struct rprocupd *skip_rpupd, struct rprocupd *only_rpupd)
769 {
770   /* End the update for all the requested services. */
771   struct rprocupd *prev_rpupd, *rpupd;
772   short is_curr, is_before_curr, is_after_curr;
773 
774   is_after_curr = 1;
775   RUPDATE_REV_ITER(rupdate.last_rpupd, prev_rpupd, rpupd,
776       is_curr = (rupdate.curr_rpupd == rpupd);
777       is_after_curr = is_after_curr && !is_curr;
778       if(!UPD_IS_PREPARING_ONLY(rpupd)) {
779           short is_before_prepare;
780           short is_prepare_done;
781           short is_initializing;
782           is_before_curr = !is_curr && !is_after_curr;
783           if(RUPDATE_IS_INITIALIZING()) {
784               is_before_prepare = 0;
785               is_prepare_done = is_after_curr;
786               is_initializing = is_before_curr;
787           }
788           else {
789               is_before_prepare = is_after_curr;
790               is_prepare_done = is_before_curr;
791               is_initializing = 0;
792           }
793           if((!skip_rpupd || rpupd != skip_rpupd) && (!only_rpupd || rpupd == only_rpupd)) {
794               /* Analyze different cases. */
795               if(is_curr) {
796                   end_update_curr(rpupd, result, reply_flag);
797               }
798               else if(is_before_prepare) {
799                   end_update_before_prepare(rpupd, result);
800               }
801               else if(is_prepare_done) {
802                   end_update_prepare_done(rpupd, result);
803               }
804               else {
805                   assert(is_initializing);
806                   end_update_initializing(rpupd, result);
807               }
808           }
809       }
810   );
811 }
812 
813 /*===========================================================================*
814  *			    end_update_debug				     *
815  *===========================================================================*/
816 void end_update_debug(char *file, int line,
817     int result, int reply_flag)
818 {
819   /* End an in-progress update process. */
820   struct rprocupd *prev_rpupd, *rpupd, *rpupd_it;
821   struct rproc *rp, *old_rp, *new_rp;
822   int i, r, slot_nr;
823 
824   assert(RUPDATE_IS_UPDATING());
825 
826   if(rs_verbose)
827       printf("RS: %s ending the update: result=%d, reply=%d at %s:%d\n",
828           srv_to_string(rupdate.curr_rpupd->rp), result, (reply_flag==RS_REPLY),
829           file, line);
830 
831   /* If the new instance of RS is active and the update failed, ending
832    * the update couldn't be any easier.
833    */
834   if(result != OK && RUPDATE_IS_RS_INIT_DONE()) {
835       if(rs_verbose)
836           printf("RS: update failed, new RS instance will now exit\n");
837       exit(1);
838   }
839 
840   /* If VM is updated as part of a multi-component live update and something
841    * goes wrong after VM has completed initialization, rollback is only
842    * supported in a best-effort way in unsafe mode. The new VM instance might
843    * have important state changes that won't be reflected in the old version
844    * once we rollback.
845    */
846   if(result != OK && RUPDATE_IS_UPD_VM_MULTI() && RUPDATE_IS_VM_INIT_DONE() && (rupdate.vm_rpupd->lu_flags & SEF_LU_UNSAFE)) {
847       printf("RS: Warning rollbacking in unsafe multi-component update including VM!\n");
848   }
849 
850   /* Handle prepare-only services first: simply cancel the update. */
851   RUPDATE_ITER(rupdate.first_rpupd, prev_rpupd, rpupd,
852       if(UPD_IS_PREPARING_ONLY(rpupd)) {
853           if(!RUPDATE_IS_INITIALIZING()) {
854               request_prepare_update_service(rpupd->rp, SEF_LU_STATE_NULL);
855           }
856           rpupd->rp->r_flags &= ~RS_PREPARE_DONE;
857       }
858   );
859 
860   /* Handle all the other services now, VM always last to support rollback. */
861   end_update_rev_iter(result, reply_flag, rupdate.vm_rpupd, NULL);
862   if(rupdate.vm_rpupd) {
863       end_update_rev_iter(result, reply_flag, NULL, rupdate.vm_rpupd);
864   }
865 
866   /* End the update and complete initialization in case of success. */
867   RUPDATE_ITER(rupdate.first_rpupd, prev_rpupd, rpupd,
868       if(prev_rpupd) {
869           rupdate_upd_clear(prev_rpupd);
870       }
871       if(result == OK && !UPD_IS_PREPARING_ONLY(rpupd)) {
872           /* The rp pointer points to the new instance in this case. */
873           new_rp = rpupd->rp;
874           end_srv_init(new_rp);
875       }
876   );
877   late_reply(rupdate.last_rpupd->rp, result);
878   rupdate_upd_clear(rupdate.last_rpupd);
879   RUPDATE_CLEAR();
880 
881   /* Clear all the old/new endpoints and update flags in the public entries. */
882   for(slot_nr = 0; slot_nr < NR_SYS_PROCS; slot_nr++) {
883       rp = &rproc[slot_nr];
884       rp->r_pub->old_endpoint = NONE;
885       rp->r_pub->new_endpoint = NONE;
886       rp->r_pub->sys_flags &= ~(SF_VM_UPDATE|SF_VM_ROLLBACK|SF_VM_NOMMAP);
887   }
888 }
889 
890 /*===========================================================================*
891 *			      end_srv_update				     *
892  *===========================================================================*/
893 void end_srv_update(struct rprocupd *rpupd, int result, int reply_flag)
894 {
895 /* End the update for the given service. There are two possibilities:
896  * 1) the update succeeded. In that case, cleanup the old version and mark the
897  *    new version as no longer under update.
898  * 2) the update failed. In that case, cleanup the new version and mark the old
899  *    version as no longer under update. Eventual late ready to update
900  *    messages (if any) will simply be ignored and the service can
901  *    continue executing. In addition, reset the check timestamp, so that if the
902  *    service has a period, a status request will be forced in the next period.
903  */
904   struct rproc *old_rp, *new_rp, *exiting_rp, *surviving_rp;
905   struct rproc **rps;
906 
907   struct rprocpub *rpub;
908   int nr_rps, i;
909 
910   old_rp = rpupd->rp;
911   new_rp = old_rp->r_new_rp;
912   assert(old_rp && new_rp);
913   if(result == OK && new_rp->r_pub->endpoint == VM_PROC_NR && RUPDATE_IS_UPD_MULTI()) {
914       /* VM has already been replied to in case of multi-component live update.
915        * Send an update cancel message to trigger cleanup.
916        */
917       reply_flag = RS_CANCEL;
918   }
919 
920   if(rs_verbose)
921       printf("RS: ending update from %s to %s with result=%d, reply=%d\n",
922           srv_to_string(old_rp), srv_to_string(new_rp), result, (reply_flag==RS_REPLY));
923 
924   /* Decide which version has to die out and which version has to survive. */
925   surviving_rp = (result == OK ? new_rp : old_rp);
926   exiting_rp =   (result == OK ? old_rp : new_rp);
927   surviving_rp->r_flags &= ~RS_INITIALIZING;
928   surviving_rp->r_check_tm = 0;
929   getticks(&surviving_rp->r_alive_tm);
930 
931   /* Keep track of the surviving process in the update descriptor from now on. */
932   rpupd->rp = surviving_rp;
933 
934   /* Unlink the two versions. */
935   old_rp->r_new_rp = NULL;
936   new_rp->r_old_rp = NULL;
937 
938   /* Mark the version that has to survive as no longer updating and
939    * reply when asked to.
940    */
941   surviving_rp->r_flags &= ~(RS_UPDATING|RS_PREPARE_DONE|RS_INIT_DONE|RS_INIT_PENDING);
942   if(reply_flag == RS_REPLY) {
943       message m;
944       m.m_type = result;
945       reply(surviving_rp->r_pub->endpoint, surviving_rp, &m);
946   }
947   else if(reply_flag == RS_CANCEL) {
948       if(!(surviving_rp->r_flags & RS_TERMINATED)) {
949           request_prepare_update_service(surviving_rp, SEF_LU_STATE_NULL);
950       }
951   }
952 
953   /* Cleanup or detach the version that has to die out. */
954   get_service_instances(exiting_rp, &rps, &nr_rps);
955   for(i=0;i<nr_rps;i++) {
956       if(rps[i] == old_rp && (rpupd->lu_flags & SEF_LU_DETACHED)) {
957           message m;
958           m.m_type = EDEADEPT;
959           rps[i]->r_flags |= RS_CLEANUP_DETACH;
960           cleanup_service(rps[i]);
961           reply(rps[i]->r_pub->endpoint, rps[i], &m);
962       }
963       else {
964           cleanup_service(rps[i]);
965       }
966   }
967 
968   if(rs_verbose)
969       printf("RS: %s ended the %s\n", srv_to_string(surviving_rp),
970           srv_upd_to_string(rpupd));
971 }
972 
973