**/
#include "collectd.h"
+
#include "common.h"
#include "plugin.h"
typedef llist_t kstat_t;
-static long long get_zfs_value(kstat_t *zfs_stats __attribute__((unused)),
- char *name)
+static int put_zfs_value (kstat_t *ksp, char const *k, value_t v)
+{
+ llentry_t *e;
+ char *k_copy;
+ value_t *v_copy;
+
+ k_copy = strdup (k);
+ if (k_copy == NULL)
+ return ENOMEM;
+
+ v_copy = malloc (sizeof (*v_copy));
+ if (v_copy == NULL)
+ {
+ sfree (k_copy);
+ return ENOMEM;
+ }
+ *v_copy = v;
+
+ e = llentry_create (k_copy, v_copy);
+ if (e == NULL)
+ {
+ sfree (v_copy);
+ sfree (k_copy);
+ return ENOMEM;
+ }
+
+ llist_append (ksp, e);
+ return 0;
+}
+
+static long long get_zfs_value(kstat_t *ksp, const char *key)
{
llentry_t *e;
+ value_t *v;
- e = llist_search (zfs_stats, name);
+ e = llist_search (ksp, key);
if (e == NULL)
{
- ERROR ("zfs_arc plugin: `llist_search` failed for key: '%s'.", name);
+ ERROR ("zfs_arc plugin: `llist_search` failed for key: '%s'.", key);
return (-1);
}
- return ((long long int)e->value);
+ v = e->value;
+ return ((long long) v->derive);
}
-#elif !defined(__FreeBSD__) // Solaris
+static void free_zfs_values (kstat_t *ksp)
+{
+ if (ksp == NULL)
+ return;
+
+ for (llentry_t *e = llist_head (ksp); e != NULL; e = e->next)
+ {
+ sfree (e->key);
+ sfree (e->value);
+ }
+
+ llist_destroy (ksp);
+}
+
+#elif defined(KERNEL_SOLARIS)
extern kstat_ctl_t *kc;
static long long get_zfs_value(kstat_t *ksp, char *name)
return (get_kstat_value(ksp, name));
}
-#else // FreeBSD
+#elif defined(KERNEL_FREEBSD)
#include <sys/types.h>
#include <sys/sysctl.h>
value_t l2_io[2];
kstat_t *ksp = NULL;
-#if KERNEL_LINUX
- long long int *llvalues = NULL;
- char file_contents[1024 * 10];
- char *fields[3];
- int numfields;
- ssize_t len;
+#if defined(KERNEL_LINUX)
+ FILE *fh;
+ char buffer[1024];
+
+ fh = fopen (ZOL_ARCSTATS_FILE, "r");
+ if (fh == NULL)
+ {
+ char errbuf[1024];
+ ERROR ("zfs_arc plugin: Opening \"%s\" failed: %s", ZOL_ARCSTATS_FILE,
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ return (-1);
+ }
ksp = llist_create ();
if (ksp == NULL)
{
ERROR ("zfs_arc plugin: `llist_create' failed.");
+ fclose (fh);
return (-1);
}
- len = read_file_contents (ZOL_ARCSTATS_FILE, file_contents, sizeof(file_contents));
- if (len > 1)
+ while (fgets (buffer, sizeof (buffer), fh) != NULL)
{
+ char *fields[3];
+ value_t v;
+ int status;
- int i=0;
- char *pnl = file_contents;
- char *pnnl;
-
- file_contents[len] = '\0';
-
- while (pnl != NULL)
- {
- pnl = strchr(pnl, '\n');
- i++;
- if (pnl && (*pnl != '\0'))
- pnl++;
- }
-
- if (i > 0)
- {
- llentry_t *e;
- llvalues = malloc(sizeof(long long int) * i);
- i = 0;
-
- pnl = file_contents;
- while (pnl != NULL)
- {
- pnnl = strchr(pnl, '\n');
- if (pnnl != NULL)
- *pnnl = '\0';
-
- numfields = strsplit (pnl, fields, 4);
- if (numfields == 3)
- {
- llvalues[i] = atoll (fields[2]);
-
- e = llentry_create (fields[0], (void *)llvalues[i]);
- if (e == NULL)
- {
- ERROR ("zfs_arc plugin: `llentry_create' failed.");
- }
- else
- {
- llist_append (ksp, e);
- }
- }
- pnl = pnnl;
- if (pnl != NULL)
- pnl ++;
- }
- }
+ status = strsplit (buffer, fields, STATIC_ARRAY_SIZE (fields));
+ if (status != 3)
+ continue;
+
+ status = parse_value (fields[2], &v, DS_TYPE_DERIVE);
+ if (status != 0)
+ continue;
+
+ put_zfs_value (ksp, fields[0], v);
}
-#elif !defined(__FreeBSD__) // Solaris
+ fclose (fh);
+
+#elif defined(KERNEL_SOLARIS)
get_kstat (&ksp, "zfs", 0, "arcstats");
if (ksp == NULL)
{
#endif
/* Sizes */
- za_read_gauge (ksp, "size", "cache_size", "arc");
- za_read_gauge (ksp, "l2_size", "cache_size", "L2");
+ za_read_gauge (ksp, "anon_size", "cache_size", "anon_size");
+ za_read_gauge (ksp, "c", "cache_size", "c");
+ za_read_gauge (ksp, "c_max", "cache_size", "c_max");
+ za_read_gauge (ksp, "c_min", "cache_size", "c_min");
+ za_read_gauge (ksp, "hdr_size", "cache_size", "hdr_size");
+ za_read_gauge (ksp, "metadata_size", "cache_size", "metadata_size");
+ za_read_gauge (ksp, "mfu_ghost_size", "cache_size", "mfu_ghost_size");
+ za_read_gauge (ksp, "mfu_size", "cache_size", "mfu_size");
+ za_read_gauge (ksp, "mru_ghost_size", "cache_size", "mru_ghost_size");
+ za_read_gauge (ksp, "mru_size", "cache_size", "mru_size");
+ za_read_gauge (ksp, "other_size", "cache_size", "other_size");
+ za_read_gauge (ksp, "p", "cache_size", "p");
+ za_read_gauge (ksp, "size", "cache_size", "arc");
+
+ /* The "l2_size" value has disappeared from Solaris some time in
+ * early 2013, and has only reappeared recently in Solaris 11.2.
+ * Stop trying if we ever fail to read it, so we don't spam the log.
+ */
+ static int l2_size_avail = 1;
+ if (l2_size_avail && za_read_gauge (ksp, "l2_size", "cache_size", "L2") != 0)
+ l2_size_avail = 0;
/* Operations */
za_read_derive (ksp, "deleted", "cache_operation", "deleted");
-#if __FreeBSD__
+#if defined(KERNEL_FREEBSD)
za_read_derive (ksp, "allocated","cache_operation", "allocated");
- za_read_derive (ksp, "stolen", "cache_operation", "stolen");
#endif
/* Issue indicators */
za_read_derive (ksp, "mutex_miss", "mutex_operations", "miss");
za_read_derive (ksp, "hash_collisions", "hash_collisions", "");
+ za_read_derive (ksp, "memory_throttle_count", "memory_throttle_count", "");
/* Evictions */
za_read_derive (ksp, "evict_l2_cached", "cache_eviction", "cached");
za_read_derive (ksp, "demand_metadata_misses", "cache_result", "demand_metadata-miss");
za_read_derive (ksp, "prefetch_data_misses", "cache_result", "prefetch_data-miss");
za_read_derive (ksp, "prefetch_metadata_misses", "cache_result", "prefetch_metadata-miss");
+ za_read_derive (ksp, "mfu_hits", "cache_result", "mfu-hit");
+ za_read_derive (ksp, "mfu_ghost_hits", "cache_result", "mfu_ghost-hit");
+ za_read_derive (ksp, "mru_hits", "cache_result", "mru-hit");
+ za_read_derive (ksp, "mru_ghost_hits", "cache_result", "mru_ghost-hit");
+ za_read_derive (ksp, "prefetch_metadata_misses", "cache_result", "prefetch_metadata-miss");
/* Ratios */
arc_hits = (gauge_t) get_zfs_value(ksp, "hits");
za_submit ("io_octets", "L2", l2_io, /* num values = */ 2);
#if defined(KERNEL_LINUX)
- if (llvalues != NULL)
- {
- free(llvalues);
- }
- if (ksp != NULL)
- {
- llist_destroy (ksp);
- }
+ free_zfs_values (ksp);
#endif
return (0);
static int za_init (void) /* {{{ */
{
-#if !defined(__FreeBSD__) && !defined(KERNEL_LINUX) // Solaris
+#if defined(KERNEL_SOLARIS)
/* kstats chain already opened by update_kstat (using *kc), verify everything went fine. */
if (kc == NULL)
{