Line 0
Link Here
|
|
|
1 |
--- src/disk.c.orig 2015-03-10 14:14:45 UTC |
2 |
+++ src/disk.c |
3 |
@@ -53,6 +53,10 @@ |
4 |
#if HAVE_IOKIT_IOBSD_H |
5 |
# include <IOKit/IOBSD.h> |
6 |
#endif |
7 |
+#if KERNEL_FREEBSD |
8 |
+#include <devstat.h> |
9 |
+#include <libgeom.h> |
10 |
+#endif |
11 |
|
12 |
#if HAVE_LIMITS_H |
13 |
# include <limits.h> |
14 |
@@ -107,6 +111,9 @@ typedef struct diskstats |
15 |
|
16 |
static diskstats_t *disklist; |
17 |
/* #endif KERNEL_LINUX */ |
18 |
+#elif KERNEL_FREEBSD |
19 |
+static struct gmesh geom_tree; |
20 |
+/* #endif KERNEL_FREEBSD */ |
21 |
|
22 |
#elif HAVE_LIBKSTAT |
23 |
#define MAX_NUMDISK 1024 |
24 |
@@ -222,6 +229,21 @@ static int disk_init (void) |
25 |
/* do nothing */ |
26 |
/* #endif KERNEL_LINUX */ |
27 |
|
28 |
+#elif KERNEL_FREEBSD |
29 |
+ int rv; |
30 |
+ |
31 |
+ rv = geom_gettree(&geom_tree); |
32 |
+ if (rv != 0) { |
33 |
+ ERROR ("geom_gettree() failed, returned %d", rv); |
34 |
+ return (-1); |
35 |
+ } |
36 |
+ rv = geom_stats_open(); |
37 |
+ if (rv != 0) { |
38 |
+ ERROR ("geom_stats_open() failed, returned %d", rv); |
39 |
+ return (-1); |
40 |
+ } |
41 |
+/* #endif KERNEL_FREEBSD */ |
42 |
+ |
43 |
#elif HAVE_LIBKSTAT |
44 |
kstat_t *ksp_chain; |
45 |
|
46 |
@@ -395,173 +417,223 @@ static int disk_read (void) |
47 |
io_registry_entry_t disk; |
48 |
io_registry_entry_t disk_child; |
49 |
io_iterator_t disk_list; |
50 |
- CFDictionaryRef props_dict; |
51 |
+ CFMutableDictionaryRef props_dict, child_dict; |
52 |
CFDictionaryRef stats_dict; |
53 |
- CFDictionaryRef child_dict; |
54 |
CFStringRef tmp_cf_string_ref; |
55 |
kern_return_t status; |
56 |
|
57 |
- signed long long read_ops; |
58 |
- signed long long read_byt; |
59 |
- signed long long read_tme; |
60 |
- signed long long write_ops; |
61 |
- signed long long write_byt; |
62 |
- signed long long write_tme; |
63 |
+ signed long long read_ops, read_byt, read_tme; |
64 |
+ signed long long write_ops, write_byt, write_tme; |
65 |
|
66 |
- int disk_major; |
67 |
- int disk_minor; |
68 |
+ int disk_major, disk_minor; |
69 |
char disk_name[DATA_MAX_NAME_LEN]; |
70 |
- char disk_name_bsd[DATA_MAX_NAME_LEN]; |
71 |
+ char child_disk_name_bsd[DATA_MAX_NAME_LEN], props_disk_name_bsd[DATA_MAX_NAME_LEN]; |
72 |
|
73 |
/* Get the list of all disk objects. */ |
74 |
- if (IOServiceGetMatchingServices (io_master_port, |
75 |
- IOServiceMatching (kIOBlockStorageDriverClass), |
76 |
- &disk_list) != kIOReturnSuccess) |
77 |
- { |
78 |
+ if (IOServiceGetMatchingServices (io_master_port, IOServiceMatching (kIOBlockStorageDriverClass), &disk_list) != kIOReturnSuccess) { |
79 |
ERROR ("disk plugin: IOServiceGetMatchingServices failed."); |
80 |
return (-1); |
81 |
} |
82 |
|
83 |
- while ((disk = IOIteratorNext (disk_list)) != 0) |
84 |
- { |
85 |
+ while ((disk = IOIteratorNext (disk_list)) != 0) { |
86 |
props_dict = NULL; |
87 |
stats_dict = NULL; |
88 |
child_dict = NULL; |
89 |
|
90 |
- /* `disk_child' must be released */ |
91 |
- if ((status = IORegistryEntryGetChildEntry (disk, kIOServicePlane, &disk_child)) |
92 |
- != kIOReturnSuccess) |
93 |
- { |
94 |
- /* This fails for example for DVD/CD drives.. */ |
95 |
+ /* get child of disk entry and corresponding property dictionary */ |
96 |
+ if ((status = IORegistryEntryGetChildEntry (disk, kIOServicePlane, &disk_child)) != kIOReturnSuccess) { |
97 |
+ /* This fails for example for DVD/CD drives, which we want to ignore anyway */ |
98 |
DEBUG ("IORegistryEntryGetChildEntry (disk) failed: 0x%08x", status); |
99 |
IOObjectRelease (disk); |
100 |
continue; |
101 |
} |
102 |
- |
103 |
- /* We create `props_dict' => we need to release it later */ |
104 |
- if (IORegistryEntryCreateCFProperties (disk, |
105 |
- (CFMutableDictionaryRef *) &props_dict, |
106 |
- kCFAllocatorDefault, |
107 |
- kNilOptions) |
108 |
- != kIOReturnSuccess) |
109 |
- { |
110 |
- ERROR ("disk-plugin: IORegistryEntryCreateCFProperties failed."); |
111 |
+ if (IORegistryEntryCreateCFProperties (disk_child, (CFMutableDictionaryRef *) &child_dict, kCFAllocatorDefault, kNilOptions) != kIOReturnSuccess || child_dict == NULL) { |
112 |
+ ERROR ("disk plugin: IORegistryEntryCreateCFProperties (disk_child) failed."); |
113 |
IOObjectRelease (disk_child); |
114 |
IOObjectRelease (disk); |
115 |
continue; |
116 |
} |
117 |
|
118 |
- if (props_dict == NULL) |
119 |
- { |
120 |
- DEBUG ("IORegistryEntryCreateCFProperties (disk) failed."); |
121 |
- IOObjectRelease (disk_child); |
122 |
- IOObjectRelease (disk); |
123 |
- continue; |
124 |
+ /* extract name and major/minor numbers */ |
125 |
+ memset (child_disk_name_bsd, 0, sizeof (child_disk_name_bsd)); |
126 |
+ tmp_cf_string_ref = (CFStringRef) CFDictionaryGetValue (child_dict, CFSTR(kIOBSDNameKey)); |
127 |
+ if (tmp_cf_string_ref) { |
128 |
+ assert (CFGetTypeID (tmp_cf_string_ref) == CFStringGetTypeID ()); |
129 |
+ CFStringGetCString (tmp_cf_string_ref, child_disk_name_bsd, sizeof (child_disk_name_bsd), kCFStringEncodingUTF8); |
130 |
} |
131 |
+ disk_major = (int) dict_get_value (child_dict, kIOBSDMajorKey); |
132 |
+ disk_minor = (int) dict_get_value (child_dict, kIOBSDMinorKey); |
133 |
+ DEBUG ("disk plugin: child_disk_name_bsd=\"%s\" major=%d minor=%d", child_disk_name_bsd, disk_major, disk_minor); |
134 |
+ CFRelease (child_dict); |
135 |
+ IOObjectRelease (disk_child); |
136 |
|
137 |
- /* tmp_cf_string_ref doesn't need to be released. */ |
138 |
- tmp_cf_string_ref = (CFStringRef) CFDictionaryGetValue (props_dict, |
139 |
- CFSTR(kIOBSDNameKey)); |
140 |
- if (!tmp_cf_string_ref) |
141 |
- { |
142 |
- DEBUG ("disk plugin: CFDictionaryGetValue(" |
143 |
- "kIOBSDNameKey) failed."); |
144 |
- CFRelease (props_dict); |
145 |
- IOObjectRelease (disk_child); |
146 |
+ /* get property dictionary of the disk entry itself */ |
147 |
+ if (IORegistryEntryCreateCFProperties (disk, (CFMutableDictionaryRef *) &props_dict, kCFAllocatorDefault, kNilOptions) != kIOReturnSuccess || props_dict == NULL) { |
148 |
+ ERROR ("disk-plugin: IORegistryEntryCreateCFProperties failed."); |
149 |
IOObjectRelease (disk); |
150 |
continue; |
151 |
} |
152 |
- assert (CFGetTypeID (tmp_cf_string_ref) == CFStringGetTypeID ()); |
153 |
|
154 |
- memset (disk_name_bsd, 0, sizeof (disk_name_bsd)); |
155 |
- CFStringGetCString (tmp_cf_string_ref, |
156 |
- disk_name_bsd, sizeof (disk_name_bsd), |
157 |
- kCFStringEncodingUTF8); |
158 |
- if (disk_name_bsd[0] == 0) |
159 |
- { |
160 |
- ERROR ("disk plugin: CFStringGetCString() failed."); |
161 |
- CFRelease (props_dict); |
162 |
- IOObjectRelease (disk_child); |
163 |
- IOObjectRelease (disk); |
164 |
- continue; |
165 |
+ /* extract name and stats dictionary */ |
166 |
+ memset (props_disk_name_bsd, 0, sizeof (props_disk_name_bsd)); |
167 |
+ tmp_cf_string_ref = (CFStringRef) CFDictionaryGetValue (props_dict, CFSTR(kIOBSDNameKey)); |
168 |
+ if (tmp_cf_string_ref) { |
169 |
+ assert (CFGetTypeID (tmp_cf_string_ref) == CFStringGetTypeID ()); |
170 |
+ CFStringGetCString (tmp_cf_string_ref, props_disk_name_bsd, sizeof (props_disk_name_bsd), kCFStringEncodingUTF8); |
171 |
} |
172 |
- DEBUG ("disk plugin: disk_name_bsd = \"%s\"", disk_name_bsd); |
173 |
- |
174 |
- stats_dict = (CFDictionaryRef) CFDictionaryGetValue (props_dict, |
175 |
- CFSTR (kIOBlockStorageDriverStatisticsKey)); |
176 |
- |
177 |
- if (stats_dict == NULL) |
178 |
- { |
179 |
- DEBUG ("disk plugin: CFDictionaryGetValue (" |
180 |
- "%s) failed.", |
181 |
- kIOBlockStorageDriverStatisticsKey); |
182 |
+ stats_dict = (CFDictionaryRef) CFDictionaryGetValue (props_dict, CFSTR (kIOBlockStorageDriverStatisticsKey)); |
183 |
+ if (stats_dict == NULL) { |
184 |
+ ERROR ("disk plugin: CFDictionaryGetValue (%s) failed.", kIOBlockStorageDriverStatisticsKey); |
185 |
CFRelease (props_dict); |
186 |
- IOObjectRelease (disk_child); |
187 |
IOObjectRelease (disk); |
188 |
continue; |
189 |
} |
190 |
+ DEBUG ("disk plugin: props_disk_name_bsd=\"%s\"", props_disk_name_bsd); |
191 |
|
192 |
- if (IORegistryEntryCreateCFProperties (disk_child, |
193 |
- (CFMutableDictionaryRef *) &child_dict, |
194 |
- kCFAllocatorDefault, |
195 |
- kNilOptions) |
196 |
- != kIOReturnSuccess) |
197 |
- { |
198 |
- DEBUG ("disk plugin: IORegistryEntryCreateCFProperties (" |
199 |
- "disk_child) failed."); |
200 |
- IOObjectRelease (disk_child); |
201 |
- CFRelease (props_dict); |
202 |
- IOObjectRelease (disk); |
203 |
- continue; |
204 |
+ /* choose name */ |
205 |
+ if (use_bsd_name) { |
206 |
+ if (child_disk_name_bsd[0] != 0) |
207 |
+ sstrncpy (disk_name, child_disk_name_bsd, sizeof (disk_name)); |
208 |
+ else if (props_disk_name_bsd[0] != 0) |
209 |
+ sstrncpy (disk_name, props_disk_name_bsd, sizeof (disk_name)); |
210 |
+ else { |
211 |
+ ERROR ("disk plugin: can't find bsd disk name."); |
212 |
+ ssnprintf (disk_name, sizeof (disk_name), "%i-%i", disk_major, disk_minor); |
213 |
+ } |
214 |
} |
215 |
+ else |
216 |
+ ssnprintf (disk_name, sizeof (disk_name), "%i-%i", disk_major, disk_minor); |
217 |
|
218 |
- /* kIOBSDNameKey */ |
219 |
- disk_major = (int) dict_get_value (child_dict, |
220 |
- kIOBSDMajorKey); |
221 |
- disk_minor = (int) dict_get_value (child_dict, |
222 |
- kIOBSDMinorKey); |
223 |
- read_ops = dict_get_value (stats_dict, |
224 |
- kIOBlockStorageDriverStatisticsReadsKey); |
225 |
- read_byt = dict_get_value (stats_dict, |
226 |
- kIOBlockStorageDriverStatisticsBytesReadKey); |
227 |
- read_tme = dict_get_value (stats_dict, |
228 |
- kIOBlockStorageDriverStatisticsTotalReadTimeKey); |
229 |
- write_ops = dict_get_value (stats_dict, |
230 |
- kIOBlockStorageDriverStatisticsWritesKey); |
231 |
- write_byt = dict_get_value (stats_dict, |
232 |
- kIOBlockStorageDriverStatisticsBytesWrittenKey); |
233 |
- /* This property describes the number of nanoseconds spent |
234 |
- * performing writes since the block storage driver was |
235 |
- * instantiated. It is one of the statistic entries listed |
236 |
- * under the top-level kIOBlockStorageDriverStatisticsKey |
237 |
- * property table. It has an OSNumber value. */ |
238 |
- write_tme = dict_get_value (stats_dict, |
239 |
- kIOBlockStorageDriverStatisticsTotalWriteTimeKey); |
240 |
+ /* extract the stats */ |
241 |
+ read_ops = dict_get_value (stats_dict, kIOBlockStorageDriverStatisticsReadsKey); |
242 |
+ read_byt = dict_get_value (stats_dict, kIOBlockStorageDriverStatisticsBytesReadKey); |
243 |
+ read_tme = dict_get_value (stats_dict, kIOBlockStorageDriverStatisticsTotalReadTimeKey); |
244 |
+ write_ops = dict_get_value (stats_dict, kIOBlockStorageDriverStatisticsWritesKey); |
245 |
+ write_byt = dict_get_value (stats_dict, kIOBlockStorageDriverStatisticsBytesWrittenKey); |
246 |
+ write_tme = dict_get_value (stats_dict, kIOBlockStorageDriverStatisticsTotalWriteTimeKey); |
247 |
+ CFRelease (props_dict); |
248 |
+ IOObjectRelease (disk); |
249 |
|
250 |
- if (use_bsd_name) |
251 |
- sstrncpy (disk_name, disk_name_bsd, sizeof (disk_name)); |
252 |
- else |
253 |
- ssnprintf (disk_name, sizeof (disk_name), "%i-%i", |
254 |
- disk_major, disk_minor); |
255 |
+ /* and submit */ |
256 |
DEBUG ("disk plugin: disk_name = \"%s\"", disk_name); |
257 |
- |
258 |
if ((read_byt != -1LL) || (write_byt != -1LL)) |
259 |
disk_submit (disk_name, "disk_octets", read_byt, write_byt); |
260 |
if ((read_ops != -1LL) || (write_ops != -1LL)) |
261 |
disk_submit (disk_name, "disk_ops", read_ops, write_ops); |
262 |
if ((read_tme != -1LL) || (write_tme != -1LL)) |
263 |
- disk_submit (disk_name, "disk_time", |
264 |
- read_tme / 1000, |
265 |
- write_tme / 1000); |
266 |
+ disk_submit (disk_name, "disk_time", read_tme / 1000, write_tme / 1000); |
267 |
|
268 |
- CFRelease (child_dict); |
269 |
- IOObjectRelease (disk_child); |
270 |
- CFRelease (props_dict); |
271 |
- IOObjectRelease (disk); |
272 |
} |
273 |
IOObjectRelease (disk_list); |
274 |
/* #endif HAVE_IOKIT_IOKITLIB_H */ |
275 |
|
276 |
+#elif KERNEL_FREEBSD |
277 |
+ int retry, dirty; |
278 |
+ |
279 |
+ void *snap = NULL; |
280 |
+ struct devstat *snap_iter; |
281 |
+ |
282 |
+ struct gident *geom_id; |
283 |
+ |
284 |
+ const char *disk_name; |
285 |
+ long double read_time, write_time; |
286 |
+ |
287 |
+ for (retry = 0, dirty = 1; retry < 5 && dirty == 1; retry++) { |
288 |
+ if (snap != NULL) |
289 |
+ geom_stats_snapshot_free(snap); |
290 |
+ |
291 |
+ /* Get a fresh copy of stats snapshot */ |
292 |
+ snap = geom_stats_snapshot_get(); |
293 |
+ if (snap == NULL) { |
294 |
+ ERROR("disk plugin: geom_stats_snapshot_get() failed."); |
295 |
+ return (-1); |
296 |
+ } |
297 |
+ |
298 |
+ /* Check if we have dirty read from this snapshot */ |
299 |
+ dirty = 0; |
300 |
+ geom_stats_snapshot_reset(snap); |
301 |
+ while ((snap_iter = geom_stats_snapshot_next(snap)) != NULL) { |
302 |
+ if (snap_iter->id == NULL) |
303 |
+ continue; |
304 |
+ geom_id = geom_lookupid(&geom_tree, snap_iter->id); |
305 |
+ |
306 |
+ /* New device? refresh GEOM tree */ |
307 |
+ if (geom_id == NULL) { |
308 |
+ geom_deletetree(&geom_tree); |
309 |
+ if (geom_gettree(&geom_tree) != 0) { |
310 |
+ ERROR("disk plugin: geom_gettree() failed"); |
311 |
+ geom_stats_snapshot_free(snap); |
312 |
+ return (-1); |
313 |
+ } |
314 |
+ geom_id = geom_lookupid(&geom_tree, snap_iter->id); |
315 |
+ } |
316 |
+ /* |
317 |
+ * This should be rare: the device come right before we take the |
318 |
+ * snapshot and went away right after it. We will handle this |
319 |
+ * case later, so don't mark dirty but silently ignore it. |
320 |
+ */ |
321 |
+ if (geom_id == NULL) |
322 |
+ continue; |
323 |
+ |
324 |
+ /* Only collect PROVIDER data */ |
325 |
+ if (geom_id->lg_what != ISPROVIDER) |
326 |
+ continue; |
327 |
+ |
328 |
+ /* Only collect data when rank is 1 (physical devices) */ |
329 |
+ if (((struct gprovider *)(geom_id->lg_ptr))->lg_geom->lg_rank != 1) |
330 |
+ continue; |
331 |
+ |
332 |
+ /* Check if this is a dirty read quit for another try */ |
333 |
+ if (snap_iter->sequence0 != snap_iter->sequence1) { |
334 |
+ dirty = 1; |
335 |
+ break; |
336 |
+ } |
337 |
+ } |
338 |
+ } |
339 |
+ |
340 |
+ /* Reset iterator */ |
341 |
+ geom_stats_snapshot_reset(snap); |
342 |
+ for (;;) { |
343 |
+ snap_iter = geom_stats_snapshot_next(snap); |
344 |
+ if (snap_iter == NULL) |
345 |
+ break; |
346 |
+ |
347 |
+ if (snap_iter->id == NULL) |
348 |
+ continue; |
349 |
+ geom_id = geom_lookupid(&geom_tree, snap_iter->id); |
350 |
+ if (geom_id == NULL) |
351 |
+ continue; |
352 |
+ if (geom_id->lg_what != ISPROVIDER) |
353 |
+ continue; |
354 |
+ if (((struct gprovider *)(geom_id->lg_ptr))->lg_geom->lg_rank != 1) |
355 |
+ continue; |
356 |
+ /* Skip dirty reads, if present */ |
357 |
+ if (dirty && (snap_iter->sequence0 != snap_iter->sequence1)) |
358 |
+ continue; |
359 |
+ |
360 |
+ disk_name = ((struct gprovider *)geom_id->lg_ptr)->lg_name; |
361 |
+ |
362 |
+ if ((snap_iter->bytes[1] != 0) || (snap_iter->bytes[2] != 0)) { |
363 |
+ disk_submit(disk_name, "disk_octets", |
364 |
+ (derive_t)snap_iter->bytes[1], |
365 |
+ (derive_t)snap_iter->bytes[2]); |
366 |
+ } |
367 |
+ |
368 |
+ if ((snap_iter->operations[1] != 0) || (snap_iter->operations[2] != 0)) { |
369 |
+ disk_submit(disk_name, "disk_ops", |
370 |
+ (derive_t)snap_iter->operations[1], |
371 |
+ (derive_t)snap_iter->operations[2]); |
372 |
+ } |
373 |
+ |
374 |
+ read_time = devstat_compute_etime(&snap_iter->duration[DEVSTAT_READ], NULL); |
375 |
+ write_time = devstat_compute_etime(&snap_iter->duration[DEVSTAT_WRITE], NULL); |
376 |
+ if ((read_time != 0) || (write_time != 0)) { |
377 |
+ disk_submit (disk_name, "disk_time", |
378 |
+ (derive_t)(read_time*1000), (derive_t)(write_time*1000)); |
379 |
+ } |
380 |
+ } |
381 |
+ geom_stats_snapshot_free(snap); |
382 |
+ |
383 |
#elif KERNEL_LINUX |
384 |
FILE *fh; |
385 |
char buffer[1024]; |