1 #include "syslib.h"
2 #include <assert.h>
3 #include <minix/sysutil.h>
4 #include <minix/rs.h>
5
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;
11
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
27 };
28
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);
32
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);
38
39 /* Debug. */
40 EXTERN char* sef_debug_header(void);
41 static int sef_lu_debug_cycle = 0;
42
43 /* Information about SELF. */
44 EXTERN endpoint_t sef_self_endpoint;
45
46 /*===========================================================================*
47 * do_sef_lu_before_receive *
48 *===========================================================================*/
do_sef_lu_before_receive(void)49 void do_sef_lu_before_receive(void)
50 {
51 /* Handle SEF Live update before receive events. */
52 int r;
53
54 assert(sef_lu_state != SEF_LU_STATE_NULL);
55
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
65
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.
69 */
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;
86 }
87 if(r == OK || r != ENOTREADY) {
88 sef_lu_ready(r);
89 }
90 }
91
92 /*===========================================================================*
93 * do_sef_lu_request *
94 *===========================================================================*/
do_sef_lu_request(message * m_ptr)95 int do_sef_lu_request(message *m_ptr)
96 {
97 /* Handle a SEF Live update request. */
98 int r, state, flags, is_valid_state;
99 cp_grant_id_t rs_state_data_gid;
100
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;
105
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;
110 }
111
112 /* Check if we are already busy. */
113 if(sef_lu_state != SEF_LU_STATE_NULL) {
114 sef_lu_ready(EBUSY);
115 return OK;
116 }
117
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);
124 }
125 else {
126 sef_lu_ready(EINVAL);
127 }
128 return OK;
129 }
130
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;
136 }
137
138 /* Set the new live update state. */
139 sef_lu_state_change(state, flags);
140
141
142 /* Return OK not to let anybody else intercept the request. */
143 return(OK);
144 }
145
146 /*===========================================================================*
147 * sef_lu_ready *
148 *===========================================================================*/
sef_lu_ready(int result)149 static void sef_lu_ready(int result)
150 {
151 message m;
152 int r=EINVAL;
153
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
161
162 /* If result is OK, let the callback code cleanup and save
163 * any state that must be carried over to the new version.
164 */
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);
169 }
170 if(r != OK) {
171 /* Abort update in case of error. */
172 result = r;
173 }
174 }
175
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.
179 */
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);
185
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
194
195 /* Something went wrong. Update was aborted and we didn't get updated.
196 * Restore things back to normal and continue executing.
197 */
198 sef_lu_state_change(SEF_LU_STATE_NULL, 0);
199
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
228 */
229 senda_reload();
230 }
231
232 /*===========================================================================*
233 * sef_lu_state_change *
234 *===========================================================================*/
sef_lu_state_change(int state,int flags)235 static void sef_lu_state_change(int state, int flags)
236 {
237 int r, old_state;
238
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__);
246 }
247 if(old_state != sef_lu_state) {
248 sef_lu_cbs.sef_cb_lu_state_changed(old_state, sef_lu_state);
249 }
250 }
251
252 /*===========================================================================*
253 * sef_lu_handle_state_data *
254 *===========================================================================*/
sef_lu_handle_state_data(endpoint_t src_e,int state,cp_grant_id_t state_data_gid)255 int sef_lu_handle_state_data(endpoint_t src_e,
256 int state, cp_grant_id_t state_data_gid)
257 {
258 int r;
259 struct rs_state_data rs_state_data;
260
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;
264 }
265
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;
270 }
271 if(rs_state_data.size != sizeof(rs_state_data)) {
272 return E2BIG;
273 }
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;
278 }
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;
283 }
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;
289 }
290 }
291 else {
292 /* SEF_LU_STATE_EVAL requires a valid eval expression. */
293 return EINVAL;
294 }
295 }
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;
303 }
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;
311 }
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++;
328 }
329 #if SEF_LU_DEBUG
330 sef_lu_debug_end();
331 #endif
332 if(num_elements == 0) {
333 r = EINVAL;
334 break;
335 }
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;
340 }
341 }
342 if(r != OK) {
343 sys_statectl(SYS_STATE_CLEAR_IPC_FILTERS, 0, 0);
344 return r;
345 }
346 }
347 return OK;
348 }
349
350 /*===========================================================================*
351 * sef_setcb_lu_prepare *
352 *===========================================================================*/
sef_setcb_lu_prepare(sef_cb_lu_prepare_t cb)353 void sef_setcb_lu_prepare(sef_cb_lu_prepare_t cb)
354 {
355 assert(cb != NULL);
356 sef_lu_cbs.sef_cb_lu_prepare = cb;
357 }
358
359 /*===========================================================================*
360 * sef_setcb_lu_state_isvalid *
361 *===========================================================================*/
sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid_t cb)362 void sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid_t cb)
363 {
364 assert(cb != NULL);
365 sef_lu_cbs.sef_cb_lu_state_isvalid = cb;
366 }
367
368 /*===========================================================================*
369 * sef_setcb_lu_state_changed *
370 *===========================================================================*/
sef_setcb_lu_state_changed(sef_cb_lu_state_changed_t cb)371 void sef_setcb_lu_state_changed(sef_cb_lu_state_changed_t cb)
372 {
373 assert(cb != NULL);
374 sef_lu_cbs.sef_cb_lu_state_changed = cb;
375 }
376
377 /*===========================================================================*
378 * sef_setcb_lu_state_dump *
379 *===========================================================================*/
sef_setcb_lu_state_dump(sef_cb_lu_state_dump_t cb)380 void sef_setcb_lu_state_dump(sef_cb_lu_state_dump_t cb)
381 {
382 assert(cb != NULL);
383 sef_lu_cbs.sef_cb_lu_state_dump = cb;
384 }
385
386 /*===========================================================================*
387 * sef_setcb_lu_state_save *
388 *===========================================================================*/
sef_setcb_lu_state_save(sef_cb_lu_state_save_t cb)389 void sef_setcb_lu_state_save(sef_cb_lu_state_save_t cb)
390 {
391 assert(cb != NULL);
392 sef_lu_cbs.sef_cb_lu_state_save = cb;
393 }
394
395 /*===========================================================================*
396 * sef_setcb_lu_response *
397 *===========================================================================*/
sef_setcb_lu_response(sef_cb_lu_response_t cb)398 void sef_setcb_lu_response(sef_cb_lu_response_t cb)
399 {
400 assert(cb != NULL);
401 sef_lu_cbs.sef_cb_lu_response = cb;
402 }
403
404 /*===========================================================================*
405 * sef_cb_lu_prepare_null *
406 *===========================================================================*/
sef_cb_lu_prepare_null(int UNUSED (state))407 int sef_cb_lu_prepare_null(int UNUSED(state))
408 {
409 return ENOTREADY;
410 }
411
412 /*===========================================================================*
413 * sef_cb_lu_state_isvalid_null *
414 *===========================================================================*/
sef_cb_lu_state_isvalid_null(int UNUSED (state),int UNUSED (flags))415 int sef_cb_lu_state_isvalid_null(int UNUSED(state), int UNUSED(flags))
416 {
417 return FALSE;
418 }
419
420 /*===========================================================================*
421 * sef_cb_lu_state_changed_null *
422 *===========================================================================*/
sef_cb_lu_state_changed_null(int UNUSED (old_state),int UNUSED (state))423 void sef_cb_lu_state_changed_null(int UNUSED(old_state),
424 int UNUSED(state))
425 {
426 }
427
428 /*===========================================================================*
429 * sef_cb_lu_state_dump_null *
430 *===========================================================================*/
sef_cb_lu_state_dump_null(int UNUSED (state))431 void sef_cb_lu_state_dump_null(int UNUSED(state))
432 {
433 sef_lu_dprint("NULL\n");
434 }
435
436 /*===========================================================================*
437 * sef_cb_lu_state_save_null *
438 *===========================================================================*/
sef_cb_lu_state_save_null(int UNUSED (result),int UNUSED (flags))439 int sef_cb_lu_state_save_null(int UNUSED(result), int UNUSED(flags))
440 {
441 return OK;
442 }
443
444 /*===========================================================================*
445 * sef_cb_lu_response_null *
446 *===========================================================================*/
sef_cb_lu_response_null(message * UNUSED (m_ptr))447 int sef_cb_lu_response_null(message * UNUSED(m_ptr))
448 {
449 return ENOSYS;
450 }
451
452 /*===========================================================================*
453 * sef_cb_lu_prepare_always_ready *
454 *===========================================================================*/
sef_cb_lu_prepare_always_ready(int UNUSED (state))455 int sef_cb_lu_prepare_always_ready(int UNUSED(state))
456 {
457 return OK;
458 }
459
460 /*===========================================================================*
461 * sef_cb_lu_prepare_never_ready *
462 *===========================================================================*/
sef_cb_lu_prepare_never_ready(int UNUSED (state))463 int sef_cb_lu_prepare_never_ready(int UNUSED(state))
464 {
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
471
472 return ENOTREADY;
473 }
474
475 /*===========================================================================*
476 * sef_cb_lu_prepare_crash *
477 *===========================================================================*/
sef_cb_lu_prepare_crash(int UNUSED (state))478 int sef_cb_lu_prepare_crash(int UNUSED(state))
479 {
480 panic("Simulating a crash at update prepare time...\n");
481
482 return OK;
483 }
484
485 /*===========================================================================*
486 * sef_cb_lu_prepare_eval *
487 *===========================================================================*/
sef_cb_lu_prepare_eval(int UNUSED (state))488 int sef_cb_lu_prepare_eval(int UNUSED(state))
489 {
490 char result = 0;
491 int ret = sef_llvm_eval_bool(sef_lu_state_eval, &result);
492
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
499
500 if(ret < 0) {
501 return ret == ENOTREADY ? EINTR : ret;
502 }
503 return result ? OK : ENOTREADY;
504 }
505
506 /*===========================================================================*
507 * sef_cb_lu_state_isvalid_standard *
508 *===========================================================================*/
sef_cb_lu_state_isvalid_standard(int state,int UNUSED (flags))509 int sef_cb_lu_state_isvalid_standard(int state, int UNUSED(flags))
510 {
511 return SEF_LU_STATE_IS_STANDARD(state);
512 }
513
514 /*===========================================================================*
515 * sef_cb_lu_state_isvalid_workfree *
516 *===========================================================================*/
sef_cb_lu_state_isvalid_workfree(int state,int UNUSED (flags))517 int sef_cb_lu_state_isvalid_workfree(int state, int UNUSED(flags))
518 {
519 return (state == SEF_LU_STATE_WORK_FREE);
520 }
521
522 /*===========================================================================*
523 * sef_cb_lu_state_isvalid_workfree_self *
524 *===========================================================================*/
sef_cb_lu_state_isvalid_workfree_self(int state,int flags)525 int sef_cb_lu_state_isvalid_workfree_self(int state, int flags)
526 {
527 return (state == SEF_LU_STATE_WORK_FREE) && (flags & (SEF_LU_SELF|SEF_LU_ASR));
528 }
529
530 /*===========================================================================*
531 * sef_cb_lu_state_isvalid_generic *
532 *===========================================================================*/
sef_cb_lu_state_isvalid_generic(int state,int flags)533 int sef_cb_lu_state_isvalid_generic(int state, int flags)
534 {
535 return (state == SEF_LU_STATE_EVAL) || sef_cb_lu_state_isvalid_workfree(state, flags);
536 }
537
538 /*===========================================================================*
539 * sef_cb_lu_state_dump_eval *
540 *===========================================================================*/
sef_cb_lu_state_dump_eval(int state)541 void sef_cb_lu_state_dump_eval(int state)
542 {
543 if(state == SEF_LU_STATE_EVAL) {
544 sef_llvm_dump_eval(sef_lu_state_eval);
545 }
546 else {
547 return sef_cb_lu_state_dump_null(state);
548 }
549 }
550
551 /*===========================================================================*
552 * sef_cb_lu_response_rs_reply *
553 *===========================================================================*/
sef_cb_lu_response_rs_reply(message * m_ptr)554 int sef_cb_lu_response_rs_reply(message *m_ptr)
555 {
556 int r;
557
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;
562 }
563
564 return m_ptr->m_type == RS_LU_PREPARE ? EINTR : m_ptr->m_type;
565 }
566
567