# 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 */
#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 */
/* Type definitions. */
typedef struct {
cp_grant_id_t rproctab_gid;
+ endpoint_t endpoint;
endpoint_t old_endpoint;
} sef_init_info_t;
#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) );
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)
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
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 {
}
/* 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++) {
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 */
* 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 */
#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 */
_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) );
* 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
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);
* 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);
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: {
#if USE_PRIVCTL
+#define PRIV_DEBUG 0
+
+FORWARD _PROTOTYPE(int update_priv, (struct proc *rp, struct priv *priv));
+
/*===========================================================================*
* do_privctl *
*===========================================================================*/
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
/* 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);
}
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 */
*/
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: ");
#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
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. */
{
/* 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 {
#include "syslib.h"
#include <assert.h>
+#include <unistd.h>
#include <minix/sysutil.h>
/* SEF Init callbacks. */
};
/* 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:
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);
/*===========================================================================*
* 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;
strncpy(who_name, m.GIWHO_NAME, lenmin);
who_name[lenmin] = '\0';
*who_ep = m.GIWHO_EP;
+ *priv_flags = m.GIWHO_PRIVFLAGS;
return OK;
}
/* 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");
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") &&
#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 */
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);
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,
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. */
*/
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;
/*===========================================================================*
* 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
/* 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]);
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);
}
/*===========================================================================*
* 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)
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;
}
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;
}
PUBLIC void stop_service(struct rproc *rp,int how)
{
struct rprocpub *rpub;
+ int signo;
rpub = rp->r_pub;
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 */
}
/* 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;
}
}
* 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
/* 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;
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;
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) {
/* 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;
}
_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) );
_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));
/* 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;
}
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));
}
}
*/
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
/* 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));
}
}
* 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)
/* 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);
}
}
- /* 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;
* 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. */
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;
}
/*===========================================================================*
*/
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