]> Zhao Yanbai Git Server - minix.git/commitdiff
kernel: Allow kernel calls to return ENOTREADY. 81/3081/2
authorCristiano Giuffrida <giuffrida@cs.vu.nl>
Tue, 11 Mar 2014 16:47:40 +0000 (17:47 +0100)
committerDavid van Moolenbroek <david@minix3.org>
Wed, 16 Sep 2015 11:02:31 +0000 (11:02 +0000)
This is required to avoid races with safecopy() at live update time.

Change-Id: I1f3e22d40f22d94bd2b850915f9b8163a08b5616

minix/include/minix/safecopies.h
minix/kernel/arch/i386/do_sdevio.c
minix/kernel/priv.h
minix/kernel/system/do_privctl.c
minix/kernel/system/do_safecopy.c
minix/lib/libsys/kernel_call.c

index 4d9b4e2e84cefddff8d7f120ae4afbbed1d657ac..3f875614b1f7c11cc6d11dc8ebdab5627cf018ee 100644 (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 */
 
index 28558672a2815d2b73b1780c9467377d3677f7a8..add9f2adf23d251f4bff6401dd565fefbbda4ca6 100644 (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;
     }
index 06e4c091e7a65b164cb60a250cd4b9d11816c0f3..4efd9e8778a5d87d73081f456ac2d8939d12b210 100644 (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 */
 };
index 41eee88c77309743a20631c79431d4110a213a5f..0fc6c3118e20dda206ca30b3ef096b7e81f28018 100644 (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;
index 3820682697823a5fc2c5b852c605ca86398a5146..ce3ef9630d41efa258cee7ea11296a7d23c32e4d 100644 (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);
index 856e45aa663a1c107e0e80629b8661e0d96c6550..ed92b73424c9d0464cbfc478ab6b5cb887080742 100644 (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;
 }
+