973 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			973 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
/*
 | 
						|
 * Changes:
 | 
						|
 *   Jan 22, 2010:  Created  (Cristiano Giuffrida)
 | 
						|
 */
 | 
						|
 | 
						|
#include "inc.h"
 | 
						|
 | 
						|
#include "kernel/proc.h"
 | 
						|
 | 
						|
FORWARD int check_request(struct rs_start *rs_start);
 | 
						|
 | 
						|
/*===========================================================================*
 | 
						|
 *				   do_up				     *
 | 
						|
 *===========================================================================*/
 | 
						|
PUBLIC int do_up(m_ptr)
 | 
						|
message *m_ptr;					/* request message pointer */
 | 
						|
{
 | 
						|
/* A request was made to start a new system service. */
 | 
						|
  struct rproc *rp;
 | 
						|
  struct rprocpub *rpub;
 | 
						|
  int r;
 | 
						|
  struct rs_start rs_start;
 | 
						|
  int noblock;
 | 
						|
 | 
						|
  /* Check if the call can be allowed. */
 | 
						|
  if((r = check_call_permission(m_ptr->m_source, RS_UP, NULL)) != OK)
 | 
						|
      return r;
 | 
						|
 | 
						|
  /* Allocate a new system service slot. */
 | 
						|
  r = alloc_slot(&rp);
 | 
						|
  if(r != OK) {
 | 
						|
      printf("RS: do_up: unable to allocate a new slot: %d\n", r);
 | 
						|
      return r;
 | 
						|
  }
 | 
						|
  rpub = rp->r_pub;
 | 
						|
 | 
						|
  /* Copy the request structure. */
 | 
						|
  r = copy_rs_start(m_ptr->m_source, m_ptr->RS_CMD_ADDR, &rs_start);
 | 
						|
  if (r != OK) {
 | 
						|
      return r;
 | 
						|
  }
 | 
						|
  r = check_request(&rs_start);
 | 
						|
  if (r != OK) {
 | 
						|
      return r;
 | 
						|
  }
 | 
						|
  noblock = (rs_start.rss_flags & RSS_NOBLOCK);
 | 
						|
 | 
						|
  /* Initialize the slot as requested. */
 | 
						|
  r = init_slot(rp, &rs_start, m_ptr->m_source);
 | 
						|
  if(r != OK) {
 | 
						|
      printf("RS: do_up: unable to init the new slot: %d\n", r);
 | 
						|
      return r;
 | 
						|
  }
 | 
						|
 | 
						|
  /* Check for duplicates */
 | 
						|
  if(lookup_slot_by_label(rpub->label)) {
 | 
						|
      printf("RS: service with the same label '%s' already exists\n",
 | 
						|
          rpub->label);
 | 
						|
      return EBUSY;
 | 
						|
  }
 | 
						|
  if(rpub->dev_nr>0 && lookup_slot_by_dev_nr(rpub->dev_nr)) {
 | 
						|
      printf("RS: service with the same device number %d already exists\n",
 | 
						|
          rpub->dev_nr);
 | 
						|
      return EBUSY;
 | 
						|
  }
 | 
						|
 | 
						|
  /* All information was gathered. Now try to start the system service. */
 | 
						|
  r = start_service(rp);
 | 
						|
  if(r != OK) {
 | 
						|
      return r;
 | 
						|
  }
 | 
						|
 | 
						|
  /* Unblock the caller immediately if requested. */
 | 
						|
  if(noblock) {
 | 
						|
      return OK;
 | 
						|
  }
 | 
						|
 | 
						|
  /* Late reply - send a reply when service completes initialization. */
 | 
						|
  rp->r_flags |= RS_LATEREPLY;
 | 
						|
  rp->r_caller = m_ptr->m_source;
 | 
						|
  rp->r_caller_request = RS_UP;
 | 
						|
 | 
						|
  return EDONTREPLY;
 | 
						|
}
 | 
						|
 | 
						|
/*===========================================================================*
 | 
						|
 *				do_down					     *
 | 
						|
 *===========================================================================*/
 | 
						|
PUBLIC int do_down(message *m_ptr)
 | 
						|
{
 | 
						|
  register struct rproc *rp;
 | 
						|
  register struct rprocpub *rpub;
 | 
						|
  int s;
 | 
						|
  char label[RS_MAX_LABEL_LEN];
 | 
						|
 | 
						|
  /* Copy label. */
 | 
						|
  s = copy_label(m_ptr->m_source, m_ptr->RS_CMD_ADDR,
 | 
						|
      m_ptr->RS_CMD_LEN, label, sizeof(label));
 | 
						|
  if(s != OK) {
 | 
						|
      return s;
 | 
						|
  }
 | 
						|
 | 
						|
  /* Lookup slot by label. */
 | 
						|
  rp = lookup_slot_by_label(label);
 | 
						|
  if(!rp) {
 | 
						|
      if(rs_verbose)
 | 
						|
          printf("RS: do_down: service '%s' not found\n", label);
 | 
						|
      return(ESRCH);
 | 
						|
  }
 | 
						|
  rpub = rp->r_pub;
 | 
						|
 | 
						|
  /* Check if the call can be allowed. */
 | 
						|
  if((s = check_call_permission(m_ptr->m_source, RS_DOWN, rp)) != OK)
 | 
						|
      return s;
 | 
						|
 | 
						|
  /* Stop service. */
 | 
						|
  if (rp->r_flags & RS_TERMINATED) {
 | 
						|
        /* A recovery script is requesting us to bring down the service.
 | 
						|
         * The service is already gone, simply perform cleanup.
 | 
						|
         */
 | 
						|
        if(rs_verbose)
 | 
						|
            printf("RS: recovery script performs service down...\n");
 | 
						|
  	unpublish_service(rp);
 | 
						|
  	cleanup_service(rp);
 | 
						|
    	return(OK);
 | 
						|
  }
 | 
						|
  stop_service(rp,RS_EXITING);
 | 
						|
 | 
						|
  /* Late reply - send a reply when service dies. */
 | 
						|
  rp->r_flags |= RS_LATEREPLY;
 | 
						|
  rp->r_caller = m_ptr->m_source;
 | 
						|
  rp->r_caller_request = RS_DOWN;
 | 
						|
 | 
						|
  return EDONTREPLY;
 | 
						|
}
 | 
						|
 | 
						|
/*===========================================================================*
 | 
						|
 *				do_restart				     *
 | 
						|
 *===========================================================================*/
 | 
						|
PUBLIC int do_restart(message *m_ptr)
 | 
						|
{
 | 
						|
  struct rproc *rp;
 | 
						|
  int s, r;
 | 
						|
  char label[RS_MAX_LABEL_LEN];
 | 
						|
  char script[MAX_SCRIPT_LEN];
 | 
						|
 | 
						|
  /* Copy label. */
 | 
						|
  s = copy_label(m_ptr->m_source, m_ptr->RS_CMD_ADDR,
 | 
						|
      m_ptr->RS_CMD_LEN, label, sizeof(label));
 | 
						|
  if(s != OK) {
 | 
						|
      return s;
 | 
						|
  }
 | 
						|
 | 
						|
  /* Lookup slot by label. */
 | 
						|
  rp = lookup_slot_by_label(label);
 | 
						|
  if(!rp) {
 | 
						|
      if(rs_verbose)
 | 
						|
          printf("RS: do_restart: service '%s' not found\n", label);
 | 
						|
      return(ESRCH);
 | 
						|
  }
 | 
						|
 | 
						|
  /* Check if the call can be allowed. */
 | 
						|
  if((r = check_call_permission(m_ptr->m_source, RS_RESTART, rp)) != OK)
 | 
						|
      return r;
 | 
						|
 | 
						|
  /* We can only be asked to restart a service from a recovery script. */
 | 
						|
  if (! (rp->r_flags & RS_TERMINATED) ) {
 | 
						|
      if(rs_verbose)
 | 
						|
          printf("RS: %s is still running\n", srv_to_string(rp));
 | 
						|
      return EBUSY;
 | 
						|
  }
 | 
						|
 | 
						|
  if(rs_verbose)
 | 
						|
      printf("RS: recovery script performs service restart...\n");
 | 
						|
 | 
						|
  /* Restart the service, but make sure we don't call the script again. */
 | 
						|
  strcpy(script, rp->r_script);
 | 
						|
  rp->r_script[0] = '\0';
 | 
						|
  restart_service(rp);
 | 
						|
  strcpy(rp->r_script, script);
 | 
						|
 | 
						|
  return OK;
 | 
						|
}
 | 
						|
 | 
						|
/*===========================================================================*
 | 
						|
 *				do_clone				     *
 | 
						|
 *===========================================================================*/
 | 
						|
PUBLIC int do_clone(message *m_ptr)
 | 
						|
{
 | 
						|
  struct rproc *rp;
 | 
						|
  struct rprocpub *rpub;
 | 
						|
  int s, r;
 | 
						|
  char label[RS_MAX_LABEL_LEN];
 | 
						|
 | 
						|
  /* Copy label. */
 | 
						|
  s = copy_label(m_ptr->m_source, m_ptr->RS_CMD_ADDR,
 | 
						|
      m_ptr->RS_CMD_LEN, label, sizeof(label));
 | 
						|
  if(s != OK) {
 | 
						|
      return s;
 | 
						|
  }
 | 
						|
 | 
						|
  /* Lookup slot by label. */
 | 
						|
  rp = lookup_slot_by_label(label);
 | 
						|
  if(!rp) {
 | 
						|
      if(rs_verbose)
 | 
						|
          printf("RS: do_clone: service '%s' not found\n", label);
 | 
						|
      return(ESRCH);
 | 
						|
  }
 | 
						|
  rpub = rp->r_pub;
 | 
						|
 | 
						|
  /* Check if the call can be allowed. */
 | 
						|
  if((r = check_call_permission(m_ptr->m_source, RS_CLONE, rp)) != OK)
 | 
						|
      return r;
 | 
						|
 | 
						|
  /* Don't clone if a replica is already available. */
 | 
						|
  if(rp->r_next_rp) {
 | 
						|
      return EEXIST;
 | 
						|
  }
 | 
						|
 | 
						|
  /* Clone the service as requested. */
 | 
						|
  rpub->sys_flags |= SF_USE_REPL;
 | 
						|
  if ((r = clone_service(rp, RST_SYS_PROC)) != OK) {
 | 
						|
      rpub->sys_flags &= ~SF_USE_REPL;
 | 
						|
      return r;
 | 
						|
  }
 | 
						|
 | 
						|
  return OK;
 | 
						|
}
 | 
						|
 | 
						|
/*===========================================================================*
 | 
						|
 *				    do_edit				     *
 | 
						|
 *===========================================================================*/
 | 
						|
PUBLIC int do_edit(message *m_ptr)
 | 
						|
{
 | 
						|
  struct rproc *rp;
 | 
						|
  struct rprocpub *rpub;
 | 
						|
  struct rs_start rs_start;
 | 
						|
  int r;
 | 
						|
  char label[RS_MAX_LABEL_LEN];
 | 
						|
 | 
						|
  /* Copy the request structure. */
 | 
						|
  r = copy_rs_start(m_ptr->m_source, m_ptr->RS_CMD_ADDR, &rs_start);
 | 
						|
  if (r != OK) {
 | 
						|
      return r;
 | 
						|
  }
 | 
						|
 | 
						|
  /* Copy label. */
 | 
						|
  r = copy_label(m_ptr->m_source, rs_start.rss_label.l_addr,
 | 
						|
      rs_start.rss_label.l_len, label, sizeof(label));
 | 
						|
  if(r != OK) {
 | 
						|
      return r;
 | 
						|
  }
 | 
						|
 | 
						|
  /* Lookup slot by label. */
 | 
						|
  rp = lookup_slot_by_label(label);
 | 
						|
  if(!rp) {
 | 
						|
      if(rs_verbose)
 | 
						|
          printf("RS: do_edit: service '%s' not found\n", label);
 | 
						|
      return ESRCH;
 | 
						|
  }
 | 
						|
  rpub = rp->r_pub;
 | 
						|
 | 
						|
  /* Check if the call can be allowed. */
 | 
						|
  if((r = check_call_permission(m_ptr->m_source, RS_EDIT, rp)) != OK)
 | 
						|
      return r;
 | 
						|
 | 
						|
  if(rs_verbose)
 | 
						|
      printf("RS: %s edits settings\n", srv_to_string(rp));
 | 
						|
 | 
						|
  /* Synch the privilege structure with the kernel. */
 | 
						|
  if ((r = sys_getpriv(&rp->r_priv, rpub->endpoint)) != OK) {
 | 
						|
      printf("RS: do_edit: unable to synch privilege structure: %d\n", r);
 | 
						|
      return r;
 | 
						|
  }
 | 
						|
 | 
						|
  /* Tell scheduler this process is finished */
 | 
						|
  if ((r = sched_stop(rp->r_scheduler, rpub->endpoint)) != OK) {
 | 
						|
      printf("RS: do_edit: scheduler won't give up process: %d\n", r);
 | 
						|
      return r;
 | 
						|
  }
 | 
						|
 | 
						|
  /* Edit the slot as requested. */
 | 
						|
  if((r = edit_slot(rp, &rs_start, m_ptr->m_source)) != OK) {
 | 
						|
      printf("RS: do_edit: unable to edit the existing slot: %d\n", r);
 | 
						|
      return r;
 | 
						|
  }
 | 
						|
 | 
						|
  /* Update privilege structure. */
 | 
						|
  r = sys_privctl(rpub->endpoint, SYS_PRIV_UPDATE_SYS, &rp->r_priv);
 | 
						|
  if(r != OK) {
 | 
						|
      printf("RS: do_edit: unable to update privilege structure: %d\n", r);
 | 
						|
      return r;
 | 
						|
  }
 | 
						|
 | 
						|
  /* Update VM calls. */
 | 
						|
  if ((r = vm_set_priv(rpub->endpoint, &rpub->vm_call_mask[0])) != OK) {
 | 
						|
      printf("RS: do_edit: failed: %d\n", r);
 | 
						|
      return r;
 | 
						|
  }
 | 
						|
 | 
						|
  /* Reinitialize scheduling. */
 | 
						|
  if ((r = sched_init_proc(rp)) != OK) {
 | 
						|
      printf("RS: do_edit: unable to reinitialize scheduling: %d\n", r);
 | 
						|
      return r;
 | 
						|
  }
 | 
						|
 | 
						|
  /* Cleanup old replicas and create a new one, if necessary. */
 | 
						|
  if(rpub->sys_flags & SF_USE_REPL) {
 | 
						|
      if(rp->r_next_rp) {
 | 
						|
          cleanup_service(rp->r_next_rp);
 | 
						|
          rp->r_next_rp = NULL;
 | 
						|
      }
 | 
						|
      if ((r = clone_service(rp, RST_SYS_PROC)) != OK) {
 | 
						|
          printf("RS: warning: unable to clone %s\n", srv_to_string(rp));
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  return OK;
 | 
						|
}
 | 
						|
 | 
						|
/*===========================================================================*
 | 
						|
 *				do_refresh				     *
 | 
						|
 *===========================================================================*/
 | 
						|
PUBLIC int do_refresh(message *m_ptr)
 | 
						|
{
 | 
						|
  register struct rproc *rp;
 | 
						|
  register struct rprocpub *rpub;
 | 
						|
  int s;
 | 
						|
  char label[RS_MAX_LABEL_LEN];
 | 
						|
 | 
						|
  /* Copy label. */
 | 
						|
  s = copy_label(m_ptr->m_source, m_ptr->RS_CMD_ADDR,
 | 
						|
      m_ptr->RS_CMD_LEN, label, sizeof(label));
 | 
						|
  if(s != OK) {
 | 
						|
      return s;
 | 
						|
  }
 | 
						|
 | 
						|
  /* Lookup slot by label. */
 | 
						|
  rp = lookup_slot_by_label(label);
 | 
						|
  if(!rp) {
 | 
						|
      if(rs_verbose)
 | 
						|
          printf("RS: do_refresh: service '%s' not found\n", label);
 | 
						|
      return(ESRCH);
 | 
						|
  }
 | 
						|
  rpub = rp->r_pub;
 | 
						|
 | 
						|
  /* Check if the call can be allowed. */
 | 
						|
  if((s = check_call_permission(m_ptr->m_source, RS_REFRESH, rp)) != OK)
 | 
						|
      return s;
 | 
						|
 | 
						|
  /* Refresh service. */
 | 
						|
  if(rs_verbose)
 | 
						|
      printf("RS: %s refreshing\n", srv_to_string(rp));
 | 
						|
  stop_service(rp,RS_REFRESHING);
 | 
						|
 | 
						|
  return OK;
 | 
						|
}
 | 
						|
 | 
						|
/*===========================================================================*
 | 
						|
 *				do_shutdown				     *
 | 
						|
 *===========================================================================*/
 | 
						|
PUBLIC int do_shutdown(message *m_ptr)
 | 
						|
{
 | 
						|
  int slot_nr;
 | 
						|
  struct rproc *rp;
 | 
						|
  int r;
 | 
						|
 | 
						|
  /* Check if the call can be allowed. */
 | 
						|
  if (m_ptr != NULL) {
 | 
						|
      if((r = check_call_permission(m_ptr->m_source, RS_SHUTDOWN, NULL)) != OK)
 | 
						|
          return r;
 | 
						|
  }
 | 
						|
 | 
						|
  if(rs_verbose)
 | 
						|
      printf("RS: shutting down...\n");
 | 
						|
 | 
						|
  /* Set flag to tell RS we are shutting down. */
 | 
						|
  shutting_down = TRUE;
 | 
						|
 | 
						|
  /* Don't restart dead services. */
 | 
						|
  for (slot_nr = 0; slot_nr < NR_SYS_PROCS; slot_nr++) {
 | 
						|
      rp = &rproc[slot_nr];
 | 
						|
      if (rp->r_flags & RS_IN_USE) {
 | 
						|
          rp->r_flags |= RS_EXITING;
 | 
						|
      }
 | 
						|
  }
 | 
						|
  return(OK);
 | 
						|
}
 | 
						|
 | 
						|
/*===========================================================================*
 | 
						|
 *				do_init_ready				     *
 | 
						|
 *===========================================================================*/
 | 
						|
PUBLIC int do_init_ready(message *m_ptr)
 | 
						|
{
 | 
						|
  int who_p;
 | 
						|
  message m;
 | 
						|
  struct rproc *rp;
 | 
						|
  struct rprocpub *rpub;
 | 
						|
  int result, is_rs;
 | 
						|
  int r;
 | 
						|
 | 
						|
  is_rs = (m_ptr->m_source == RS_PROC_NR);
 | 
						|
  who_p = _ENDPOINT_P(m_ptr->m_source);
 | 
						|
  result = m_ptr->RS_INIT_RESULT;
 | 
						|
 | 
						|
  /* Check for RS failing initialization first. */
 | 
						|
  if(is_rs && result != OK) {
 | 
						|
      return result;
 | 
						|
  }
 | 
						|
 | 
						|
  rp = rproc_ptr[who_p];
 | 
						|
  rpub = rp->r_pub;
 | 
						|
 | 
						|
  /* Make sure the originating service was requested to initialize. */
 | 
						|
  if(! (rp->r_flags & RS_INITIALIZING) ) {
 | 
						|
      if(rs_verbose)
 | 
						|
          printf("RS: do_init_ready: got unexpected init ready msg from %d\n",
 | 
						|
              m_ptr->m_source);
 | 
						|
      return EINVAL;
 | 
						|
  }
 | 
						|
 | 
						|
  /* Check if something went wrong and the service failed to init.
 | 
						|
   * In that case, kill the service.
 | 
						|
   */
 | 
						|
  if(result != OK) {
 | 
						|
      if(rs_verbose)
 | 
						|
          printf("RS: %s initialization error: %s\n", srv_to_string(rp),
 | 
						|
              init_strerror(result));
 | 
						|
      crash_service(rp); /* simulate crash */
 | 
						|
      return EDONTREPLY;
 | 
						|
  }
 | 
						|
 | 
						|
  /* Mark the slot as no longer initializing. */
 | 
						|
  rp->r_flags &= ~RS_INITIALIZING;
 | 
						|
  rp->r_check_tm = 0;
 | 
						|
  getuptime(&rp->r_alive_tm);
 | 
						|
 | 
						|
  /* Reply and unblock the service before doing anything else. */
 | 
						|
  m.m_type = OK;
 | 
						|
  reply(rpub->endpoint, rp, &m);
 | 
						|
 | 
						|
  /* See if a late reply has to be sent. */
 | 
						|
  late_reply(rp, OK);
 | 
						|
 | 
						|
  if(rs_verbose)
 | 
						|
      printf("RS: %s initialized\n", srv_to_string(rp));
 | 
						|
 | 
						|
  /* If the service has completed initialization after a live
 | 
						|
   * update, end the update now.
 | 
						|
   */
 | 
						|
  if(rp->r_flags & RS_UPDATING) {
 | 
						|
      printf("RS: update succeeded\n");
 | 
						|
      end_update(OK, RS_DONTREPLY);
 | 
						|
  }
 | 
						|
 | 
						|
  /* If the service has completed initialization after a crash
 | 
						|
   * make the new instance active and cleanup the old replica.
 | 
						|
   */
 | 
						|
  if(rp->r_prev_rp) {
 | 
						|
      cleanup_service(rp->r_prev_rp);
 | 
						|
      rp->r_prev_rp = NULL;
 | 
						|
      rp->r_restarts += 1;
 | 
						|
 | 
						|
      if(rs_verbose)
 | 
						|
          printf("RS: %s completed restart\n", srv_to_string(rp));
 | 
						|
  }
 | 
						|
 | 
						|
  /* If we must keep a replica of this system service, create it now. */
 | 
						|
  if(rpub->sys_flags & SF_USE_REPL) {
 | 
						|
      if ((r = clone_service(rp, RST_SYS_PROC)) != OK) {
 | 
						|
          printf("RS: warning: unable to clone %s\n", srv_to_string(rp));
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  return is_rs ? OK : EDONTREPLY; /* return what the caller expects */
 | 
						|
}
 | 
						|
 | 
						|
/*===========================================================================*
 | 
						|
 *				do_update				     *
 | 
						|
 *===========================================================================*/
 | 
						|
PUBLIC int do_update(message *m_ptr)
 | 
						|
{
 | 
						|
  struct rproc *rp;
 | 
						|
  struct rproc *new_rp;
 | 
						|
  struct rprocpub *rpub;
 | 
						|
  struct rs_start rs_start;
 | 
						|
  int noblock, do_self_update;
 | 
						|
  int s;
 | 
						|
  char label[RS_MAX_LABEL_LEN];
 | 
						|
  int lu_state;
 | 
						|
  int prepare_maxtime;
 | 
						|
 | 
						|
  /* Copy the request structure. */
 | 
						|
  s = copy_rs_start(m_ptr->m_source, m_ptr->RS_CMD_ADDR, &rs_start);
 | 
						|
  if (s != OK) {
 | 
						|
      return s;
 | 
						|
  }
 | 
						|
  noblock = (rs_start.rss_flags & RSS_NOBLOCK);
 | 
						|
  do_self_update = (rs_start.rss_flags & RSS_SELF_LU);
 | 
						|
  s = check_request(&rs_start);
 | 
						|
  if (s != OK) {
 | 
						|
      return s;
 | 
						|
  }
 | 
						|
 | 
						|
  /* Copy label. */
 | 
						|
  s = copy_label(m_ptr->m_source, rs_start.rss_label.l_addr,
 | 
						|
      rs_start.rss_label.l_len, label, sizeof(label));
 | 
						|
  if(s != OK) {
 | 
						|
      return s;
 | 
						|
  }
 | 
						|
 | 
						|
  /* Lookup slot by label. */
 | 
						|
  rp = lookup_slot_by_label(label);
 | 
						|
  if(!rp) {
 | 
						|
      if(rs_verbose)
 | 
						|
          printf("RS: do_update: service '%s' not found\n", label);
 | 
						|
      return ESRCH;
 | 
						|
  }
 | 
						|
  rpub = rp->r_pub;
 | 
						|
 | 
						|
  /* Check if the call can be allowed. */
 | 
						|
  if((s = check_call_permission(m_ptr->m_source, RS_UPDATE, rp)) != OK)
 | 
						|
      return s;
 | 
						|
 | 
						|
  /* Retrieve live update state. */
 | 
						|
  lu_state = m_ptr->RS_LU_STATE;
 | 
						|
  if(lu_state == SEF_LU_STATE_NULL) {
 | 
						|
      return(EINVAL);
 | 
						|
  }
 | 
						|
 | 
						|
  /* Retrieve prepare max time. */
 | 
						|
  prepare_maxtime = m_ptr->RS_LU_PREPARE_MAXTIME;
 | 
						|
  if(prepare_maxtime) {
 | 
						|
      if(prepare_maxtime < 0 || prepare_maxtime > RS_MAX_PREPARE_MAXTIME) {
 | 
						|
          return(EINVAL);
 | 
						|
      }
 | 
						|
  }
 | 
						|
  else {
 | 
						|
      prepare_maxtime = RS_DEFAULT_PREPARE_MAXTIME;
 | 
						|
  }
 | 
						|
 | 
						|
  /* Make sure we are not already updating. */
 | 
						|
  if(rupdate.flags & RS_UPDATING) {
 | 
						|
      if(rs_verbose)
 | 
						|
	  printf("RS: do_update: an update is already in progress\n");
 | 
						|
      return EBUSY;
 | 
						|
  }
 | 
						|
 | 
						|
  /* A self update live updates a service instance into a replica, a regular
 | 
						|
   * update live updates a service instance into a new version, as specified
 | 
						|
   * by the given binary.
 | 
						|
   */
 | 
						|
  if(do_self_update) {
 | 
						|
      if(rs_verbose)
 | 
						|
          printf("RS: %s performs self update\n", srv_to_string(rp));
 | 
						|
 | 
						|
      /* Clone the system service and use the replica as the new version. */
 | 
						|
      s = clone_service(rp, LU_SYS_PROC);
 | 
						|
      if(s != OK) {
 | 
						|
          printf("RS: do_update: unable to clone service: %d\n", s);
 | 
						|
          return s;
 | 
						|
      }
 | 
						|
  }
 | 
						|
  else {
 | 
						|
      if(rs_verbose)
 | 
						|
          printf("RS: %s performs regular update\n", srv_to_string(rp));
 | 
						|
 | 
						|
      /* Allocate a system service slot for the new version. */
 | 
						|
      s = alloc_slot(&new_rp);
 | 
						|
      if(s != OK) {
 | 
						|
          printf("RS: do_update: unable to allocate a new slot: %d\n", s);
 | 
						|
          return s;
 | 
						|
      }
 | 
						|
 | 
						|
      /* Initialize the slot as requested. */
 | 
						|
      s = init_slot(new_rp, &rs_start, m_ptr->m_source);
 | 
						|
      if(s != OK) {
 | 
						|
          printf("RS: do_update: unable to init the new slot: %d\n", s);
 | 
						|
          return s;
 | 
						|
      }
 | 
						|
 | 
						|
      /* Let the new version inherit defaults from the old one. */
 | 
						|
      inherit_service_defaults(rp, new_rp);
 | 
						|
 | 
						|
      /* Link the two versions. */
 | 
						|
      rp->r_new_rp = new_rp;
 | 
						|
      new_rp->r_old_rp = rp;
 | 
						|
 | 
						|
      /* Create new version of the service but don't let it run. */
 | 
						|
      new_rp->r_priv.s_flags |= LU_SYS_PROC;
 | 
						|
      s = create_service(new_rp);
 | 
						|
      if(s != OK) {
 | 
						|
          printf("RS: do_update: unable to create a new service: %d\n", s);
 | 
						|
          return s;
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  /* Mark both versions as updating. */
 | 
						|
  rp->r_flags |= RS_UPDATING;
 | 
						|
  rp->r_new_rp->r_flags |= RS_UPDATING;
 | 
						|
  rupdate.flags |= RS_UPDATING;
 | 
						|
  getuptime(&rupdate.prepare_tm);
 | 
						|
  rupdate.prepare_maxtime = prepare_maxtime;
 | 
						|
  rupdate.rp = rp;
 | 
						|
 | 
						|
  if(rs_verbose)
 | 
						|
    printf("RS: %s updating\n", srv_to_string(rp));
 | 
						|
 | 
						|
  /* If RS is updating, set up signal managers for the new instance.
 | 
						|
   * The current RS instance must be made the backup signal manager to
 | 
						|
   * support rollback in case of a crash during initialization.
 | 
						|
   */
 | 
						|
  if(rp->r_priv.s_flags & ROOT_SYS_PROC) {
 | 
						|
      new_rp = rp->r_new_rp;
 | 
						|
 | 
						|
      s = update_sig_mgrs(new_rp, SELF, new_rp->r_pub->endpoint);
 | 
						|
      if(s != OK) {
 | 
						|
          cleanup_service(new_rp);
 | 
						|
          return s;
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  if(noblock) {
 | 
						|
      /* Unblock the caller immediately if requested. */
 | 
						|
      m_ptr->m_type = OK;
 | 
						|
      reply(m_ptr->m_source, NULL, m_ptr);
 | 
						|
  }
 | 
						|
  else {
 | 
						|
      /* Send a reply when the new version completes initialization. */
 | 
						|
      rp->r_flags |= RS_LATEREPLY;
 | 
						|
      rp->r_caller = m_ptr->m_source;
 | 
						|
      rp->r_caller_request = RS_UPDATE;
 | 
						|
  }
 | 
						|
 | 
						|
  /* Request to update. */
 | 
						|
  m_ptr->m_type = RS_LU_PREPARE;
 | 
						|
  if(rpub->endpoint == RS_PROC_NR) {
 | 
						|
      /* RS can process the request directly. */
 | 
						|
      do_sef_lu_request(m_ptr);
 | 
						|
  }
 | 
						|
  else {
 | 
						|
      /* Send request message to the system service. */
 | 
						|
      asynsend3(rpub->endpoint, m_ptr, AMF_NOREPLY);
 | 
						|
  }
 | 
						|
 | 
						|
  return EDONTREPLY;
 | 
						|
}
 | 
						|
 | 
						|
/*===========================================================================*
 | 
						|
 *				do_upd_ready				     *
 | 
						|
 *===========================================================================*/
 | 
						|
PUBLIC int do_upd_ready(message *m_ptr)
 | 
						|
{
 | 
						|
  struct rproc *rp, *old_rp, *new_rp;
 | 
						|
  int who_p;
 | 
						|
  int result;
 | 
						|
  int is_rs;
 | 
						|
  int r;
 | 
						|
 | 
						|
  who_p = _ENDPOINT_P(m_ptr->m_source);
 | 
						|
  rp = rproc_ptr[who_p];
 | 
						|
  result = m_ptr->RS_LU_RESULT;
 | 
						|
  is_rs = (m_ptr->m_source == RS_PROC_NR);
 | 
						|
 | 
						|
  /* Make sure the originating service was requested to prepare for update. */
 | 
						|
  if(rp != rupdate.rp) {
 | 
						|
      if(rs_verbose)
 | 
						|
          printf("RS: do_upd_ready: got unexpected update ready msg from %d\n",
 | 
						|
              m_ptr->m_source);
 | 
						|
      return EINVAL;
 | 
						|
  }
 | 
						|
 | 
						|
  /* Check if something went wrong and the service failed to prepare
 | 
						|
   * for the update. In that case, end the update process. The old version will
 | 
						|
   * be replied to and continue executing.
 | 
						|
   */
 | 
						|
  if(result != OK) {
 | 
						|
      end_update(result, RS_REPLY);
 | 
						|
 | 
						|
      printf("RS: update failed: %s\n", lu_strerror(result));
 | 
						|
      return is_rs ? result : EDONTREPLY; /* return what the caller expects */
 | 
						|
  }
 | 
						|
 | 
						|
  old_rp = rp;
 | 
						|
  new_rp = rp->r_new_rp;
 | 
						|
 | 
						|
  /* If RS itself is updating, yield control to the new version immediately. */
 | 
						|
  if(is_rs) {
 | 
						|
      r = init_service(new_rp, SEF_INIT_LU);
 | 
						|
      if(r != OK) {
 | 
						|
          panic("unable to initialize the new RS instance: %d", r);
 | 
						|
      }
 | 
						|
      r = sys_privctl(new_rp->r_pub->endpoint, SYS_PRIV_YIELD, NULL);
 | 
						|
      if(r != OK) {
 | 
						|
          panic("unable to yield control to the new RS instance: %d", r);
 | 
						|
      }
 | 
						|
      /* If we get this far, the new version failed to initialize. Rollback. */
 | 
						|
      r = srv_update(RS_PROC_NR, new_rp->r_pub->endpoint);
 | 
						|
      assert(r == OK); /* can't fail */
 | 
						|
      end_update(ERESTART, RS_REPLY);
 | 
						|
      return ERESTART;
 | 
						|
  }
 | 
						|
 | 
						|
  /* Perform the update. */
 | 
						|
  r = update_service(&old_rp, &new_rp, RS_SWAP);
 | 
						|
  if(r != OK) {
 | 
						|
      end_update(r, RS_REPLY);
 | 
						|
      printf("RS: update failed: error %d\n", r);
 | 
						|
      return EDONTREPLY;
 | 
						|
  }
 | 
						|
 | 
						|
  /* Let the new version run. */
 | 
						|
  r = run_service(new_rp, SEF_INIT_LU);
 | 
						|
  if(r != OK) {
 | 
						|
      /* Something went wrong. Rollback. */
 | 
						|
      r = update_service(&new_rp, &old_rp, RS_SWAP);
 | 
						|
      assert(r == OK); /* can't fail */
 | 
						|
      end_update(r, RS_REPLY);
 | 
						|
      printf("RS: update failed: error %d\n", r);
 | 
						|
      return EDONTREPLY;
 | 
						|
  }
 | 
						|
 | 
						|
  return EDONTREPLY;
 | 
						|
}
 | 
						|
 | 
						|
/*===========================================================================*
 | 
						|
 *				do_period				     *
 | 
						|
 *===========================================================================*/
 | 
						|
PUBLIC void do_period(m_ptr)
 | 
						|
message *m_ptr;
 | 
						|
{
 | 
						|
  register struct rproc *rp;
 | 
						|
  register struct rprocpub *rpub;
 | 
						|
  clock_t now = m_ptr->NOTIFY_TIMESTAMP;
 | 
						|
  int s;
 | 
						|
  long period;
 | 
						|
 | 
						|
  /* If an update is in progress, check its status. */
 | 
						|
  if(rupdate.flags & RS_UPDATING) {
 | 
						|
      update_period(m_ptr);
 | 
						|
  }
 | 
						|
 | 
						|
  /* Search system services table. Only check slots that are in use and not
 | 
						|
   * updating.
 | 
						|
   */
 | 
						|
  for (rp=BEG_RPROC_ADDR; rp<END_RPROC_ADDR; rp++) {
 | 
						|
      rpub = rp->r_pub;
 | 
						|
      if ((rp->r_flags & RS_ACTIVE) && !(rp->r_flags & RS_UPDATING)) {
 | 
						|
 | 
						|
          /* Compute period. */
 | 
						|
          period = rp->r_period;
 | 
						|
          if(rp->r_flags & RS_INITIALIZING) {
 | 
						|
              period = RS_INIT_T;
 | 
						|
          }
 | 
						|
 | 
						|
          /* If the service is to be revived (because it repeatedly exited, 
 | 
						|
	   * and was not directly restarted), the binary backoff field is  
 | 
						|
	   * greater than zero. 
 | 
						|
	   */
 | 
						|
	  if (rp->r_backoff > 0) {
 | 
						|
              rp->r_backoff -= 1;
 | 
						|
	      if (rp->r_backoff == 0) {
 | 
						|
		  restart_service(rp);
 | 
						|
	      }
 | 
						|
	  }
 | 
						|
 | 
						|
	  /* If the service was signaled with a SIGTERM and fails to respond,
 | 
						|
	   * kill the system service with a SIGKILL signal.
 | 
						|
	   */
 | 
						|
	  else if (rp->r_stop_tm > 0 && now - rp->r_stop_tm > 2*RS_DELTA_T
 | 
						|
	   && rp->r_pid > 0) {
 | 
						|
              rp->r_stop_tm = 0;
 | 
						|
              crash_service(rp); /* simulate crash */
 | 
						|
	  }
 | 
						|
 | 
						|
	  /* There seems to be no special conditions. If the service has a 
 | 
						|
	   * period assigned check its status. 
 | 
						|
	   */
 | 
						|
	  else if (period > 0) {
 | 
						|
 | 
						|
	      /* Check if an answer to a status request is still pending. If 
 | 
						|
	       * the service didn't respond within time, kill it to simulate 
 | 
						|
	       * a crash. The failure will be detected and the service will 
 | 
						|
	       * be restarted automatically. Give the service a free pass if
 | 
						|
	       * somebody is initializing. There may be some weird dependencies
 | 
						|
	       * if another service is, for example, restarting at the same
 | 
						|
	       * time.
 | 
						|
	       */
 | 
						|
              if (rp->r_alive_tm < rp->r_check_tm) { 
 | 
						|
	          if (now - rp->r_alive_tm > 2*period &&
 | 
						|
		      rp->r_pid > 0 && !(rp->r_flags & RS_NOPINGREPLY)) { 
 | 
						|
		      if(rs_verbose)
 | 
						|
                           printf("RS: %s reported late\n", srv_to_string(rp)); 
 | 
						|
		      if(lookup_slot_by_flags(RS_INITIALIZING)) {
 | 
						|
                           /* Skip for now. */
 | 
						|
                           if(rs_verbose)
 | 
						|
                               printf("RS: %s gets a free pass\n",
 | 
						|
                                   srv_to_string(rp)); 
 | 
						|
                           rp->r_alive_tm = now;
 | 
						|
                           rp->r_check_tm = now+1;
 | 
						|
                           continue;
 | 
						|
		      }
 | 
						|
		      rp->r_flags |= RS_NOPINGREPLY;
 | 
						|
                      crash_service(rp); /* simulate crash */
 | 
						|
		  }
 | 
						|
	      }
 | 
						|
 | 
						|
	      /* No answer pending. Check if a period expired since the last
 | 
						|
	       * check and, if so request the system service's status.
 | 
						|
	       */
 | 
						|
	      else if (now - rp->r_check_tm > rp->r_period) {
 | 
						|
  		  notify(rpub->endpoint);		/* request status */
 | 
						|
		  rp->r_check_tm = now;			/* mark time */
 | 
						|
              }
 | 
						|
          }
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  /* Reschedule a synchronous alarm for the next period. */
 | 
						|
  if (OK != (s=sys_setalarm(RS_DELTA_T, 0)))
 | 
						|
      panic("couldn't set alarm: %d", s);
 | 
						|
}
 | 
						|
 | 
						|
/*===========================================================================*
 | 
						|
 *			          do_sigchld				     *
 | 
						|
 *===========================================================================*/
 | 
						|
PUBLIC void do_sigchld()
 | 
						|
{
 | 
						|
/* PM informed us that there are dead children to cleanup. Go get them. */
 | 
						|
  pid_t pid;
 | 
						|
  int status;
 | 
						|
  struct rproc *rp;
 | 
						|
  struct rproc **rps;
 | 
						|
  struct rprocpub *rpub;
 | 
						|
  int i, nr_rps;
 | 
						|
 | 
						|
  if(rs_verbose)
 | 
						|
     printf("RS: got SIGCHLD signal, cleaning up dead children\n");
 | 
						|
 | 
						|
  while ( (pid = waitpid(-1, &status, WNOHANG)) != 0 ) {
 | 
						|
      rp = lookup_slot_by_pid(pid);
 | 
						|
      if(rp != NULL) {
 | 
						|
          rpub = rp->r_pub;
 | 
						|
 | 
						|
          if(rs_verbose)
 | 
						|
              printf("RS: %s exited via another signal manager\n",
 | 
						|
                  srv_to_string(rp));
 | 
						|
 | 
						|
          /* The slot is still there. This means RS is not the signal
 | 
						|
           * manager assigned to the process. Ignore the event but
 | 
						|
           * free slots for all the service instances and send a late
 | 
						|
           * reply if necessary.
 | 
						|
           */
 | 
						|
          get_service_instances(rp, &rps, &nr_rps);
 | 
						|
          for(i=0;i<nr_rps;i++) {
 | 
						|
              if(rupdate.flags & RS_UPDATING) {
 | 
						|
                  rupdate.flags &= ~RS_UPDATING;
 | 
						|
              }
 | 
						|
              free_slot(rps[i]);
 | 
						|
          }
 | 
						|
      }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/*===========================================================================*
 | 
						|
 *				do_getsysinfo				     *
 | 
						|
 *===========================================================================*/
 | 
						|
PUBLIC int do_getsysinfo(m_ptr)
 | 
						|
message *m_ptr;
 | 
						|
{
 | 
						|
  vir_bytes src_addr, dst_addr;
 | 
						|
  int dst_proc;
 | 
						|
  size_t len;
 | 
						|
  int s;
 | 
						|
 | 
						|
  /* Check if the call can be allowed. */
 | 
						|
  if((s = check_call_permission(m_ptr->m_source, 0, NULL)) != OK)
 | 
						|
      return s;
 | 
						|
 | 
						|
  switch(m_ptr->m1_i1) {
 | 
						|
  case SI_PROC_TAB:
 | 
						|
  	src_addr = (vir_bytes) rproc;
 | 
						|
  	len = sizeof(struct rproc) * NR_SYS_PROCS;
 | 
						|
  	break; 
 | 
						|
  case SI_PROCPUB_TAB:
 | 
						|
  	src_addr = (vir_bytes) rprocpub;
 | 
						|
  	len = sizeof(struct rprocpub) * NR_SYS_PROCS;
 | 
						|
  	break; 
 | 
						|
  default:
 | 
						|
  	return(EINVAL);
 | 
						|
  }
 | 
						|
 | 
						|
  dst_proc = m_ptr->m_source;
 | 
						|
  dst_addr = (vir_bytes) m_ptr->m1_p1;
 | 
						|
  if (OK != (s=sys_datacopy(SELF, src_addr, dst_proc, dst_addr, len)))
 | 
						|
  	return(s);
 | 
						|
  return(OK);
 | 
						|
}
 | 
						|
 | 
						|
/*===========================================================================*
 | 
						|
 *				do_lookup				     *
 | 
						|
 *===========================================================================*/
 | 
						|
PUBLIC int do_lookup(m_ptr)
 | 
						|
message *m_ptr;
 | 
						|
{
 | 
						|
	static char namebuf[100];
 | 
						|
	int len, r;
 | 
						|
	struct rproc *rrp;
 | 
						|
	struct rprocpub *rrpub;
 | 
						|
 | 
						|
	len = m_ptr->RS_NAME_LEN;
 | 
						|
 | 
						|
	if(len < 2 || len >= sizeof(namebuf)) {
 | 
						|
		printf("RS: len too weird (%d)\n", len);
 | 
						|
		return EINVAL;
 | 
						|
	}
 | 
						|
 | 
						|
	if((r=sys_vircopy(m_ptr->m_source, D, (vir_bytes) m_ptr->RS_NAME,
 | 
						|
		SELF, D, (vir_bytes) namebuf, len)) != OK) {
 | 
						|
		printf("RS: name copy failed\n");
 | 
						|
		return r;
 | 
						|
 | 
						|
	}
 | 
						|
 | 
						|
	namebuf[len] = '\0';
 | 
						|
 | 
						|
	rrp = lookup_slot_by_label(namebuf);
 | 
						|
	if(!rrp) {
 | 
						|
		return ESRCH;
 | 
						|
	}
 | 
						|
	rrpub = rrp->r_pub;
 | 
						|
	m_ptr->RS_ENDPOINT = rrpub->endpoint;
 | 
						|
 | 
						|
	return OK;
 | 
						|
}
 | 
						|
 | 
						|
/*===========================================================================*
 | 
						|
 *				   check_request			     *
 | 
						|
 *===========================================================================*/
 | 
						|
PRIVATE int check_request(struct rs_start *rs_start)
 | 
						|
{
 | 
						|
  /* Verify scheduling parameters */
 | 
						|
  if (rs_start->rss_scheduler != KERNEL && 
 | 
						|
	(rs_start->rss_scheduler < 0 || 
 | 
						|
	rs_start->rss_scheduler > LAST_SPECIAL_PROC_NR)) {
 | 
						|
	printf("RS: check_request: invalid scheduler %d\n", 
 | 
						|
		rs_start->rss_scheduler);
 | 
						|
	return EINVAL;
 | 
						|
  }
 | 
						|
  if (rs_start->rss_priority >= NR_SCHED_QUEUES) {
 | 
						|
	printf("RS: check_request: priority %u out of range\n", 
 | 
						|
		rs_start->rss_priority);
 | 
						|
	return EINVAL;
 | 
						|
  }
 | 
						|
  if (rs_start->rss_quantum <= 0) {
 | 
						|
	printf("RS: check_request: quantum %u out of range\n", 
 | 
						|
		rs_start->rss_quantum);
 | 
						|
	return EINVAL;
 | 
						|
  }
 | 
						|
 | 
						|
  /* Verify signal manager. */
 | 
						|
  if (rs_start->rss_sigmgr != SELF && 
 | 
						|
	(rs_start->rss_sigmgr < 0 || 
 | 
						|
	rs_start->rss_sigmgr > LAST_SPECIAL_PROC_NR)) {
 | 
						|
	printf("RS: check_request: invalid signal manager %d\n", 
 | 
						|
		rs_start->rss_sigmgr);
 | 
						|
	return EINVAL;
 | 
						|
  }
 | 
						|
 | 
						|
  return OK;
 | 
						|
}
 | 
						|
 |