VBoxServiceBalloon.cpp revision c70fcf9f64f7571fad767b2b66e82a3d21091ffa
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync * VBoxService - Memory Ballooning.
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync * Copyright (C) 2006-2010 Sun Microsystems, Inc.
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync * available from http://www.virtualbox.org. This file is free software;
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync * you can redistribute it and/or modify it under the terms of the GNU
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync * General Public License (GPL) as published by the Free Software
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync * additional information or have any questions.
2d97f8baccdd684bc0a8a15eb86bbe9ff2b85374vboxsync/*******************************************************************************
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync* Header Files *
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync*******************************************************************************/
032703cba22135d6032705fc2d67dd1294a6491avboxsync/*******************************************************************************
315f68b04971772d94ba6c4408eaa19559a77cedvboxsync* Global Variables *
032703cba22135d6032705fc2d67dd1294a6491avboxsync*******************************************************************************/
032703cba22135d6032705fc2d67dd1294a6491avboxsync/** The balloon size. */
032703cba22135d6032705fc2d67dd1294a6491avboxsync/** The semaphore we're blocking on. */
315f68b04971772d94ba6c4408eaa19559a77cedvboxsyncstatic RTSEMEVENTMULTI g_MemBalloonEvent = NIL_RTSEMEVENTMULTI;
032703cba22135d6032705fc2d67dd1294a6491avboxsync/** The array holding the R3 pointers of the balloon. */
032703cba22135d6032705fc2d67dd1294a6491avboxsync/** True = madvise(MADV_DONTFORK) works, false otherwise. */
032703cba22135d6032705fc2d67dd1294a6491avboxsync * Check whether madvise() works.
032703cba22135d6032705fc2d67dd1294a6491avboxsync g_fSysMadviseWorks = madvise(pv, PAGE_SIZE, MADV_DONTFORK) == 0;
032703cba22135d6032705fc2d67dd1294a6491avboxsync * Allocate a chunk of the balloon. Fulfil the prerequisite that we can lock this memory
032703cba22135d6032705fc2d67dd1294a6491avboxsync * and protect it against fork() in R0. See also suplibOsPageAlloc().
032703cba22135d6032705fc2d67dd1294a6491avboxsyncstatic void* VBoxServiceBalloonAllocChunk(void)
315f68b04971772d94ba6c4408eaa19559a77cedvboxsync pu8 = (char*)mmap(NULL, cb, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync * It is not fatal if we fail here but a forked child (e.g. the ALSA sound server)
315f68b04971772d94ba6c4408eaa19559a77cedvboxsync * could crash. Linux < 2.6.16 does not implement madvise(MADV_DONTFORK) but the
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync * kernel seems to split bigger VMAs and that is all that we want -- later we set the
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync * VM_DONTCOPY attribute in supdrvOSLockMemOne().
315f68b04971772d94ba6c4408eaa19559a77cedvboxsync * madvise(MADV_DONTFORK) is not available (most probably Linux 2.4). Enclose any
315f68b04971772d94ba6c4408eaa19559a77cedvboxsync * mmapped region by two unmapped pages to guarantee that there is exactly one VM
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync * area struct of the very same size as the mmap area.
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync RTMemProtect(pu8 + cb - PAGE_SIZE, PAGE_SIZE, RTMEM_PROT_NONE);
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync * Free an allocated chunk undoing VBoxServiceBalloonAllocChunk().
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync /* This is not really necessary */
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync RTMemProtect(pu8, PAGE_SIZE, RTMEM_PROT_READ | RTMEM_PROT_WRITE);
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync RTMemProtect(pu8 + cb - PAGE_SIZE, PAGE_SIZE, RTMEM_PROT_READ | RTMEM_PROT_WRITE);
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync * Adapt the R0 memory balloon by granting/reclaiming 1MB chunks to/from R0.
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync * returns IPRT status code.
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync * @param cNewChunks The new number of 1MB chunks in the balloon.
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsyncstatic int VBoxServiceBalloonSetUser(uint32_t cNewChunks)
032703cba22135d6032705fc2d67dd1294a6491avboxsync VBoxServiceVerbose(3, "VBoxServiceBalloonSetUser: cNewChunks=%u g_cMemBalloonChunks=%u\n", cNewChunks, g_cMemBalloonChunks);
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync /* inflate */
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync g_pavBalloon = (void**)RTMemRealloc(g_pavBalloon, cNewChunks * sizeof(void*));
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync rc = VbglR3MemBalloonChange(pv, /* inflate=*/ true);
032703cba22135d6032705fc2d67dd1294a6491avboxsync * Protect against access by dangling pointers (ignore errors as it may fail).
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync * On Solaris it corrupts the address space leaving the process unkillable. This
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync * could perhaps be related to what the underlying segment driver does; currently
315f68b04971772d94ba6c4408eaa19559a77cedvboxsync * just disable it.
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync RTMemProtect(pv, VMMDEV_MEMORY_BALLOON_CHUNK_SIZE, RTMEM_PROT_NONE);
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync VBoxServiceVerbose(3, "VBoxServiceBalloonSetUser: inflation complete. chunks=%u rc=%d\n", i, rc);
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync /* deflate */
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync rc = VbglR3MemBalloonChange(pv, /* inflate=*/ false);
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync /* unprotect */
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync RTMemProtect(pv, VMMDEV_MEMORY_BALLOON_CHUNK_SIZE, RTMEM_PROT_READ | RTMEM_PROT_WRITE);
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync VBoxServiceVerbose(3, "VBoxServiceBalloonSetUser: deflation complete. chunks=%u rc=%d\n", i, rc);
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync/** @copydoc VBOXSERVICE::pfnPreInit */
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsyncstatic DECLCALLBACK(int) VBoxServiceBalloonPreInit(void)
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync/** @copydoc VBOXSERVICE::pfnOption */
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsyncstatic DECLCALLBACK(int) VBoxServiceBalloonOption(const char **ppszShort, int argc, char **argv, int *pi)
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync/** @copydoc VBOXSERVICE::pfnInit */
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsyncstatic DECLCALLBACK(int) VBoxServiceBalloonInit(void)
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync int rc = RTSemEventMultiCreate(&g_MemBalloonEvent);
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync /* Check balloon size */
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync rc = VbglR3MemBalloonRefresh(&cNewChunks, &fHandleInR3);
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync VBoxServiceVerbose(3, "VBoxMemBalloonInit: new balloon size %d MB (%s memory)\n",
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync VBoxServiceVerbose(3, "VBoxMemBalloonInit: VbglR3MemBalloonRefresh failed with %Rrc\n", rc);
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync /* We shouldn't fail here if ballooning isn't available. This can have several reasons,
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync * for instance, host too old (which is not that fatal). */
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync * Query the size of the memory balloon, given as a page count.
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync * @returns Number of pages.
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync * @param cbPage The page size.
b64efece437bfca8872b81be9d0568ba90389d91vboxsyncuint32_t VBoxServiceBalloonQueryPages(uint32_t cbPage)
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync return g_cMemBalloonChunks * (VMMDEV_MEMORY_BALLOON_CHUNK_SIZE / cbPage);
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync/** @copydoc VBOXSERVICE::pfnWorker */
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsyncDECLCALLBACK(int) VBoxServiceBalloonWorker(bool volatile *pfShutdown)
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync /* Start monitoring of the stat event change event. */
032703cba22135d6032705fc2d67dd1294a6491avboxsync int rc = VbglR3CtlFilterMask(VMMDEV_EVENT_BALLOON_CHANGE_REQUEST, 0);
3755e2bacafa2dd718108ad1a18661dcd9566bd8vboxsync VBoxServiceVerbose(3, "VBoxServiceBalloonWorker: VbglR3CtlFilterMask failed with %Rrc\n", rc);
032703cba22135d6032705fc2d67dd1294a6491avboxsync * Tell the control thread that it can continue
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync * spawning services.
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync * Now enter the loop retrieving runtime data continuously.
3755e2bacafa2dd718108ad1a18661dcd9566bd8vboxsync /* Check if an update interval change is pending. */
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync rc = VbglR3WaitEvent(VMMDEV_EVENT_BALLOON_CHANGE_REQUEST, 0 /* no wait */, &fEvents);
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync && (fEvents & VMMDEV_EVENT_BALLOON_CHANGE_REQUEST))
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync rc = VbglR3MemBalloonRefresh(&cNewChunks, &fHandleInR3);
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync VBoxServiceVerbose(3, "VBoxServiceBalloonWorker: new balloon size %d MB (%s memory)\n",
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync VBoxServiceVerbose(3, "VBoxServiceBalloonWorker: failed to set balloon size %d MB (%s memory)\n",
032703cba22135d6032705fc2d67dd1294a6491avboxsync VBoxServiceVerbose(3, "VBoxServiceBalloonWorker: successfully set requested balloon size %d.\n", cNewChunks);
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync VBoxServiceVerbose(3, "VBoxServiceBalloonWorker: VbglR3MemBalloonRefresh failed with %Rrc\n", rc);
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync * Block for a while.
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync * The event semaphore takes care of ignoring interruptions and it
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync * allows us to implement service wakeup later.
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync int rc2 = RTSemEventMultiWait(g_MemBalloonEvent, 5000);
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync VBoxServiceError("RTSemEventMultiWait failed; rc2=%Rrc\n", rc2);
3755e2bacafa2dd718108ad1a18661dcd9566bd8vboxsync /* Cancel monitoring of the memory balloon change event. */
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync rc = VbglR3CtlFilterMask(0, VMMDEV_EVENT_BALLOON_CHANGE_REQUEST);
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync VBoxServiceVerbose(3, "VBoxServiceBalloonWorker: VbglR3CtlFilterMask failed with %Rrc\n", rc);
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync VBoxServiceVerbose(3, "VBoxServiceBalloonWorker: finished mem balloon change request thread\n");
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync/** @copydoc VBOXSERVICE::pfnTerm */
b64efece437bfca8872b81be9d0568ba90389d91vboxsyncstatic DECLCALLBACK(void) VBoxServiceBalloonTerm(void)
b64efece437bfca8872b81be9d0568ba90389d91vboxsync/** @copydoc VBOXSERVICE::pfnStop */
b64efece437bfca8872b81be9d0568ba90389d91vboxsyncstatic DECLCALLBACK(void) VBoxServiceBalloonStop(void)
b64efece437bfca8872b81be9d0568ba90389d91vboxsync * The 'memballoon' service description.
b64efece437bfca8872b81be9d0568ba90389d91vboxsync /* pszName. */
b64efece437bfca8872b81be9d0568ba90389d91vboxsync "memballoon",
b64efece437bfca8872b81be9d0568ba90389d91vboxsync /* pszDescription. */
b64efece437bfca8872b81be9d0568ba90389d91vboxsync "Memory Ballooning",
ab37cc785e1bcbaaad50b8fb791bfecba6f4b4d5vboxsync /* pszUsage. */
b64efece437bfca8872b81be9d0568ba90389d91vboxsync /* pszOptions. */
b64efece437bfca8872b81be9d0568ba90389d91vboxsync /* methods */