ohmu
·
2026-10-15
1#include "diskio.h"
2
3#if __has_include(<libgeom.h>)
4
5 #include "common/debug.h"
6 #include "common/strutil.h"
7
8 #include <devstat.h>
9 #include <memory.h>
10 #include <fcntl.h>
11 #include <sys/ioctl.h>
12 #include <sys/disk.h>
13 #include <libgeom.h>
14
15 #include <errno.h>
16 #include <string.h>
17
18const char* ffDiskIOGetIoCounters(FFlist* result, FFDiskIOOptions* options) {
19 [[gnu::cleanup(geom_deletetree)]] struct gmesh geomTree = {};
20 if (geom_gettree(&geomTree) < 0) {
21 FF_DEBUG("geom_gettree() failed: %s", strerror(errno));
22 return "geom_gettree() failed";
23 }
24
25 if (geom_stats_open() < 0) {
26 FF_DEBUG("geom_stats_open() failed: %s", strerror(errno));
27 return "geom_stats_open() failed";
28 }
29
30 void* snap = geom_stats_snapshot_get();
31 if (!snap) {
32 FF_DEBUG("geom_stats_snapshot_get() returned null");
33 return "geom_stats_snapshot_get() failed";
34 }
35
36 struct devstat* snapIter;
37 while ((snapIter = geom_stats_snapshot_next(snap)) != nullptr) {
38 if (snapIter->device_type & DEVSTAT_TYPE_PASS) {
39 continue;
40 }
41 struct gident* geomId = geom_lookupid(&geomTree, snapIter->id);
42 if (geomId == nullptr) {
43 continue;
44 }
45 if (geomId->lg_what != ISPROVIDER) {
46 continue;
47 }
48 struct gprovider* provider = (struct gprovider*) geomId->lg_ptr;
49 if (provider->lg_geom->lg_rank != 1) {
50 continue;
51 }
52
53 FF_STRBUF_AUTO_DESTROY name = ffStrbufCreate();
54 for (struct gconfig* ptr = provider->lg_config.lh_first; ptr; ptr = ptr->lg_config.le_next) {
55 if (ffStrEquals(ptr->lg_name, "descr")) {
56 ffStrbufSetS(&name, ptr->lg_val);
57 }
58 }
59 if (name.length == 0) {
60 ffStrbufSetS(&name, provider->lg_name);
61 }
62
63 if (options->namePrefix.length && !ffStrbufStartsWith(&name, &options->namePrefix)) {
64 continue;
65 }
66
67 FFDiskIOResult* device = FF_LIST_ADD(FFDiskIOResult, *result);
68 ffStrbufInitF(&device->devPath, "/dev/%s", provider->lg_name);
69 device->bytesRead = snapIter->bytes[DEVSTAT_READ];
70 device->readCount = snapIter->operations[DEVSTAT_READ];
71 device->bytesWritten = snapIter->bytes[DEVSTAT_WRITE];
72 device->writeCount = snapIter->operations[DEVSTAT_WRITE];
73 ffStrbufInitMove(&device->name, &name);
74 }
75
76 geom_stats_snapshot_free(snap);
77 geom_stats_close();
78
79 return nullptr;
80}
81
82#else
83
84 #include "common/debug.h"
85
86 #include <devstat.h>
87 #include <memory.h>
88 #include <errno.h>
89
90const char* ffDiskIOGetIoCounters(FFlist* result, FFDiskIOOptions* options) {
91 if (checkversion() < 0) {
92 FF_DEBUG("checkversion() failed: %s", strerror(errno));
93 return "checkversion() failed";
94 }
95
96 struct statinfo stats = {
97 .dinfo = (struct devinfo*) calloc(1, sizeof(struct devinfo)),
98 };
99 if (getdevs(&stats) < 0) {
100 FF_DEBUG("getdevs() failed: %s", strerror(errno));
101 return "getdevs() failed";
102 }
103
104 for (int i = 0; i < stats.dinfo->numdevs; i++) {
105 struct devstat* current = &stats.dinfo->devices[i];
106 if (current->device_type & DEVSTAT_TYPE_PASS) {
107 continue;
108 }
109
110 char deviceName[128];
111 snprintf(deviceName, sizeof(deviceName), "%s%d", current->device_name, current->unit_number);
112
113 if (options->namePrefix.length && strncmp(deviceName, options->namePrefix.chars, options->namePrefix.length) != 0) {
114 continue;
115 }
116
117 FFDiskIOResult* device = FF_LIST_ADD(FFDiskIOResult, *result);
118 ffStrbufInitS(&device->name, deviceName);
119 ffStrbufInitF(&device->devPath, "/dev/%s", deviceName);
120 device->bytesRead = current->bytes_read;
121 device->readCount = current->num_reads;
122 device->bytesWritten = current->bytes_written;
123 device->writeCount = current->num_writes;
124 }
125
126 free(stats.dinfo->mem_ptr);
127 free(stats.dinfo);
128
129 return nullptr;
130}
131
132#endif