From: Cristiano Giuffrida Date: Tue, 6 Jul 2010 22:05:21 +0000 (+0000) Subject: RS crash recovery support. X-Git-Tag: v3.1.8~272 X-Git-Url: http://zhaoyanbai.com/repos/doc/mandoc_char.7.html?a=commitdiff_plain;h=1f8dbed02971cc9a96319db90b9a2a93ce6fbf87;p=minix.git RS crash recovery support. --- diff --git a/include/minix/com.h b/include/minix/com.h index af0c7d74d..4deb30c20 100644 --- a/include/minix/com.h +++ b/include/minix/com.h @@ -487,7 +487,7 @@ # 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 */ @@ -500,6 +500,7 @@ /* 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 */ @@ -529,6 +530,7 @@ */ #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 */ diff --git a/include/minix/const.h b/include/minix/const.h index a3049eec2..897ef1b41 100644 --- a/include/minix/const.h +++ b/include/minix/const.h @@ -168,14 +168,17 @@ #define PROC_FULLVM 0x100 /* VM sets and manages full pagetable */ /* Bits for s_flags in the privilege structure. */ -#define PREEMPTIBLE 0x02 /* kernel tasks are not preemptible */ -#define BILLABLE 0x04 /* some processes are not billable */ -#define DYN_PRIV_ID 0x08 /* 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 */ diff --git a/include/minix/sef.h b/include/minix/sef.h index 11251ee5d..70c504e78 100644 --- a/include/minix/sef.h +++ b/include/minix/sef.h @@ -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; diff --git a/include/minix/syslib.h b/include/minix/syslib.h index 762a6b181..5cc9670cd 100644 --- a/include/minix/syslib.h +++ b/include/minix/syslib.h @@ -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) ); diff --git a/kernel/debug.c b/kernel/debug.c index 544fcecee..f6b71205f 100644 --- a/kernel/debug.c +++ b/kernel/debug.c @@ -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) diff --git a/kernel/main.c b/kernel/main.c index 99d17b863..b08a52b03 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -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++) { diff --git a/kernel/priv.h b/kernel/priv.h index 1a8c1e9c4..297cc5141 100644 --- a/kernel/priv.h +++ b/kernel/priv.h @@ -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 */ diff --git a/kernel/proto.h b/kernel/proto.h index 53f254ea0..f54f33809 100644 --- a/kernel/proto.h +++ b/kernel/proto.h @@ -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) ); diff --git a/kernel/system.c b/kernel/system.c index 09c3b9bc4..fe45bcbfe 100644 --- a/kernel/system.c +++ b/kernel/system.c @@ -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); diff --git a/kernel/system/do_getinfo.c b/kernel/system/do_getinfo.c index 7d29fb9f3..342ebf83e 100644 --- a/kernel/system/do_getinfo.c +++ b/kernel/system/do_getinfo.c @@ -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: { diff --git a/kernel/system/do_privctl.c b/kernel/system/do_privctl.c index eaefe76bd..a4f4b67b7 100644 --- a/kernel/system/do_privctl.c +++ b/kernel/system/do_privctl.c @@ -15,6 +15,10 @@ #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; is_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; is_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; is_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; is_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; is_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; is_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 */ diff --git a/lib/libsys/panic.c b/lib/libsys/panic.c index 5103fd7af..e8a06ca5e 100644 --- a/lib/libsys/panic.c +++ b/lib/libsys/panic.c @@ -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: "); diff --git a/lib/libsys/sef.c b/lib/libsys/sef.c index 212dd9c9e..a987e06e8 100644 --- a/lib/libsys/sef.c +++ b/lib/libsys/sef.c @@ -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 { diff --git a/lib/libsys/sef_init.c b/lib/libsys/sef_init.c index f06a04e47..87aa73280 100644 --- a/lib/libsys/sef_init.c +++ b/lib/libsys/sef_init.c @@ -1,5 +1,6 @@ #include "syslib.h" #include +#include #include /* 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); diff --git a/lib/libsys/sys_getinfo.c b/lib/libsys/sys_getinfo.c index 7bab35547..bb408d7bb 100644 --- a/lib/libsys/sys_getinfo.c +++ b/lib/libsys/sys_getinfo.c @@ -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; } diff --git a/servers/inet/inet.c b/servers/inet/inet.c index 6a582369c..cf4b5785b 100644 --- a/servers/inet/inet.c +++ b/servers/inet/inet.c @@ -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") && diff --git a/servers/rs/const.h b/servers/rs/const.h index 289a0a4ed..485d7dbf7 100644 --- a/servers/rs/const.h +++ b/servers/rs/const.h @@ -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 */ diff --git a/servers/rs/main.c b/servers/rs/main.c index 98c91db1f..69c7d27cd 100644 --- a/servers/rs/main.c +++ b/servers/rs/main.c @@ -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, diff --git a/servers/rs/manager.c b/servers/rs/manager.c index d0cf9a2fe..d3596e1c9 100644 --- a/servers/rs/manager.c +++ b/servers/rs/manager.c @@ -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;ir_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; } diff --git a/servers/rs/proto.h b/servers/rs/proto.h index c9f950aa2..1d2bb0874 100644 --- a/servers/rs/proto.h +++ b/servers/rs/proto.h @@ -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)); diff --git a/servers/rs/request.c b/servers/rs/request.c index 069b17280..24d8fb72d 100755 --- a/servers/rs/request.c +++ b/servers/rs/request.c @@ -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