[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [win-pv-devel] [PATCH 2/4] Add Suspend IOCTL interface



> -----Original Message-----
> From: win-pv-devel [mailto:win-pv-devel-bounces@xxxxxxxxxxxxxxxxxxxx] On
> Behalf Of Owen Smith
> Sent: 28 June 2016 11:36
> To: win-pv-devel@xxxxxxxxxxxxxxxxxxxx
> Cc: Owen Smith
> Subject: [win-pv-devel] [PATCH 2/4] Add Suspend IOCTL interface
> 
> Adds IOCTLs for:
> * GetCount - returns a value which changes over suspend
> * Register - registers an event that is set on resume from suspend
> * Deregister - deregisters a resume from suspend event
> 
> Signed-off-by: Owen Smith <owen.smith@xxxxxxxxxx>

Reviewed-by: Paul Durrant <paul.durrant@xxxxxxxxxx>

> ---
>  include/xeniface_ioctls.h        |  37 +++++++
>  src/xeniface/fdo.c               |  12 +++
>  src/xeniface/fdo.h               |   3 +
>  src/xeniface/ioctl_suspend.c     | 222
> +++++++++++++++++++++++++++++++++++++++
>  src/xeniface/ioctls.c            |  30 ++++++
>  src/xeniface/ioctls.h            |  46 ++++++++
>  vs2012/xeniface/xeniface.vcxproj |   1 +
>  vs2013/xeniface/xeniface.vcxproj |   1 +
>  8 files changed, 352 insertions(+)
>  create mode 100644 src/xeniface/ioctl_suspend.c
> 
> diff --git a/include/xeniface_ioctls.h b/include/xeniface_ioctls.h
> index 17beaa1..5f65f14 100644
> --- a/include/xeniface_ioctls.h
> +++ b/include/xeniface_ioctls.h
> @@ -323,4 +323,41 @@ typedef struct
> _XENIFACE_GNTTAB_UNMAP_FOREIGN_PAGES_IN {
>      ULONG RequestId; /*! Request ID used in the corresponding
> IOCTL_XENIFACE_GNTTAB_MAP_FOREIGN_PAGES call */
>  } XENIFACE_GNTTAB_UNMAP_FOREIGN_PAGES_IN,
> *PXENIFACE_GNTTAB_UNMAP_FOREIGN_PAGES_IN;
> 
> +/*! \brief Gets the current suspend count.
> +
> +    Input: None
> +
> +    Output: ULONG
> +*/
> +#define IOCTL_XENIFACE_SUSPEND_GET_COUNT \
> +    CTL_CODE(FILE_DEVICE_UNKNOWN, 0x830, METHOD_BUFFERED,
> FILE_ANY_ACCESS)
> +
> +/*! \brief Input for IOCTL_XENIFACE_SUSPEND_REGISTER */
> +typedef struct _XENIFACE_SUSPEND_REGISTER_IN {
> +    HANDLE Event; /*!< Handle to an event object that will receive suspend
> notifications */
> +} XENIFACE_SUSPEND_REGISTER_IN,
> *PXENIFACE_SUSPEND_REGISTER_IN;
> +
> +/*! \brief Output for IOCTL_XENIFACE_SUSPEND_REGISTER, Input for
> IOCTL_XENIFACE_SUSPEND_DEREGISTER */
> +typedef struct _XENIFACE_SUSPEND_REGISTER_OUT {
> +    PVOID Context; /*!< Handle to the suspend event */
> +} XENIFACE_SUSPEND_REGISTER_OUT,
> *PXENIFACE_SUSPEND_REGISTER_OUT;
> +
> +/*! \brief Registers an event which is signalled on resume-from-suspend
> +
> +    Input: XENIFACE_SUSPEND_REGISTER_IN
> +
> +    Output: XENIFACE_SUSPEND_REGISTER_OUT
> +*/
> +#define IOCTL_XENIFACE_SUSPEND_REGISTER \
> +    CTL_CODE(FILE_DEVICE_UNKNOWN, 0x831, METHOD_BUFFERED,
> FILE_ANY_ACCESS)
> +
> +/*! \brief Deregisters an event which is signalled on resume-from-suspend
> +
> +    Input: XENIFACE_SUSPEND_REGISTER_OUT
> +
> +    Output: None
> +*/
> +#define IOCTL_XENIFACE_SUSPEND_DEREGISTER \
> +    CTL_CODE(FILE_DEVICE_UNKNOWN, 0x832, METHOD_BUFFERED,
> FILE_ANY_ACCESS)
> +
>  #endif // _XENIFACE_IOCTLS_H_
> diff --git a/src/xeniface/fdo.c b/src/xeniface/fdo.c
> index ba8d19a..19e50fe 100644
> --- a/src/xeniface/fdo.c
> +++ b/src/xeniface/fdo.c
> @@ -908,6 +908,7 @@ FdoSuspendCallbackLate(
>      ASSERT(NT_SUCCESS(status));
> 
>      WmiFireSuspendEvent(Fdo);
> +    SuspendEventFire(Fdo);
>  }
> 
>  static DECLSPEC_NOINLINE NTSTATUS
> @@ -2593,6 +2594,9 @@ FdoCreate(
>      KeInitializeSpinLock(&Fdo->EvtchnLock);
>      InitializeListHead(&Fdo->EvtchnList);
> 
> +    KeInitializeSpinLock(&Fdo->SuspendLock);
> +    InitializeListHead(&Fdo->SuspendList);
> +
>      KeInitializeSpinLock(&Fdo->IrpQueueLock);
>      InitializeListHead(&Fdo->IrpList);
> 
> @@ -2625,6 +2629,10 @@ fail15:
>      RtlZeroMemory(&Fdo->IrpList, sizeof (LIST_ENTRY));
>      RtlZeroMemory(&Fdo->IrpQueueLock, sizeof (KSPIN_LOCK));
> 
> +    ASSERT(IsListEmpty(&Fdo->SuspendList));
> +    RtlZeroMemory(&Fdo->SuspendList, sizeof (LIST_ENTRY));
> +    RtlZeroMemory(&Fdo->SuspendLock, sizeof (KSPIN_LOCK));
> +
>      ASSERT(IsListEmpty(&Fdo->EvtchnList));
>      RtlZeroMemory(&Fdo->EvtchnList, sizeof (LIST_ENTRY));
>      RtlZeroMemory(&Fdo->EvtchnLock, sizeof (KSPIN_LOCK));
> @@ -2747,6 +2755,10 @@ FdoDestroy(
>      RtlZeroMemory(&Fdo->IrpQueueLock, sizeof (KSPIN_LOCK));
>      RtlZeroMemory(&Fdo->IrpQueue, sizeof (IO_CSQ));
> 
> +    ASSERT(IsListEmpty(&Fdo->SuspendList));
> +    RtlZeroMemory(&Fdo->SuspendList, sizeof (LIST_ENTRY));
> +    RtlZeroMemory(&Fdo->SuspendLock, sizeof (KSPIN_LOCK));
> +
>      ASSERT(IsListEmpty(&Fdo->EvtchnList));
>      RtlZeroMemory(&Fdo->EvtchnList, sizeof (LIST_ENTRY));
>      RtlZeroMemory(&Fdo->EvtchnLock, sizeof (KSPIN_LOCK));
> diff --git a/src/xeniface/fdo.h b/src/xeniface/fdo.h
> index 6cd628c..0791906 100644
> --- a/src/xeniface/fdo.h
> +++ b/src/xeniface/fdo.h
> @@ -90,6 +90,9 @@ typedef struct _XENIFACE_FDO {
>      KSPIN_LOCK                      EvtchnLock;
>      LIST_ENTRY                      EvtchnList;
> 
> +    KSPIN_LOCK                      SuspendLock;
> +    LIST_ENTRY                      SuspendList;
> +
>      KSPIN_LOCK                      GnttabCacheLock;
> 
>      IO_CSQ                          IrpQueue;
> diff --git a/src/xeniface/ioctl_suspend.c b/src/xeniface/ioctl_suspend.c
> new file mode 100644
> index 0000000..e848864
> --- /dev/null
> +++ b/src/xeniface/ioctl_suspend.c
> @@ -0,0 +1,222 @@
> +/* Copyright (c) Citrix Systems Inc.
> + * All rights reserved.
> + *
> + * Redistribution and use in source and binary forms,
> + * with or without modification, are permitted provided
> + * that the following conditions are met:
> + *
> + * *   Redistributions of source code must retain the above
> + *     copyright notice, this list of conditions and the
> + *     following disclaimer.
> + * *   Redistributions in binary form must reproduce the above
> + *     copyright notice, this list of conditions and the
> + *     following disclaimer in the documentation and/or other
> + *     materials provided with the distribution.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
> + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
> + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
> + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
> + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
> + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
> + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
> + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
> + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
> + * SUCH DAMAGE.
> + */
> +
> +#include "driver.h"
> +#include "ioctls.h"
> +#include "xeniface_ioctls.h"
> +#include "log.h"
> +
> +DECLSPEC_NOINLINE
> +NTSTATUS
> +IoctlSuspendGetCount(
> +    __in  PXENIFACE_FDO     Fdo,
> +    __in  PCHAR             Buffer,
> +    __in  ULONG             InLen,
> +    __in  ULONG             OutLen,
> +    __out PULONG_PTR        Info
> +    )
> +{
> +    NTSTATUS    status;
> +    PULONG      Value;
> +
> +    status = STATUS_INVALID_BUFFER_SIZE;
> +    if (InLen != 0)
> +        goto fail1;
> +
> +    if (OutLen != sizeof(ULONG))
> +        goto fail2;
> +
> +    Value = (PULONG)Buffer;
> +    *Value = XENBUS_SUSPEND(GetCount, &Fdo->SuspendInterface);
> +    *Info = (ULONG_PTR)sizeof(ULONG);
> +    status = STATUS_SUCCESS;
> +
> +    return status;
> +
> +fail2:
> +    XenIfaceDebugPrint(ERROR, "Fail2\n");
> +fail1:
> +    XenIfaceDebugPrint(ERROR, "Fail1 (%08x)\n", status);
> +    return status;
> +}
> +
> +DECLSPEC_NOINLINE
> +NTSTATUS
> +IoctlSuspendRegister(
> +    __in  PXENIFACE_FDO     Fdo,
> +    __in  PVOID             Buffer,
> +    __in  ULONG             InLen,
> +    __in  ULONG             OutLen,
> +    __in  PFILE_OBJECT      FileObject,
> +    __out PULONG_PTR        Info
> +    )
> +{
> +    NTSTATUS status;
> +    PXENIFACE_SUSPEND_REGISTER_IN In = Buffer;
> +    PXENIFACE_SUSPEND_REGISTER_OUT Out = Buffer;
> +    PXENIFACE_SUSPEND_CONTEXT Context;
> +
> +    status = STATUS_INVALID_BUFFER_SIZE;
> +    if (InLen != sizeof(XENIFACE_SUSPEND_REGISTER_IN) ||
> +        OutLen != sizeof(XENIFACE_SUSPEND_REGISTER_OUT)) {
> +        goto fail1;
> +    }
> +
> +    status = STATUS_NO_MEMORY;
> +    Context = ExAllocatePoolWithTag(NonPagedPool,
> sizeof(XENIFACE_SUSPEND_CONTEXT), XENIFACE_POOL_TAG);
> +    if (Context == NULL)
> +        goto fail2;
> +
> +    RtlZeroMemory(Context, sizeof(XENIFACE_SUSPEND_CONTEXT));
> +
> +    Context->FileObject = FileObject;
> +
> +    status = ObReferenceObjectByHandle(In->Event,
> +                                       EVENT_MODIFY_STATE,
> +                                       *ExEventObjectType,
> +                                       UserMode,
> +                                       &Context->Event,
> +                                       NULL);
> +    if (!NT_SUCCESS(status))
> +        goto fail3;
> +
> +    XenIfaceDebugPrint(TRACE, "> Suspend Event %p, FO %p\n", In->Event,
> FileObject);
> +    ExInterlockedInsertTailList(&Fdo->SuspendList, &Context->Entry, &Fdo-
> >SuspendLock);
> +
> +    Out->Context = Context;
> +    *Info = sizeof(XENIFACE_SUSPEND_REGISTER_OUT);
> +
> +    return status;
> +
> +fail3:
> +    XenIfaceDebugPrint(ERROR, "Fail3\n");
> +    RtlZeroMemory(Context, sizeof(XENIFACE_SUSPEND_CONTEXT));
> +    ExFreePoolWithTag(Context, XENIFACE_POOL_TAG);
> +
> +fail2:
> +    XenIfaceDebugPrint(ERROR, "Fail2\n");
> +
> +fail1:
> +    XenIfaceDebugPrint(ERROR, "Fail1 (%08x)\n", status);
> +    return status;
> +}
> +
> +_IRQL_requires_max_(DISPATCH_LEVEL)
> +VOID
> +SuspendFreeEvent(
> +    __in     PXENIFACE_FDO Fdo,
> +    __inout  PXENIFACE_SUSPEND_CONTEXT Context
> +    )
> +{
> +    XenIfaceDebugPrint(TRACE, "Context %p, FO %p\n",
> +                       Context, Context->FileObject);
> +
> +    ObDereferenceObject(Context->Event);
> +    RtlZeroMemory(Context, sizeof(XENIFACE_SUSPEND_CONTEXT));
> +    ExFreePoolWithTag(Context, XENIFACE_POOL_TAG);
> +}
> +
> +DECLSPEC_NOINLINE
> +NTSTATUS
> +IoctlSuspendDeregister(
> +    __in  PXENIFACE_FDO     Fdo,
> +    __in  PVOID             Buffer,
> +    __in  ULONG             InLen,
> +    __in  ULONG             OutLen,
> +    __in  PFILE_OBJECT      FileObject
> +    )
> +{
> +    NTSTATUS status;
> +    PXENIFACE_SUSPEND_REGISTER_OUT In = Buffer;
> +    PXENIFACE_SUSPEND_CONTEXT Context = NULL;
> +    KIRQL Irql;
> +    PLIST_ENTRY Node;
> +
> +    status = STATUS_INVALID_BUFFER_SIZE;
> +    if (InLen != sizeof(XENIFACE_SUSPEND_REGISTER_OUT) ||
> +        OutLen != 0) {
> +        goto fail1;
> +    }
> +
> +    XenIfaceDebugPrint(TRACE, "> Context %p, FO %p\n", In->Context,
> FileObject);
> +
> +    KeAcquireSpinLock(&Fdo->SuspendLock, &Irql);
> +    Node = Fdo->SuspendList.Flink;
> +    while (Node->Flink != Fdo->SuspendList.Flink) {
> +        Context = CONTAINING_RECORD(Node,
> XENIFACE_SUSPEND_CONTEXT, Entry);
> +
> +        Node = Node->Flink;
> +        if (Context != In->Context ||
> +            Context->FileObject != FileObject) {
> +            continue;
> +        }
> +
> +        RemoveEntryList(&Context->Entry);
> +        break;
> +    }
> +    KeReleaseSpinLock(&Fdo->SuspendLock, Irql);
> +
> +    status = STATUS_NOT_FOUND;
> +    if (Context == NULL || Context != In->Context)
> +        goto fail2;
> +
> +    SuspendFreeEvent(Fdo, Context);
> +
> +    return STATUS_SUCCESS;
> +
> +fail2:
> +    XenIfaceDebugPrint(ERROR, "Fail2\n");
> +
> +fail1:
> +    XenIfaceDebugPrint(ERROR, "Fail1 (%08x)\n", status);
> +    return status;
> +}
> +
> +VOID
> +SuspendEventFire(
> +    __in    PXENIFACE_FDO   Fdo
> +    )
> +{
> +    KIRQL       Irql;
> +    PLIST_ENTRY Node;
> +    PXENIFACE_SUSPEND_CONTEXT Context;
> +
> +    KeAcquireSpinLock(&Fdo->SuspendLock, &Irql);
> +    Node = Fdo->SuspendList.Flink;
> +    while (Node->Flink != Fdo->SuspendList.Flink) {
> +        Context = CONTAINING_RECORD(Node,
> XENIFACE_SUSPEND_CONTEXT, Entry);
> +
> +        KeSetEvent(Context->Event, IO_NO_INCREMENT, FALSE);
> +
> +        Node = Node->Flink;
> +    }
> +    KeReleaseSpinLock(&Fdo->SuspendLock, Irql);
> +}
> diff --git a/src/xeniface/ioctls.c b/src/xeniface/ioctls.c
> index a8a5538..2df299c 100644
> --- a/src/xeniface/ioctls.c
> +++ b/src/xeniface/ioctls.c
> @@ -96,6 +96,7 @@ XenIfaceCleanup(
>      PLIST_ENTRY Node;
>      PXENIFACE_STORE_CONTEXT StoreContext;
>      PXENIFACE_EVTCHN_CONTEXT EvtchnContext;
> +    PXENIFACE_SUSPEND_CONTEXT SuspendContext;
>      KIRQL Irql;
>      LIST_ENTRY ToFree;
> 
> @@ -141,6 +142,22 @@ XenIfaceCleanup(
>          RemoveEntryList(&EvtchnContext->Entry);
>          EvtchnFree(Fdo, EvtchnContext);
>      }
> +
> +    // suspend events
> +    KeAcquireSpinLock(&Fdo->SuspendLock, &Irql);
> +    Node = Fdo->SuspendList.Flink;
> +    while (Node->Flink != Fdo->SuspendList.Flink) {
> +        SuspendContext = CONTAINING_RECORD(Node,
> XENIFACE_SUSPEND_CONTEXT, Entry);
> +
> +        Node = Node->Flink;
> +        if (SuspendContext->FileObject != FileObject)
> +            continue;
> +
> +        XenIfaceDebugPrint(TRACE, "Suspend context %p\n",
> SuspendContext);
> +        RemoveEntryList(&SuspendContext->Entry);
> +        SuspendFreeEvent(Fdo, SuspendContext);
> +    }
> +    KeReleaseSpinLock(&Fdo->SuspendLock, Irql);
>  }
> 
>  NTSTATUS
> @@ -227,6 +244,19 @@ XenIfaceIoctl(
>          status = IoctlGnttabUnmapForeignPages(Fdo, Buffer, InLen, OutLen);
>          break;
> 
> +        // suspend
> +    case IOCTL_XENIFACE_SUSPEND_GET_COUNT:
> +        status = IoctlSuspendGetCount(Fdo, Buffer, InLen, OutLen, &Irp-
> >IoStatus.Information);
> +        break;
> +
> +    case IOCTL_XENIFACE_SUSPEND_REGISTER:
> +        status = IoctlSuspendRegister(Fdo, Buffer, InLen, OutLen, Stack-
> >FileObject, &Irp->IoStatus.Information);
> +        break;
> +
> +    case IOCTL_XENIFACE_SUSPEND_DEREGISTER:
> +        status = IoctlSuspendDeregister(Fdo, Buffer, InLen, OutLen, Stack-
> >FileObject);
> +        break;
> +
>      default:
>          status = STATUS_INVALID_DEVICE_REQUEST;
>          break;
> diff --git a/src/xeniface/ioctls.h b/src/xeniface/ioctls.h
> index da273ce..7dd34ee 100644
> --- a/src/xeniface/ioctls.h
> +++ b/src/xeniface/ioctls.h
> @@ -63,6 +63,12 @@ typedef struct _XENIFACE_EVTCHN_CONTEXT {
>      PVOID                  FileObject;
>  } XENIFACE_EVTCHN_CONTEXT, *PXENIFACE_EVTCHN_CONTEXT;
> 
> +typedef struct _XENIFACE_SUSPEND_CONTEXT {
> +    LIST_ENTRY              Entry;
> +    PKEVENT                 Event;
> +    PVOID                   FileObject;
> +} XENIFACE_SUSPEND_CONTEXT, *PXENIFACE_SUSPEND_CONTEXT;
> +
>  typedef struct _XENIFACE_GRANT_CONTEXT {
>      XENIFACE_CONTEXT_ID        Id;
>      LIST_ENTRY                 Entry;
> @@ -363,5 +369,45 @@ GnttabFreeMap(
>      __inout  PXENIFACE_MAP_CONTEXT Context
>      );
> 
> +NTSTATUS
> +IoctlSuspendGetCount(
> +    __in  PXENIFACE_FDO     Fdo,
> +    __in  PCHAR             Buffer,
> +    __in  ULONG             InLen,
> +    __in  ULONG             OutLen,
> +    __out PULONG_PTR        Info
> +    );
> +
> +NTSTATUS
> +IoctlSuspendRegister(
> +    __in  PXENIFACE_FDO     Fdo,
> +    __in  PVOID             Buffer,
> +    __in  ULONG             InLen,
> +    __in  ULONG             OutLen,
> +    __in  PFILE_OBJECT      FileObject,
> +    __out PULONG_PTR        Info
> +    );
> +
> +NTSTATUS
> +IoctlSuspendDeregister(
> +    __in  PXENIFACE_FDO     Fdo,
> +    __in  PVOID             Buffer,
> +    __in  ULONG             InLen,
> +    __in  ULONG             OutLen,
> +    __in  PFILE_OBJECT      FileObject
> +    );
> +
> +VOID
> +SuspendEventFire(
> +    __in    PXENIFACE_FDO   Fdo
> +    );
> +
> +_IRQL_requires_max_(DISPATCH_LEVEL)
> +VOID
> +SuspendFreeEvent(
> +    __in     PXENIFACE_FDO Fdo,
> +    __inout  PXENIFACE_SUSPEND_CONTEXT Context
> +    );
> +
>  #endif // _IOCTLS_H_
> 
> diff --git a/vs2012/xeniface/xeniface.vcxproj
> b/vs2012/xeniface/xeniface.vcxproj
> index c57e2a2..ff70eb0 100644
> --- a/vs2012/xeniface/xeniface.vcxproj
> +++ b/vs2012/xeniface/xeniface.vcxproj
> @@ -79,6 +79,7 @@
>               <ClCompile Include="..\..\src\xeniface\fdo.c" />
>               <ClCompile Include="..\..\src\xeniface\registry.c" />
>               <ClCompile Include="..\..\src\xeniface\thread.c" />
> +             <ClCompile Include="..\..\src\xeniface\ioctl_suspend.c" />
>               <ClCompile Include="..\..\src\xeniface\ioctl_evtchn.c" />
>               <ClCompile Include="..\..\src\xeniface\ioctl_gnttab.c" />
>               <ClCompile Include="..\..\src\xeniface\ioctl_store.c" />
> diff --git a/vs2013/xeniface/xeniface.vcxproj
> b/vs2013/xeniface/xeniface.vcxproj
> index 08ac3a1..3a3a937 100644
> --- a/vs2013/xeniface/xeniface.vcxproj
> +++ b/vs2013/xeniface/xeniface.vcxproj
> @@ -131,6 +131,7 @@
>      <ClCompile Include="..\..\src\xeniface\fdo.c" />
>      <ClCompile Include="..\..\src\xeniface\registry.c" />
>      <ClCompile Include="..\..\src\xeniface\thread.c" />
> +    <ClCompile Include="..\..\src\xeniface\ioctl_suspend.c" />
>      <ClCompile Include="..\..\src\xeniface\ioctl_evtchn.c" />
>      <ClCompile Include="..\..\src\xeniface\ioctl_gnttab.c" />
>      <ClCompile Include="..\..\src\xeniface\ioctl_store.c" />
> --
> 1.9.4.msysgit.1
> 
> 
> _______________________________________________
> win-pv-devel mailing list
> win-pv-devel@xxxxxxxxxxxxxxxxxxxx
> http://lists.xenproject.org/cgi-bin/mailman/listinfo/win-pv-devel
_______________________________________________
win-pv-devel mailing list
win-pv-devel@xxxxxxxxxxxxxxxxxxxx
http://lists.xenproject.org/cgi-bin/mailman/listinfo/win-pv-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.