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
|
@ -87,7 +87,8 @@ void cpf_reload(void);
|
||||||
/* Set a process' grant table location and size (in-kernel only). */
|
/* Set a process' grant table location and size (in-kernel only). */
|
||||||
#define _K_SET_GRANT_TABLE(rp, ptr, entries) \
|
#define _K_SET_GRANT_TABLE(rp, ptr, entries) \
|
||||||
priv(rp)->s_grant_table= (ptr); \
|
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 */
|
#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;
|
vir_bytes count = m_ptr->m_lsys_krn_sys_sdevio.vec_size;
|
||||||
long port = m_ptr->m_lsys_krn_sys_sdevio.port;
|
long port = m_ptr->m_lsys_krn_sys_sdevio.port;
|
||||||
phys_bytes vir_buf;
|
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 priv *privp;
|
||||||
struct io_range *iorp;
|
struct io_range *iorp;
|
||||||
struct proc *destproc;
|
struct proc *destproc;
|
||||||
|
@ -67,11 +67,12 @@ int do_sdevio(struct proc * caller, message *m_ptr)
|
||||||
/* Check for 'safe' variants. */
|
/* Check for 'safe' variants. */
|
||||||
if((m_ptr->m_lsys_krn_sys_sdevio.request & _DIO_SAFEMASK) == _DIO_SAFE) {
|
if((m_ptr->m_lsys_krn_sys_sdevio.request & _DIO_SAFEMASK) == _DIO_SAFE) {
|
||||||
/* Map grant address to physical address. */
|
/* 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,
|
m_ptr->m_lsys_krn_sys_sdevio.vec_addr, count,
|
||||||
req_dir == _DIO_INPUT ? CPF_WRITE : CPF_READ,
|
req_dir == _DIO_INPUT ? CPF_WRITE : CPF_READ,
|
||||||
m_ptr->m_lsys_krn_sys_sdevio.offset, &newoffset, &newep,
|
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");
|
printf("do_sdevio: verify_grant failed\n");
|
||||||
return EPERM;
|
return EPERM;
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,6 +60,7 @@ struct priv {
|
||||||
int s_irq_tab[NR_IRQ];
|
int s_irq_tab[NR_IRQ];
|
||||||
vir_bytes s_grant_table; /* grant table address of process, or 0 */
|
vir_bytes s_grant_table; /* grant table address of process, or 0 */
|
||||||
int s_grant_entries; /* no. of entries, 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 */
|
vir_bytes s_state_table; /* state table address of process, or 0 */
|
||||||
int s_state_entries; /* no. of entries, 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_nr_irq= 0;
|
||||||
priv(rp)->s_grant_table= 0;
|
priv(rp)->s_grant_table= 0;
|
||||||
priv(rp)->s_grant_entries= 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_table= 0;
|
||||||
priv(rp)->s_state_entries= 0;
|
priv(rp)->s_state_entries= 0;
|
||||||
priv(rp)->s_ipcf= 0;
|
priv(rp)->s_ipcf= 0;
|
||||||
|
|
|
@ -64,6 +64,23 @@ u32_t *flags; /* CPF_* */
|
||||||
}
|
}
|
||||||
granter_proc = proc_addr(proc_nr);
|
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
|
/* If there is no priv. structure, or no grant table in the
|
||||||
* priv. structure, or the grant table in the priv. structure
|
* priv. structure, or the grant table in the priv. structure
|
||||||
* is too small for the grant, return EPERM.
|
* 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;
|
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. */
|
/* Decide who is src and who is dst. */
|
||||||
if(access & CPF_READ) {
|
if(access & CPF_READ) {
|
||||||
src = &granter;
|
src = &granter;
|
||||||
|
@ -275,6 +284,7 @@ int access; /* CPF_READ for a copy from granter to grantee, CPF_WRITE
|
||||||
/* Verify permission exists. */
|
/* Verify permission exists. */
|
||||||
if((r=verify_grant(granter, grantee, grantid, bytes, access,
|
if((r=verify_grant(granter, grantee, grantid, bytes, access,
|
||||||
g_offset, &v_offset, &new_granter, &flags)) != OK) {
|
g_offset, &v_offset, &new_granter, &flags)) != OK) {
|
||||||
|
if(r == ENOTREADY) return r;
|
||||||
printf(
|
printf(
|
||||||
"grant %d verify to copy %d->%d by %d failed: err %d\n",
|
"grant %d verify to copy %d->%d by %d failed: err %d\n",
|
||||||
grantid, *src, *dst, grantee, r);
|
grantid, *src, *dst, grantee, r);
|
||||||
|
|
|
@ -1,9 +1,22 @@
|
||||||
|
#define _SYSTEM 1
|
||||||
|
|
||||||
#include <lib.h>
|
#include <lib.h>
|
||||||
#include <minix/syslib.h>
|
#include <minix/syslib.h>
|
||||||
|
#include <minix/sysutil.h>
|
||||||
|
|
||||||
int _kernel_call(int syscallnr, message *msgptr)
|
int _kernel_call(int syscallnr, message *msgptr)
|
||||||
{
|
{
|
||||||
|
int t, r;
|
||||||
|
t = 1;
|
||||||
|
while(1) {
|
||||||
msgptr->m_type = syscallnr;
|
msgptr->m_type = syscallnr;
|
||||||
do_kernel_call(msgptr);
|
do_kernel_call(msgptr);
|
||||||
return(msgptr->m_type);
|
r = msgptr->m_type;
|
||||||
|
if(r != ENOTREADY) {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
tickdelay(t++);
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue