# define RS_NAME m1_p1 /* name */
# define RS_NAME_LEN m1_i1 /* namelen */
-# define RS_INIT_RESULT m1_i1 /* init result */
-# define RS_INIT_TYPE m1_i2 /* init type */
-# define RS_INIT_RPROCTAB_GID m1_i3 /* init rproc table gid */
+# define RS_INIT_RESULT m7_i1 /* init result */
+# define RS_INIT_TYPE m7_i2 /* init type */
+# define RS_INIT_RPROCTAB_GID m7_i3 /* init rproc table gid */
+# define RS_INIT_OLD_ENDPOINT m7_i4 /* init old endpoint */
# define RS_LU_RESULT m1_i1 /* live update result */
# define RS_LU_STATE m1_i2 /* state required to update */
#define RSS_NR_IO 16
/* RSS flags. */
-#define RSS_COPY 0x01 /* Copy the brinary into RS to make it possible
- * to restart the driver without accessing FS
- */
+#define RSS_COPY 0x01 /* keep an in-memory copy of the binary */
#define RSS_IPC_VALID 0x02 /* rss_ipc and rss_ipclen are valid */
#define RSS_REUSE 0x04 /* Try to reuse previously copied binary */
#define RSS_NOBLOCK 0x08 /* unblock caller immediately */
+#define RSS_REPLICA 0x10 /* keep a replica of the service */
/* Common definitions. */
#define RS_NR_CONTROL 8
/* Type definitions. */
typedef struct {
cp_grant_id_t rproctab_gid;
+ endpoint_t old_endpoint;
} sef_init_info_t;
/* Callback type definitions. */
/* Let the callback code handle the request. */
type = m_ptr->RS_INIT_TYPE;
info.rproctab_gid = m_ptr->RS_INIT_RPROCTAB_GID;
+ info.old_endpoint = m_ptr->RS_INIT_OLD_ENDPOINT;
switch(type) {
case SEF_INIT_FRESH:
r = sef_cbs.sef_cb_init_fresh(type, &info);
PUBLIC struct rprocpub rprocpub[NR_SYS_PROCS];
PUBLIC struct rproc rproc[NR_SYS_PROCS];
-FORWARD _PROTOTYPE( char *s_flags_str, (int flags) );
+FORWARD _PROTOTYPE( char *s_flags_str, (int flags, int sys_flags) );
/*===========================================================================*
* rproc_dmp *
getsysinfo(RS_PROC_NR, SI_PROC_TAB, rproc);
printf("Reincarnation Server (RS) system process table dump\n");
- printf("----label---- endpoint- -pid- flags -dev- -T- alive_tm starts command\n");
+ printf("----label---- endpoint- -pid- flags- -dev- -T- alive_tm starts command\n");
for (i=prev_i; i<NR_SYS_PROCS; i++) {
rp = &rproc[i];
rpub = &rprocpub[i];
if (! (rp->r_flags & RS_IN_USE)) continue;
if (++n > 22) break;
- printf("%13s %9d %5d %5s %3d/%1d %3u %8u %5dx %s",
+ printf("%13s %9d %5d %6s %3d/%1d %3u %8u %5dx %s",
rpub->label, rpub->endpoint, rp->r_pid,
- s_flags_str(rp->r_flags), rpub->dev_nr, rpub->dev_style,
- rpub->period, rp->r_alive_tm, rp->r_restarts,
+ s_flags_str(rp->r_flags, rpub->sys_flags), rpub->dev_nr,
+ rpub->dev_style, rpub->period, rp->r_alive_tm, rp->r_restarts,
rp->r_args
);
printf("\n");
}
-PRIVATE char *s_flags_str(int flags)
+PRIVATE char *s_flags_str(int flags, int sys_flags)
{
static char str[10];
- str[0] = (flags & RS_ACTIVE) ? 'A' : '-';
- str[1] = (flags & RS_INITIALIZING) ? 'I' : '-';
- str[2] = (flags & RS_UPDATING) ? 'U' : '-';
- str[3] = (flags & RS_EXITING) ? 'E' : '-';
- str[4] = (flags & RS_NOPINGREPLY) ? 'N' : '-';
- str[5] = '\0';
+ str[0] = (flags & RS_ACTIVE) ? 'A' : '-';
+ str[1] = (flags & RS_UPDATING) ? 'U' : '-';
+ str[2] = (flags & RS_EXITING) ? 'E' : '-';
+ str[3] = (flags & RS_NOPINGREPLY) ? 'N' : '-';
+ str[4] = (sys_flags & SF_USE_COPY) ? 'C' : '-';
+ str[5] = (sys_flags & SF_USE_REPL) ? 'R' : '-';
+ str[6] = '\0';
return(str);
}
MAN=
BINDIR?= /usr/sbin
-INSTALLFLAGS+= -S 850k
+INSTALLFLAGS+= -S 1050k
CPPFLAGS= -I${MINIXSRCDIR}
/* Sys flag values. */
#define SF_CORE_SRV 0x001 /* set for core system services */
#define SF_SYNCH_BOOT 0X002 /* set when process needs synch boot init */
-#define SF_NEED_COPY 0x004 /* set when process needs copy to restart */
+#define SF_NEED_COPY 0x004 /* set when process needs copy to start */
#define SF_USE_COPY 0x008 /* set when process has a copy in memory */
+#define SF_NEED_REPL 0x010 /* set when process needs replica to start */
+#define SF_USE_REPL 0x020 /* set when process has a replica */
/* Constants determining RS period and binary exponential backoff. */
#define RS_INIT_T 600 /* allow T ticks for init */
/* Define sys flags for the various process types. */
#define SRV_SF (SF_CORE_SRV | SF_NEED_COPY) /* system services */
-#define SRVC_SF (SRV_SF | SF_USE_COPY) /* system services with a copy */
+#define SRVR_SF (SRV_SF | SF_NEED_REPL) /* services needing a replica */
#define DSRV_SF (0) /* dynamic system services */
-#define VM_SF (SRV_SF | SF_SYNCH_BOOT) /* vm */
+#define VM_SF (SRVR_SF | SF_SYNCH_BOOT) /* vm */
/* Define device flags for the various process types. */
#define SRV_DF (DRV_FORCED) /* system services */
*/
extern struct boot_image_dev boot_image_dev_table[];
+/* The buffer where the boot image is copied during initialization. */
+EXTERN int boot_image_buffer_size;
+EXTERN char *boot_image_buffer;
+
/* The system process table. This table only has entries for system
* services (servers and drivers), and thus is not directly indexed by
* slot number. The size of the table must match the size of the privilege
FORWARD _PROTOTYPE(void catch_boot_init_ready, (endpoint_t endpoint) );
FORWARD _PROTOTYPE(void get_work, (message *m_ptr, int *status_ptr) );
-/* The buffer where the boot image is copied during initialization. */
-PRIVATE int boot_image_buffer_size;
-PRIVATE char *boot_image_buffer;
-
/* Flag set when memory unmapping can be done. */
EXTERN int unmap_ok;
/* If we must keep a copy of this system service, read the header
* and increase the size of the boot image buffer.
*/
+ if(boot_image_sys->flags & SF_USE_REPL) {
+ boot_image_sys->flags |= SF_USE_COPY;
+ }
if(boot_image_sys->flags & SF_USE_COPY) {
if((s = sys_getaoutheader(&header, i)) != OK) {
panic("unable to get copy of a.out header: %d", s);
strcpy(rpub->proc_name, ip->proc_name);
/* Get command settings. */
- rp->r_cmd[0]= '\0';
+ strcpy(rp->r_cmd, ip->proc_name);
rp->r_script[0]= '\0';
build_cmd_dep(rp);
if(j == NR_PROCS) {
panic("unable to get pid");
}
+
+ /* If we must keep a replica of this system service, create it now. */
+ if(rpub->sys_flags & SF_USE_REPL) {
+ if ((s = clone_service(rp)) != OK) {
+ panic("unable to clone service: %d", s);
+ }
+ }
}
/*
if(rs_verbose)
printf("RS: ignoring spurious signal %d for process %d\n",
signo, target);
- return OK; /* Since we're ignoring it, we have handled
- * the signal without problem. All is OK.
- */
+ return OK; /* clear the signal */
}
rp = rproc_ptr[target_p];
rpub = rp->r_pub;
/* Don't bother if a termination signal has already been processed. */
- if(rp->r_flags & RS_TERMINATED) {
+ if((rp->r_flags & RS_TERMINATED) && !(rp->r_flags & RS_EXITING)) {
return EDEADSRCDST; /* process is gone */
}
+ /* Ignore external signals for inactive service instances. */
+ if( !(rp->r_flags & RS_ACTIVE) && !(rp->r_flags & RS_EXITING)) {
+ if(rs_verbose)
+ printf("RS: ignoring signal %d for inactive %s\n",
+ signo, srv_to_string(rp));
+ return OK; /* clear the signal */
+ }
+
if(rs_verbose)
printf("RS: %s got %s signal %d\n", srv_to_string(rp),
SIGS_IS_TERMINATION(signo) ? "termination" : "non-termination",signo);
return(_syscall(PM_PROC_NR, SRV_KILL, &m));
}
+/*===========================================================================*
+ * srv_update *
+ *===========================================================================*/
+PUBLIC int srv_update(endpoint_t src_e, endpoint_t dst_e)
+{
+ int r;
+
+ /* Ask VM to swap the slots of the two processes and tell the kernel to
+ * do the same. If VM is the service being updated, only perform the kernel
+ * part of the call. The new instance of VM will do the rest at
+ * initialization time.
+ */
+ if(src_e != VM_PROC_NR) {
+ r = vm_update(src_e, dst_e);
+ }
+ else {
+ r = sys_update(src_e, dst_e);
+ }
+
+ return r;
+}
+
/*===========================================================================*
* update_period *
*===========================================================================*/
new_rp->r_old_rp = NULL;
old_rp->r_check_tm = 0;
- /* Make the version that has to survive as active. */
- activate_service(surviving_rp, exiting_rp);
-
/* Send a late reply if necessary. */
late_reply(old_rp, result);
* version as no longer updating.
*/
surviving_rp->r_flags &= ~RS_UPDATING;
- unpublish_process(exiting_rp);
cleanup_service(exiting_rp);
if(rs_verbose)
/* Create the given system service. */
int child_proc_nr_e, child_proc_nr_n; /* child process slot */
pid_t child_pid; /* child's process id */
- int s, use_copy;
+ int s, use_copy, has_replica;
extern char **environ;
struct rprocpub *rpub;
rpub = rp->r_pub;
use_copy= (rpub->sys_flags & SF_USE_COPY);
+ has_replica= (rp->r_prev_rp && !(rp->r_prev_rp->r_flags & RS_TERMINATED));
- /* See if we are not using a copy but we do need one to start the service. */
+ /* Do we need an existing replica to create the service? */
+ if(!has_replica && (rpub->sys_flags & SF_NEED_REPL)) {
+ printf("RS: unable to create service '%s' without a replica\n",
+ rpub->label);
+ free_slot(rp);
+ return(EPERM);
+ }
+
+ /* Do we need an in-memory copy to create the service? */
if(!use_copy && (rpub->sys_flags & SF_NEED_COPY)) {
- printf("RS: unable to start service '%s' without an in-memory copy\n",
- rpub->label);
- free_slot(rp);
- return(EPERM);
+ printf("RS: unable to create service '%s' without an in-memory copy\n",
+ rpub->label);
+ free_slot(rp);
+ return(EPERM);
}
/* Now fork and branch for parent and child process (and check for error). */
/* There is now a child process. Update the system process table. */
child_proc_nr_n = _ENDPOINT_P(child_proc_nr_e);
rp->r_flags = RS_IN_USE; /* mark slot in use */
- rp->r_restarts += 1; /* raise nr of restarts */
- rp->r_old_rp = NULL; /* no old version yet */
- rp->r_new_rp = NULL; /* no new version yet */
- rp->r_prev_rp = NULL; /* no prev replica yet */
- rp->r_next_rp = NULL; /* no next replica yet */
rpub->endpoint = child_proc_nr_e; /* set child endpoint */
rp->r_pid = child_pid; /* set child pid */
rp->r_check_tm = 0; /* not checked yet */
rproc_ptr[child_proc_nr_n] = rp; /* mapping for fast access */
rpub->in_use = TRUE; /* public entry is now in use */
-
/* Set resources when asked to. */
if (rp->r_set_resources) {
/* Initialize privilege structure. */
return OK;
}
+/*===========================================================================*
+ * clone_service *
+ *===========================================================================*/
+PUBLIC int clone_service(rp)
+struct rproc *rp;
+{
+/* Clone the given system service instance. */
+ struct rproc *replica_rp;
+ int r;
+
+ if(rs_verbose)
+ printf("RS: creating a replica for %s\n", srv_to_string(rp));
+
+ /* Clone slot. */
+ if((r = clone_slot(rp, &replica_rp)) != OK) {
+ return r;
+ }
+
+ /* Link the two slots. */
+ rp->r_next_rp = replica_rp;
+ replica_rp->r_prev_rp = rp;
+
+ /* Create a new replica of the service. */
+ r = create_service(replica_rp);
+ if(r != OK) {
+ rp->r_next_rp = NULL;
+ return r;
+ }
+
+ return OK;
+}
+
/*===========================================================================*
* publish_service *
*===========================================================================*/
PUBLIC int publish_service(rp)
struct rproc *rp; /* pointer to service slot */
{
-/* Publish service-wide properties of a service. */
+/* Publish a service. */
int r;
struct rprocpub *rpub;
+ struct rs_pci pci_acl;
rpub = rp->r_pub;
}
}
- if(rs_verbose)
- printf("RS: %s service-wide properties published\n",
- srv_to_string(rp));
-
- return OK;
-}
-
-/*===========================================================================*
- * publish_process *
- *===========================================================================*/
-PUBLIC int publish_process(rp)
-struct rproc *rp; /* pointer to service slot */
-{
-/* Publish process-wide properties of a service. */
- int r;
- struct rprocpub *rpub;
- struct rs_pci pci_acl;
-
- rpub = rp->r_pub;
+ /* Tell VM about allowed calls, if any. */
+ if(rpub->vm_call_mask[0]) {
+ r = vm_set_priv(rpub->endpoint, &rpub->vm_call_mask[0]);
+ if (r != OK) {
+ return kill_service(rp, "vm_set_priv call failed", r);
+ }
+ }
/* If PCI properties are set, inform the PCI driver about the new service. */
if(rpub->pci_acl.rsp_nr_device || rpub->pci_acl.rsp_nr_class) {
}
}
- /* Tell VM about allowed calls, if any. */
- if(rpub->vm_call_mask[0]) {
- r = vm_set_priv(rpub->endpoint, &rpub->vm_call_mask[0]);
- if (r != OK) {
- return kill_service(rp, "vm_set_priv call failed", r);
- }
- }
-
if(rs_verbose)
- printf("RS: %s process-wide properties published\n",
- srv_to_string(rp));
+ printf("RS: %s published\n", srv_to_string(rp));
return OK;
}
PUBLIC int unpublish_service(rp)
struct rproc *rp; /* pointer to service slot */
{
-/* Unpublish service-wide properties of a service. */
+/* Unpublish a service. */
struct rprocpub *rpub;
int r, result;
result = r;
}
- /* No need to inform VFS, cleanup is performed on exit automatically. */
-
- if(rs_verbose)
- printf("RS: %s service-wide properties unpublished\n",
- srv_to_string(rp));
-
- return result;
-}
-
-/*===========================================================================*
- * unpublish_process *
- *===========================================================================*/
-PUBLIC int unpublish_process(rp)
-struct rproc *rp; /* pointer to service slot */
-{
-/* Unpublish process-wide properties of a service. */
- struct rprocpub *rpub;
- int r, result;
-
- rpub = rp->r_pub;
- result = OK;
+ /* No need to inform VFS and VM, cleanup is done on exit automatically. */
/* If PCI properties are set, inform the PCI driver. */
if(rpub->pci_acl.rsp_nr_device || rpub->pci_acl.rsp_nr_class) {
}
}
- /* No need to inform VM, cleanup is performed on exit automatically. */
-
if(rs_verbose)
- printf("RS: %s process-wide properties unpublished\n",
- srv_to_string(rp));
+ printf("RS: %s unpublished\n", srv_to_string(rp));
return result;
}
rpub = rp->r_pub;
- /* Create. */
+ /* Create and make active. */
r = create_service(rp);
+ activate_service(rp, NULL);
if(r != OK) {
return r;
}
/* Publish service properties. */
- r = publish_process(rp);
- if (r != OK) {
- return r;
- }
r = publish_service(rp);
if (r != OK) {
return r;
}
/* Run. */
- init_type = rp->r_restarts > 0 ? SEF_INIT_RESTART : SEF_INIT_FRESH;
+ init_type = SEF_INIT_FRESH;
r = run_service(rp, init_type);
if(r != OK) {
return r;
}
- /* The system service now has been successfully started. The only thing
- * that can go wrong now, is that execution fails at the child. If that's
- * the case, the child will exit.
- */
if(rs_verbose)
printf("RS: %s started with major %d\n", srv_to_string(rp),
rpub->dev_nr);
printf("RS: %s updating into %s\n",
srv_to_string(src_rp), srv_to_string(dst_rp));
- /* Ask VM to swap the slots of the two processes and tell the kernel to
- * do the same.
- */
- r = vm_update(src_rpub->endpoint, dst_rpub->endpoint);
+ /* Swap the slots of the two processes. */
+ r = srv_update(src_rpub->endpoint, dst_rpub->endpoint);
if(r != OK) {
return r;
}
*src_rpp = src_rp;
*dst_rpp = dst_rp;
+ /* Make the new version active. */
+ activate_service(dst_rp, src_rp);
+
if(rs_verbose)
printf("RS: %s updated into %s\n",
srv_to_string(src_rp), srv_to_string(dst_rp));
/* Unpublish the service. */
unpublish_service(rp);
- unpublish_process(rp);
/* Cleanup all the instances of the service. */
get_service_instances(rp, &rps, &nr_rps);
* that just exited will continue executing.
*/
if(rp->r_flags & RS_UPDATING) {
- if(! (rp->r_flags & RS_ACTIVE) ) {
- return; /* ignore unexpected signals */
- }
end_update(ERESTART);
}
/* See if a late reply has to be sent. */
late_reply(rp, OK);
+ /* Run a recovery script if available. */
if (rp->r_script[0] != '\0') {
- /* Run a recovery script. */
run_script(rp);
+ return;
}
- else {
- /* Unpublish the service. */
- unpublish_service(rp);
- unpublish_process(rp);
- /* Clone slots. */
- if((r = clone_slot(rp, &replica_rp)) != OK) {
+ /* Restart directly. We need a replica if not already available. */
+ if(rp->r_next_rp == NULL) {
+ /* Create the replica. */
+ r = clone_service(rp);
+ if(r != OK) {
kill_service(rp, "unable to clone service", r);
return;
}
+ }
+ replica_rp = rp->r_next_rp;
- if(rs_verbose)
- printf("RS: %s restarting into %s\n",
- srv_to_string(rp), srv_to_string(replica_rp));
-
- /* Swap slots. */
- swap_slot(&rp, &replica_rp);
+ /* Update the service into the replica. */
+ r = update_service(&rp, &replica_rp);
+ if(r != OK) {
+ kill_service(rp, "unable to update into new replica", r);
+ return;
+ }
- /* Direct restart. */
- if((r = start_service(replica_rp)) != OK) {
- kill_service(rp, "unable to restart service", r);
- return;
- }
+ /* Let the new replica run. */
+ r = run_service(replica_rp, SEF_INIT_RESTART);
+ if(r != OK) {
+ kill_service(rp, "unable to let the replica run", r);
+ return;
+ }
- /* Link the two slots. */
- rp->r_next_rp = replica_rp;
- replica_rp->r_prev_rp = rp;
+ /* Increase the number of restarts. */
+ replica_rp->r_restarts += 1;
- if(rs_verbose)
- printf("RS: %s restarted into %s\n",
- srv_to_string(rp), srv_to_string(replica_rp));
- }
+ if(rs_verbose)
+ printf("RS: %s restarted into %s\n",
+ srv_to_string(rp), srv_to_string(replica_rp));
}
/*===========================================================================*
struct rproc *rp;
{
/* Free an exec image. */
- int slot_nr, has_shared_exec;
+ int slot_nr, has_shared_exec, is_boot_image_mem;
struct rproc *other_rp;
/* Search for some other slot sharing the same exec image. */
}
}
- /* If nobody uses our copy of the exec image, we can get rid of it. */
+ /* If nobody uses our copy of the exec image, we can try to get rid of it. */
if(!has_shared_exec) {
- if(rs_verbose)
- printf("RS: %s frees exec image\n", srv_to_string(rp));
- free(rp->r_exec);
+ is_boot_image_mem = (rp->r_exec >= boot_image_buffer
+ && rp->r_exec < boot_image_buffer + boot_image_buffer_size);
+
+ /* Free memory only if not part of the boot image buffer. */
+ if(is_boot_image_mem) {
+ if(rs_verbose)
+ printf("RS: %s has exec image in the boot image buffer\n",
+ srv_to_string(rp));
+ }
+ else {
+ if(rs_verbose)
+ printf("RS: %s frees exec image\n", srv_to_string(rp));
+ free(rp->r_exec);
+ }
}
else {
if(rs_verbose)
else
rp->r_ipc_list[0]= '\0';
+ /* Set system flags. */
rpub->sys_flags = DSRV_SF;
rp->r_exec= NULL;
if (rs_start->rss_flags & RSS_COPY) {
rpub->sys_flags |= SF_USE_COPY;
}
+ if (rs_start->rss_flags & RSS_REPLICA) {
+ rpub->sys_flags |= SF_USE_REPL;
+ }
/* All dynamically created services get the same privilege flags, and
* allowed traps, and signal manager. Other privilege settings can be
/* Initialize some fields. */
rpub->period = rs_start->rss_period;
- rp->r_restarts = -1; /* will be incremented */
+ rp->r_restarts = 0; /* no restarts yet */
rp->r_set_resources= 1; /* set resources */
+ rp->r_old_rp = NULL; /* no old version yet */
+ rp->r_new_rp = NULL; /* no new version yet */
+ rp->r_prev_rp = NULL; /* no prev replica yet */
+ rp->r_next_rp = NULL; /* no next replica yet */
/* Copy VM call mask. Inherit basic VM calls. */
memcpy(rpub->vm_call_mask, rs_start->rss_vm,
/* Deep copy. */
clone_rp->r_flags &= ~RS_ACTIVE; /* the clone is not active yet */
clone_rp->r_pid = -1; /* no pid yet */
- clone_rpub->endpoint = -1; /* no endpoint yet */
+ clone_rpub->endpoint = -1; /* no endpoint yet */
clone_rp->r_pub = clone_rpub; /* restore pointer to public entry */
build_cmd_dep(clone_rp); /* rebuild cmd dependencies */
if(clone_rpub->sys_flags & SF_USE_COPY) {
_PROTOTYPE( void build_cmd_dep, (struct rproc *rp) );
_PROTOTYPE( int srv_fork, (void) );
_PROTOTYPE( int srv_kill, (pid_t pid, int sig) );
+_PROTOTYPE( int srv_update, (endpoint_t src_e, endpoint_t dst_e) );
#define kill_service(rp, errstr, err) \
kill_service_debug(__FILE__, __LINE__, rp, errstr, err)
_PROTOTYPE( int kill_service_debug, (char *file, int line, struct rproc *rp,
_PROTOTYPE( void cleanup_service_debug, (char *file, int line,
struct rproc *rp) );
_PROTOTYPE( int create_service, (struct rproc *rp) );
+_PROTOTYPE( int clone_service, (struct rproc *rp) );
_PROTOTYPE( int publish_service, (struct rproc *rp) );
-_PROTOTYPE( int publish_process, (struct rproc *rp) );
_PROTOTYPE( int unpublish_service, (struct rproc *rp) );
-_PROTOTYPE( int unpublish_process, (struct rproc *rp) );
_PROTOTYPE( int run_service, (struct rproc *rp, int init_type) );
_PROTOTYPE( int start_service, (struct rproc *rp) );
_PROTOTYPE( void stop_service, (struct rproc *rp,int how) );
/* All information was gathered. Now try to start the system service. */
r = start_service(rp);
- activate_service(rp, NULL);
if(r != OK) {
return r;
}
if(rs_verbose)
printf("RS: recovery script performs service down...\n");
unpublish_service(rp);
- unpublish_process(rp);
cleanup_service(rp);
return(OK);
}
struct rproc *rp;
struct rprocpub *rpub;
int result;
+ int r;
who_p = _ENDPOINT_P(m_ptr->m_source);
rp = rproc_ptr[who_p];
* make the new instance active and cleanup the old replica.
*/
if(rp->r_prev_rp) {
- activate_service(rp, rp->r_prev_rp);
cleanup_service(rp->r_prev_rp);
rp->r_prev_rp = NULL;
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)) != OK) {
+ printf("RS: warning: unable to clone %s\n", srv_to_string(rp));
+ }
+ }
+
return(OK);
}
return s;
}
- /* Publish process-wide properties. */
- s = publish_process(new_rp);
- if (s != OK) {
- printf("RS: do_update: publish_process failed: %d\n", s);
- return s;
- }
-
/* Link old version to new version and mark both as updating. */
rp->r_new_rp = new_rp;
new_rp->r_old_rp = rp;
char *hz, *buff;
int req_nr;
int c, i, j;
- int c_flag, r_flag, n_flag;
+ int c_flag, r_flag, n_flag, p_flag;
c_flag = 0;
r_flag = 0;
n_flag = 0;
- while (c= getopt(argc, argv, "rcn?"), c != -1)
+ p_flag = 0;
+ while (c= getopt(argc, argv, "rcnp?"), c != -1)
{
switch(c)
{
case 'n':
n_flag = 1;
break;
+ case 'p':
+ p_flag = 1;
+ break;
default:
fprintf(stderr, "%s: getopt failed: %c\n",
argv[ARG_NAME], c);
if(n_flag)
rs_start.rss_flags |= RSS_NOBLOCK;
+ if(p_flag)
+ rs_start.rss_flags |= RSS_REPLICA;
+
if (do_run)
{
/* Set default recovery script for RUN */
/* Definition of the boot image sys table. */
PUBLIC struct boot_image_sys boot_image_sys_table[] = {
/*endpoint, flags */
- { RS_PROC_NR, SRV_SF },
+ { RS_PROC_NR, SRVR_SF },
{ VM_PROC_NR, VM_SF },
- { LOG_PROC_NR, SRVC_SF },
- { MFS_PROC_NR, SF_USE_COPY | SF_NEED_COPY },
- { PFS_PROC_NR, SRVC_SF },
+ { PM_PROC_NR, SRVR_SF },
+ { VFS_PROC_NR, SRVR_SF },
+ { LOG_PROC_NR, SRV_SF | SF_USE_REPL },
+ { MFS_PROC_NR, SF_NEED_COPY | SF_USE_COPY },
+ { PFS_PROC_NR, SRV_SF | SF_USE_COPY },
{ DEFAULT_BOOT_NR, SRV_SF } /* default entry */
};
int r;
message m;
struct rprocpub *rpub;
+ endpoint_t old_endpoint;
rpub = rp->r_pub;
rp->r_flags |= RS_INITIALIZING; /* now initializing */
rp->r_check_tm = rp->r_alive_tm + 1; /* expect reply within period */
+ /* Determine the old endpoint if this is a new instance. */
+ old_endpoint = NONE;
+ if(rp->r_old_rp) {
+ old_endpoint = rp->r_old_rp->r_pub->endpoint;
+ }
+ else if(rp->r_prev_rp) {
+ old_endpoint = rp->r_prev_rp->r_pub->endpoint;
+ }
+
+ /* Send initialization message. */
m.m_type = RS_INIT;
m.RS_INIT_TYPE = type;
m.RS_INIT_RPROCTAB_GID = rinit.rproctab_gid;
+ m.RS_INIT_OLD_ENDPOINT = old_endpoint;
r = asynsend(rpub->endpoint, &m);
return r;
_PROTOTYPE( int vm_isokendpt, (endpoint_t ep, int *proc) );
_PROTOTYPE( int get_stack_ptr, (int proc_nr, vir_bytes *sp) );
_PROTOTYPE( int do_info, (message *) );
+_PROTOTYPE( int swap_proc, (endpoint_t src_e, endpoint_t dst_e) );
/* exit.c */
_PROTOTYPE( void clear_proc, (struct vmproc *vmp) );
#include "util.h"
#include "region.h"
-#define LU_DEBUG 0
-
/*===========================================================================*
* do_rs_set_priv *
*===========================================================================*/
PUBLIC int do_rs_update(message *m_ptr)
{
endpoint_t src_e, dst_e;
- struct vmproc *src_vmp, *dst_vmp;
- struct vmproc orig_src_vmproc, orig_dst_vmproc;
- int src_p, dst_p, r;
- struct vir_region *vr;
+ int r;
src_e = m_ptr->VM_RS_SRC_ENDPT;
dst_e = m_ptr->VM_RS_DST_ENDPT;
return r;
}
- /* Lookup slots for source and destination process. */
- if(vm_isokendpt(src_e, &src_p) != OK) {
- printf("do_rs_update: bad src endpoint %d\n", src_e);
- return EINVAL;
- }
- src_vmp = &vmproc[src_p];
- if(vm_isokendpt(dst_e, &dst_p) != OK) {
- printf("do_rs_update: bad dst endpoint %d\n", dst_e);
- return EINVAL;
- }
- dst_vmp = &vmproc[dst_p];
-
-#if LU_DEBUG
- printf("do_rs_update: updating %d (%d, %d) into %d (%d, %d)\n",
- src_vmp->vm_endpoint, src_p, src_vmp->vm_slot,
- dst_vmp->vm_endpoint, dst_p, dst_vmp->vm_slot);
-
- printf("do_rs_update: map_printmap for source before updating:\n");
- map_printmap(src_vmp);
- printf("do_rs_update: map_printmap for destination before updating:\n");
- map_printmap(dst_vmp);
-#endif
-
- /* Save existing data. */
- orig_src_vmproc = *src_vmp;
- orig_dst_vmproc = *dst_vmp;
-
- /* Swap slots. */
- *src_vmp = orig_dst_vmproc;
- *dst_vmp = orig_src_vmproc;
-
- /* Preserve endpoints and slot numbers. */
- src_vmp->vm_endpoint = orig_src_vmproc.vm_endpoint;
- src_vmp->vm_slot = orig_src_vmproc.vm_slot;
- dst_vmp->vm_endpoint = orig_dst_vmproc.vm_endpoint;
- dst_vmp->vm_slot = orig_dst_vmproc.vm_slot;
-
- /* Preserve vir_region's parents. */
- for(vr = src_vmp->vm_regions; vr; vr = vr->next) {
- vr->parent = src_vmp;
- }
- for(vr = dst_vmp->vm_regions; vr; vr = vr->next) {
- vr->parent = dst_vmp;
- }
-
- /* Adjust page tables. */
- assert(src_vmp->vm_flags & VMF_HASPT);
- assert(dst_vmp->vm_flags & VMF_HASPT);
- pt_bind(&src_vmp->vm_pt, src_vmp);
- pt_bind(&dst_vmp->vm_pt, dst_vmp);
- if((r=sys_vmctl(SELF, VMCTL_FLUSHTLB, 0)) != OK) {
- panic("do_rs_update: VMCTL_FLUSHTLB failed: %d", r);
- }
-
-#if LU_DEBUG
- printf("do_rs_update: updated %d (%d, %d) into %d (%d, %d)\n",
- src_vmp->vm_endpoint, src_p, src_vmp->vm_slot,
- dst_vmp->vm_endpoint, dst_p, dst_vmp->vm_slot);
-
- printf("do_rs_update: map_printmap for source after updating:\n");
- map_printmap(src_vmp);
- printf("do_rs_update: map_printmap for destination after updating:\n");
- map_printmap(dst_vmp);
-#endif
+ /* Do the update in VM now. */
+ r = swap_proc(src_e, dst_e);
- return OK;
+ return r;
}
#include <env.h>
#include <unistd.h>
#include <memory.h>
+#include <assert.h>
#include "proto.h"
#include "glo.h"
#include "util.h"
+#include "region.h"
#include <machine/archtypes.h>
#include "kernel/const.h"
#include "kernel/type.h"
#include "kernel/proc.h"
+#define SWAP_PROC_DEBUG 0
+
/*===========================================================================*
* get_mem_map *
*===========================================================================*/
(vir_bytes) vmp->vm_endpoint, ptr, size);
}
+/*===========================================================================*
+ * swap_proc *
+ *===========================================================================*/
+PUBLIC int swap_proc(endpoint_t src_e, endpoint_t dst_e)
+{
+ struct vmproc *src_vmp, *dst_vmp;
+ struct vmproc orig_src_vmproc, orig_dst_vmproc;
+ int src_p, dst_p, r;
+ struct vir_region *vr;
+
+ /* Lookup slots for source and destination process. */
+ if(vm_isokendpt(src_e, &src_p) != OK) {
+ printf("swap_proc: bad src endpoint %d\n", src_e);
+ return EINVAL;
+ }
+ src_vmp = &vmproc[src_p];
+ if(vm_isokendpt(dst_e, &dst_p) != OK) {
+ printf("swap_proc: bad dst endpoint %d\n", dst_e);
+ return EINVAL;
+ }
+ dst_vmp = &vmproc[dst_p];
+
+#if SWAP_PROC_DEBUG
+ printf("swap_proc: swapping %d (%d, %d) and %d (%d, %d)\n",
+ src_vmp->vm_endpoint, src_p, src_vmp->vm_slot,
+ dst_vmp->vm_endpoint, dst_p, dst_vmp->vm_slot);
+
+ printf("swap_proc: map_printmap for source before swapping:\n");
+ map_printmap(src_vmp);
+ printf("swap_proc: map_printmap for destination before swapping:\n");
+ map_printmap(dst_vmp);
+#endif
+
+ /* Save existing data. */
+ orig_src_vmproc = *src_vmp;
+ orig_dst_vmproc = *dst_vmp;
+
+ /* Swap slots. */
+ *src_vmp = orig_dst_vmproc;
+ *dst_vmp = orig_src_vmproc;
+
+ /* Preserve endpoints and slot numbers. */
+ src_vmp->vm_endpoint = orig_src_vmproc.vm_endpoint;
+ src_vmp->vm_slot = orig_src_vmproc.vm_slot;
+ dst_vmp->vm_endpoint = orig_dst_vmproc.vm_endpoint;
+ dst_vmp->vm_slot = orig_dst_vmproc.vm_slot;
+
+ /* Preserve vir_region's parents. */
+ for(vr = src_vmp->vm_regions; vr; vr = vr->next) {
+ vr->parent = src_vmp;
+ }
+ for(vr = dst_vmp->vm_regions; vr; vr = vr->next) {
+ vr->parent = dst_vmp;
+ }
+
+ /* Adjust page tables. */
+ assert(src_vmp->vm_flags & VMF_HASPT);
+ assert(dst_vmp->vm_flags & VMF_HASPT);
+ pt_bind(&src_vmp->vm_pt, src_vmp);
+ pt_bind(&dst_vmp->vm_pt, dst_vmp);
+ if((r=sys_vmctl(SELF, VMCTL_FLUSHTLB, 0)) != OK) {
+ panic("swap_proc: VMCTL_FLUSHTLB failed: %d", r);
+ }
+
+#if SWAP_PROC_DEBUG
+ printf("swap_proc: swapped %d (%d, %d) and %d (%d, %d)\n",
+ src_vmp->vm_endpoint, src_p, src_vmp->vm_slot,
+ dst_vmp->vm_endpoint, dst_p, dst_vmp->vm_slot);
+
+ printf("swap_proc: map_printmap for source after swapping:\n");
+ map_printmap(src_vmp);
+ printf("swap_proc: map_printmap for destination after swapping:\n");
+ map_printmap(dst_vmp);
+#endif
+
+ return OK;
+}
+