xref: /minix3/minix/servers/rs/utility.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1 /* This file contains some utility routines for RS.
2  *
3  * Changes:
4  *   Nov 22, 2009: Created    (Cristiano Giuffrida)
5  */
6 
7 #include "inc.h"
8 
9 #include <assert.h>
10 #include <minix/sched.h>
11 #include "kernel/proc.h"
12 
13 #define PRINT_SEP() printf("---------------------------------------------------------------------------------\n")
14 
15 /*===========================================================================*
16  *				 init_service				     *
17  *===========================================================================*/
init_service(struct rproc * rp,int type,int flags)18 int init_service(struct rproc *rp, int type, int flags)
19 {
20   int r, prepare_state;
21   message m;
22   endpoint_t old_endpoint;
23 
24   rp->r_flags |= RS_INITIALIZING;              /* now initializing */
25   rp->r_alive_tm = getticks();
26   rp->r_check_tm = rp->r_alive_tm + 1;         /* expect reply within period */
27 
28   /* In case of RS initialization, we are done. */
29   if(rp->r_priv.s_flags & ROOT_SYS_PROC) {
30       return OK;
31   }
32 
33   /* Determine the old endpoint if this is a new instance. */
34   old_endpoint = NONE;
35   prepare_state = SEF_LU_STATE_NULL;
36   if(rp->r_old_rp) {
37       old_endpoint = rp->r_upd.state_endpoint;
38       prepare_state = rp->r_upd.prepare_state;
39   }
40   else if(rp->r_prev_rp) {
41       old_endpoint = rp->r_prev_rp->r_pub->endpoint;
42   }
43 
44   /* Check flags. */
45   if(rp->r_pub->sys_flags & SF_USE_SCRIPT) {
46       flags |= SEF_INIT_SCRIPT_RESTART;
47   }
48 
49   /* Send initialization message. */
50   m.m_type = RS_INIT;
51   m.m_rs_init.type = (short) type;
52   m.m_rs_init.flags = flags;
53   m.m_rs_init.rproctab_gid = rinit.rproctab_gid;
54   m.m_rs_init.old_endpoint = old_endpoint;
55   m.m_rs_init.restarts = (short) rp->r_restarts+1;
56   m.m_rs_init.buff_addr = rp->r_map_prealloc_addr;
57   m.m_rs_init.buff_len  = rp->r_map_prealloc_len;
58   m.m_rs_init.prepare_state = prepare_state;
59   rp->r_map_prealloc_addr = 0;
60   rp->r_map_prealloc_len = 0;
61   r = rs_asynsend(rp, &m, 0);
62 
63   return r;
64 }
65 
66 /*===========================================================================*
67  *				 fi_service				     *
68  *===========================================================================*/
fi_service(struct rproc * rp)69 int fi_service(struct rproc *rp)
70 {
71   message m;
72 
73   /* Send fault injection message. */
74   m.m_type = COMMON_REQ_FI_CTL;
75   m.m_lsys_fi_ctl.subtype = RS_FI_CRASH;
76   return rs_asynsend(rp, &m, 0);
77 }
78 
79 /*===========================================================================*
80  *			      fill_send_mask                                 *
81  *===========================================================================*/
fill_send_mask(send_mask,set_bits)82 void fill_send_mask(send_mask, set_bits)
83 sys_map_t *send_mask;		/* the send mask to fill in */
84 int set_bits;			/* TRUE sets all bits, FALSE clears all bits */
85 {
86 /* Fill in a send mask. */
87   int i;
88 
89   for (i = 0; i < NR_SYS_PROCS; i++) {
90 	if (set_bits)
91 		set_sys_bit(*send_mask, i);
92 	else
93 		unset_sys_bit(*send_mask, i);
94   }
95 }
96 
97 /*===========================================================================*
98  *			      fill_call_mask                                 *
99  *===========================================================================*/
fill_call_mask(calls,tot_nr_calls,call_mask,call_base,is_init)100 void fill_call_mask(calls, tot_nr_calls, call_mask, call_base, is_init)
101 int *calls;                     /* the unordered set of calls */
102 int tot_nr_calls;               /* the total number of calls */
103 bitchunk_t *call_mask;          /* the call mask to fill in */
104 int call_base;                  /* the base offset for the calls */
105 int is_init;                    /* set when initializing a call mask */
106 {
107 /* Fill a call mask from an unordered set of calls. */
108   int i;
109   int call_mask_size, nr_calls;
110 
111   call_mask_size = BITMAP_CHUNKS(tot_nr_calls);
112 
113   /* Count the number of calls to fill in. */
114   nr_calls = 0;
115   for(i=0; calls[i] != NULL_C; i++) {
116       nr_calls++;
117   }
118 
119   /* See if all calls are allowed and call mask must be completely filled. */
120   if(nr_calls == 1 && calls[0] == ALL_C) {
121       for(i=0; i < call_mask_size; i++) {
122           call_mask[i] = (~0);
123       }
124   }
125   else {
126       /* When initializing, reset the mask first. */
127       if(is_init) {
128           for(i=0; i < call_mask_size; i++) {
129               call_mask[i] = 0;
130           }
131       }
132       /* Enter calls bit by bit. */
133       for(i=0; i < nr_calls; i++) {
134           SET_BIT(call_mask, calls[i] - call_base);
135       }
136   }
137 }
138 
139 /*===========================================================================*
140  *			     srv_to_string_gen				     *
141  *===========================================================================*/
srv_to_string_gen(struct rproc * rp,int is_verbose)142 char* srv_to_string_gen(struct rproc *rp, int is_verbose)
143 {
144   struct rprocpub *rpub;
145   int slot_nr;
146   char *srv_string;
147 /* LSC: Workaround broken GCC which complains that a const variable is not constant... */
148 #define max_len (RS_MAX_LABEL_LEN + 256)
149   static char srv_string_pool[3][max_len];
150   static int srv_string_pool_index = 0;
151 
152   rpub = rp->r_pub;
153   slot_nr = rp - rproc;
154   srv_string = srv_string_pool[srv_string_pool_index];
155   srv_string_pool_index = (srv_string_pool_index + 1) % 3;
156 
157 #define srv_str(cmd) ((cmd) == NULL || (cmd)[0] == '\0' ? "_" : (cmd))
158 #define srv_active_str(rp) ((rp)->r_flags & RS_ACTIVE ? "*" : " ")
159 #define srv_version_str(rp) ((rp)->r_new_rp || (rp)->r_next_rp ? "-" : \
160     ((rp)->r_old_rp || (rp)->r_prev_rp ? "+" : " "))
161 
162   if(is_verbose) {
163       snprintf(srv_string, max_len, "service '%s'%s%s"
164 		"(slot %d, ep %d, pid %d, cmd %s,"
165 		" script %s, proc %s, major %d,"
166 		" flags 0x%03x, sys_flags 0x%02x)",
167 		rpub->label, srv_active_str(rp), srv_version_str(rp),
168 		slot_nr, rpub->endpoint, rp->r_pid, srv_str(rp->r_cmd),
169 		srv_str(rp->r_script), srv_str(rpub->proc_name), rpub->dev_nr,
170 		rp->r_flags, rpub->sys_flags);
171   }
172   else {
173       snprintf(srv_string, max_len, "service '%s'%s%s(slot %d, ep %d, pid %d)",
174           rpub->label, srv_active_str(rp), srv_version_str(rp),
175           slot_nr, rpub->endpoint, rp->r_pid);
176   }
177 
178 #undef srv_str
179 #undef srv_active_str
180 #undef srv_version_str
181 #undef max_len
182 
183   return srv_string;
184 }
185 
186 /*===========================================================================*
187  *			     srv_upd_to_string				     *
188  *===========================================================================*/
srv_upd_to_string(struct rprocupd * rpupd)189 char* srv_upd_to_string(struct rprocupd *rpupd)
190 {
191    static char srv_upd_string[256];
192    struct rprocpub *rpub, *next_rpub, *prev_rpub;
193    rpub = rpupd->rp ? rpupd->rp->r_pub : NULL;
194    next_rpub = rpupd->next_rpupd && rpupd->next_rpupd->rp ? rpupd->next_rpupd->rp->r_pub : NULL;
195    prev_rpub = rpupd->prev_rpupd && rpupd->prev_rpupd->rp ? rpupd->prev_rpupd->rp->r_pub : NULL;
196 
197 #define srv_ep(RPUB) (RPUB ? (RPUB)->endpoint : -1)
198 #define srv_upd_luflag_c(F) (rpupd->lu_flags & F ? '1' : '0')
199 #define srv_upd_iflag_c(F) (rpupd->init_flags & F ? '1' : '0')
200 
201    snprintf(srv_upd_string, sizeof(srv_upd_string), "update (lu_flags(SAMPNDRV)="
202 		"%c%c%c%c%c%c%c%c,"
203 		" init_flags=(FCTD)=%c%c%c%c, state %d (%s),"
204 		" tm %u, maxtime %u, endpoint %d,"
205 		" state_data_gid %d, prev_ep %d, next_ep %d)",
206 		srv_upd_luflag_c(SEF_LU_SELF), srv_upd_luflag_c(SEF_LU_ASR),
207 		srv_upd_luflag_c(SEF_LU_MULTI), srv_upd_luflag_c(SEF_LU_PREPARE_ONLY),
208 		srv_upd_luflag_c(SEF_LU_NOMMAP), srv_upd_luflag_c(SEF_LU_DETACHED),
209 		srv_upd_luflag_c(SEF_LU_INCLUDES_RS),
210 		srv_upd_luflag_c(SEF_LU_INCLUDES_VM), srv_upd_iflag_c(SEF_INIT_FAIL),
211 		srv_upd_iflag_c(SEF_INIT_CRASH), srv_upd_iflag_c(SEF_INIT_TIMEOUT),
212 		srv_upd_iflag_c(SEF_INIT_DEFCB), rpupd->prepare_state,
213 		rpupd->prepare_state_data.eval_addr ? rpupd->prepare_state_data.eval_addr : "",
214 		rpupd->prepare_tm, rpupd->prepare_maxtime, srv_ep(rpub),
215 		rpupd->prepare_state_data_gid, srv_ep(prev_rpub), srv_ep(next_rpub));
216 
217    return srv_upd_string;
218 }
219 
220 /*===========================================================================*
221  *			     rs_asynsend				     *
222  *===========================================================================*/
rs_asynsend(struct rproc * rp,message * m_ptr,int no_reply)223 int rs_asynsend(struct rproc *rp, message *m_ptr, int no_reply)
224 {
225   struct rprocpub *rpub;
226   int r;
227 
228   rpub = rp->r_pub;
229 
230   if(no_reply) {
231       r = asynsend3(rpub->endpoint, m_ptr, AMF_NOREPLY);
232   }
233   else {
234       r = asynsend(rpub->endpoint, m_ptr);
235   }
236 
237   if(rs_verbose)
238       printf("RS: %s being asynsent to with message type %d, noreply=%d, result=%d\n",
239           srv_to_string(rp), m_ptr->m_type, no_reply, r);
240 
241   return r;
242 }
243 
244 /*===========================================================================*
245  *			     rs_receive_ticks				     *
246  *===========================================================================*/
rs_receive_ticks(endpoint_t src,message * m_ptr,int * status_ptr,clock_t ticks)247 int rs_receive_ticks(endpoint_t src, message *m_ptr,
248     int *status_ptr, clock_t ticks)
249 {
250 /* IPC receive with timeout.  Implemented with IPC filters.  The timer
251  * management logic comes from the tickdelay(3) implementation.
252  */
253   ipc_filter_el_t ipc_filter[2];
254   clock_t time_left, uptime;
255   int r, s, status;
256 
257   /* Use IPC filters to receive from the provided source and CLOCK only.
258    * We make the hard assumption that RS did not already have IPC filters set.
259    */
260   memset(ipc_filter, 0, sizeof(ipc_filter));
261   ipc_filter[0].flags = IPCF_MATCH_M_SOURCE;
262   ipc_filter[0].m_source = CLOCK;
263   ipc_filter[1].flags = IPCF_MATCH_M_SOURCE;
264   ipc_filter[1].m_source = src;
265 
266   if ((s = sys_statectl(SYS_STATE_ADD_IPC_WL_FILTER, ipc_filter,
267     sizeof(ipc_filter))) != OK)
268       panic("RS: rs_receive_ticks: setting IPC filter failed: %d", s);
269 
270   /* Set a new alarm, and get information about the previous alarm. */
271   if ((s = sys_setalarm2(ticks, FALSE, &time_left, &uptime)) != OK)
272       panic("RS: rs_receive_ticks: setting alarm failed: %d", s);
273 
274   /* Receive a message from either the provided source or CLOCK. */
275   while ((r = ipc_receive(ANY, m_ptr, &status)) == OK &&
276     m_ptr->m_source == CLOCK) {
277       /* Ignore early clock notifications. */
278       if (m_ptr->m_type == NOTIFY_MESSAGE &&
279         m_ptr->m_notify.timestamp >= uptime + ticks)
280           break;
281   }
282 
283   /* Reinstate the previous alarm, if any. Do this in any case. */
284   if (time_left != TMR_NEVER) {
285       if (time_left > ticks)
286           time_left -= ticks;
287       else
288           time_left = 1; /* force an alarm */
289 
290       (void)sys_setalarm(time_left, FALSE);
291   }
292 
293   /* Clear the IPC filters. */
294   if ((s = sys_statectl(SYS_STATE_CLEAR_IPC_FILTERS, NULL, 0)) != OK)
295       panic("RS: rs_receive_ticks: setting IPC filter failed: %d", s);
296 
297   /* If the last received message was from CLOCK, we timed out. */
298   if (r == OK && m_ptr->m_source == CLOCK)
299       return ENOTREADY;
300 
301   if (status_ptr != NULL)
302       *status_ptr = status;
303   return r;
304 }
305 
306 /*===========================================================================*
307  *				reply					     *
308  *===========================================================================*/
reply(who,rp,m_ptr)309 void reply(who, rp, m_ptr)
310 endpoint_t who;                        	/* replyee */
311 struct rproc *rp;                       /* replyee slot (if any) */
312 message *m_ptr;                         /* reply message */
313 {
314   int r;				/* send status */
315 
316   /* No need to actually reply to RS */
317   if(who == RS_PROC_NR) {
318       return;
319   }
320 
321   if(rs_verbose && rp)
322       printf("RS: %s being replied to with message type %d\n", srv_to_string(rp), m_ptr->m_type);
323 
324   r = ipc_sendnb(who, m_ptr);		/* send the message */
325   if (r != OK)
326       printf("RS: unable to send reply to %d: %d\n", who, r);
327 }
328 
329 /*===========================================================================*
330  *			      late_reply				     *
331  *===========================================================================*/
late_reply(rp,code)332 void late_reply(rp, code)
333 struct rproc *rp;				/* pointer to process slot */
334 int code;					/* status code */
335 {
336 /* If a caller is waiting for a reply, unblock it. */
337   if(rp->r_flags & RS_LATEREPLY) {
338       message m;
339       m.m_type = code;
340       if(rs_verbose)
341           printf("RS: %s late reply %d to %d for request %d\n",
342               srv_to_string(rp), code, rp->r_caller, rp->r_caller_request);
343 
344       reply(rp->r_caller, NULL, &m);
345       rp->r_flags &= ~RS_LATEREPLY;
346   }
347 }
348 
349 /*===========================================================================*
350  *				rs_isokendpt			 	     *
351  *===========================================================================*/
rs_isokendpt(endpoint_t endpoint,int * proc)352 int rs_isokendpt(endpoint_t endpoint, int *proc)
353 {
354 	*proc = _ENDPOINT_P(endpoint);
355 	if(*proc < -NR_TASKS || *proc >= NR_PROCS)
356 		return EINVAL;
357 
358 	return OK;
359 }
360 
361 /*===========================================================================*
362  *				sched_init_proc			 	     *
363  *===========================================================================*/
sched_init_proc(struct rproc * rp)364 int sched_init_proc(struct rproc *rp)
365 {
366   int s;
367   int is_usr_proc;
368 
369   /* Make sure user processes have no scheduler. PM deals with them. */
370   is_usr_proc = !(rp->r_priv.s_flags & SYS_PROC);
371   if(is_usr_proc) assert(rp->r_scheduler == NONE);
372   if(!is_usr_proc) assert(rp->r_scheduler != NONE);
373 
374   /* Start scheduling for the given process. */
375   if ((s = sched_start(rp->r_scheduler, rp->r_pub->endpoint,
376       RS_PROC_NR, rp->r_priority, rp->r_quantum, rp->r_cpu,
377       &rp->r_scheduler)) != OK) {
378       return s;
379   }
380 
381   return s;
382 }
383 
384 /*===========================================================================*
385  *				update_sig_mgrs			 	     *
386  *===========================================================================*/
update_sig_mgrs(struct rproc * rp,endpoint_t sig_mgr,endpoint_t bak_sig_mgr)387 int update_sig_mgrs(struct rproc *rp, endpoint_t sig_mgr,
388 	endpoint_t bak_sig_mgr)
389 {
390   int r;
391   struct rprocpub *rpub;
392 
393   rpub = rp->r_pub;
394 
395   if(rs_verbose)
396       printf("RS: %s updates signal managers: %d%s / %d\n", srv_to_string(rp),
397           sig_mgr == SELF ? rpub->endpoint : sig_mgr,
398           sig_mgr == SELF ? "(SELF)" : "",
399           bak_sig_mgr == NONE ? -1 : bak_sig_mgr);
400 
401   /* Synch privilege structure with the kernel. */
402   if ((r = sys_getpriv(&rp->r_priv, rpub->endpoint)) != OK) {
403       printf("unable to synch privilege structure: %d", r);
404       return r;
405   }
406 
407   /* Set signal managers. */
408   rp->r_priv.s_sig_mgr = sig_mgr;
409   rp->r_priv.s_bak_sig_mgr = bak_sig_mgr;
410 
411   /* Update privilege structure. */
412   r = sys_privctl(rpub->endpoint, SYS_PRIV_UPDATE_SYS, &rp->r_priv);
413   if(r != OK) {
414       printf("unable to update privilege structure: %d", r);
415       return r;
416   }
417 
418   return OK;
419 }
420 
421 /*===========================================================================*
422  *				rs_is_idle			 	     *
423  *===========================================================================*/
rs_is_idle()424 int rs_is_idle()
425 {
426   int slot_nr;
427   struct rproc *rp;
428   for (slot_nr = 0; slot_nr < NR_SYS_PROCS; slot_nr++) {
429       rp = &rproc[slot_nr];
430       if (!(rp->r_flags & RS_IN_USE)) {
431           continue;
432       }
433       if(!RS_SRV_IS_IDLE(rp)) {
434           return 0;
435       }
436   }
437   return 1;
438 }
439 
440 /*===========================================================================*
441  *				rs_idle_period				     *
442  *===========================================================================*/
rs_idle_period()443 void rs_idle_period()
444 {
445   struct rproc *rp;
446   struct rprocpub *rpub;
447   int r;
448 
449   /* Not much to do when RS is not idle. */
450   /* However, to avoid deadlocks it is absolutely necessary that during system
451    * shutdown, dead services are actually cleaned up. Override the idle check.
452    */
453   if(!shutting_down && !rs_is_idle()) {
454       return;
455   }
456 
457   /* Cleanup dead services. */
458   for (rp=BEG_RPROC_ADDR; rp<END_RPROC_ADDR; rp++) {
459       if((rp->r_flags & (RS_IN_USE|RS_DEAD)) == (RS_IN_USE|RS_DEAD)) {
460           cleanup_service(rp);
461       }
462   }
463 
464   if (shutting_down) return;
465 
466   /* Create missing replicas when necessary. */
467   for (rp=BEG_RPROC_ADDR; rp<END_RPROC_ADDR; rp++) {
468       rpub = rp->r_pub;
469       if((rp->r_flags & RS_ACTIVE) && (rpub->sys_flags & SF_USE_REPL) && rp->r_next_rp == NULL) {
470           if(rpub->endpoint == VM_PROC_NR && (rp->r_old_rp || rp->r_new_rp)) {
471               /* Only one replica at the time for VM. */
472               continue;
473           }
474           if ((r = clone_service(rp, RST_SYS_PROC, 0)) != OK) {
475               printf("RS: warning: unable to clone %s (error %d)\n",
476                   srv_to_string(rp), r);
477           }
478       }
479   }
480 }
481 
482 /*===========================================================================*
483  *			   print_services_status		 	     *
484  *===========================================================================*/
print_services_status()485 void print_services_status()
486 {
487   int slot_nr;
488   struct rproc *rp;
489   int num_services = 0;
490   int num_service_instances = 0;
491   int is_verbose = 1;
492 
493   PRINT_SEP();
494   printf("Printing information about all the system service instances:\n");
495   PRINT_SEP();
496   for (slot_nr = 0; slot_nr < NR_SYS_PROCS; slot_nr++) {
497       rp = &rproc[slot_nr];
498       if (!(rp->r_flags & RS_IN_USE)) {
499           continue;
500       }
501       if (rp->r_flags & RS_ACTIVE) {
502           num_services++;
503       }
504       num_service_instances++;
505       printf("%s\n", srv_to_string_gen(rp, is_verbose));
506   }
507   PRINT_SEP();
508   printf("Found %d service instances, of which %d are active services\n",
509   	  num_service_instances, num_services);
510   PRINT_SEP();
511 }
512 
513 /*===========================================================================*
514  *			    print_update_status 		 	     *
515  *===========================================================================*/
print_update_status()516 void print_update_status()
517 {
518   struct rprocupd *prev_rpupd, *rpupd;
519   int is_updating = RUPDATE_IS_UPDATING();
520   int i;
521 
522 #define rupdate_flag_c(F) (rupdate.flags & F ? '1' : '0')
523 
524   if(!is_updating && !RUPDATE_IS_UPD_SCHEDULED()) {
525       PRINT_SEP();
526       printf("No update is in progress or scheduled\n");
527       PRINT_SEP();
528       return;
529   }
530 
531   PRINT_SEP();
532   i = 1;
533   printf("A %s-component update is %s, flags(UIRV)=%c%c%c%c:\n", RUPDATE_IS_UPD_MULTI() ? "multi" : "single",
534       is_updating ? "in progress" : "scheduled",
535       rupdate_flag_c(RS_UPDATING), rupdate_flag_c(RS_INITIALIZING),
536       rupdate.rs_rpupd ? '1' : '0', rupdate.vm_rpupd ? '1' : '0');
537   PRINT_SEP();
538   RUPDATE_ITER(rupdate.first_rpupd, prev_rpupd, rpupd,
539       printf("%d. %s %s %s\n", i++, srv_to_string(rpupd->rp),
540           is_updating ? "updating with" : "scheduled for",
541           srv_upd_to_string(rpupd));
542   );
543   PRINT_SEP();
544 
545 #undef rupdate_flag_c
546 }
547 
548