* Copyright (C) 2012 Aurelien Rougemont
* Copyright (C) 2013 Xin Li
* Copyright (C) 2014 Marc Fournier
+ * Copyright (C) 2014 Wilfried Goesgens
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Aurelien Rougemont <beorn at gandi.net>
* Xin Li <delphij at FreeBSD.org>
* Marc Fournier <marc.fournier at camptocamp.com>
+ * Wilfried Goesgens <dothebart at citadel.org>
**/
#include "collectd.h"
#include "utils_llist.h"
#define ZOL_ARCSTATS_FILE "/proc/spl/kstat/zfs/arcstats"
-#if !defined(kstat_t)
-typedef void kstat_t;
-static llist_t *zfs_stats = NULL;
-#endif
+typedef llist_t kstat_t;
-static long long get_zfs_value(kstat_t *dummy __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;
- e = llist_search (zfs_stats, name);
+ 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)
{
- ERROR ("zfs_arc plugin: `llist_search` failed for key: '%s'.", name);
+ sfree (v_copy);
+ sfree (k_copy);
+ return ENOMEM;
+ }
+
+ llist_append (ksp, e);
+ return 0;
+}
+
+static long long get_zfs_value(kstat_t *ksp, char *key)
+{
+ llentry_t *e;
+ value_t *v;
+
+ e = llist_search (ksp, key);
+ if (e == NULL)
+ {
+ 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);
+}
+
+static void free_zfs_values (kstat_t *ksp)
+{
+ llentry_t *e;
+
+ if (ksp == NULL)
+ return;
+
+ for (e = llist_head (ksp); e != NULL; e = e->next)
+ {
+ sfree (e->key);
+ sfree (e->value);
+ }
+
+ llist_destroy (ksp);
}
#elif !defined(__FreeBSD__) // Solaris
#if KERNEL_LINUX
FILE *fh;
+ char buffer[1024];
- char buf[1024];
- char *fields[3];
- int numfields;
-
- if ((fh = fopen (ZOL_ARCSTATS_FILE, "r")) == NULL)
+ fh = fopen (ZOL_ARCSTATS_FILE, "r");
+ if (fh == NULL)
{
char errbuf[1024];
- ERROR ("zfs_arc plugin: `fopen (%s)' failed: %s",
- ZOL_ARCSTATS_FILE,
- sstrerror (errno, errbuf, sizeof (errbuf)));
+ ERROR ("zfs_arc plugin: Opening \"%s\" failed: %s", ZOL_ARCSTATS_FILE,
+ sstrerror (errno, errbuf, sizeof (errbuf)));
return (-1);
}
- zfs_stats = llist_create ();
- if (zfs_stats == NULL)
+ ksp = llist_create ();
+ if (ksp == NULL)
{
ERROR ("zfs_arc plugin: `llist_create' failed.");
fclose (fh);
return (-1);
}
- while (fgets (buf, 1024, fh) != NULL)
+ while (fgets (buffer, sizeof (buffer), fh) != NULL)
{
- numfields = strsplit (buf, fields, 4);
- if (numfields != 3)
- continue;
-
- char *llkey;
- long long int llvalue;
+ char *fields[3];
+ value_t v;
+ int status;
- llkey = strdup (fields[0]);
- if (llkey == NULL) {
- char errbuf[1024];
- ERROR ("zfs_arc plugin: `strdup' failed: %s",
- sstrerror (errno, errbuf, sizeof (errbuf)));
+ status = strsplit (buffer, fields, STATIC_ARRAY_SIZE (fields));
+ if (status != 3)
continue;
- }
-
- llvalue = atoll (fields[2]);
- llentry_t *e;
- e = llentry_create (llkey, (void *)llvalue);
- if (e == NULL)
- {
- ERROR ("zfs_arc plugin: `llentry_create' failed.");
- free (llkey);
+ status = parse_value (fields[2], &v, DS_TYPE_DERIVE);
+ if (status != 0)
continue;
- }
- free (llkey);
-
- llist_append (zfs_stats, e);
+ put_zfs_value (ksp, fields[0], v);
}
- if (fclose (fh))
- {
- char errbuf[1024];
- WARNING ("zfs_arc: `fclose' failed: %s", sstrerror (errno, errbuf, sizeof (errbuf)));
- }
+ fclose (fh);
#elif !defined(__FreeBSD__) // Solaris
get_kstat (&ksp, "zfs", 0, "arcstats");
/* Sizes */
za_read_gauge (ksp, "size", "cache_size", "arc");
- za_read_gauge (ksp, "l2_size", "cache_size", "L2");
+ za_read_gauge (ksp, "c", "cache_size", "c");
+ za_read_gauge (ksp, "c_min", "cache_size", "c_min");
+ za_read_gauge (ksp, "c_max", "cache_size", "c_max");
+
+ /* 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");
za_submit ("io_octets", "L2", l2_io, /* num values = */ 2);
#if defined(KERNEL_LINUX)
- if (zfs_stats != NULL)
- {
- llist_destroy (zfs_stats);
- }
+ free_zfs_values (ksp);
#endif
return (0);