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

Re: [win-pv-devel] [PATCH 1/2] Add foreign page mapping functions to the GNTTAB interface



> -----Original Message-----
> From: win-pv-devel-bounces@xxxxxxxxxxxxxxxxxxxx [mailto:win-pv-devel-
> bounces@xxxxxxxxxxxxxxxxxxxx] On Behalf Of Rafal Wojdyla
> Sent: 25 August 2015 17:16
> To: win-pv-devel@xxxxxxxxxxxxxxxxxxxx
> Subject: [win-pv-devel] [PATCH 1/2] Add foreign page mapping functions to
> the GNTTAB interface
> 
> GNTTAB interface now includes functions to map and unmap memory pages
> granted by a foreign domain. The page(s) are mapped under an address
> allocated from the PCI BAR space.
> 
> Signed-off-by: RafaÅ WojdyÅa <omeg@xxxxxxxxxxxxxxxxxxxxxx>
> ---
>  include/gnttab_interface.h |  62 +++++++++++++++++++++++-
>  include/xen.h              |  19 ++++++++
>  src/xen/grant_table.c      |  85 +++++++++++++++++++++++++++++++++
>  src/xenbus/gnttab.c        | 114
> +++++++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 278 insertions(+), 2 deletions(-)
> 
> diff --git a/include/gnttab_interface.h b/include/gnttab_interface.h
> index d29440a..0016888 100644
> --- a/include/gnttab_interface.h
> +++ b/include/gnttab_interface.h
> @@ -163,6 +163,47 @@ typedef VOID
>      IN  PXENBUS_GNTTAB_CACHE    Cache
>      );
> 
> +/*! \typedef XENBUS_GNTTAB_MAP_FOREIGN_PAGES
> +    \brief Map foreign memory pages into the system address space
> +
> +    \param Interface The interface header
> +    \param Domain The domid of the foreign domain that granted the pages
> +    \param NumberPages Number of pages to map
> +    \param References Array of grant reference numbers shared by the
> foreign domain
> +    \param ReadOnly If TRUE, pages are mapped with read-only access
> +    \param Address The physical address that the foreign pages are mapped
> under
> +    (allocated from the PCI IO space)

They need not be - we could decrease_reservation out some RAM - so I'd see this 
as an implementation detail rather than something to be documented in the 
interface.

> +    \param Handles An array of tracking numbers that represent the mapping
> +    of each individual page
> + */

It's kind of ugly to expose Xen's grant mapping handles out through this 
interface. Could we do better? I think we could: How about using a hash table 
of base addresses to grant map handles? Also, that means the unmap-pages 
function only need take the base address; no need for number of pages or handle 
array. That makes the functions look for like a malloc()/free() pair which I 
think is nicer.

> +
> +typedef NTSTATUS
> +(*XENBUS_GNTTAB_MAP_FOREIGN_PAGES)(
> +    IN  PINTERFACE              Interface,
> +    IN  USHORT                  Domain,
> +    IN  ULONG                   NumberPages,
> +    IN  PULONG                  References,
> +    IN  BOOLEAN                 ReadOnly,
> +    OUT PHYSICAL_ADDRESS        *Address,
> +    OUT ULONG                   *Handles
> +    );
> +
> +/*! \typedef XENBUS_GNTTAB_UNMAP_FOREIGN_PAGES
> +    \brief Unmap foreign memory pages from the system address space
> +
> +    \param Interface The interface header
> +    \param NumberPages Number of pages to unmap
> +    \param Address The physical address that the foreign pages are mapped
> under
> +    \param Handles An array of tracking numbers that represent the mapping
> + */
> +typedef NTSTATUS
> +(*XENBUS_GNTTAB_UNMAP_FOREIGN_PAGES)(
> +    IN  PINTERFACE              Interface,
> +    IN  ULONG                   NumberPages,
> +    IN  PHYSICAL_ADDRESS        Address,
> +    IN  PULONG                  Handles
> +    );
> +
>  // {763679C5-E5C2-4A6D-8B88-6BB02EC42D8E}
>  DEFINE_GUID(GUID_XENBUS_GNTTAB_INTERFACE,
>  0x763679c5, 0xe5c2, 0x4a6d, 0x8b, 0x88, 0x6b, 0xb0, 0x2e, 0xc4, 0x2d, 0x8e);
> @@ -182,7 +223,24 @@ struct _XENBUS_GNTTAB_INTERFACE_V1 {
>      XENBUS_GNTTAB_DESTROY_CACHE         GnttabDestroyCache;
>  };
> 
> -typedef struct _XENBUS_GNTTAB_INTERFACE_V1
> XENBUS_GNTTAB_INTERFACE, *PXENBUS_GNTTAB_INTERFACE;
> +/*! \struct _XENBUS_GNTTAB_INTERFACE_V2
> +    \brief GNTTAB interface version 2 (added map/unmap foreign pages)
> +    \ingroup interfaces
> + */
> +struct _XENBUS_GNTTAB_INTERFACE_V2 {
> +    INTERFACE                           Interface;
> +    XENBUS_GNTTAB_ACQUIRE               GnttabAcquire;
> +    XENBUS_GNTTAB_RELEASE               GnttabRelease;
> +    XENBUS_GNTTAB_CREATE_CACHE          GnttabCreateCache;
> +    XENBUS_GNTTAB_PERMIT_FOREIGN_ACCESS
> GnttabPermitForeignAccess;
> +    XENBUS_GNTTAB_REVOKE_FOREIGN_ACCESS
> GnttabRevokeForeignAccess;
> +    XENBUS_GNTTAB_GET_REFERENCE         GnttabGetReference;
> +    XENBUS_GNTTAB_DESTROY_CACHE         GnttabDestroyCache;
> +    XENBUS_GNTTAB_MAP_FOREIGN_PAGES     GnttabMapForeignPages;
> +    XENBUS_GNTTAB_UNMAP_FOREIGN_PAGES
> GnttabUnmapForeignPages;
> +};
> +
> +typedef struct _XENBUS_GNTTAB_INTERFACE_V2
> XENBUS_GNTTAB_INTERFACE, *PXENBUS_GNTTAB_INTERFACE;
> 
>  /*! \def XENBUS_GNTTAB
>      \brief Macro at assist in method invocation
> @@ -193,7 +251,7 @@ typedef struct _XENBUS_GNTTAB_INTERFACE_V1
> XENBUS_GNTTAB_INTERFACE, *PXENBUS_GNT
>  #endif  // _WINDLL
> 
>  #define XENBUS_GNTTAB_INTERFACE_VERSION_MIN 1
> -#define XENBUS_GNTTAB_INTERFACE_VERSION_MAX 1
> +#define XENBUS_GNTTAB_INTERFACE_VERSION_MAX 2
> 
>  #endif  // _XENBUS_GNTTAB_INTERFACE_H
> 
> diff --git a/include/xen.h b/include/xen.h
> index 6007582..23c7ac0 100644
> --- a/include/xen.h
> +++ b/include/xen.h
> @@ -258,6 +258,25 @@ GrantTableCopy(
>      IN  ULONG               Count
>      );
> 
> +__checkReturn
> +XEN_API
> +NTSTATUS
> +GrantTableMapForeignPage(
> +    IN  USHORT                  Domain,
> +    IN  ULONG                   GrantRef,
> +    IN  PHYSICAL_ADDRESS        Address,
> +    IN  BOOLEAN                 ReadOnly,
> +    OUT ULONG                   *Handle
> +    );
> +
> +__checkReturn
> +XEN_API
> +NTSTATUS
> +GrantTableUnmapForeignPage(
> +    IN  ULONG                   Handle,
> +    IN  PHYSICAL_ADDRESS        Address
> +    );
> +
>  // SCHED
> 
>  __checkReturn
> diff --git a/src/xen/grant_table.c b/src/xen/grant_table.c
> index 6facb3f..6450062 100644
> --- a/src/xen/grant_table.c
> +++ b/src/xen/grant_table.c
> @@ -131,3 +131,88 @@ fail1:
> 
>      return status;
>  }
> +
> +__checkReturn
> +XEN_API
> +NTSTATUS
> +GrantTableMapForeignPage(
> +    IN  USHORT                  Domain,
> +    IN  ULONG                   GrantRef,
> +    IN  PHYSICAL_ADDRESS        Address,
> +    IN  BOOLEAN                 ReadOnly,
> +    OUT ULONG                   *Handle
> +    )
> +{
> +    struct gnttab_map_grant_ref op;
> +    LONG_PTR rc;
> +    NTSTATUS status;
> +
> +    RtlZeroMemory(&op, sizeof(op));
> +    op.dom = Domain;
> +    op.ref = GrantRef;
> +    op.flags = GNTMAP_host_map;
> +    if (ReadOnly)
> +        op.flags |= GNTMAP_readonly;
> +    op.host_addr = Address.QuadPart;
> +
> +    rc = GrantTableOp(GNTTABOP_map_grant_ref, &op, 1);
> +
> +    if (rc < 0) {
> +        ERRNO_TO_STATUS(-rc, status);
> +        goto fail1;
> +    }
> +
> +    if (op.status != GNTST_okay) {
> +        status = STATUS_UNSUCCESSFUL;
> +        goto fail2;
> +    }
> +
> +    *Handle = op.handle;
> +
> +    return STATUS_SUCCESS;
> +
> +fail2:
> +    Error("fail2: op.status = %d\n", op.status);

In general I've tried to keep 'Error' messages other than 'fail1:'  plain. 
Rather than just setting status to unsuccessful and logging the raw grant 
status here it would be nicer to have a GNTST_TO_STATUS() macro to set status 
to something meaningful and then just log that in the 'fail1:' below.

> +fail1:
> +    Error("fail1 (%08x)\n", status);
> +
> +    return status;
> +}
> +
> +__checkReturn
> +XEN_API
> +NTSTATUS
> +GrantTableUnmapForeignPage(
> +    IN  ULONG                   Handle,
> +    IN  PHYSICAL_ADDRESS        Address
> +    )
> +{
> +    struct gnttab_unmap_grant_ref op;
> +    LONG_PTR rc;
> +    NTSTATUS status;
> +
> +    RtlZeroMemory(&op, sizeof(op));
> +    op.handle = Handle;
> +    op.host_addr = Address.QuadPart;
> +
> +    rc = GrantTableOp(GNTTABOP_unmap_grant_ref, &op, 1);
> +
> +    if (rc < 0) {
> +        ERRNO_TO_STATUS(-rc, status);
> +        goto fail1;
> +    }
> +
> +    if (op.status != GNTST_okay) {
> +        status = STATUS_UNSUCCESSFUL;
> +        goto fail2;
> +    }
> +
> +    return STATUS_SUCCESS;
> +
> +fail2:
> +    Error("op.status = %d\n", op.status);

Same here.

> +fail1:
> +    Error("fail1 (%08x)\n", status);
> +
> +    return status;
> +}
> diff --git a/src/xenbus/gnttab.c b/src/xenbus/gnttab.c
> index 165e38f..24d45af 100644
> --- a/src/xenbus/gnttab.c
> +++ b/src/xenbus/gnttab.c
> @@ -534,6 +534,90 @@ GnttabGetReference(
>      return (ULONG)Entry->Reference;
>  }
> 
> +static NTSTATUS
> +GnttabMapForeignPages(
> +    IN  PINTERFACE              Interface,
> +    IN  USHORT                  Domain,
> +    IN  ULONG                   NumberPages,
> +    IN  PULONG                  References,
> +    IN  BOOLEAN                 ReadOnly,
> +    OUT PHYSICAL_ADDRESS        *Address,
> +    OUT ULONG                   *Handles
> +    )
> +{
> +    NTSTATUS                    status;
> +    PXENBUS_GNTTAB_CONTEXT      Context = Interface->Context;
> +    ULONG                       PageIndex;
> +    PHYSICAL_ADDRESS            PageAddress;
> +
> +    status = FdoAllocateIoSpace(Context->Fdo, NumberPages * PAGE_SIZE,
> Address);
> +    if (!NT_SUCCESS(status))
> +        goto fail1;
> +
> +    PageAddress.QuadPart = Address->QuadPart;
> +
> +    for (PageIndex = 0; PageIndex < NumberPages; PageIndex++) {
> +        status = GrantTableMapForeignPage(Domain,
> +                                          References[PageIndex],
> +                                          PageAddress,
> +                                          ReadOnly,
> +                                          &(Handles[PageIndex]));
> +        if (!NT_SUCCESS(status))
> +            goto fail2;
> +
> +        PageAddress.QuadPart += PAGE_SIZE;
> +    }
> +
> +    return STATUS_SUCCESS;
> +
> +fail2:
> +    Error("fail2: PageIndex %lu, PageAddress %p, Handle %lu\n", PageIndex,
> PageAddress.QuadPart, Handles[PageIndex]);
> +
> +    while (PageIndex > 0) {
> +        --PageIndex;
> +        PageAddress.QuadPart -= PAGE_SIZE;
> +
> ASSERT(NT_SUCCESS(GrantTableUnmapForeignPage(Handles[PageIndex],
> PageAddress)));
> +    }
> +
> +    FdoFreeIoSpace(Context->Fdo, *Address, NumberPages * PAGE_SIZE);
> +
> +fail1:
> +    Error("fail1: (%08x)\n", status);
> +    return status;
> +}
> +
> +static NTSTATUS
> +GnttabUnmapForeignPages(
> +    IN  PINTERFACE              Interface,
> +    IN  ULONG                   NumberPages,
> +    IN  PHYSICAL_ADDRESS        Address,
> +    IN  PULONG                  Handles
> +    )
> +{
> +    NTSTATUS                    status;
> +    PXENBUS_GNTTAB_CONTEXT      Context = Interface->Context;
> +    ULONG                       PageIndex;
> +    PHYSICAL_ADDRESS            PageAddress;
> +
> +    PageAddress.QuadPart = Address.QuadPart;
> +
> +    for (PageIndex = 0; PageIndex < NumberPages; PageIndex++) {
> +        status = GrantTableUnmapForeignPage(Handles[PageIndex],
> PageAddress);
> +        if (!NT_SUCCESS(status))
> +            goto fail1;
> +
> +        PageAddress.QuadPart += PAGE_SIZE;
> +    }
> +
> +    FdoFreeIoSpace(Context->Fdo, Address, NumberPages * PAGE_SIZE);
> +    return STATUS_SUCCESS;
> +
> +fail1:
> +    Error("fail1: (%08x), leaking memory at %p, size 0x%lx. PageIndex = %lu,
> PageAddress = %p, Handle = %lu\n",
> +          status, Address.QuadPart, NumberPages * PAGE_SIZE, PageIndex,
> PageAddress.QuadPart, Handles[PageIndex]);

Hmm. What do we want to do on an unmap failure? I suspect such a failure 
probably means something has gone pretty disastrously wrong somewhere. We 
should probably bugcheck and let Xen clean up, otherwise we're potentially 
preventing another domain from dying.

  Paul

> +    return status;
> +}
> +
>  static VOID
>  GnttabSuspendCallbackEarly(
>      IN  PVOID               Argument
> @@ -789,6 +873,19 @@ static struct _XENBUS_GNTTAB_INTERFACE_V1
> GnttabInterfaceVersion1 = {
>      GnttabDestroyCache
>  };
> 
> +static struct _XENBUS_GNTTAB_INTERFACE_V2   GnttabInterfaceVersion2 =
> {
> +    { sizeof(struct _XENBUS_GNTTAB_INTERFACE_V2), 2, NULL, NULL, NULL
> },
> +    GnttabAcquire,
> +    GnttabRelease,
> +    GnttabCreateCache,
> +    GnttabPermitForeignAccess,
> +    GnttabRevokeForeignAccess,
> +    GnttabGetReference,
> +    GnttabDestroyCache,
> +    GnttabMapForeignPages,
> +    GnttabUnmapForeignPages
> +};
> +
>  NTSTATUS
>  GnttabInitialize(
>      IN  PXENBUS_FDO             Fdo,
> @@ -878,6 +975,23 @@ GnttabGetInterface(
>          status = STATUS_SUCCESS;
>          break;
>      }
> +    case 2: {
> +        struct _XENBUS_GNTTAB_INTERFACE_V2  *GnttabInterface;
> +
> +        GnttabInterface = (struct _XENBUS_GNTTAB_INTERFACE_V2
> *)Interface;
> +
> +        status = STATUS_BUFFER_OVERFLOW;
> +        if (Size < sizeof(struct _XENBUS_GNTTAB_INTERFACE_V2))
> +            break;
> +
> +        *GnttabInterface = GnttabInterfaceVersion2;
> +
> +        ASSERT3U(Interface->Version, ==, Version);
> +        Interface->Context = Context;
> +
> +        status = STATUS_SUCCESS;
> +        break;
> +    }
>      default:
>          status = STATUS_NOT_SUPPORTED;
>          break;
> 
> _______________________________________________
> 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®.