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:
parent
c8a9900b0c
commit
9e6b1315c3
6 changed files with 42 additions and 15 deletions
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue