direct-io.hg

changeset 2714:77fbe6c094f2

bitkeeper revision 1.1159.1.261 (41792d94c9Ck-m72kpZkL5_a2aSoZA)

Merge freefall.cl.cam.ac.uk:/auto/groups/xeno/users/cl349/BK/xeno.bk-26dom0
into freefall.cl.cam.ac.uk:/local/scratch/cl349/xeno.bk-24dom0
author cl349@freefall.cl.cam.ac.uk
date Fri Oct 22 15:56:04 2004 +0000 (2004-10-22)
parents 7275617d86ce 06527e1d6757
children cf913b2c5774
files tools/libxc/xc.h tools/libxc/xc_evtchn.c tools/python/xen/lowlevel/xc/xc.c tools/python/xen/lowlevel/xu/xu.c xen/common/event_channel.c xen/include/hypervisor-ifs/event_channel.h
line diff
     1.1 --- a/tools/libxc/xc.h	Fri Oct 22 13:53:19 2004 +0000
     1.2 +++ b/tools/libxc/xc.h	Fri Oct 22 15:56:04 2004 +0000
     1.3 @@ -146,6 +146,9 @@ typedef struct {
     1.4      } u;
     1.5  } xc_evtchn_status_t;
     1.6  
     1.7 +int xc_evtchn_alloc_unbound(int xc_handle,
     1.8 +                            u32 dom,
     1.9 +                            int *port);
    1.10  int xc_evtchn_bind_interdomain(int xc_handle,
    1.11                                 u32 dom1,   /* may be DOMID_SELF */
    1.12                                 u32 dom2,   /* may be DOMID_SELF */
     2.1 --- a/tools/libxc/xc_evtchn.c	Fri Oct 22 13:53:19 2004 +0000
     2.2 +++ b/tools/libxc/xc_evtchn.c	Fri Oct 22 15:56:04 2004 +0000
     2.3 @@ -31,6 +31,26 @@ static int do_evtchn_op(int xc_handle, e
     2.4  }
     2.5  
     2.6  
     2.7 +int xc_evtchn_alloc_unbound(int xc_handle,
     2.8 +                            u32 dom,
     2.9 +                            int *port)
    2.10 +{
    2.11 +    evtchn_op_t op;
    2.12 +    int         rc;
    2.13 +
    2.14 +    op.cmd = EVTCHNOP_alloc_unbound;
    2.15 +    op.u.alloc_unbound.dom = (domid_t)dom;
    2.16 +   
    2.17 +    if ( (rc = do_evtchn_op(xc_handle, &op)) == 0 )
    2.18 +    {
    2.19 +        if ( port != NULL )
    2.20 +            *port = op.u.alloc_unbound.port;
    2.21 +    }
    2.22 +    
    2.23 +    return rc;
    2.24 +}
    2.25 +
    2.26 +
    2.27  int xc_evtchn_bind_interdomain(int xc_handle,
    2.28                                 u32 dom1,
    2.29                                 u32 dom2,
    2.30 @@ -41,9 +61,12 @@ int xc_evtchn_bind_interdomain(int xc_ha
    2.31      int         rc;
    2.32  
    2.33      op.cmd = EVTCHNOP_bind_interdomain;
    2.34 -    op.u.bind_interdomain.dom1 = (domid_t)dom1;
    2.35 -    op.u.bind_interdomain.dom2 = (domid_t)dom2;
    2.36 -   
    2.37 +    op.u.bind_interdomain.dom1  = (domid_t)dom1;
    2.38 +    op.u.bind_interdomain.dom2  = (domid_t)dom2;
    2.39 +    op.u.bind_interdomain.port1 = (port1 != NULL) ? *port1 : 0;
    2.40 +    op.u.bind_interdomain.port2 = (port2 != NULL) ? *port2 : 0;
    2.41 +
    2.42 +
    2.43      if ( (rc = do_evtchn_op(xc_handle, &op)) == 0 )
    2.44      {
    2.45          if ( port1 != NULL )
     3.1 --- a/tools/python/xen/lowlevel/xc/xc.c	Fri Oct 22 13:53:19 2004 +0000
     3.2 +++ b/tools/python/xen/lowlevel/xc/xc.c	Fri Oct 22 15:56:04 2004 +0000
     3.3 @@ -462,6 +462,26 @@ static PyObject *pyxc_bvtsched_domain_ge
     3.4                           "warpu", warpu);
     3.5  }
     3.6  
     3.7 +static PyObject *pyxc_evtchn_alloc_unbound(PyObject *self,
     3.8 +                                           PyObject *args,
     3.9 +                                           PyObject *kwds)
    3.10 +{
    3.11 +    XcObject *xc = (XcObject *)self;
    3.12 +
    3.13 +    u32 dom;
    3.14 +    int port;
    3.15 +
    3.16 +    static char *kwd_list[] = { "dom", NULL };
    3.17 +
    3.18 +    if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, &dom) )
    3.19 +        return NULL;
    3.20 +
    3.21 +    if ( xc_evtchn_alloc_unbound(xc->xc_handle, dom, &port) != 0 )
    3.22 +        return PyErr_SetFromErrno(xc_error);
    3.23 +
    3.24 +    return PyInt_FromLong(port);
    3.25 +}
    3.26 +
    3.27  static PyObject *pyxc_evtchn_bind_interdomain(PyObject *self,
    3.28                                                PyObject *args,
    3.29                                                PyObject *kwds)
    3.30 @@ -469,12 +489,12 @@ static PyObject *pyxc_evtchn_bind_interd
    3.31      XcObject *xc = (XcObject *)self;
    3.32  
    3.33      u32 dom1 = DOMID_SELF, dom2 = DOMID_SELF;
    3.34 -    int port1, port2;
    3.35 +    int port1 = 0, port2 = 0;
    3.36  
    3.37 -    static char *kwd_list[] = { "dom1", "dom2", NULL };
    3.38 +    static char *kwd_list[] = { "dom1", "dom2", "port1", "port2", NULL };
    3.39  
    3.40 -    if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|ii", kwd_list, 
    3.41 -                                      &dom1, &dom2) )
    3.42 +    if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|iiii", kwd_list, 
    3.43 +                                      &dom1, &dom2, &port1, &port2) )
    3.44          return NULL;
    3.45  
    3.46      if ( xc_evtchn_bind_interdomain(xc->xc_handle, dom1, 
    3.47 @@ -965,6 +985,13 @@ static PyMethodDef pyxc_methods[] = {
    3.48        "Returns [dict]:\n"
    3.49        " slice  [long]: Scheduler time slice.\n" },    
    3.50  
    3.51 +    { "evtchn_alloc_unbound", 
    3.52 +      (PyCFunction)pyxc_evtchn_alloc_unbound,
    3.53 +      METH_VARARGS | METH_KEYWORDS, "\n"
    3.54 +      "Allocate an unbound local port that will await a remote connection.\n"
    3.55 +      " dom [int]: Remote domain to accept connections from.\n\n"
    3.56 +      "Returns: [int] Unbound event-channel port.\n" },
    3.57 +
    3.58      { "evtchn_bind_interdomain", 
    3.59        (PyCFunction)pyxc_evtchn_bind_interdomain, 
    3.60        METH_VARARGS | METH_KEYWORDS, "\n"
    3.61 @@ -985,7 +1012,7 @@ static PyMethodDef pyxc_methods[] = {
    3.62      { "evtchn_close", 
    3.63        (PyCFunction)pyxc_evtchn_close, 
    3.64        METH_VARARGS | METH_KEYWORDS, "\n"
    3.65 -      "Close an event channel.\n"
    3.66 +      "Close an event channel. If interdomain, sets remote end to 'unbound'.\n"
    3.67        " dom  [int, SELF]: Dom-id of one endpoint of the channel.\n"
    3.68        " port [int]:       Port-id of one endpoint of the channel.\n\n"
    3.69        "Returns: [int] 0 on success; -1 on error.\n" },
     4.1 --- a/tools/python/xen/lowlevel/xu/xu.c	Fri Oct 22 13:53:19 2004 +0000
     4.2 +++ b/tools/python/xen/lowlevel/xu/xu.c	Fri Oct 22 15:56:04 2004 +0000
     4.3 @@ -1059,7 +1059,7 @@ static PyObject *xu_port_new(PyObject *s
     4.4  {
     4.5      xu_port_object *xup;
     4.6      u32 dom;
     4.7 -    int port1, port2;
     4.8 +    int port1 = 0, port2 = 0;
     4.9  
    4.10      if ( !PyArg_ParseTuple(args, "i", &dom) )
    4.11          return NULL;
     5.1 --- a/xen/common/event_channel.c	Fri Oct 22 13:53:19 2004 +0000
     5.2 +++ b/xen/common/event_channel.c	Fri Oct 22 15:56:04 2004 +0000
     5.3 @@ -29,6 +29,7 @@
     5.4  #define INIT_EVENT_CHANNELS   16
     5.5  #define MAX_EVENT_CHANNELS  1024
     5.6  
     5.7 +
     5.8  static int get_free_port(struct domain *d)
     5.9  {
    5.10      int max, port;
    5.11 @@ -67,16 +68,44 @@ static int get_free_port(struct domain *
    5.12      return port;
    5.13  }
    5.14  
    5.15 +
    5.16 +static long evtchn_alloc_unbound(evtchn_alloc_unbound_t *alloc)
    5.17 +{
    5.18 +    struct domain *d = current;
    5.19 +    int            port;
    5.20 +
    5.21 +    spin_lock(&d->event_channel_lock);
    5.22 +
    5.23 +    if ( (port = get_free_port(d)) >= 0 )
    5.24 +    {
    5.25 +        d->event_channel[port].state = ECS_UNBOUND;
    5.26 +        d->event_channel[port].u.unbound.remote_domid = alloc->dom;
    5.27 +    }
    5.28 +
    5.29 +    spin_unlock(&d->event_channel_lock);
    5.30 +
    5.31 +    if ( port < 0 )
    5.32 +        return port;
    5.33 +
    5.34 +    alloc->port = port;
    5.35 +    return 0;
    5.36 +}
    5.37 +
    5.38 +
    5.39  static long evtchn_bind_interdomain(evtchn_bind_interdomain_t *bind)
    5.40  {
    5.41 +#define ERROR_EXIT(_errno) do { rc = (_errno); goto out; } while ( 0 )
    5.42      struct domain *d1, *d2;
    5.43 -    int            port1 = 0, port2 = 0;
    5.44 +    int            port1 = bind->port1, port2 = bind->port2;
    5.45      domid_t        dom1 = bind->dom1, dom2 = bind->dom2;
    5.46      long           rc = 0;
    5.47  
    5.48 -    if ( !IS_PRIV(current) )
    5.49 +    if ( !IS_PRIV(current) && (dom1 != DOMID_SELF) )
    5.50          return -EPERM;
    5.51  
    5.52 +    if ( (port1 < 0) || (port2 < 0) )
    5.53 +        return -EINVAL;
    5.54 +
    5.55      if ( dom1 == DOMID_SELF )
    5.56          dom1 = current->id;
    5.57      if ( dom2 == DOMID_SELF )
    5.58 @@ -103,25 +132,73 @@ static long evtchn_bind_interdomain(evtc
    5.59          spin_lock(&d1->event_channel_lock);
    5.60      }
    5.61  
    5.62 -    if ( (port1 = get_free_port(d1)) < 0 )
    5.63 +    /* Obtain, or ensure that we already have, a valid <port1>. */
    5.64 +    if ( port1 == 0 )
    5.65 +    {
    5.66 +        if ( (port1 = get_free_port(d1)) < 0 )
    5.67 +            ERROR_EXIT(port1);
    5.68 +    }
    5.69 +    else if ( port1 >= d1->max_event_channel )
    5.70 +        ERROR_EXIT(-EINVAL);
    5.71 +
    5.72 +    /* Obtain, or ensure that we already have, a valid <port2>. */
    5.73 +    if ( port2 == 0 )
    5.74      {
    5.75 -        rc = port1;
    5.76 +        /* Make port1 non-free while we allocate port2 (in case dom1==dom2). */
    5.77 +        u16 tmp = d1->event_channel[port1].state;
    5.78 +        d1->event_channel[port1].state = ECS_INTERDOMAIN;
    5.79 +        port2 = get_free_port(d2);
    5.80 +        d1->event_channel[port1].state = tmp;
    5.81 +        if ( port2 < 0 )
    5.82 +            ERROR_EXIT(port2);
    5.83 +    }
    5.84 +    else if ( port2 >= d2->max_event_channel )
    5.85 +        ERROR_EXIT(-EINVAL);
    5.86 +
    5.87 +    /* Validate <dom1,port1>'s current state. */
    5.88 +    switch ( d1->event_channel[port1].state )
    5.89 +    {
    5.90 +    case ECS_FREE:
    5.91 +        break;
    5.92 +
    5.93 +    case ECS_UNBOUND:
    5.94 +        if ( d1->event_channel[port1].u.unbound.remote_domid != dom2 )
    5.95 +            ERROR_EXIT(-EINVAL);
    5.96 +        break;
    5.97 +
    5.98 +    case ECS_INTERDOMAIN:
    5.99 +        rc = ((d1->event_channel[port1].u.interdomain.remote_dom != d2) ||
   5.100 +              (d1->event_channel[port1].u.interdomain.remote_port != port2)) ?
   5.101 +            -EINVAL : 0;
   5.102          goto out;
   5.103 +
   5.104 +    default:
   5.105 +        ERROR_EXIT(-EINVAL);
   5.106      }
   5.107  
   5.108 -    /* 'Allocate' port1 before searching for a free port2. */
   5.109 -    d1->event_channel[port1].state = ECS_INTERDOMAIN;
   5.110 -
   5.111 -    if ( (port2 = get_free_port(d2)) < 0 )
   5.112 +    /* Validate <dom2,port2>'s current state. */
   5.113 +    switch ( d2->event_channel[port2].state )
   5.114      {
   5.115 -        d1->event_channel[port1].state = ECS_FREE;
   5.116 -        rc = port2;
   5.117 -        goto out;
   5.118 +    case ECS_FREE:
   5.119 +        break;
   5.120 +
   5.121 +    case ECS_UNBOUND:
   5.122 +        if ( d2->event_channel[port2].u.unbound.remote_domid != dom1 )
   5.123 +            ERROR_EXIT(-EINVAL);
   5.124 +        break;
   5.125 +
   5.126 +    default:
   5.127 +        ERROR_EXIT(-EINVAL);
   5.128      }
   5.129  
   5.130 +    /*
   5.131 +     * Everything checked out okay -- bind <dom1,port1> to <dom2,port2>.
   5.132 +     */
   5.133 +
   5.134      d1->event_channel[port1].u.interdomain.remote_dom  = d2;
   5.135      d1->event_channel[port1].u.interdomain.remote_port = (u16)port2;
   5.136 -
   5.137 +    d1->event_channel[port1].state                     = ECS_INTERDOMAIN;
   5.138 +    
   5.139      d2->event_channel[port2].u.interdomain.remote_dom  = d1;
   5.140      d2->event_channel[port2].u.interdomain.remote_port = (u16)port1;
   5.141      d2->event_channel[port2].state                     = ECS_INTERDOMAIN;
   5.142 @@ -138,6 +215,7 @@ static long evtchn_bind_interdomain(evtc
   5.143      bind->port2 = port2;
   5.144  
   5.145      return rc;
   5.146 +#undef ERROR_EXIT
   5.147  }
   5.148  
   5.149  
   5.150 @@ -295,6 +373,7 @@ static long __evtchn_close(struct domain
   5.151              BUG();
   5.152  
   5.153          chn2[port2].state = ECS_UNBOUND;
   5.154 +        chn2[port2].u.unbound.remote_domid = d1->id;
   5.155          break;
   5.156  
   5.157      default:
   5.158 @@ -397,6 +476,7 @@ static long evtchn_status(evtchn_status_
   5.159          break;
   5.160      case ECS_UNBOUND:
   5.161          status->status = EVTCHNSTAT_unbound;
   5.162 +        status->u.unbound.dom = chn[port].u.unbound.remote_domid;
   5.163          break;
   5.164      case ECS_INTERDOMAIN:
   5.165          status->status = EVTCHNSTAT_interdomain;
   5.166 @@ -432,6 +512,12 @@ long do_event_channel_op(evtchn_op_t *uo
   5.167  
   5.168      switch ( op.cmd )
   5.169      {
   5.170 +    case EVTCHNOP_alloc_unbound:
   5.171 +        rc = evtchn_alloc_unbound(&op.u.alloc_unbound);
   5.172 +        if ( (rc == 0) && (copy_to_user(uop, &op, sizeof(op)) != 0) )
   5.173 +            rc = -EFAULT; /* Cleaning up here would be a mess! */
   5.174 +        break;
   5.175 +
   5.176      case EVTCHNOP_bind_interdomain:
   5.177          rc = evtchn_bind_interdomain(&op.u.bind_interdomain);
   5.178          if ( (rc == 0) && (copy_to_user(uop, &op, sizeof(op)) != 0) )
     6.1 --- a/xen/include/hypervisor-ifs/event_channel.h	Fri Oct 22 13:53:19 2004 +0000
     6.2 +++ b/xen/include/hypervisor-ifs/event_channel.h	Fri Oct 22 15:56:04 2004 +0000
     6.3 @@ -10,17 +10,43 @@
     6.4  #define __HYPERVISOR_IFS__EVENT_CHANNEL_H__
     6.5  
     6.6  /*
     6.7 - * EVTCHNOP_bind_interdomain: Open an event channel between <dom1> and <dom2>.
     6.8 + * EVTCHNOP_alloc_unbound: Allocate a fresh local port and prepare
     6.9 + * it for binding to <dom>.
    6.10 + */
    6.11 +#define EVTCHNOP_alloc_unbound    6
    6.12 +typedef struct {
    6.13 +    /* IN parameters */
    6.14 +    domid_t dom;                      /*  0 */
    6.15 +    u16     __pad;
    6.16 +    /* OUT parameters */
    6.17 +    u32     port;                     /*  4 */
    6.18 +} PACKED evtchn_alloc_unbound_t; /* 8 bytes */
    6.19 +
    6.20 +/*
    6.21 + * EVTCHNOP_bind_interdomain: Construct an interdomain event channel between
    6.22 + * <dom1> and <dom2>. Either <port1> or <port2> may be wildcarded by setting to
    6.23 + * zero. On successful return both <port1> and <port2> are filled in and
    6.24 + * <dom1,port1> is fully bound to <dom2,port2>.
    6.25 + * 
    6.26   * NOTES:
    6.27 - *  1. <dom1> and/or <dom2> may be specified as DOMID_SELF.
    6.28 - *  2. Only a sufficiently-privileged domain may create an event channel.
    6.29 - *  3. <port1> and <port2> are only supplied if the op succeeds.
    6.30 + *  1. A wildcarded port is allocated from the relevant domain's free list
    6.31 + *     (i.e., some port that was previously EVTCHNSTAT_closed). However, if the
    6.32 + *     remote port pair is already fully bound then a port is not allocated,
    6.33 + *     and instead the existing local port is returned to the caller.
    6.34 + *  2. If the caller is unprivileged then <dom1> must be DOMID_SELF.
    6.35 + *  3. If the caller is unprivileged and <dom2,port2> is EVTCHNSTAT_closed
    6.36 + *     then <dom2> must be DOMID_SELF.
    6.37 + *  4. If either port is already bound then it must be bound to the other
    6.38 + *     specified domain and port (if not wildcarded).
    6.39 + *  5. If either port is awaiting binding (EVTCHNSTAT_unbound) then it must
    6.40 + *     be awaiting binding to the other domain, and the other port pair must
    6.41 + *     be closed or unbound.
    6.42   */
    6.43  #define EVTCHNOP_bind_interdomain 0
    6.44  typedef struct {
    6.45      /* IN parameters. */
    6.46      domid_t dom1, dom2;               /*  0,  2 */
    6.47 -    /* OUT parameters. */
    6.48 +    /* IN/OUT parameters. */
    6.49      u32     port1, port2;             /*  4,  8 */
    6.50  } PACKED evtchn_bind_interdomain_t; /* 12 bytes */
    6.51  
    6.52 @@ -55,7 +81,8 @@ typedef struct {
    6.53  
    6.54  /*
    6.55   * EVTCHNOP_close: Close the communication channel which has an endpoint at
    6.56 - * <dom, port>.
    6.57 + * <dom, port>. If the channel is interdomain then the remote end is placed in
    6.58 + * the unbound state (EVTCHNSTAT_unbound), awaiting a new connection.
    6.59   * NOTES:
    6.60   *  1. <dom> may be specified as DOMID_SELF.
    6.61   *  2. Only a sufficiently-privileged domain may close an event channel
    6.62 @@ -96,8 +123,8 @@ typedef struct {
    6.63      u16     __pad;
    6.64      u32     port;                     /*  4 */
    6.65      /* OUT parameters */
    6.66 -#define EVTCHNSTAT_closed       0  /* Chennel is not in use.                 */
    6.67 -#define EVTCHNSTAT_unbound      1  /* Channel is not bound to a source.      */
    6.68 +#define EVTCHNSTAT_closed       0  /* Channel is not in use.                 */
    6.69 +#define EVTCHNSTAT_unbound      1  /* Channel is waiting interdom connection.*/
    6.70  #define EVTCHNSTAT_interdomain  2  /* Channel is connected to remote domain. */
    6.71  #define EVTCHNSTAT_pirq         3  /* Channel is bound to a phys IRQ line.   */
    6.72  #define EVTCHNSTAT_virq         4  /* Channel is bound to a virtual IRQ line */
    6.73 @@ -105,6 +132,9 @@ typedef struct {
    6.74      union {                           /* 12 */
    6.75          struct {
    6.76              domid_t dom;                              /* 12 */
    6.77 +        } PACKED unbound; /* EVTCHNSTAT_unbound */
    6.78 +        struct {
    6.79 +            domid_t dom;                              /* 12 */
    6.80              u16     __pad;
    6.81              u32     port;                             /* 16 */
    6.82          } PACKED interdomain; /* EVTCHNSTAT_interdomain */
    6.83 @@ -117,6 +147,7 @@ typedef struct {
    6.84      u32 cmd; /* EVTCHNOP_* */         /*  0 */
    6.85      u32 __reserved;                   /*  4 */
    6.86      union {                           /*  8 */
    6.87 +        evtchn_alloc_unbound_t    alloc_unbound;
    6.88          evtchn_bind_interdomain_t bind_interdomain;
    6.89          evtchn_bind_virq_t        bind_virq;
    6.90          evtchn_bind_pirq_t        bind_pirq;