VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/solaris/PerformanceSolaris.cpp@ 102673

Last change on this file since 102673 was 98807, checked in by vboxsync, 22 months ago

Some small Solaris-specific build warning fixes:

Main/Console: Remove a duplicate 'HRESULT hrc' declaration (flagged as
'warning: declaration of ‘hrc’ shadows a previous local [-Wshadow]').

Main/PerformanceSolaris: Move global variable ‘g_fNotReported’ behind
'if ARCH_BITS == 32' as it's only used in 32-bit mode (flagged as
'warning: ‘g_fNotReported’ defined but not used [-Wunused-variable]').

HostDrivers/VBoxNetFlt: The vboxNetFltSolarisMuxIdToFd() routine calls
the Solaris STREAMS kernel routine strioctl() which only sets the
seventh argument (int *rvalp) upon success. vboxNetFltSolarisMuxIdToFd()
passes in an 'int *pFd' argument for this returned value and logically
only sets it upon success. The subsequent code ignores 'pFd' upon
failure but the compiler isn't smart enough to figure that out so add in
an initialization for '*pFd' (flagged as 'warning: ‘Ip6MuxFd’ may be used
uninitialized [-Wmaybe-uninitialized]' and similarly for 'Ip4MuxFd' and
'ArpMuxFd').

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 23.7 KB
Line 
1/* $Id: PerformanceSolaris.cpp 98807 2023-03-01 16:38:03Z vboxsync $ */
2/** @file
3 * VBox Solaris-specific Performance Classes implementation.
4 */
5
6/*
7 * Copyright (C) 2008-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28#define LOG_GROUP LOG_GROUP_MAIN_PERFORMANCECOLLECTOR
29#undef _FILE_OFFSET_BITS
30#include <procfs.h>
31#include <stdio.h>
32#include <errno.h>
33#include <fcntl.h>
34#include <kstat.h>
35#include <unistd.h>
36#include <sys/sysinfo.h>
37#include <sys/time.h>
38#include <sys/types.h>
39#include <sys/statvfs.h>
40
41#include <iprt/ctype.h>
42#include <iprt/err.h>
43#include <iprt/string.h>
44#include <iprt/alloc.h>
45#include <iprt/param.h>
46#include <iprt/path.h>
47#include <iprt/system.h>
48
49#include "LoggingNew.h"
50#include "Performance.h"
51
52#include <dlfcn.h>
53
54#include <libzfs.h>
55#include <libnvpair.h>
56
57#include <map>
58
59namespace pm {
60
61 typedef libzfs_handle_t *(*PFNZFSINIT)(void);
62 typedef void (*PFNZFSFINI)(libzfs_handle_t *);
63 typedef zfs_handle_t *(*PFNZFSOPEN)(libzfs_handle_t *, const char *, int);
64 typedef void (*PFNZFSCLOSE)(zfs_handle_t *);
65 typedef uint64_t (*PFNZFSPROPGETINT)(zfs_handle_t *, zfs_prop_t);
66 typedef zpool_handle_t *(*PFNZPOOLOPEN)(libzfs_handle_t *, const char *);
67 typedef void (*PFNZPOOLCLOSE)(zpool_handle_t *);
68 typedef nvlist_t *(*PFNZPOOLGETCONFIG)(zpool_handle_t *, nvlist_t **);
69 typedef char *(*PFNZPOOLVDEVNAME)(libzfs_handle_t *, zpool_handle_t *, nvlist_t *, boolean_t);
70
71 typedef std::map<RTCString,RTCString> FsMap;
72
73class CollectorSolaris : public CollectorHAL
74{
75public:
76 CollectorSolaris();
77 virtual ~CollectorSolaris();
78 virtual int getHostMemoryUsage(ULONG *total, ULONG *used, ULONG *available);
79 virtual int getHostFilesystemUsage(const char *name, ULONG *total, ULONG *used, ULONG *available);
80 virtual int getHostDiskSize(const char *name, uint64_t *size);
81 virtual int getProcessMemoryUsage(RTPROCESS process, ULONG *used);
82
83 virtual int getRawHostCpuLoad(uint64_t *user, uint64_t *kernel, uint64_t *idle);
84 virtual int getRawHostNetworkLoad(const char *name, uint64_t *rx, uint64_t *tx);
85 virtual int getRawHostDiskLoad(const char *name, uint64_t *disk_ms, uint64_t *total_ms);
86 virtual int getRawProcessCpuLoad(RTPROCESS process, uint64_t *user, uint64_t *kernel, uint64_t *total);
87
88 virtual int getDiskListByFs(const char *name, DiskList& listUsage, DiskList& listLoad);
89private:
90 static uint32_t getInstance(const char *pszIfaceName, char *pszDevName);
91 uint64_t getZfsTotal(uint64_t cbTotal, const char *szFsType, const char *szFsName);
92 void updateFilesystemMap(void);
93 RTCString physToInstName(const char *pcszPhysName);
94 RTCString pathToInstName(const char *pcszDevPathName);
95 uint64_t wrapCorrection(uint32_t cur, uint64_t prev, const char *name);
96 uint64_t wrapDetection(uint64_t cur, uint64_t prev, const char *name);
97
98 kstat_ctl_t *mKC;
99 kstat_t *mSysPages;
100 kstat_t *mZFSCache;
101
102 void *mZfsSo;
103 libzfs_handle_t *mZfsLib;
104 PFNZFSINIT mZfsInit;
105 PFNZFSFINI mZfsFini;
106 PFNZFSOPEN mZfsOpen;
107 PFNZFSCLOSE mZfsClose;
108 PFNZFSPROPGETINT mZfsPropGetInt;
109 PFNZPOOLOPEN mZpoolOpen;
110 PFNZPOOLCLOSE mZpoolClose;
111 PFNZPOOLGETCONFIG mZpoolGetConfig;
112 PFNZPOOLVDEVNAME mZpoolVdevName;
113
114 FsMap mFsMap;
115 uint32_t mCpus;
116 ULONG totalRAM;
117};
118
119CollectorHAL *createHAL()
120{
121 return new CollectorSolaris();
122}
123
124// Collector HAL for Solaris
125
126
127CollectorSolaris::CollectorSolaris()
128 : mKC(0),
129 mSysPages(0),
130 mZFSCache(0),
131 mZfsLib(0),
132 mCpus(0)
133{
134 if ((mKC = kstat_open()) == 0)
135 {
136 Log(("kstat_open() -> %d\n", errno));
137 return;
138 }
139
140 if ((mSysPages = kstat_lookup(mKC, (char *)"unix", 0, (char *)"system_pages")) == 0)
141 {
142 Log(("kstat_lookup(system_pages) -> %d\n", errno));
143 return;
144 }
145
146 if ((mZFSCache = kstat_lookup(mKC, (char *)"zfs", 0, (char *)"arcstats")) == 0)
147 {
148 Log(("kstat_lookup(system_pages) -> %d\n", errno));
149 }
150
151 /* Try to load libzfs dynamically, it may be missing. */
152 mZfsSo = dlopen("libzfs.so", RTLD_LAZY);
153 if (mZfsSo)
154 {
155 mZfsInit = (PFNZFSINIT)(uintptr_t)dlsym(mZfsSo, "libzfs_init");
156 mZfsFini = (PFNZFSFINI)(uintptr_t)dlsym(mZfsSo, "libzfs_fini");
157 mZfsOpen = (PFNZFSOPEN)(uintptr_t)dlsym(mZfsSo, "zfs_open");
158 mZfsClose = (PFNZFSCLOSE)(uintptr_t)dlsym(mZfsSo, "zfs_close");
159 mZfsPropGetInt = (PFNZFSPROPGETINT)(uintptr_t)dlsym(mZfsSo, "zfs_prop_get_int");
160 mZpoolOpen = (PFNZPOOLOPEN)(uintptr_t)dlsym(mZfsSo, "zpool_open");
161 mZpoolClose = (PFNZPOOLCLOSE)(uintptr_t)dlsym(mZfsSo, "zpool_close");
162 mZpoolGetConfig = (PFNZPOOLGETCONFIG)(uintptr_t)dlsym(mZfsSo, "zpool_get_config");
163 mZpoolVdevName = (PFNZPOOLVDEVNAME)(uintptr_t)dlsym(mZfsSo, "zpool_vdev_name");
164
165 if ( mZfsInit
166 && mZfsOpen
167 && mZfsClose
168 && mZfsPropGetInt
169 && mZpoolOpen
170 && mZpoolClose
171 && mZpoolGetConfig
172 && mZpoolVdevName)
173 mZfsLib = mZfsInit();
174 else
175 LogRel(("Incompatible libzfs? libzfs_init=%p zfs_open=%p zfs_close=%p zfs_prop_get_int=%p\n",
176 mZfsInit, mZfsOpen, mZfsClose, mZfsPropGetInt));
177 }
178
179 updateFilesystemMap();
180 /* Notice that mCpus member will be initialized by HostCpuLoadRaw::init() */
181
182 uint64_t cb;
183 int vrc = RTSystemQueryTotalRam(&cb);
184 if (RT_FAILURE(vrc))
185 totalRAM = 0;
186 else
187 totalRAM = (ULONG)(cb / 1024);
188}
189
190CollectorSolaris::~CollectorSolaris()
191{
192 if (mKC)
193 kstat_close(mKC);
194 /* Not calling libzfs_fini() causes file descriptor leaks (#6788). */
195 if (mZfsFini && mZfsLib)
196 mZfsFini(mZfsLib);
197 if (mZfsSo)
198 dlclose(mZfsSo);
199}
200
201int CollectorSolaris::getRawHostCpuLoad(uint64_t *user, uint64_t *kernel, uint64_t *idle)
202{
203 kstat_t *ksp;
204 uint64_t tmpUser, tmpKernel, tmpIdle;
205 int cpus;
206 cpu_stat_t cpu_stats;
207
208 if (mKC == 0)
209 return VERR_INTERNAL_ERROR;
210
211 tmpUser = tmpKernel = tmpIdle = cpus = 0;
212 for (ksp = mKC->kc_chain; ksp != NULL; ksp = ksp->ks_next) {
213 if (strcmp(ksp->ks_module, "cpu_stat") == 0) {
214 if (kstat_read(mKC, ksp, &cpu_stats) == -1)
215 {
216 Log(("kstat_read() -> %d\n", errno));
217 return VERR_INTERNAL_ERROR;
218 }
219 ++cpus;
220 tmpUser += cpu_stats.cpu_sysinfo.cpu[CPU_USER];
221 tmpKernel += cpu_stats.cpu_sysinfo.cpu[CPU_KERNEL];
222 tmpIdle += cpu_stats.cpu_sysinfo.cpu[CPU_IDLE];
223 }
224 }
225
226 if (cpus == 0)
227 {
228 Log(("no cpu stats found!\n"));
229 return VERR_INTERNAL_ERROR;
230 }
231 else
232 mCpus = cpus;
233
234 if (user) *user = tmpUser;
235 if (kernel) *kernel = tmpKernel;
236 if (idle) *idle = tmpIdle;
237
238 return VINF_SUCCESS;
239}
240
241int CollectorSolaris::getRawProcessCpuLoad(RTPROCESS process, uint64_t *user, uint64_t *kernel, uint64_t *total)
242{
243 int vrc = VINF_SUCCESS;
244 char *pszName;
245 prusage_t prusage;
246
247 RTStrAPrintf(&pszName, "/proc/%d/usage", process);
248 Log(("Opening %s...\n", pszName));
249 int h = open(pszName, O_RDONLY);
250 RTStrFree(pszName);
251
252 if (h != -1)
253 {
254 if (read(h, &prusage, sizeof(prusage)) == sizeof(prusage))
255 {
256 //Assert((pid_t)process == pstatus.pr_pid);
257 //Log(("user=%u kernel=%u total=%u\n", prusage.pr_utime.tv_sec, prusage.pr_stime.tv_sec, prusage.pr_tstamp.tv_sec));
258 /*
259 * The CPU time spent must be adjusted by the number of cores for compatibility with
260 * other platforms (see @bugref{6345}).
261 */
262 Assert(mCpus);
263 if (mCpus)
264 {
265 *user = ((uint64_t)prusage.pr_utime.tv_sec * 1000000000 + prusage.pr_utime.tv_nsec) / mCpus;
266 *kernel = ((uint64_t)prusage.pr_stime.tv_sec * 1000000000 + prusage.pr_stime.tv_nsec) / mCpus;
267 }
268 else
269 *user = *kernel = 0;
270 *total = (uint64_t)prusage.pr_tstamp.tv_sec * 1000000000 + prusage.pr_tstamp.tv_nsec;
271 //Log(("user=%llu kernel=%llu total=%llu\n", *user, *kernel, *total));
272 }
273 else
274 {
275 Log(("read() -> %d\n", errno));
276 vrc = VERR_FILE_IO_ERROR;
277 }
278 close(h);
279 }
280 else
281 {
282 Log(("open() -> %d\n", errno));
283 vrc = VERR_ACCESS_DENIED;
284 }
285
286 return vrc;
287}
288
289int CollectorSolaris::getHostMemoryUsage(ULONG *total, ULONG *used, ULONG *available)
290{
291 AssertReturn(totalRAM, VERR_INTERNAL_ERROR);
292 uint64_t cb;
293 int vrc = RTSystemQueryAvailableRam(&cb);
294 if (RT_SUCCESS(vrc))
295 {
296 *total = totalRAM;
297 *available = (ULONG)RT_MIN(cb / 1024, ~(ULONG)0);
298 *used = *total - *available;
299 }
300 return vrc;
301}
302
303int CollectorSolaris::getProcessMemoryUsage(RTPROCESS process, ULONG *used)
304{
305 int vrc = VINF_SUCCESS;
306 char *pszName = NULL;
307 psinfo_t psinfo;
308
309 RTStrAPrintf(&pszName, "/proc/%d/psinfo", process);
310 Log(("Opening %s...\n", pszName));
311 int h = open(pszName, O_RDONLY);
312 RTStrFree(pszName);
313
314 if (h != -1)
315 {
316 /* psinfo_t keeps growing, so only read what we need to maximize
317 * cross-version compatibility. The structures are compatible. */
318 ssize_t cb = RT_UOFFSETOF(psinfo_t, pr_rssize) + RT_SIZEOFMEMB(psinfo_t, pr_rssize);
319 AssertCompile(RTASSERT_OFFSET_OF(psinfo_t, pr_rssize) > RTASSERT_OFFSET_OF(psinfo_t, pr_pid));
320 if (read(h, &psinfo, cb) == cb)
321 {
322 Assert((pid_t)process == psinfo.pr_pid);
323 *used = (ULONG)RT_MIN(psinfo.pr_rssize, ~(ULONG)0);
324 }
325 else
326 {
327 Log(("read() -> %d\n", errno));
328 vrc = VERR_FILE_IO_ERROR;
329 }
330 close(h);
331 }
332 else
333 {
334 Log(("open() -> %d\n", errno));
335 vrc = VERR_ACCESS_DENIED;
336 }
337
338 return vrc;
339}
340
341uint32_t CollectorSolaris::getInstance(const char *pszIfaceName, char *pszDevName)
342{
343 /*
344 * Get the instance number from the interface name, then clip it off.
345 */
346 int cbInstance = 0;
347 size_t cbIface = strlen(pszIfaceName);
348 const char *pszEnd = pszIfaceName + cbIface - 1;
349 for (size_t i = 0; i < cbIface - 1; i++)
350 {
351 if (!RT_C_IS_DIGIT(*pszEnd))
352 break;
353 cbInstance++;
354 pszEnd--;
355 }
356
357 uint32_t uInstance = RTStrToUInt32(pszEnd + 1);
358 strncpy(pszDevName, pszIfaceName, cbIface - cbInstance);
359 pszDevName[cbIface - cbInstance] = '\0';
360 return uInstance;
361}
362
363uint64_t CollectorSolaris::wrapCorrection(uint32_t cur, uint64_t prev, const char *name)
364{
365 NOREF(name);
366 uint64_t corrected = (prev & 0xffffffff00000000) + cur;
367 if (cur < (prev & 0xffffffff))
368 {
369 /* wrap has occurred */
370 corrected += 0x100000000;
371 LogFlowThisFunc(("Corrected wrap on %s (%u < %u), returned %llu.\n",
372 name, cur, (uint32_t)prev, corrected));
373 }
374 return corrected;
375}
376
377uint64_t CollectorSolaris::wrapDetection(uint64_t cur, uint64_t prev, const char *name)
378{
379 if (cur < prev)
380 LogRelMax(2, ("Detected wrap on %s (%llu < %llu).\n", name, cur, prev));
381 return cur;
382}
383
384/*
385 * WARNING! This function expects the previous values of rx and tx counter to
386 * be passed in as well as returnes new values in the same parameters. This is
387 * needed to provide a workaround for 32-bit counter wrapping.
388 */
389int CollectorSolaris::getRawHostNetworkLoad(const char *name, uint64_t *rx, uint64_t *tx)
390{
391#if ARCH_BITS == 32
392 static bool g_fNotReported = true;
393#endif
394 AssertReturn(strlen(name) < KSTAT_STRLEN, VERR_INVALID_PARAMETER);
395 LogFlowThisFunc(("m=%s i=%d n=%s\n", "link", -1, name));
396 kstat_t *ksAdapter = kstat_lookup(mKC, (char *)"link", -1, (char *)name);
397 if (ksAdapter == 0)
398 {
399 char szModule[KSTAT_STRLEN];
400 uint32_t uInstance = getInstance(name, szModule);
401 LogFlowThisFunc(("m=%s i=%u n=%s\n", szModule, uInstance, "phys"));
402 ksAdapter = kstat_lookup(mKC, szModule, uInstance, (char *)"phys");
403 if (ksAdapter == 0)
404 {
405 LogFlowThisFunc(("m=%s i=%u n=%s\n", szModule, uInstance, name));
406 ksAdapter = kstat_lookup(mKC, szModule, uInstance, (char *)name);
407 if (ksAdapter == 0)
408 {
409 static uint32_t s_tsLogRelLast;
410 uint32_t tsNow = RTTimeProgramSecTS();
411 if ( tsNow < RT_SEC_1HOUR
412 || (tsNow - s_tsLogRelLast >= 60))
413 {
414 s_tsLogRelLast = tsNow;
415 LogRel(("Failed to get network statistics for %s. Max one msg/min.\n", name));
416 }
417 return VERR_INTERNAL_ERROR;
418 }
419 }
420 }
421 if (kstat_read(mKC, ksAdapter, 0) == -1)
422 {
423 LogRel(("kstat_read(adapter) -> %d\n", errno));
424 return VERR_INTERNAL_ERROR;
425 }
426 kstat_named_t *kn;
427 if ((kn = (kstat_named_t *)kstat_data_lookup(ksAdapter, (char *)"rbytes64")) == NULL)
428 {
429 if ((kn = (kstat_named_t *)kstat_data_lookup(ksAdapter, (char *)"rbytes")) == NULL)
430 {
431 LogRel(("kstat_data_lookup(rbytes) -> %d, name=%s\n", errno, name));
432 return VERR_INTERNAL_ERROR;
433 }
434#if ARCH_BITS == 32
435 if (g_fNotReported)
436 {
437 g_fNotReported = false;
438 LogRel(("Failed to locate rbytes64, falling back to 32-bit counters...\n"));
439 }
440 *rx = wrapCorrection(kn->value.ul, *rx, "rbytes");
441#else
442 AssertCompile(sizeof(kn->value.ul) == sizeof(uint64_t));
443 *rx = wrapDetection(kn->value.ul, *rx, "rbytes");
444#endif
445 }
446 else
447 *rx = wrapDetection(kn->value.ull, *rx, "rbytes64");
448 if ((kn = (kstat_named_t *)kstat_data_lookup(ksAdapter, (char *)"obytes64")) == NULL)
449 {
450 if ((kn = (kstat_named_t *)kstat_data_lookup(ksAdapter, (char *)"obytes")) == NULL)
451 {
452 LogRel(("kstat_data_lookup(obytes) -> %d\n", errno));
453 return VERR_INTERNAL_ERROR;
454 }
455#if ARCH_BITS == 32
456 if (g_fNotReported)
457 {
458 g_fNotReported = false;
459 LogRel(("Failed to locate obytes64, falling back to 32-bit counters...\n"));
460 }
461 *tx = wrapCorrection(kn->value.ul, *tx, "obytes");
462#else
463 AssertCompile(sizeof(kn->value.ul) == sizeof(uint64_t));
464 *tx = wrapDetection(kn->value.ul, *tx, "obytes");
465#endif
466 }
467 else
468 *tx = wrapDetection(kn->value.ull, *tx, "obytes64");
469 return VINF_SUCCESS;
470}
471
472int CollectorSolaris::getRawHostDiskLoad(const char *name, uint64_t *disk_ms, uint64_t *total_ms)
473{
474 int vrc = VINF_SUCCESS;
475 AssertReturn(strlen(name) < KSTAT_STRLEN, VERR_INVALID_PARAMETER);
476 LogFlowThisFunc(("n=%s\n", name));
477 kstat_t *ksDisk = kstat_lookup(mKC, NULL, -1, (char *)name);
478 if (ksDisk != 0)
479 {
480 if (kstat_read(mKC, ksDisk, 0) == -1)
481 {
482 LogRel(("kstat_read(%s) -> %d\n", name, errno));
483 vrc = VERR_INTERNAL_ERROR;
484 }
485 else
486 {
487 kstat_io_t *ksIo = KSTAT_IO_PTR(ksDisk);
488 /*
489 * We do not care for wrap possibility here, although we may
490 * reconsider in about 300 years (9223372036854775807 ns).
491 */
492 *disk_ms = ksIo->rtime / 1000000;
493 *total_ms = ksDisk->ks_snaptime / 1000000;
494 }
495 }
496 else
497 {
498 LogRel(("kstat_lookup(%s) -> %d\n", name, errno));
499 vrc = VERR_INTERNAL_ERROR;
500 }
501
502 return vrc;
503}
504
505uint64_t CollectorSolaris::getZfsTotal(uint64_t cbTotal, const char *szFsType, const char *szFsName)
506{
507 if (strcmp(szFsType, "zfs"))
508 return cbTotal;
509 FsMap::iterator it = mFsMap.find(szFsName);
510 if (it == mFsMap.end())
511 return cbTotal;
512
513 char *pszDataset = strdup(it->second.c_str());
514 char *pszEnd = pszDataset + strlen(pszDataset);
515 uint64_t uAvail = 0;
516 while (pszEnd)
517 {
518 zfs_handle_t *hDataset;
519
520 *pszEnd = 0;
521 hDataset = mZfsOpen(mZfsLib, pszDataset, ZFS_TYPE_DATASET);
522 if (!hDataset)
523 break;
524
525 if (uAvail == 0)
526 {
527 uAvail = mZfsPropGetInt(hDataset, ZFS_PROP_REFQUOTA);
528 if (uAvail == 0)
529 uAvail = UINT64_MAX;
530 }
531
532 uint64_t uQuota = mZfsPropGetInt(hDataset, ZFS_PROP_QUOTA);
533 if (uQuota && uAvail > uQuota)
534 uAvail = uQuota;
535
536 pszEnd = strrchr(pszDataset, '/');
537 if (!pszEnd)
538 {
539 uint64_t uPoolSize = mZfsPropGetInt(hDataset, ZFS_PROP_USED) +
540 mZfsPropGetInt(hDataset, ZFS_PROP_AVAILABLE);
541 if (uAvail > uPoolSize)
542 uAvail = uPoolSize;
543 }
544 mZfsClose(hDataset);
545 }
546 free(pszDataset);
547
548 return uAvail ? uAvail : cbTotal;
549}
550
551int CollectorSolaris::getHostFilesystemUsage(const char *path, ULONG *total, ULONG *used, ULONG *available)
552{
553 struct statvfs64 stats;
554
555 if (statvfs64(path, &stats) == -1)
556 {
557 LogRel(("Failed to collect %s filesystem usage: errno=%d.\n", path, errno));
558 return VERR_ACCESS_DENIED;
559 }
560 uint64_t cbBlock = stats.f_frsize ? stats.f_frsize : stats.f_bsize;
561 *total = (ULONG)(getZfsTotal(cbBlock * stats.f_blocks, stats.f_basetype, path) / _1M);
562 LogFlowThisFunc(("f_blocks=%llu.\n", stats.f_blocks));
563 *used = (ULONG)(cbBlock * (stats.f_blocks - stats.f_bfree) / _1M);
564 *available = (ULONG)(cbBlock * stats.f_bavail / _1M);
565
566 return VINF_SUCCESS;
567}
568
569int CollectorSolaris::getHostDiskSize(const char *name, uint64_t *size)
570{
571 int vrc = VINF_SUCCESS;
572 AssertReturn(strlen(name) + 5 < KSTAT_STRLEN, VERR_INVALID_PARAMETER);
573 LogFlowThisFunc(("n=%s\n", name));
574 char szName[KSTAT_STRLEN];
575 strcpy(szName, name);
576 strcat(szName, ",err");
577 kstat_t *ksDisk = kstat_lookup(mKC, NULL, -1, szName);
578 if (ksDisk != 0)
579 {
580 if (kstat_read(mKC, ksDisk, 0) == -1)
581 {
582 LogRel(("kstat_read(%s) -> %d\n", name, errno));
583 vrc = VERR_INTERNAL_ERROR;
584 }
585 else
586 {
587 kstat_named_t *kn;
588 if ((kn = (kstat_named_t *)kstat_data_lookup(ksDisk, (char *)"Size")) == 0)
589 {
590 LogRel(("kstat_data_lookup(rbytes) -> %d, name=%s\n", errno, name));
591 return VERR_INTERNAL_ERROR;
592 }
593 *size = kn->value.ull;
594 }
595 }
596 else
597 {
598 LogRel(("kstat_lookup(%s) -> %d\n", szName, errno));
599 vrc = VERR_INTERNAL_ERROR;
600 }
601
602
603 return vrc;
604}
605
606RTCString CollectorSolaris::physToInstName(const char *pcszPhysName)
607{
608 FILE *fp = fopen("/etc/path_to_inst", "r");
609 if (!fp)
610 return RTCString();
611
612 RTCString strInstName;
613 size_t cbName = strlen(pcszPhysName);
614 char szBuf[RTPATH_MAX];
615 while (fgets(szBuf, sizeof(szBuf), fp))
616 {
617 if (szBuf[0] == '"' && strncmp(szBuf + 1, pcszPhysName, cbName) == 0)
618 {
619 char *pszDriver, *pszInstance;
620 pszDriver = strrchr(szBuf, '"');
621 if (pszDriver)
622 {
623 *pszDriver = '\0';
624 pszDriver = strrchr(szBuf, '"');
625 if (pszDriver)
626 {
627 *pszDriver++ = '\0';
628 pszInstance = strrchr(szBuf, ' ');
629 if (pszInstance)
630 {
631 *pszInstance = '\0';
632 pszInstance = strrchr(szBuf, ' ');
633 if (pszInstance)
634 {
635 *pszInstance++ = '\0';
636 strInstName = pszDriver;
637 strInstName += pszInstance;
638 break;
639 }
640 }
641 }
642 }
643 }
644 }
645 fclose(fp);
646
647 return strInstName;
648}
649
650RTCString CollectorSolaris::pathToInstName(const char *pcszDevPathName)
651{
652 char szLink[RTPATH_MAX];
653 if (readlink(pcszDevPathName, szLink, sizeof(szLink)) != -1)
654 {
655 char *pszStart, *pszEnd;
656 pszStart = strstr(szLink, "/devices/");
657 pszEnd = strrchr(szLink, ':');
658 if (pszStart && pszEnd)
659 {
660 pszStart += 8; // Skip "/devices"
661 *pszEnd = '\0'; // Trim partition
662 return physToInstName(pszStart);
663 }
664 }
665
666 return RTCString(pcszDevPathName);
667}
668
669int CollectorSolaris::getDiskListByFs(const char *name, DiskList& listUsage, DiskList& listLoad)
670{
671 FsMap::iterator it = mFsMap.find(name);
672 if (it == mFsMap.end())
673 return VERR_INVALID_PARAMETER;
674
675 RTCString strName = it->second.substr(0, it->second.find("/"));
676 if (mZpoolOpen && mZpoolClose && mZpoolGetConfig && !strName.isEmpty())
677 {
678 zpool_handle_t *zh = mZpoolOpen(mZfsLib, strName.c_str());
679 if (zh)
680 {
681 unsigned int cChildren = 0;
682 nvlist_t **nvChildren = NULL;
683 nvlist_t *nvRoot = NULL;
684 nvlist_t *nvConfig = mZpoolGetConfig(zh, NULL);
685 if ( !nvlist_lookup_nvlist(nvConfig, ZPOOL_CONFIG_VDEV_TREE, &nvRoot)
686 && !nvlist_lookup_nvlist_array(nvRoot, ZPOOL_CONFIG_CHILDREN, &nvChildren, &cChildren))
687 {
688 for (unsigned int i = 0; i < cChildren; ++i)
689 {
690 uint64_t fHole = 0;
691 uint64_t fLog = 0;
692
693 nvlist_lookup_uint64(nvChildren[i], ZPOOL_CONFIG_IS_HOLE, &fHole);
694 nvlist_lookup_uint64(nvChildren[i], ZPOOL_CONFIG_IS_LOG, &fLog);
695
696 if (!fHole && !fLog)
697 {
698 char *pszChildName = mZpoolVdevName(mZfsLib, zh, nvChildren[i], _B_FALSE);
699 Assert(pszChildName);
700 RTCString strDevPath("/dev/dsk/");
701 strDevPath += pszChildName;
702 char szLink[RTPATH_MAX];
703 if (readlink(strDevPath.c_str(), szLink, sizeof(szLink)) != -1)
704 {
705 char *pszStart, *pszEnd;
706 pszStart = strstr(szLink, "/devices/");
707 pszEnd = strrchr(szLink, ':');
708 if (pszStart && pszEnd)
709 {
710 pszStart += 8; // Skip "/devices"
711 *pszEnd = '\0'; // Trim partition
712 listUsage.push_back(physToInstName(pszStart));
713 }
714 }
715 free(pszChildName);
716 }
717 }
718 }
719 mZpoolClose(zh);
720 }
721 }
722 else
723 listUsage.push_back(pathToInstName(it->second.c_str()));
724 listLoad = listUsage;
725 return VINF_SUCCESS;
726}
727
728void CollectorSolaris::updateFilesystemMap(void)
729{
730 FILE *fp = fopen("/etc/mnttab", "r");
731 if (fp)
732 {
733 struct mnttab Entry;
734 int iRc = 0;
735 resetmnttab(fp);
736 while ((iRc = getmntent(fp, &Entry)) == 0)
737 mFsMap[Entry.mnt_mountp] = Entry.mnt_special;
738 fclose(fp);
739 if (iRc != -1)
740 LogRel(("Error while reading mnttab: %d\n", iRc));
741 }
742}
743
744}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette