Treewide: cleanup whitespace
[collectd.git] / src / disk.c
index 1c3dd98..85b2329 100644 (file)
 #if HAVE_IOKIT_IOBSD_H
 #  include <IOKit/IOBSD.h>
 #endif
+#if KERNEL_FREEBSD
+#include <devstat.h>
+#include <libgeom.h>
+#endif
 
 #if HAVE_LIMITS_H
 # include <limits.h>
@@ -107,6 +111,9 @@ typedef struct diskstats
 
 static diskstats_t *disklist;
 /* #endif KERNEL_LINUX */
+#elif KERNEL_FREEBSD
+static struct gmesh geom_tree;
+/* #endif KERNEL_FREEBSD */
 
 #elif HAVE_LIBKSTAT
 #define MAX_NUMDISK 1024
@@ -222,6 +229,21 @@ static int disk_init (void)
        /* do nothing */
 /* #endif KERNEL_LINUX */
 
+#elif KERNEL_FREEBSD
+       int rv;
+
+       rv = geom_gettree(&geom_tree);
+       if (rv != 0) {
+               ERROR ("geom_gettree() failed, returned %d", rv);
+               return (-1);
+       }
+       rv = geom_stats_open();
+       if (rv != 0) {
+               ERROR ("geom_stats_open() failed, returned %d", rv);
+               return (-1);
+       }
+/* #endif KERNEL_FREEBSD */
+
 #elif HAVE_LIBKSTAT
        kstat_t *ksp_chain;
 
@@ -367,7 +389,7 @@ static signed long long dict_get_value (CFDictionaryRef dict, const char *key)
                DEBUG ("CFStringCreateWithCString (%s) failed.", key);
                return (-1LL);
        }
-       
+
        /* get => we don't need to release (== free) the object */
        val_obj = (CFNumberRef) CFDictionaryGetValue (dict, key_obj);
 
@@ -505,10 +527,117 @@ static int disk_read (void)
        IOObjectRelease (disk_list);
 /* #endif HAVE_IOKIT_IOKITLIB_H */
 
+#elif KERNEL_FREEBSD
+       int retry, dirty;
+
+       void *snap = NULL;
+       struct devstat *snap_iter;
+
+       struct gident *geom_id;
+
+       const char *disk_name;
+       long double read_time, write_time;
+
+       for (retry = 0, dirty = 1; retry < 5 && dirty == 1; retry++) {
+               if (snap != NULL)
+                       geom_stats_snapshot_free(snap);
+
+               /* Get a fresh copy of stats snapshot */
+               snap = geom_stats_snapshot_get();
+               if (snap == NULL) {
+                       ERROR("disk plugin: geom_stats_snapshot_get() failed.");
+                       return (-1);
+               }
+
+               /* Check if we have dirty read from this snapshot */
+               dirty = 0;
+               geom_stats_snapshot_reset(snap);
+               while ((snap_iter = geom_stats_snapshot_next(snap)) != NULL) {
+                       if (snap_iter->id == NULL)
+                               continue;
+                       geom_id = geom_lookupid(&geom_tree, snap_iter->id);
+
+                       /* New device? refresh GEOM tree */
+                       if (geom_id == NULL) {
+                               geom_deletetree(&geom_tree);
+                               if (geom_gettree(&geom_tree) != 0) {
+                                       ERROR("disk plugin: geom_gettree() failed");
+                                       geom_stats_snapshot_free(snap);
+                                       return (-1);
+                               }
+                               geom_id = geom_lookupid(&geom_tree, snap_iter->id);
+                       }
+                       /*
+                        * This should be rare: the device come right before we take the
+                        * snapshot and went away right after it.  We will handle this
+                        * case later, so don't mark dirty but silently ignore it.
+                        */
+                       if (geom_id == NULL)
+                               continue;
+
+                       /* Only collect PROVIDER data */
+                       if (geom_id->lg_what != ISPROVIDER)
+                               continue;
+
+                       /* Only collect data when rank is 1 (physical devices) */
+                       if (((struct gprovider *)(geom_id->lg_ptr))->lg_geom->lg_rank != 1)
+                               continue;
+
+                       /* Check if this is a dirty read quit for another try */
+                       if (snap_iter->sequence0 != snap_iter->sequence1) {
+                               dirty = 1;
+                               break;
+                       }
+               }
+       }
+
+       /* Reset iterator */
+       geom_stats_snapshot_reset(snap);
+       for (;;) {
+               snap_iter = geom_stats_snapshot_next(snap);
+               if (snap_iter == NULL)
+                       break;
+
+               if (snap_iter->id == NULL)
+                       continue;
+               geom_id = geom_lookupid(&geom_tree, snap_iter->id);
+               if (geom_id == NULL)
+                       continue;
+               if (geom_id->lg_what != ISPROVIDER)
+                       continue;
+               if (((struct gprovider *)(geom_id->lg_ptr))->lg_geom->lg_rank != 1)
+                       continue;
+               /* Skip dirty reads, if present */
+               if (dirty && (snap_iter->sequence0 != snap_iter->sequence1))
+                       continue;
+
+               disk_name = ((struct gprovider *)geom_id->lg_ptr)->lg_name;
+
+               if ((snap_iter->bytes[DEVSTAT_READ] != 0) || (snap_iter->bytes[DEVSTAT_WRITE] != 0)) {
+                       disk_submit(disk_name, "disk_octets",
+                                       (derive_t)snap_iter->bytes[DEVSTAT_READ],
+                                       (derive_t)snap_iter->bytes[DEVSTAT_WRITE]);
+               }
+
+               if ((snap_iter->operations[DEVSTAT_READ] != 0) || (snap_iter->operations[DEVSTAT_WRITE] != 0)) {
+                       disk_submit(disk_name, "disk_ops",
+                                       (derive_t)snap_iter->operations[DEVSTAT_READ],
+                                       (derive_t)snap_iter->operations[DEVSTAT_WRITE]);
+               }
+
+               read_time = devstat_compute_etime(&snap_iter->duration[DEVSTAT_READ], NULL);
+               write_time = devstat_compute_etime(&snap_iter->duration[DEVSTAT_WRITE], NULL);
+               if ((read_time != 0) || (write_time != 0)) {
+                       disk_submit (disk_name, "disk_time",
+                                       (derive_t)(read_time*1000), (derive_t)(write_time*1000));
+               }
+       }
+       geom_stats_snapshot_free(snap);
+
 #elif KERNEL_LINUX
        FILE *fh;
        char buffer[1024];
-       
+
        char *fields[32];
        int numfields;
        int fieldshift = 0;
@@ -552,7 +681,6 @@ static int disk_read (void)
        {
                char *disk_name;
                char *output_name;
-               char *alt_name;
 
                numfields = strsplit (buffer, fields, 32);
 
@@ -712,13 +840,10 @@ static int disk_read (void)
                output_name = disk_name;
 
 #if HAVE_LIBUDEV
-               alt_name = disk_udev_attr_name (handle_udev, disk_name,
-                               conf_udev_name_attr);
-#else
-               alt_name = NULL;
-#endif
+               char *alt_name = disk_udev_attr_name (handle_udev, disk_name, conf_udev_name_attr);
                if (alt_name != NULL)
                        output_name = alt_name;
+#endif
 
                if ((ds->read_bytes != 0) || (ds->write_bytes != 0))
                        disk_submit (output_name, "disk_octets",
@@ -740,8 +865,10 @@ static int disk_read (void)
                        submit_io_time (output_name, io_time, weighted_time);
                } /* if (is_disk) */
 
+#if HAVE_LIBUDEV
                /* release udev-based alternate name, if allocated */
-               free(alt_name);
+               sfree (alt_name);
+#endif
        } /* while (fgets (buffer, sizeof (buffer), fh) != NULL) */
 
 #if HAVE_LIBUDEV
@@ -809,10 +936,10 @@ static int disk_read (void)
 #endif
        int counter;
        char name[DATA_MAX_NAME_LEN];
-       
+
        if ((ds = sg_get_disk_io_stats(&disks)) == NULL)
                return (0);
-               
+
        for (counter=0; counter < disks; counter++) {
                strncpy(name, ds->disk_name, sizeof(name));
                name[sizeof(name)-1] = '\0'; /* strncpy doesn't terminate longer strings */
@@ -832,7 +959,7 @@ static int disk_read (void)
        int rnumdisk;
        int i;
 
-       if ((numdisk = perfstat_disk(NULL, NULL, sizeof(perfstat_disk_t), 0)) < 0) 
+       if ((numdisk = perfstat_disk(NULL, NULL, sizeof(perfstat_disk_t), 0)) < 0)
        {
                char errbuf[1024];
                WARNING ("disk plugin: perfstat_disk: %s",
@@ -841,14 +968,14 @@ static int disk_read (void)
        }
 
        if (numdisk != pnumdisk || stat_disk==NULL) {
-               if (stat_disk!=NULL) 
+               if (stat_disk!=NULL)
                        free(stat_disk);
                stat_disk = (perfstat_disk_t *)calloc(numdisk, sizeof(perfstat_disk_t));
-       } 
+       }
        pnumdisk = numdisk;
 
        firstpath.name[0]='\0';
-       if ((rnumdisk = perfstat_disk(&firstpath, stat_disk, sizeof(perfstat_disk_t), numdisk)) < 0) 
+       if ((rnumdisk = perfstat_disk(&firstpath, stat_disk, sizeof(perfstat_disk_t), numdisk)) < 0)
        {
                char errbuf[1024];
                WARNING ("disk plugin: perfstat_disk : %s",
@@ -856,7 +983,7 @@ static int disk_read (void)
                return (-1);
        }
 
-       for (i = 0; i < rnumdisk; i++) 
+       for (i = 0; i < rnumdisk; i++)
        {
                read_sectors = stat_disk[i].rblks*stat_disk[i].bsize;
                write_sectors = stat_disk[i].wblks*stat_disk[i].bsize;