/**
* collectd - src/lvm.c
* Copyright (C) 2013 Chad Malfait
+ * Copyright (C) 2014 Carnegie Mellon University
*
* 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
*
* Authors:
* Chad Malfait <malfaitc at yahoo.com>
+ * Benjamin Gilbert <bgilbert at cs.cmu.edu>
**/
#include <lvm2app.h>
#include "common.h"
#include "plugin.h"
+#define NO_VALUE UINT64_MAX
+#define PERCENT_SCALE_FACTOR 1e-8
+
+static uint64_t get_lv_property_int(lv_t lv, char const *property)
+{
+ lvm_property_value_t v;
+
+ v = lvm_lv_get_property(lv, property);
+ if (!v.is_valid || !v.is_integer)
+ return NO_VALUE;
+ /* May be NO_VALUE if @property does not apply to this LV */
+ return v.value.integer;
+}
+
+static char const *get_lv_property_string(lv_t lv, char const *property)
+{
+ lvm_property_value_t v;
+
+ v = lvm_lv_get_property(lv, property);
+ if (!v.is_valid || !v.is_string)
+ return NULL;
+ return v.value.string;
+}
+
static void lvm_submit (char const *plugin_instance, char const *type_instance,
uint64_t ivalue)
{
plugin_dispatch_values (&vl);
}
+static void report_lv_utilization(lv_t lv, char const *vg_name,
+ char const *lv_name, uint64_t lv_size,
+ char const *used_percent_property)
+{
+ uint64_t used_percent_unscaled;
+ uint64_t used_bytes;
+ char plugin_instance[DATA_MAX_NAME_LEN];
+
+ used_percent_unscaled = get_lv_property_int(lv, used_percent_property);
+ if (used_percent_unscaled == NO_VALUE)
+ return;
+ used_bytes = lv_size * (used_percent_unscaled * PERCENT_SCALE_FACTOR);
+
+ ssnprintf(plugin_instance, sizeof(plugin_instance), "%s-%s",
+ vg_name, lv_name);
+ lvm_submit(plugin_instance, "used", used_bytes);
+ lvm_submit(plugin_instance, "free", lv_size - used_bytes);
+}
+
+static void report_thin_pool_utilization(lv_t lv, char const *vg_name,
+ uint64_t lv_size)
+{
+ char const *data_lv;
+ char const *metadata_lv;
+ uint64_t metadata_size;
+
+ data_lv = get_lv_property_string(lv, "data_lv");
+ metadata_lv = get_lv_property_string(lv, "metadata_lv");
+ metadata_size = get_lv_property_int(lv, "lv_metadata_size");
+ if (data_lv == NULL || metadata_lv == NULL || metadata_size == NO_VALUE)
+ return;
+
+ report_lv_utilization(lv, vg_name, data_lv, lv_size, "data_percent");
+ report_lv_utilization(lv, vg_name, metadata_lv, metadata_size,
+ "metadata_percent");
+}
+
static void vg_read(vg_t vg, char const *vg_name)
{
struct dm_list *lvs;
struct lvm_lv_list *lvl;
+ char const *name;
char const *attrs;
+ uint64_t size;
lvm_submit (vg_name, "free", lvm_vg_get_free_size(vg));
lvs = lvm_vg_list_lvs(vg);
dm_list_iterate_items(lvl, lvs) {
+ name = lvm_lv_get_name(lvl->lv);
attrs = lvm_lv_get_attr(lvl->lv);
- if (attrs == NULL)
+ size = lvm_lv_get_size(lvl->lv);
+ if (name == NULL || attrs == NULL || size == NO_VALUE)
continue;
+
/* Condition on volume type. We want the reported sizes in the
volume group to sum to the size of the volume group, so we ignore
virtual volumes. */
switch (attrs[0]) {
+ case 's':
+ case 'S':
+ /* Snapshot. Also report used/free space. */
+ report_lv_utilization(lvl->lv, vg_name, name, size,
+ "data_percent");
+ break;
case 't':
/* Thin pool virtual volume. We report the underlying data
- and metadata volumes, not this one. Ignore. */
+ and metadata volumes, not this one. Report used/free
+ space, then ignore. */
+ report_thin_pool_utilization(lvl->lv, vg_name, size);
continue;
case 'v':
/* Virtual volume. Ignore. */
/* Thin volume or thin snapshot. Ignore. */
continue;
}
- lvm_submit(vg_name, lvm_lv_get_name(lvl->lv), lvm_lv_get_size(lvl->lv));
+ lvm_submit(vg_name, name, size);
}
}