diff options
author | Lorry Tar Creator <lorry-tar-importer@baserock.org> | 2014-03-26 19:21:20 +0000 |
---|---|---|
committer | <> | 2014-05-08 15:03:54 +0000 |
commit | fb123f93f9f5ce42c8e5785d2f8e0edaf951740e (patch) | |
tree | c2103d76aec5f1f10892cd1d3a38e24f665ae5db /src/VBox/Main/src-server/solaris | |
parent | 58ed4748338f9466599adfc8a9171280ed99e23f (diff) | |
download | VirtualBox-master.tar.gz |
Imported from /home/lorry/working-area/delta_VirtualBox/VirtualBox-4.3.10.tar.bz2.HEADVirtualBox-4.3.10master
Diffstat (limited to 'src/VBox/Main/src-server/solaris')
5 files changed, 541 insertions, 132 deletions
diff --git a/src/VBox/Main/src-server/solaris/DynLoadLibSolaris.cpp b/src/VBox/Main/src-server/solaris/DynLoadLibSolaris.cpp index 4bd864f1..a38b7654 100644 --- a/src/VBox/Main/src-server/solaris/DynLoadLibSolaris.cpp +++ b/src/VBox/Main/src-server/solaris/DynLoadLibSolaris.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2008 Oracle Corporation + * Copyright (C) 2008-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Main/src-server/solaris/DynLoadLibSolaris.h b/src/VBox/Main/src-server/solaris/DynLoadLibSolaris.h index 4fc35b8a..e306dac0 100644 --- a/src/VBox/Main/src-server/solaris/DynLoadLibSolaris.h +++ b/src/VBox/Main/src-server/solaris/DynLoadLibSolaris.h @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2008 Oracle Corporation + * Copyright (C) 2008-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Main/src-server/solaris/NetIf-solaris.cpp b/src/VBox/Main/src-server/solaris/NetIf-solaris.cpp index bc700820..82e8a338 100644 --- a/src/VBox/Main/src-server/solaris/NetIf-solaris.cpp +++ b/src/VBox/Main/src-server/solaris/NetIf-solaris.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2008-2011 Oracle Corporation + * Copyright (C) 2008-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -24,6 +24,7 @@ #include <iprt/err.h> #include <iprt/ctype.h> +#include <iprt/mem.h> #include <iprt/path.h> #include <list> @@ -73,10 +74,10 @@ static uint32_t getInstance(const char *pszIfaceName, char *pszDevName) return uInstance; } -static uint64_t kstatGet(const char *name) +static uint32_t kstatGet(const char *name) { kstat_ctl_t *kc; - uint64_t uSpeed = 0; + uint32_t uSpeed = 0; if ((kc = kstat_open()) == 0) { @@ -84,14 +85,14 @@ static uint64_t kstatGet(const char *name) return 0; } - kstat_t *ksAdapter = kstat_lookup(kc, "link", -1, (char *)name); + kstat_t *ksAdapter = kstat_lookup(kc, (char *)"link", -1, (char *)name); if (ksAdapter == 0) { char szModule[KSTAT_STRLEN]; uint32_t uInstance = getInstance(name, szModule); - ksAdapter = kstat_lookup(kc, szModule, uInstance, "phys"); + ksAdapter = kstat_lookup(kc, szModule, uInstance, (char *)"phys"); if (ksAdapter == 0) - ksAdapter = kstat_lookup(kc, szModule, uInstance, name); + ksAdapter = kstat_lookup(kc, szModule, uInstance, (char*)name); } if (ksAdapter == 0) LogRel(("Failed to get network statistics for %s\n", name)); @@ -103,15 +104,21 @@ static uint64_t kstatGet(const char *name) if ((kn = (kstat_named_t *)kstat_data_lookup(ksAdapter, (char *)"ifspeed")) == 0) LogRel(("kstat_data_lookup(ifspeed) -> %d, name=%s\n", errno, name)); else - uSpeed = kn->value.ul; + uSpeed = kn->value.ul / 1000000; /* bits -> Mbits */ } kstat_close(kc); + LogFlow(("kstatGet(%s) -> %u Mbit/s\n", name, uSpeed)); return uSpeed; } static void queryIfaceSpeed(PNETIFINFO pInfo) { - pInfo->uSpeedMbits = kstatGet(pInfo->szShortName) / 1000000; /* bits -> Mbits */ + /* Don't query interface speed for inactive interfaces (see @bugref{6345}). */ + if (pInfo->enmStatus == NETIF_S_UP) + pInfo->uSpeedMbits = kstatGet(pInfo->szShortName); + else + pInfo->uSpeedMbits = 0; + LogFlow(("queryIfaceSpeed(%s) -> %u\n", pInfo->szShortName, pInfo->uSpeedMbits)); } static void vboxSolarisAddHostIface(char *pszIface, int Instance, void *pvHostNetworkInterfaceList) @@ -192,12 +199,12 @@ static void vboxSolarisAddHostIface(char *pszIface, int Instance, void *pvHostNe * Try to get IP V4 address and netmask as well as Ethernet address. */ NETIFINFO Info; - memset(&Info, 0, sizeof(Info)); + RT_ZERO(Info); int Sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP); if (Sock > 0) { struct lifreq IfReq; - strcpy(IfReq.lifr_name, szNICInstance); + RTStrCopy(IfReq.lifr_name, sizeof(IfReq.lifr_name), szNICInstance); if (ioctl(Sock, SIOCGLIFADDR, &IfReq) >= 0) { memcpy(Info.IPAddress.au8, &((struct sockaddr_in *)&IfReq.lifr_addr)->sin_addr.s_addr, @@ -236,7 +243,7 @@ static void vboxSolarisAddHostIface(char *pszIface, int Instance, void *pvHostNe if (Sock > 0) { struct lifreq IfReq; - strcpy(IfReq.lifr_name, szNICInstance); + RTStrCopy(IfReq.lifr_name, sizeof(IfReq.lifr_name), szNICInstance); if (ioctl(Sock, SIOCGLIFADDR, &IfReq) >= 0) { memcpy(Info.IPv6Address.au8, ((struct sockaddr_in6 *)&IfReq.lifr_addr)->sin6_addr.s6_addr, @@ -269,7 +276,7 @@ static void vboxSolarisAddHostIface(char *pszIface, int Instance, void *pvHostNe strncpy(Info.szShortName, szNICInstance, sizeof(Info.szShortName) - 1); HostNetworkInterfaceType_T enmType; - if (strncmp("vboxnet", szNICInstance, 7)) + if (strncmp(szNICInstance, RT_STR_TUPLE("vboxnet"))) enmType = HostNetworkInterfaceType_Bridged; else enmType = HostNetworkInterfaceType_HostOnly; @@ -285,15 +292,15 @@ static boolean_t vboxSolarisAddLinkHostIface(const char *pszIface, void *pvHostN /* * Skip IPSEC interfaces. It's at IP level. */ - if (!strncmp(pszIface, "ip.tun", 6)) + if (!strncmp(pszIface, RT_STR_TUPLE("ip.tun"))) return _B_FALSE; /* * Skip our own dynamic VNICs but don't skip VNIC templates. * These names originate from VBoxNetFltBow-solaris.c, hardcoded here for now. */ - if ( strncmp(pszIface, "vboxvnic_template", 17) - && !strncmp(pszIface, "vboxvnic", 8)) + if ( strncmp(pszIface, RT_STR_TUPLE("vboxvnic_template")) + && !strncmp(pszIface, RT_STR_TUPLE("vboxvnic"))) return _B_FALSE; /* @@ -406,59 +413,65 @@ int NetIfList(std::list <ComObjPtr<HostNetworkInterface> > &list) if (Sock > 0) { struct lifnum IfNum; - memset(&IfNum, 0, sizeof(IfNum)); + RT_ZERO(IfNum); IfNum.lifn_family = AF_INET; int rc = ioctl(Sock, SIOCGLIFNUM, &IfNum); if (!rc) { - struct lifreq Ifaces[24]; - struct lifconf IfConfig; - memset(&IfConfig, 0, sizeof(IfConfig)); - IfConfig.lifc_family = AF_INET; - IfConfig.lifc_len = sizeof(Ifaces); - IfConfig.lifc_buf = (caddr_t)&(Ifaces[0]); - rc = ioctl(Sock, SIOCGLIFCONF, &IfConfig); - if (!rc) + int cIfaces = RT_MIN(1024, IfNum.lifn_count); /* sane limit */ + int cbIfaces = cIfaces * sizeof(struct lifreq); + struct lifreq *Ifaces = (struct lifreq *)RTMemTmpAlloc(cbIfaces); + if (Ifaces) { - for (int i = 0; i < IfNum.lifn_count; i++) + struct lifconf IfConfig; + RT_ZERO(IfConfig); + IfConfig.lifc_family = AF_INET; + IfConfig.lifc_len = cbIfaces; + IfConfig.lifc_buf = (caddr_t)Ifaces; + rc = ioctl(Sock, SIOCGLIFCONF, &IfConfig); + if (!rc) { - /* - * Skip loopback interfaces. - */ - if (!strncmp(Ifaces[i].lifr_name, "lo", 2)) - continue; - -#if 0 - rc = ioctl(Sock, SIOCGLIFADDR, &(Ifaces[i])); - if (rc >= 0) + for (int i = 0; i < cIfaces; i++) { - memcpy(Info.IPAddress.au8, ((struct sockaddr *)&Ifaces[i].lifr_addr)->sa_data, - sizeof(Info.IPAddress.au8)); - // SIOCGLIFNETMASK - struct arpreq ArpReq; - memcpy(&ArpReq.arp_pa, &Ifaces[i].lifr_addr, sizeof(struct sockaddr_in)); - /* - * We might fail if the interface has not been assigned an IP address. - * That doesn't matter; as long as it's plumbed we can pick it up. - * But, if it has not acquired an IP address we cannot obtain it's MAC - * address this way, so we just use all zeros there. + * Skip loopback interfaces. */ - rc = ioctl(Sock, SIOCGARP, &ArpReq); + if (!strncmp(Ifaces[i].lifr_name, RT_STR_TUPLE("lo"))) + continue; + +#if 0 + rc = ioctl(Sock, SIOCGLIFADDR, &(Ifaces[i])); if (rc >= 0) - memcpy(&Info.MACAddress, ArpReq.arp_ha.sa_data, sizeof(Info.MACAddress)); + { + memcpy(Info.IPAddress.au8, ((struct sockaddr *)&Ifaces[i].lifr_addr)->sa_data, + sizeof(Info.IPAddress.au8)); + // SIOCGLIFNETMASK + struct arpreq ArpReq; + memcpy(&ArpReq.arp_pa, &Ifaces[i].lifr_addr, sizeof(struct sockaddr_in)); + + /* + * We might fail if the interface has not been assigned an IP address. + * That doesn't matter; as long as it's plumbed we can pick it up. + * But, if it has not acquired an IP address we cannot obtain it's MAC + * address this way, so we just use all zeros there. + */ + rc = ioctl(Sock, SIOCGARP, &ArpReq); + if (rc >= 0) + memcpy(&Info.MACAddress, ArpReq.arp_ha.sa_data, sizeof(Info.MACAddress)); + + char szNICDesc[LIFNAMSIZ + 256]; + char *pszIface = Ifaces[i].lifr_name; + strcpy(szNICDesc, pszIface); + + vboxSolarisAddLinkHostIface(pszIface, &list); + } +#endif - char szNICDesc[LIFNAMSIZ + 256]; char *pszIface = Ifaces[i].lifr_name; - strcpy(szNICDesc, pszIface); - vboxSolarisAddLinkHostIface(pszIface, &list); } -#endif - - char *pszIface = Ifaces[i].lifr_name; - vboxSolarisAddLinkHostIface(pszIface, &list); } + RTMemTmpFree(Ifaces); } } close(Sock); @@ -486,3 +499,17 @@ int NetIfGetConfigByName(PNETIFINFO pInfo) return VERR_NOT_IMPLEMENTED; } +/** + * Retrieve the physical link speed in megabits per second. If the interface is + * not up or otherwise unavailable the zero speed is returned. + * + * @returns VBox status code. + * + * @param pcszIfName Interface name. + * @param puMbits Where to store the link speed. + */ +int NetIfGetLinkSpeed(const char *pcszIfName, uint32_t *puMbits) +{ + *puMbits = kstatGet(pcszIfName); + return VINF_SUCCESS; +} diff --git a/src/VBox/Main/src-server/solaris/PerformanceSolaris.cpp b/src/VBox/Main/src-server/solaris/PerformanceSolaris.cpp index 7abeae04..ed935116 100644 --- a/src/VBox/Main/src-server/solaris/PerformanceSolaris.cpp +++ b/src/VBox/Main/src-server/solaris/PerformanceSolaris.cpp @@ -6,7 +6,7 @@ */ /* - * Copyright (C) 2008 Oracle Corporation + * Copyright (C) 2008-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -26,33 +26,85 @@ #include <unistd.h> #include <sys/sysinfo.h> #include <sys/time.h> +#include <sys/types.h> +#include <sys/statvfs.h> #include <iprt/ctype.h> #include <iprt/err.h> #include <iprt/string.h> #include <iprt/alloc.h> #include <iprt/param.h> -#include <VBox/log.h> +#include <iprt/path.h> +#include <iprt/system.h> + +#include "Logging.h" #include "Performance.h" +#include <dlfcn.h> + +#include <libzfs.h> +#include <libnvpair.h> + +#include <map> + namespace pm { + typedef libzfs_handle_t *(*PFNZFSINIT)(void); + typedef void (*PFNZFSFINI)(libzfs_handle_t *); + typedef zfs_handle_t *(*PFNZFSOPEN)(libzfs_handle_t *, const char *, int); + typedef void (*PFNZFSCLOSE)(zfs_handle_t *); + typedef uint64_t (*PFNZFSPROPGETINT)(zfs_handle_t *, zfs_prop_t); + typedef zpool_handle_t *(*PFNZPOOLOPEN)(libzfs_handle_t *, const char *); + typedef void (*PFNZPOOLCLOSE)(zpool_handle_t *); + typedef nvlist_t *(*PFNZPOOLGETCONFIG)(zpool_handle_t *, nvlist_t **); + typedef char *(*PFNZPOOLVDEVNAME)(libzfs_handle_t *, zpool_handle_t *, nvlist_t *, boolean_t); + + typedef std::map<RTCString,RTCString> FsMap; + class CollectorSolaris : public CollectorHAL { public: CollectorSolaris(); virtual ~CollectorSolaris(); virtual int getHostMemoryUsage(ULONG *total, ULONG *used, ULONG *available); + virtual int getHostFilesystemUsage(const char *name, ULONG *total, ULONG *used, ULONG *available); + virtual int getHostDiskSize(const char *name, uint64_t *size); virtual int getProcessMemoryUsage(RTPROCESS process, ULONG *used); virtual int getRawHostCpuLoad(uint64_t *user, uint64_t *kernel, uint64_t *idle); virtual int getRawHostNetworkLoad(const char *name, uint64_t *rx, uint64_t *tx); + virtual int getRawHostDiskLoad(const char *name, uint64_t *disk_ms, uint64_t *total_ms); virtual int getRawProcessCpuLoad(RTPROCESS process, uint64_t *user, uint64_t *kernel, uint64_t *total); + + virtual int getDiskListByFs(const char *name, DiskList& listUsage, DiskList& listLoad); private: static uint32_t getInstance(const char *pszIfaceName, char *pszDevName); - kstat_ctl_t *mKC; - kstat_t *mSysPages; - kstat_t *mZFSCache; + uint64_t getZfsTotal(uint64_t cbTotal, const char *szFsType, const char *szFsName); + void updateFilesystemMap(void); + RTCString physToInstName(const char *pcszPhysName); + RTCString pathToInstName(const char *pcszDevPathName); + uint64_t wrapCorrection(uint32_t cur, uint64_t prev, const char *name); + uint64_t wrapDetection(uint64_t cur, uint64_t prev, const char *name); + + kstat_ctl_t *mKC; + kstat_t *mSysPages; + kstat_t *mZFSCache; + + void *mZfsSo; + libzfs_handle_t *mZfsLib; + PFNZFSINIT mZfsInit; + PFNZFSFINI mZfsFini; + PFNZFSOPEN mZfsOpen; + PFNZFSCLOSE mZfsClose; + PFNZFSPROPGETINT mZfsPropGetInt; + PFNZPOOLOPEN mZpoolOpen; + PFNZPOOLCLOSE mZpoolClose; + PFNZPOOLGETCONFIG mZpoolGetConfig; + PFNZPOOLVDEVNAME mZpoolVdevName; + + FsMap mFsMap; + uint32_t mCpus; + ULONG totalRAM; }; CollectorHAL *createHAL() @@ -66,7 +118,9 @@ CollectorHAL *createHAL() CollectorSolaris::CollectorSolaris() : mKC(0), mSysPages(0), - mZFSCache(0) + mZFSCache(0), + mZfsLib(0), + mCpus(0) { if ((mKC = kstat_open()) == 0) { @@ -84,12 +138,55 @@ CollectorSolaris::CollectorSolaris() { Log(("kstat_lookup(system_pages) -> %d\n", errno)); } + + /* Try to load libzfs dynamically, it may be missing. */ + mZfsSo = dlopen("libzfs.so", RTLD_LAZY); + if (mZfsSo) + { + mZfsInit = (PFNZFSINIT)(uintptr_t)dlsym(mZfsSo, "libzfs_init"); + mZfsFini = (PFNZFSFINI)(uintptr_t)dlsym(mZfsSo, "libzfs_fini"); + mZfsOpen = (PFNZFSOPEN)(uintptr_t)dlsym(mZfsSo, "zfs_open"); + mZfsClose = (PFNZFSCLOSE)(uintptr_t)dlsym(mZfsSo, "zfs_close"); + mZfsPropGetInt = (PFNZFSPROPGETINT)(uintptr_t)dlsym(mZfsSo, "zfs_prop_get_int"); + mZpoolOpen = (PFNZPOOLOPEN)(uintptr_t)dlsym(mZfsSo, "zpool_open"); + mZpoolClose = (PFNZPOOLCLOSE)(uintptr_t)dlsym(mZfsSo, "zpool_close"); + mZpoolGetConfig = (PFNZPOOLGETCONFIG)(uintptr_t)dlsym(mZfsSo, "zpool_get_config"); + mZpoolVdevName = (PFNZPOOLVDEVNAME)(uintptr_t)dlsym(mZfsSo, "zpool_vdev_name"); + + if ( mZfsInit + && mZfsOpen + && mZfsClose + && mZfsPropGetInt + && mZpoolOpen + && mZpoolClose + && mZpoolGetConfig + && mZpoolVdevName) + mZfsLib = mZfsInit(); + else + LogRel(("Incompatible libzfs? libzfs_init=%p zfs_open=%p zfs_close=%p zfs_prop_get_int=%p\n", + mZfsInit, mZfsOpen, mZfsClose, mZfsPropGetInt)); + } + + updateFilesystemMap(); + /* Notice that mCpus member will be initialized by HostCpuLoadRaw::init() */ + + uint64_t cb; + int rc = RTSystemQueryTotalRam(&cb); + if (RT_FAILURE(rc)) + totalRAM = 0; + else + totalRAM = (ULONG)(cb / 1024); } CollectorSolaris::~CollectorSolaris() { if (mKC) kstat_close(mKC); + /* Not calling libzfs_fini() causes file descriptor leaks (#6788). */ + if (mZfsFini && mZfsLib) + mZfsFini(mZfsLib); + if (mZfsSo) + dlclose(mZfsSo); } int CollectorSolaris::getRawHostCpuLoad(uint64_t *user, uint64_t *kernel, uint64_t *idle) @@ -123,6 +220,8 @@ int CollectorSolaris::getRawHostCpuLoad(uint64_t *user, uint64_t *kernel, uint64 Log(("no cpu stats found!\n")); return VERR_INTERNAL_ERROR; } + else + mCpus = cpus; if (user) *user = tmpUser; if (kernel) *kernel = tmpKernel; @@ -148,8 +247,18 @@ int CollectorSolaris::getRawProcessCpuLoad(RTPROCESS process, uint64_t *user, ui { //Assert((pid_t)process == pstatus.pr_pid); //Log(("user=%u kernel=%u total=%u\n", prusage.pr_utime.tv_sec, prusage.pr_stime.tv_sec, prusage.pr_tstamp.tv_sec)); - *user = (uint64_t)prusage.pr_utime.tv_sec * 1000000000 + prusage.pr_utime.tv_nsec; - *kernel = (uint64_t)prusage.pr_stime.tv_sec * 1000000000 + prusage.pr_stime.tv_nsec; + /* + * The CPU time spent must be adjusted by the number of cores for compatibility with + * other platforms (see @bugref{6345}). + */ + Assert(mCpus); + if (mCpus) + { + *user = ((uint64_t)prusage.pr_utime.tv_sec * 1000000000 + prusage.pr_utime.tv_nsec) / mCpus; + *kernel = ((uint64_t)prusage.pr_stime.tv_sec * 1000000000 + prusage.pr_stime.tv_nsec) / mCpus; + } + else + *user = *kernel = 0; *total = (uint64_t)prusage.pr_tstamp.tv_sec * 1000000000 + prusage.pr_tstamp.tv_nsec; //Log(("user=%llu kernel=%llu total=%llu\n", *user, *kernel, *total)); } @@ -171,61 +280,15 @@ int CollectorSolaris::getRawProcessCpuLoad(RTPROCESS process, uint64_t *user, ui int CollectorSolaris::getHostMemoryUsage(ULONG *total, ULONG *used, ULONG *available) { - int rc = VINF_SUCCESS; - - kstat_named_t *kn; - - if (mKC == 0 || mSysPages == 0) - return VERR_INTERNAL_ERROR; - - if (kstat_read(mKC, mSysPages, 0) == -1) + AssertReturn(totalRAM, VERR_INTERNAL_ERROR); + uint64_t cb; + int rc = RTSystemQueryAvailableRam(&cb); + if (RT_SUCCESS(rc)) { - Log(("kstat_read(sys_pages) -> %d\n", errno)); - return VERR_INTERNAL_ERROR; + *total = totalRAM; + *available = cb / 1024; + *used = *total - *available; } - if ((kn = (kstat_named_t *)kstat_data_lookup(mSysPages, (char *)"freemem")) == 0) - { - Log(("kstat_data_lookup(freemem) -> %d\n", errno)); - return VERR_INTERNAL_ERROR; - } - *available = kn->value.ul * (PAGE_SIZE/1024); - - if (kstat_read(mKC, mZFSCache, 0) != -1) - { - if (mZFSCache) - { - if ((kn = (kstat_named_t *)kstat_data_lookup(mZFSCache, (char *)"size"))) - { - ulong_t ulSize = kn->value.ul; - - if ((kn = (kstat_named_t *)kstat_data_lookup(mZFSCache, (char *)"c_min"))) - { - /* - * Account for ZFS minimum arc cache size limit. - * "c_min" is the target minimum size of the ZFS cache, and not the hard limit. It's possible - * for "size" to shrink below "c_min" (e.g: during boot & high memory consumption). - */ - ulong_t ulMin = kn->value.ul; - *available += ulSize > ulMin ? (ulSize - ulMin) / 1024 : 0; - } - else - Log(("kstat_data_lookup(c_min) ->%d\n", errno)); - } - else - Log(("kstat_data_lookup(size) -> %d\n", errno)); - } - else - Log(("mZFSCache missing.\n")); - } - - if ((kn = (kstat_named_t *)kstat_data_lookup(mSysPages, (char *)"physmem")) == 0) - { - Log(("kstat_data_lookup(physmem) -> %d\n", errno)); - return VERR_INTERNAL_ERROR; - } - *total = kn->value.ul * (PAGE_SIZE/1024); - *used = *total - *available; - return rc; } @@ -285,21 +348,53 @@ uint32_t CollectorSolaris::getInstance(const char *pszIfaceName, char *pszDevNam return uInstance; } +uint64_t CollectorSolaris::wrapCorrection(uint32_t cur, uint64_t prev, const char *name) +{ + NOREF(name); + uint64_t corrected = (prev & 0xffffffff00000000) + cur; + if (cur < (prev & 0xffffffff)) + { + /* wrap has occurred */ + corrected += 0x100000000; + LogFlowThisFunc(("Corrected wrap on %s (%u < %u), returned %llu.\n", + name, cur, (uint32_t)prev, corrected)); + } + return corrected; +} + +uint64_t CollectorSolaris::wrapDetection(uint64_t cur, uint64_t prev, const char *name) +{ + static bool fNotSeen = true; + + if (fNotSeen && cur < prev) + { + fNotSeen = false; + LogRel(("Detected wrap on %s (%llu < %llu).\n", name, cur, prev)); + } + return cur; +} + +/* + * WARNING! This function expects the previous values of rx and tx counter to + * be passed in as well as returnes new values in the same parameters. This is + * needed to provide a workaround for 32-bit counter wrapping. + */ int CollectorSolaris::getRawHostNetworkLoad(const char *name, uint64_t *rx, uint64_t *tx) { + static bool g_fNotReported = true; AssertReturn(strlen(name) < KSTAT_STRLEN, VERR_INVALID_PARAMETER); LogFlowThisFunc(("m=%s i=%d n=%s\n", "link", -1, name)); - kstat_t *ksAdapter = kstat_lookup(mKC, "link", -1, (char *)name); + kstat_t *ksAdapter = kstat_lookup(mKC, (char *)"link", -1, (char *)name); if (ksAdapter == 0) { char szModule[KSTAT_STRLEN]; uint32_t uInstance = getInstance(name, szModule); LogFlowThisFunc(("m=%s i=%u n=%s\n", szModule, uInstance, "phys")); - ksAdapter = kstat_lookup(mKC, szModule, uInstance, "phys"); + ksAdapter = kstat_lookup(mKC, szModule, uInstance, (char *)"phys"); if (ksAdapter == 0) { LogFlowThisFunc(("m=%s i=%u n=%s\n", szModule, uInstance, name)); - ksAdapter = kstat_lookup(mKC, szModule, uInstance, name); + ksAdapter = kstat_lookup(mKC, szModule, uInstance, (char *)name); if (ksAdapter == 0) { LogRel(("Failed to get network statistics for %s\n", name)); @@ -313,24 +408,311 @@ int CollectorSolaris::getRawHostNetworkLoad(const char *name, uint64_t *rx, uint return VERR_INTERNAL_ERROR; } kstat_named_t *kn; - if ((kn = (kstat_named_t *)kstat_data_lookup(ksAdapter, (char *)"rbytes")) == 0) + if ((kn = (kstat_named_t *)kstat_data_lookup(ksAdapter, (char *)"rbytes64")) == 0) { - LogRel(("kstat_data_lookup(rbytes) -> %d, name=%s\n", errno, name)); - return VERR_INTERNAL_ERROR; + if (g_fNotReported) + { + g_fNotReported = false; + LogRel(("Failed to locate rbytes64, falling back to 32-bit counters...\n")); + } + if ((kn = (kstat_named_t *)kstat_data_lookup(ksAdapter, (char *)"rbytes")) == 0) + { + LogRel(("kstat_data_lookup(rbytes) -> %d, name=%s\n", errno, name)); + return VERR_INTERNAL_ERROR; + } + *rx = wrapCorrection(kn->value.ul, *rx, "rbytes"); } - *rx = kn->value.ul; - if ((kn = (kstat_named_t *)kstat_data_lookup(ksAdapter, (char *)"obytes")) == 0) + else + *rx = wrapDetection(kn->value.ull, *rx, "rbytes64"); + if ((kn = (kstat_named_t *)kstat_data_lookup(ksAdapter, (char *)"obytes64")) == 0) { - LogRel(("kstat_data_lookup(obytes) -> %d\n", errno)); - return VERR_INTERNAL_ERROR; + if (g_fNotReported) + { + g_fNotReported = false; + LogRel(("Failed to locate obytes64, falling back to 32-bit counters...\n")); + } + if ((kn = (kstat_named_t *)kstat_data_lookup(ksAdapter, (char *)"obytes")) == 0) + { + LogRel(("kstat_data_lookup(obytes) -> %d\n", errno)); + return VERR_INTERNAL_ERROR; + } + *tx = wrapCorrection(kn->value.ul, *tx, "obytes"); + } + else + *tx = wrapDetection(kn->value.ull, *tx, "obytes64"); + return VINF_SUCCESS; +} + +int CollectorSolaris::getRawHostDiskLoad(const char *name, uint64_t *disk_ms, uint64_t *total_ms) +{ + int rc = VINF_SUCCESS; + AssertReturn(strlen(name) < KSTAT_STRLEN, VERR_INVALID_PARAMETER); + LogFlowThisFunc(("n=%s\n", name)); + kstat_t *ksDisk = kstat_lookup(mKC, NULL, -1, (char *)name); + if (ksDisk != 0) + { + if (kstat_read(mKC, ksDisk, 0) == -1) + { + LogRel(("kstat_read(%s) -> %d\n", name, errno)); + rc = VERR_INTERNAL_ERROR; + } + else + { + kstat_io_t *ksIo = KSTAT_IO_PTR(ksDisk); + /* + * We do not care for wrap possibility here, although we may + * reconsider in about 300 years (9223372036854775807 ns). + */ + *disk_ms = ksIo->rtime / 1000000; + *total_ms = ksDisk->ks_snaptime / 1000000; + } } - *tx = kn->value.ul; + else + { + LogRel(("kstat_lookup(%s) -> %d\n", name, errno)); + rc = VERR_INTERNAL_ERROR; + } + + return rc; +} + +uint64_t CollectorSolaris::getZfsTotal(uint64_t cbTotal, const char *szFsType, const char *szFsName) +{ + if (strcmp(szFsType, "zfs")) + return cbTotal; + FsMap::iterator it = mFsMap.find(szFsName); + if (it == mFsMap.end()) + return cbTotal; + + char *pszDataset = strdup(it->second.c_str()); + char *pszEnd = pszDataset + strlen(pszDataset); + uint64_t uAvail = 0; + while (pszEnd) + { + zfs_handle_t *hDataset; + + *pszEnd = 0; + hDataset = mZfsOpen(mZfsLib, pszDataset, ZFS_TYPE_DATASET); + if (!hDataset) + break; + + if (uAvail == 0) + { + uAvail = mZfsPropGetInt(hDataset, ZFS_PROP_REFQUOTA); + if (uAvail == 0) + uAvail = UINT64_MAX; + } + + uint64_t uQuota = mZfsPropGetInt(hDataset, ZFS_PROP_QUOTA); + if (uQuota && uAvail > uQuota) + uAvail = uQuota; + + pszEnd = strrchr(pszDataset, '/'); + if (!pszEnd) + { + uint64_t uPoolSize = mZfsPropGetInt(hDataset, ZFS_PROP_USED) + + mZfsPropGetInt(hDataset, ZFS_PROP_AVAILABLE); + if (uAvail > uPoolSize) + uAvail = uPoolSize; + } + mZfsClose(hDataset); + } + free(pszDataset); + + return uAvail ? uAvail : cbTotal; +} + +int CollectorSolaris::getHostFilesystemUsage(const char *path, ULONG *total, ULONG *used, ULONG *available) +{ + struct statvfs64 stats; + + if (statvfs64(path, &stats) == -1) + { + LogRel(("Failed to collect %s filesystem usage: errno=%d.\n", path, errno)); + return VERR_ACCESS_DENIED; + } + uint64_t cbBlock = stats.f_frsize ? stats.f_frsize : stats.f_bsize; + *total = (ULONG)(getZfsTotal(cbBlock * stats.f_blocks, stats.f_basetype, path) / _1M); + LogFlowThisFunc(("f_blocks=%llu.\n", stats.f_blocks)); + *used = (ULONG)(cbBlock * (stats.f_blocks - stats.f_bfree) / _1M); + *available = (ULONG)(cbBlock * stats.f_bavail / _1M); + return VINF_SUCCESS; } -int getDiskListByFs(const char *name, DiskList& list) +int CollectorSolaris::getHostDiskSize(const char *name, uint64_t *size) { - return VERR_NOT_IMPLEMENTED; + int rc = VINF_SUCCESS; + AssertReturn(strlen(name) + 5 < KSTAT_STRLEN, VERR_INVALID_PARAMETER); + LogFlowThisFunc(("n=%s\n", name)); + char szName[KSTAT_STRLEN]; + strcpy(szName, name); + strcat(szName, ",err"); + kstat_t *ksDisk = kstat_lookup(mKC, NULL, -1, szName); + if (ksDisk != 0) + { + if (kstat_read(mKC, ksDisk, 0) == -1) + { + LogRel(("kstat_read(%s) -> %d\n", name, errno)); + rc = VERR_INTERNAL_ERROR; + } + else + { + kstat_named_t *kn; + if ((kn = (kstat_named_t *)kstat_data_lookup(ksDisk, (char *)"Size")) == 0) + { + LogRel(("kstat_data_lookup(rbytes) -> %d, name=%s\n", errno, name)); + return VERR_INTERNAL_ERROR; + } + *size = kn->value.ull; + } + } + else + { + LogRel(("kstat_lookup(%s) -> %d\n", szName, errno)); + rc = VERR_INTERNAL_ERROR; + } + + + return rc; +} + +RTCString CollectorSolaris::physToInstName(const char *pcszPhysName) +{ + FILE *fp = fopen("/etc/path_to_inst", "r"); + if (!fp) + return RTCString(); + + RTCString strInstName; + size_t cbName = strlen(pcszPhysName); + char szBuf[RTPATH_MAX]; + while (fgets(szBuf, sizeof(szBuf), fp)) + { + if (szBuf[0] == '"' && strncmp(szBuf + 1, pcszPhysName, cbName) == 0) + { + char *pszDriver, *pszInstance; + pszDriver = strrchr(szBuf, '"'); + if (pszDriver) + { + *pszDriver = '\0'; + pszDriver = strrchr(szBuf, '"'); + if (pszDriver) + { + *pszDriver++ = '\0'; + pszInstance = strrchr(szBuf, ' '); + if (pszInstance) + { + *pszInstance = '\0'; + pszInstance = strrchr(szBuf, ' '); + if (pszInstance) + { + *pszInstance++ = '\0'; + strInstName = pszDriver; + strInstName += pszInstance; + break; + } + } + } + } + } + } + fclose(fp); + + return strInstName; +} + +RTCString CollectorSolaris::pathToInstName(const char *pcszDevPathName) +{ + char szLink[RTPATH_MAX]; + if (readlink(pcszDevPathName, szLink, sizeof(szLink)) != -1) + { + char *pszStart, *pszEnd; + pszStart = strstr(szLink, "/devices/"); + pszEnd = strrchr(szLink, ':'); + if (pszStart && pszEnd) + { + pszStart += 8; // Skip "/devices" + *pszEnd = '\0'; // Trim partition + return physToInstName(pszStart); + } + } + + return RTCString(pcszDevPathName); +} + +int CollectorSolaris::getDiskListByFs(const char *name, DiskList& listUsage, DiskList& listLoad) +{ + FsMap::iterator it = mFsMap.find(name); + if (it == mFsMap.end()) + return VERR_INVALID_PARAMETER; + + RTCString strName = it->second.substr(0, it->second.find("/")); + if (mZpoolOpen && mZpoolClose && mZpoolGetConfig && !strName.isEmpty()) + { + zpool_handle_t *zh = mZpoolOpen(mZfsLib, strName.c_str()); + if (zh) + { + unsigned int cChildren = 0; + nvlist_t **nvChildren = NULL; + nvlist_t *nvRoot = NULL; + nvlist_t *nvConfig = mZpoolGetConfig(zh, NULL); + if ( !nvlist_lookup_nvlist(nvConfig, ZPOOL_CONFIG_VDEV_TREE, &nvRoot) + && !nvlist_lookup_nvlist_array(nvRoot, ZPOOL_CONFIG_CHILDREN, &nvChildren, &cChildren)) + { + for (unsigned int i = 0; i < cChildren; ++i) + { + uint64_t fHole = 0; + uint64_t fLog = 0; + + nvlist_lookup_uint64(nvChildren[i], ZPOOL_CONFIG_IS_HOLE, &fHole); + nvlist_lookup_uint64(nvChildren[i], ZPOOL_CONFIG_IS_LOG, &fLog); + + if (!fHole && !fLog) + { + char *pszChildName = mZpoolVdevName(mZfsLib, zh, nvChildren[i], _B_FALSE); + Assert(pszChildName); + RTCString strDevPath("/dev/dsk/"); + strDevPath += pszChildName; + char szLink[RTPATH_MAX]; + if (readlink(strDevPath.c_str(), szLink, sizeof(szLink)) != -1) + { + char *pszStart, *pszEnd; + pszStart = strstr(szLink, "/devices/"); + pszEnd = strrchr(szLink, ':'); + if (pszStart && pszEnd) + { + pszStart += 8; // Skip "/devices" + *pszEnd = '\0'; // Trim partition + listUsage.push_back(physToInstName(pszStart)); + } + } + free(pszChildName); + } + } + } + mZpoolClose(zh); + } + } + else + listUsage.push_back(pathToInstName(it->second.c_str())); + listLoad = listUsage; + return VINF_SUCCESS; +} + +void CollectorSolaris::updateFilesystemMap(void) +{ + FILE *fp = fopen("/etc/mnttab", "r"); + if (fp) + { + struct mnttab Entry; + int rc = 0; + resetmnttab(fp); + while ((rc = getmntent(fp, &Entry)) == 0) + mFsMap[Entry.mnt_mountp] = Entry.mnt_special; + fclose(fp); + if (rc != -1) + LogRel(("Error while reading mnttab: %d\n", rc)); + } } } diff --git a/src/VBox/Main/src-server/solaris/USBProxyServiceSolaris.cpp b/src/VBox/Main/src-server/solaris/USBProxyServiceSolaris.cpp index 8261d990..0d6d85e8 100644 --- a/src/VBox/Main/src-server/solaris/USBProxyServiceSolaris.cpp +++ b/src/VBox/Main/src-server/solaris/USBProxyServiceSolaris.cpp @@ -173,7 +173,7 @@ static int solarisWalkDeviceNode(di_node_t Node, void *pvArg) char *pszCompatNames = NULL; int cCompatNames = di_compatible_names(Node, &pszCompatNames); for (int i = 0; i < cCompatNames; i++, pszCompatNames += strlen(pszCompatNames) + 1) - if (!strncmp(pszCompatNames, "usb", 3)) + if (!strncmp(pszCompatNames, RT_STR_TUPLE("usb"))) { fUSBDevice = true; break; @@ -304,7 +304,7 @@ static int solarisWalkDeviceNode(di_node_t Node, void *pvArg) pList->pTail = pList->pHead = pCur; rc = DI_WALK_CONTINUE; - } while(0); + } while (0); di_devfs_path_free(pszDevicePath); if (!fValidDevice) @@ -322,7 +322,7 @@ static USBDEVICESTATE solarisDetermineUSBDeviceState(PUSBDEVICE pDevice, di_node if (!pszDriverName) return USBDEVICESTATE_UNUSED; - if (!strncmp(pszDriverName, VBOXUSB_DRIVER_NAME, sizeof(VBOXUSB_DRIVER_NAME) - 1)) + if (!strncmp(pszDriverName, RT_STR_TUPLE(VBOXUSB_DRIVER_NAME))) return USBDEVICESTATE_HELD_BY_PROXY; NOREF(pDevice); |