kernel: Handle IPC properly at live update time.

Change-Id: I2dfc6c6cf4d2bfe198e159d3e4b7c50d0bb499c8
This commit is contained in:
Cristiano Giuffrida 2014-03-11 18:06:45 +01:00 committed by David van Moolenbroek
parent 56e56d2af2
commit 062400c0e2
4 changed files with 60 additions and 1 deletions

View file

@ -30,6 +30,7 @@ struct priv {
size_t s_asynsize; /* number of elements in table. 0 when not in
* use
*/
endpoint_t s_asynendpoint; /* the endpoint the asyn table belongs to. */
short s_trap_mask; /* allowed system call traps */
sys_map_t s_ipc_to; /* allowed destination processes */

View file

@ -1153,6 +1153,7 @@ int try_deliver_senda(struct proc *caller_ptr,
/* Clear table */
privp->s_asyntab = -1;
privp->s_asynsize = 0;
privp->s_asynendpoint = caller_ptr->p_endpoint;
if (size == 0) return(OK); /* Nothing to do, just return */
@ -1346,6 +1347,7 @@ static int try_one(endpoint_t receive_e, struct proc *src_ptr,
unset_sys_bit(priv(dst_ptr)->s_asyn_pending, privp->s_id);
if (size == 0) return(EAGAIN);
if (privp->s_asynendpoint != src_ptr->p_endpoint) return EAGAIN;
if (!may_asynsend_to(src_ptr, proc_nr(dst_ptr))) return (ECALLDENIED);
caller_ptr = src_ptr; /* Needed for A_ macros later on */

View file

@ -126,6 +126,7 @@ int do_privctl(struct proc * caller, message * m_ptr)
reset_kernel_timer(&priv(rp)->s_alarm_timer); /* - alarm */
priv(rp)->s_asyntab= -1; /* - asynsends */
priv(rp)->s_asynsize= 0;
priv(rp)->s_asynendpoint = rp->p_endpoint;
priv(rp)->s_diag_sig = FALSE; /* no request for diag sigs */
/* Set defaults for privilege bitmaps. */

View file

@ -23,9 +23,11 @@
static int inherit_priv_irq(struct proc *src_rp, struct proc *dst_rp);
static int inherit_priv_io(struct proc *src_rp, struct proc *dst_rp);
static int inherit_priv_mem(struct proc *src_rp, struct proc *dst_rp);
static void abort_proc_ipc_send(struct proc *rp);
static void adjust_proc_slot(struct proc *rp, struct proc *from_rp);
static void adjust_priv_slot(struct priv *privp, struct priv
*from_privp);
static void adjust_asyn_table(struct priv *src_privp, struct priv *dst_privp);
static void swap_proc_slot_pointer(struct proc **rpp, struct proc
*src_rp, struct proc *dst_rp);
@ -38,7 +40,7 @@ int do_update(struct proc * caller, message * m_ptr)
* slots.
*/
endpoint_t src_e, dst_e;
int src_p, dst_p;
int src_p, dst_p, flags;
struct proc *src_rp, *dst_rp;
struct priv *src_privp, *dst_privp;
struct proc orig_src_proc;
@ -48,6 +50,7 @@ int do_update(struct proc * caller, message * m_ptr)
int i, r;
/* Lookup slots for source and destination process. */
flags = m_ptr->SYS_UPD_FLAGS;
src_e = m_ptr->SYS_UPD_SRC_ENDPT;
if(!isokendpt(src_e, &src_p)) {
return EINVAL;
@ -112,6 +115,15 @@ int do_update(struct proc * caller, message * m_ptr)
orig_dst_proc = *dst_rp;
orig_dst_priv = *(priv(dst_rp));
/* Adjust asyn tables. */
adjust_asyn_table(priv(src_rp), priv(dst_rp));
adjust_asyn_table(priv(dst_rp), priv(src_rp));
/* Abort any pending send() on rollback. */
if(flags & SYS_UPD_ROLLBACK) {
abort_proc_ipc_send(src_rp);
}
/* Swap slots. */
*src_rp = orig_dst_proc;
*src_privp = orig_dst_priv;
@ -195,6 +207,27 @@ int inherit_priv_mem(struct proc *src_rp, struct proc *dst_rp)
return OK;
}
/*===========================================================================*
* abort_proc_ipc_send *
*===========================================================================*/
void abort_proc_ipc_send(struct proc *rp)
{
if(RTS_ISSET(rp, RTS_SENDING)) {
struct proc **xpp;
RTS_UNSET(rp, RTS_SENDING);
rp->p_misc_flags &= ~MF_SENDING_FROM_KERNEL;
xpp = &(proc_addr(_ENDPOINT_P(rp->p_sendto_e))->p_caller_q);
while (*xpp) {
if(*xpp == rp) {
*xpp = rp->p_q_link;
rp->p_q_link = NULL;
break;
}
xpp = &(*xpp)->p_q_link;
}
}
}
/*===========================================================================*
* adjust_proc_slot *
*===========================================================================*/
@ -205,6 +238,7 @@ static void adjust_proc_slot(struct proc *rp, struct proc *from_rp)
rp->p_nr = from_rp->p_nr;
rp->p_priv = from_rp->p_priv;
priv(rp)->s_proc_nr = from_rp->p_nr;
rp->p_caller_q = from_rp->p_caller_q;
/* preserve scheduling */
@ -216,6 +250,27 @@ static void adjust_proc_slot(struct proc *rp, struct proc *from_rp)
#endif
}
/*===========================================================================*
* adjust_asyn_table *
*===========================================================================*/
static void adjust_asyn_table(struct priv *src_privp, struct priv *dst_privp)
{
/* Transfer the asyn table if source's table belongs to the destination. */
endpoint_t src_e = proc_addr(src_privp->s_proc_nr)->p_endpoint;
endpoint_t dst_e = proc_addr(dst_privp->s_proc_nr)->p_endpoint;
if(src_privp->s_asynsize > 0 && dst_privp->s_asynsize > 0 && src_privp->s_asynendpoint == dst_e) {
if(data_copy(src_e, src_privp->s_asyntab, dst_e, dst_privp->s_asyntab,
src_privp->s_asynsize*sizeof(asynmsg_t)) != OK) {
printf("Warning: unable to transfer asyn table from ep %d to ep %d\n",
src_e, dst_e);
}
else {
dst_privp->s_asynsize = src_privp->s_asynsize;
}
}
}
/*===========================================================================*
* adjust_priv_slot *
*===========================================================================*/