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

[RFC XENBUS PATCH 1/1] Add GNTTAB_INTERFACE_V5


  • To: win-pv-devel@xxxxxxxxxxxxxxxxxxxx
  • From: Tu Dinh <ngoc-tu.dinh@xxxxxxxxxx>
  • Date: Fri, 23 Oct 2026 17:14:08 +0200
  • Authentication-results: eu.smtp.expurgate.cloud; dkim=pass header.s=selector1 header.d=vates.tech header.i="@vates.tech" header.h="From:Subject:Date:Message-ID:To:Cc:MIME-Version:Content-Type:In-Reply-To:References:Feedback-ID"
  • Cc: Tu Dinh <ngoc-tu.dinh@xxxxxxxxxx>
  • Delivery-date: Fri, 23 Oct 2026 15:14:29 +0000
  • Feedback-id: default:8631fc262581453bbf619ec5b2062170:Sweego
  • List-id: Developer list for the Windows PV Drivers subproject <win-pv-devel.lists.xenproject.org>

Avoid retrying and calling SCHEDOP_yield in RevokeForeignAccess. Leave
the retry logic to the individual drivers instead, because individual
drivers need to revoke grants in the background to avoid having backends
trample over pages that have an active grant entry yet have already been
released to the OS.

RevokeForeignAccessV2 continues providing the retry logic to legacy
clients.

Note that RevokeForeignAccess in GNTTAB_INTERFACE_V5 cannot
transparently replace RevokeForeignAccessV2 because of semantic changes.
Migrating to GNTTAB_INTERFACE_V5 requires reimplementing the drivers'
grant revocation path.

Assisted-by: LLM
Signed-off-by: Tu Dinh <ngoc-tu.dinh@xxxxxxxxxx>
---
This silently changes the semantics of RevokeForeignAccess. I can rename
it to e.g. TryRevokeForeignAccess if that is preferable.
---
 include/gnttab_interface.h | 90 ++++++++++++++++++++++++++++----------
 include/revision.h         |  3 +-
 src/xenbus/gnttab.c        | 77 +++++++++++++++++++++++++++-----
 3 files changed, 135 insertions(+), 35 deletions(-)

diff --git a/include/gnttab_interface.h b/include/gnttab_interface.h
index 92a95a7..3ca4407 100644
--- a/include/gnttab_interface.h
+++ b/include/gnttab_interface.h
@@ -132,6 +132,26 @@ typedef NTSTATUS
     _Outptr_ PXENBUS_GNTTAB_ENTRY   *Entry
     );
 
+/*! \typedef XENBUS_GNTTAB_REVOKE_FOREIGN_ACCESS_V2
+    \brief Revoke foreign access and return the \a Entry to the \a Cache
+
+    \param Interface The interface header
+    \param Cache The grant table cache handle
+    \param Locked If mutually exclusive access to the cache is already
+    guaranteed then set this to TRUE
+    \param Entry The grant table entry handle
+
+    If the foreign domain is still accessing the granted page, this retries
+    for a while before giving up.
+*/
+typedef NTSTATUS
+(*XENBUS_GNTTAB_REVOKE_FOREIGN_ACCESS_V2)(
+    _In_ PINTERFACE                 Interface,
+    _In_ PXENBUS_GNTTAB_CACHE       Cache,
+    _In_ BOOLEAN                    Locked,
+    _In_ PXENBUS_GNTTAB_ENTRY       Entry
+    );
+
 /*! \typedef XENBUS_GNTTAB_REVOKE_FOREIGN_ACCESS
     \brief Revoke foreign access and return the \a Entry to the \a Cache
 
@@ -140,6 +160,12 @@ typedef NTSTATUS
     \param Locked If mutually exclusive access to the cache is already
     guaranteed then set this to TRUE
     \param Entry The grant table entry handle
+    \return STATUS_DEVICE_BUSY if the foreign domain is still accessing the
+    granted page
+
+    This does not wait for the foreign domain. On failure, foreign access
+    remains in effect and \a Entry remains valid: the caller must keep the
+    granted page alive, and should retry the revocation later.
 */
 typedef NTSTATUS
 (*XENBUS_GNTTAB_REVOKE_FOREIGN_ACCESS)(
@@ -239,16 +265,16 @@ DEFINE_GUID(GUID_XENBUS_GNTTAB_INTERFACE,
     \ingroup interfaces
 */
 struct _XENBUS_GNTTAB_INTERFACE_V2 {
-    INTERFACE                           Interface;
-    XENBUS_GNTTAB_ACQUIRE               GnttabAcquire;
-    XENBUS_GNTTAB_RELEASE               GnttabRelease;
-    XENBUS_GNTTAB_CREATE_CACHE_V1       GnttabCreateCacheVersion1;
-    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;
+    INTERFACE                               Interface;
+    XENBUS_GNTTAB_ACQUIRE                   GnttabAcquire;
+    XENBUS_GNTTAB_RELEASE                   GnttabRelease;
+    XENBUS_GNTTAB_CREATE_CACHE_V1           GnttabCreateCacheVersion1;
+    XENBUS_GNTTAB_PERMIT_FOREIGN_ACCESS     GnttabPermitForeignAccess;
+    XENBUS_GNTTAB_REVOKE_FOREIGN_ACCESS_V2  GnttabRevokeForeignAccessVersion2;
+    XENBUS_GNTTAB_GET_REFERENCE             GnttabGetReference;
+    XENBUS_GNTTAB_DESTROY_CACHE             GnttabDestroyCache;
+    XENBUS_GNTTAB_MAP_FOREIGN_PAGES         GnttabMapForeignPages;
+    XENBUS_GNTTAB_UNMAP_FOREIGN_PAGES       GnttabUnmapForeignPages;
 };
 
 /*! \struct _XENBUS_GNTTAB_INTERFACE_V3
@@ -256,17 +282,17 @@ struct _XENBUS_GNTTAB_INTERFACE_V2 {
     \ingroup interfaces
 */
 struct _XENBUS_GNTTAB_INTERFACE_V3 {
-    INTERFACE                           Interface;
-    XENBUS_GNTTAB_ACQUIRE               GnttabAcquire;
-    XENBUS_GNTTAB_RELEASE               GnttabRelease;
-    XENBUS_GNTTAB_CREATE_CACHE_V1       GnttabCreateCacheVersion1;
-    XENBUS_GNTTAB_PERMIT_FOREIGN_ACCESS GnttabPermitForeignAccess;
-    XENBUS_GNTTAB_REVOKE_FOREIGN_ACCESS GnttabRevokeForeignAccess;
-    XENBUS_GNTTAB_GET_REFERENCE         GnttabGetReference;
-    XENBUS_GNTTAB_QUERY_REFERENCE       GnttabQueryReference;
-    XENBUS_GNTTAB_DESTROY_CACHE         GnttabDestroyCache;
-    XENBUS_GNTTAB_MAP_FOREIGN_PAGES     GnttabMapForeignPages;
-    XENBUS_GNTTAB_UNMAP_FOREIGN_PAGES   GnttabUnmapForeignPages;
+    INTERFACE                               Interface;
+    XENBUS_GNTTAB_ACQUIRE                   GnttabAcquire;
+    XENBUS_GNTTAB_RELEASE                   GnttabRelease;
+    XENBUS_GNTTAB_CREATE_CACHE_V1           GnttabCreateCacheVersion1;
+    XENBUS_GNTTAB_PERMIT_FOREIGN_ACCESS     GnttabPermitForeignAccess;
+    XENBUS_GNTTAB_REVOKE_FOREIGN_ACCESS_V2  GnttabRevokeForeignAccessVersion2;
+    XENBUS_GNTTAB_GET_REFERENCE             GnttabGetReference;
+    XENBUS_GNTTAB_QUERY_REFERENCE           GnttabQueryReference;
+    XENBUS_GNTTAB_DESTROY_CACHE             GnttabDestroyCache;
+    XENBUS_GNTTAB_MAP_FOREIGN_PAGES         GnttabMapForeignPages;
+    XENBUS_GNTTAB_UNMAP_FOREIGN_PAGES       GnttabUnmapForeignPages;
 };
 
 /*! \struct _XENBUS_GNTTAB_INTERFACE_V4
@@ -274,6 +300,24 @@ struct _XENBUS_GNTTAB_INTERFACE_V3 {
     \ingroup interfaces
 */
 struct _XENBUS_GNTTAB_INTERFACE_V4 {
+    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_V2  GnttabRevokeForeignAccessVersion2;
+    XENBUS_GNTTAB_GET_REFERENCE             GnttabGetReference;
+    XENBUS_GNTTAB_QUERY_REFERENCE           GnttabQueryReference;
+    XENBUS_GNTTAB_DESTROY_CACHE             GnttabDestroyCache;
+    XENBUS_GNTTAB_MAP_FOREIGN_PAGES         GnttabMapForeignPages;
+    XENBUS_GNTTAB_UNMAP_FOREIGN_PAGES       GnttabUnmapForeignPages;
+};
+
+/*! \struct _XENBUS_GNTTAB_INTERFACE_V5
+    \brief GNTTAB interface version 5
+    \ingroup interfaces
+*/
+struct _XENBUS_GNTTAB_INTERFACE_V5 {
     INTERFACE                           Interface;
     XENBUS_GNTTAB_ACQUIRE               GnttabAcquire;
     XENBUS_GNTTAB_RELEASE               GnttabRelease;
@@ -287,7 +331,7 @@ struct _XENBUS_GNTTAB_INTERFACE_V4 {
     XENBUS_GNTTAB_UNMAP_FOREIGN_PAGES   GnttabUnmapForeignPages;
 };
 
-typedef struct _XENBUS_GNTTAB_INTERFACE_V4 XENBUS_GNTTAB_INTERFACE, 
*PXENBUS_GNTTAB_INTERFACE;
+typedef struct _XENBUS_GNTTAB_INTERFACE_V5 XENBUS_GNTTAB_INTERFACE, 
*PXENBUS_GNTTAB_INTERFACE;
 
 /*! \def XENBUS_GNTTAB
     \brief Macro at assist in method invocation
@@ -298,6 +342,6 @@ typedef struct _XENBUS_GNTTAB_INTERFACE_V4 
XENBUS_GNTTAB_INTERFACE, *PXENBUS_GNT
 #endif  // _WINDLL
 
 #define XENBUS_GNTTAB_INTERFACE_VERSION_MIN 2
-#define XENBUS_GNTTAB_INTERFACE_VERSION_MAX 4
+#define XENBUS_GNTTAB_INTERFACE_VERSION_MAX 5
 
 #endif  // _XENBUS_GNTTAB_INTERFACE_H
diff --git a/include/revision.h b/include/revision.h
index a63e550..c1ab047 100644
--- a/include/revision.h
+++ b/include/revision.h
@@ -52,6 +52,7 @@
     DEFINE_REVISION(0x09000009,  1,  4,  9,  1,  2,  1,  2,  4,  1,  1,  2), \
     DEFINE_REVISION(0x0900000A,  1,  4,  9,  1,  2,  1,  2,  4,  2,  1,  2), \
     DEFINE_REVISION(0x0900000B,  1,  4,  9,  1,  2,  1,  2,  4,  3,  1,  2), \
-    DEFINE_REVISION(0x0900000C,  1,  4,  9,  1,  2,  1,  2,  4,  3,  1,  3)
+    DEFINE_REVISION(0x0900000C,  1,  4,  9,  1,  2,  1,  2,  4,  3,  1,  3), \
+    DEFINE_REVISION(0x0900000D,  1,  4,  9,  1,  2,  1,  2,  5,  3,  1,  3)
 
 #endif  // _REVISION_H
diff --git a/src/xenbus/gnttab.c b/src/xenbus/gnttab.c
index bdf8b2b..47be658 100644
--- a/src/xenbus/gnttab.c
+++ b/src/xenbus/gnttab.c
@@ -559,7 +559,6 @@ GnttabRevokeForeignAccess(
     PXENBUS_GNTTAB_FRAME        Frame;
     ULONG                       Index;
     volatile SHORT              *flags;
-    ULONG                       Attempt;
     NTSTATUS                    status;
 
     ASSERT3U(Entry->Magic, ==, XENBUS_GNTTAB_ENTRY_MAGIC);
@@ -571,25 +570,21 @@ GnttabRevokeForeignAccess(
 
     flags = (volatile SHORT *)&Frame->Entry[Index].flags;
 
-    for (Attempt = 0; Attempt < 100; Attempt++) {
+    for (;;) {
         uint16_t    Old;
         uint16_t    New;
 
         Old = *flags;
-        Old &= ~(GTF_reading | GTF_writing);
+
+        if (Old & (GTF_reading | GTF_writing))
+            return STATUS_DEVICE_BUSY;
 
         New = Old & ~GTF_permit_access;
 
         if (InterlockedCompareExchange16(flags, New, Old) == Old)
             break;
-
-        SchedYield();
     }
 
-    status = STATUS_UNSUCCESSFUL;
-    if (Attempt == 100)
-        goto fail1;
-
     RtlZeroMemory(&Frame->Entry[Index], sizeof (grant_entry_v1_t));
     RtlZeroMemory(&Entry->Entry, sizeof (grant_entry_v1_t));
 
@@ -600,6 +595,35 @@ GnttabRevokeForeignAccess(
                  Locked);
 
     return STATUS_SUCCESS;
+}
+
+static NTSTATUS
+GnttabRevokeForeignAccessVersion2(
+    _In_ PINTERFACE             Interface,
+    _In_ PXENBUS_GNTTAB_CACHE   Cache,
+    _In_ BOOLEAN                Locked,
+    _In_ PXENBUS_GNTTAB_ENTRY   Entry
+    )
+{
+    ULONG                       Attempt;
+    NTSTATUS                    status;
+
+    for (Attempt = 0; Attempt < 100; Attempt++) {
+        status = GnttabRevokeForeignAccess(Interface,
+                                           Cache,
+                                           Locked,
+                                           Entry);
+        if (NT_SUCCESS(status))
+            break;
+
+        SchedYield();
+    }
+
+    status = STATUS_UNSUCCESSFUL;
+    if (Attempt == 100)
+        goto fail1;
+
+    return STATUS_SUCCESS;
 
 fail1:
     Error("fail1 (%08x)\n", status);
@@ -1044,7 +1068,7 @@ static struct _XENBUS_GNTTAB_INTERFACE_V2   
GnttabInterfaceVersion2 = {
     GnttabRelease,
     GnttabCreateCacheVersion1,
     GnttabPermitForeignAccess,
-    GnttabRevokeForeignAccess,
+    GnttabRevokeForeignAccessVersion2,
     GnttabGetReference,
     GnttabDestroyCache,
     GnttabMapForeignPages,
@@ -1057,7 +1081,7 @@ static struct _XENBUS_GNTTAB_INTERFACE_V3   
GnttabInterfaceVersion3 = {
     GnttabRelease,
     GnttabCreateCacheVersion1,
     GnttabPermitForeignAccess,
-    GnttabRevokeForeignAccess,
+    GnttabRevokeForeignAccessVersion2,
     GnttabGetReference,
     GnttabQueryReference,
     GnttabDestroyCache,
@@ -1071,6 +1095,20 @@ static struct _XENBUS_GNTTAB_INTERFACE_V4   
GnttabInterfaceVersion4 = {
     GnttabRelease,
     GnttabCreateCache,
     GnttabPermitForeignAccess,
+    GnttabRevokeForeignAccessVersion2,
+    GnttabGetReference,
+    GnttabQueryReference,
+    GnttabDestroyCache,
+    GnttabMapForeignPages,
+    GnttabUnmapForeignPages
+};
+
+static struct _XENBUS_GNTTAB_INTERFACE_V5   GnttabInterfaceVersion5 = {
+    { sizeof (struct _XENBUS_GNTTAB_INTERFACE_V5), 5, NULL, NULL, NULL },
+    GnttabAcquire,
+    GnttabRelease,
+    GnttabCreateCache,
+    GnttabPermitForeignAccess,
     GnttabRevokeForeignAccess,
     GnttabGetReference,
     GnttabQueryReference,
@@ -1212,6 +1250,23 @@ GnttabGetInterface(
         status = STATUS_SUCCESS;
         break;
     }
+    case 5: {
+        struct _XENBUS_GNTTAB_INTERFACE_V5  *GnttabInterface;
+
+        GnttabInterface = (struct _XENBUS_GNTTAB_INTERFACE_V5 *)Interface;
+
+        status = STATUS_BUFFER_OVERFLOW;
+        if (Size < sizeof (struct _XENBUS_GNTTAB_INTERFACE_V5))
+            break;
+
+        *GnttabInterface = GnttabInterfaceVersion5;
+
+        ASSERT3U(Interface->Version, ==, Version);
+        Interface->Context = Context;
+
+        status = STATUS_SUCCESS;
+        break;
+    }
     default:
         status = STATUS_NOT_SUPPORTED;
         break;
-- 
2.56.0.windows.3



--
Ngoc Tu Dinh | Vates XCP-ng Developer

XCP-ng & Xen Orchestra - Vates solutions

web: https://vates.tech

 


Rackspace

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