Index: trunk/src/VBox/Additions/common/VBoxGuest/VBoxGuest-linux.c
===================================================================
--- trunk/src/VBox/Additions/common/VBoxGuest/VBoxGuest-linux.c	(revision 54605)
+++ trunk/src/VBox/Additions/common/VBoxGuest/VBoxGuest-linux.c	(revision 54606)
@@ -967,5 +967,4 @@
 }
 
-
 /** log and dbg_log parameter getter. */
 static int vboxguestLinuxParamLogGrpGet(char *pszBuf, struct kernel_param *pParam)
@@ -993,5 +992,4 @@
 }
 
-
 /** log and dbg_log_flags parameter getter. */
 static int vboxguestLinuxParamLogFlagsGet(char *pszBuf, struct kernel_param *pParam)
@@ -1019,5 +1017,4 @@
 }
 
-
 /** log and dbg_log_dest parameter getter. */
 static int vboxguestLinuxParamLogDstGet(char *pszBuf, struct kernel_param *pParam)
@@ -1029,4 +1026,32 @@
     return strlen(pszBuf);
 }
+
+
+/** r3_log_to_host parameter setter. */
+static int vboxguestLinuxParamR3LogToHostSet(const char *pszValue, struct kernel_param *pParam)
+{
+    if (    pszValue == NULL
+        || *pszValue == '\0'
+        || *pszValue == 'n'
+        || *pszValue == 'N'
+        || *pszValue == 'y'
+        || *pszValue == 'y'
+        || *pszValue == 'd'
+        || *pszValue == 'D'
+        || !strcmp(pszValue, "off")
+       )
+        g_DevExt.fLoggingEnabled = false;
+    else
+        g_DevExt.fLoggingEnabled = true;
+    return 0;
+}
+
+/** r3_log_to_host parameter getter. */
+static int vboxguestLinuxParamR3LogToHostGet(char *pszBuf, struct kernel_param *pParam)
+{
+    strcpy(pszBuf, g_DevExt.fLoggingEnabled ? "enabled" : "disabled");
+    return strlen(pszBuf);
+}
+
 
 /*
@@ -1041,4 +1066,5 @@
 module_param_call(dbg_log_dest,   vboxguestLinuxParamLogDstSet,   vboxguestLinuxParamLogDstGet,   NULL, 0664);
 # endif
+module_param_call(r3_log_to_host, vboxguestLinuxParamR3LogToHostSet, vboxguestLinuxParamR3LogToHostGet, NULL, 0664);
 
 #endif /* 2.6.0 and later */
Index: trunk/src/VBox/Additions/common/VBoxGuest/VBoxGuest.cpp
===================================================================
--- trunk/src/VBox/Additions/common/VBoxGuest/VBoxGuest.cpp	(revision 54605)
+++ trunk/src/VBox/Additions/common/VBoxGuest/VBoxGuest.cpp	(revision 54606)
@@ -90,10 +90,17 @@
 #endif
 static int VBoxGuestCommonIOCtl_CancelAllWaitEvents(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession);
-static int      vboxGuestUpdateHostFlags(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, unsigned fFlags);
+static void     vbgdBitUsageTrackerClear(PVBOXGUESTBITUSAGETRACER pTracker);
 static uint32_t vbgdGetAllowedEventMaskForSession(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession);
-static int      vbgdUpdateCapabilitiesOnHost(PVBOXGUESTDEVEXT pDevExt);
+static int      vbgdResetEventFilterOnHost(PVBOXGUESTDEVEXT pDevExt, uint32_t fFixedEvents);
+static int      vbgdResetMouseStatusOnHost(PVBOXGUESTDEVEXT pDevExt);
+static int      vbgdResetCapabilitiesOnHost(PVBOXGUESTDEVEXT pDevExt);
+static int      vbgdSetSessionEventFilter(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession,
+                                          uint32_t fOrMask, uint32_t fNotMask, bool fSessionTermination);
+static int      vbgdSetSessionMouseStatus(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession,
+                                          uint32_t fOrMask, uint32_t fNotMask, bool fSessionTermination);
+static int      vbgdSetSessionCapabilities(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession,
+                                           uint32_t fOrMask, uint32_t fNoMask, bool fSessionTermination);
 static int      vbgdAcquireSessionCapabilities(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, uint32_t fOrMask,
                                                uint32_t fNotMask, VBOXGUESTCAPSACQUIRE_FLAGS enmFlags, bool fSessionTermination);
-static int      vbgdSetSessionCapabilities(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, uint32_t fOrMask, uint32_t fNoMask);
 static int      vbgdDispatchEventsLocked(PVBOXGUESTDEVEXT pDevExt, uint32_t fEvents);
 
@@ -852,5 +859,4 @@
     pDevExt->IOPortBase = IOPortBase;
     pDevExt->pVMMDevMemory = NULL;
-    pDevExt->fFixedEvents = fFixedEvents;
     pDevExt->hGuestMappings = NIL_RTR0MEMOBJ;
     pDevExt->EventSpinlock = NIL_RTSPINLOCK;
@@ -882,4 +888,17 @@
     pDevExt->pReqGuestHeartbeat = NULL;
 
+    pDevExt->fFixedEvents = fFixedEvents;
+    vbgdBitUsageTrackerClear(&pDevExt->EventFilterTracker);
+    pDevExt->fEventFilterHost = UINT32_MAX;  /* forces a report */
+
+    vbgdBitUsageTrackerClear(&pDevExt->MouseStatusTracker);
+    pDevExt->fMouseStatusHost = UINT32_MAX;  /* forces a report */
+
+    pDevExt->u32AcquireModeGuestCaps = 0;
+    pDevExt->u32SetModeGuestCaps = 0;
+    pDevExt->u32GuestCapsAcquired = 0;
+    vbgdBitUsageTrackerClear(&pDevExt->SetGuestCapsTracker);
+    pDevExt->fGuestCapsHost = UINT32_MAX; /* forces a report */
+
     /*
      * If there is an MMIO region validate the version and size.
@@ -902,10 +921,4 @@
     }
 
-    pDevExt->u32AcquireModeGuestCaps = 0;
-    pDevExt->u32SetModeGuestCaps = 0;
-    pDevExt->u32GuestCapsAcquired = 0;
-    RT_ZERO(pDevExt->acGuestCapsSet);
-    pDevExt->fGuestCapsHost = UINT32_MAX; /* forces a report */
-
     /*
      * Create the wait and session spinlocks as well as the ballooning mutex.
@@ -949,17 +962,21 @@
             {
                 /*
-                 * Set the fixed event and disable the guest graphics capability
-                 * by default. The guest specific graphics driver will re-enable
-                 * the graphics capability if and when appropriate.
+                 * Set the fixed event and make sure guest capabilities are cleared.
                  */
-                rc = vboxGuestUpdateHostFlags(pDevExt, NULL, HostFlags_FilterMask);
+                rc = vbgdResetEventFilterOnHost(pDevExt, pDevExt->fFixedEvents);
                 if (RT_SUCCESS(rc))
                 {
-                    rc = vbgdUpdateCapabilitiesOnHost(pDevExt);
+                    rc = vbgdResetCapabilitiesOnHost(pDevExt);
                     if (RT_SUCCESS(rc))
                     {
+                        /*
+                         * Initialize stuff which may fail without requiring the driver init to fail.
+                         */
                         vboxGuestInitFixateGuestMappings(pDevExt);
                         vbgdHeartbeatInit(pDevExt);
 
+                        /*
+                         * Done!
+                         */
                         rc = VBoxGuestReportDriverStatus(true /* Driver is active */);
                         if (RT_FAILURE(rc))
@@ -1055,5 +1072,8 @@
     /* Update the host flags (mouse status etc) not to reflect this session. */
     pDevExt->fFixedEvents = 0;
-    vboxGuestUpdateHostFlags(pDevExt, NULL, HostFlags_All);
+    vbgdResetEventFilterOnHost(pDevExt, 0 /*fFixedEvents*/);
+    vbgdResetCapabilitiesOnHost(pDevExt);
+    vbgdResetMouseStatusOnHost(pDevExt);
+
     vboxGuestCloseMemBalloon(pDevExt, (PVBOXGUESTSESSION)NULL);
 
@@ -1178,5 +1198,7 @@
     vbgdAcquireSessionCapabilities(pDevExt, pSession, 0, UINT32_MAX, VBOXGUESTCAPSACQUIRE_FLAGS_NONE,
                                    true /*fSessionTermination*/);
-    vbgdSetSessionCapabilities(pDevExt, pSession, 0 /*fOrMask*/, UINT32_MAX /*fNotMask*/);
+    vbgdSetSessionCapabilities(pDevExt, pSession, 0 /*fOrMask*/, UINT32_MAX /*fNotMask*/, true /*fSessionTermination*/);
+    vbgdSetSessionEventFilter(pDevExt, pSession, 0 /*fOrMask*/, UINT32_MAX /*fNotMask*/, true /*fSessionTermination*/);
+    vbgdSetSessionMouseStatus(pDevExt, pSession, 0 /*fOrMask*/, UINT32_MAX /*fNotMask*/, true /*fSessionTermination*/);
 
     VBoxGuestCommonIOCtl_CancelAllWaitEvents(pDevExt, pSession);
@@ -1200,12 +1222,4 @@
     vboxGuestCloseMemBalloon(pDevExt, pSession);
     RTMemFree(pSession);
-
-    /* Update the host flags (mouse status etc) not to reflect this session. */
-    vboxGuestUpdateHostFlags(pDevExt, NULL,
-                               HostFlags_All
-#ifdef RT_OS_WINDOWS
-                             & ~HostFlags_MouseStatus
-#endif
-                             );
 }
 
@@ -1894,46 +1908,4 @@
 
 
-static int VBoxGuestCommonIOCtl_CtlFilterMask(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession,
-                                              VBoxGuestFilterMaskInfo *pInfo)
-{
-    int rc;
-
-    if ((pInfo->u32OrMask | pInfo->u32NotMask) & ~VMMDEV_EVENT_VALID_EVENT_MASK)
-        return VERR_INVALID_PARAMETER;
-    RTSpinlockAcquire(pDevExt->SessionSpinlock);
-    pSession->fFilterMask |= pInfo->u32OrMask;
-    pSession->fFilterMask &= ~pInfo->u32NotMask;
-    RTSpinlockRelease(pDevExt->SessionSpinlock);
-    rc = vboxGuestUpdateHostFlags(pDevExt, pSession, HostFlags_FilterMask);
-    return rc;
-}
-
-
-/**
- * Sets the mouse status features for this session and updates them
- * globally.
- *
- * @returns VBox status code.
- *
- * @param   pDevExt             The device extention.
- * @param   pSession            The session.
- * @param   fFeatures           New bitmap of enabled features.
- */
-static int vboxGuestCommonIOCtl_SetMouseStatus(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, uint32_t fFeatures)
-{
-    int rc;
-
-    if (fFeatures & ~VMMDEV_MOUSE_GUEST_MASK)
-        return VERR_INVALID_PARAMETER;
-    /* Since this is more of a negative feature we invert it to get the real
-     * feature (when the guest does not need the host cursor). */
-    fFeatures ^= VMMDEV_MOUSE_GUEST_NEEDS_HOST_CURSOR;
-    RTSpinlockAcquire(pDevExt->SessionSpinlock);
-    pSession->fMouseStatus = fFeatures;
-    RTSpinlockRelease(pDevExt->SessionSpinlock);
-    rc = vboxGuestUpdateHostFlags(pDevExt, pSession, HostFlags_MouseStatus);
-    return rc;
-}
-
 #ifdef VBOX_WITH_HGCM
 
@@ -2406,4 +2378,5 @@
     NOREF(pch);
     NOREF(cbData);
+RTAssertMsg2Weak("\nVBoxGuestCommonIOCtl_Log: cbData=%#x\n", cbData);
     if (pDevExt->fLoggingEnabled)
         RTLogBackdoorPrintf("%.*s", cbData, pch);
@@ -2423,133 +2396,413 @@
 
 /**
- * Sets the interrupt filter mask during initialization and termination.
- *
- * This will ASSUME that we're the ones in carge over the mask, so
- * we'll simply clear all bits we don't set.
- *
- * @returns VBox status code (ignored).
- * @param   fMask       The new mask.
- */
-static int vboxGuestSetFilterMask(VMMDevCtlGuestFilterMask *pReq, uint32_t fMask)
+ * Clears a bit usage tracker (init time).
+ *
+ * @param   pTracker            The tracker to clear.
+ */
+static void vbgdBitUsageTrackerClear(PVBOXGUESTBITUSAGETRACER pTracker)
+{
+    uint32_t iBit;
+    AssertCompile(sizeof(pTracker->acPerBitUsage) == 32 * sizeof(uint32_t));
+
+    for (iBit = 0; iBit < 32; iBit++)
+        pTracker->acPerBitUsage[iBit] = 0;
+    pTracker->fMask = 0;
+}
+
+
+#ifdef VBOX_STRICT
+/**
+ * Checks that pTracker->fMask is correct and that the usage values are within
+ * the valid range.
+ *
+ * @param   pTracker            The tracker.
+ * @param   cMax                Max valid usage value.
+ * @param   pszWhat             Identifies the tracker in assertions.
+ */
+static void vbgdBitUsageTrackerCheckMask(PCVBOXGUESTBITUSAGETRACER pTracker, uint32_t cMax, const char *pszWhat)
+{
+    uint32_t fMask = 0;
+    uint32_t iBit;
+    AssertCompile(sizeof(pTracker->acPerBitUsage) == 32 * sizeof(uint32_t));
+
+    for (iBit = 0; iBit < 32; iBit++)
+        if (pTracker->acPerBitUsage[iBit])
+        {
+            fMask |= RT_BIT_32(iBit);
+            AssertMsg(pTracker->acPerBitUsage[iBit] <= cMax,
+                      ("%s: acPerBitUsage[%u]=%#x cMax=%#x\n", pszWhat, iBit, pTracker->acPerBitUsage[iBit], cMax));
+        }
+
+    AssertMsg(fMask == pTracker->fMask, ("%s: %#x vs %#x\n", pszWhat, fMask, pTracker->fMask));
+}
+#endif
+
+
+/**
+ * Applies a change to the bit usage tracker.
+ *
+ *
+ * @returns true if the mask changed, false if not.
+ * @param   pTracker            The bit usage tracker.
+ * @param   fChanged            The bits to change.
+ * @param   fPrevious           The previous value of the bits.
+ * @param   cMax                The max valid usage value for assertions.
+ * @param   pszWhat             Identifies the tracker in assertions.
+ */
+static bool vbgdBitUsageTrackerChange(PVBOXGUESTBITUSAGETRACER pTracker, uint32_t fChanged, uint32_t fPrevious,
+                                     uint32_t cMax, const char *pszWhat)
+{
+    bool        fGlobalChange = false;
+    uint32_t    iBit;
+    AssertCompile(sizeof(pTracker->acPerBitUsage) == 32 * sizeof(uint32_t));
+
+    for (iBit = ASMBitFirstSetU32(fChanged) - 1; iBit < 32; iBit++)
+    {
+        uint32_t const fBitMask = RT_BIT_32(iBit);
+        if (fBitMask & fChanged)
+        {
+            if (fChanged & fPrevious)
+            {
+                pTracker->acPerBitUsage[iBit] -= 1;
+                AssertMsg(pTracker->acPerBitUsage[iBit] <= cMax,
+                          ("%s: acPerBitUsage[%u]=%#x cMax=%#x\n", pszWhat, iBit, pTracker->acPerBitUsage[iBit], cMax));
+                if (pTracker->acPerBitUsage[iBit] == 0)
+                {
+                    fGlobalChange = true;
+                    pTracker->fMask &= ~fBitMask;
+                }
+            }
+            else
+            {
+                pTracker->acPerBitUsage[iBit] += 1;
+                AssertMsg(pTracker->acPerBitUsage[iBit] > 0 && pTracker->acPerBitUsage[iBit] <= cMax,
+                          ("pTracker->acPerBitUsage[%u]=%#x cMax=%#x\n", pszWhat, iBit, pTracker->acPerBitUsage[iBit], cMax));
+                if (pTracker->acPerBitUsage[iBit] == 1)
+                {
+                    fGlobalChange = true;
+                    pTracker->fMask |= fBitMask;
+                }
+            }
+            fChanged &= ~fBitMask;
+            if (!fChanged)
+                break;
+        }
+    }
+
+#ifdef VBOX_STRICT
+    vbgdBitUsageTrackerCheckMask(pTracker, cMax, pszWhat);
+#endif
+    NOREF(pszWhat); NOREF(cMax);
+    return fGlobalChange;
+}
+
+
+/**
+ * Init and termination worker for resetting the (host) event filter on the host
+ *
+ * @returns VBox status code.
+ * @param   pDevExt         The device extension.
+ * @param   fFixedEvents    Fixed events (init time).
+ */
+static int vbgdResetEventFilterOnHost(PVBOXGUESTDEVEXT pDevExt, uint32_t fFixedEvents)
+{
+    VMMDevCtlGuestFilterMask *pReq;
+    int rc = VbglGRAlloc((VMMDevRequestHeader **)&pReq, sizeof(*pReq), VMMDevReq_CtlGuestFilterMask);
+    if (RT_SUCCESS(rc))
+    {
+        pReq->u32NotMask = UINT32_MAX & ~fFixedEvents;
+        pReq->u32OrMask  = fFixedEvents;
+        rc = VbglGRPerform(&pReq->header);
+        if (RT_FAILURE(rc))
+            LogRelFunc(("failed with rc=%Rrc\n", rc));
+        VbglGRFree(&pReq->header);
+    }
+    return rc;
+}
+
+
+/**
+ * Changes the event filter mask for the given session.
+ *
+ * This is called in response to VBOXGUEST_IOCTL_CTL_FILTER_MASK as well as to
+ * do session cleanup.
+ *
+ * @returns VBox status code.
+ * @param   pDevExt             The device extension.
+ * @param   pSession            The session.
+ * @param   fOrMask             The events to add.
+ * @param   fNotMask            The events to remove.
+ * @param   fSessionTermination Set if we're called by the session cleanup code.
+ *                              This tweaks the error handling so we perform
+ *                              proper session cleanup even if the host
+ *                              misbehaves.
+ *
+ * @remarks Takes the session spinlock.
+ */
+static int vbgdSetSessionEventFilter(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession,
+                                     uint32_t fOrMask, uint32_t fNotMask, bool fSessionTermination)
+{
+    VMMDevCtlGuestFilterMask   *pReq;
+    uint32_t                    fChanged;
+    uint32_t                    fPrevious;
+    int                         rc;
+
+    /*
+     * Preallocate a request buffer so we can do all in one go without leaving the spinlock.
+     */
+    rc = VbglGRAlloc((VMMDevRequestHeader **)&pReq, sizeof(*pReq), VMMDevReq_CtlGuestFilterMask);
+    if (RT_SUCCESS(rc))
+    { /* nothing */ }
+    else if (!fSessionTermination)
+    {
+        LogRel(("vbgdSetSessionFilterMask: VbglGRAlloc failure: %Rrc\n", rc));
+        return rc;
+    }
+    else
+        pReq = NULL; /* Ignore failure, we must do session cleanup. */
+
+
+    RTSpinlockAcquire(pDevExt->SessionSpinlock);
+
+    /*
+     * Apply the changes to the session mask.
+     */
+    fPrevious = pSession->fEventFilter;
+    pSession->fEventFilter |= fOrMask;
+    pSession->fEventFilter &= fNotMask;
+
+    /*
+     * If anything actually changed, update the global usage counters.
+     */
+    fChanged = fPrevious ^ pSession->fEventFilter;
+    if (fChanged)
+    {
+        bool fGlobalChange = vbgdBitUsageTrackerChange(&pDevExt->EventFilterTracker, fChanged, fPrevious,
+                                                       pDevExt->cSessions, "EventFilterTracker");
+
+        /*
+         * If there are global changes, update the event filter on the host.
+         */
+        if (fGlobalChange || pDevExt->fEventFilterHost == UINT32_MAX)
+        {
+            Assert(pReq || fSessionTermination);
+            if (pReq)
+            {
+                pReq->u32OrMask = pDevExt->fFixedEvents | pDevExt->EventFilterTracker.fMask;
+                if (pReq->u32OrMask == pDevExt->fEventFilterHost)
+                    rc = VINF_SUCCESS;
+                else
+                {
+                    pDevExt->fEventFilterHost = pReq->u32OrMask;
+                    pReq->u32NotMask = ~pReq->u32OrMask;
+                    rc = VbglGRPerform(&pReq->header);
+                    if (RT_FAILURE(rc))
+                    {
+                        /*
+                         * Failed, roll back (unless it's session termination time).
+                         */
+                        pDevExt->fEventFilterHost = UINT32_MAX;
+                        if (!fSessionTermination)
+                        {
+                            vbgdBitUsageTrackerChange(&pDevExt->EventFilterTracker, fChanged, pSession->fEventFilter,
+                                                      pDevExt->cSessions, "EventFilterTracker");
+                            pSession->fEventFilter = fPrevious;
+                        }
+                    }
+                }
+            }
+            else
+                rc = VINF_SUCCESS;
+        }
+    }
+
+    RTSpinlockRelease(pDevExt->SessionSpinlock);
+    if (pReq)
+        VbglGRFree(&pReq->header);
+    return rc;
+}
+
+
+/**
+ * Handle VBOXGUEST_IOCTL_CTL_FILTER_MASK.
+ *
+ * @returns VBox status code.
+ *
+ * @param   pDevExt             The device extension.
+ * @param   pSession            The session.
+ * @param   pInfo               The request.
+ */
+static int VBoxGuestCommonIOCtl_CtlFilterMask(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession,
+                                              VBoxGuestFilterMaskInfo *pInfo)
+{
+    LogFlow(("VBoxGuestCommonIOCtl: CTL_FILTER_MASK or=%#x not=%#x\n", pInfo->u32OrMask, pInfo->u32NotMask));
+
+    if ((pInfo->u32OrMask | pInfo->u32NotMask) & ~VMMDEV_EVENT_VALID_EVENT_MASK)
+    {
+        Log(("VBoxGuestCommonIOCtl: CTL_FILTER_MASK or=%#x not=%#x: Invalid masks!\n", pInfo->u32OrMask, pInfo->u32NotMask));
+        return VERR_INVALID_PARAMETER;
+    }
+
+    return vbgdSetSessionEventFilter(pDevExt, pSession, pInfo->u32OrMask, pInfo->u32NotMask, false /*fSessionTermination*/);
+}
+
+
+/**
+ * Init and termination worker for set mouse feature status to zero on the host.
+ *
+ * @returns VBox status code.
+ * @param   pDevExt         The device extension.
+ */
+static int vbgdResetMouseStatusOnHost(PVBOXGUESTDEVEXT pDevExt)
+{
+    VMMDevReqMouseStatus *pReq;
+    int rc = VbglGRAlloc((VMMDevRequestHeader **)&pReq, sizeof(*pReq), VMMDevReq_SetMouseStatus);
+    if (RT_SUCCESS(rc))
+    {
+        pReq->mouseFeatures = 0;
+        pReq->pointerXPos   = 0;
+        pReq->pointerYPos   = 0;
+        rc = VbglGRPerform(&pReq->header);
+        if (RT_FAILURE(rc))
+            LogRelFunc(("failed with rc=%Rrc\n", rc));
+        VbglGRFree(&pReq->header);
+    }
+    return rc;
+}
+
+
+/**
+ * Changes the mouse status mask for the given session.
+ *
+ * This is called in response to VBOXGUEST_IOCTL_SET_MOUSE_STATUS as well as to
+ * do session cleanup.
+ *
+ * @returns VBox status code.
+ * @param   pDevExt             The device extension.
+ * @param   pSession            The session.
+ * @param   fOrMask             The status flags to add.
+ * @param   fNotMask            The status flags to remove.
+ * @param   fSessionTermination Set if we're called by the session cleanup code.
+ *                              This tweaks the error handling so we perform
+ *                              proper session cleanup even if the host
+ *                              misbehaves.
+ *
+ * @remarks Takes the session spinlock.
+ */
+static int vbgdSetSessionMouseStatus(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession,
+                                     uint32_t fOrMask, uint32_t fNotMask, bool fSessionTermination)
+{
+    VMMDevReqMouseStatus   *pReq;
+    uint32_t                fChanged;
+    uint32_t                fPrevious;
+    int                     rc;
+
+    /*
+     * Preallocate a request buffer so we can do all in one go without leaving the spinlock.
+     */
+    rc = VbglGRAlloc((VMMDevRequestHeader **)&pReq, sizeof(*pReq), VMMDevReq_SetMouseStatus);
+    if (RT_SUCCESS(rc))
+    { /* nothing */ }
+    else if (!fSessionTermination)
+    {
+        LogRel(("vbgdSetSessionMouseStatus: VbglGRAlloc failure: %Rrc\n", rc));
+        return rc;
+    }
+    else
+        pReq = NULL; /* Ignore failure, we must do session cleanup. */
+
+
+    RTSpinlockAcquire(pDevExt->SessionSpinlock);
+
+    /*
+     * Apply the changes to the session mask.
+     */
+    fPrevious = pSession->fMouseStatus;
+    pSession->fMouseStatus |= fOrMask;
+    pSession->fMouseStatus &= fNotMask;
+
+    /*
+     * If anything actually changed, update the global usage counters.
+     */
+    fChanged = fPrevious ^ pSession->fMouseStatus;
+    if (fChanged)
+    {
+        bool fGlobalChange = vbgdBitUsageTrackerChange(&pDevExt->MouseStatusTracker, fChanged, fPrevious,
+                                                       pDevExt->cSessions, "MouseStatusTracker");
+
+        /*
+         * If there are global changes, update the event filter on the host.
+         */
+        if (fGlobalChange || pDevExt->fMouseStatusHost == UINT32_MAX)
+        {
+            Assert(pReq || fSessionTermination);
+            if (pReq)
+            {
+                /* Since VMMDEV_MOUSE_GUEST_NEEDS_HOST_CURSOR is inverted in the session
+                 * capabilities we invert it again here before sending it to the host. */
+                pReq->mouseFeatures = pDevExt->MouseStatusTracker.fMask ^ VMMDEV_MOUSE_GUEST_NEEDS_HOST_CURSOR;
+                if (pReq->mouseFeatures == pDevExt->fMouseStatusHost)
+                    rc = VINF_SUCCESS;
+                else
+                {
+                    pDevExt->fMouseStatusHost = pReq->mouseFeatures;
+                    pReq->pointerXPos = 0;
+                    pReq->pointerYPos = 0;
+                    rc = VbglGRPerform(&pReq->header);
+                    if (RT_FAILURE(rc))
+                    {
+                        /*
+                         * Failed, roll back (unless it's session termination time).
+                         */
+                        pDevExt->fMouseStatusHost = UINT32_MAX;
+                        if (!fSessionTermination)
+                        {
+                            vbgdBitUsageTrackerChange(&pDevExt->MouseStatusTracker, fChanged, pSession->fMouseStatus,
+                                                      pDevExt->cSessions, "MouseStatusTracker");
+                            pSession->fMouseStatus = fPrevious;
+                        }
+                    }
+                }
+            }
+            else
+                rc = VINF_SUCCESS;
+        }
+    }
+
+    RTSpinlockRelease(pDevExt->SessionSpinlock);
+    if (pReq)
+        VbglGRFree(&pReq->header);
+    return rc;
+}
+
+
+/**
+ * Sets the mouse status features for this session and updates them globally.
+ *
+ * @returns VBox status code.
+ *
+ * @param   pDevExt             The device extention.
+ * @param   pSession            The session.
+ * @param   fFeatures           New bitmap of enabled features.
+ */
+static int vboxGuestCommonIOCtl_SetMouseStatus(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, uint32_t fFeatures)
 {
     int rc;
-
-    pReq->u32OrMask = fMask;
-    pReq->u32NotMask = ~fMask;
-    rc = VbglGRPerform(&pReq->header);
-    if (RT_FAILURE(rc))
-        LogRel(("vboxGuestSetFilterMask: failed with rc=%Rrc\n", rc));
-    return rc;
-}
-
-
-/**
- * Sets the mouse status to the host.
- *
- * This will ASSUME that we're the ones in charge of the mask, so
- * we'll simply clear all bits we don't set.
- *
- * @returns VBox status code.
- * @param   fMask       The new mask.
- */
-static int vboxGuestSetMouseStatus(VMMDevReqMouseStatus *pReq, uint32_t fMask)
-{
-    int rc;
-
-    pReq->mouseFeatures = fMask;
-    pReq->pointerXPos   = 0;
-    pReq->pointerYPos   = 0;
-    rc = VbglGRPerform(&pReq->header);
-    if (RT_FAILURE(rc))
-        LogRelFunc(("failed with rc=%Rrc\n", rc));
-    return rc;
-}
-
-
-static int vboxGuestGetHostFlagsFromSessions(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession,
-                                             uint32_t *pfFilterMask, uint32_t *pfMouseStatus)
-{
-    PVBOXGUESTSESSION pIterator;
-    uint32_t fFilterMask = 0;
-    uint32_t fMouseStatus = 0;
-    unsigned cSessions = 0;
-    int rc = VINF_SUCCESS;
-
-/** @todo r=bird: Please just do the global bit counting thing.  This code
- * gives me the [performances] creeps.  */
-    RTListForEach(&pDevExt->SessionList, pIterator, VBOXGUESTSESSION, ListNode)
-    {
-        fFilterMask   |= pIterator->fFilterMask;
-        fMouseStatus  |= pIterator->fMouseStatus;
-        ++cSessions;
-    }
-    if (!cSessions)
-        if (fFilterMask | fMouseStatus)
-            rc = VERR_INTERNAL_ERROR;
-    if (cSessions == 1 && pSession)
-        if (   fFilterMask   != pSession->fFilterMask
-            || fMouseStatus  != pSession->fMouseStatus)
-            rc = VERR_INTERNAL_ERROR;
-    if (cSessions > 1 && pSession)
-        if (   ~fFilterMask   & pSession->fFilterMask
-            || ~fMouseStatus  & pSession->fMouseStatus)
-            rc = VERR_INTERNAL_ERROR;
-    *pfFilterMask = fFilterMask;
-    *pfMouseStatus = fMouseStatus;
-    return rc;
-}
-
-
-/**
- * Calls the host and set the filter mask, capabilities and/or mouse status.
- *
- * Check which host flags in a given category are being asserted by some guest
- * session and assert exactly those on the host which are being asserted by one
- * or more sessions.  pCallingSession is purely for sanity checking and can be
- * NULL.
- *
- * @note Takes the session spin-lock.
- */
-static int vboxGuestUpdateHostFlags(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, unsigned fFlags)
-{
-    int rc;
-    VMMDevCtlGuestFilterMask    *pFilterReq = NULL;
-    VMMDevReqMouseStatus        *pStatusReq = NULL;
-    uint32_t                     fFilterMask = 0;
-    uint32_t                     fMouseStatus = 0;
-
-    rc = VbglGRAlloc((VMMDevRequestHeader **)&pFilterReq, sizeof(*pFilterReq),
-                     VMMDevReq_CtlGuestFilterMask);
-    if (RT_SUCCESS(rc))
-        rc = VbglGRAlloc((VMMDevRequestHeader **)&pStatusReq,
-                         sizeof(*pStatusReq), VMMDevReq_SetMouseStatus);
-    if (RT_SUCCESS(rc))
-    {
-        RTSpinlockAcquire(pDevExt->SessionSpinlock);
-        rc = vboxGuestGetHostFlagsFromSessions(pDevExt, pSession, &fFilterMask, &fMouseStatus);
-        if (RT_SUCCESS(rc))
-        {
-            fFilterMask |= pDevExt->fFixedEvents;
-            /* Since VMMDEV_MOUSE_GUEST_NEEDS_HOST_CURSOR is inverted in the session
-             * capabilities we invert it again before sending it to the host. */
-            fMouseStatus ^= VMMDEV_MOUSE_GUEST_NEEDS_HOST_CURSOR;
-            if (fFlags & HostFlags_FilterMask)
-                vboxGuestSetFilterMask(pFilterReq, fFilterMask);
-            if (fFlags & HostFlags_MouseStatus)
-                vboxGuestSetMouseStatus(pStatusReq, fMouseStatus);
-        }
-        RTSpinlockRelease(pDevExt->SessionSpinlock);
-    }
-    if (pFilterReq)
-        VbglGRFree(&pFilterReq->header);
-    if (pStatusReq)
-        VbglGRFree(&pStatusReq->header);
-
-    return rc;
-}
-
-
-/**
- * Return the mask of VMM device events that this session is allowed to see.
+    LogFlow(("VBoxGuestCommonIOCtl: CTL_FILTER_MASK features=%#x\n", fFeatures));
+
+    if (fFeatures & ~VMMDEV_MOUSE_GUEST_MASK)
+        return VERR_INVALID_PARAMETER;
+
+    /* Since this is more of a negative feature we invert it to get the real
+     * feature (when the guest does not need the host cursor). */
+    fFeatures ^= VMMDEV_MOUSE_GUEST_NEEDS_HOST_CURSOR;
+
+    return vbgdSetSessionMouseStatus(pDevExt, pSession, fFeatures, ~fFeatures, false /*fSessionTermination*/);
+}
+
+
+/**
+ * Return the mask of VMM device events that this session is allowed to see (wrt
+ * to "acquire" mode guest capabilities).
  *
  * The events associated with guest capabilities in "acquire" mode will be
@@ -2600,4 +2853,28 @@
 
 /**
+ * Init and termination worker for set guest capabilities to zero on the host.
+ *
+ * @returns VBox status code.
+ * @param   pDevExt         The device extension.
+ */
+static int vbgdResetCapabilitiesOnHost(PVBOXGUESTDEVEXT pDevExt)
+{
+    VMMDevReqGuestCapabilities2 *pReq;
+    int rc = VbglGRAlloc((VMMDevRequestHeader **)&pReq, sizeof(*pReq), VMMDevReq_SetGuestCapabilities);
+    if (RT_SUCCESS(rc))
+    {
+        pReq->u32NotMask = UINT32_MAX;
+        pReq->u32OrMask  = 0;
+        rc = VbglGRPerform(&pReq->header);
+
+        if (RT_FAILURE(rc))
+            LogRelFunc(("failed with rc=%Rrc\n", rc));
+        VbglGRFree(&pReq->header);
+    }
+    return rc;
+}
+
+
+/**
  * Sets the guest capabilities to the host while holding the lock.
  *
@@ -2613,9 +2890,5 @@
     uint32_t iBit;
 
-    pReq->u32OrMask = pDevExt->u32GuestCapsAcquired;
-    for (iBit = 0; iBit < 32; iBit++)
-        if (pDevExt->acGuestCapsSet[iBit] > 0)
-            pReq->u32OrMask |= RT_BIT_32(iBit);
-
+    pReq->u32OrMask = pDevExt->u32GuestCapsAcquired | pDevExt->SetGuestCapsTracker.fMask;
     if (pReq->u32OrMask == pDevExt->fGuestCapsHost)
         rc = VINF_SUCCESS;
@@ -2634,35 +2907,6 @@
 
 /**
- * Sets the guest capabilities to the host.
- *
- * This will ASSUME that we're the ones in charge of the mask, so
- * we'll simply clear all bits we don't set.
- *
- * @returns VBox status code.
- * @param   fMask       The new mask.
- */
-static int vbgdUpdateCapabilitiesOnHost(PVBOXGUESTDEVEXT pDevExt)
-{
-    VMMDevReqGuestCapabilities2 *pReq;
-    int rc = VbglGRAlloc((VMMDevRequestHeader **)&pReq, sizeof(*pReq), VMMDevReq_SetGuestCapabilities);
-    if (RT_SUCCESS(rc))
-    {
-        RTSpinlockAcquire(pDevExt->SessionSpinlock);
-
-        rc = vbgdUpdateCapabilitiesOnHostWithReqAndLock(pDevExt, pReq);
-
-        RTSpinlockRelease(pDevExt->SessionSpinlock);
-
-        if (RT_FAILURE(rc))
-            LogRelFunc(("failed with rc=%Rrc\n", rc));
-        VbglGRFree(&pReq->header);
-    }
-    return rc;
-}
-
-
-/**
- * Switch a set of capabilities into "acuquire" mode and (maybe) acquire them
- * for the given session.
+ * Switch a set of capabilities into "acquire" mode and (maybe) acquire them for
+ * the given session.
  *
  * This is called in response to VBOXGUEST_IOCTL_GUEST_CAPS_ACQUIRE as well as
@@ -2719,4 +2963,5 @@
         return VERR_INVALID_PARAMETER;
     }
+    Assert(!fOrMask || !fSessionTermination);
 
     /* The fNotMask no need to have all values valid, invalid ones will simply be ignored. */
@@ -2730,5 +2975,7 @@
     {
         rc = VbglGRAlloc((VMMDevRequestHeader **)&pReq, sizeof(*pReq), VMMDevReq_SetGuestCapabilities);
-        if (RT_FAILURE(rc))
+        if (RT_SUCCESS(rc))
+        { /* do nothing */ }
+        else if (!fSessionTermination)
         {
             LogRel(("vbgdAcquireSessionCapabilities: pSession=%p fOrMask=%#x fNotMask=%#x enmFlags=%#x: VbglGRAlloc failure: %Rrc\n",
@@ -2736,4 +2983,6 @@
             return rc;
         }
+        else
+            pReq = NULL; /* Ignore failure, we must do session cleanup. */
     }
 
@@ -2742,5 +2991,5 @@
      *
      * Note! We currently ignore anyone which may already have "set" the capabilities
-     *       in fOrMask.  This is simple, but perhaps not the best idea?
+     *       in fOrMask.  Perhaps not the best way to handle it, but it's simple...
      */
     RTSpinlockAcquire(pDevExt->EventSpinlock);
@@ -2772,5 +3021,5 @@
         return VINF_SUCCESS;
     }
-    Assert(pReq);
+    Assert(pReq || fSessionTermination);
 
     /*
@@ -2803,30 +3052,31 @@
          * If something changes (which is very likely), tell the host.
          */
-        if (fSessionAddedCaps || fSessionRemovedCaps)
-        {
-            rc = vbgdUpdateCapabilitiesOnHostWithReqAndLock(pDevExt, pReq);
-            if (RT_FAILURE(rc))
+        if (fSessionAddedCaps || fSessionRemovedCaps || pDevExt->fGuestCapsHost == UINT32_MAX)
+        {
+            Assert(pReq || fSessionTermination);
+            if (pReq)
             {
-                /*
-                 * Failed, roll back.  Except, don't roll back session cleanups.
-                 */
-                if (fSessionAddedCaps)
+                rc = vbgdUpdateCapabilitiesOnHostWithReqAndLock(pDevExt, pReq);
+                if (RT_FAILURE(rc) && !fSessionTermination)
                 {
-                    pSession->u32AquiredGuestCaps &= ~fSessionAddedCaps;
-                    pDevExt->u32GuestCapsAcquired &= ~fSessionAddedCaps;
+                    /* Failed, roll back. */
+                    if (fSessionAddedCaps)
+                    {
+                        pSession->u32AquiredGuestCaps &= ~fSessionAddedCaps;
+                        pDevExt->u32GuestCapsAcquired &= ~fSessionAddedCaps;
+                    }
+                    if (fSessionRemovedCaps)
+                    {
+                        pSession->u32AquiredGuestCaps |= fSessionRemovedCaps;
+                        pDevExt->u32GuestCapsAcquired |= fSessionRemovedCaps;
+                    }
+
+                    RTSpinlockRelease(pDevExt->EventSpinlock);
+                    LogRel(("vbgdAcquireSessionCapabilities: VBoxGuestSetGuestCapabilities failed: rc=%Rrc\n", rc));
+                    VbglGRFree(&pReq->header);
+                    return rc;
                 }
-                if (fSessionRemovedCaps && !fSessionTermination)
-                {
-                    pSession->u32AquiredGuestCaps |= fSessionRemovedCaps;
-                    pDevExt->u32GuestCapsAcquired |= fSessionRemovedCaps;
-                }
-
-                RTSpinlockRelease(pDevExt->EventSpinlock);
-                LogRel(("vbgdAcquireSessionCapabilities: VBoxGuestSetGuestCapabilities failed: rc=%Rrc\n", rc));
-                VbglGRFree(&pReq->header);
-                return rc;
             }
         }
-
     }
     else
@@ -2840,5 +3090,6 @@
 
     RTSpinlockRelease(pDevExt->EventSpinlock);
-    VbglGRFree(&pReq->header);
+    if (pReq)
+        VbglGRFree(&pReq->header);
 
     /*
@@ -2905,10 +3156,30 @@
  * @param   fOrMask             The capabilities to add.
  * @param   fNotMask            The capabilities to remove.
+ * @param   fSessionTermination Set if we're called by the session cleanup code.
+ *                              This tweaks the error handling so we perform
+ *                              proper session cleanup even if the host
+ *                              misbehaves.
  *
  * @remarks Takes the session spinlock.
  */
-static int vbgdSetSessionCapabilities(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, uint32_t fOrMask, uint32_t fNotMask)
-{
-    int rc;
+static int vbgdSetSessionCapabilities(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession,
+                                      uint32_t fOrMask, uint32_t fNotMask, bool fSessionTermination)
+{
+    /*
+     * Preallocate a request buffer so we can do all in one go without leaving the spinlock.
+     */
+    VMMDevReqGuestCapabilities2 *pReq;
+    int rc = VbglGRAlloc((VMMDevRequestHeader **)&pReq, sizeof(*pReq), VMMDevReq_SetGuestCapabilities);
+    if (RT_SUCCESS(rc))
+    { /* nothing */ }
+    else if (!fSessionTermination)
+    {
+        LogRel(("vbgdSetSessionCapabilities: VbglGRAlloc failure: %Rrc\n", rc));
+        return rc;
+    }
+    else
+        pReq = NULL; /* Ignore failure, we must do session cleanup. */
+
+
     RTSpinlockAcquire(pDevExt->SessionSpinlock);
 
@@ -2935,41 +3206,27 @@
         if (fChanged)
         {
-            bool        fGlobalChange = false;
-            uint32_t    iBit;
-            for (iBit = ASMBitFirstSetU32(fChanged) - 1; iBit < 32; iBit++)
-                if (RT_BIT_32(iBit) & fChanged)
+            bool fGlobalChange = vbgdBitUsageTrackerChange(&pDevExt->SetGuestCapsTracker, fChanged, fPrevious,
+                                                           pDevExt->cSessions, "SetGuestCapsTracker");
+
+            /*
+             * If there are global changes, update the capabilities on the host.
+             */
+            if (fGlobalChange || pDevExt->fGuestCapsHost == UINT32_MAX)
+            {
+                Assert(pReq || fSessionTermination);
+                if (pReq)
                 {
-                    if (fChanged & fPrevious)
+                    rc = vbgdUpdateCapabilitiesOnHostWithReqAndLock(pDevExt, pReq);
+
+                    /* On failure, roll back (unless it's session termination time). */
+                    if (RT_FAILURE(rc) && !fSessionTermination)
                     {
-                        pDevExt->acGuestCapsSet[iBit] -= 1;
-                        AssertMsg(pDevExt->acGuestCapsSet[iBit] <= pDevExt->cSessions,
-                                  ("pDevExt->acGuestCaps[%u]=%#x cSessions=%#x\n",
-                                   iBit, pDevExt->acGuestCapsSet[iBit], pDevExt->cSessions));
-                        fGlobalChange |= pDevExt->acGuestCapsSet[iBit] == 0;
+                        vbgdBitUsageTrackerChange(&pDevExt->SetGuestCapsTracker, fChanged, pSession->fCapabilities,
+                                                  pDevExt->cSessions, "SetGuestCapsTracker");
+                        pSession->fCapabilities = fPrevious;
                     }
-                    else
-                    {
-                        pDevExt->acGuestCapsSet[iBit] += 1;
-                        AssertMsg(pDevExt->acGuestCapsSet[iBit] > 0 && pDevExt->acGuestCapsSet[iBit] <= pDevExt->cSessions,
-                                  ("pDevExt->acGuestCaps[%u]=%#x cSessions=%#x\n",
-                                   iBit, pDevExt->acGuestCapsSet[iBit], pDevExt->cSessions));
-                        fGlobalChange |= pDevExt->acGuestCapsSet[iBit] == 1;
-                    }
-                    fChanged &= ~RT_BIT_32(iBit);
-                    if (!fChanged)
-                        break;
                 }
-
-            /*
-             * If there were global changes, update the capabilities on the host.
-             */
-            if (fGlobalChange)
-            {
-                RTSpinlockRelease(pDevExt->SessionSpinlock);
-
-                return vbgdUpdateCapabilitiesOnHost(pDevExt);
             }
         }
-        rc = VINF_SUCCESS;
     }
 #ifndef VBOXGUEST_DISREGARD_ACQUIRE_MODE_GUEST_CAPS
@@ -2979,4 +3236,6 @@
 
     RTSpinlockRelease(pDevExt->SessionSpinlock);
+    if (pReq)
+        VbglGRFree(&pReq->header);
     return rc;
 }
@@ -2999,5 +3258,5 @@
 
     if (!((pInfo->u32OrMask | pInfo->u32NotMask) & ~VMMDEV_GUEST_CAPABILITIES_MASK))
-        rc = vbgdSetSessionCapabilities(pDevExt, pSession, pInfo->u32OrMask, pInfo->u32NotMask);
+        rc = vbgdSetSessionCapabilities(pDevExt, pSession, pInfo->u32OrMask, pInfo->u32NotMask, false /*fSessionTermination*/);
     else
         rc = VERR_INVALID_PARAMETER;
Index: trunk/src/VBox/Additions/common/VBoxGuest/VBoxGuestInternal.h
===================================================================
--- trunk/src/VBox/Additions/common/VBoxGuest/VBoxGuestInternal.h	(revision 54605)
+++ trunk/src/VBox/Additions/common/VBoxGuest/VBoxGuestInternal.h	(revision 54606)
@@ -109,4 +109,23 @@
 typedef VBOXGUESTMEMBALLOON *PVBOXGUESTMEMBALLOON;
 
+
+/**
+ * Per bit usage tracker for a uint32_t mask.
+ *
+ * Used for optimal handling of guest properties, mouse status and event filter.
+ */
+typedef struct VBOXGUESTBITUSAGETRACER
+{
+    /** Per bit usage counters. */
+    uint32_t        acPerBitUsage[32];
+    /** The current mask according to acPerBitUsage. */
+    uint32_t        fMask;
+} VBOXGUESTBITUSAGETRACER;
+/** Pointer to a per bit usage tracker.  */
+typedef VBOXGUESTBITUSAGETRACER *PVBOXGUESTBITUSAGETRACER;
+/** Pointer to a const per bit usage tracker.  */
+typedef VBOXGUESTBITUSAGETRACER const *PCVBOXGUESTBITUSAGETRACER;
+
+
 /**
  * VBox guest device (data) extension.
@@ -118,6 +137,4 @@
     /** Pointer to the mapping of the VMMDev adapter memory. */
     VMMDevMemory volatile      *pVMMDevMemory;
-    /** Events we won't permit anyone to filter out. */
-    uint32_t                    fFixedEvents;
     /** The memory object reserving space for the guest mappings. */
     RTR0MEMOBJ                  hGuestMappings;
@@ -173,5 +190,23 @@
     VBoxGuestMouseSetNotifyCallback MouseNotifyCallback;
 
-    /** @name Guest Capabilities.
+    /** @name Host Event Filtering
+     * @{ */
+    /** Events we won't permit anyone to filter out. */
+    uint32_t                    fFixedEvents;
+    /** Usage counters for the host events. (Fixed events are not included.) */
+    VBOXGUESTBITUSAGETRACER     EventFilterTracker;
+    /** The event filter last reported to the host (UINT32_MAX on failure). */
+    uint32_t                    fEventFilterHost;
+    /** @} */
+
+    /** @name Mouse Status
+     * @{ */
+    /** Usage counters for the mouse statuses (VMMDEV_MOUSE_XXX). */
+    VBOXGUESTBITUSAGETRACER     MouseStatusTracker;
+    /** The mouse status last reported to the host (UINT32_MAX on failure). */
+    uint32_t                    fMouseStatusHost;
+    /** @} */
+
+    /** @name Guest Capabilities
      * @{ */
     /** Guest capabilities which have been set to "acquire" mode.  This means
@@ -190,6 +225,6 @@
     /** Usage counters for guest capabilities in "set" mode. Indexed by
      *  capability bit number, one count per session using a capability. */
-    uint32_t                    acGuestCapsSet[32];
-    /** The set guest capabilities reported to the host. */
+    VBOXGUESTBITUSAGETRACER     SetGuestCapsTracker;
+    /** The guest capabilities last reported to the host (UINT32_MAX on failure). */
     uint32_t                    fGuestCapsHost;
     /** @} */
@@ -241,8 +276,8 @@
      * Used to implement polling.  */
     uint32_t volatile           u32MousePosChangedSeq;
-    /** VMMDev events requested.  An event type requested in any guest session
-     * will be added to the host filter.
-     * Use under the VBOXGUESTDEVEXT#SessionSpinlock lock. */
-    uint32_t                    fFilterMask;
+    /** Host events requested by the session.
+     * An event type requested in any guest session will be added to the host
+     * filter.  Protected by VBOXGUESTDEVEXT::SessionSpinlock. */
+    uint32_t                    fEventFilter;
     /** Guest capabilities held in "acquired" by this session.
      * Protected by VBOXGUESTDEVEXT::SessionSpinlock, but is unfortunately read
