VirtualBox

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

Last change on this file since 46316 was 46316, checked in by vboxsync, 12 years ago

Main/Metrics: Solaris file descriptor leak fix (#6788)

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

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