Index: /trunk/src/VBox/VMM/GMM.cpp
===================================================================
--- /trunk/src/VBox/VMM/GMM.cpp	(revision 27083)
+++ /trunk/src/VBox/VMM/GMM.cpp	(revision 27084)
@@ -276,22 +276,16 @@
 
 
-#if 0 /* impractical */
-GMMR3DECL(int)  GMMR3BalloonedPages(PVM pVM, uint32_t cBalloonedPages, uint32_t cPagesToFree, PGMMFREEPAGEDESC paPages, bool fCompleted)
+/**
+ * @see GMMR0BalloonedPages
+ */
+GMMR3DECL(int)  GMMR3BalloonedPages(PVM pVM, bool fInflate, uint32_t cBalloonedPages)
 {
     GMMBALLOONEDPAGESREQ Req;
     Req.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
     Req.Hdr.cbReq = sizeof(Req);
+    Req.fInflate = fInflate;
+    Req.cBalloonedPages = cBalloonedPages;
 
     return VMMR3CallR0(pVM, VMMR0_DO_GMM_BALLOONED_PAGES, 0, &Req.Hdr);
-}
-#endif
-
-
-/**
- * @see GMMR0DeflatedBalloon
- */
-GMMR3DECL(int)  GMMR3DeflatedBalloon(PVM pVM, uint32_t cPages)
-{
-    return VMMR3CallR0(pVM, VMMR0_DO_GMM_DEFLATED_BALLOON, cPages, NULL);
 }
 
Index: /trunk/src/VBox/VMM/PGMPhys.cpp
===================================================================
--- /trunk/src/VBox/VMM/PGMPhys.cpp	(revision 27083)
+++ /trunk/src/VBox/VMM/PGMPhys.cpp	(revision 27084)
@@ -772,5 +772,5 @@
 
 /**
- * Rendezvous callback used by PGMR3PhysFreeRamPages that frees a range of guest physical pages
+ * Rendezvous callback used by PGMR3ChangeMemBalloon that changes the memory balloon size
  *
  * This is only called on one of the EMTs while the other ones are waiting for
@@ -782,33 +782,20 @@
  * @param   pvUser      User parameter
  */
-static DECLCALLBACK(VBOXSTRICTRC) pgmR3PhysFreeRamPagesRendezvous(PVM pVM, PVMCPU pVCpu, void *pvUser)
+static DECLCALLBACK(VBOXSTRICTRC) pgmR3PhysChangeMemBalloonRendezvous(PVM pVM, PVMCPU pVCpu, void *pvUser)
 {
     uintptr_t          *paUser          = (uintptr_t *)pvUser;
-    unsigned            cPages          = paUser[0];
-    RTGCPHYS           *paPhysPage      = (RTGCPHYS *)paUser[1];
+    bool                fInflate        = !!paUser[0];
+    unsigned            cPages          = paUser[1];
+    RTGCPHYS           *paPhysPage      = (RTGCPHYS *)paUser[2];
     uint32_t            cPendingPages   = 0;
     PGMMFREEPAGESREQ    pReq;
+    int                 rc;
 
     pgmLock(pVM);
-    int rc = GMMR3FreePagesPrepare(pVM, &pReq, PGMPHYS_FREE_PAGE_BATCH_SIZE, GMMACCOUNT_BASE);
-    if (RT_FAILURE(rc))
-    {
-        pgmUnlock(pVM);
-        AssertLogRelRC(rc);
-        return rc;
-    }
-
-    /* Iterate the pages. */
-    for (unsigned i = 0; i < cPages; i++)
-    {
-        PPGMPAGE pPage = pgmPhysGetPage(&pVM->pgm.s, paPhysPage[i]);
-        if (    pPage == NULL
-            ||  pPage->uTypeY != PGMPAGETYPE_RAM)
-        {
-            Log(("PGMR3PhysFreePageRange: invalid physical page %RGp pPage->u3Type=%d\n", paPhysPage[i], (pPage) ? pPage->uTypeY : 0));
-            break;
-        }
-
-        rc = pgmPhysFreePage(pVM, pReq, &cPendingPages, pPage, paPhysPage[i]);
+
+    if (fInflate)
+    {
+        /* Replace pages with ZERO pages. */
+        rc = GMMR3FreePagesPrepare(pVM, &pReq, PGMPHYS_FREE_PAGE_BATCH_SIZE, GMMACCOUNT_BASE);
         if (RT_FAILURE(rc))
         {
@@ -817,22 +804,45 @@
             return rc;
         }
-    }
-
-    if (cPendingPages)
-    {
-        rc = GMMR3FreePagesPerform(pVM, pReq, cPendingPages);
-        if (RT_FAILURE(rc))
-        {
-            pgmUnlock(pVM);
-            AssertLogRelRC(rc);
-            return rc;
-        }
-    }
-    GMMR3FreePagesCleanup(pReq);
-
-    /* Flush the PGM pool cache as we might have stale references to pages that we just freed. */
-    pgmR3PoolClearAllRendezvous(pVM, pVCpu, NULL);
-
+
+        /* Iterate the pages. */
+        for (unsigned i = 0; i < cPages; i++)
+        {
+            PPGMPAGE pPage = pgmPhysGetPage(&pVM->pgm.s, paPhysPage[i]);
+            if (    pPage == NULL
+                ||  pPage->uTypeY != PGMPAGETYPE_RAM)
+            {
+                Log(("PGMR3PhysFreePageRange: invalid physical page %RGp pPage->u3Type=%d\n", paPhysPage[i], (pPage) ? pPage->uTypeY : 0));
+                break;
+            }
+
+            rc = pgmPhysFreePage(pVM, pReq, &cPendingPages, pPage, paPhysPage[i]);
+            if (RT_FAILURE(rc))
+            {
+                pgmUnlock(pVM);
+                AssertLogRelRC(rc);
+                return rc;
+            }
+        }
+
+        if (cPendingPages)
+        {
+            rc = GMMR3FreePagesPerform(pVM, pReq, cPendingPages);
+            if (RT_FAILURE(rc))
+            {
+                pgmUnlock(pVM);
+                AssertLogRelRC(rc);
+                return rc;
+            }
+        }
+        GMMR3FreePagesCleanup(pReq);
+
+        /* Flush the PGM pool cache as we might have stale references to pages that we just freed. */
+        pgmR3PoolClearAllRendezvous(pVM, pVCpu, NULL);
+    }
+
+    /* Notify GMM about the balloon change. */
+    rc = GMMR3BalloonedPages(pVM, fInflate, cPages);
     pgmUnlock(pVM);
+    AssertLogRelRC(rc);
     return rc;
 }
@@ -843,14 +853,16 @@
  * @returns VBox status code.
  * @param   pVM         The VM handle.
+ * @param   fInflate    Inflate or deflate memory balloon
  * @param   cPages      Number of pages to free
  * @param   paPhysPage  Array of guest physical addresses
  */
-static DECLCALLBACK(void) pgmR3PhysFreeRamPagesHelper(PVM pVM, unsigned cPages, RTGCPHYS *paPhysPage)
-{
-    uintptr_t paUser[2];
-
-    paUser[0] = cPages;
-    paUser[1] = (uintptr_t)paPhysPage;
-    int rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE, pgmR3PhysFreeRamPagesRendezvous, (void *)paUser);
+static DECLCALLBACK(void) pgmR3PhysChangeMemBalloonHelper(PVM pVM, bool fInflate, unsigned cPages, RTGCPHYS *paPhysPage)
+{
+    uintptr_t paUser[3];
+
+    paUser[0] = fInflate;
+    paUser[1] = cPages;
+    paUser[2] = (uintptr_t)paPhysPage;
+    int rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE, pgmR3PhysChangeMemBalloonRendezvous, (void *)paUser);
     AssertRC(rc);
 
@@ -860,16 +872,15 @@
 
 /**
- * Frees a range of ram pages, replacing them with ZERO pages
+ * Inflate or deflate a memory balloon
  *
  * @returns VBox status code.
  * @param   pVM         The VM handle.
+ * @param   fInflate    Inflate or deflate memory balloon
  * @param   cPages      Number of pages to free
  * @param   paPhysPage  Array of guest physical addresses
  */
-VMMR3DECL(int) PGMR3PhysFreeRamPages(PVM pVM, unsigned cPages, RTGCPHYS *paPhysPage)
+VMMR3DECL(int) PGMR3PhysChangeMemBalloon(PVM pVM, bool fInflate, unsigned cPages, RTGCPHYS *paPhysPage)
 {
     int rc;
-
-    /* Currently only used by the VMM device in responds to a balloon request. */
 
     /* We own the IOM lock here and could cause a deadlock by waiting for another VCPU that is blocking on the IOM lock.
@@ -884,14 +895,15 @@
         memcpy(paPhysPageCopy, paPhysPage, cbPhysPage);
 
-        rc = VMR3ReqCallNoWait(pVM, VMCPUID_ANY_QUEUE, (PFNRT)pgmR3PhysFreeRamPagesHelper, 3, pVM, cPages, paPhysPageCopy);
+        rc = VMR3ReqCallNoWait(pVM, VMCPUID_ANY_QUEUE, (PFNRT)pgmR3PhysChangeMemBalloonHelper, 4, pVM, fInflate, cPages, paPhysPageCopy);
         AssertRC(rc);
     }
     else
     {
-        uintptr_t paUser[2];
-
-        paUser[0] = cPages;
-        paUser[1] = (uintptr_t)paPhysPage;
-        rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE, pgmR3PhysFreeRamPagesRendezvous, (void *)paUser);
+        uintptr_t paUser[3];
+
+        paUser[0] = fInflate;
+        paUser[1] = cPages;
+        paUser[2] = (uintptr_t)paPhysPage;
+        rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE, pgmR3PhysChangeMemBalloonRendezvous, (void *)paUser);
         AssertRC(rc);
     }
Index: /trunk/src/VBox/VMM/VMMR0/GMMR0.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR0/GMMR0.cpp	(revision 27083)
+++ /trunk/src/VBox/VMM/VMMR0/GMMR0.cpp	(revision 27084)
@@ -1079,5 +1079,5 @@
  * The initial resource reservations.
  *
- * This will make memory reservations according to policy and priority. If there isn't
+ * This will make memory reservations according to policy and priority. If there aren't
  * sufficient resources available to sustain the VM this function will fail and all
  * future allocations requests will fail as well.
@@ -1813,5 +1813,5 @@
     {
         case GMMACCOUNT_BASE:
-            if (RT_UNLIKELY(pGVM->gmm.s.Allocated.cBasePages + cPages > pGVM->gmm.s.Reserved.cBasePages))
+            if (RT_UNLIKELY(pGVM->gmm.s.Allocated.cBasePages + pGVM->gmm.s.cBalloonedPages + cPages > pGVM->gmm.s.Reserved.cBasePages))
             {
                 Log(("gmmR0AllocatePages: Reserved=%#llx Allocated+Requested=%#llx+%#x!\n",
@@ -2324,5 +2324,5 @@
         GMMPAGEDESC    PageDesc;
 
-        if (RT_UNLIKELY(pGVM->gmm.s.Allocated.cBasePages + cPages > pGVM->gmm.s.Reserved.cBasePages))
+        if (RT_UNLIKELY(pGVM->gmm.s.Allocated.cBasePages + pGVM->gmm.s.cBalloonedPages + cPages > pGVM->gmm.s.Reserved.cBasePages))
         {
             Log(("GMMR0AllocateLargePage: Reserved=%#llx Allocated+Requested=%#llx+%#x!\n",
@@ -2841,8 +2841,4 @@
  * ballooned.
  *
- * Since the whole purpose of ballooning is to free up guest RAM pages, this API
- * may also be given a set of related pages to be freed. These pages are assumed
- * to be on the base account.
- *
  * @returns VBox status code:
  * @retval  xxx
@@ -2850,16 +2846,13 @@
  * @param   pVM                 Pointer to the shared VM structure.
  * @param   idCpu               VCPU id
+ * @param   fInflate            Inflate or deflate the balloon
  * @param   cBalloonedPages     The number of pages that was ballooned.
- * @param   cPagesToFree        The number of pages to be freed.
- * @param   paPages             Pointer to the page descriptors for the pages that's to be freed.
- * @param   fCompleted          Indicates whether the ballooning request was completed (true) or
- *                              if there is more pages to come (false). If the ballooning was not
- *                              not triggered by the GMM, don't set this.
+ *
  * @thread  EMT.
  */
-GMMR0DECL(int) GMMR0BalloonedPages(PVM pVM, VMCPUID idCpu, uint32_t cBalloonedPages, uint32_t cPagesToFree, PGMMFREEPAGEDESC paPages, bool fCompleted)
-{
-    LogFlow(("GMMR0BalloonedPages: pVM=%p cBalloonedPages=%#x cPagestoFree=%#x paPages=%p enmAccount=%d fCompleted=%RTbool\n",
-             pVM, cBalloonedPages, cPagesToFree, paPages, fCompleted));
+GMMR0DECL(int) GMMR0BalloonedPages(PVM pVM, VMCPUID idCpu, bool fInflate, uint32_t cBalloonedPages)
+{
+    LogFlow(("GMMR0BalloonedPages: pVM=%p fInflate=%RTBool cBalloonedPages=%#x\n",
+             pVM, fInflate, cBalloonedPages));
 
     /*
@@ -2873,12 +2866,5 @@
         return rc;
 
-    AssertPtrReturn(paPages, VERR_INVALID_PARAMETER);
     AssertMsgReturn(cBalloonedPages < RT_BIT(32 - PAGE_SHIFT), ("%#x\n", cBalloonedPages), VERR_INVALID_PARAMETER);
-    AssertMsgReturn(cPagesToFree <= cBalloonedPages, ("%#x\n", cPagesToFree), VERR_INVALID_PARAMETER);
-
-    for (unsigned iPage = 0; iPage < cPagesToFree; iPage++)
-        AssertMsgReturn(    paPages[iPage].idPage <= GMM_PAGEID_LAST
-                        /*||  paPages[iPage].idPage == NIL_GMM_PAGEID*/,
-                        ("#%#x: %#x\n", iPage, paPages[iPage].idPage), VERR_INVALID_PARAMETER);
 
     /*
@@ -2889,44 +2875,49 @@
     if (GMM_CHECK_SANITY_UPON_ENTERING(pGMM))
     {
-
-        if (pGVM->gmm.s.Allocated.cBasePages >= cPagesToFree)
-        {
-            /*
-             * Record the ballooned memory.
-             */
-            pGMM->cBalloonedPages += cBalloonedPages;
-            if (pGVM->gmm.s.cReqBalloonedPages)
+        if (fInflate)
+        {
+            if (pGVM->gmm.s.Allocated.cBasePages >= cBalloonedPages)
             {
-                pGVM->gmm.s.cBalloonedPages += cBalloonedPages;
-                pGVM->gmm.s.cReqActuallyBalloonedPages += cBalloonedPages;
-                if (fCompleted)
+                /*
+                 * Record the ballooned memory.
+                 */
+                pGMM->cBalloonedPages += cBalloonedPages;
+                if (pGVM->gmm.s.cReqBalloonedPages)
                 {
-                    Log(("GMMR0BalloonedPages: +%#x - Global=%#llx;  / VM: Total=%#llx Req=%#llx Actual=%#llx (completed)\n", cBalloonedPages,
+                    /* Codepath never taken. Might be interesting in the future to request ballooned memory from guests in low memory conditions.. */
+                    AssertFailed();
+
+                    pGVM->gmm.s.cBalloonedPages += cBalloonedPages;
+                    pGVM->gmm.s.cReqActuallyBalloonedPages += cBalloonedPages;
+                    Log(("GMMR0BalloonedPages: +%#x - Global=%#llx / VM: Total=%#llx Req=%#llx Actual=%#llx (pending)\n", cBalloonedPages,
                          pGMM->cBalloonedPages, pGVM->gmm.s.cBalloonedPages, pGVM->gmm.s.cReqBalloonedPages, pGVM->gmm.s.cReqActuallyBalloonedPages));
-
-                    /*
-                     * Anything we need to do here now when the request has been completed?
-                     */
-                    pGVM->gmm.s.cReqBalloonedPages = 0;
                 }
                 else
-                    Log(("GMMR0BalloonedPages: +%#x - Global=%#llx / VM: Total=%#llx Req=%#llx Actual=%#llx (pending)\n", cBalloonedPages,
-                         pGMM->cBalloonedPages, pGVM->gmm.s.cBalloonedPages, pGVM->gmm.s.cReqBalloonedPages, pGVM->gmm.s.cReqActuallyBalloonedPages));
+                {
+                    pGVM->gmm.s.cBalloonedPages += cBalloonedPages;
+                    Log(("GMMR0BalloonedPages: +%#x - Global=%#llx / VM: Total=%#llx (user)\n",
+                         cBalloonedPages, pGMM->cBalloonedPages, pGVM->gmm.s.cBalloonedPages));
+                }
             }
             else
+                rc = VERR_GMM_ATTEMPT_TO_FREE_TOO_MUCH;
+        }
+        else
+        {
+            /* Deflate. */
+            if (pGVM->gmm.s.cBalloonedPages >= cBalloonedPages)
             {
-                pGVM->gmm.s.cBalloonedPages += cBalloonedPages;
-                Log(("GMMR0BalloonedPages: +%#x - Global=%#llx / VM: Total=%#llx (user)\n",
+                /*
+                 * Record the ballooned memory.
+                 */
+                Assert(pGMM->cBalloonedPages >= cBalloonedPages);
+                pGMM->cBalloonedPages       -= cBalloonedPages;
+                pGVM->gmm.s.cBalloonedPages -= cBalloonedPages;
+                Log(("GMMR0BalloonedPages: -%#x - Global=%#llx / VM: Total=%#llx (user)\n",
                      cBalloonedPages, pGMM->cBalloonedPages, pGVM->gmm.s.cBalloonedPages));
             }
-
-            /*
-             * Any pages to free?
-             */
-            if (cPagesToFree)
-                rc = gmmR0FreePages(pGMM, pGVM, cPagesToFree, paPages, GMMACCOUNT_BASE);
-        }
-        else
-            rc = VERR_GMM_ATTEMPT_TO_FREE_TOO_MUCH;
+            else
+                rc = VERR_GMM_ATTEMPT_TO_DEFLATE_TOO_MUCH;
+        }
         GMM_CHECK_SANITY_UPON_LEAVING(pGMM);
     }
@@ -2954,12 +2945,9 @@
     AssertPtrReturn(pVM, VERR_INVALID_POINTER);
     AssertPtrReturn(pReq, VERR_INVALID_POINTER);
-    AssertMsgReturn(pReq->Hdr.cbReq >= RT_UOFFSETOF(GMMBALLOONEDPAGESREQ, aPages[0]),
-                    ("%#x < %#x\n", pReq->Hdr.cbReq, RT_UOFFSETOF(GMMBALLOONEDPAGESREQ, aPages[0])),
+    AssertMsgReturn(pReq->Hdr.cbReq == sizeof(GMMBALLOONEDPAGESREQ),
+                    ("%#x < %#x\n", pReq->Hdr.cbReq, sizeof(GMMBALLOONEDPAGESREQ)),
                     VERR_INVALID_PARAMETER);
-    AssertMsgReturn(pReq->Hdr.cbReq == RT_UOFFSETOF(GMMBALLOONEDPAGESREQ, aPages[pReq->cPagesToFree]),
-                    ("%#x != %#x\n", pReq->Hdr.cbReq, RT_UOFFSETOF(GMMBALLOONEDPAGESREQ, aPages[pReq->cPagesToFree])),
-                    VERR_INVALID_PARAMETER);
-
-    return GMMR0BalloonedPages(pVM, idCpu, pReq->cBalloonedPages, pReq->cPagesToFree, &pReq->aPages[0], pReq->fCompleted);
+
+    return GMMR0BalloonedPages(pVM, idCpu, pReq->fInflate, pReq->cBalloonedPages);
 }
 
Index: /trunk/src/VBox/VMM/VMMR0/VMMR0.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR0/VMMR0.cpp	(revision 27083)
+++ /trunk/src/VBox/VMM/VMMR0/VMMR0.cpp	(revision 27084)
@@ -915,9 +915,4 @@
             return GMMR0BalloonedPagesReq(pVM, idCpu, (PGMMBALLOONEDPAGESREQ)pReqHdr);
 
-        case VMMR0_DO_GMM_DEFLATED_BALLOON:
-            if (pReqHdr)
-                return VERR_INVALID_PARAMETER;
-            return GMMR0DeflatedBalloon(pVM, idCpu, (uint32_t)u64Arg);
-
         case VMMR0_DO_GMM_MAP_UNMAP_CHUNK:
             if (u64Arg)
@@ -1116,5 +1111,4 @@
             case VMMR0_DO_GMM_FREE_PAGES:
             case VMMR0_DO_GMM_BALLOONED_PAGES:
-            case VMMR0_DO_GMM_DEFLATED_BALLOON:
             /* On the mac we might not have a valid jmp buf, so check these as well. */
             case VMMR0_DO_VMMR0_INIT:
