From 60e50072e5d2be8542beab336638af7f90194a7f Mon Sep 17 00:00:00 2001 From: Alasdair G Kergon Date: Wed, 8 Mar 2017 14:57:35 +0000 Subject: report: Demo mount/fs fields a bit like df. ./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 --- lib/report/columns.h | 22 ++++++++ lib/report/properties.c | 10 ++++ lib/report/report.c | 30 ++++++++++- lib/report/report.h | 18 ++++++- tools/reporter.c | 137 +++++++++++++++++++++++++++++++++++++++++++----- 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 + 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); -- cgit v1.2.1