kernel: Allow kernel calls to return ENOTREADY.

This is required to avoid races with safecopy() at live update time.

Change-Id: I1f3e22d40f22d94bd2b850915f9b8163a08b5616
This commit is contained in:
Cristiano Giuffrida 2014-03-11 17:47:40 +01:00 committed by David van Moolenbroek
parent c8a9900b0c
commit 9e6b1315c3
6 changed files with 42 additions and 15 deletions

View file

@ -87,7 +87,8 @@ void cpf_reload(void);
/* Set a process' grant table location and size (in-kernel only). */
#define _K_SET_GRANT_TABLE(rp, ptr, entries) \
priv(rp)->s_grant_table= (ptr); \
priv(rp)->s_grant_entries= (entries);
priv(rp)->s_grant_entries= (entries); \
priv(rp)->s_grant_endpoint= (rp)->p_endpoint;
#endif /* _MINIX_SAFECOPIES_H */

View file

@ -30,7 +30,7 @@ int do_sdevio(struct proc * caller, message *m_ptr)
vir_bytes count = m_ptr->m_lsys_krn_sys_sdevio.vec_size;
long port = m_ptr->m_lsys_krn_sys_sdevio.port;
phys_bytes vir_buf;
int i, req_type, req_dir, size, nr_io_range;
int i, r, req_type, req_dir, size, nr_io_range;
struct priv *privp;
struct io_range *iorp;
struct proc *destproc;
@ -67,11 +67,12 @@ int do_sdevio(struct proc * caller, message *m_ptr)
/* Check for 'safe' variants. */
if((m_ptr->m_lsys_krn_sys_sdevio.request & _DIO_SAFEMASK) == _DIO_SAFE) {
/* Map grant address to physical address. */
if(verify_grant(proc_nr_e, caller->p_endpoint,
if((r=verify_grant(proc_nr_e, caller->p_endpoint,
m_ptr->m_lsys_krn_sys_sdevio.vec_addr, count,
req_dir == _DIO_INPUT ? CPF_WRITE : CPF_READ,
m_ptr->m_lsys_krn_sys_sdevio.offset, &newoffset, &newep,
NULL) != OK) {
NULL)) != OK) {
if(r == ENOTREADY) return r;
printf("do_sdevio: verify_grant failed\n");
return EPERM;
}

View file

@ -60,6 +60,7 @@ struct priv {
int s_irq_tab[NR_IRQ];
vir_bytes s_grant_table; /* grant table address of process, or 0 */
int s_grant_entries; /* no. of entries, or 0 */
endpoint_t s_grant_endpoint; /* the endpoint the grant table belongs to */
vir_bytes s_state_table; /* state table address of process, or 0 */
int s_state_entries; /* no. of entries, or 0 */
};

View file

@ -156,6 +156,7 @@ int do_privctl(struct proc * caller, message * m_ptr)
priv(rp)->s_nr_irq= 0;
priv(rp)->s_grant_table= 0;
priv(rp)->s_grant_entries= 0;
priv(rp)->s_grant_endpoint = rp->p_endpoint;
priv(rp)->s_state_table= 0;
priv(rp)->s_state_entries= 0;
priv(rp)->s_ipcf= 0;

View file

@ -64,6 +64,23 @@ u32_t *flags; /* CPF_* */
}
granter_proc = proc_addr(proc_nr);
/* If the granter has a temporary grant table, always allow
* requests with unspecified access and return ENOTREADY if
* no grant table is present or if the grantee's endpoint is not
* the endpoint the table belongs to. When ENOTREADY is returned
* the same verify_grant() request will be replayed again in a
* while until the grant table is final. This is necessary to
* avoid races at live update time.
*/
if(priv(granter_proc)->s_grant_endpoint != granter_proc->p_endpoint) {
if(!access) {
return OK;
}
else if(!HASGRANTTABLE(granter_proc) || grantee != priv(granter_proc)->s_grant_endpoint) {
return ENOTREADY;
}
}
/* If there is no priv. structure, or no grant table in the
* priv. structure, or the grant table in the priv. structure
* is too small for the grant, return EPERM.
@ -255,14 +272,6 @@ int access; /* CPF_READ for a copy from granter to grantee, CPF_WRITE
return EFAULT;
}
/* See if there is a reasonable grant table. */
if(!(granter_p = endpoint_lookup(granter))) return EINVAL;
if(!HASGRANTTABLE(granter_p)) {
printf(
"safecopy failed: granter %d has no grant table\n", granter);
return(EPERM);
}
/* Decide who is src and who is dst. */
if(access & CPF_READ) {
src = &granter;
@ -275,6 +284,7 @@ int access; /* CPF_READ for a copy from granter to grantee, CPF_WRITE
/* Verify permission exists. */
if((r=verify_grant(granter, grantee, grantid, bytes, access,
g_offset, &v_offset, &new_granter, &flags)) != OK) {
if(r == ENOTREADY) return r;
printf(
"grant %d verify to copy %d->%d by %d failed: err %d\n",
grantid, *src, *dst, grantee, r);

View file

@ -1,9 +1,22 @@
#define _SYSTEM 1
#include <lib.h>
#include <minix/syslib.h>
#include <minix/sysutil.h>
int _kernel_call(int syscallnr, message *msgptr)
{
msgptr->m_type = syscallnr;
do_kernel_call(msgptr);
return(msgptr->m_type);
int t, r;
t = 1;
while(1) {
msgptr->m_type = syscallnr;
do_kernel_call(msgptr);
r = msgptr->m_type;
if(r != ENOTREADY) {
break;
}
tickdelay(t++);
}
return r;
}