]> Zhao Yanbai Git Server - minix.git/commitdiff
RS crash recovery support.
authorCristiano Giuffrida <cristiano@minix3.org>
Tue, 6 Jul 2010 22:05:21 +0000 (22:05 +0000)
committerCristiano Giuffrida <cristiano@minix3.org>
Tue, 6 Jul 2010 22:05:21 +0000 (22:05 +0000)
21 files changed:
include/minix/com.h
include/minix/const.h
include/minix/sef.h
include/minix/syslib.h
kernel/debug.c
kernel/main.c
kernel/priv.h
kernel/proto.h
kernel/system.c
kernel/system/do_getinfo.c
kernel/system/do_privctl.c
lib/libsys/panic.c
lib/libsys/sef.c
lib/libsys/sef_init.c
lib/libsys/sys_getinfo.c
servers/inet/inet.c
servers/rs/const.h
servers/rs/main.c
servers/rs/manager.c
servers/rs/proto.h
servers/rs/request.c

index af0c7d74d960cfef81c70de382fba188e724ed97..4deb30c201e46a201fc2b750bb31ad6cecc0056b 100644 (file)
 #   define GET_IRQACTIDS  16   /* get the IRQ masks */
 #   define GET_PRIV      17    /* get privilege structure */
 #   define GET_HZ        18    /* get HZ value */
-#   define GET_WHOAMI    19    /* get own name and endpoint */
+#   define GET_WHOAMI    19    /* get own name, endpoint, and privileges */
 #   define GET_RANDOMNESS_BIN 20 /* get one randomness bin */
 #   define GET_IDLETSC   21    /* get cumulative idle time stamp counter */
 #   define GET_AOUTHEADER 22    /* get a.out headers from the boot image */
 /* GET_WHOAMI fields. */
 #define GIWHO_EP       m3_i1
 #define GIWHO_NAME     m3_ca1
+#define GIWHO_PRIVFLAGS        m3_i2
 
 /* Field names for SYS_TIMES. */
 #define T_ENDPT                m4_l1   /* process to request time info for */
                                         */
 #define SYS_PRIV_ADD_IRQ       7       /* Add IRQ */
 #define SYS_PRIV_QUERY_MEM     8       /* Verify memory privilege. */
+#define SYS_PRIV_UPDATE_SYS    9       /* Update a sys privilege structure. */
 
 /* Field names for SYS_SETGRANT */
 #define SG_ADDR                m2_p1   /* address */
index a3049eec20e7fcc2b613fcd87c3df89faaa3d7bc..897ef1b41233f447e84e12099d9554e83a34e937 100644 (file)
 #define PROC_FULLVM    0x100    /* VM sets and manages full pagetable */
 
 /* Bits for s_flags in the privilege structure. */
-#define PREEMPTIBLE     0x0   /* kernel tasks are not preemptible */
-#define BILLABLE        0x0   /* some processes are not billable */
-#define DYN_PRIV_ID     0x0   /* privilege id assigned dynamically */
+#define PREEMPTIBLE     0x002   /* kernel tasks are not preemptible */
+#define BILLABLE        0x004   /* some processes are not billable */
+#define DYN_PRIV_ID     0x008   /* privilege id assigned dynamically */
  
-#define SYS_PROC        0x10    /* system processes have own priv structure */
-#define CHECK_IO_PORT   0x20    /* check if I/O request is allowed */
-#define CHECK_IRQ       0x40    /* check if IRQ can be used */
-#define CHECK_MEM       0x80    /* check if (VM) mem map request is allowed */
+#define SYS_PROC        0x010   /* system processes have own priv structure */
+#define CHECK_IO_PORT   0x020   /* check if I/O request is allowed */
+#define CHECK_IRQ       0x040   /* check if IRQ can be used */
+#define CHECK_MEM       0x080   /* check if (VM) mem map request is allowed */
+#define ROOT_SYS_PROC   0x100   /* this is a root system process instance */
+#define LU_SYS_PROC     0x200   /* this is a live updated sys proc instance */
+#define RST_SYS_PROC    0x400   /* this is a restarted sys proc instance */
 
 /* Bits for device driver flags managed by RS and VFS. */
 #define DRV_FORCED      0x01    /* driver is mapped even if not alive yet */
index 11251ee5d6a268b7c6f6211641560abffc6139e7..70c504e786c36078de67af18f688b852fc582dd8 100644 (file)
@@ -29,6 +29,7 @@ _PROTOTYPE( void sef_exit, (int status) );
 /* Type definitions. */
 typedef struct {
     cp_grant_id_t rproctab_gid;
+    endpoint_t endpoint;
     endpoint_t old_endpoint;
 } sef_init_info_t;
 
index 762a6b1814de4943daaa60f90cea8f1ca0759eb4..5cc9670cddacfd4b5780aa15749b4126a5d13800 100644 (file)
@@ -197,7 +197,8 @@ _PROTOTYPE(int sys_segctl, (int *index, u16_t *seg, vir_bytes *off,
 #define sys_getaoutheader(dst,nr) sys_getinfo(GET_AOUTHEADER, dst, 0,0,nr)
 _PROTOTYPE(int sys_getinfo, (int request, void *val_ptr, int val_len,
                                 void *val_ptr2, int val_len2)          );
-_PROTOTYPE(int sys_whoami, (endpoint_t *ep, char *name, int namelen));
+_PROTOTYPE(int sys_whoami, (endpoint_t *ep, char *name, int namelen,
+                                int *priv_flags));
 
 /* Signal control. */
 _PROTOTYPE(int sys_kill, (endpoint_t proc_ep, int sig) );
index 544fcecee7176187d7c01abba3f6cd9fb6241522..f6b71205f986e80e6a01a1a6cd165d3c3fff438f 100644 (file)
@@ -162,40 +162,87 @@ schedulerstr(struct proc *scheduler)
        return "KERNEL";
 }
 
+PRIVATE void
+print_proc_name(struct proc *pp)
+{
+       char *name = pp->p_name;
+       endpoint_t ep = pp->p_endpoint;
+
+       if(name) {
+               printf("%s(%d)", name, ep);
+       }
+       else {
+               printf("%d", ep);
+       }
+}
+
+PRIVATE void
+print_endpoint(endpoint_t ep)
+{
+       int proc_nr;
+       struct proc *pp = NULL;
+
+       switch(ep) {
+       case ANY:
+               printf("ANY");
+       break;
+       case SELF:
+               printf("SELF");
+       break;
+       case NONE:
+               printf("NONE");
+       break;
+       default:
+               if(!isokendpt(ep, &proc_nr)) {
+                       printf("??? %d\n", ep);
+               }
+               else {
+                       pp = proc_addr(proc_nr);
+                       if(isemptyp(pp)) {
+                               printf("??? empty slot %d\n", proc_nr);
+                       }
+                       else {
+                               print_proc_name(pp);
+                       }
+               }
+       break;
+       }
+}
+
+PRIVATE void
+print_sigmgr(struct proc *pp)
+{
+       endpoint_t sig_mgr, bak_sig_mgr;
+       sig_mgr = priv(pp)->s_sig_mgr;
+       bak_sig_mgr = priv(pp)->s_bak_sig_mgr;
+       printf("sigmgr ");
+       print_endpoint(sig_mgr);
+       if(bak_sig_mgr != NONE) {
+               printf(" / ");
+               print_endpoint(bak_sig_mgr);
+       }
+}
+
 PUBLIC void print_proc(struct proc *pp)
 {
        struct proc *depproc = NULL;
        endpoint_t dep;
 
-       printf("%d: %s %d prio %d time %d/%d cycles 0x%x%08x cr3 0x%lx rts %s misc %s sched %s",
+       printf("%d: %s %d prio %d time %d/%d cycles 0x%x%08x cr3 0x%lx rts %s misc %s sched %s ",
                proc_nr(pp), pp->p_name, pp->p_endpoint,
                pp->p_priority, pp->p_user_time,
                pp->p_sys_time, pp->p_cycles.hi, pp->p_cycles.lo, pp->p_seg.p_cr3,
                rtsflagstr(pp->p_rts_flags), miscflagstr(pp->p_misc_flags),
                schedulerstr(pp->p_scheduler));
 
+       print_sigmgr(pp);
+
        dep = P_BLOCKEDON(pp);
        if(dep != NONE) {
                printf(" blocked on: ");
-               if(dep == ANY) {
-                       printf(" ANY\n");
-               } else {
-                       int procno;
-                       if(!isokendpt(dep, &procno)) {
-                               printf(" ??? %d\n", dep);
-                       } else {
-                               depproc = proc_addr(procno);
-                               if(isemptyp(depproc)) {
-                                       printf(" empty slot %d???\n", procno);
-                                       depproc = NULL;
-                               } else {
-                                       printf(" %s\n", depproc->p_name);
-                               }
-                       }
-               }
-       } else {
-               printf("\n");
+               print_endpoint(dep);
        }
+       printf("\n");
 }
 
 PRIVATE void print_proc_depends(struct proc *pp, const int level)
index 99d17b8637feee6385213df34c3c41b8b023d71b..b08a52b0356d379bc8804466bc1acbac4f097b18 100644 (file)
@@ -58,6 +58,8 @@ PUBLIC int main(void)
        sp->s_proc_nr = NONE;                   /* initialize as free */
        sp->s_id = (sys_id_t) i;                /* priv structure index */
        ppriv_addr[i] = sp;                     /* priv ptr from number */
+       sp->s_sig_mgr = NONE;                   /* clear signal managers */
+       sp->s_bak_sig_mgr = NONE;
   }
 
   /* Set up proc table entries for processes in boot image.  The stacks of the
@@ -116,6 +118,7 @@ PUBLIC int main(void)
                 ipc_to_m = RSYS_M;                 /* allowed targets */
                 kcalls = RSYS_KC;                  /* allowed kernel calls */
                 priv(rp)->s_sig_mgr = RSYS_SM;     /* signal manager */
+                priv(rp)->s_bak_sig_mgr = NONE;    /* backup signal manager */
             }
             /* Priviliges for ordinary process. */
             else {
@@ -123,12 +126,7 @@ PUBLIC int main(void)
             }
 
             /* Fill in target mask. */
-            for (j=0; j < NR_SYS_PROCS; j++) {
-                if (ipc_to_m & (1 << j))
-                    set_sendto_bit(rp, j);
-                else
-                    unset_sendto_bit(rp, j);
-           }
+            fill_sendto_mask(rp, ipc_to_m);
 
             /* Fill in kernel call mask. */
             for(j = 0; j < SYS_CALL_MASK_SIZE; j++) {
index 1a8c1e9c4476e882bf7abba66320584b8998fb92..297cc51418eb0a86ace49a377a674270d369cdc4 100644 (file)
@@ -44,6 +44,7 @@ struct priv {
   bitchunk_t s_k_call_mask[SYS_CALL_MASK_SIZE];
 
   endpoint_t s_sig_mgr;                /* signal manager for system signals */
+  endpoint_t s_bak_sig_mgr;    /* backup signal manager for system signals */
   sys_map_t s_notify_pending;          /* bit map with pending notifications */
   irq_id_t s_int_pending;      /* pending hardware interrupts */
   sigset_t s_sig_pending;      /* pending signals */
@@ -130,7 +131,7 @@ EXTERN struct priv *ppriv_addr[NR_SYS_PROCS];       /* direct slot pointers */
                                          * and there is another runnable process
                                          */
 #define TSK_F     (SYS_PROC)                            /* other kernel tasks */
-#define RSYS_F    (SYS_PROC | PREEMPTIBLE)              /* root system proc */
+#define RSYS_F    (SYS_PROC | PREEMPTIBLE | ROOT_SYS_PROC) /* root sys proc */
 #define DEF_SYS_F (RSYS_F | DYN_PRIV_ID)                /* default sys proc */
 
 /* allowed traps */
@@ -152,7 +153,7 @@ EXTERN struct priv *ppriv_addr[NR_SYS_PROCS];       /* direct slot pointers */
 #define DEF_SYS_KC RSYS_KC                              /* default sys proc */
 
 /* signal manager */
-#define RSYS_SM    ROOT_SYS_PROC_NR                     /* root system proc */
+#define RSYS_SM    SELF                                 /* root system proc */
 #define DEF_SYS_SM ROOT_SYS_PROC_NR                     /* default sys proc */
 
 /* scheduler */
index 53f254ea0e0eaa5c0c30296d091e5ef4ba9525bf..f54f33809bfea60e60d889cfba3d498011f9ccd4 100644 (file)
@@ -65,6 +65,7 @@ _PROTOTYPE( char *env_get, (const char *key));
 _PROTOTYPE( int get_priv, (register struct proc *rc, int proc_type)    );
 _PROTOTYPE( void set_sendto_bit, (const struct proc *rc, int id)       );
 _PROTOTYPE( void unset_sendto_bit, (const struct proc *rc, int id)     );
+_PROTOTYPE( void fill_sendto_mask, (const struct proc *rc, int mask)   );
 _PROTOTYPE( void send_sig, (endpoint_t proc_nr, int sig_nr)            );
 _PROTOTYPE( void cause_sig, (proc_nr_t proc_nr, int sig_nr)                    );
 _PROTOTYPE( void sig_delay_done, (struct proc *rp)                     );
index 09c3b9bc40bc12da2b1ae9c4a60a3bbc8f000ceb..fe45bcbfe4faf7e1ee5a95806d2cf8f5fce1c1b2 100644 (file)
@@ -14,6 +14,7 @@
  *   get_priv:         assign privilege structure to user or system process
  *   set_sendto_bit:   allow a process to send messages to a new target
  *   unset_sendto_bit: disallow a process from sending messages to a target
+ *   fill_sendto_mask: fill the target mask of a given process
  *   send_sig:         send a signal directly to a system process
  *   cause_sig:                take action to cause a signal to occur via a signal mgr
  *   sig_delay_done:   tell PM that a process is not sending
@@ -333,19 +334,35 @@ PUBLIC void unset_sendto_bit(const struct proc *rp, int id)
   unset_sys_bit(priv_addr(id)->s_ipc_to, priv_id(rp));
 }
 
+/*===========================================================================*
+ *                           fill_sendto_mask                               *
+ *===========================================================================*/
+PUBLIC void fill_sendto_mask(const struct proc *rp, int mask)
+{
+  int i;
+
+  for (i=0; i < NR_SYS_PROCS; i++) {
+       if (mask & (1 << i))
+               set_sendto_bit(rp, i);
+       else
+               unset_sendto_bit(rp, i);
+  }
+}
+
 /*===========================================================================*
  *                             send_sig                                     *
  *===========================================================================*/
-PUBLIC void send_sig(endpoint_t proc_nr, int sig_nr)
+PUBLIC void send_sig(endpoint_t ep, int sig_nr)
 {
 /* Notify a system process about a signal. This is straightforward. Simply
  * set the signal that is to be delivered in the pending signals map and 
  * send a notification with source SYSTEM.
  */ 
   register struct proc *rp;
+  int proc_nr;
 
-  if(!isokprocn(proc_nr) || isemptyn(proc_nr))
-       panic("send_sig to empty process: %d",  proc_nr);
+  if(!isokendpt(ep, &proc_nr) || isemptyn(proc_nr))
+       panic("send_sig to empty process: %d",  ep);
 
   rp = proc_addr(proc_nr);
   (void) sigaddset(&priv(rp)->s_sig_pending, sig_nr);
@@ -372,19 +389,32 @@ int sig_nr;                       /* signal to be sent */
  * only called when a user process causes a CPU exception and from the kernel 
  * process level, which runs to completion.
  */
-  register struct proc *rp;
+  register struct proc *rp, *sig_mgr_rp;
   endpoint_t sig_mgr;
+  int sig_mgr_proc_nr;
 
   /* Lookup signal manager. */
   rp = proc_addr(proc_nr);
   sig_mgr = priv(rp)->s_sig_mgr;
+  if(sig_mgr == SELF) sig_mgr = rp->p_endpoint;
 
   /* If the target is the signal manager of itself, send the signal directly. */
   if(rp->p_endpoint == sig_mgr) {
        if(SIGS_IS_LETHAL(sig_nr)) {
+           /* If the signal is lethal, see if a backup signal manager exists. */
+           sig_mgr = priv(rp)->s_bak_sig_mgr;
+           if(sig_mgr != NONE && isokendpt(sig_mgr, &sig_mgr_proc_nr)) {
+               priv(rp)->s_sig_mgr = sig_mgr;
+               priv(rp)->s_bak_sig_mgr = NONE;
+               sig_mgr_rp = proc_addr(sig_mgr_proc_nr);
+               RTS_UNSET(sig_mgr_rp, RTS_NO_PRIV);
+               cause_sig(proc_nr, sig_nr); /* try again with the new sig mgr. */
+               return;
+           }
+           /* We are out of luck. Time to panic. */
            proc_stacktrace(rp);
-           panic("cause_sig: signal manager gets lethal signal %d for itself",
-               sig_nr);
+           panic("cause_sig: sig manager %d gets lethal signal %d for itself",
+               rp->p_endpoint, sig_nr);
        }
        (void) sigaddset(&priv(rp)->s_sig_pending, sig_nr);
        send_sig(rp->p_endpoint, SIGKSIGSM);
index 7d29fb9f31603a385c206ffaf74dcdb49870be58..342ebf83e15d5b177e47fee5313d95b9dbc0daf3 100644 (file)
@@ -96,6 +96,7 @@ PUBLIC int do_getinfo(struct proc * caller, message * m_ptr)
        len = MIN(sizeof(m_ptr->GIWHO_NAME), sizeof(caller->p_name))-1;
        strncpy(m_ptr->GIWHO_NAME, caller->p_name, len);
        m_ptr->GIWHO_NAME[len] = '\0';
+       m_ptr->GIWHO_PRIVFLAGS = priv(caller)->s_flags;
        return OK;
     }
     case GET_MONPARAMS: {
index eaefe76bdd316f27a3c329a804899d6f2cc52000..a4f4b67b7f5b81468258e81671437ec4197f7ac4 100644 (file)
 
 #if USE_PRIVCTL
 
+#define PRIV_DEBUG 0
+
+FORWARD _PROTOTYPE(int update_priv, (struct proc *rp, struct priv *priv));
+
 /*===========================================================================*
  *                             do_privctl                                   *
  *===========================================================================*/
@@ -107,13 +111,15 @@ PUBLIC int do_privctl(struct proc * caller, message * m_ptr)
        priv(rp)->s_flags= DEF_SYS_F;           /* privilege flags */
        priv(rp)->s_trap_mask= DEF_SYS_T;       /* allowed traps */
        ipc_to_m = DEF_SYS_M;                   /* allowed targets */
+       fill_sendto_mask(rp, ipc_to_m);
        kcalls = DEF_SYS_KC;                    /* allowed kernel calls */
        for(i = 0; i < SYS_CALL_MASK_SIZE; i++) {
                priv(rp)->s_k_call_mask[i] = (kcalls == NO_C ? 0 : (~0));
        }
 
-       /* Set the default signal manager. */
+       /* Set the default signal managers. */
        priv(rp)->s_sig_mgr = DEF_SYS_SM;
+       priv(rp)->s_bak_sig_mgr = NONE;
 
        /* Set defaults for resources: no I/O resources, no memory resources,
         * no IRQs, no grant table
@@ -127,76 +133,9 @@ PUBLIC int do_privctl(struct proc * caller, message * m_ptr)
        /* Override defaults if the caller has supplied a privilege structure. */
        if (m_ptr->CTL_ARG_PTR)
        {
-               /* Copy s_flags and signal manager. */
-               priv(rp)->s_flags = priv.s_flags;
-               priv(rp)->s_sig_mgr = priv.s_sig_mgr;
-
-               /* Copy IRQs */
-               if(priv.s_flags & CHECK_IRQ) {
-                       if (priv.s_nr_irq < 0 || priv.s_nr_irq > NR_IRQ)
-                               return EINVAL;
-                       priv(rp)->s_nr_irq= priv.s_nr_irq;
-                       for (i= 0; i<priv.s_nr_irq; i++)
-                       {
-                               priv(rp)->s_irq_tab[i]= priv.s_irq_tab[i];
-#if 0
-                               printf("do_privctl: adding IRQ %d for %d\n",
-                                       priv(rp)->s_irq_tab[i], rp->p_endpoint);
-#endif
-                       }
-               }
-
-               /* Copy I/O ranges */
-               if(priv.s_flags & CHECK_IO_PORT) {
-                       if (priv.s_nr_io_range < 0 || priv.s_nr_io_range > NR_IO_RANGE)
-                               return EINVAL;
-                       priv(rp)->s_nr_io_range= priv.s_nr_io_range;
-                       for (i= 0; i<priv.s_nr_io_range; i++)
-                       {
-                               priv(rp)->s_io_tab[i]= priv.s_io_tab[i];
-#if 0
-                               printf("do_privctl: adding I/O range [%x..%x] for %d\n",
-                                       priv(rp)->s_io_tab[i].ior_base,
-                                       priv(rp)->s_io_tab[i].ior_limit,
-                                       rp->p_endpoint);
-#endif
-                       }
-               }
-
-               /* Copy memory ranges */
-               if(priv.s_flags & CHECK_MEM) {
-                       if (priv.s_nr_mem_range < 0 || priv.s_nr_mem_range > NR_MEM_RANGE)
-                               return EINVAL;
-                       priv(rp)->s_nr_mem_range= priv.s_nr_mem_range;
-                       for (i= 0; i<priv.s_nr_mem_range; i++)
-                       {
-                               priv(rp)->s_mem_tab[i]= priv.s_mem_tab[i];
-#if 0
-                               printf("do_privctl: adding mem range [%x..%x] for %d\n",
-                                       priv(rp)->s_mem_tab[i].mr_base,
-                                       priv(rp)->s_mem_tab[i].mr_limit,
-                                       rp->p_endpoint);
-#endif
-                       }
-               }
-
-               /* Copy trap mask. */
-               priv(rp)->s_trap_mask = priv.s_trap_mask;
-
-               /* Copy target mask. */
-               memcpy(&ipc_to_m, &priv.s_ipc_to, sizeof(ipc_to_m));
-
-               /* Copy kernel call mask. */
-               memcpy(priv(rp)->s_k_call_mask, priv.s_k_call_mask,
-                       sizeof(priv(rp)->s_k_call_mask));
-       }
-
-       /* Fill in target mask. */
-       for (i=0; i < NR_SYS_PROCS; i++) {
-               if (ipc_to_m & (1 << i))
-                       set_sendto_bit(rp, i);
-               else
-                       unset_sendto_bit(rp, i);
+               if((r = update_priv(rp, &priv)) != OK) {
+                       return r;
+               } 
        }
 
        return(OK);
@@ -316,11 +255,105 @@ PUBLIC int do_privctl(struct proc * caller, message * m_ptr)
        }
        return EPERM;
   }
+
+  case SYS_PRIV_UPDATE_SYS:
+       /* Update the privilege structure of a system process. */
+       if(!m_ptr->CTL_ARG_PTR) return EINVAL;
+
+       /* Copy privilege structure from caller */
+       if((r=data_copy(caller->p_endpoint, (vir_bytes) m_ptr->CTL_ARG_PTR,
+               KERNEL, (vir_bytes) &priv, sizeof(priv))) != OK)
+               return r;
+
+       /* Override settings in existing privilege structure. */
+       if((r = update_priv(rp, &priv)) != OK) {
+               return r;
+       }
+
+       return(OK);
+
   default:
        printf("do_privctl: bad request %d\n", m_ptr->CTL_REQUEST);
        return EINVAL;
   }
 }
 
+/*===========================================================================*
+ *                             update_priv                                  *
+ *===========================================================================*/
+PRIVATE int update_priv(struct proc *rp, struct priv *priv)
+{
+/* Update the privilege structure of a given process. */
+
+  int ipc_to_m, i;
+
+  /* Copy s_flags and signal managers. */
+  priv(rp)->s_flags = priv->s_flags;
+  priv(rp)->s_sig_mgr = priv->s_sig_mgr;
+  priv(rp)->s_bak_sig_mgr = priv->s_bak_sig_mgr;
+
+  /* Copy IRQs. */
+  if(priv->s_flags & CHECK_IRQ) {
+       if (priv->s_nr_irq < 0 || priv->s_nr_irq > NR_IRQ)
+               return EINVAL;
+       priv(rp)->s_nr_irq= priv->s_nr_irq;
+       for (i= 0; i<priv->s_nr_irq; i++)
+       {
+               priv(rp)->s_irq_tab[i]= priv->s_irq_tab[i];
+#if PRIV_DEBUG
+               printf("do_privctl: adding IRQ %d for %d\n",
+                       priv(rp)->s_irq_tab[i], rp->p_endpoint);
+#endif
+       }
+  }
+
+  /* Copy I/O ranges. */
+  if(priv->s_flags & CHECK_IO_PORT) {
+       if (priv->s_nr_io_range < 0 || priv->s_nr_io_range > NR_IO_RANGE)
+               return EINVAL;
+       priv(rp)->s_nr_io_range= priv->s_nr_io_range;
+       for (i= 0; i<priv->s_nr_io_range; i++)
+       {
+               priv(rp)->s_io_tab[i]= priv->s_io_tab[i];
+#if PRIV_DEBUG
+               printf("do_privctl: adding I/O range [%x..%x] for %d\n",
+                       priv(rp)->s_io_tab[i].ior_base,
+                       priv(rp)->s_io_tab[i].ior_limit,
+                       rp->p_endpoint);
+#endif
+       }
+  }
+
+  /* Copy memory ranges. */
+  if(priv->s_flags & CHECK_MEM) {
+       if (priv->s_nr_mem_range < 0 || priv->s_nr_mem_range > NR_MEM_RANGE)
+               return EINVAL;
+       priv(rp)->s_nr_mem_range= priv->s_nr_mem_range;
+       for (i= 0; i<priv->s_nr_mem_range; i++)
+       {
+               priv(rp)->s_mem_tab[i]= priv->s_mem_tab[i];
+#if PRIV_DEBUG
+               printf("do_privctl: adding mem range [%x..%x] for %d\n",
+                       priv(rp)->s_mem_tab[i].mr_base,
+                       priv(rp)->s_mem_tab[i].mr_limit,
+                       rp->p_endpoint);
+#endif
+       }
+  }
+
+  /* Copy trap mask. */
+  priv(rp)->s_trap_mask = priv->s_trap_mask;
+
+  /* Copy target mask. */
+  memcpy(&ipc_to_m, &priv->s_ipc_to, sizeof(ipc_to_m));
+  fill_sendto_mask(rp, ipc_to_m);
+
+  /* Copy kernel call mask. */
+  memcpy(priv(rp)->s_k_call_mask, priv->s_k_call_mask,
+       sizeof(priv(rp)->s_k_call_mask));
+
+  return OK;
+}
+
 #endif /* USE_PRIVCTL */
 
index 5103fd7af2f28b6965234429c089626b79298c9e..e8a06ca5ed6f85c1e78119abeaa0d8b0794efb7b 100644 (file)
@@ -17,10 +17,11 @@ PUBLIC void panic(const char *fmt, ...)
  */
   endpoint_t me = NONE;
   char name[20];
+  int priv_flags;
   void (*suicide)(void);
   va_list args;
 
-  if(sys_whoami(&me, name, sizeof(name)) == OK && me != NONE)
+  if(sys_whoami(&me, name, sizeof(name), &priv_flags) == OK && me != NONE)
        printf("%s(%d): panic: ", name, me);
   else
        printf("(sys_whoami failed): panic: ");
index 212dd9c9e8b3cb10d2fab8e8bbfb1b437725bfc2..a987e06e8c8da55050e3f988154c3924b8e2f488 100644 (file)
@@ -7,6 +7,7 @@
 #define SEF_SELF_NAME_MAXLEN 20
 PUBLIC char sef_self_name[SEF_SELF_NAME_MAXLEN];
 PUBLIC endpoint_t sef_self_endpoint;
+PUBLIC int sef_self_priv_flags;
 
 /* Debug. */
 #define SEF_DEBUG_HEADER_MAXLEN 32
@@ -19,7 +20,7 @@ FORWARD _PROTOTYPE( void sef_debug_refresh_params, (void) );
 PUBLIC _PROTOTYPE( char* sef_debug_header, (void) );
 
 /* SEF Init prototypes. */
-EXTERN _PROTOTYPE( int do_sef_rs_init, (void) );
+EXTERN _PROTOTYPE( int do_sef_rs_init, (endpoint_t old_endpoint) );
 EXTERN _PROTOTYPE( int do_sef_init_request, (message *m_ptr) );
 
 /* SEF Ping prototypes. */
@@ -39,20 +40,34 @@ PUBLIC void sef_startup()
 {
 /* SEF startup interface for system services. */
   int r, status;
+  endpoint_t old_endpoint;
 
   /* Get information about self. */
-  r = sys_whoami(&sef_self_endpoint, sef_self_name, SEF_SELF_NAME_MAXLEN);
+  r = sys_whoami(&sef_self_endpoint, sef_self_name, SEF_SELF_NAME_MAXLEN,
+      &sef_self_priv_flags);
   if ( r != OK) {
       sef_self_endpoint = SELF;
       sprintf(sef_self_name, "%s", "Unknown");
   }
+  old_endpoint = NONE;
+
+  /* RS may wake up with the wrong endpoint, perfom the update in that case. */
+  if((sef_self_priv_flags & ROOT_SYS_PROC) && sef_self_endpoint != RS_PROC_NR) {
+      r = vm_update(RS_PROC_NR, sef_self_endpoint);
+      if(r != OK) {
+          panic("unable to update RS from instance %d to %d",
+              RS_PROC_NR, sef_self_endpoint);
+      }
+      old_endpoint = sef_self_endpoint;
+      sef_self_endpoint = RS_PROC_NR;
+  }
 
 #if INTERCEPT_SEF_INIT_REQUESTS
   /* Intercept SEF Init requests. */
-  if(sef_self_endpoint == RS_PROC_NR) {
+  if(sef_self_priv_flags & ROOT_SYS_PROC) {
       /* RS initialization is special. */
-      if((r = do_sef_rs_init()) != OK) {
-          panic("unable to complete init: %d", r);
+      if((r = do_sef_rs_init(old_endpoint)) != OK) {
+          panic("RS unable to complete init: %d (%s)", r, strerror(-r));
       }
   }
   else {
index f06a04e471bb3d473012f69036418c90bceceb11..87aa7328015998d6790d66acc74bedcb4e284d56 100644 (file)
@@ -1,5 +1,6 @@
 #include "syslib.h"
 #include <assert.h>
+#include <unistd.h>
 #include <minix/sysutil.h>
 
 /* SEF Init callbacks. */
@@ -14,52 +15,42 @@ PRIVATE struct sef_cbs {
 };
 
 /* SEF Init prototypes for sef_startup(). */
-PUBLIC _PROTOTYPE( int do_sef_rs_init, (void) );
+PUBLIC _PROTOTYPE( int do_sef_rs_init, (endpoint_t old_endpoint) );
 PUBLIC _PROTOTYPE( int do_sef_init_request, (message *m_ptr) );
 
 /* Debug. */
 EXTERN _PROTOTYPE( char* sef_debug_header, (void) );
 
-/*===========================================================================*
- *                              do_sef_rs_init                              *
- *===========================================================================*/
-PUBLIC int do_sef_rs_init()
-{
-/* Special SEF Init for RS. */
-  return sef_cbs.sef_cb_init_fresh(SEF_INIT_FRESH, NULL);
-}
+/* Information about SELF. */
+EXTERN endpoint_t sef_self_endpoint;
+EXTERN endpoint_t sef_self_priv_flags;
 
 /*===========================================================================*
- *                            do_sef_init_request                           *
+ *                              process_init                                *
  *===========================================================================*/
-PUBLIC int do_sef_init_request(message *m_ptr)
+PRIVATE int process_init(int type, sef_init_info_t *info)
 {
-/* Handle a SEF Init request. */
+/* Process initialization. */
   int r;
-  int type;
-  sef_init_info_t info;
 
   /* Debug. */
 #if SEF_INIT_DEBUG
   sef_init_debug_begin();
   sef_init_dprint("%s. Got a SEF Init request of type: %d. About to init.\n",
-      sef_debug_header(), m_ptr->RS_INIT_TYPE);
+      sef_debug_header(), type);
   sef_init_debug_end();
 #endif
 
-  /* 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;
+  /* Let the callback code handle the specific initialization type. */
   switch(type) {
       case SEF_INIT_FRESH:
-          r = sef_cbs.sef_cb_init_fresh(type, &info);
+          r = sef_cbs.sef_cb_init_fresh(type, info);
       break;
       case SEF_INIT_LU:
-          r = sef_cbs.sef_cb_init_lu(type, &info);
+          r = sef_cbs.sef_cb_init_lu(type, info);
       break;
       case SEF_INIT_RESTART:
-          r = sef_cbs.sef_cb_init_restart(type, &info);
+          r = sef_cbs.sef_cb_init_restart(type, info);
       break;
 
       default:
@@ -68,6 +59,56 @@ PUBLIC int do_sef_init_request(message *m_ptr)
       break;
   }
 
+  return r;
+}
+
+/*===========================================================================*
+ *                              do_sef_rs_init                              *
+ *===========================================================================*/
+PUBLIC int do_sef_rs_init(endpoint_t old_endpoint)
+{
+/* Special SEF Init for RS. */
+  int r;
+  int type;
+  sef_init_info_t info;
+
+  /* Get init parameters from SEF. */
+  type = SEF_INIT_FRESH;
+  if(sef_self_priv_flags & LU_SYS_PROC) {
+      type = SEF_INIT_LU;
+  }
+  else if(sef_self_priv_flags & RST_SYS_PROC) {
+      type = SEF_INIT_RESTART;
+  }
+  info.rproctab_gid = -1;
+  info.endpoint = sef_self_endpoint;
+  info.old_endpoint = old_endpoint;
+
+  /* Peform initialization. */
+  r = process_init(type, &info);
+
+  return r;
+}
+
+/*===========================================================================*
+ *                            do_sef_init_request                           *
+ *===========================================================================*/
+PUBLIC int do_sef_init_request(message *m_ptr)
+{
+/* Handle a SEF Init request. */
+  int r;
+  int type;
+  sef_init_info_t info;
+
+  /* Get init parameters from message. */
+  type = m_ptr->RS_INIT_TYPE;
+  info.rproctab_gid = m_ptr->RS_INIT_RPROCTAB_GID;
+  info.endpoint = sef_self_endpoint;
+  info.old_endpoint = m_ptr->RS_INIT_OLD_ENDPOINT;
+
+  /* Peform initialization. */
+  r = process_init(type, &info);
+
   /* Report back to RS. */
   m_ptr->RS_INIT_RESULT = r;
   r = sendrec(RS_PROC_NR, m_ptr);
index 7bab35547d72ac9c99938855362cb618b034f4f6..bb408d7bbd2bdc06b2392aa321b9ed0173fdf8c6 100644 (file)
@@ -28,7 +28,8 @@ int len2;                             /* length or process nr */
 /*===========================================================================*
  *                                sys_whoami                                *
  *===========================================================================*/
-PUBLIC int sys_whoami(endpoint_t *who_ep, char *who_name, int len)
+PUBLIC int sys_whoami(endpoint_t *who_ep, char *who_name, int len,
+       int *priv_flags)
 {
        message m;
        int r;
@@ -47,6 +48,7 @@ PUBLIC int sys_whoami(endpoint_t *who_ep, char *who_name, int len)
        strncpy(who_name, m.GIWHO_NAME, lenmin);
        who_name[lenmin] = '\0';
        *who_ep = m.GIWHO_EP;
+       *priv_flags = m.GIWHO_PRIVFLAGS;
 
        return OK;
 }
index 6a582369c75fbb4f0aa884e44951aa8471e36e48..cf4b5785b7003303be8b1ce8f51ff58b940ed5a7 100644 (file)
@@ -206,10 +206,8 @@ PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info)
 /* Initialize the inet server. */
        int r;
        int timerand, fd;
-       endpoint_t tasknr;
        u8_t randbits[32];
        struct timeval tv;
-       char my_name[32];
 
 #if DEBUG
        printf("Starting inet...\n");
@@ -258,10 +256,7 @@ PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info)
        init_rand256(randbits);
 
        /* Our new identity as a server. */
-       r = sys_whoami(&tasknr, my_name, sizeof(my_name));
-       if (r != OK)
-               ip_panic(("inet: sys_whoami failed for 'inet': %d", r));
-       this_proc= tasknr;
+       this_proc= info->endpoint;
 
 #ifdef BUF_CONSISTENCY_CHECK
        inet_buf_debug= (getenv("inetbufdebug") && 
index 289a0a4edaf53d67fa7f25952cef69ca11d4305c..485d7dbf793e5428ef9505b81997899b17e1739f 100644 (file)
@@ -93,5 +93,9 @@
 #define SRV_DF   (DRV_FORCED)            /* system services */
 #define DSRV_DF  (SRV_DF)                /* dynamic system services */
 
+/* Reply flags. */
+#define RS_DONTREPLY    0
+#define RS_REPLY        1
+
 #endif /* RS_CONST_H */
 
index 98c91db1fe52658840879feba64b243f966bf24f..69c7d27cd7a5446c082139e46dd5554f1d9b1425 100644 (file)
@@ -138,7 +138,8 @@ PUBLIC int main(void)
 PRIVATE void sef_local_startup()
 {
   /* Register init callbacks. */
-  sef_setcb_init_fresh(sef_cb_init_fresh);     /* RS can only start fresh. */
+  sef_setcb_init_fresh(sef_cb_init_fresh);
+  sef_setcb_init_restart(sef_cb_init_fail);
 
   /* Register signal callbacks. */
   sef_setcb_signal_handler(sef_cb_signal_handler);
@@ -262,6 +263,7 @@ PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info)
       memcpy(&rp->r_priv.s_ipc_to, &boot_image_priv->ipc_to,
                         sizeof(rp->r_priv.s_ipc_to));      /* targets */
       rp->r_priv.s_sig_mgr = boot_image_priv->sig_mgr;     /* sig mgr */
+      rp->r_priv.s_bak_sig_mgr = NONE;                     /* backup sig mgr */
       
       /* Initialize kernel call mask bitmap from unordered set. */
       fill_call_mask(boot_image_priv->k_calls, NR_SYS_CALLS,
index d0cf9a2fe8b2d5d4be18555db5a1de080a9995f3..d3596e1c9e3c75228bc08bcd90fde013b4bbd1bb 100644 (file)
@@ -100,9 +100,9 @@ struct rproc *rp;
           return EPERM;
       }
 
-      /* Only allow RS_EDIT for RS. */
+      /* Disallow RS_UPDATE for RS. */
       if(rpub->endpoint == RS_PROC_NR) {
-          if(call != RS_EDIT) return EPERM;
+          if(call == RS_UPDATE) return EPERM;
       }
 
       /* Disallow the call if another call is in progress for the service. */
@@ -273,7 +273,7 @@ PUBLIC void update_period(message *m_ptr)
    */
   if(has_update_timed_out) {
       printf("RS: update failed: maximum prepare time reached\n");
-      end_update(EINTR);
+      end_update(EINTR, RS_DONTREPLY);
 
       /* Prepare cancel request. */
       m.m_type = RS_LU_PREPARE;
@@ -285,7 +285,7 @@ PUBLIC void update_period(message *m_ptr)
 /*===========================================================================*
  *                             end_update                                   *
  *===========================================================================*/
-PUBLIC void end_update(int result)
+PUBLIC void end_update(int result, int reply_flag)
 {
 /* End the update process. There are two possibilities:
  * 1) the update succeeded. In that case, cleanup the old version and mark the
@@ -321,10 +321,19 @@ PUBLIC void end_update(int result)
   /* Send a late reply if necessary. */
   late_reply(old_rp, result);
 
-  /* Cleanup the version that has to die out and mark the other
-   * version as no longer updating.
+  /* Mark the version that has to survive as no longer updating and
+   * reply when asked to.
    */
   surviving_rp->r_flags &= ~RS_UPDATING;
+  if(reply_flag == RS_REPLY) {
+      message m;
+      if(rs_verbose)
+          printf("RS: %s being replied to\n", srv_to_string(surviving_rp));
+      m.m_type = result;
+      reply(surviving_rp->r_pub->endpoint, &m);
+  }
+
+  /* Cleanup the version that has to die out. */
   get_service_instances(exiting_rp, &rps, &nr_rps);
   for(i=0;i<nr_rps;i++) {
       cleanup_service(rps[i]);
@@ -371,6 +380,11 @@ struct rproc *rp;
       printf("RS: %s %skilled at %s:%d\n", srv_to_string(rp),
           rp->r_flags & RS_EXITING ? "lethally " : "", file, line);
 
+  /* RS should simply exit() directly. */
+  if(rpub->endpoint == RS_PROC_NR) {
+      exit(0);
+  }
+
   return sys_kill(rpub->endpoint, SIGKILL);
 }
 
@@ -552,12 +566,17 @@ struct rproc *rp;
 /*===========================================================================*
  *                             clone_service                                *
  *===========================================================================*/
-PUBLIC int clone_service(rp)
+PUBLIC int clone_service(rp, instance_flag)
 struct rproc *rp;
+int instance_flag;
 {
 /* Clone the given system service instance. */
   struct rproc *replica_rp;
   struct rprocpub *replica_rpub;
+  struct rproc **rp_link;
+  struct rproc **replica_link;
+  struct rproc *rs_rp;
+  int rs_flags;
   int r;
 
   if(rs_verbose)
@@ -568,14 +587,25 @@ struct rproc *rp;
       return r;
   }
 
+  /* Clone is a live updated or restarted service instance? */
+  if(instance_flag == LU_SYS_PROC) {
+      rp_link = &rp->r_new_rp;
+      replica_link = &replica_rp->r_old_rp;
+  }
+  else {
+      rp_link = &rp->r_next_rp;
+      replica_link = &replica_rp->r_prev_rp;
+  }
+  replica_rp->r_priv.s_flags |= instance_flag;
+
   /* Link the two slots. */
-  rp->r_next_rp = replica_rp;
-  replica_rp->r_prev_rp = rp;
+  *rp_link = replica_rp;
+  *replica_link = rp;
 
   /* Create a new replica of the service. */
   r = create_service(replica_rp);
   if(r != OK) {
-      rp->r_next_rp = NULL;
+      *rp_link = NULL;
       return r;
   }
 
@@ -584,11 +614,32 @@ struct rproc *rp;
   if(replica_rpub->vm_call_mask[0]) {
       r = vm_set_priv(replica_rpub->endpoint, &replica_rpub->vm_call_mask[0]);
       if (r != OK) {
-          rp->r_next_rp = NULL;
+          *rp_link = NULL;
           return kill_service(replica_rp, "vm_set_priv call failed", r);
       }
   }
 
+  /* If this instance is for restarting RS, set up a backup signal manager. */
+  rs_flags = (ROOT_SYS_PROC | RST_SYS_PROC);
+  if((replica_rp->r_priv.s_flags & rs_flags) == rs_flags) {
+      rs_rp = rproc_ptr[_ENDPOINT_P(RS_PROC_NR)];
+      if(rs_verbose)
+          printf("RS: %s gets a backup signal manager\n", srv_to_string(rs_rp));
+
+      /* Update privilege structures. */
+      rs_rp->r_priv.s_bak_sig_mgr = replica_rpub->endpoint;
+      replica_rp->r_priv.s_sig_mgr = SELF;
+      r = sys_privctl(RS_PROC_NR, SYS_PRIV_UPDATE_SYS, &rs_rp->r_priv);
+      if(r == OK) {
+          r = sys_privctl(replica_rpub->endpoint, SYS_PRIV_UPDATE_SYS,
+              &replica_rp->r_priv);
+      }
+      if(r != OK) {
+          *rp_link = NULL;
+          return kill_service(replica_rp, "sys_privctl call failed", r);
+      }
+  }
+
   return OK;
 }
 
@@ -756,6 +807,7 @@ struct rproc *rp;
 PUBLIC void stop_service(struct rproc *rp,int how)
 {
   struct rprocpub *rpub;
+  int signo;
 
   rpub = rp->r_pub;
 
@@ -767,8 +819,10 @@ PUBLIC void stop_service(struct rproc *rp,int how)
   if(rs_verbose)
       printf("RS: %s signaled with SIGTERM\n", srv_to_string(rp));
 
+  signo = rpub->endpoint != RS_PROC_NR ? SIGTERM : SIGHUP; /* SIGHUP for RS. */
+
   rp->r_flags |= how;                          /* what to on exit? */
-  sys_kill(rpub->endpoint, SIGTERM);           /* first try friendly */
+  sys_kill(rpub->endpoint, signo);             /* first try friendly */
   getuptime(&rp->r_stop_tm);                   /* record current time */
 }
 
@@ -874,16 +928,13 @@ PUBLIC void terminate_service(struct rproc *rp)
 
       /* If updating, rollback. */
       if(rp->r_flags & RS_UPDATING) {
-          message m;
           struct rproc *old_rp, *new_rp;
           printf("RS: update failed: state transfer failed. Rolling back...\n");
           new_rp = rp;
           old_rp = new_rp->r_old_rp;
           new_rp->r_flags &= ~RS_INITIALIZING;
           update_service(&new_rp, &old_rp); /* can't fail */
-          m.m_type = ERESTART;
-          reply(old_rp->r_pub->endpoint, &m);
-          end_update(ERESTART);
+          end_update(ERESTART, RS_REPLY);
           return;
       }
   }
@@ -916,7 +967,7 @@ PUBLIC void terminate_service(struct rproc *rp)
        * that just exited will continue executing.
        */
       if(rp->r_flags & RS_UPDATING) {
-          end_update(ERESTART);
+          end_update(ERESTART, RS_DONTREPLY);
       }
 
       /* Determine what to do. If this is the first unexpected 
@@ -1012,7 +1063,7 @@ PUBLIC void restart_service(struct rproc *rp)
   /* Restart directly. We need a replica if not already available. */
   if(rp->r_next_rp == NULL) {
       /* Create the replica. */
-      r = clone_service(rp);
+      r = clone_service(rp, RST_SYS_PROC);
       if(r != OK) {
           kill_service(rp, "unable to clone service", r);
           return;
@@ -1061,6 +1112,9 @@ struct rproc *rp;
   rpub->dev_style = def_rpub->dev_style;
   rpub->dev_style2 = def_rpub->dev_style2;
 
+  /* Service type flags. */
+  rp->r_priv.s_flags |= rp->r_priv.s_flags & ROOT_SYS_PROC;
+
   /* Period. */
   if(!rp->r_period && def_rp->r_period) {
       rp->r_period = def_rp->r_period;
@@ -1327,6 +1381,7 @@ endpoint_t source;
   rp->r_priv.s_flags = DSRV_F;           /* privilege flags */
   rp->r_priv.s_trap_mask = DSRV_T;       /* allowed traps */
   rp->r_priv.s_sig_mgr = DSRV_SM;        /* signal manager */
+  rp->r_priv.s_bak_sig_mgr = NONE;       /* backup signal manager */
 
   /* Initialize control labels. */
   if(rs_start->rss_nr_control > 0) {
@@ -1522,6 +1577,9 @@ struct rproc **clone_rpp;
   /* Force dynamic privilege id. */
   clone_rp->r_priv.s_flags |= DYN_PRIV_ID;
 
+  /* Clear instance flags. */
+  clone_rp->r_priv.s_flags &= ~(LU_SYS_PROC | RST_SYS_PROC);
+
   *clone_rpp = clone_rp;
   return OK;
 }
index c9f950aa2aaa3d267077ff8d9b5b80325140be5f..1d2bb08746c23b06cf4b67f869f5b1e02da58cae 100644 (file)
@@ -51,7 +51,7 @@ _PROTOTYPE( int crash_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 clone_service, (struct rproc *rp, int instance_flag) );
 _PROTOTYPE( int publish_service, (struct rproc *rp) );
 _PROTOTYPE( int unpublish_service, (struct rproc *rp) );
 _PROTOTYPE( int run_service, (struct rproc *rp, int init_type) );
@@ -85,7 +85,7 @@ _PROTOTYPE( void add_forward_ipc, (struct rproc *rp, struct priv *privp) );
 _PROTOTYPE( void add_backward_ipc, (struct rproc *rp, struct priv *privp) );
 _PROTOTYPE( void init_privs, (struct rproc *rp, struct priv *privp) );
 _PROTOTYPE( void update_period, (message *m_ptr) );
-_PROTOTYPE( void end_update, (int result) );
+_PROTOTYPE( void end_update, (int result, int reply_flag) );
 
 /* utility.c */
 _PROTOTYPE( int init_service, (struct rproc *rp, int type));
index 069b172806d575b34a6f0c4a4aab7818956e905d..24d8fb72d5b8f21a4dee9ff5bdbf3e02389af278 100755 (executable)
@@ -219,7 +219,7 @@ PUBLIC int do_clone(message *m_ptr)
 
   /* Clone the service as requested. */
   rpub->sys_flags |= SF_USE_REPL;
-  if ((r = clone_service(rp)) != OK) {
+  if ((r = clone_service(rp, RST_SYS_PROC)) != OK) {
       rpub->sys_flags &= ~SF_USE_REPL;
       return r;
   }
@@ -280,7 +280,7 @@ PUBLIC int do_edit(message *m_ptr)
           cleanup_service(rp->r_next_rp);
           rp->r_next_rp = NULL;
       }
-      if ((r = clone_service(rp)) != OK) {
+      if ((r = clone_service(rp, RST_SYS_PROC)) != OK) {
           printf("RS: warning: unable to clone %s\n", srv_to_string(rp));
       }
   }
@@ -408,7 +408,7 @@ PUBLIC int do_init_ready(message *m_ptr)
    */
   if(rp->r_flags & RS_UPDATING) {
       printf("RS: update succeeded\n");
-      end_update(OK);
+      end_update(OK, RS_DONTREPLY);
   }
 
   /* If the service has completed initialization after a crash
@@ -424,7 +424,7 @@ PUBLIC int do_init_ready(message *m_ptr)
 
   /* 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) {
+      if ((r = clone_service(rp, RST_SYS_PROC)) != OK) {
           printf("RS: warning: unable to clone %s\n", srv_to_string(rp));
       }
   }
@@ -508,25 +508,15 @@ PUBLIC int do_update(message *m_ptr)
    * by the given binary.
    */
   if(do_self_update) {
-      struct rproc *r_next_rp;
       if(rs_verbose)
           printf("RS: %s performs self update\n", srv_to_string(rp));
 
-      /* Save information about existing replica (if any). */
-      r_next_rp = rp->r_next_rp;
-      rp->r_next_rp = NULL;
-
       /* Clone the system service and use the replica as the new version. */
-      s = clone_service(rp);
+      s = clone_service(rp, LU_SYS_PROC);
       if(s != OK) {
           printf("RS: do_update: unable to clone service: %d\n", s);
           return s;
       }
-      new_rp = rp->r_next_rp;
-      new_rp->r_prev_rp = NULL;
-
-      /* Restore information about existing replica (if any). */
-      rp->r_next_rp = r_next_rp;
   }
   else {
       if(rs_verbose)
@@ -549,7 +539,12 @@ PUBLIC int do_update(message *m_ptr)
       /* 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);
@@ -557,9 +552,7 @@ PUBLIC int do_update(message *m_ptr)
       }
   }
 
-  /* Link old version to new version and mark both as updating. */
-  rp->r_new_rp = new_rp;
-  new_rp->r_old_rp = rp;
+  /* Mark both versions as updating. */
   rp->r_flags |= RS_UPDATING;
   rp->r_new_rp->r_flags |= RS_UPDATING;
   rupdate.flags |= RS_UPDATING;
@@ -614,10 +607,10 @@ PUBLIC int do_upd_ready(message *m_ptr)
    * be replied to and continue executing.
    */
   if(result != OK) {
-      end_update(result);
+      end_update(result, RS_REPLY);
 
       printf("RS: update failed: %s\n", lu_strerror(result));
-      return OK;
+      return EDONTREPLY;
   }
 
   /* Perform the update. */
@@ -625,21 +618,21 @@ PUBLIC int do_upd_ready(message *m_ptr)
   new_rp = rp->r_new_rp;
   r = update_service(&old_rp, &new_rp);
   if(r != OK) {
-      end_update(r);
+      end_update(r, RS_REPLY);
       printf("RS: update failed: error %d\n", r);
-      return r;
+      return EDONTREPLY;
   }
 
   /* Let the new version run. */
   r = run_service(new_rp, SEF_INIT_LU);
   if(r != OK) {
       update_service(&new_rp, &old_rp); /* rollback, can't fail. */
-      end_update(r);
+      end_update(r, RS_REPLY);
       printf("RS: update failed: error %d\n", r);
-      return r;
+      return EDONTREPLY;
   }
 
-  return(EDONTREPLY);
+  return EDONTREPLY;
 }
 
 /*===========================================================================*
@@ -688,8 +681,8 @@ message *m_ptr;
           */
          else if (rp->r_stop_tm > 0 && now - rp->r_stop_tm > 2*RS_DELTA_T
           && rp->r_pid > 0) {
-              crash_service(rp); /* simulate crash */
               rp->r_stop_tm = 0;
+              crash_service(rp); /* simulate crash */
          }
 
          /* There seems to be no special conditions. If the service has a