vm: util.S not used currently; leave it out.
[minix.git] / servers / rs / request.c
blobcfe696acf671557bc272687aeb06a9ba3cbf2569
1 /*
2 * Changes:
3 * Jan 22, 2010: Created (Cristiano Giuffrida)
4 */
6 #include "inc.h"
8 /*===========================================================================*
9 * do_up *
10 *===========================================================================*/
11 PUBLIC int do_up(m_ptr)
12 message *m_ptr; /* request message pointer */
14 /* A request was made to start a new system service. */
15 struct rproc *rp;
16 struct rprocpub *rpub;
17 int r;
18 struct rs_start rs_start;
19 int noblock;
21 /* Check if the call can be allowed. */
22 if((r = check_call_permission(m_ptr->m_source, RS_UP, NULL)) != OK)
23 return r;
25 /* Allocate a new system service slot. */
26 r = alloc_slot(&rp);
27 if(r != OK) {
28 printf("RS: do_up: unable to allocate a new slot: %d\n", r);
29 return r;
31 rpub = rp->r_pub;
33 /* Copy the request structure. */
34 r = copy_rs_start(m_ptr->m_source, m_ptr->RS_CMD_ADDR, &rs_start);
35 if (r != OK) {
36 return r;
38 noblock = (rs_start.rss_flags & RSS_NOBLOCK);
40 /* Initialize the slot as requested. */
41 r = init_slot(rp, &rs_start, m_ptr->m_source);
42 if(r != OK) {
43 printf("RS: do_up: unable to init the new slot: %d\n", r);
44 return r;
47 /* Check for duplicates */
48 if(lookup_slot_by_label(rpub->label)) {
49 printf("RS: service with the same label '%s' already exists\n",
50 rpub->label);
51 return EBUSY;
53 if(rpub->dev_nr>0 && lookup_slot_by_dev_nr(rpub->dev_nr)) {
54 printf("RS: service with the same device number %d already exists\n",
55 rpub->dev_nr);
56 return EBUSY;
59 /* All information was gathered. Now try to start the system service. */
60 r = start_service(rp);
61 activate_service(rp, NULL);
62 if(r != OK) {
63 return r;
66 /* Unblock the caller immediately if requested. */
67 if(noblock) {
68 return OK;
71 /* Late reply - send a reply when service completes initialization. */
72 rp->r_flags |= RS_LATEREPLY;
73 rp->r_caller = m_ptr->m_source;
74 rp->r_caller_request = RS_UP;
76 return EDONTREPLY;
79 /*===========================================================================*
80 * do_down *
81 *===========================================================================*/
82 PUBLIC int do_down(message *m_ptr)
84 register struct rproc *rp;
85 register struct rprocpub *rpub;
86 int s;
87 char label[RS_MAX_LABEL_LEN];
89 /* Copy label. */
90 s = copy_label(m_ptr->m_source, m_ptr->RS_CMD_ADDR,
91 m_ptr->RS_CMD_LEN, label, sizeof(label));
92 if(s != OK) {
93 return s;
96 /* Lookup slot by label. */
97 rp = lookup_slot_by_label(label);
98 if(!rp) {
99 if(rs_verbose)
100 printf("RS: do_down: service '%s' not found\n", label);
101 return(ESRCH);
103 rpub = rp->r_pub;
105 /* Check if the call can be allowed. */
106 if((s = check_call_permission(m_ptr->m_source, RS_DOWN, rp)) != OK)
107 return s;
109 /* Stop service. */
110 if (rp->r_flags & RS_TERMINATED) {
111 /* A recovery script is requesting us to bring down the service.
112 * The service is already gone, simply perform cleanup.
114 if(rs_verbose)
115 printf("RS: recovery script performs service down...\n");
116 unpublish_service(rp);
117 unpublish_process(rp);
118 cleanup_service(rp);
119 return(OK);
121 stop_service(rp,RS_EXITING);
123 /* Late reply - send a reply when service dies. */
124 rp->r_flags |= RS_LATEREPLY;
125 rp->r_caller = m_ptr->m_source;
126 rp->r_caller_request = RS_DOWN;
128 return EDONTREPLY;
131 /*===========================================================================*
132 * do_restart *
133 *===========================================================================*/
134 PUBLIC int do_restart(message *m_ptr)
136 struct rproc *rp;
137 int s, r;
138 char label[RS_MAX_LABEL_LEN];
139 char script[MAX_SCRIPT_LEN];
141 /* Copy label. */
142 s = copy_label(m_ptr->m_source, m_ptr->RS_CMD_ADDR,
143 m_ptr->RS_CMD_LEN, label, sizeof(label));
144 if(s != OK) {
145 return s;
148 /* Lookup slot by label. */
149 rp = lookup_slot_by_label(label);
150 if(!rp) {
151 if(rs_verbose)
152 printf("RS: do_restart: service '%s' not found\n", label);
153 return(ESRCH);
156 /* Check if the call can be allowed. */
157 if((r = check_call_permission(m_ptr->m_source, RS_RESTART, rp)) != OK)
158 return r;
160 /* We can only be asked to restart a service from a recovery script. */
161 if (! (rp->r_flags & RS_TERMINATED) ) {
162 if(rs_verbose)
163 printf("RS: %s is still running\n", srv_to_string(rp));
164 return EBUSY;
167 if(rs_verbose)
168 printf("RS: recovery script performs service restart...\n");
170 /* Restart the service, but make sure we don't call the script again. */
171 strcpy(script, rp->r_script);
172 rp->r_script[0] = '\0';
173 restart_service(rp);
174 strcpy(rp->r_script, script);
176 return OK;
180 /*===========================================================================*
181 * do_refresh *
182 *===========================================================================*/
183 PUBLIC int do_refresh(message *m_ptr)
185 register struct rproc *rp;
186 register struct rprocpub *rpub;
187 int s;
188 char label[RS_MAX_LABEL_LEN];
190 /* Copy label. */
191 s = copy_label(m_ptr->m_source, m_ptr->RS_CMD_ADDR,
192 m_ptr->RS_CMD_LEN, label, sizeof(label));
193 if(s != OK) {
194 return s;
197 /* Lookup slot by label. */
198 rp = lookup_slot_by_label(label);
199 if(!rp) {
200 if(rs_verbose)
201 printf("RS: do_refresh: service '%s' not found\n", label);
202 return(ESRCH);
204 rpub = rp->r_pub;
206 /* Check if the call can be allowed. */
207 if((s = check_call_permission(m_ptr->m_source, RS_REFRESH, rp)) != OK)
208 return s;
210 /* Refresh service. */
211 if(rs_verbose)
212 printf("RS: %s refreshing\n", srv_to_string(rp));
213 stop_service(rp,RS_REFRESHING);
215 return OK;
218 /*===========================================================================*
219 * do_shutdown *
220 *===========================================================================*/
221 PUBLIC int do_shutdown(message *m_ptr)
223 int slot_nr;
224 struct rproc *rp;
225 int r;
227 /* Check if the call can be allowed. */
228 if (m_ptr != NULL) {
229 if((r = check_call_permission(m_ptr->m_source, RS_SHUTDOWN, NULL)) != OK)
230 return r;
233 if(rs_verbose)
234 printf("RS: shutting down...\n");
236 /* Set flag to tell RS we are shutting down. */
237 shutting_down = TRUE;
239 /* Don't restart dead services. */
240 for (slot_nr = 0; slot_nr < NR_SYS_PROCS; slot_nr++) {
241 rp = &rproc[slot_nr];
242 if (rp->r_flags & RS_IN_USE) {
243 rp->r_flags |= RS_EXITING;
246 return(OK);
249 /*===========================================================================*
250 * do_init_ready *
251 *===========================================================================*/
252 PUBLIC int do_init_ready(message *m_ptr)
254 int who_p;
255 struct rproc *rp;
256 struct rprocpub *rpub;
257 int result;
259 who_p = _ENDPOINT_P(m_ptr->m_source);
260 rp = rproc_ptr[who_p];
261 rpub = rp->r_pub;
262 result = m_ptr->RS_INIT_RESULT;
264 /* Make sure the originating service was requested to initialize. */
265 if(! (rp->r_flags & RS_INITIALIZING) ) {
266 if(rs_verbose)
267 printf("RS: do_init_ready: got unexpected init ready msg from %d\n",
268 m_ptr->m_source);
269 return(EDONTREPLY);
272 /* Check if something went wrong and the service failed to init.
273 * In that case, kill the service.
275 if(result != OK) {
276 if(rs_verbose)
277 printf("RS: %s initialization error: %s\n", srv_to_string(rp),
278 init_strerror(result));
279 crash_service(rp); /* simulate crash */
280 return(EDONTREPLY);
283 /* Mark the slot as no longer initializing. */
284 rp->r_flags &= ~RS_INITIALIZING;
285 rp->r_check_tm = 0;
286 getuptime(&rp->r_alive_tm);
288 /* See if a late reply has to be sent. */
289 late_reply(rp, OK);
291 if(rs_verbose)
292 printf("RS: %s initialized\n", srv_to_string(rp));
294 /* If the service has completed initialization after a live
295 * update, end the update now.
297 if(rp->r_flags & RS_UPDATING) {
298 printf("RS: update succeeded\n");
299 end_update(OK);
302 /* If the service has completed initialization after a crash
303 * make the new instance active and cleanup the old replica.
305 if(rp->r_prev_rp) {
306 activate_service(rp, rp->r_prev_rp);
307 cleanup_service(rp->r_prev_rp);
308 rp->r_prev_rp = NULL;
310 if(rs_verbose)
311 printf("RS: %s completed restart\n", srv_to_string(rp));
314 return(OK);
317 /*===========================================================================*
318 * do_update *
319 *===========================================================================*/
320 PUBLIC int do_update(message *m_ptr)
322 struct rproc *rp;
323 struct rproc *new_rp;
324 struct rprocpub *rpub;
325 struct rs_start rs_start;
326 int noblock;
327 int s;
328 char label[RS_MAX_LABEL_LEN];
329 int lu_state;
330 int prepare_maxtime;
332 /* Copy the request structure. */
333 s = copy_rs_start(m_ptr->m_source, m_ptr->RS_CMD_ADDR, &rs_start);
334 if (s != OK) {
335 return s;
337 noblock = (rs_start.rss_flags & RSS_NOBLOCK);
339 /* Copy label. */
340 s = copy_label(m_ptr->m_source, rs_start.rss_label.l_addr,
341 rs_start.rss_label.l_len, label, sizeof(label));
342 if(s != OK) {
343 return s;
346 /* Lookup slot by label. */
347 rp = lookup_slot_by_label(label);
348 if(!rp) {
349 if(rs_verbose)
350 printf("RS: do_update: service '%s' not found\n", label);
351 return ESRCH;
353 rpub = rp->r_pub;
355 /* Check if the call can be allowed. */
356 if((s = check_call_permission(m_ptr->m_source, RS_UPDATE, rp)) != OK)
357 return s;
359 /* Retrieve live update state. */
360 lu_state = m_ptr->RS_LU_STATE;
361 if(lu_state == SEF_LU_STATE_NULL) {
362 return(EINVAL);
365 /* Retrieve prepare max time. */
366 prepare_maxtime = m_ptr->RS_LU_PREPARE_MAXTIME;
367 if(prepare_maxtime) {
368 if(prepare_maxtime < 0 || prepare_maxtime > RS_MAX_PREPARE_MAXTIME) {
369 return(EINVAL);
372 else {
373 prepare_maxtime = RS_DEFAULT_PREPARE_MAXTIME;
376 /* Make sure we are not already updating. */
377 if(rupdate.flags & RS_UPDATING) {
378 if(rs_verbose)
379 printf("RS: do_update: an update is already in progress\n");
380 return EBUSY;
383 /* Allocate a system service slot for the new version. */
384 s = alloc_slot(&new_rp);
385 if(s != OK) {
386 printf("RS: do_update: unable to allocate a new slot: %d\n", s);
387 return s;
390 /* Initialize the slot as requested. */
391 s = init_slot(new_rp, &rs_start, m_ptr->m_source);
392 if(s != OK) {
393 printf("RS: do_update: unable to init the new slot: %d\n", s);
394 return s;
397 /* Let the new version inherit defaults from the old one. */
398 inherit_service_defaults(rp, new_rp);
400 /* Create new version of the service but don't let it run. */
401 s = create_service(new_rp);
402 if(s != OK) {
403 printf("RS: do_update: unable to create a new service: %d\n", s);
404 return s;
407 /* Publish process-wide properties. */
408 s = publish_process(new_rp);
409 if (s != OK) {
410 printf("RS: do_update: publish_process failed: %d\n", s);
411 return s;
414 /* Link old version to new version and mark both as updating. */
415 rp->r_new_rp = new_rp;
416 new_rp->r_old_rp = rp;
417 rp->r_flags |= RS_UPDATING;
418 rp->r_new_rp->r_flags |= RS_UPDATING;
419 rupdate.flags |= RS_UPDATING;
420 getuptime(&rupdate.prepare_tm);
421 rupdate.prepare_maxtime = prepare_maxtime;
422 rupdate.rp = rp;
424 if(rs_verbose)
425 printf("RS: %s updating\n", srv_to_string(rp));
427 /* Request to update. */
428 m_ptr->m_type = RS_LU_PREPARE;
429 asynsend3(rpub->endpoint, m_ptr, AMF_NOREPLY);
431 /* Unblock the caller immediately if requested. */
432 if(noblock) {
433 return OK;
436 /* Late reply - send a reply when the new version completes initialization. */
437 rp->r_flags |= RS_LATEREPLY;
438 rp->r_caller = m_ptr->m_source;
439 rp->r_caller_request = RS_UPDATE;
441 return EDONTREPLY;
444 /*===========================================================================*
445 * do_upd_ready *
446 *===========================================================================*/
447 PUBLIC int do_upd_ready(message *m_ptr)
449 struct rproc *rp, *old_rp, *new_rp;
450 int who_p;
451 int result;
452 int r;
454 who_p = _ENDPOINT_P(m_ptr->m_source);
455 rp = rproc_ptr[who_p];
456 result = m_ptr->RS_LU_RESULT;
458 /* Make sure the originating service was requested to prepare for update. */
459 if(rp != rupdate.rp) {
460 if(rs_verbose)
461 printf("RS: do_upd_ready: got unexpected update ready msg from %d\n",
462 m_ptr->m_source);
463 return(EINVAL);
466 /* Check if something went wrong and the service failed to prepare
467 * for the update. In that case, end the update process. The old version will
468 * be replied to and continue executing.
470 if(result != OK) {
471 end_update(result);
473 printf("RS: update failed: %s\n", lu_strerror(result));
474 return OK;
477 /* Perform the update. */
478 old_rp = rp;
479 new_rp = rp->r_new_rp;
480 r = update_service(&old_rp, &new_rp);
481 if(r != OK) {
482 end_update(r);
483 printf("RS: update failed: error %d\n", r);
484 return r;
487 /* Let the new version run. */
488 r = run_service(new_rp, SEF_INIT_LU);
489 if(r != OK) {
490 update_service(&new_rp, &old_rp); /* rollback, can't fail. */
491 end_update(r);
492 printf("RS: update failed: error %d\n", r);
493 return r;
496 return(EDONTREPLY);
499 /*===========================================================================*
500 * do_period *
501 *===========================================================================*/
502 PUBLIC void do_period(m_ptr)
503 message *m_ptr;
505 register struct rproc *rp;
506 register struct rprocpub *rpub;
507 clock_t now = m_ptr->NOTIFY_TIMESTAMP;
508 int s;
509 long period;
511 /* If an update is in progress, check its status. */
512 if(rupdate.flags & RS_UPDATING) {
513 update_period(m_ptr);
516 /* Search system services table. Only check slots that are in use and not
517 * updating.
519 for (rp=BEG_RPROC_ADDR; rp<END_RPROC_ADDR; rp++) {
520 rpub = rp->r_pub;
521 if ((rp->r_flags & RS_IN_USE) && !(rp->r_flags & RS_UPDATING)) {
523 /* Compute period. */
524 period = rpub->period;
525 if(rp->r_flags & RS_INITIALIZING) {
526 period = RS_INIT_T;
529 /* If the service is to be revived (because it repeatedly exited,
530 * and was not directly restarted), the binary backoff field is
531 * greater than zero.
533 if (rp->r_backoff > 0) {
534 rp->r_backoff -= 1;
535 if (rp->r_backoff == 0) {
536 restart_service(rp);
540 /* If the service was signaled with a SIGTERM and fails to respond,
541 * kill the system service with a SIGKILL signal.
543 else if (rp->r_stop_tm > 0 && now - rp->r_stop_tm > 2*RS_DELTA_T
544 && rp->r_pid > 0) {
545 crash_service(rp); /* simulate crash */
546 rp->r_stop_tm = 0;
549 /* There seems to be no special conditions. If the service has a
550 * period assigned check its status.
552 else if (period > 0) {
554 /* Check if an answer to a status request is still pending. If
555 * the service didn't respond within time, kill it to simulate
556 * a crash. The failure will be detected and the service will
557 * be restarted automatically.
559 if (rp->r_alive_tm < rp->r_check_tm) {
560 if (now - rp->r_alive_tm > 2*period &&
561 rp->r_pid > 0 && !(rp->r_flags & RS_NOPINGREPLY)) {
562 if(rs_verbose)
563 printf("RS: %s reported late\n",
564 srv_to_string(rp));
565 rp->r_flags |= RS_NOPINGREPLY;
566 crash_service(rp); /* simulate crash */
570 /* No answer pending. Check if a period expired since the last
571 * check and, if so request the system service's status.
573 else if (now - rp->r_check_tm > rpub->period) {
574 notify(rpub->endpoint); /* request status */
575 rp->r_check_tm = now; /* mark time */
581 /* Reschedule a synchronous alarm for the next period. */
582 if (OK != (s=sys_setalarm(RS_DELTA_T, 0)))
583 panic("couldn't set alarm: %d", s);
586 /*===========================================================================*
587 * do_sigchld *
588 *===========================================================================*/
589 PUBLIC void do_sigchld()
591 /* PM informed us that there are dead children to cleanup. Go get them. */
592 pid_t pid;
593 int status;
594 struct rproc *rp;
595 struct rproc **rps;
596 struct rprocpub *rpub;
597 int i, nr_rps;
599 if(rs_verbose)
600 printf("RS: got SIGCHLD signal, cleaning up dead children\n");
602 while ( (pid = waitpid(-1, &status, WNOHANG)) != 0 ) {
603 rp = lookup_slot_by_pid(pid);
604 if(rp != NULL) {
605 rpub = rp->r_pub;
607 if(rs_verbose)
608 printf("RS: %s exited via another signal manager\n",
609 srv_to_string(rp));
611 /* The slot is still there. This means RS is not the signal
612 * manager assigned to the process. Ignore the event but
613 * free slots for all the service instances and send a late
614 * reply if necessary.
616 get_service_instances(rp, &rps, &nr_rps);
617 for(i=0;i<nr_rps;i++) {
618 if(rupdate.flags & RS_UPDATING) {
619 rupdate.flags &= ~RS_UPDATING;
621 free_slot(rps[i]);
627 /*===========================================================================*
628 * do_getsysinfo *
629 *===========================================================================*/
630 PUBLIC int do_getsysinfo(m_ptr)
631 message *m_ptr;
633 vir_bytes src_addr, dst_addr;
634 int dst_proc;
635 size_t len;
636 int s;
638 /* Check if the call can be allowed. */
639 if((s = check_call_permission(m_ptr->m_source, 0, NULL)) != OK)
640 return s;
642 switch(m_ptr->m1_i1) {
643 case SI_PROC_TAB:
644 src_addr = (vir_bytes) rproc;
645 len = sizeof(struct rproc) * NR_SYS_PROCS;
646 break;
647 case SI_PROCPUB_TAB:
648 src_addr = (vir_bytes) rprocpub;
649 len = sizeof(struct rprocpub) * NR_SYS_PROCS;
650 break;
651 default:
652 return(EINVAL);
655 dst_proc = m_ptr->m_source;
656 dst_addr = (vir_bytes) m_ptr->m1_p1;
657 if (OK != (s=sys_datacopy(SELF, src_addr, dst_proc, dst_addr, len)))
658 return(s);
659 return(OK);
662 /*===========================================================================*
663 * do_lookup *
664 *===========================================================================*/
665 PUBLIC int do_lookup(m_ptr)
666 message *m_ptr;
668 static char namebuf[100];
669 int len, r;
670 struct rproc *rrp;
671 struct rprocpub *rrpub;
673 len = m_ptr->RS_NAME_LEN;
675 if(len < 2 || len >= sizeof(namebuf)) {
676 printf("RS: len too weird (%d)\n", len);
677 return EINVAL;
680 if((r=sys_vircopy(m_ptr->m_source, D, (vir_bytes) m_ptr->RS_NAME,
681 SELF, D, (vir_bytes) namebuf, len)) != OK) {
682 printf("RS: name copy failed\n");
683 return r;
687 namebuf[len] = '\0';
689 rrp = lookup_slot_by_label(namebuf);
690 if(!rrp) {
691 return ESRCH;
693 rrpub = rrp->r_pub;
694 m_ptr->RS_ENDPOINT = rrpub->endpoint;
696 return OK;