VBoxServiceBalloon.cpp revision c70fcf9f64f7571fad767b2b66e82a3d21091ffa
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync/* $Id$ */
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync/** @file
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync * VBoxService - Memory Ballooning.
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync */
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync
b3eb676cebf5407921b8f535095ca7655edb9db3vboxsync/*
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync * Copyright (C) 2006-2010 Sun Microsystems, Inc.
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync *
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 *
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.
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync */
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync
2d97f8baccdd684bc0a8a15eb86bbe9ff2b85374vboxsync/*******************************************************************************
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync* Header Files *
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync*******************************************************************************/
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync#include <iprt/assert.h>
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync#include <iprt/mem.h>
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync#include <iprt/stream.h>
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync#include <iprt/string.h>
032703cba22135d6032705fc2d67dd1294a6491avboxsync#include <iprt/semaphore.h>
032703cba22135d6032705fc2d67dd1294a6491avboxsync#include <iprt/system.h>
032703cba22135d6032705fc2d67dd1294a6491avboxsync#include <iprt/thread.h>
032703cba22135d6032705fc2d67dd1294a6491avboxsync#include <iprt/time.h>
315f68b04971772d94ba6c4408eaa19559a77cedvboxsync#include <VBox/VBoxGuestLib.h>
315f68b04971772d94ba6c4408eaa19559a77cedvboxsync#include "VBoxServiceInternal.h"
032703cba22135d6032705fc2d67dd1294a6491avboxsync#include "VBoxServiceUtils.h"
032703cba22135d6032705fc2d67dd1294a6491avboxsync
032703cba22135d6032705fc2d67dd1294a6491avboxsync#ifdef RT_OS_LINUX
315f68b04971772d94ba6c4408eaa19559a77cedvboxsync# include <sys/mman.h>
032703cba22135d6032705fc2d67dd1294a6491avboxsync# ifndef MADV_DONTFORK
032703cba22135d6032705fc2d67dd1294a6491avboxsync# define MADV_DONTFORK 10
032703cba22135d6032705fc2d67dd1294a6491avboxsync# endif
032703cba22135d6032705fc2d67dd1294a6491avboxsync#endif
032703cba22135d6032705fc2d67dd1294a6491avboxsync
032703cba22135d6032705fc2d67dd1294a6491avboxsync
032703cba22135d6032705fc2d67dd1294a6491avboxsync
032703cba22135d6032705fc2d67dd1294a6491avboxsync/*******************************************************************************
315f68b04971772d94ba6c4408eaa19559a77cedvboxsync* Global Variables *
032703cba22135d6032705fc2d67dd1294a6491avboxsync*******************************************************************************/
032703cba22135d6032705fc2d67dd1294a6491avboxsync/** The balloon size. */
032703cba22135d6032705fc2d67dd1294a6491avboxsyncstatic uint32_t g_cMemBalloonChunks = 0;
032703cba22135d6032705fc2d67dd1294a6491avboxsync
032703cba22135d6032705fc2d67dd1294a6491avboxsync/** The semaphore we're blocking on. */
315f68b04971772d94ba6c4408eaa19559a77cedvboxsyncstatic RTSEMEVENTMULTI g_MemBalloonEvent = NIL_RTSEMEVENTMULTI;
032703cba22135d6032705fc2d67dd1294a6491avboxsync
032703cba22135d6032705fc2d67dd1294a6491avboxsync/** The array holding the R3 pointers of the balloon. */
315f68b04971772d94ba6c4408eaa19559a77cedvboxsyncstatic void **g_pavBalloon = NULL;
032703cba22135d6032705fc2d67dd1294a6491avboxsync
032703cba22135d6032705fc2d67dd1294a6491avboxsync/** True = madvise(MADV_DONTFORK) works, false otherwise. */
032703cba22135d6032705fc2d67dd1294a6491avboxsyncstatic bool g_fSysMadviseWorks;
032703cba22135d6032705fc2d67dd1294a6491avboxsync
032703cba22135d6032705fc2d67dd1294a6491avboxsync
032703cba22135d6032705fc2d67dd1294a6491avboxsync/**
032703cba22135d6032705fc2d67dd1294a6491avboxsync * Check whether madvise() works.
032703cba22135d6032705fc2d67dd1294a6491avboxsync */
032703cba22135d6032705fc2d67dd1294a6491avboxsyncstatic void VBoxServiceBalloonInitMadvise(void)
032703cba22135d6032705fc2d67dd1294a6491avboxsync{
032703cba22135d6032705fc2d67dd1294a6491avboxsync#ifdef RT_OS_LINUX
032703cba22135d6032705fc2d67dd1294a6491avboxsync void *pv = RTMemPageAlloc(PAGE_SIZE);
032703cba22135d6032705fc2d67dd1294a6491avboxsync g_fSysMadviseWorks = madvise(pv, PAGE_SIZE, MADV_DONTFORK) == 0;
032703cba22135d6032705fc2d67dd1294a6491avboxsync RTMemPageFree(pv);
032703cba22135d6032705fc2d67dd1294a6491avboxsync#endif
032703cba22135d6032705fc2d67dd1294a6491avboxsync}
032703cba22135d6032705fc2d67dd1294a6491avboxsync
032703cba22135d6032705fc2d67dd1294a6491avboxsync
032703cba22135d6032705fc2d67dd1294a6491avboxsync/**
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().
032703cba22135d6032705fc2d67dd1294a6491avboxsync */
032703cba22135d6032705fc2d67dd1294a6491avboxsyncstatic void* VBoxServiceBalloonAllocChunk(void)
032703cba22135d6032705fc2d67dd1294a6491avboxsync{
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync size_t cb = VMMDEV_MEMORY_BALLOON_CHUNK_SIZE;
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync char *pu8;
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync#ifdef RT_OS_LINUX
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync if (!g_fSysMadviseWorks)
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync cb += 2 * PAGE_SIZE;
315f68b04971772d94ba6c4408eaa19559a77cedvboxsync
315f68b04971772d94ba6c4408eaa19559a77cedvboxsync pu8 = (char*)mmap(NULL, cb, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync if (pu8 == MAP_FAILED)
315f68b04971772d94ba6c4408eaa19559a77cedvboxsync return NULL;
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync if (g_fSysMadviseWorks)
315f68b04971772d94ba6c4408eaa19559a77cedvboxsync {
315f68b04971772d94ba6c4408eaa19559a77cedvboxsync /*
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 */
315f68b04971772d94ba6c4408eaa19559a77cedvboxsync madvise(pu8, cb, MADV_DONTFORK);
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync }
315f68b04971772d94ba6c4408eaa19559a77cedvboxsync else
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync {
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync /*
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 */
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync RTMemProtect(pu8, PAGE_SIZE, RTMEM_PROT_NONE);
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync RTMemProtect(pu8 + cb - PAGE_SIZE, PAGE_SIZE, RTMEM_PROT_NONE);
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync pu8 += PAGE_SIZE;
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync }
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync#else
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync pu8 = (char*)RTMemPageAlloc(cb);
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync if (!pu8)
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync return pu8;
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync#endif
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync memset(pu8, 0, VMMDEV_MEMORY_BALLOON_CHUNK_SIZE);
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync return pu8;
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync}
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync/**
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync * Free an allocated chunk undoing VBoxServiceBalloonAllocChunk().
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync */
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsyncstatic void VBoxServiceBalloonFreeChunk(void *pv)
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync{
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync char *pu8 = (char*)pv;
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync size_t cb = VMMDEV_MEMORY_BALLOON_CHUNK_SIZE;
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync#ifdef RT_OS_LINUX
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync if (!g_fSysMadviseWorks)
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync {
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync cb += 2 * PAGE_SIZE;
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync pu8 -= PAGE_SIZE;
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 }
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync munmap(pu8, cb);
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync#else
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync RTMemPageFree(pu8);
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync#endif
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync}
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync/**
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync * Adapt the R0 memory balloon by granting/reclaiming 1MB chunks to/from R0.
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync *
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync * returns IPRT status code.
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync * @param cNewChunks The new number of 1MB chunks in the balloon.
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync */
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsyncstatic int VBoxServiceBalloonSetUser(uint32_t cNewChunks)
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync{
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync if (cNewChunks == g_cMemBalloonChunks)
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync return VINF_SUCCESS;
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync
032703cba22135d6032705fc2d67dd1294a6491avboxsync VBoxServiceVerbose(3, "VBoxServiceBalloonSetUser: cNewChunks=%u g_cMemBalloonChunks=%u\n", cNewChunks, g_cMemBalloonChunks);
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync int rc = VINF_SUCCESS;
315f68b04971772d94ba6c4408eaa19559a77cedvboxsync if (cNewChunks > g_cMemBalloonChunks)
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync {
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync /* inflate */
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync g_pavBalloon = (void**)RTMemRealloc(g_pavBalloon, cNewChunks * sizeof(void*));
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync uint32_t i;
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync for (i = g_cMemBalloonChunks; i < cNewChunks; i++)
032703cba22135d6032705fc2d67dd1294a6491avboxsync {
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync void *pv = VBoxServiceBalloonAllocChunk();
315f68b04971772d94ba6c4408eaa19559a77cedvboxsync if (!pv)
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync break;
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync rc = VbglR3MemBalloonChange(pv, /* inflate=*/ true);
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync if (RT_SUCCESS(rc))
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync {
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync g_pavBalloon[i] = pv;
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync#ifndef RT_OS_SOLARIS
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync /*
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 */
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync RTMemProtect(pv, VMMDEV_MEMORY_BALLOON_CHUNK_SIZE, RTMEM_PROT_NONE);
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync#endif
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync g_cMemBalloonChunks++;
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync }
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync else
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync {
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync VBoxServiceBalloonFreeChunk(pv);
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync break;
032703cba22135d6032705fc2d67dd1294a6491avboxsync }
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync }
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync VBoxServiceVerbose(3, "VBoxServiceBalloonSetUser: inflation complete. chunks=%u rc=%d\n", i, rc);
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync }
315f68b04971772d94ba6c4408eaa19559a77cedvboxsync else
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync {
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync /* deflate */
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync uint32_t i;
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync for (i = g_cMemBalloonChunks; i-- > cNewChunks;)
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync {
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync void *pv = g_pavBalloon[i];
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync rc = VbglR3MemBalloonChange(pv, /* inflate=*/ false);
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync if (RT_SUCCESS(rc))
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync {
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync#ifndef RT_OS_SOLARIS
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync /* unprotect */
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync RTMemProtect(pv, VMMDEV_MEMORY_BALLOON_CHUNK_SIZE, RTMEM_PROT_READ | RTMEM_PROT_WRITE);
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync#endif
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync VBoxServiceBalloonFreeChunk(pv);
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync g_pavBalloon[i] = NULL;
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync g_cMemBalloonChunks--;
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync }
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync else
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync break;
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync VBoxServiceVerbose(3, "VBoxServiceBalloonSetUser: deflation complete. chunks=%u rc=%d\n", i, rc);
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync }
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync }
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync return VINF_SUCCESS;
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync}
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync/** @copydoc VBOXSERVICE::pfnPreInit */
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsyncstatic DECLCALLBACK(int) VBoxServiceBalloonPreInit(void)
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync{
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync return VINF_SUCCESS;
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync}
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync/** @copydoc VBOXSERVICE::pfnOption */
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsyncstatic DECLCALLBACK(int) VBoxServiceBalloonOption(const char **ppszShort, int argc, char **argv, int *pi)
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync{
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync NOREF(ppszShort);
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync NOREF(argc);
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync NOREF(argv);
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync NOREF(pi);
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync return VINF_SUCCESS;
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync}
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync/** @copydoc VBOXSERVICE::pfnInit */
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsyncstatic DECLCALLBACK(int) VBoxServiceBalloonInit(void)
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync{
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync VBoxServiceVerbose(3, "VBoxServiceBalloonInit\n");
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync int rc = RTSemEventMultiCreate(&g_MemBalloonEvent);
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync AssertRCReturn(rc, rc);
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync VBoxServiceBalloonInitMadvise();
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync g_cMemBalloonChunks = 0;
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync uint32_t cNewChunks = 0;
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync bool fHandleInR3;
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync /* Check balloon size */
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync rc = VbglR3MemBalloonRefresh(&cNewChunks, &fHandleInR3);
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync if (RT_SUCCESS(rc))
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync {
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync VBoxServiceVerbose(3, "VBoxMemBalloonInit: new balloon size %d MB (%s memory)\n",
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync cNewChunks, fHandleInR3 ? "R3" : "R0");
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync if (fHandleInR3)
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync rc = VBoxServiceBalloonSetUser(cNewChunks);
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync else
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync g_cMemBalloonChunks = cNewChunks;
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync }
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync else
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync VBoxServiceVerbose(3, "VBoxMemBalloonInit: VbglR3MemBalloonRefresh failed with %Rrc\n", rc);
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync
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 return VINF_SUCCESS;
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync}
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync/**
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync * Query the size of the memory balloon, given as a page count.
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync *
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync * @returns Number of pages.
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync * @param cbPage The page size.
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync */
b64efece437bfca8872b81be9d0568ba90389d91vboxsyncuint32_t VBoxServiceBalloonQueryPages(uint32_t cbPage)
b64efece437bfca8872b81be9d0568ba90389d91vboxsync{
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync return g_cMemBalloonChunks * (VMMDEV_MEMORY_BALLOON_CHUNK_SIZE / cbPage);
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync}
ab37cc785e1bcbaaad50b8fb791bfecba6f4b4d5vboxsync
3755e2bacafa2dd718108ad1a18661dcd9566bd8vboxsync
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync/** @copydoc VBOXSERVICE::pfnWorker */
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsyncDECLCALLBACK(int) VBoxServiceBalloonWorker(bool volatile *pfShutdown)
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync{
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync /* Start monitoring of the stat event change event. */
032703cba22135d6032705fc2d67dd1294a6491avboxsync int rc = VbglR3CtlFilterMask(VMMDEV_EVENT_BALLOON_CHANGE_REQUEST, 0);
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync if (RT_FAILURE(rc))
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync {
3755e2bacafa2dd718108ad1a18661dcd9566bd8vboxsync VBoxServiceVerbose(3, "VBoxServiceBalloonWorker: VbglR3CtlFilterMask failed with %Rrc\n", rc);
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync return rc;
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync }
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync /*
032703cba22135d6032705fc2d67dd1294a6491avboxsync * Tell the control thread that it can continue
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync * spawning services.
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync */
3755e2bacafa2dd718108ad1a18661dcd9566bd8vboxsync RTThreadUserSignal(RTThreadSelf());
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync /*
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync * Now enter the loop retrieving runtime data continuously.
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync */
032703cba22135d6032705fc2d67dd1294a6491avboxsync for (;;)
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync {
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync uint32_t fEvents = 0;
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync
3755e2bacafa2dd718108ad1a18661dcd9566bd8vboxsync /* Check if an update interval change is pending. */
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync rc = VbglR3WaitEvent(VMMDEV_EVENT_BALLOON_CHANGE_REQUEST, 0 /* no wait */, &fEvents);
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync if ( RT_SUCCESS(rc)
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync && (fEvents & VMMDEV_EVENT_BALLOON_CHANGE_REQUEST))
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync {
032703cba22135d6032705fc2d67dd1294a6491avboxsync uint32_t cNewChunks;
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync bool fHandleInR3;
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync rc = VbglR3MemBalloonRefresh(&cNewChunks, &fHandleInR3);
3755e2bacafa2dd718108ad1a18661dcd9566bd8vboxsync if (RT_SUCCESS(rc))
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync {
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync VBoxServiceVerbose(3, "VBoxServiceBalloonWorker: new balloon size %d MB (%s memory)\n",
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync cNewChunks, fHandleInR3 ? "R3" : "R0");
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync if (fHandleInR3)
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync {
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync rc = VBoxServiceBalloonSetUser(cNewChunks);
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync if (RT_FAILURE(rc))
3755e2bacafa2dd718108ad1a18661dcd9566bd8vboxsync {
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync VBoxServiceVerbose(3, "VBoxServiceBalloonWorker: failed to set balloon size %d MB (%s memory)\n",
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync cNewChunks, fHandleInR3 ? "R3" : "R0");
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync }
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync else
032703cba22135d6032705fc2d67dd1294a6491avboxsync VBoxServiceVerbose(3, "VBoxServiceBalloonWorker: successfully set requested balloon size %d.\n", cNewChunks);
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync }
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync else
3755e2bacafa2dd718108ad1a18661dcd9566bd8vboxsync g_cMemBalloonChunks = cNewChunks;
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync }
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync else
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync VBoxServiceVerbose(3, "VBoxServiceBalloonWorker: VbglR3MemBalloonRefresh failed with %Rrc\n", rc);
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync }
032703cba22135d6032705fc2d67dd1294a6491avboxsync
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync /*
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync * Block for a while.
3755e2bacafa2dd718108ad1a18661dcd9566bd8vboxsync *
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync * The event semaphore takes care of ignoring interruptions and it
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync * allows us to implement service wakeup later.
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync */
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync if (*pfShutdown)
032703cba22135d6032705fc2d67dd1294a6491avboxsync break;
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync int rc2 = RTSemEventMultiWait(g_MemBalloonEvent, 5000);
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync if (*pfShutdown)
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync break;
3755e2bacafa2dd718108ad1a18661dcd9566bd8vboxsync if (rc2 != VERR_TIMEOUT && RT_FAILURE(rc2))
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync {
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync VBoxServiceError("RTSemEventMultiWait failed; rc2=%Rrc\n", rc2);
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync rc = rc2;
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync break;
032703cba22135d6032705fc2d67dd1294a6491avboxsync }
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync }
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync
3755e2bacafa2dd718108ad1a18661dcd9566bd8vboxsync /* Cancel monitoring of the memory balloon change event. */
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync rc = VbglR3CtlFilterMask(0, VMMDEV_EVENT_BALLOON_CHANGE_REQUEST);
032703cba22135d6032705fc2d67dd1294a6491avboxsync if (RT_FAILURE(rc))
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync VBoxServiceVerbose(3, "VBoxServiceBalloonWorker: VbglR3CtlFilterMask failed with %Rrc\n", rc);
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync RTSemEventMultiDestroy(g_MemBalloonEvent);
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync g_MemBalloonEvent = NIL_RTSEMEVENTMULTI;
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync VBoxServiceVerbose(3, "VBoxServiceBalloonWorker: finished mem balloon change request thread\n");
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync return 0;
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync}
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync/** @copydoc VBOXSERVICE::pfnTerm */
b64efece437bfca8872b81be9d0568ba90389d91vboxsyncstatic DECLCALLBACK(void) VBoxServiceBalloonTerm(void)
b64efece437bfca8872b81be9d0568ba90389d91vboxsync{
b64efece437bfca8872b81be9d0568ba90389d91vboxsync VBoxServiceVerbose(3, "VBoxServiceBalloonTerm\n");
65c72795ab90d3daefa759b716fbb5c6352c7a56vboxsync return;
b64efece437bfca8872b81be9d0568ba90389d91vboxsync}
b64efece437bfca8872b81be9d0568ba90389d91vboxsync
b64efece437bfca8872b81be9d0568ba90389d91vboxsync
b64efece437bfca8872b81be9d0568ba90389d91vboxsync/** @copydoc VBOXSERVICE::pfnStop */
b64efece437bfca8872b81be9d0568ba90389d91vboxsyncstatic DECLCALLBACK(void) VBoxServiceBalloonStop(void)
b64efece437bfca8872b81be9d0568ba90389d91vboxsync{
b64efece437bfca8872b81be9d0568ba90389d91vboxsync RTSemEventMultiSignal(g_MemBalloonEvent);
b64efece437bfca8872b81be9d0568ba90389d91vboxsync}
b64efece437bfca8872b81be9d0568ba90389d91vboxsync
b64efece437bfca8872b81be9d0568ba90389d91vboxsync
b64efece437bfca8872b81be9d0568ba90389d91vboxsync/**
b64efece437bfca8872b81be9d0568ba90389d91vboxsync * The 'memballoon' service description.
b64efece437bfca8872b81be9d0568ba90389d91vboxsync */
b64efece437bfca8872b81be9d0568ba90389d91vboxsyncVBOXSERVICE g_MemBalloon =
b64efece437bfca8872b81be9d0568ba90389d91vboxsync{
b64efece437bfca8872b81be9d0568ba90389d91vboxsync /* pszName. */
b64efece437bfca8872b81be9d0568ba90389d91vboxsync "memballoon",
b64efece437bfca8872b81be9d0568ba90389d91vboxsync /* pszDescription. */
b64efece437bfca8872b81be9d0568ba90389d91vboxsync "Memory Ballooning",
ab37cc785e1bcbaaad50b8fb791bfecba6f4b4d5vboxsync /* pszUsage. */
3755e2bacafa2dd718108ad1a18661dcd9566bd8vboxsync NULL,
b64efece437bfca8872b81be9d0568ba90389d91vboxsync /* pszOptions. */
b64efece437bfca8872b81be9d0568ba90389d91vboxsync NULL,
b64efece437bfca8872b81be9d0568ba90389d91vboxsync /* methods */
b64efece437bfca8872b81be9d0568ba90389d91vboxsync VBoxServiceBalloonPreInit,
032703cba22135d6032705fc2d67dd1294a6491avboxsync VBoxServiceBalloonOption,
b64efece437bfca8872b81be9d0568ba90389d91vboxsync VBoxServiceBalloonInit,
b64efece437bfca8872b81be9d0568ba90389d91vboxsync VBoxServiceBalloonWorker,
3755e2bacafa2dd718108ad1a18661dcd9566bd8vboxsync VBoxServiceBalloonStop,
b64efece437bfca8872b81be9d0568ba90389d91vboxsync VBoxServiceBalloonTerm
b64efece437bfca8872b81be9d0568ba90389d91vboxsync};
b64efece437bfca8872b81be9d0568ba90389d91vboxsync