From eaab2f514f08b9a9b4815df4b5e852c7caaa8ff9 Mon Sep 17 00:00:00 2001 From: Benjamin Gilbert Date: Wed, 16 Apr 2014 15:00:11 -0400 Subject: [PATCH] lvm: Report used/free space for thin pools and thick snapshots Thin pools and traditional snapshot volumes fill up as I/O is performed to their associated thin volumes or origins. When they run out of free space, things break, so it's useful to monitor their disk utilization. Add new plugin instances for thin pool data LVs, thin pool metadata LVs, and thick snapshot LVs, each with "used" and "free" type instances. --- AUTHORS | 3 +++ src/lvm.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 82 insertions(+), 3 deletions(-) diff --git a/AUTHORS b/AUTHORS index 31d132fb..fa55cc0e 100644 --- a/AUTHORS +++ b/AUTHORS @@ -47,6 +47,9 @@ Aurélien Reynaud - LPAR plugin. - Various fixes for AIX, HP-UX and Solaris. +Benjamin Gilbert + - Improvements to the LVM plugin. + Bert Vermeulen - sigrok plugin diff --git a/src/lvm.c b/src/lvm.c index 1677f056..97d80170 100644 --- a/src/lvm.c +++ b/src/lvm.c @@ -1,6 +1,7 @@ /** * 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 @@ -17,6 +18,7 @@ * * Authors: * Chad Malfait + * Benjamin Gilbert **/ #include @@ -25,6 +27,30 @@ #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) { @@ -45,26 +71,76 @@ static void lvm_submit (char const *plugin_instance, char const *type_instance, 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. */ @@ -73,7 +149,7 @@ static void vg_read(vg_t vg, char const *vg_name) /* 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); } } -- 2.11.0