etc/services - sync with NetBSD-8
[minix.git] / minix / lib / libsys / sef_liveupdate.c
blob34e19ab45efd5793c67cb8e1306d5eddf82f77e1
1 #include "syslib.h"
2 #include <assert.h>
3 #include <minix/sysutil.h>
4 #include <minix/rs.h>
6 /* SEF Live update variables. */
7 int sef_lu_state;
8 int __sef_st_before_receive_enabled;
9 char sef_lu_state_eval[SEF_LU_STATE_EVAL_MAX_LEN];
10 static int sef_lu_flags;
12 /* SEF Live update callbacks. */
13 static struct sef_lu_cbs {
14 sef_cb_lu_prepare_t sef_cb_lu_prepare;
15 sef_cb_lu_state_isvalid_t sef_cb_lu_state_isvalid;
16 sef_cb_lu_state_changed_t sef_cb_lu_state_changed;
17 sef_cb_lu_state_dump_t sef_cb_lu_state_dump;
18 sef_cb_lu_state_save_t sef_cb_lu_state_save;
19 sef_cb_lu_response_t sef_cb_lu_response;
20 } sef_lu_cbs = {
21 SEF_CB_LU_PREPARE_DEFAULT,
22 SEF_CB_LU_STATE_ISVALID_DEFAULT,
23 SEF_CB_LU_STATE_CHANGED_DEFAULT,
24 SEF_CB_LU_STATE_DUMP_DEFAULT,
25 SEF_CB_LU_STATE_SAVE_DEFAULT,
26 SEF_CB_LU_RESPONSE_DEFAULT
29 /* SEF Live update prototypes for sef_receive(). */
30 void do_sef_lu_before_receive(void);
31 int do_sef_lu_request(message *m_ptr);
33 /* SEF Live update helpers. */
34 static void sef_lu_ready(int result);
35 static void sef_lu_state_change(int state, int flags);
36 int sef_lu_handle_state_data(endpoint_t src_e, int state,
37 cp_grant_id_t state_data_gid);
39 /* Debug. */
40 EXTERN char* sef_debug_header(void);
41 static int sef_lu_debug_cycle = 0;
43 /* Information about SELF. */
44 EXTERN endpoint_t sef_self_endpoint;
46 /*===========================================================================*
47 * do_sef_lu_before_receive *
48 *===========================================================================*/
49 void do_sef_lu_before_receive(void)
51 /* Handle SEF Live update before receive events. */
52 int r;
54 assert(sef_lu_state != SEF_LU_STATE_NULL);
56 /* Debug. */
57 #if SEF_LU_DEBUG
58 sef_lu_debug_cycle++;
59 sef_lu_debug_begin();
60 sef_lu_dprint("%s, cycle=%d. Dumping state variables:\n",
61 sef_debug_header(), sef_lu_debug_cycle);
62 sef_lu_cbs.sef_cb_lu_state_dump(sef_lu_state);
63 sef_lu_debug_end();
64 #endif
66 /* Check the state. For SEF_LU_STATE_WORK_FREE/SEF_LU_STATE_UNREACHABLE,
67 * we are always/never ready. For SEF_LU_STATE_EVAL, evaluate the expression.
68 * For other states, let the callback code handle the event.
70 switch(sef_lu_state) {
71 case SEF_LU_STATE_WORK_FREE:
72 r = OK;
73 break;
74 case SEF_LU_STATE_UNREACHABLE:
75 r = sef_cb_lu_prepare_never_ready(sef_lu_state);
76 break;
77 case SEF_LU_STATE_PREPARE_CRASH:
78 r = sef_cb_lu_prepare_crash(sef_lu_state);
79 break;
80 case SEF_LU_STATE_EVAL:
81 r = sef_cb_lu_prepare_eval(sef_lu_state);
82 break;
83 default:
84 r = sef_lu_cbs.sef_cb_lu_prepare(sef_lu_state);
85 break;
87 if(r == OK || r != ENOTREADY) {
88 sef_lu_ready(r);
92 /*===========================================================================*
93 * do_sef_lu_request *
94 *===========================================================================*/
95 int do_sef_lu_request(message *m_ptr)
97 /* Handle a SEF Live update request. */
98 int r, state, flags, is_valid_state;
99 cp_grant_id_t rs_state_data_gid;
101 sef_lu_debug_cycle = 0;
102 state = m_ptr->m_rs_update.state;
103 flags = m_ptr->m_rs_update.flags;
104 rs_state_data_gid = m_ptr->m_rs_update.state_data_gid;
106 /* Deal with prepare cancel requests first, where no reply is requested. */
107 if(state == SEF_LU_STATE_NULL) {
108 sef_lu_state_change(SEF_LU_STATE_NULL, 0);
109 return OK;
112 /* Check if we are already busy. */
113 if(sef_lu_state != SEF_LU_STATE_NULL) {
114 sef_lu_ready(EBUSY);
115 return OK;
118 /* Otherwise only accept live update requests with a valid state. */
119 is_valid_state = SEF_LU_ALWAYS_ALLOW_DEBUG_STATES && SEF_LU_STATE_IS_DEBUG(state);
120 is_valid_state = is_valid_state || sef_lu_cbs.sef_cb_lu_state_isvalid(state, flags);
121 if(!is_valid_state) {
122 if(sef_lu_cbs.sef_cb_lu_state_isvalid == SEF_CB_LU_STATE_ISVALID_DEFAULT) {
123 sef_lu_ready(ENOSYS);
125 else {
126 sef_lu_ready(EINVAL);
128 return OK;
131 /* Handle additional state data (if any). */
132 r = sef_lu_handle_state_data(m_ptr->m_source, state, rs_state_data_gid);
133 if(r != OK) {
134 sef_lu_ready(r);
135 return OK;
138 /* Set the new live update state. */
139 sef_lu_state_change(state, flags);
142 /* Return OK not to let anybody else intercept the request. */
143 return(OK);
146 /*===========================================================================*
147 * sef_lu_ready *
148 *===========================================================================*/
149 static void sef_lu_ready(int result)
151 message m;
152 int r=EINVAL;
154 #if SEF_LU_DEBUG
155 sef_lu_debug_begin();
156 sef_lu_dprint("%s, cycle=%d. Ready to update with result: %d%s\n",
157 sef_debug_header(), sef_lu_debug_cycle,
158 result, (result == OK ? "(OK)" : ""));
159 sef_lu_debug_end();
160 #endif
162 /* If result is OK, let the callback code cleanup and save
163 * any state that must be carried over to the new version.
165 if(result == OK) {
166 r = sef_llvm_state_cleanup();
167 if(r == OK) {
168 r = sef_lu_cbs.sef_cb_lu_state_save(sef_lu_state, sef_lu_flags);
170 if(r != OK) {
171 /* Abort update in case of error. */
172 result = r;
176 /* Let the callback code produce a live update response and block.
177 * We should get beyond this point only if either result is an error or
178 * something else goes wrong in the callback code.
180 m.m_source = sef_self_endpoint;
181 m.m_type = RS_LU_PREPARE;
182 m.m_rs_update.state = sef_lu_state;
183 m.m_rs_update.result = result;
184 r = sef_lu_cbs.sef_cb_lu_response(&m);
186 #if SEF_LU_DEBUG
187 sef_lu_debug_begin();
188 sef_lu_dprint("%s, cycle=%d. The %s aborted the update with result %d!\n",
189 sef_debug_header(), sef_lu_debug_cycle,
190 (result == OK ? "server" : "client"),
191 (result == OK ? r : result)); /* EINTR if update was canceled. */
192 sef_lu_debug_end();
193 #endif
195 /* Something went wrong. Update was aborted and we didn't get updated.
196 * Restore things back to normal and continue executing.
198 sef_lu_state_change(SEF_LU_STATE_NULL, 0);
200 /* Transfer of asynsend tables during live update is messy at best. The
201 * general idea is that the asynsend table is preserved during live update,
202 * so that messages never get lost. That means that 1) the new instance
203 * takes over the table from the old instance upon live update, and 2) the
204 * old instance takes over the table on rollback. Case 1 is not atomic:
205 * the new instance starts with no asynsend table, and after swapping slots,
206 * the old instance's table will no longer be looked at by the kernel. The
207 * new instance copies over the table from the old instance, and then calls
208 * senda_reload() to tell the kernel about the new location of the otherwise
209 * preserved table. Case 2 is different: the old instance cannot copy the
210 * table from the new instance, and so the kernel does that part, based on
211 * the table provided through the new instance's senda_reload(). However, if
212 * the new instance never got to the senda_reload() call, then the kernel
213 * also would not have been able to deliver any messages, and so the old
214 * instance's table can still be used as is. Now the problem. Because case 1
215 * is not atomic, there is a small window during which other processes may
216 * attempt to receive a message, based on the fact that their s_asyn_pending
217 * mask in the kernel has a bit set for the process being updated. Failing
218 * to find a matching message in the yet-missing table of the new process,
219 * the kernel will unset the s_asyn_pending bit. Now, normally the bit would
220 * be set again through the new instance's senda_reload() call. However, if
221 * the new instance rolls back instead, the old instance will have a message
222 * for the other process, but its s_asyn_pending bit will not be set. Thus,
223 * the message will never be delivered unless we call senda_reload() here.
224 * XXX TODO: the story is even more complicated, because based on the above
225 * story, copying back the table should never be necessary and never happen.
226 * My logs show it does happen for at least RS, which may indicate RS sends
227 * asynchronous messages in its initialization code.. -dcvmoole
229 senda_reload();
232 /*===========================================================================*
233 * sef_lu_state_change *
234 *===========================================================================*/
235 static void sef_lu_state_change(int state, int flags)
237 int r, old_state;
239 old_state = sef_lu_state;
240 sef_lu_state = state;
241 sef_lu_flags = flags;
242 if(sef_lu_state == SEF_LU_STATE_NULL) {
243 r = sys_statectl(SYS_STATE_CLEAR_IPC_FILTERS, 0, 0);
244 if(r != OK)
245 panic("%s:%d: SYS_STATE_CLEAR_IPC_FILTERS failed\n", __func__, __LINE__);
247 if(old_state != sef_lu_state) {
248 sef_lu_cbs.sef_cb_lu_state_changed(old_state, sef_lu_state);
252 /*===========================================================================*
253 * sef_lu_handle_state_data *
254 *===========================================================================*/
255 int sef_lu_handle_state_data(endpoint_t src_e,
256 int state, cp_grant_id_t state_data_gid)
258 int r;
259 struct rs_state_data rs_state_data;
261 if(state_data_gid == GRANT_INVALID) {
262 /* SEF_LU_STATE_EVAL requires an eval expression. */
263 return state == SEF_LU_STATE_EVAL ? EINVAL : OK;
266 r = sys_safecopyfrom(src_e, state_data_gid, 0,
267 (vir_bytes) &rs_state_data, sizeof(rs_state_data));
268 if(r != OK) {
269 return r;
271 if(rs_state_data.size != sizeof(rs_state_data)) {
272 return E2BIG;
274 if(state == SEF_LU_STATE_EVAL) {
275 if(rs_state_data.eval_addr && rs_state_data.eval_len) {
276 if(rs_state_data.eval_len >= SEF_LU_STATE_EVAL_MAX_LEN) {
277 return E2BIG;
279 r = sys_safecopyfrom(src_e, rs_state_data.eval_gid, 0,
280 (vir_bytes) sef_lu_state_eval, rs_state_data.eval_len);
281 if(r != OK) {
282 return r;
284 sef_lu_state_eval[rs_state_data.eval_len] = '\0';
285 r = sef_cb_lu_prepare_eval(SEF_LU_STATE_EVAL);
286 if(r != OK && r != ENOTREADY) {
287 /* State expression could not be evaluated correctly. */
288 return EINVAL;
291 else {
292 /* SEF_LU_STATE_EVAL requires a valid eval expression. */
293 return EINVAL;
296 if(rs_state_data.ipcf_els && rs_state_data.ipcf_els_size) {
297 ipc_filter_el_t ipc_filter[IPCF_MAX_ELEMENTS];
298 size_t ipc_filter_size = sizeof(ipc_filter);
299 int num_ipc_filters = rs_state_data.ipcf_els_size / ipc_filter_size;
300 int i;
301 if(rs_state_data.ipcf_els_size % ipc_filter_size) {
302 return E2BIG;
304 r = OK;
305 for(i=0;i<num_ipc_filters;i++) {
306 int num_elements=0;
307 r = sys_safecopyfrom(src_e, rs_state_data.ipcf_els_gid, i*ipc_filter_size,
308 (vir_bytes) ipc_filter, ipc_filter_size);
309 if(r != OK) {
310 break;
312 #if SEF_LU_DEBUG
313 sef_lu_debug_begin();
314 sef_lu_dprint("%s, Installing ipc filter:\n", sef_debug_header());
315 #endif
316 while(num_elements < IPCF_MAX_ELEMENTS && ipc_filter[num_elements].flags) {
317 #if SEF_LU_DEBUG
318 sef_lu_dprint("el[%d]=(flags=%c%c%c%c, m_source=%d, m_type=%d)",
319 num_elements,
320 (ipc_filter[num_elements].flags & IPCF_MATCH_M_SOURCE) ? 'S' : '-',
321 (ipc_filter[num_elements].flags & IPCF_MATCH_M_TYPE) ? 'T' : '-',
322 (ipc_filter[num_elements].flags & IPCF_EL_BLACKLIST) ? 'B' : '-',
323 (ipc_filter[num_elements].flags & IPCF_EL_WHITELIST) ? 'W' : '-',
324 ipc_filter[num_elements].m_source, ipc_filter[num_elements].m_type);
325 sef_lu_dprint("\n");
326 #endif
327 num_elements++;
329 #if SEF_LU_DEBUG
330 sef_lu_debug_end();
331 #endif
332 if(num_elements == 0) {
333 r = EINVAL;
334 break;
336 r = sys_statectl(ipc_filter[0].flags & IPCF_EL_BLACKLIST ? SYS_STATE_ADD_IPC_BL_FILTER : SYS_STATE_ADD_IPC_WL_FILTER,
337 ipc_filter, num_elements*sizeof(ipc_filter_el_t));
338 if(r != OK) {
339 break;
342 if(r != OK) {
343 sys_statectl(SYS_STATE_CLEAR_IPC_FILTERS, 0, 0);
344 return r;
347 return OK;
350 /*===========================================================================*
351 * sef_setcb_lu_prepare *
352 *===========================================================================*/
353 void sef_setcb_lu_prepare(sef_cb_lu_prepare_t cb)
355 assert(cb != NULL);
356 sef_lu_cbs.sef_cb_lu_prepare = cb;
359 /*===========================================================================*
360 * sef_setcb_lu_state_isvalid *
361 *===========================================================================*/
362 void sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid_t cb)
364 assert(cb != NULL);
365 sef_lu_cbs.sef_cb_lu_state_isvalid = cb;
368 /*===========================================================================*
369 * sef_setcb_lu_state_changed *
370 *===========================================================================*/
371 void sef_setcb_lu_state_changed(sef_cb_lu_state_changed_t cb)
373 assert(cb != NULL);
374 sef_lu_cbs.sef_cb_lu_state_changed = cb;
377 /*===========================================================================*
378 * sef_setcb_lu_state_dump *
379 *===========================================================================*/
380 void sef_setcb_lu_state_dump(sef_cb_lu_state_dump_t cb)
382 assert(cb != NULL);
383 sef_lu_cbs.sef_cb_lu_state_dump = cb;
386 /*===========================================================================*
387 * sef_setcb_lu_state_save *
388 *===========================================================================*/
389 void sef_setcb_lu_state_save(sef_cb_lu_state_save_t cb)
391 assert(cb != NULL);
392 sef_lu_cbs.sef_cb_lu_state_save = cb;
395 /*===========================================================================*
396 * sef_setcb_lu_response *
397 *===========================================================================*/
398 void sef_setcb_lu_response(sef_cb_lu_response_t cb)
400 assert(cb != NULL);
401 sef_lu_cbs.sef_cb_lu_response = cb;
404 /*===========================================================================*
405 * sef_cb_lu_prepare_null *
406 *===========================================================================*/
407 int sef_cb_lu_prepare_null(int UNUSED(state))
409 return ENOTREADY;
412 /*===========================================================================*
413 * sef_cb_lu_state_isvalid_null *
414 *===========================================================================*/
415 int sef_cb_lu_state_isvalid_null(int UNUSED(state), int UNUSED(flags))
417 return FALSE;
420 /*===========================================================================*
421 * sef_cb_lu_state_changed_null *
422 *===========================================================================*/
423 void sef_cb_lu_state_changed_null(int UNUSED(old_state),
424 int UNUSED(state))
428 /*===========================================================================*
429 * sef_cb_lu_state_dump_null *
430 *===========================================================================*/
431 void sef_cb_lu_state_dump_null(int UNUSED(state))
433 sef_lu_dprint("NULL\n");
436 /*===========================================================================*
437 * sef_cb_lu_state_save_null *
438 *===========================================================================*/
439 int sef_cb_lu_state_save_null(int UNUSED(result), int UNUSED(flags))
441 return OK;
444 /*===========================================================================*
445 * sef_cb_lu_response_null *
446 *===========================================================================*/
447 int sef_cb_lu_response_null(message * UNUSED(m_ptr))
449 return ENOSYS;
452 /*===========================================================================*
453 * sef_cb_lu_prepare_always_ready *
454 *===========================================================================*/
455 int sef_cb_lu_prepare_always_ready(int UNUSED(state))
457 return OK;
460 /*===========================================================================*
461 * sef_cb_lu_prepare_never_ready *
462 *===========================================================================*/
463 int sef_cb_lu_prepare_never_ready(int UNUSED(state))
465 #if SEF_LU_DEBUG
466 sef_lu_debug_begin();
467 sef_lu_dprint("%s, cycle=%d. Simulating a service never ready to update...\n",
468 sef_debug_header(), sef_lu_debug_cycle);
469 sef_lu_debug_end();
470 #endif
472 return ENOTREADY;
475 /*===========================================================================*
476 * sef_cb_lu_prepare_crash *
477 *===========================================================================*/
478 int sef_cb_lu_prepare_crash(int UNUSED(state))
480 panic("Simulating a crash at update prepare time...\n");
482 return OK;
485 /*===========================================================================*
486 * sef_cb_lu_prepare_eval *
487 *===========================================================================*/
488 int sef_cb_lu_prepare_eval(int UNUSED(state))
490 char result = 0;
491 int ret = sef_llvm_eval_bool(sef_lu_state_eval, &result);
493 #if SEF_LU_DEBUG
494 sef_lu_debug_begin();
495 sef_lu_dprint("%s, cycle=%d. Evaluated state expression '%s' with error code %d and result %d\n",
496 sef_debug_header(), sef_lu_debug_cycle, sef_lu_state_eval, ret, result);
497 sef_lu_debug_end();
498 #endif
500 if(ret < 0) {
501 return ret == ENOTREADY ? EINTR : ret;
503 return result ? OK : ENOTREADY;
506 /*===========================================================================*
507 * sef_cb_lu_state_isvalid_standard *
508 *===========================================================================*/
509 int sef_cb_lu_state_isvalid_standard(int state, int UNUSED(flags))
511 return SEF_LU_STATE_IS_STANDARD(state);
514 /*===========================================================================*
515 * sef_cb_lu_state_isvalid_workfree *
516 *===========================================================================*/
517 int sef_cb_lu_state_isvalid_workfree(int state, int UNUSED(flags))
519 return (state == SEF_LU_STATE_WORK_FREE);
522 /*===========================================================================*
523 * sef_cb_lu_state_isvalid_workfree_self *
524 *===========================================================================*/
525 int sef_cb_lu_state_isvalid_workfree_self(int state, int flags)
527 return (state == SEF_LU_STATE_WORK_FREE) && (flags & (SEF_LU_SELF|SEF_LU_ASR));
530 /*===========================================================================*
531 * sef_cb_lu_state_isvalid_generic *
532 *===========================================================================*/
533 int sef_cb_lu_state_isvalid_generic(int state, int flags)
535 return (state == SEF_LU_STATE_EVAL) || sef_cb_lu_state_isvalid_workfree(state, flags);
538 /*===========================================================================*
539 * sef_cb_lu_state_dump_eval *
540 *===========================================================================*/
541 void sef_cb_lu_state_dump_eval(int state)
543 if(state == SEF_LU_STATE_EVAL) {
544 sef_llvm_dump_eval(sef_lu_state_eval);
546 else {
547 return sef_cb_lu_state_dump_null(state);
551 /*===========================================================================*
552 * sef_cb_lu_response_rs_reply *
553 *===========================================================================*/
554 int sef_cb_lu_response_rs_reply(message *m_ptr)
556 int r;
558 /* Inform RS that we're ready with the given result. */
559 r = ipc_sendrec(RS_PROC_NR, m_ptr);
560 if ( r != OK) {
561 return r;
564 return m_ptr->m_type == RS_LU_PREPARE ? EINTR : m_ptr->m_type;