summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlasdair G Kergon <agk@redhat.com>2017-03-08 14:57:35 +0000
committerAlasdair G Kergon <agk@redhat.com>2017-03-08 14:57:35 +0000
commit60e50072e5d2be8542beab336638af7f90194a7f (patch)
tree60c34feb29f2d956865db46b94d61a2af1139261
parent3a5561e5ab5c916df8f90cc880ce2acb04ee2ecb (diff)
downloadlvm2-dev-agk-fs-reporting.tar.gz
report: Demo mount/fs fields a bit like df.dev-agk-fs-reporting
./lvm pvs -a -opv_name,fs_size,fs_used,fs_free,mount_all -S 'fs_size>0' --units k ./lvm pvs -a -opv_name,fs_size,fs_used,fs_free,fs_avail,mount_all -S 'fs_size>0' --units b --reportformat json --nosuffix
-rw-r--r--lib/report/columns.h22
-rw-r--r--lib/report/properties.c10
-rw-r--r--lib/report/report.c30
-rw-r--r--lib/report/report.h18
-rw-r--r--tools/reporter.c137
5 files changed, 199 insertions, 18 deletions
diff --git a/lib/report/columns.h b/lib/report/columns.h
index 74078f54c..e594611d7 100644
--- a/lib/report/columns.h
+++ b/lib/report/columns.h
@@ -283,4 +283,26 @@ FIELD(PVSEGS, pvseg, NUM, "SSize", len, 0, uint32, pvseg_size, "Number of extent
/*
* End of PVSEGS type fields
*/
+
+/*
+ * MOUNTINFO type fields
+ */
+FIELD(MOUNTINFO, mountinfo, STR, "Mounted on", mountpoint, 0, string, mount_point, "Mount point of filesystem on device.", 0)
+/*
+ * End of MOUNTINFO type fields
+ */
+
+
+/*
+ * FSINFO type fields
+ */
+FIELD(FSINFO, fsinfo, SIZ, "FSUsed", fs_used, 0, size64, fs_used, "Space used in mounted filesystem on device.", 0)
+FIELD(FSINFO, fsinfo, SIZ, "FSSize", fs_size, 0, size64, fs_size, "Size of mounted filesystem on device.", 0)
+FIELD(FSINFO, fsinfo, SIZ, "FSFree", fs_free, 0, size64, fs_free, "Free space in mounted filesystem on device.", 0)
+FIELD(FSINFO, fsinfo, SIZ, "FSAvail", fs_avail, 0, size64, fs_avail, "Available space in mounted filesystem on device.", 0)
+/*
+ * End of FSINFO type fields
+ */
+
+
/* *INDENT-ON* */
diff --git a/lib/report/properties.c b/lib/report/properties.c
index 04f2cef24..92a1c1ad0 100644
--- a/lib/report/properties.c
+++ b/lib/report/properties.c
@@ -520,6 +520,16 @@ GET_PVSEG_NUM_PROPERTY_FN(pvseg_start, pvseg->pe)
GET_PVSEG_NUM_PROPERTY_FN(pvseg_size, (SECTOR_SIZE * pvseg->len))
#define _pvseg_size_set prop_not_implemented_set
+#define _mount_point_get prop_not_implemented_get
+#define _mount_point_set prop_not_implemented_set
+#define _fs_used_get prop_not_implemented_get
+#define _fs_used_set prop_not_implemented_set
+#define _fs_size_get prop_not_implemented_get
+#define _fs_size_set prop_not_implemented_set
+#define _fs_free_get prop_not_implemented_get
+#define _fs_free_set prop_not_implemented_set
+#define _fs_avail_get prop_not_implemented_get
+#define _fs_avail_set prop_not_implemented_set
struct lvm_property_type _properties[] = {
#include "columns.h"
diff --git a/lib/report/report.c b/lib/report/report.c
index 4204d479b..781d03a51 100644
--- a/lib/report/report.c
+++ b/lib/report/report.c
@@ -36,6 +36,8 @@ struct lvm_report_object {
struct lv_segment *seg;
struct pv_segment *pvseg;
struct label *label;
+ struct lvm_mountinfo *mountinfo;
+ struct lvm_fsinfo *fsinfo;
};
static uint32_t log_seqnum = 1;
@@ -3791,6 +3793,13 @@ static struct volume_group _unknown_vg = {
.tags = DM_LIST_HEAD_INIT(_unknown_vg.tags),
};
+static struct lvm_mountinfo _unknown_mountinfo = {
+ .mountpoint = ""
+};
+
+static struct lvm_fsinfo _unknown_fsinfo = {
+};
+
static void *_obj_get_vg(void *obj)
{
struct volume_group *vg = ((struct lvm_report_object *)obj)->vg;
@@ -3828,6 +3837,16 @@ static void *_obj_get_pvseg(void *obj)
return ((struct lvm_report_object *)obj)->pvseg;
}
+static void *_obj_get_mountinfo(void *obj)
+{
+ return ((struct lvm_report_object *)obj)->mountinfo;
+}
+
+static void *_obj_get_fsinfo(void *obj)
+{
+ return ((struct lvm_report_object *)obj)->fsinfo;
+}
+
static void *_obj_get_devtypes(void *obj)
{
return obj;
@@ -3853,6 +3872,8 @@ static const struct dm_report_object_type _report_types[] = {
{ LABEL, "Physical Volume Label", "pv_", _obj_get_label },
{ SEGS, "Logical Volume Segment", "seg_", _obj_get_seg },
{ PVSEGS, "Physical Volume Segment", "pvseg_", _obj_get_pvseg },
+ { MOUNTINFO, "Mount Point", "mount_", _obj_get_mountinfo },
+ { FSINFO, "Filesystem", "fs_", _obj_get_fsinfo },
{ 0, "", "", NULL },
};
@@ -3885,6 +3906,8 @@ typedef struct volume_group type_vg;
typedef struct lv_segment type_seg;
typedef struct pv_segment type_pvseg;
typedef struct label type_label;
+typedef struct lvm_mountinfo type_mountinfo;
+typedef struct lvm_fsinfo type_fsinfo;
typedef dev_known_type_t type_devtype;
@@ -4012,7 +4035,8 @@ int report_object(void *handle, int selection_only, const struct volume_group *v
const struct logical_volume *lv, const struct physical_volume *pv,
const struct lv_segment *seg, const struct pv_segment *pvseg,
const struct lv_with_info_and_seg_status *lvdm,
- const struct label *label)
+ const struct label *label,
+ const struct lvm_mountinfo *mountinfo, const struct lvm_fsinfo *fsinfo)
{
struct selection_handle *sh = selection_only ? (struct selection_handle *) handle : NULL;
struct device dummy_device = { .dev = 0 };
@@ -4023,7 +4047,9 @@ int report_object(void *handle, int selection_only, const struct volume_group *v
.pv = (struct physical_volume *) pv,
.seg = (struct lv_segment *) seg,
.pvseg = (struct pv_segment *) pvseg,
- .label = (struct label *) (label ? : (pv ? pv_label(pv) : NULL))
+ .label = (struct label *) (label ? : (pv ? pv_label(pv) : NULL)),
+ .mountinfo = (struct lvm_mountinfo *) mountinfo ? : &_unknown_mountinfo,
+ .fsinfo = (struct lvm_fsinfo *) fsinfo ? : &_unknown_fsinfo,
};
/* FIXME workaround for pv_label going through cache; remove once struct
diff --git a/lib/report/report.h b/lib/report/report.h
index c787f56ce..95f182bce 100644
--- a/lib/report/report.h
+++ b/lib/report/report.h
@@ -32,9 +32,22 @@ typedef enum {
SEGS = 256,
PVSEGS = 512,
LABEL = 1024,
- DEVTYPES = 2048
+ DEVTYPES = 2048,
+ MOUNTINFO = 4096,
+ FSINFO = 8192
} report_type_t;
+struct lvm_mountinfo {
+ const char *mountpoint;
+};
+
+struct lvm_fsinfo {
+ uint64_t fs_used;
+ uint64_t fs_size;
+ uint64_t fs_free;
+ uint64_t fs_avail;
+};
+
/*
* The "struct selection_handle" is used only for selection
* of items that should be processed further (not for display!).
@@ -104,7 +117,8 @@ int report_object(void *handle, int selection_only, const struct volume_group *v
const struct logical_volume *lv, const struct physical_volume *pv,
const struct lv_segment *seg, const struct pv_segment *pvseg,
const struct lv_with_info_and_seg_status *lvdm,
- const struct label *label);
+ const struct label *label,
+ const struct lvm_mountinfo *mountinfo, const struct lvm_fsinfo *fsinfo);
int report_devtypes(void *handle);
int report_cmdlog(void *handle, const char *type, const char *context,
const char *object_type_name, const char *object_name,
diff --git a/tools/reporter.c b/tools/reporter.c
index 980f39c7c..41af8c876 100644
--- a/tools/reporter.c
+++ b/tools/reporter.c
@@ -17,6 +17,8 @@
#include "report.h"
+#include <sys/vfs.h>
+
typedef enum {
REPORT_IDX_NULL = -1,
REPORT_IDX_SINGLE,
@@ -79,7 +81,7 @@ static int _vgs_single(struct cmd_context *cmd __attribute__((unused)),
struct selection_handle *sh = handle->selection_handle;
if (!report_object(sh ? : handle->custom_handle, sh != NULL,
- vg, NULL, NULL, NULL, NULL, NULL, NULL))
+ vg, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL))
return_ECMD_FAILED;
check_current_backup(vg);
@@ -177,7 +179,7 @@ static int _do_lvs_with_info_and_status_single(struct cmd_context *cmd,
}
if (!report_object(sh ? : handle->custom_handle, sh != NULL,
- lv->vg, lv, NULL, NULL, NULL, &status, NULL))
+ lv->vg, lv, NULL, NULL, NULL, &status, NULL, NULL, NULL))
goto out;
r = ECMD_PROCESSED;
@@ -239,7 +241,7 @@ static int _do_segs_with_info_and_status_single(struct cmd_context *cmd,
}
if (!report_object(sh ? : handle->custom_handle, sh != NULL,
- seg->lv->vg, seg->lv, NULL, seg, NULL, &status, NULL))
+ seg->lv->vg, seg->lv, NULL, seg, NULL, &status, NULL, NULL, NULL))
goto_out;
r = ECMD_PROCESSED;
@@ -367,7 +369,7 @@ static int _do_pvsegs_sub_single(struct cmd_context *cmd,
if (!report_object(sh ? : handle->custom_handle, sh != NULL,
vg, seg ? seg->lv : &_free_logical_volume,
pvseg->pv, seg ? : &_free_lv_segment, pvseg,
- &status, pv_label(pvseg->pv))) {
+ &status, pv_label(pvseg->pv), NULL, NULL)) {
ret = ECMD_FAILED;
goto_out;
}
@@ -443,26 +445,110 @@ static int _pvsegs_with_lv_info_and_status_single(struct cmd_context *cmd,
return process_each_segment_in_pv(cmd, vg, pv, handle, _pvsegs_with_lv_info_and_status_sub_single);
}
-static int _pvs_single(struct cmd_context *cmd, struct volume_group *vg,
- struct physical_volume *pv,
- struct processing_handle *handle)
+struct mountinfo_s { // FIXME
+ unsigned maj; //FIXME
+ unsigned min; //FIXME
+ const char *mountpoint;
+};
+
+static int _get_mountpoint(char *buffer, unsigned major, unsigned minor,
+ char *target, void *cb_data)
+{
+ struct mountinfo_s *data = cb_data;
+
+ if ((major == data->maj) && (minor == data->min))
+ data->mountpoint = dm_strdup(target); // FIXME error/pool
+
+ return 1;
+}
+
+static int _populate_mount_info(struct physical_volume *pv, struct lvm_mountinfo *mountinfo)
+{
+ struct mountinfo_s data = {
+ .maj = MAJOR(pv->dev->dev),
+ .min = MINOR(pv->dev->dev),
+ };
+
+ if (!dm_mountinfo_read(_get_mountpoint, &data))
+ return 0;
+
+ if (data.mountpoint)
+ mountinfo->mountpoint = data.mountpoint;
+ else
+ mountinfo->mountpoint = "";
+
+ return 1;
+}
+
+static int _populate_fs_info(const char *mountpoint, struct lvm_fsinfo *fsinfo)
+{
+ struct statfs buf;
+
+ if (statfs(mountpoint, &buf)) {
+ log_sys_error("statfs", mountpoint);
+ return 0;
+ }
+
+ fsinfo->fs_size = (buf.f_blocks * buf.f_bsize) >> SECTOR_SHIFT;
+ fsinfo->fs_free = (buf.f_bfree * buf.f_bsize) >> SECTOR_SHIFT;
+ fsinfo->fs_avail = (buf.f_bavail * buf.f_bsize) >> SECTOR_SHIFT;
+ fsinfo->fs_used = ((buf.f_blocks - buf.f_bfree) * buf.f_bsize) >> SECTOR_SHIFT;
+
+ return 1;
+}
+
+static int _do_pvs_with_mount_and_fs_info_single(struct cmd_context *cmd, struct volume_group *vg,
+ struct physical_volume *pv,
+ struct processing_handle *handle,
+ int do_mount_info, int do_fs_info)
{
struct selection_handle *sh = handle->selection_handle;
+ struct lvm_mountinfo mountinfo;
+ struct lvm_fsinfo fsinfo;
+
+ if (do_mount_info)
+ if (!_populate_mount_info(pv, &mountinfo))
+ return_0;
+
+ if (do_fs_info && *mountinfo.mountpoint)
+ if (!_populate_fs_info(mountinfo.mountpoint, &fsinfo))
+ return_0;
if (!report_object(sh ? : handle->custom_handle, sh != NULL,
- vg, NULL, pv, NULL, NULL, NULL, NULL))
+ vg, NULL, pv, NULL, NULL, NULL, NULL, do_mount_info ? &mountinfo : NULL, do_fs_info && *mountinfo.mountpoint ? &fsinfo : NULL))
return_ECMD_FAILED;
return ECMD_PROCESSED;
}
+static int _pvs_single(struct cmd_context *cmd, struct volume_group *vg,
+ struct physical_volume *pv,
+ struct processing_handle *handle)
+{
+ return _do_pvs_with_mount_and_fs_info_single(cmd, vg, pv, handle, 0, 0);
+}
+
+static int _pvs_with_mount_info_single(struct cmd_context *cmd, struct volume_group *vg,
+ struct physical_volume *pv,
+ struct processing_handle *handle)
+{
+ return _do_pvs_with_mount_and_fs_info_single(cmd, vg, pv, handle, 1, 0);
+}
+
+static int _pvs_with_fs_info_single(struct cmd_context *cmd, struct volume_group *vg,
+ struct physical_volume *pv,
+ struct processing_handle *handle)
+{
+ return _do_pvs_with_mount_and_fs_info_single(cmd, vg, pv, handle, 1, 1);
+}
+
static int _label_single(struct cmd_context *cmd, struct label *label,
struct processing_handle *handle)
{
struct selection_handle *sh = handle->selection_handle;
if (!report_object(sh ? : handle->custom_handle, sh != NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, label))
+ NULL, NULL, NULL, NULL, NULL, NULL, label, NULL, NULL))
return_ECMD_FAILED;
return ECMD_PROCESSED;
@@ -487,6 +573,8 @@ static int _get_final_report_type(struct report_args *args,
report_type_t report_type,
int *lv_info_needed,
int *lv_segment_status_needed,
+ int *mountinfo_needed,
+ int *fsinfo_needed,
report_type_t *final_report_type)
{
/* Do we need to acquire LV device info in addition? */
@@ -498,8 +586,16 @@ static int _get_final_report_type(struct report_args *args,
/* Ensure options selected are compatible */
if (report_type & SEGS)
report_type |= LVS;
+
if (report_type & PVSEGS)
report_type |= PVS;
+
+ if (report_type & FSINFO)
+ report_type |= MOUNTINFO;
+
+ if (report_type & MOUNTINFO)
+ report_type |= PVS; // FIXME Temporarily drive fs and mount from pvs
+
if ((report_type & (LVS | LVSINFO | LVSSTATUS | LVSINFOSTATUS)) &&
(report_type & (PVS | LABEL)) && !(single_args->args_are_pvs || (args->full_report_vg && single_args->report_type == PVSEGS))) {
log_error("Can't report LV and PV fields at the same time in %sreport type \"%s\"%s%s.",
@@ -509,6 +605,12 @@ static int _get_final_report_type(struct report_args *args,
return 0;
}
+ /* Do we need to acquire mount point information? */
+ *mountinfo_needed = (report_type & MOUNTINFO) ? 1 : 0;
+
+ /* Do we need to acquire mounted filesystem information? */
+ *fsinfo_needed = (report_type & FSINFO) ? 1 : 0;
+
/* Change report type if fields specified makes this necessary */
if (report_type & FULL)
report_type = FULL;
@@ -603,7 +705,7 @@ static int _report_all_in_lv(struct cmd_context *cmd, struct processing_handle *
static int _report_all_in_pv(struct cmd_context *cmd, struct processing_handle *handle,
struct physical_volume *pv, report_type_t type,
- int do_lv_info, int do_lv_seg_status)
+ int do_lv_info, int do_lv_seg_status, int do_mount_info, int do_fs_info)
{
int r = 0;
@@ -635,7 +737,7 @@ int report_for_selection(struct cmd_context *cmd,
struct selection_handle *sh = parent_handle->selection_handle;
struct report_args args = {0};
struct single_report_args *single_args = &args.single_args[REPORT_IDX_SINGLE];
- int do_lv_info, do_lv_seg_status;
+ int do_lv_info, do_lv_seg_status, do_mount_info, do_fs_info;
struct processing_handle *handle;
int r = 0;
@@ -645,6 +747,7 @@ int report_for_selection(struct cmd_context *cmd,
if (!_get_final_report_type(&args, single_args,
single_args->report_type,
&do_lv_info, &do_lv_seg_status,
+ &do_mount_info, &do_fs_info,
&sh->report_type))
return_0;
@@ -688,7 +791,7 @@ int report_for_selection(struct cmd_context *cmd,
r = _report_all_in_vg(cmd, handle, vg, sh->report_type, do_lv_info, do_lv_seg_status);
break;
case PVS:
- r = _report_all_in_pv(cmd, handle, pv, sh->report_type, do_lv_info, do_lv_seg_status);
+ r = _report_all_in_pv(cmd, handle, pv, sh->report_type, do_lv_info, do_lv_seg_status, do_mount_info, do_fs_info);
break;
default:
log_error(INTERNAL_ERROR "report_for_selection: incorrect report type");
@@ -1079,6 +1182,7 @@ static int _do_report(struct cmd_context *cmd, struct processing_handle *handle,
int lock_global = 0;
int lv_info_needed;
int lv_segment_status_needed;
+ int do_mount_info, do_fs_info;
int report_in_group = 0;
int r = ECMD_FAILED;
@@ -1091,7 +1195,9 @@ static int _do_report(struct cmd_context *cmd, struct processing_handle *handle,
handle->custom_handle = report_handle;
if (!_get_final_report_type(args, single_args, report_type, &lv_info_needed,
- &lv_segment_status_needed, &report_type))
+ &lv_segment_status_needed,
+ &do_mount_info, &do_fs_info,
+ &report_type))
goto_out;
if (!(args->log_only && (single_args->report_type != CMDLOG))) {
@@ -1151,7 +1257,10 @@ static int _do_report(struct cmd_context *cmd, struct processing_handle *handle,
if (single_args->args_are_pvs)
r = process_each_pv(cmd, args->argc, args->argv, NULL,
arg_is_set(cmd, all_ARG), 0,
- handle, &_pvs_single);
+ handle,
+ do_fs_info ? &_pvs_with_fs_info_single :
+ do_mount_info ? &_pvs_with_mount_info_single :
+ &_pvs_single);
else
r = process_each_vg(cmd, args->argc, args->argv, NULL, NULL,
0, 0, handle, &_pvs_in_vg);