diff options
Diffstat (limited to 'lib/report')
-rw-r--r-- | lib/report/columns-cmdlog.h | 40 | ||||
-rw-r--r-- | lib/report/columns-devtypes.h | 32 | ||||
-rw-r--r-- | lib/report/columns.h | 418 | ||||
-rw-r--r-- | lib/report/properties.c | 775 | ||||
-rw-r--r-- | lib/report/properties.h | 26 | ||||
-rw-r--r-- | lib/report/report.c | 4257 | ||||
-rw-r--r-- | lib/report/report.h | 99 | ||||
-rw-r--r-- | lib/report/values.h | 139 |
8 files changed, 4960 insertions, 826 deletions
diff --git a/lib/report/columns-cmdlog.h b/lib/report/columns-cmdlog.h new file mode 100644 index 0000000..3dd7df5 --- /dev/null +++ b/lib/report/columns-cmdlog.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2016 Red Hat, Inc. All rights reserved. + * + * This file is part of LVM2. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU Lesser General Public License v.2.1. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * This file defines the fields (columns) for the command log reporting. + * + * The preferred order of the field descriptions in the help text + * determines the order the entries appear in this file. + * + * When adding new entries take care to use the existing style. + * Displayed fields names normally have a type prefix and use underscores. + * Field-specific internal functions names normally match the displayed + * field names but without underscores. + * Help text ends with a full stop. + */ + +/* *INDENT-OFF* */ +FIELD(CMDLOG, cmd_log_item, NUM, "Seq", seq_num, 3, uint32, log_seq_num, "Log sequence number.", 0) +FIELD(CMDLOG, cmd_log_item, STR, "LogType", type, 7, string, log_type, "Log type.", 0) +FIELD(CMDLOG, cmd_log_item, STR, "Context", context, 7, string, log_context, "Current context.", 0) +FIELD(CMDLOG, cmd_log_item, STR, "ObjType", object_type_name, 7, string, log_object_type, "Current object type.", 0) +FIELD(CMDLOG, cmd_log_item, STR, "ObjName", object_name, 7, string, log_object_name, "Current object name.", 0) +FIELD(CMDLOG, cmd_log_item, STR, "ObjID", object_id, 7, string, log_object_id, "Current object ID.", 0) +FIELD(CMDLOG, cmd_log_item, STR, "ObjGrp", object_group, 7, string, log_object_group, "Current object group.", 0) +FIELD(CMDLOG, cmd_log_item, STR, "ObjGrpID", object_group_id, 8, string, log_object_group_id, "Current object group ID.", 0) +FIELD(CMDLOG, cmd_log_item, STR, "Msg", msg, 7, string, log_message, "Log message.", 0) +FIELD(CMDLOG, cmd_log_item, SNUM, "Errno", current_errno, 5, int32, log_errno, "Errno.", 0) +FIELD(CMDLOG, cmd_log_item, SNUM, "RetCode", ret_code, 7, int32, log_ret_code, "Return code.", 0) +/* *INDENT-ON* */ diff --git a/lib/report/columns-devtypes.h b/lib/report/columns-devtypes.h new file mode 100644 index 0000000..59f4665 --- /dev/null +++ b/lib/report/columns-devtypes.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2013 Red Hat, Inc. All rights reserved. + * + * This file is part of LVM2. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU Lesser General Public License v.2.1. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * This file defines the fields (columns) for the devtypes reporting command. + * + * The preferred order of the field descriptions in the help text + * determines the order the entries appear in this file. + * + * When adding new entries take care to use the existing style. + * Displayed fields names normally have a type prefix and use underscores. + * Field-specific internal functions names normally match the displayed + * field names but without underscores. + * Help text ends with a full stop. + */ + +/* *INDENT-OFF* */ +FIELD(DEVTYPES, devtype, STR, "DevType", name, 7, chars, devtype_name, "Name of Device Type exactly as it appears in /proc/devices.", 0) +FIELD(DEVTYPES, devtype, NUM, "MaxParts", max_partitions, 8, int8, devtype_max_partitions, "Maximum number of partitions. (How many device minor numbers get reserved for each device.)", 0) +FIELD(DEVTYPES, devtype, STR, "Description", desc, 11, string, devtype_description, "Description of Device Type.", 0) +/* *INDENT-ON* */ diff --git a/lib/report/columns.h b/lib/report/columns.h index 6299a2b..1bb36b9 100644 --- a/lib/report/columns.h +++ b/lib/report/columns.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved. - * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved. + * Copyright (C) 2004-2019 Red Hat, Inc. All rights reserved. * * This file is part of LVM2. * @@ -10,146 +10,318 @@ * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* * This file defines the fields (columns) for the reporting commands * (pvs/vgs/lvs). + * + * The preferred order of the field descriptions in the help text + * determines the order the entries appear in this file. + * + * When adding new entries take care to use the existing style. + * + * Do not interleave fields from different report types - for example, + * if you have a field of type "LVS" add it in between "LVS type fields" + * and "End of LVS type fields" comment. If you interleaved fields of + * different types here in this file, they would end up interleaved in + * the <reporting_command> -o help output too which may be confusing + * for users. + * + * Displayed fields names normally have a type prefix and use underscores. + * + * Field-specific internal functions names normally match the displayed + * field names but without underscores. + * + * Help text ends with a full stop. */ + /* - * The 'FIELD' macro arguments are defined as follows: - * 1. report_type. An enum value that selects a specific - * struct dm_report_object_type in the _report_types array. The value is - * used to select the containing base object address (see *obj_get* - * functions) for any data values of any field in the report. - * 2. Containing struct. The structure that either contains the field data - * as a member or should be used to obtain the field data. The containing - * struct should match the base object of the report_type. - * 3. Field type. This must be either 'STR' or 'NUM'. - * 4. Report heading. This is the field heading that is displayed by the - * reporting commands. - * 5. Data value pointer. This argument is always a member of the - * containing struct. It may point directly to the data value (for example, - * lv_uuid - see _uuid_disp()) or may be used to derive the data value (for - * example, seg_count - see _lvsegcount_disp()). In the FIELD macro - * definition, it is used in an offset calculation to derive the offset to - * the data value from the containing struct base address. Note that in some - * cases, the argument is the first member of the struct, in which case the - * data value pointer points to the start of the struct itself (for example, - * 'lvid' field of struct 'lv'). - * 6. Minimum display width. This is the minimum width used to display - * the field value, typically matching the width of the column heading. - * 7. Display function identifier. Used to derive the full name of the - * function that displays this field. Derivation is done by appending '_' - * then prepending this argument to '_disp'. For example, if this argument - * is 'uuid', the display function is _uuid_disp(). Adding a new field may - * require defining a new display function (for example _myfieldname_disp()), - * or re-use of an existing one (for example, _uint32_disp()). - * 8. Unique format identifier / field id. This name must be unique and is - * used to select fields via '-o' in the reporting commands (pvs/vgs/lvs). - * The string used to specify the field - the 'id' member of - * struct dm_report_field_type. - * 9. Description of field. This is a brief (ideally <= 52 chars) description - * of the field used in the reporting commands. - * 10. Flags. - * FIELD_MODIFIABLE. A '_set' function exists to change the field's value. - * The function name is derived in a similar way to item 7 above. + * FIELD(report_object_type, structure, sort_type, heading, structure_field, output_width, reporting_function, field_id, description, settable_via_lib) */ -#define FIELD_MODIFIABLE 0x00000001 - /* *INDENT-OFF* */ -FIELD(LVS, lv, STR, "LV UUID", lvid.id[1], 38, uuid, lv_uuid, "Unique identifier.", 0) +/* + * LVS type fields + */ +FIELD(LVS, lv, STR, "LV UUID", lvid, 38, lvuuid, lv_uuid, "Unique identifier.", 0) FIELD(LVS, lv, STR, "LV", lvid, 4, lvname, lv_name, "Name. LVs created for internal use are enclosed in brackets.", 0) -FIELD(LVS, lv, STR, "Path", lvid, 4, lvpath, lv_path, "Full pathname for LV.", 0) -FIELD(LVS, lv, STR, "Attr", lvid, 4, lvstatus, lv_attr, "Various attributes - see man page.", 0) -FIELD(LVS, lv, NUM, "Maj", major, 3, int32, lv_major, "Persistent major number or -1 if not persistent.", 0) -FIELD(LVS, lv, NUM, "Min", minor, 3, int32, lv_minor, "Persistent minor number or -1 if not persistent.", 0) -FIELD(LVS, lv, NUM, "Rahead", lvid, 6, lvreadahead, lv_read_ahead, "Read ahead setting in current units.", 0) -FIELD(LVS, lv, STR, "KMaj", lvid, 4, lvkmaj, lv_kernel_major, "Currently assigned major number or -1 if LV is not active.", 0) -FIELD(LVS, lv, STR, "KMin", lvid, 4, lvkmin, lv_kernel_minor, "Currently assigned minor number or -1 if LV is not active.", 0) -FIELD(LVS, lv, NUM, "KRahead", lvid, 7, lvkreadahead, lv_kernel_read_ahead, "Currently-in-use read ahead setting in current units.", 0) -FIELD(LVS, lv, NUM, "LSize", size, 5, size64, lv_size, "Size of LV in current units.", 0) -FIELD(LVS, lv, NUM, "MSize", lvid, 6, lvmetadatasize, lv_metadata_size, "For thin pools, the size of the LV that holds the metadata.", 0) -FIELD(LVS, lv, NUM, "#Seg", lvid, 4, lvsegcount, seg_count, "Number of segments in LV.", 0) -FIELD(LVS, lv, STR, "Origin", lvid, 6, origin, origin, "For snapshots, the origin device of this LV.", 0) -FIELD(LVS, lv, NUM, "OSize", lvid, 5, originsize, origin_size, "For snapshots, the size of the origin device of this LV.", 0) -FIELD(LVS, lv, NUM, "Data%", lvid, 6, datapercent, data_percent, "For snapshot and thin pools and volumes, the percentage full if LV is active.", 0) -FIELD(LVS, lv, NUM, "Snap%", lvid, 6, snpercent, snap_percent, "For snapshots, the percentage full if LV is active.", 0) -FIELD(LVS, lv, NUM, "Meta%", lvid, 6, metadatapercent, metadata_percent, "For thin pools, the percentage of metadata full if LV is active.", 0) -FIELD(LVS, lv, NUM, "Copy%", lvid, 6, copypercent, copy_percent, "For mirrors and pvmove, current percentage in-sync.", 0) -FIELD(LVS, lv, STR, "Move", lvid, 4, movepv, move_pv, "For pvmove, Source PV of temporary LV created by pvmove.", 0) -FIELD(LVS, lv, STR, "Convert", lvid, 7, convertlv, convert_lv, "For lvconvert, Name of temporary LV created by lvconvert.", 0) -FIELD(LVS, lv, STR, "Log", lvid, 3, loglv, mirror_log, "For mirrors, the LV holding the synchronisation log.", 0) -FIELD(LVS, lv, STR, "Data", lvid, 4, datalv, data_lv, "For thin pools, the LV holding the associated data.", 0) -FIELD(LVS, lv, STR, "Meta", lvid, 4, metadatalv, metadata_lv, "For thin pools, the LV holding the associated metadata.", 0) -FIELD(LVS, lv, STR, "Pool", lvid, 4, poollv, pool_lv, "For thin volumes, the thin pool LV for this volume.", 0) -FIELD(LVS, lv, STR, "LV Tags", tags, 7, tags, lv_tags, "Tags, if any.", 0) -FIELD(LVS, lv, STR, "Time", lvid, 26, lvtime, lv_time, "Creation time of the LV, if known", 0) +FIELD(LVS, lv, STR, "LV", lvid, 4, lvfullname, lv_full_name, "Full name of LV including its VG, namely VG/LV.", 0) +FIELD(LVS, lv, STR, "Path", lvid, 0, lvpath, lv_path, "Full pathname for LV. Blank for internal LVs.", 0) +FIELD(LVS, lv, STR, "DMPath", lvid, 0, lvdmpath, lv_dm_path, "Internal device-mapper pathname for LV (in /dev/mapper directory).", 0) +FIELD(LVS, lv, STR, "Parent", lvid, 0, lvparent, lv_parent, "For LVs that are components of another LV, the parent LV.", 0) +FIELD(LVS, lv, STR_LIST, "Layout", lvid, 10, lvlayout, lv_layout, "LV layout.", 0) +FIELD(LVS, lv, STR_LIST, "Role", lvid, 10, lvrole, lv_role, "LV role.", 0) +FIELD(LVS, lv, BIN, "InitImgSync", lvid, 10, lvinitialimagesync, lv_initial_image_sync, "Set if mirror/RAID images underwent initial resynchronization.", 0) +FIELD(LVS, lv, BIN, "ImgSynced", lvid, 10, lvimagesynced, lv_image_synced, "Set if mirror/RAID image is synchronized.", 0) +FIELD(LVS, lv, BIN, "Merging", lvid, 10, lvmerging, lv_merging, "Set if snapshot LV is being merged to origin.", 0) +FIELD(LVS, lv, BIN, "Converting", lvid, 0, lvconverting, lv_converting, "Set if LV is being converted.", 0) +FIELD(LVS, lv, STR, "AllocPol", lvid, 10, lvallocationpolicy, lv_allocation_policy, "LV allocation policy.", 0) +FIELD(LVS, lv, BIN, "AllocLock", lvid, 10, lvallocationlocked, lv_allocation_locked, "Set if LV is locked against allocation changes.", 0) +FIELD(LVS, lv, BIN, "FixMin", lvid, 10, lvfixedminor, lv_fixed_minor, "Set if LV has fixed minor number assigned.", 0) +FIELD(LVS, lv, BIN, "SkipAct", lvid, 15, lvskipactivation, lv_skip_activation, "Set if LV is skipped on activation.", 0) +FIELD(LVS, lv, BIN, "AutoAct", lvid, 0, lvautoactivation, lv_autoactivation, "Set if LV autoactivation is enabled.", 0) +FIELD(LVS, lv, STR, "WhenFull", lvid, 15, lvwhenfull, lv_when_full, "For thin pools, behavior when full.", 0) +FIELD(LVS, lv, BIN, "Active", lvid, 0, lvactive, lv_active, "Active state of the LV.", 0) +FIELD(LVS, lv, BIN, "ActLocal", lvid, 10, lvactivelocally, lv_active_locally, "Set if the LV is active locally.", 0) +FIELD(LVS, lv, BIN, "ActRemote", lvid, 10, lvactiveremotely, lv_active_remotely, "Set if the LV is active remotely.", 0) +FIELD(LVS, lv, BIN, "ActExcl", lvid, 10, lvactiveexclusively, lv_active_exclusively, "Set if the LV is active exclusively.", 0) +FIELD(LVS, lv, SNUM, "Maj", major, 0, int32, lv_major, "Persistent major number or -1 if not persistent.", 0) +FIELD(LVS, lv, SNUM, "Min", minor, 0, int32, lv_minor, "Persistent minor number or -1 if not persistent.", 0) +FIELD(LVS, lv, SIZ, "Rahead", lvid, 0, lvreadahead, lv_read_ahead, "Read ahead setting in current units.", 0) +FIELD(LVS, lv, SIZ, "LSize", lvid, 0, lv_size, lv_size, "Size of LV in current units.", 0) +FIELD(LVS, lv, SIZ, "MSize", lvid, 0, lvmetadatasize, lv_metadata_size, "For thin and cache pools, the size of the LV that holds the metadata.", 0) +FIELD(LVS, lv, NUM, "#Seg", lvid, 0, lvsegcount, seg_count, "Number of segments in LV.", 0) +FIELD(LVS, lv, STR, "Origin", lvid, 0, origin, origin, "For snapshots and thins, the origin device of this LV.", 0) +FIELD(LVS, lv, STR, "Origin UUID", lvid, 38, originuuid, origin_uuid, "For snapshots and thins, the UUID of origin device of this LV.", 0) +FIELD(LVS, lv, SIZ, "OSize", lvid, 0, originsize, origin_size, "For snapshots, the size of the origin device of this LV.", 0) +FIELD(LVS, lv, STR_LIST, "Ancestors", lvid, 0, lvancestors, lv_ancestors, "LV ancestors ignoring any stored history of the ancestry chain.", 0) +FIELD(LVS, lv, STR_LIST, "FAncestors", lvid, 0, lvfullancestors, lv_full_ancestors, "LV ancestors including stored history of the ancestry chain.", 0) +FIELD(LVS, lv, STR_LIST, "Descendants", lvid, 0, lvdescendants, lv_descendants, "LV descendants ignoring any stored history of the ancestry chain.", 0) +FIELD(LVS, lv, STR_LIST, "FDescendants", lvid, 0, lvfulldescendants, lv_full_descendants, "LV descendants including stored history of the ancestry chain.", 0) +FIELD(LVS, lv, NUM, "Mismatches", lvid, 0, raidmismatchcount, raid_mismatch_count, "For RAID, number of mismatches found or repaired.", 0) +FIELD(LVS, lv, STR, "SyncAction", lvid, 0, raidsyncaction, raid_sync_action, "For RAID, the current synchronization action being performed.", 0) +FIELD(LVS, lv, NUM, "WBehind", lvid, 0, raidwritebehind, raid_write_behind, "For RAID1, the number of outstanding writes allowed to writemostly devices.", 0) +FIELD(LVS, lv, NUM, "MinSync", lvid, 0, raidminrecoveryrate, raid_min_recovery_rate, "For RAID1, the minimum recovery I/O load in kiB/sec/disk.", 0) +FIELD(LVS, lv, NUM, "MaxSync", lvid, 0, raidmaxrecoveryrate, raid_max_recovery_rate, "For RAID1, the maximum recovery I/O load in kiB/sec/disk.", 0) +FIELD(LVS, lv, STR, "IntegMode", lvid, 0, raidintegritymode, raidintegritymode, "The integrity mode", 0) +FIELD(LVS, lv, NUM, "IntegBlkSize", lvid, 0, raidintegrityblocksize, raidintegrityblocksize, "The integrity block size", 0) +FIELD(LVS, lv, NUM, "IntegMismatches", lvid, 0, integritymismatches, integritymismatches, "The number of integrity mismatches.", 0) +FIELD(LVS, lv, STR, "Move", lvid, 0, movepv, move_pv, "For pvmove, Source PV of temporary LV created by pvmove.", 0) +FIELD(LVS, lv, STR, "Move UUID", lvid, 38, movepvuuid, move_pv_uuid, "For pvmove, the UUID of Source PV of temporary LV created by pvmove.", 0) +FIELD(LVS, lv, STR, "Convert", lvid, 0, convertlv, convert_lv, "For lvconvert, Name of temporary LV created by lvconvert.", 0) +FIELD(LVS, lv, STR, "Convert UUID", lvid, 38, convertlvuuid, convert_lv_uuid, "For lvconvert, UUID of temporary LV created by lvconvert.", 0) +FIELD(LVS, lv, STR, "Log", lvid, 0, loglv, mirror_log, "For mirrors, the LV holding the synchronization log.", 0) +FIELD(LVS, lv, STR, "Log UUID", lvid, 38, loglvuuid, mirror_log_uuid, "For mirrors, the UUID of the LV holding the synchronization log.", 0) +FIELD(LVS, lv, STR, "Data", lvid, 0, datalv, data_lv, "For cache/thin/vdo pools, the LV holding the associated data.", 0) +FIELD(LVS, lv, STR, "Data UUID", lvid, 38, datalvuuid, data_lv_uuid, "For cache/thin/vdo pools, the UUID of the LV holding the associated data.", 0) +FIELD(LVS, lv, STR, "Meta", lvid, 0, metadatalv, metadata_lv, "For cache/thin pools, the LV holding the associated metadata.", 0) +FIELD(LVS, lv, STR, "Meta UUID", lvid, 38, metadatalvuuid, metadata_lv_uuid, "For cache/thin pools, the UUID of the LV holding the associated metadata.", 0) +FIELD(LVS, lv, STR, "Pool", lvid, 0, poollv, pool_lv, "For cache/thin/vdo volumes, the cache/thin/vdo pool LV for this volume.", 0) +FIELD(LVS, lv, STR, "Pool UUID", lvid, 38, poollvuuid, pool_lv_uuid, "For cache/thin/vdo volumes, the UUID of the cache/thin/vdo pool LV for this volume.", 0) +FIELD(LVS, lv, STR_LIST, "LV Tags", tags, 0, tags, lv_tags, "Tags, if any.", 0) +FIELD(LVS, lv, STR, "LProfile", lvid, 0, lvprofile, lv_profile, "Configuration profile attached to this LV.", 0) +FIELD(LVS, lv, STR, "LLockArgs", lvid, 0, lvlockargs, lv_lockargs, "Lock args of the LV used by lvmlockd.", 0) +FIELD(LVS, lv, TIM, "CTime", lvid, 26, lvtime, lv_time, "Creation time of the LV, if known", 0) +FIELD(LVS, lv, TIM, "RTime", lvid, 26, lvtimeremoved, lv_time_removed, "Removal time of the LV, if known", 0) FIELD(LVS, lv, STR, "Host", lvid, 10, lvhost, lv_host, "Creation host of the LV, if known.", 0) -FIELD(LVS, lv, STR, "Modules", lvid, 7, modules, modules, "Kernel device-mapper modules required for this LV.", 0) +FIELD(LVS, lv, STR_LIST, "Modules", lvid, 0, modules, lv_modules, "Kernel device-mapper modules required for this LV.", 0) +FIELD(LVS, lv, BIN, "Historical", lvid, 0, lvhistorical, lv_historical, "Set if the LV is historical.", 0) +FIELD(LVS, lv, NUM, "WCacheBlkSize", lvid, 0, writecache_block_size, writecache_block_size, "The writecache block size", 0) +/* + * End of LVS type fields + */ -FIELD(LABEL, pv, STR, "Fmt", id, 3, pvfmt, pv_fmt, "Type of metadata.", 0) -FIELD(LABEL, pv, STR, "PV UUID", id, 38, uuid, pv_uuid, "Unique identifier.", 0) -FIELD(LABEL, pv, NUM, "DevSize", id, 7, devsize, dev_size, "Size of underlying device in current units.", 0) -FIELD(LABEL, pv, STR, "PV", dev, 10, dev_name, pv_name, "Name.", 0) -FIELD(LABEL, pv, NUM, "PMdaFree", id, 9, pvmdafree, pv_mda_free, "Free metadata area space on this device in current units.", 0) -FIELD(LABEL, pv, NUM, "PMdaSize", id, 9, pvmdasize, pv_mda_size, "Size of smallest metadata area on this device in current units.", 0) +/* + * LVSINFO type fields + */ +FIELD(LVSINFO, lv, SNUM, "KMaj", lvid, 0, lvkmaj, lv_kernel_major, "Currently assigned major number or -1 if LV is not active.", 0) +FIELD(LVSINFO, lv, SNUM, "KMin", lvid, 0, lvkmin, lv_kernel_minor, "Currently assigned minor number or -1 if LV is not active.", 0) +FIELD(LVSINFO, lv, SIZ, "KRahead", lvid, 0, lvkreadahead, lv_kernel_read_ahead, "Currently-in-use read ahead setting in current units.", 0) +FIELD(LVSINFO, lv, STR, "LPerms", lvid, 8, lvpermissions, lv_permissions, "LV permissions.", 0) +FIELD(LVSINFO, lv, BIN, "Suspended", lvid, 10, lvsuspended, lv_suspended, "Set if LV is suspended.", 0) +FIELD(LVSINFO, lv, BIN, "LiveTable", lvid, 20, lvlivetable, lv_live_table, "Set if LV has live table present.", 0) +FIELD(LVSINFO, lv, BIN, "InactiveTable", lvid, 20, lvinactivetable, lv_inactive_table, "Set if LV has inactive table present.", 0) +FIELD(LVSINFO, lv, BIN, "DevOpen", lvid, 10, lvdeviceopen, lv_device_open, "Set if LV device is open.", 0) +/* + * End of LVSINFO type fields + */ + +/* + * LVSSTATUS type fields + */ +FIELD(LVSSTATUS, lv, PCT, "Data%", lvid, 6, datapercent, data_percent, "For snapshot, cache and thin pools and volumes, the percentage full if LV is active.", 0) +FIELD(LVSSTATUS, lv, PCT, "Snap%", lvid, 6, snpercent, snap_percent, "For snapshots, the percentage full if LV is active.", 0) +FIELD(LVSSTATUS, lv, PCT, "Meta%", lvid, 6, metadatapercent, metadata_percent, "For cache and thin pools, the percentage of metadata full if LV is active.", 0) +FIELD(LVSSTATUS, lv, PCT, "Cpy%Sync", lvid, 0, copypercent, copy_percent, "For Cache, RAID, mirrors and pvmove, current percentage in-sync.", 0) +FIELD(LVSSTATUS, lv, PCT, "Cpy%Sync", lvid, 0, copypercent, sync_percent, "For Cache, RAID, mirrors and pvmove, current percentage in-sync.", 0) +FIELD(LVSSTATUS, lv, NUM, "CacheTotalBlocks", lvid, 0, cache_total_blocks, cache_total_blocks, "Total cache blocks.", 0) +FIELD(LVSSTATUS, lv, NUM, "CacheUsedBlocks", lvid, 16, cache_used_blocks, cache_used_blocks, "Used cache blocks.", 0) +FIELD(LVSSTATUS, lv, NUM, "CacheDirtyBlocks", lvid, 0, cache_dirty_blocks, cache_dirty_blocks, "Dirty cache blocks.", 0) +FIELD(LVSSTATUS, lv, NUM, "CacheReadHits", lvid, 16, cache_read_hits, cache_read_hits, "Cache read hits.", 0) +FIELD(LVSSTATUS, lv, NUM, "CacheReadMisses", lvid, 16, cache_read_misses, cache_read_misses, "Cache read misses.", 0) +FIELD(LVSSTATUS, lv, NUM, "CacheWriteHits", lvid, 16, cache_write_hits, cache_write_hits, "Cache write hits.", 0) +FIELD(LVSSTATUS, lv, NUM, "CacheWriteMisses", lvid, 0, cache_write_misses, cache_write_misses, "Cache write misses.", 0) +FIELD(LVSSTATUS, lv, STR_LIST, "KCacheSettings", lvid, 18, kernel_cache_settings, kernel_cache_settings, "Cache settings/parameters as set in kernel, including default values (cached segments only).", 0) +FIELD(LVSSTATUS, lv, STR, "KCachePolicy", lvid, 18, kernel_cache_policy, kernel_cache_policy, "Cache policy used in kernel.", 0) +FIELD(LVSSTATUS, lv, NUM, "KMFmt", lvid, 0, kernelmetadataformat, kernel_metadata_format, "Cache metadata format used in kernel.", 0) +FIELD(LVSSTATUS, lv, STR, "Health", lvid, 15, lvhealthstatus, lv_health_status, "LV health status.", 0) +FIELD(LVSSTATUS, lv, STR, "KDiscards", lvid, 0, kdiscards, kernel_discards, "For thin pools, how discards are handled in kernel.", 0) +FIELD(LVSSTATUS, lv, BIN, "CheckNeeded", lvid, 15, lvcheckneeded, lv_check_needed, "For thin pools and cache volumes, whether metadata check is needed.", 0) +FIELD(LVSSTATUS, lv, BIN, "MergeFailed", lvid, 15, lvmergefailed, lv_merge_failed, "Set if snapshot merge failed.", 0) +FIELD(LVSSTATUS, lv, BIN, "SnapInvalid", lvid, 15, lvsnapshotinvalid, lv_snapshot_invalid, "Set if snapshot LV is invalid.", 0) +FIELD(LVSSTATUS, lv, STR, "VDOOperatingMode", lvid, 0, vdo_operating_mode, vdo_operating_mode, "For vdo pools, its current operating mode.", 0) +FIELD(LVSSTATUS, lv, STR, "VDOCompressionState", lvid, 0, vdo_compression_state, vdo_compression_state, "For vdo pools, whether compression is running.", 0) +FIELD(LVSSTATUS, lv, STR, "VDOIndexState", lvid, 0, vdo_index_state, vdo_index_state, "For vdo pools, state of index for deduplication.", 0) +FIELD(LVSSTATUS, lv, NUM, "VDOUsedSize", lvid, 0, vdo_used_size, vdo_used_size, "For vdo pools, currently used space.", 0) +FIELD(LVSSTATUS, lv, NUM, "VDOSaving%", lvid, 0, vdo_saving_percent, vdo_saving_percent, "For vdo pools, percentage of saved space.", 0) +FIELD(LVSSTATUS, lv, NUM, "WCacheTotalBlocks", lvid, 0, writecache_total_blocks, writecache_total_blocks, "Total writecache blocks.", 0) +FIELD(LVSSTATUS, lv, NUM, "WCacheFreeBlocks", lvid, 0, writecache_free_blocks, writecache_free_blocks, "Total writecache free blocks.", 0) +FIELD(LVSSTATUS, lv, NUM, "WCacheWritebackBlocks", lvid, 0, writecache_writeback_blocks, writecache_writeback_blocks, "Total writecache writeback blocks.", 0) +FIELD(LVSSTATUS, lv, NUM, "WCacheErrors", lvid, 0, writecache_error, writecache_error, "Total writecache errors.", 0) +/* + * End of LVSSTATUS type fields + */ -FIELD(PVS, pv, NUM, "1st PE", pe_start, 7, size64, pe_start, "Offset to the start of data on the underlying device.", 0) -FIELD(PVS, pv, NUM, "PSize", id, 5, pvsize, pv_size, "Size of PV in current units.", 0) -FIELD(PVS, pv, NUM, "PFree", id, 5, pvfree, pv_free, "Total amount of unallocated space in current units.", 0) -FIELD(PVS, pv, NUM, "Used", id, 4, pvused, pv_used, "Total amount of allocated space in current units.", 0) -FIELD(PVS, pv, STR, "Attr", id, 4, pvstatus, pv_attr, "Various attributes - see man page.", 0) +/* + * LVSINFOSTATUS type fields + */ +FIELD(LVSINFOSTATUS, lv, STR, "Attr", lvid, 0, lvstatus, lv_attr, "Various attributes - see man page.", 0) +/* + * End of LVSINFOSTATUS type fields + */ + +/* + * LABEL type fields + */ +FIELD(LABEL, label, STR, "Fmt", type, 0, pvfmt, pv_fmt, "Type of metadata.", 0) +FIELD(LABEL, label, STR, "PV UUID", type, 38, pvuuid, pv_uuid, "Unique identifier.", 0) +FIELD(LABEL, label, SIZ, "DevSize", dev, 0, devsize, dev_size, "Size of underlying device in current units.", 0) +FIELD(LABEL, label, STR, "PV", dev, 10, dev_name, pv_name, "Name.", 0) +FIELD(LABEL, label, SNUM, "Maj", dev, 0, devmajor, pv_major, "Device major number.", 0) +FIELD(LABEL, label, SNUM, "Min", dev, 0, devminor, pv_minor, "Device minor number.", 0) +FIELD(LABEL, label, SIZ, "PMdaFree", type, 9, pvmdafree, pv_mda_free, "Free metadata area space on this device in current units.", 0) +FIELD(LABEL, label, SIZ, "PMdaSize", type, 9, pvmdasize, pv_mda_size, "Size of smallest metadata area on this device in current units.", 0) +FIELD(LABEL, label, NUM, "PExtVsn", type, 0, pvextvsn, pv_ext_vsn, "PV header extension version.", 0) +/* + * End of LABEL type fields + */ + +/* + * PVS type fields + */ +FIELD(PVS, pv, SIZ, "1st PE", pe_start, 7, size64, pe_start, "Offset to the start of data on the underlying device.", 0) +FIELD(PVS, pv, SIZ, "PSize", id, 0, pvsize, pv_size, "Size of PV in current units.", 0) +FIELD(PVS, pv, SIZ, "PFree", id, 0, pvfree, pv_free, "Total amount of unallocated space in current units.", 0) +FIELD(PVS, pv, SIZ, "Used", id, 0, pvused, pv_used, "Total amount of allocated space in current units.", 0) +FIELD(PVS, pv, STR, "Attr", id, 0, pvstatus, pv_attr, "Various attributes - see man page.", 0) +FIELD(PVS, pv, BIN, "Allocatable", id, 0, pvallocatable, pv_allocatable, "Set if this device can be used for allocation.", 0) +FIELD(PVS, pv, BIN, "Exported", id, 10, pvexported, pv_exported, "Set if this device is exported.", 0) +FIELD(PVS, pv, BIN, "Missing", id, 10, pvmissing, pv_missing, "Set if this device is missing in system.", 0) FIELD(PVS, pv, NUM, "PE", pe_count, 3, uint32, pv_pe_count, "Total number of Physical Extents.", 0) -FIELD(PVS, pv, NUM, "Alloc", pe_alloc_count, 5, uint32, pv_pe_alloc_count, "Total number of allocated Physical Extents.", 0) -FIELD(PVS, pv, STR, "PV Tags", tags, 7, tags, pv_tags, "Tags, if any.", 0) -FIELD(PVS, pv, NUM, "#PMda", id, 5, pvmdas, pv_mda_count, "Number of metadata areas on this device.", 0) -FIELD(PVS, pv, NUM, "#PMdaUse", id, 8, pvmdasused, pv_mda_used_count, "Number of metadata areas in use on this device.", 0) +FIELD(PVS, pv, NUM, "Alloc", pe_alloc_count, 0, uint32, pv_pe_alloc_count, "Total number of allocated Physical Extents.", 0) +FIELD(PVS, pv, STR_LIST, "PV Tags", tags, 0, tags, pv_tags, "Tags, if any.", 0) +FIELD(PVS, pv, NUM, "#PMda", id, 0, pvmdas, pv_mda_count, "Number of metadata areas on this device.", 0) +FIELD(PVS, pv, NUM, "#PMdaUse", id, 0, pvmdasused, pv_mda_used_count, "Number of metadata areas in use on this device.", 0) +FIELD(PVS, pv, SIZ, "BA Start", ba_start, 0, size64, pv_ba_start, "Offset to the start of PV Bootloader Area on the underlying device in current units.", 0) +FIELD(PVS, pv, SIZ, "BA Size", ba_size, 0, size64, pv_ba_size, "Size of PV Bootloader Area in current units.", 0) +FIELD(PVS, pv, BIN, "PInUse", id, 0, pvinuse, pv_in_use, "Set if PV is used.", 0) +FIELD(PVS, pv, BIN, "Duplicate", id, 0, pvduplicate, pv_duplicate, "Set if PV is an unchosen duplicate.", 0) +FIELD(PVS, pv, STR, "DeviceID", id, 0, pvdeviceid, pv_device_id, "Device ID such as the WWID.", 0) +FIELD(PVS, pv, STR, "DeviceIDType", id, 0, pvdeviceidtype, pv_device_id_type, "Type of device ID such as WWID.", 0) +/* + * End of PVS type fields + */ -FIELD(VGS, vg, STR, "Fmt", cmd, 3, vgfmt, vg_fmt, "Type of metadata.", 0) +/* + * VGS type fields + */ +FIELD(VGS, vg, STR, "Fmt", cmd, 0, vgfmt, vg_fmt, "Type of metadata.", 0) FIELD(VGS, vg, STR, "VG UUID", id, 38, uuid, vg_uuid, "Unique identifier.", 0) -FIELD(VGS, vg, STR, "VG", name, 4, string, vg_name, "Name.", 0) +FIELD(VGS, vg, STR, "VG", name, 0, string, vg_name, "Name.", 0) FIELD(VGS, vg, STR, "Attr", cmd, 5, vgstatus, vg_attr, "Various attributes - see man page.", 0) -FIELD(VGS, vg, NUM, "VSize", cmd, 5, vgsize, vg_size, "Total size of VG in current units.", 0) -FIELD(VGS, vg, NUM, "VFree", cmd, 5, vgfree, vg_free, "Total amount of free space in current units.", 0) -FIELD(VGS, vg, STR, "SYS ID", system_id, 6, string, vg_sysid, "System ID indicating when and where it was created.", 0) -FIELD(VGS, vg, NUM, "Ext", extent_size, 3, size32, vg_extent_size, "Size of Physical Extents in current units.", 0) -FIELD(VGS, vg, NUM, "#Ext", extent_count, 4, uint32, vg_extent_count, "Total number of Physical Extents.", 0) -FIELD(VGS, vg, NUM, "Free", free_count, 4, uint32, vg_free_count, "Total number of unallocated Physical Extents.", 0) -FIELD(VGS, vg, NUM, "MaxLV", max_lv, 5, uint32, max_lv, "Maximum number of LVs allowed in VG or 0 if unlimited.", 0) -FIELD(VGS, vg, NUM, "MaxPV", max_pv, 5, uint32, max_pv, "Maximum number of PVs allowed in VG or 0 if unlimited.", 0) -FIELD(VGS, vg, NUM, "#PV", pv_count, 3, uint32, pv_count, "Number of PVs.", 0) -FIELD(VGS, vg, NUM, "#LV", cmd, 3, lvcount, lv_count, "Number of LVs.", 0) -FIELD(VGS, vg, NUM, "#SN", cmd, 3, snapcount, snap_count, "Number of snapshots.", 0) -FIELD(VGS, vg, NUM, "Seq", seqno, 3, uint32, vg_seqno, "Revision number of internal metadata. Incremented whenever it changes.", 0) -FIELD(VGS, vg, STR, "VG Tags", tags, 7, tags, vg_tags, "Tags, if any.", 0) -FIELD(VGS, vg, NUM, "#VMda", cmd, 5, vgmdas, vg_mda_count, "Number of metadata areas on this VG.", 0) -FIELD(VGS, vg, NUM, "#VMdaUse", cmd, 8, vgmdasused, vg_mda_used_count, "Number of metadata areas in use on this VG.", 0) -FIELD(VGS, vg, NUM, "VMdaFree", cmd, 9, vgmdafree, vg_mda_free, "Free metadata area space for this VG in current units.", 0) -FIELD(VGS, vg, NUM, "VMdaSize", cmd, 9, vgmdasize, vg_mda_size, "Size of smallest metadata area for this VG in current units.", 0) -FIELD(VGS, vg, NUM, "#VMdaCps", cmd, 8, vgmdacopies, vg_mda_copies, "Target number of in use metadata areas in the VG.", 1) +FIELD(VGS, vg, STR, "VPerms", cmd, 10, vgpermissions, vg_permissions, "VG permissions.", 0) +FIELD(VGS, vg, BIN, "Extendable", cmd, 0, vgextendable, vg_extendable, "Set if VG is extendable.", 0) +FIELD(VGS, vg, BIN, "Exported", cmd, 10, vgexported, vg_exported, "Set if VG is exported.", 0) +FIELD(VGS, vg, BIN, "AutoAct", cmd, 0, vgautoactivation, vg_autoactivation, "Set if VG autoactivation is enabled.", 0) +FIELD(VGS, vg, BIN, "Partial", cmd, 10, vgpartial, vg_partial, "Set if VG is partial.", 0) +FIELD(VGS, vg, STR, "AllocPol", cmd, 10, vgallocationpolicy, vg_allocation_policy, "VG allocation policy.", 0) +FIELD(VGS, vg, BIN, "Clustered", cmd, 10, vgclustered, vg_clustered, "Set if VG is clustered.", 0) +FIELD(VGS, vg, BIN, "Shared", cmd, 7, vgshared, vg_shared, "Set if VG is shared.", 0) +FIELD(VGS, vg, SIZ, "VSize", cmd, 0, vgsize, vg_size, "Total size of VG in current units.", 0) +FIELD(VGS, vg, SIZ, "VFree", cmd, 0, vgfree, vg_free, "Total amount of free space in current units.", 0) +FIELD(VGS, vg, STR, "SYS ID", cmd, 0, vgsystemid, vg_sysid, "System ID of the VG indicating which host owns it.", 0) +FIELD(VGS, vg, STR, "System ID", cmd, 0, vgsystemid, vg_systemid, "System ID of the VG indicating which host owns it.", 0) +FIELD(VGS, vg, STR, "LockType", cmd, 0, vglocktype, vg_lock_type, "Lock type of the VG used by lvmlockd.", 0) +FIELD(VGS, vg, STR, "VLockArgs", cmd, 0, vglockargs, vg_lock_args, "Lock args of the VG used by lvmlockd.", 0) +FIELD(VGS, vg, SIZ, "Ext", extent_size, 0, size32, vg_extent_size, "Size of Physical Extents in current units.", 0) +FIELD(VGS, vg, NUM, "#Ext", extent_count, 0, uint32, vg_extent_count, "Total number of Physical Extents.", 0) +FIELD(VGS, vg, NUM, "Free", free_count, 0, uint32, vg_free_count, "Total number of unallocated Physical Extents.", 0) +FIELD(VGS, vg, NUM, "MaxLV", max_lv, 0, uint32, max_lv, "Maximum number of LVs allowed in VG or 0 if unlimited.", 0) +FIELD(VGS, vg, NUM, "MaxPV", max_pv, 0, uint32, max_pv, "Maximum number of PVs allowed in VG or 0 if unlimited.", 0) +FIELD(VGS, vg, NUM, "#PV", pv_count, 0, uint32, pv_count, "Number of PVs in VG.", 0) +FIELD(VGS, vg, NUM, "#PV Missing", cmd, 0, vgmissingpvcount, vg_missing_pv_count, "Number of PVs in VG which are missing.", 0) +FIELD(VGS, vg, NUM, "#LV", cmd, 0, lvcount, lv_count, "Number of LVs.", 0) +FIELD(VGS, vg, NUM, "#SN", cmd, 0, snapcount, snap_count, "Number of snapshots.", 0) +FIELD(VGS, vg, NUM, "Seq", seqno, 0, uint32, vg_seqno, "Revision number of internal metadata. Incremented whenever it changes.", 0) +FIELD(VGS, vg, STR_LIST, "VG Tags", tags, 0, tags, vg_tags, "Tags, if any.", 0) +FIELD(VGS, vg, STR, "VProfile", cmd, 0, vgprofile, vg_profile, "Configuration profile attached to this VG.", 0) +FIELD(VGS, vg, NUM, "#VMda", cmd, 0, vgmdas, vg_mda_count, "Number of metadata areas on this VG.", 0) +FIELD(VGS, vg, NUM, "#VMdaUse", cmd, 0, vgmdasused, vg_mda_used_count, "Number of metadata areas in use on this VG.", 0) +FIELD(VGS, vg, SIZ, "VMdaFree", cmd, 9, vgmdafree, vg_mda_free, "Free metadata area space for this VG in current units.", 0) +FIELD(VGS, vg, SIZ, "VMdaSize", cmd, 9, vgmdasize, vg_mda_size, "Size of smallest metadata area for this VG in current units.", 0) +FIELD(VGS, vg, NUM, "#VMdaCps", cmd, 0, vgmdacopies, vg_mda_copies, "Target number of in use metadata areas in the VG.", 1) +/* + * End of VGS type fields + */ + +/* + * SEGS type fields + */ +FIELD(SEGS, seg, STR, "Type", list, 0, segtype, segtype, "Type of LV segment.", 0) +FIELD(SEGS, seg, NUM, "#Str", list, 0, seg_stripes, stripes, "Number of stripes or mirror/raid1 legs.", 0) +FIELD(SEGS, seg, NUM, "#DStr", list, 0, seg_data_stripes, data_stripes, "Number of data stripes or mirror/raid1 legs.", 0) +FIELD(SEGS, seg, SIZ, "RSize", list, 0, seg_reshape_len, reshape_len, "Size of out-of-place reshape space in current units.", 0) +FIELD(SEGS, seg, NUM, "RSize", list, 0, seg_reshape_len_le, reshape_len_le, "Size of out-of-place reshape space in logical extents.", 0) +FIELD(SEGS, seg, NUM, "#Cpy", list, 0, seg_data_copies, data_copies, "Number of data copies.", 0) +FIELD(SEGS, seg, NUM, "DOff", list, 0, seg_data_offset, data_offset, "Data offset on each image device.", 0) +FIELD(SEGS, seg, NUM, "NOff", list, 0, seg_new_data_offset, new_data_offset, "New data offset after any reshape on each image device.", 0) +FIELD(SEGS, seg, NUM, "#Par", list, 0, seg_parity_chunks, parity_chunks, "Number of (rotating) parity chunks.", 0) +FIELD(SEGS, seg, SIZ, "Stripe", stripe_size, 0, size32, stripe_size, "For stripes, amount of data placed on one device before switching to the next.", 0) +FIELD(SEGS, seg, SIZ, "Region", region_size, 0, size32, region_size, "For mirrors/raids, the unit of data per leg when synchronizing devices.", 0) +FIELD(SEGS, seg, SIZ, "Chunk", list, 0, chunksize, chunk_size, "For snapshots, the unit of data used when tracking changes.", 0) +FIELD(SEGS, seg, NUM, "#Thins", list, 0, thincount, thin_count, "For thin pools, the number of thin volumes in this pool.", 0) +FIELD(SEGS, seg, STR, "Discards", list, 0, discards, discards, "For thin pools, how discards are handled.", 0) +FIELD(SEGS, seg, NUM, "CMFmt", list, 0, cachemetadataformat, cache_metadata_format, "For cache, metadata format in use.", 0) +FIELD(SEGS, seg, STR, "CacheMode", list, 0, cachemode, cache_mode, "For cache, how writes are cached.", 0) +FIELD(SEGS, seg, BIN, "Zero", list, 0, thinzero, zero, "For thin pools and volumes, if zeroing is enabled.", 0) +FIELD(SEGS, seg, NUM, "TransId", list, 0, transactionid, transaction_id, "For thin pools, the transaction id and creation transaction id for thins.", 0) +FIELD(SEGS, seg, NUM, "ThId", list, 0, thinid, thin_id, "For thin volume, the thin device id.", 0) +FIELD(SEGS, seg, SIZ, "Start", list, 0, segstart, seg_start, "Offset within the LV to the start of the segment in current units.", 0) +FIELD(SEGS, seg, NUM, "Start", list, 0, segstartpe, seg_start_pe, "Offset within the LV to the start of the segment in physical extents.", 0) +FIELD(SEGS, seg, SIZ, "SSize", list, 0, segsize, seg_size, "Size of segment in current units.", 0) +FIELD(SEGS, seg, SIZ, "SSize", list, 0, segsizepe, seg_size_pe, "Size of segment in physical extents.", 0) +FIELD(SEGS, seg, STR_LIST, "Seg Tags", tags, 0, tags, seg_tags, "Tags, if any.", 0) +FIELD(SEGS, seg, STR_LIST, "PE Ranges", list, 0, peranges, seg_pe_ranges, "Ranges of Physical Extents of underlying devices in command line format (deprecated, use seg_le_ranges for common format).", 0) +FIELD(SEGS, seg, STR_LIST, "LE Ranges", list, 0, leranges, seg_le_ranges, "Ranges of Logical Extents of underlying devices in command line format.", 0) +FIELD(SEGS, seg, STR_LIST, "Metadata LE Ranges", list, 0, metadataleranges, seg_metadata_le_ranges, "Ranges of Logical Extents of underlying metadata devices in command line format.", 0) +FIELD(SEGS, seg, STR_LIST, "Devices", list, 0, devices, devices, "Underlying devices used with starting extent numbers.", 0) +FIELD(SEGS, seg, STR_LIST, "Metadata Devs", list, 0, metadatadevices, metadata_devices, "Underlying metadata devices used with starting extent numbers.", 0) +FIELD(SEGS, seg, STR, "Monitor", list, 0, segmonitor, seg_monitor, "Dmeventd monitoring status of the segment.", 0) +FIELD(SEGS, seg, STR, "CachePolicy", list, 0, cache_policy, cache_policy, "The cache policy (cached segments only).", 0) +FIELD(SEGS, seg, STR_LIST, "CacheSettings", list, 0, cache_settings, cache_settings, "Cache settings/parameters (cached segments only).", 0) + +FIELD(SEGS, seg, BIN, "VDOCompression", list, 0, vdo_compression, vdo_compression, "Set for compressed LV (vdopool).", 0) +FIELD(SEGS, seg, BIN, "VDODeduplication", list, 0, vdo_deduplication, vdo_deduplication, "Set for deduplicated LV (vdopool).", 0) +FIELD(SEGS, seg, BIN, "VDOMetadataHints", list, 0, vdo_use_metadata_hints, vdo_use_metadata_hints, "Use REQ_SYNC for writes (vdopool).", 0) +FIELD(SEGS, seg, NUM, "VDOMinimumIOSize", list, 0, vdo_minimum_io_size, vdo_minimum_io_size, "Minimum acceptable IO size (vdopool).", 0) +FIELD(SEGS, seg, SIZ, "VDOBlockMapCacheSize", list, 0, vdo_block_map_cache_size, vdo_block_map_cache_size, "Allocated caching size (vdopool).", 0) +FIELD(SEGS, seg, NUM, "VDOBlockMapEraLength", list, 0, vdo_block_map_era_length, vdo_block_map_era_length, "Speed of cache writes (vdopool).", 0) +FIELD(SEGS, seg, BIN, "VDOSparseIndex", list, 0, vdo_use_sparse_index, vdo_use_sparse_index, "Sparse indexing (vdopool).", 0) +FIELD(SEGS, seg, SIZ, "VDOIndexMemorySize", list, 0, vdo_index_memory_size, vdo_index_memory_size, "Allocated indexing memory (vdopool).", 0) +FIELD(SEGS, seg, SIZ, "VDOSlabSize", list, 0, vdo_slab_size, vdo_slab_size, "Increment size for growing (vdopool).", 0) +FIELD(SEGS, seg, NUM, "VDOAckThreads", list, 0, vdo_ack_threads, vdo_ack_threads, "Acknowledging threads (vdopool).", 0) +FIELD(SEGS, seg, NUM, "VDOBioThreads", list, 0, vdo_bio_threads, vdo_bio_threads, "IO submitting threads (vdopool).", 0) +FIELD(SEGS, seg, NUM, "VDOBioRotation", list, 0, vdo_bio_rotation, vdo_bio_rotation, "IO enqueue (vdopool).", 0) +FIELD(SEGS, seg, NUM, "VDOCPUThreads", list, 0, vdo_cpu_threads, vdo_cpu_threads, "CPU threads for compression and hashing (vdopool).", 0) +FIELD(SEGS, seg, NUM, "VDOHashZoneThreads", list, 0, vdo_hash_zone_threads, vdo_hash_zone_threads, "Threads for subdivide parts (vdopool).", 0) +FIELD(SEGS, seg, NUM, "VDOLogicalThreads", list, 0, vdo_logical_threads, vdo_logical_threads, "Logical threads for subdivide parts (vdopool).", 0) +FIELD(SEGS, seg, NUM, "VDOPhysicalThreads", list, 0, vdo_physical_threads, vdo_physical_threads, "Physical threads for subdivide parts (vdopool).", 0) +FIELD(SEGS, seg, NUM, "VDOMaxDiscard", list, 0, vdo_max_discard, vdo_max_discard, "Maximum discard size volume can recieve (vdopool).", 0) +FIELD(SEGS, seg, STR, "VDOWritePolicy", list, 0, vdo_write_policy, vdo_write_policy, "Specified write policy (vdopool).", 0) +FIELD(SEGS, seg, SIZ, "VDOHeaderSize", list, 0, vdo_header_size, vdo_header_size, "Header size at front of vdopool.", 0) -FIELD(SEGS, seg, STR, "Type", list, 4, segtype, segtype, "Type of LV segment.", 0) -FIELD(SEGS, seg, NUM, "#Str", area_count, 4, uint32, stripes, "Number of stripes or mirror legs.", 0) -FIELD(SEGS, seg, NUM, "Stripe", stripe_size, 6, size32, stripesize, "For stripes, amount of data placed on one device before switching to the next.", 0) -FIELD(SEGS, seg, NUM, "Stripe", stripe_size, 6, size32, stripe_size, "For stripes, amount of data placed on one device before switching to the next.", 0) -FIELD(SEGS, seg, NUM, "Region", region_size, 6, size32, regionsize, "For mirrors, the unit of data copied when synchronising devices.", 0) -FIELD(SEGS, seg, NUM, "Region", region_size, 6, size32, region_size, "For mirrors, the unit of data copied when synchronising devices.", 0) -FIELD(SEGS, seg, NUM, "Chunk", list, 5, chunksize, chunksize, "For snapshots, the unit of data used when tracking changes.", 0) -FIELD(SEGS, seg, NUM, "Chunk", list, 5, chunksize, chunk_size, "For snapshots, the unit of data used when tracking changes.", 0) -FIELD(SEGS, seg, NUM, "#Thins", list, 4, thincount, thin_count, "For thin pools, the number of thin volumes in this pool.", 0) -FIELD(SEGS, seg, NUM, "Discards", list, 8, discards, discards, "For thin pools, how discards are handled.", 0) -FIELD(SEGS, seg, NUM, "Zero", list, 4, thinzero, zero, "For thin pools, if zeroing is enabled.", 0) -FIELD(SEGS, seg, NUM, "TransId", list, 4, transactionid, transaction_id, "For thin pools, the transaction id.", 0) -FIELD(SEGS, seg, NUM, "Start", list, 5, segstart, seg_start, "Offset within the LV to the start of the segment in current units.", 0) -FIELD(SEGS, seg, NUM, "Start", list, 5, segstartpe, seg_start_pe, "Offset within the LV to the start of the segment in physical extents.", 0) -FIELD(SEGS, seg, NUM, "SSize", list, 5, segsize, seg_size, "Size of segment in current units.", 0) -FIELD(SEGS, seg, STR, "Seg Tags", tags, 8, tags, seg_tags, "Tags, if any.", 0) -FIELD(SEGS, seg, STR, "PE Ranges", list, 9, peranges, seg_pe_ranges, "Ranges of Physical Extents of underlying devices in command line format.", 0) -FIELD(SEGS, seg, STR, "Devices", list, 7, devices, devices, "Underlying devices used with starting extent numbers.", 0) +/* + * End of SEGS type fields + */ -FIELD(PVSEGS, pvseg, NUM, "Start", pe, 5, uint32, pvseg_start, "Physical Extent number of start of segment.", 0) -FIELD(PVSEGS, pvseg, NUM, "SSize", len, 5, uint32, pvseg_size, "Number of extents in segment.", 0) +/* + * PVSEGS type fields + */ +FIELD(PVSEGS, pvseg, NUM, "Start", pe, 0, uint32, pvseg_start, "Physical Extent number of start of segment.", 0) +FIELD(PVSEGS, pvseg, NUM, "SSize", len, 0, uint32, pvseg_size, "Number of extents in segment.", 0) +/* + * End of PVSEGS type fields + */ /* *INDENT-ON* */ diff --git a/lib/report/properties.c b/lib/report/properties.c index c4f6ab9..6f30236 100644 --- a/lib/report/properties.c +++ b/lib/report/properties.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2012 Red Hat, Inc. All rights reserved. + * Copyright (C) 2010-2017 Red Hat, Inc. All rights reserved. * * This file is part of LVM2. * @@ -9,26 +9,15 @@ * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include <errno.h> - -#include "libdevmapper.h" -#include "properties.h" -#include "activate.h" -#include "lvm-logging.h" -#include "lvm-types.h" -#include "metadata.h" - -#define GET_NUM_PROPERTY_FN(NAME, VALUE, TYPE, VAR) \ -static int _ ## NAME ## _get (const void *obj, struct lvm_property_type *prop) \ -{ \ - const struct TYPE *VAR = (const struct TYPE *)obj; \ -\ - prop->value.integer = VALUE; \ - return 1; \ -} +#include "lib/misc/lib.h" +#include "lib/report/properties.h" +#include "lib/activate/activate.h" +#include "lib/metadata/metadata.h" + + #define GET_VG_NUM_PROPERTY_FN(NAME, VALUE) \ GET_NUM_PROPERTY_FN(NAME, VALUE, volume_group, vg) #define GET_PV_NUM_PROPERTY_FN(NAME, VALUE) \ @@ -40,14 +29,6 @@ static int _ ## NAME ## _get (const void *obj, struct lvm_property_type *prop) \ #define GET_PVSEG_NUM_PROPERTY_FN(NAME, VALUE) \ GET_NUM_PROPERTY_FN(NAME, VALUE, pv_segment, pvseg) -#define SET_NUM_PROPERTY_FN(NAME, SETFN, TYPE, VAR) \ -static int _ ## NAME ## _set (void *obj, struct lvm_property_type *prop) \ -{ \ - struct TYPE *VAR = (struct TYPE *)obj; \ -\ - SETFN(VAR, prop->value.integer); \ - return 1; \ -} #define SET_VG_NUM_PROPERTY_FN(NAME, SETFN) \ SET_NUM_PROPERTY_FN(NAME, SETFN, volume_group, vg) #define SET_PV_NUM_PROPERTY_FN(NAME, SETFN) \ @@ -55,14 +36,6 @@ static int _ ## NAME ## _set (void *obj, struct lvm_property_type *prop) \ #define SET_LV_NUM_PROPERTY_FN(NAME, SETFN) \ SET_NUM_PROPERTY_FN(NAME, SETFN, logical_volume, lv) -#define GET_STR_PROPERTY_FN(NAME, VALUE, TYPE, VAR) \ -static int _ ## NAME ## _get (const void *obj, struct lvm_property_type *prop) \ -{ \ - const struct TYPE *VAR = (const struct TYPE *)obj; \ -\ - prop->value.string = (char *)VALUE; \ - return 1; \ -} #define GET_VG_STR_PROPERTY_FN(NAME, VALUE) \ GET_STR_PROPERTY_FN(NAME, VALUE, volume_group, vg) #define GET_PV_STR_PROPERTY_FN(NAME, VALUE) \ @@ -74,364 +47,676 @@ static int _ ## NAME ## _get (const void *obj, struct lvm_property_type *prop) \ #define GET_PVSEG_STR_PROPERTY_FN(NAME, VALUE) \ GET_STR_PROPERTY_FN(NAME, VALUE, pv_segment, pvseg) -static int _not_implemented_get(const void *obj, struct lvm_property_type *prop) +static dm_percent_t _copy_percent(const struct logical_volume *lv) +{ + dm_percent_t percent; + + if (!lv_mirror_percent(lv->vg->cmd, lv, 0, &percent, NULL)) + percent = DM_PERCENT_INVALID; + + return percent; +} + +static uint64_t _raidmismatchcount(const struct logical_volume *lv) +{ + uint64_t cnt; + + if (!lv_raid_mismatch_count(lv, &cnt)) + return 0; + return cnt; +} + +static char *_raidsyncaction(const struct logical_volume *lv) +{ + char *action; + + if (!lv_raid_sync_action(lv, &action)) + return 0; + + return action; +} + +static uint32_t _raidwritebehind(const struct logical_volume *lv) +{ + return first_seg(lv)->writebehind; +} + +static uint32_t _raidminrecoveryrate(const struct logical_volume *lv) +{ + return first_seg(lv)->min_recovery_rate; +} + +static uint32_t _raidmaxrecoveryrate(const struct logical_volume *lv) { - log_errno(ENOSYS, "Function not implemented"); - return 0; + return first_seg(lv)->max_recovery_rate; } -static int _not_implemented_set(void *obj, struct lvm_property_type *prop) +static const char *_raidintegritymode(const struct logical_volume *lv) { - log_errno(ENOSYS, "Function not implemented"); - return 0; + struct integrity_settings *settings = NULL; + + if (lv_raid_has_integrity((struct logical_volume *)lv)) + lv_get_raid_integrity_settings((struct logical_volume *)lv, &settings); + else if (lv_is_integrity(lv)) + settings = &first_seg(lv)->integrity_settings; + + if (settings) { + switch (settings->mode[0]) { + case 'B': return "bitmap"; + case 'J': return "journal"; + } + } + + return "unknown"; +} + +static uint32_t _raidintegrityblocksize(const struct logical_volume *lv) +{ + struct integrity_settings *settings = NULL; + + if (lv_raid_has_integrity((struct logical_volume *)lv)) + lv_get_raid_integrity_settings((struct logical_volume *)lv, &settings); + else if (lv_is_integrity(lv)) + settings = &first_seg(lv)->integrity_settings; + else + return 0; + + return (settings) ? settings->block_size : 0; } -static percent_t _copy_percent(const struct logical_volume *lv) { - percent_t perc; - if (!lv_mirror_percent(lv->vg->cmd, lv, 0, &perc, NULL)) - perc = PERCENT_INVALID; - return perc; +static uint64_t _integritymismatches(const struct logical_volume *lv) +{ + uint64_t cnt; + + if (!lv_integrity_mismatches(lv->vg->cmd, lv, &cnt)) + return 0; + return cnt; } -static percent_t _snap_percent(const struct logical_volume *lv) { - percent_t perc; +static dm_percent_t _snap_percent(const struct logical_volume *lv) +{ + dm_percent_t percent; - if (!lv_is_cow(lv) || !lv_snapshot_percent(lv, &perc)) - perc = PERCENT_INVALID; + if (!lv_is_cow(lv) || !lv_snapshot_percent(lv, &percent)) + percent = DM_PERCENT_INVALID; - return perc; + return percent; } -static percent_t _data_percent(const struct logical_volume *lv) +static dm_percent_t _data_percent(const struct logical_volume *lv) { - percent_t perc; + dm_percent_t percent = DM_PERCENT_INVALID; + struct lv_status_cache *cache_status; + struct lv_status_thin *thin_status; + struct lv_status_thin_pool *thin_pool_status; if (lv_is_cow(lv)) return _snap_percent(lv); - if (lv_is_thin_volume(lv)) - return lv_thin_percent(lv, 0, &perc) ? perc : PERCENT_INVALID; + if (lv_is_cache(lv) || lv_is_used_cache_pool(lv)) { + if (!lv_cache_status(lv, &cache_status)) + stack; + else { + percent = cache_status->data_usage; + dm_pool_destroy(cache_status->mem); + } + } else if (lv_is_thin_volume(lv)) { + if (!lv_thin_status(lv, 0, &thin_status)) + stack; + else { + percent = thin_status->usage; + dm_pool_destroy(thin_status->mem); + } + } else if (lv_is_thin_pool(lv)) { + if (!lv_thin_pool_status(lv, 0, &thin_pool_status)) + stack; + else { + percent = thin_pool_status->data_usage; + dm_pool_destroy(thin_pool_status->mem); + } + } - return lv_thin_pool_percent(lv, 0, &perc) ? perc : PERCENT_INVALID; + return percent; } -static percent_t _metadata_percent(const struct logical_volume *lv) +static dm_percent_t _metadata_percent(const struct logical_volume *lv) { - percent_t perc; + dm_percent_t percent = DM_PERCENT_INVALID; + struct lv_status_cache *cache_status; + struct lv_status_thin_pool *thin_pool_status; + + if (lv_is_cache(lv) || lv_is_used_cache_pool(lv)) { + if (!lv_cache_status(lv, &cache_status)) + stack; + else { + percent = cache_status->metadata_usage; + dm_pool_destroy(cache_status->mem); + } + } else if (lv_is_thin_pool(lv)) { + if (!lv_thin_pool_status(lv, 0, &thin_pool_status)) + stack; + else { + percent = thin_pool_status->metadata_usage; + dm_pool_destroy(thin_pool_status->mem); + } + } - return lv_thin_pool_percent(lv, 1, &perc) ? perc : PERCENT_INVALID; + return percent; } /* PV */ GET_PV_STR_PROPERTY_FN(pv_fmt, pv_fmt_dup(pv)) -#define _pv_fmt_set _not_implemented_set -GET_PV_STR_PROPERTY_FN(pv_uuid, pv_uuid_dup(pv)) -#define _pv_uuid_set _not_implemented_set +#define _pv_fmt_set prop_not_implemented_set +GET_PV_STR_PROPERTY_FN(pv_uuid, pv_uuid_dup(pv->vg->vgmem, pv)) +#define _pv_uuid_set prop_not_implemented_set GET_PV_NUM_PROPERTY_FN(dev_size, SECTOR_SIZE * pv_dev_size(pv)) -#define _dev_size_set _not_implemented_set -GET_PV_STR_PROPERTY_FN(pv_name, pv_name_dup(pv)) -#define _pv_name_set _not_implemented_set +#define _dev_size_set prop_not_implemented_set +GET_PV_STR_PROPERTY_FN(pv_name, pv_name_dup(pv->vg->vgmem, pv)) +#define _pv_name_set prop_not_implemented_set GET_PV_NUM_PROPERTY_FN(pv_mda_free, SECTOR_SIZE * pv_mda_free(pv)) -#define _pv_mda_free_set _not_implemented_set +#define _pv_mda_free_set prop_not_implemented_set GET_PV_NUM_PROPERTY_FN(pv_mda_size, SECTOR_SIZE * pv_mda_size(pv)) -#define _pv_mda_size_set _not_implemented_set +#define _pv_mda_size_set prop_not_implemented_set GET_PV_NUM_PROPERTY_FN(pe_start, SECTOR_SIZE * pv->pe_start) -#define _pe_start_set _not_implemented_set +#define _pe_start_set prop_not_implemented_set GET_PV_NUM_PROPERTY_FN(pv_size, SECTOR_SIZE * pv_size_field(pv)) -#define _pv_size_set _not_implemented_set +#define _pv_size_set prop_not_implemented_set GET_PV_NUM_PROPERTY_FN(pv_free, SECTOR_SIZE * pv_free(pv)) -#define _pv_free_set _not_implemented_set +#define _pv_free_set prop_not_implemented_set GET_PV_NUM_PROPERTY_FN(pv_used, SECTOR_SIZE * pv_used(pv)) -#define _pv_used_set _not_implemented_set +#define _pv_used_set prop_not_implemented_set GET_PV_STR_PROPERTY_FN(pv_attr, pv_attr_dup(pv->vg->vgmem, pv)) -#define _pv_attr_set _not_implemented_set +#define _pv_attr_set prop_not_implemented_set GET_PV_NUM_PROPERTY_FN(pv_pe_count, pv->pe_count) -#define _pv_pe_count_set _not_implemented_set +#define _pv_pe_count_set prop_not_implemented_set GET_PV_NUM_PROPERTY_FN(pv_pe_alloc_count, pv->pe_alloc_count) -#define _pv_pe_alloc_count_set _not_implemented_set +#define _pv_pe_alloc_count_set prop_not_implemented_set GET_PV_STR_PROPERTY_FN(pv_tags, pv_tags_dup(pv)) -#define _pv_tags_set _not_implemented_set +#define _pv_tags_set prop_not_implemented_set GET_PV_NUM_PROPERTY_FN(pv_mda_count, pv_mda_count(pv)) -#define _pv_mda_count_set _not_implemented_set +#define _pv_mda_count_set prop_not_implemented_set GET_PV_NUM_PROPERTY_FN(pv_mda_used_count, pv_mda_used_count(pv)) -#define _pv_mda_used_count_set _not_implemented_set +#define _pv_mda_used_count_set prop_not_implemented_set +GET_PV_NUM_PROPERTY_FN(pv_ba_start, SECTOR_SIZE * pv->ba_start) +#define _pv_ba_start_set prop_not_implemented_set +GET_PV_NUM_PROPERTY_FN(pv_ba_size, SECTOR_SIZE * pv->ba_size) +#define _pv_ba_size_set prop_not_implemented_set +GET_PV_STR_PROPERTY_FN(pv_device_id, pv->device_id) +#define _pv_device_id_set prop_not_implemented_set +GET_PV_STR_PROPERTY_FN(pv_device_id_type, pv->device_id_type) +#define _pv_device_id_type_set prop_not_implemented_set + +#define _pv_allocatable_set prop_not_implemented_set +#define _pv_allocatable_get prop_not_implemented_get +#define _pv_exported_set prop_not_implemented_set +#define _pv_exported_get prop_not_implemented_get +#define _pv_missing_set prop_not_implemented_set +#define _pv_missing_get prop_not_implemented_get +#define _pv_ext_vsn_get prop_not_implemented_get +#define _pv_ext_vsn_set prop_not_implemented_set +#define _pv_in_use_get prop_not_implemented_get +#define _pv_in_use_set prop_not_implemented_set +#define _pv_duplicate_get prop_not_implemented_get +#define _pv_duplicate_set prop_not_implemented_set +#define _pv_major_get prop_not_implemented_get +#define _pv_major_set prop_not_implemented_set +#define _pv_minor_get prop_not_implemented_get +#define _pv_minor_set prop_not_implemented_set + +#define _vg_permissions_set prop_not_implemented_set +#define _vg_permissions_get prop_not_implemented_get +#define _vg_extendable_set prop_not_implemented_set +#define _vg_extendable_get prop_not_implemented_get +#define _vg_exported_set prop_not_implemented_set +#define _vg_exported_get prop_not_implemented_get +#define _vg_autoactivation_set prop_not_implemented_set +#define _vg_autoactivation_get prop_not_implemented_get +#define _vg_partial_set prop_not_implemented_set +#define _vg_partial_get prop_not_implemented_get +#define _vg_allocation_policy_set prop_not_implemented_set +#define _vg_allocation_policy_get prop_not_implemented_get +#define _vg_clustered_set prop_not_implemented_set +#define _vg_clustered_get prop_not_implemented_get +#define _vg_shared_set prop_not_implemented_set +#define _vg_shared_get prop_not_implemented_get + +#define _lv_layout_set prop_not_implemented_set +#define _lv_layout_get prop_not_implemented_get +#define _lv_role_set prop_not_implemented_set +#define _lv_role_get prop_not_implemented_get +#define _lv_initial_image_sync_set prop_not_implemented_set +#define _lv_initial_image_sync_get prop_not_implemented_get +#define _lv_image_synced_get prop_not_implemented_get +#define _lv_image_synced_set prop_not_implemented_set +#define _lv_image_synced_get prop_not_implemented_get +#define _lv_merging_set prop_not_implemented_set +#define _lv_merging_get prop_not_implemented_get +#define _lv_converting_set prop_not_implemented_set +#define _lv_converting_get prop_not_implemented_get +#define _lv_permissions_set prop_not_implemented_set +#define _lv_permissions_get prop_not_implemented_get +#define _lv_allocation_policy_set prop_not_implemented_set +#define _lv_allocation_policy_get prop_not_implemented_get +#define _lv_allocation_locked_set prop_not_implemented_set +#define _lv_allocation_locked_get prop_not_implemented_get +#define _lv_active_locally_set prop_not_implemented_set +#define _lv_active_locally_get prop_not_implemented_get +#define _lv_active_remotely_set prop_not_implemented_set +#define _lv_active_remotely_get prop_not_implemented_get +#define _lv_active_exclusively_set prop_not_implemented_set +#define _lv_active_exclusively_get prop_not_implemented_get +#define _lv_fixed_minor_set prop_not_implemented_set +#define _lv_fixed_minor_get prop_not_implemented_get +#define _lv_merge_failed_set prop_not_implemented_set +#define _lv_merge_failed_get prop_not_implemented_get +#define _lv_snapshot_invalid_set prop_not_implemented_set +#define _lv_snapshot_invalid_get prop_not_implemented_get +#define _lv_suspended_set prop_not_implemented_set +#define _lv_suspended_get prop_not_implemented_get +#define _lv_live_table_set prop_not_implemented_set +#define _lv_live_table_get prop_not_implemented_get +#define _lv_inactive_table_set prop_not_implemented_set +#define _lv_inactive_table_get prop_not_implemented_get +#define _lv_device_open_set prop_not_implemented_set +#define _lv_device_open_get prop_not_implemented_get +#define _lv_health_status_set prop_not_implemented_set +#define _lv_health_status_get prop_not_implemented_get +#define _lv_skip_activation_set prop_not_implemented_set +#define _lv_skip_activation_get prop_not_implemented_get +#define _lv_check_needed_set prop_not_implemented_set +#define _lv_check_needed_get prop_not_implemented_get +#define _lv_autoactivation_set prop_not_implemented_set +#define _lv_autoactivation_get prop_not_implemented_get +#define _lv_historical_set prop_not_implemented_set +#define _lv_historical_get prop_not_implemented_get + +#define _cache_total_blocks_set prop_not_implemented_set +#define _cache_total_blocks_get prop_not_implemented_get +#define _cache_used_blocks_set prop_not_implemented_set +#define _cache_used_blocks_get prop_not_implemented_get +#define _cache_dirty_blocks_set prop_not_implemented_set +#define _cache_dirty_blocks_get prop_not_implemented_get +#define _cache_read_hits_set prop_not_implemented_set +#define _cache_read_hits_get prop_not_implemented_get +#define _cache_read_misses_set prop_not_implemented_set +#define _cache_read_misses_get prop_not_implemented_get +#define _cache_write_hits_set prop_not_implemented_set +#define _cache_write_hits_get prop_not_implemented_get +#define _cache_write_misses_set prop_not_implemented_set +#define _cache_write_misses_get prop_not_implemented_get + +#define _writecache_total_blocks_set prop_not_implemented_set +#define _writecache_total_blocks_get prop_not_implemented_get +#define _writecache_free_blocks_set prop_not_implemented_set +#define _writecache_free_blocks_get prop_not_implemented_get +#define _writecache_writeback_blocks_set prop_not_implemented_set +#define _writecache_writeback_blocks_get prop_not_implemented_get +#define _writecache_error_set prop_not_implemented_set +#define _writecache_error_get prop_not_implemented_get +#define _writecache_block_size_set prop_not_implemented_set +#define _writecache_block_size_get prop_not_implemented_get + +#define _vdo_operating_mode_set prop_not_implemented_set +#define _vdo_operating_mode_get prop_not_implemented_get +#define _vdo_compression_state_set prop_not_implemented_set +#define _vdo_compression_state_get prop_not_implemented_get +#define _vdo_index_state_set prop_not_implemented_set +#define _vdo_index_state_get prop_not_implemented_get +#define _vdo_used_size_set prop_not_implemented_set +#define _vdo_used_size_get prop_not_implemented_get +#define _vdo_saving_percent_set prop_not_implemented_set +#define _vdo_saving_percent_get prop_not_implemented_get +#define _vdo_compression_set prop_not_implemented_set +#define _vdo_compression_get prop_not_implemented_get +#define _vdo_deduplication_set prop_not_implemented_set +#define _vdo_deduplication_get prop_not_implemented_get +#define _vdo_use_metadata_hints_set prop_not_implemented_set +#define _vdo_use_metadata_hints_get prop_not_implemented_get +#define _vdo_minimum_io_size_set prop_not_implemented_set +#define _vdo_minimum_io_size_get prop_not_implemented_get +#define _vdo_block_map_cache_size_set prop_not_implemented_set +#define _vdo_block_map_cache_size_get prop_not_implemented_get +#define _vdo_block_map_era_length_set prop_not_implemented_set +#define _vdo_block_map_era_length_get prop_not_implemented_get +#define _vdo_use_sparse_index_set prop_not_implemented_set +#define _vdo_use_sparse_index_get prop_not_implemented_get +#define _vdo_index_memory_size_set prop_not_implemented_set +#define _vdo_index_memory_size_get prop_not_implemented_get +#define _vdo_slab_size_set prop_not_implemented_set +#define _vdo_slab_size_get prop_not_implemented_get +#define _vdo_ack_threads_set prop_not_implemented_set +#define _vdo_ack_threads_get prop_not_implemented_get +#define _vdo_bio_threads_set prop_not_implemented_set +#define _vdo_bio_threads_get prop_not_implemented_get +#define _vdo_bio_rotation_set prop_not_implemented_set +#define _vdo_bio_rotation_get prop_not_implemented_get +#define _vdo_cpu_threads_set prop_not_implemented_set +#define _vdo_cpu_threads_get prop_not_implemented_get +#define _vdo_hash_zone_threads_set prop_not_implemented_set +#define _vdo_hash_zone_threads_get prop_not_implemented_get +#define _vdo_logical_threads_set prop_not_implemented_set +#define _vdo_logical_threads_get prop_not_implemented_get +#define _vdo_physical_threads_set prop_not_implemented_set +#define _vdo_physical_threads_get prop_not_implemented_get +#define _vdo_max_discard_set prop_not_implemented_set +#define _vdo_max_discard_get prop_not_implemented_get +#define _vdo_write_policy_set prop_not_implemented_set +#define _vdo_write_policy_get prop_not_implemented_get +#define _vdo_header_size_set prop_not_implemented_set +#define _vdo_header_size_get prop_not_implemented_get /* LV */ -GET_LV_STR_PROPERTY_FN(lv_uuid, lv_uuid_dup(lv)) -#define _lv_uuid_set _not_implemented_set +GET_LV_STR_PROPERTY_FN(lv_uuid, lv_uuid_dup(lv->vg->vgmem, lv)) +#define _lv_uuid_set prop_not_implemented_set GET_LV_STR_PROPERTY_FN(lv_name, lv_name_dup(lv->vg->vgmem, lv)) -#define _lv_name_set _not_implemented_set +#define _lv_name_set prop_not_implemented_set +GET_LV_STR_PROPERTY_FN(lv_full_name, lv_fullname_dup(lv->vg->vgmem, lv)) +#define _lv_full_name_set prop_not_implemented_set GET_LV_STR_PROPERTY_FN(lv_path, lv_path_dup(lv->vg->vgmem, lv)) -#define _lv_path_set _not_implemented_set +#define _lv_path_set prop_not_implemented_set +GET_LV_STR_PROPERTY_FN(lv_dm_path, lv_dmpath_dup(lv->vg->vgmem, lv)) +#define _lv_dm_path_set prop_not_implemented_set +GET_LV_STR_PROPERTY_FN(lv_parent, lv_parent_dup(lv->vg->vgmem, lv)) +#define _lv_parent_set prop_not_implemented_set GET_LV_STR_PROPERTY_FN(lv_attr, lv_attr_dup(lv->vg->vgmem, lv)) -#define _lv_attr_set _not_implemented_set +#define _lv_attr_set prop_not_implemented_set GET_LV_NUM_PROPERTY_FN(lv_major, lv->major) -#define _lv_major_set _not_implemented_set +#define _lv_major_set prop_not_implemented_set GET_LV_NUM_PROPERTY_FN(lv_minor, lv->minor) -#define _lv_minor_set _not_implemented_set +#define _lv_when_full_get prop_not_implemented_get +#define _lv_when_full_set prop_not_implemented_set +#define _lv_minor_set prop_not_implemented_set GET_LV_NUM_PROPERTY_FN(lv_read_ahead, lv->read_ahead * SECTOR_SIZE) -#define _lv_read_ahead_set _not_implemented_set +#define _lv_read_ahead_set prop_not_implemented_set GET_LV_NUM_PROPERTY_FN(lv_kernel_major, lv_kernel_major(lv)) -#define _lv_kernel_major_set _not_implemented_set +#define _lv_kernel_major_set prop_not_implemented_set GET_LV_NUM_PROPERTY_FN(lv_kernel_minor, lv_kernel_minor(lv)) -#define _lv_kernel_minor_set _not_implemented_set +#define _lv_kernel_minor_set prop_not_implemented_set GET_LV_NUM_PROPERTY_FN(lv_kernel_read_ahead, lv_kernel_read_ahead(lv) * SECTOR_SIZE) -#define _lv_kernel_read_ahead_set _not_implemented_set +#define _lv_kernel_read_ahead_set prop_not_implemented_set GET_LV_NUM_PROPERTY_FN(lv_size, lv->size * SECTOR_SIZE) -#define _lv_size_set _not_implemented_set +#define _lv_size_set prop_not_implemented_set GET_LV_NUM_PROPERTY_FN(seg_count, dm_list_size(&lv->segments)) -#define _seg_count_set _not_implemented_set +#define _seg_count_set prop_not_implemented_set GET_LV_STR_PROPERTY_FN(origin, lv_origin_dup(lv->vg->vgmem, lv)) -#define _origin_set _not_implemented_set -GET_LV_NUM_PROPERTY_FN(origin_size, lv_origin_size(lv)) -#define _origin_size_set _not_implemented_set +#define _origin_set prop_not_implemented_set +GET_LV_STR_PROPERTY_FN(origin_uuid, lv_origin_uuid_dup(lv->vg->vgmem, lv)) +#define _origin_uuid_set prop_not_implemented_set +GET_LV_NUM_PROPERTY_FN(origin_size, (SECTOR_SIZE * lv_origin_size(lv))) +#define _origin_size_set prop_not_implemented_set +#define _lv_ancestors_set prop_not_implemented_set +#define _lv_ancestors_get prop_not_implemented_get +#define _lv_full_ancestors_set prop_not_implemented_set +#define _lv_full_ancestors_get prop_not_implemented_get +#define _lv_descendants_set prop_not_implemented_set +#define _lv_descendants_get prop_not_implemented_get +#define _lv_full_descendants_set prop_not_implemented_set +#define _lv_full_descendants_get prop_not_implemented_get GET_LV_NUM_PROPERTY_FN(snap_percent, _snap_percent(lv)) -#define _snap_percent_set _not_implemented_set +#define _snap_percent_set prop_not_implemented_set GET_LV_NUM_PROPERTY_FN(copy_percent, _copy_percent(lv)) -#define _copy_percent_set _not_implemented_set +#define _copy_percent_set prop_not_implemented_set +GET_LV_NUM_PROPERTY_FN(sync_percent, _copy_percent(lv)) +#define _sync_percent_set prop_not_implemented_set +GET_LV_NUM_PROPERTY_FN(raid_mismatch_count, _raidmismatchcount(lv)) +#define _raid_mismatch_count_set prop_not_implemented_set +GET_LV_NUM_PROPERTY_FN(raid_write_behind, _raidwritebehind(lv)) +#define _raid_write_behind_set prop_not_implemented_set +GET_LV_NUM_PROPERTY_FN(raid_min_recovery_rate, _raidminrecoveryrate(lv)) +#define _raid_min_recovery_rate_set prop_not_implemented_set +GET_LV_NUM_PROPERTY_FN(raid_max_recovery_rate, _raidmaxrecoveryrate(lv)) +#define _raid_max_recovery_rate_set prop_not_implemented_set +GET_LV_STR_PROPERTY_FN(raid_sync_action, _raidsyncaction(lv)) +#define _raid_sync_action_set prop_not_implemented_set +GET_LV_STR_PROPERTY_FN(raidintegritymode, _raidintegritymode(lv)) +#define _raidintegritymode_set prop_not_implemented_set +GET_LV_NUM_PROPERTY_FN(raidintegrityblocksize, _raidintegrityblocksize(lv)) +#define _raidintegrityblocksize_set prop_not_implemented_set +GET_LV_NUM_PROPERTY_FN(integritymismatches, _integritymismatches(lv)) +#define _integritymismatches_set prop_not_implemented_set GET_LV_STR_PROPERTY_FN(move_pv, lv_move_pv_dup(lv->vg->vgmem, lv)) -#define _move_pv_set _not_implemented_set +#define _move_pv_set prop_not_implemented_set +GET_LV_STR_PROPERTY_FN(move_pv_uuid, lv_move_pv_uuid_dup(lv->vg->vgmem, lv)) +#define _move_pv_uuid_set prop_not_implemented_set GET_LV_STR_PROPERTY_FN(convert_lv, lv_convert_lv_dup(lv->vg->vgmem, lv)) -#define _convert_lv_set _not_implemented_set +#define _convert_lv_set prop_not_implemented_set +GET_LV_STR_PROPERTY_FN(convert_lv_uuid, lv_convert_lv_uuid_dup(lv->vg->vgmem, lv)) +#define _convert_lv_uuid_set prop_not_implemented_set GET_LV_STR_PROPERTY_FN(lv_tags, lv_tags_dup(lv)) -#define _lv_tags_set _not_implemented_set +#define _lv_tags_set prop_not_implemented_set GET_LV_STR_PROPERTY_FN(mirror_log, lv_mirror_log_dup(lv->vg->vgmem, lv)) -#define _mirror_log_set _not_implemented_set -GET_LV_STR_PROPERTY_FN(modules, lv_modules_dup(lv->vg->vgmem, lv)) -#define _modules_set _not_implemented_set +#define _mirror_log_set prop_not_implemented_set +GET_LV_STR_PROPERTY_FN(mirror_log_uuid, lv_mirror_log_uuid_dup(lv->vg->vgmem, lv)) +#define _mirror_log_uuid_set prop_not_implemented_set +GET_LV_STR_PROPERTY_FN(lv_modules, lv_modules_dup(lv->vg->vgmem, lv)) +#define _lv_modules_set prop_not_implemented_set GET_LV_STR_PROPERTY_FN(data_lv, lv_data_lv_dup(lv->vg->vgmem, lv)) -#define _data_lv_set _not_implemented_set +#define _data_lv_set prop_not_implemented_set +GET_LV_STR_PROPERTY_FN(data_lv_uuid, lv_data_lv_uuid_dup(lv->vg->vgmem, lv)) +#define _data_lv_uuid_set prop_not_implemented_set GET_LV_STR_PROPERTY_FN(metadata_lv, lv_metadata_lv_dup(lv->vg->vgmem, lv)) -#define _metadata_lv_set _not_implemented_set +#define _metadata_lv_set prop_not_implemented_set +GET_LV_STR_PROPERTY_FN(metadata_lv_uuid, lv_metadata_lv_uuid_dup(lv->vg->vgmem, lv)) +#define _metadata_lv_uuid_set prop_not_implemented_set GET_LV_STR_PROPERTY_FN(pool_lv, lv_pool_lv_dup(lv->vg->vgmem, lv)) -#define _pool_lv_set _not_implemented_set +#define _pool_lv_set prop_not_implemented_set +GET_LV_STR_PROPERTY_FN(pool_lv_uuid, lv_pool_lv_uuid_dup(lv->vg->vgmem, lv)) +#define _pool_lv_uuid_set prop_not_implemented_set GET_LV_NUM_PROPERTY_FN(data_percent, _data_percent(lv)) -#define _data_percent_set _not_implemented_set +#define _data_percent_set prop_not_implemented_set GET_LV_NUM_PROPERTY_FN(metadata_percent, _metadata_percent(lv)) -#define _metadata_percent_set _not_implemented_set +#define _metadata_percent_set prop_not_implemented_set GET_LV_NUM_PROPERTY_FN(lv_metadata_size, lv_metadata_size(lv) * SECTOR_SIZE) -#define _lv_metadata_size_set _not_implemented_set -GET_LV_STR_PROPERTY_FN(lv_time, lv_time_dup(lv->vg->vgmem, lv)) -#define _lv_time_set _not_implemented_set +#define _lv_metadata_size_set prop_not_implemented_set +GET_LV_STR_PROPERTY_FN(lv_time, lv_creation_time_dup(lv->vg->vgmem, lv, 0)) +#define _lv_time_set prop_not_implemented_set +GET_LV_STR_PROPERTY_FN(lv_time_removed, lv_removal_time_dup(lv->vg->vgmem, lv, 0)) +#define _lv_time_removed_set prop_not_implemented_set GET_LV_STR_PROPERTY_FN(lv_host, lv_host_dup(lv->vg->vgmem, lv)) -#define _lv_host_set _not_implemented_set +#define _lv_host_set prop_not_implemented_set +GET_LV_STR_PROPERTY_FN(lv_active, lv_active_dup(lv->vg->vgmem, lv)) +#define _lv_active_set prop_not_implemented_set +GET_LV_STR_PROPERTY_FN(lv_profile, lv_profile_dup(lv->vg->vgmem, lv)) +#define _lv_profile_set prop_not_implemented_set +GET_LV_STR_PROPERTY_FN(lv_lockargs, lv_lock_args_dup(lv->vg->vgmem, lv)) +#define _lv_lockargs_set prop_not_implemented_set /* VG */ GET_VG_STR_PROPERTY_FN(vg_fmt, vg_fmt_dup(vg)) -#define _vg_fmt_set _not_implemented_set +#define _vg_fmt_set prop_not_implemented_set GET_VG_STR_PROPERTY_FN(vg_uuid, vg_uuid_dup(vg)) -#define _vg_uuid_set _not_implemented_set +#define _vg_uuid_set prop_not_implemented_set GET_VG_STR_PROPERTY_FN(vg_name, vg_name_dup(vg)) -#define _vg_name_set _not_implemented_set +#define _vg_name_set prop_not_implemented_set GET_VG_STR_PROPERTY_FN(vg_attr, vg_attr_dup(vg->vgmem, vg)) -#define _vg_attr_set _not_implemented_set +#define _vg_attr_set prop_not_implemented_set GET_VG_NUM_PROPERTY_FN(vg_size, (SECTOR_SIZE * vg_size(vg))) -#define _vg_size_set _not_implemented_set +#define _vg_size_set prop_not_implemented_set GET_VG_NUM_PROPERTY_FN(vg_free, (SECTOR_SIZE * vg_free(vg))) -#define _vg_free_set _not_implemented_set +#define _vg_free_set prop_not_implemented_set GET_VG_STR_PROPERTY_FN(vg_sysid, vg_system_id_dup(vg)) -#define _vg_sysid_set _not_implemented_set -GET_VG_NUM_PROPERTY_FN(vg_extent_size, vg->extent_size) -#define _vg_extent_size_set _not_implemented_set +#define _vg_sysid_set prop_not_implemented_set +GET_VG_STR_PROPERTY_FN(vg_systemid, vg_system_id_dup(vg)) +#define _vg_systemid_set prop_not_implemented_set +GET_VG_STR_PROPERTY_FN(vg_lock_type, vg_lock_type_dup(vg)) +#define _vg_lock_type_set prop_not_implemented_set +GET_VG_STR_PROPERTY_FN(vg_lock_args, vg_lock_args_dup(vg)) +#define _vg_lock_args_set prop_not_implemented_set +GET_VG_NUM_PROPERTY_FN(vg_extent_size, (SECTOR_SIZE * vg->extent_size)) +#define _vg_extent_size_set prop_not_implemented_set GET_VG_NUM_PROPERTY_FN(vg_extent_count, vg->extent_count) -#define _vg_extent_count_set _not_implemented_set +#define _vg_extent_count_set prop_not_implemented_set GET_VG_NUM_PROPERTY_FN(vg_free_count, vg->free_count) -#define _vg_free_count_set _not_implemented_set +#define _vg_free_count_set prop_not_implemented_set GET_VG_NUM_PROPERTY_FN(max_lv, vg->max_lv) -#define _max_lv_set _not_implemented_set +#define _max_lv_set prop_not_implemented_set GET_VG_NUM_PROPERTY_FN(max_pv, vg->max_pv) -#define _max_pv_set _not_implemented_set +#define _max_pv_set prop_not_implemented_set GET_VG_NUM_PROPERTY_FN(pv_count, vg->pv_count) -#define _pv_count_set _not_implemented_set +#define _pv_count_set prop_not_implemented_set GET_VG_NUM_PROPERTY_FN(lv_count, (vg_visible_lvs(vg))) -#define _lv_count_set _not_implemented_set +#define _lv_count_set prop_not_implemented_set GET_VG_NUM_PROPERTY_FN(snap_count, (snapshot_count(vg))) -#define _snap_count_set _not_implemented_set +#define _snap_count_set prop_not_implemented_set GET_VG_NUM_PROPERTY_FN(vg_seqno, vg->seqno) -#define _vg_seqno_set _not_implemented_set +#define _vg_seqno_set prop_not_implemented_set GET_VG_STR_PROPERTY_FN(vg_tags, vg_tags_dup(vg)) -#define _vg_tags_set _not_implemented_set +#define _vg_tags_set prop_not_implemented_set GET_VG_NUM_PROPERTY_FN(vg_mda_count, (vg_mda_count(vg))) -#define _vg_mda_count_set _not_implemented_set +#define _vg_mda_count_set prop_not_implemented_set GET_VG_NUM_PROPERTY_FN(vg_mda_used_count, (vg_mda_used_count(vg))) -#define _vg_mda_used_count_set _not_implemented_set +#define _vg_mda_used_count_set prop_not_implemented_set GET_VG_NUM_PROPERTY_FN(vg_mda_free, (SECTOR_SIZE * vg_mda_free(vg))) -#define _vg_mda_free_set _not_implemented_set +#define _vg_mda_free_set prop_not_implemented_set GET_VG_NUM_PROPERTY_FN(vg_mda_size, (SECTOR_SIZE * vg_mda_size(vg))) -#define _vg_mda_size_set _not_implemented_set +#define _vg_mda_size_set prop_not_implemented_set GET_VG_NUM_PROPERTY_FN(vg_mda_copies, (vg_mda_copies(vg))) SET_VG_NUM_PROPERTY_FN(vg_mda_copies, vg_set_mda_copies) +GET_VG_STR_PROPERTY_FN(vg_profile, vg_profile_dup(vg)) +#define _vg_profile_set prop_not_implemented_set +GET_VG_NUM_PROPERTY_FN(vg_missing_pv_count, vg_missing_pv_count(vg)) +#define _vg_missing_pv_count_set prop_not_implemented_set /* LVSEG */ GET_LVSEG_STR_PROPERTY_FN(segtype, lvseg_segtype_dup(lvseg->lv->vg->vgmem, lvseg)) -#define _segtype_set _not_implemented_set +#define _segtype_set prop_not_implemented_set +GET_LVSEG_NUM_PROPERTY_FN(data_copies, lvseg->data_copies) +#define _data_copies_set prop_not_implemented_set +GET_LVSEG_NUM_PROPERTY_FN(reshape_len, lvseg->reshape_len) +#define _reshape_len_set prop_not_implemented_set +GET_LVSEG_NUM_PROPERTY_FN(reshape_len_le, lvseg->reshape_len) +#define _reshape_len_le_set prop_not_implemented_set +GET_LVSEG_NUM_PROPERTY_FN(data_offset, lvseg->data_offset) +#define _data_offset_set prop_not_implemented_set +GET_LVSEG_NUM_PROPERTY_FN(new_data_offset, lvseg->data_offset) +#define _new_data_offset_set prop_not_implemented_set +GET_LVSEG_NUM_PROPERTY_FN(parity_chunks, lvseg->data_offset) +#define _parity_chunks_set prop_not_implemented_set GET_LVSEG_NUM_PROPERTY_FN(stripes, lvseg->area_count) -#define _stripes_set _not_implemented_set -GET_LVSEG_NUM_PROPERTY_FN(stripesize, lvseg->stripe_size) -#define _stripesize_set _not_implemented_set -GET_LVSEG_NUM_PROPERTY_FN(stripe_size, lvseg->stripe_size) -#define _stripe_size_set _not_implemented_set -GET_LVSEG_NUM_PROPERTY_FN(regionsize, lvseg->region_size) -#define _regionsize_set _not_implemented_set -GET_LVSEG_NUM_PROPERTY_FN(region_size, lvseg->region_size) -#define _region_size_set _not_implemented_set -GET_LVSEG_NUM_PROPERTY_FN(chunksize, lvseg_chunksize(lvseg)) -#define _chunksize_set _not_implemented_set -GET_LVSEG_NUM_PROPERTY_FN(chunk_size, lvseg_chunksize(lvseg)) -#define _chunk_size_set _not_implemented_set +#define _stripes_set prop_not_implemented_set +GET_LVSEG_NUM_PROPERTY_FN(data_stripes, lvseg->area_count) +#define _data_stripes_set prop_not_implemented_set +GET_LVSEG_NUM_PROPERTY_FN(stripe_size, (SECTOR_SIZE * lvseg->stripe_size)) +#define _stripe_size_set prop_not_implemented_set +GET_LVSEG_NUM_PROPERTY_FN(region_size, (SECTOR_SIZE * lvseg->region_size)) +#define _region_size_set prop_not_implemented_set +GET_LVSEG_NUM_PROPERTY_FN(chunk_size, (SECTOR_SIZE * lvseg_chunksize(lvseg))) +#define _chunk_size_set prop_not_implemented_set GET_LVSEG_NUM_PROPERTY_FN(thin_count, dm_list_size(&lvseg->lv->segs_using_this_lv)) -#define _thin_count_set _not_implemented_set -GET_LVSEG_NUM_PROPERTY_FN(zero, lvseg->zero_new_blocks) -#define _zero_set _not_implemented_set +#define _thin_count_set prop_not_implemented_set +GET_LVSEG_NUM_PROPERTY_FN(zero, (lvseg->zero_new_blocks == THIN_ZERO_YES)) +#define _zero_set prop_not_implemented_set GET_LVSEG_NUM_PROPERTY_FN(transaction_id, lvseg->transaction_id) -#define _transaction_id_set _not_implemented_set -GET_LVSEG_NUM_PROPERTY_FN(discards, lvseg->discards) -#define _discards_set _not_implemented_set -GET_LVSEG_NUM_PROPERTY_FN(seg_start, lvseg_start(lvseg)) -#define _seg_start_set _not_implemented_set +#define _transaction_id_set prop_not_implemented_set +GET_LVSEG_NUM_PROPERTY_FN(thin_id, lvseg->device_id) +#define _thin_id_set prop_not_implemented_set +GET_LVSEG_STR_PROPERTY_FN(discards, lvseg_discards_dup(lvseg->lv->vg->vgmem, lvseg)) +#define _discards_set prop_not_implemented_set +GET_LVSEG_STR_PROPERTY_FN(kernel_discards, lvseg_kernel_discards_dup(lvseg->lv->vg->vgmem, lvseg)) +#define _kernel_discards_set prop_not_implemented_set +GET_LVSEG_STR_PROPERTY_FN(cache_mode, lvseg_cachemode_dup(lvseg->lv->vg->vgmem, lvseg)) +#define _cache_mode_set prop_not_implemented_set +GET_LVSEG_NUM_PROPERTY_FN(cache_metadata_format, lvseg->cache_metadata_format) +#define _cache_metadata_format_set prop_not_implemented_set +GET_LVSEG_NUM_PROPERTY_FN(seg_start, (SECTOR_SIZE * lvseg_start(lvseg))) +#define _seg_start_set prop_not_implemented_set GET_LVSEG_NUM_PROPERTY_FN(seg_start_pe, lvseg->le) -#define _seg_start_pe_set _not_implemented_set +#define _seg_start_pe_set prop_not_implemented_set GET_LVSEG_NUM_PROPERTY_FN(seg_size, (SECTOR_SIZE * lvseg_size(lvseg))) -#define _seg_size_set _not_implemented_set +#define _seg_size_set prop_not_implemented_set +GET_LVSEG_NUM_PROPERTY_FN(seg_size_pe, lvseg->len) +#define _seg_size_pe_set prop_not_implemented_set GET_LVSEG_STR_PROPERTY_FN(seg_tags, lvseg_tags_dup(lvseg)) -#define _seg_tags_set _not_implemented_set -GET_LVSEG_STR_PROPERTY_FN(seg_pe_ranges, - lvseg_seg_pe_ranges(lvseg->lv->vg->vgmem, lvseg)) -#define _seg_pe_ranges_set _not_implemented_set -GET_LVSEG_STR_PROPERTY_FN(devices, lvseg_devices(lvseg->lv->vg->vgmem, lvseg)) -#define _devices_set _not_implemented_set - +#define _seg_tags_set prop_not_implemented_set +GET_LVSEG_STR_PROPERTY_FN(seg_pe_ranges, lvseg_seg_pe_ranges_str(lvseg->lv->vg->vgmem, lvseg)) +#define _seg_pe_ranges_set prop_not_implemented_set +GET_LVSEG_STR_PROPERTY_FN(seg_le_ranges, lvseg_seg_le_ranges_str(lvseg->lv->vg->vgmem, lvseg)) +#define _seg_le_ranges_set prop_not_implemented_set +GET_LVSEG_STR_PROPERTY_FN(seg_metadata_le_ranges, lvseg_seg_metadata_le_ranges_str(lvseg->lv->vg->vgmem, lvseg)) +#define _seg_metadata_le_ranges_set prop_not_implemented_set +GET_LVSEG_STR_PROPERTY_FN(devices, lvseg_devices_str(lvseg->lv->vg->vgmem, lvseg)) +#define _devices_set prop_not_implemented_set +GET_LVSEG_STR_PROPERTY_FN(metadata_devices, lvseg_metadata_devices_str(lvseg->lv->vg->vgmem, lvseg)) +#define _metadata_devices_set prop_not_implemented_set +GET_LVSEG_STR_PROPERTY_FN(seg_monitor, lvseg_monitor_dup(lvseg->lv->vg->vgmem, lvseg)) +#define _seg_monitor_set prop_not_implemented_set + +#define _cache_policy_get prop_not_implemented_get +#define _cache_policy_set prop_not_implemented_set +#define _cache_settings_get prop_not_implemented_get +#define _cache_settings_set prop_not_implemented_set +#define _kernel_cache_settings_get prop_not_implemented_get +#define _kernel_cache_settings_set prop_not_implemented_set +#define _kernel_cache_policy_get prop_not_implemented_get +#define _kernel_cache_policy_set prop_not_implemented_set +#define _kernel_metadata_format_get prop_not_implemented_get +#define _kernel_metadata_format_set prop_not_implemented_set /* PVSEG */ GET_PVSEG_NUM_PROPERTY_FN(pvseg_start, pvseg->pe) -#define _pvseg_start_set _not_implemented_set -GET_PVSEG_NUM_PROPERTY_FN(pvseg_size, pvseg->len) -#define _pvseg_size_set _not_implemented_set +#define _pvseg_start_set prop_not_implemented_set +GET_PVSEG_NUM_PROPERTY_FN(pvseg_size, (SECTOR_SIZE * pvseg->len)) +#define _pvseg_size_set prop_not_implemented_set -#define STR DM_REPORT_FIELD_TYPE_STRING -#define NUM DM_REPORT_FIELD_TYPE_NUMBER -#define FIELD(type, strct, sorttype, head, field, width, fn, id, desc, settable) \ - { type, #id, settable, sorttype == STR, sorttype == NUM, { .integer = 0 }, _ ## id ## _get, _ ## id ## _set }, - struct lvm_property_type _properties[] = { #include "columns.h" - { 0, "", 0, 0, 0, { .integer = 0 }, _not_implemented_get, _not_implemented_set }, + { 0, "", 0, 0, 0, 0, { .integer = 0 }, prop_not_implemented_get, prop_not_implemented_set }, }; #undef STR #undef NUM +#undef BIN +#undef SIZ +#undef PCT +#undef STR_LIST +#undef SNUM #undef FIELD - -static int _get_property(const void *obj, struct lvm_property_type *prop, - unsigned type) -{ - struct lvm_property_type *p; - - p = _properties; - while (p->id[0]) { - if (!strcmp(p->id, prop->id)) - break; - p++; - } - if (!p->id[0]) { - log_errno(EINVAL, "Invalid property name %s", prop->id); - return 0; - } - if (!(p->type & type)) { - log_errno(EINVAL, "Property name %s does not match type %d", - prop->id, p->type); - return 0; - } - - *prop = *p; - if (!p->get(obj, prop)) { - return 0; - } - return 1; -} - -static int _set_property(void *obj, struct lvm_property_type *prop, - unsigned type) -{ - struct lvm_property_type *p; - - p = _properties; - while (p->id[0]) { - if (!strcmp(p->id, prop->id)) - break; - p++; - } - if (!p->id[0]) { - log_errno(EINVAL, "Invalid property name %s", prop->id); - return 0; - } - if (!p->is_settable) { - log_errno(EINVAL, "Unable to set read-only property %s", - prop->id); - return 0; - } - if (!(p->type & type)) { - log_errno(EINVAL, "Property name %s does not match type %d", - prop->id, p->type); - return 0; - } - - if (p->is_string) - p->value.string = prop->value.string; - else - p->value.integer = prop->value.integer; - if (!p->set(obj, p)) { - return 0; - } - return 1; -} - int lvseg_get_property(const struct lv_segment *lvseg, struct lvm_property_type *prop) { - return _get_property(lvseg, prop, SEGS); + return prop_get_property(_properties, lvseg, prop, SEGS); } int lv_get_property(const struct logical_volume *lv, struct lvm_property_type *prop) { - return _get_property(lv, prop, LVS); + return prop_get_property(_properties, lv, prop, LVS | LVSINFO | LVSSTATUS | LVSINFOSTATUS); } int vg_get_property(const struct volume_group *vg, struct lvm_property_type *prop) { - return _get_property(vg, prop, VGS); + return prop_get_property(_properties, vg, prop, VGS); } int pvseg_get_property(const struct pv_segment *pvseg, struct lvm_property_type *prop) { - return _get_property(pvseg, prop, PVSEGS); + return prop_get_property(_properties, pvseg, prop, PVSEGS); } int pv_get_property(const struct physical_volume *pv, struct lvm_property_type *prop) { - return _get_property(pv, prop, PVS | LABEL); + return prop_get_property(_properties, pv, prop, PVS | LABEL); } int lv_set_property(struct logical_volume *lv, struct lvm_property_type *prop) { - return _set_property(lv, prop, LVS); + return prop_set_property(_properties, lv, prop, LVS | LVSINFO | LVSSTATUS | LVSINFOSTATUS); } int vg_set_property(struct volume_group *vg, struct lvm_property_type *prop) { - return _set_property(vg, prop, VGS); + return prop_set_property(_properties, vg, prop, VGS); } int pv_set_property(struct physical_volume *pv, struct lvm_property_type *prop) { - return _set_property(pv, prop, PVS | LABEL); + return prop_set_property(_properties, pv, prop, PVS | LABEL); } diff --git a/lib/report/properties.h b/lib/report/properties.h index aefd3f5..3d93b08 100644 --- a/lib/report/properties.h +++ b/lib/report/properties.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Red Hat, Inc. All rights reserved. + * Copyright (C) 2010-2013 Red Hat, Inc. All rights reserved. * * This file is part of LVM2. * @@ -9,29 +9,15 @@ * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _LVM_PROPERTIES_H #define _LVM_PROPERTIES_H -#include "libdevmapper.h" -#include "lvm-types.h" -#include "metadata.h" -#include "report.h" - -struct lvm_property_type { - unsigned type; - const char *id; - unsigned is_settable:1; - unsigned is_string:1; - unsigned is_integer:1; - union { - const char *string; - uint64_t integer; - } value; - int (*get) (const void *obj, struct lvm_property_type *prop); - int (*set) (void *obj, struct lvm_property_type *prop); -}; +#include "device_mapper/all.h" +#include "lib/metadata/metadata.h" +#include "lib/report/report.h" +#include "lib/properties/prop_common.h" int lvseg_get_property(const struct lv_segment *lvseg, struct lvm_property_type *prop); diff --git a/lib/report/report.c b/lib/report/report.c index eeca282..dbbb369 100644 --- a/lib/report/report.c +++ b/lib/report/report.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved. - * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved. + * Copyright (C) 2004-2019 Red Hat, Inc. All rights reserved. * * This file is part of LVM2. * @@ -10,35 +10,1299 @@ * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "lib.h" -#include "metadata.h" -#include "report.h" -#include "toolcontext.h" -#include "lvm-string.h" -#include "display.h" -#include "activate.h" -#include "segtype.h" -#include "lvmcache.h" +#include "lib/misc/lib.h" +#include "lib/metadata/metadata.h" +#include "lib/report/report.h" +#include "lib/commands/toolcontext.h" +#include "lib/misc/lvm-string.h" +#include "lib/display/display.h" +#include "lib/activate/activate.h" +#include "lib/metadata/segtype.h" +#include "lib/cache/lvmcache.h" +#include "lib/device/device-types.h" +#include "lib/datastruct/str_list.h" +#include "lib/locking/lvmlockd.h" #include <stddef.h> /* offsetof() */ +#include <float.h> /* DBL_MAX */ +#include <time.h> + +/* + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + * IMPORTANT NOTE ABOUT ADDING A NEW VALUE FOR REPORTING + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + * + * When adding a new string value to report, try to keep it + * self-descriptive so when it's printed even without the header, + * we can still deduce what it is actually reporting. + * + * If you need more than one descriptive string to mean the same value, + * please define them as reserved values in values.h. + * + * The first reserved value is the one that is printed in reports (unless + * it's a binary value and we have report/binary_values_as_numeric=1 config + * option used OR --binary command line option is used OR we're using an + * output format which must always print binary values in numeric way, + * like json_std output format. + * + * All the other (2nd and further) listed reserved names are synonyms which + * may be also used in selection (-S|--select). + * + * Also, always use proper *_disp functions to display each type of value + * properly. For example, in case of binary values, you should use + * _binary_disp so that we can always switch between numerical (0/1/-1) and + * string representation while reporting the value. + */ struct lvm_report_object { struct volume_group *vg; - struct logical_volume *lv; + struct lv_with_info_and_seg_status *lvdm; struct physical_volume *pv; struct lv_segment *seg; struct pv_segment *pvseg; + struct label *label; +}; + +static uint32_t _log_seqnum = 1; + +/* + * Enum for field_num index to use in per-field reserved value definition. + * Each field is represented by enum value with name "field_<id>" where <id> + * is the field_id of the field as registered in columns.h. + */ +#define FIELD(type, strct, sorttype, head, field_name, width, func, id, desc, writeable) field_ ## id, +enum { +/* coverity[unnecessary_header] */ +#include "columns.h" +}; +#undef FIELD + +static const uint64_t _zero64 = UINT64_C(0); +static const uint64_t _one64 = UINT64_C(1); +static const uint64_t _two64 = UINT64_C(2); +static const char _str_zero[] = "0"; +static const char _str_one[] = "1"; +static const char _str_no[] = "no"; +static const char _str_yes[] = "yes"; +static const char _str_unknown[] = "unknown"; +static const double _siz_max = DBL_MAX; + +/* + * 32 bit signed is casted to 64 bit unsigned in dm_report_field internally! + * So when stored in the struct, the _reserved_num_undef_32 is actually + * equal to _reserved_num_undef_64. + */ +static const int32_t _reserved_num_undef_32 = INT32_C(-1); + +typedef enum { + /* top-level identification */ + TIME_NULL, + TIME_NUM, + TIME_STR, + + /* direct numeric value */ + TIME_NUM__START, + TIME_NUM_MULTIPLIER, + TIME_NUM_MULTIPLIER_NEGATIVE, + TIME_NUM_DAY, + TIME_NUM_YEAR, + TIME_NUM__END, + + /* direct string value */ + TIME_STR_TIMEZONE, + + /* time frame strings */ + TIME_FRAME__START, + TIME_FRAME_AGO, + TIME_FRAME__END, + + /* labels for dates */ + TIME_LABEL_DATE__START, + + TIME_LABEL_DATE_TODAY, + TIME_LABEL_DATE_YESTERDAY, + + /* weekday name strings */ + TIME_WEEKDAY__START, + TIME_WEEKDAY_SUNDAY, + TIME_WEEKDAY_MONDAY, + TIME_WEEKDAY_TUESDAY, + TIME_WEEKDAY_WEDNESDAY, + TIME_WEEKDAY_THURSDAY, + TIME_WEEKDAY_FRIDAY, + TIME_WEEKDAY_SATURDAY, + TIME_WEEKDAY__END, + + TIME_LABEL_DATE__END, + + /* labels for times */ + TIME_LABEL_TIME__START, + TIME_LABEL_TIME_NOON, + TIME_LABEL_TIME_MIDNIGHT, + TIME_LABEL_TIME__END, + + /* time unit strings */ + TIME_UNIT__START, + TIME_UNIT_SECOND, + TIME_UNIT_SECOND_REL, + TIME_UNIT_MINUTE, + TIME_UNIT_MINUTE_REL, + TIME_UNIT_HOUR, + TIME_UNIT_HOUR_REL, + TIME_UNIT_AM, + TIME_UNIT_PM, + TIME_UNIT_DAY, + TIME_UNIT_WEEK, + TIME_UNIT_MONTH, + TIME_UNIT_YEAR, + TIME_UNIT_TZ_MINUTE, + TIME_UNIT_TZ_HOUR, + TIME_UNIT__END, + + /* month name strings */ + TIME_MONTH__START, + TIME_MONTH_JANUARY, + TIME_MONTH_FEBRUARY, + TIME_MONTH_MARCH, + TIME_MONTH_APRIL, + TIME_MONTH_MAY, + TIME_MONTH_JUNE, + TIME_MONTH_JULY, + TIME_MONTH_AUGUST, + TIME_MONTH_SEPTEMBER, + TIME_MONTH_OCTOBER, + TIME_MONTH_NOVEMBER, + TIME_MONTH_DECEMBER, + TIME_MONTH__END, +} time_id_t; + +#define TIME_PROP_DATE 0x00000001 /* date-related */ +#define TIME_PROP_TIME 0x00000002 /* time-related */ +#define TIME_PROP_ABS 0x00000004 /* absolute value */ +#define TIME_PROP_REL 0x00000008 /* relative value */ + +struct time_prop { + time_id_t id; + uint32_t prop_flags; + time_id_t granularity; +}; + +#define ADD_TIME_PROP(id, flags, granularity) [(id)] = {(id), (flags), (granularity)}, + +static const struct time_prop _time_props[] = { + ADD_TIME_PROP(TIME_NULL, 0, TIME_NULL) + ADD_TIME_PROP(TIME_NUM, 0, TIME_NULL) + ADD_TIME_PROP(TIME_STR, 0, TIME_NULL) + + ADD_TIME_PROP(TIME_NUM_MULTIPLIER, 0, TIME_NULL) + ADD_TIME_PROP(TIME_NUM_MULTIPLIER_NEGATIVE, 0, TIME_NULL) + ADD_TIME_PROP(TIME_NUM_DAY, TIME_PROP_DATE | TIME_PROP_ABS, TIME_UNIT_DAY) + ADD_TIME_PROP(TIME_NUM_YEAR, TIME_PROP_DATE | TIME_PROP_ABS, TIME_UNIT_YEAR) + + ADD_TIME_PROP(TIME_STR_TIMEZONE, TIME_PROP_TIME | TIME_PROP_ABS, TIME_NULL) + + ADD_TIME_PROP(TIME_FRAME_AGO, TIME_PROP_DATE | TIME_PROP_TIME | TIME_PROP_REL, TIME_NULL) + + ADD_TIME_PROP(TIME_LABEL_DATE_TODAY, TIME_PROP_DATE | TIME_PROP_ABS, TIME_UNIT_DAY) + ADD_TIME_PROP(TIME_LABEL_DATE_YESTERDAY, TIME_PROP_DATE | TIME_PROP_ABS, TIME_UNIT_DAY) + ADD_TIME_PROP(TIME_WEEKDAY_SUNDAY, TIME_PROP_DATE | TIME_PROP_ABS, TIME_UNIT_DAY) + ADD_TIME_PROP(TIME_WEEKDAY_MONDAY, TIME_PROP_DATE | TIME_PROP_ABS, TIME_UNIT_DAY) + ADD_TIME_PROP(TIME_WEEKDAY_TUESDAY, TIME_PROP_DATE | TIME_PROP_ABS, TIME_UNIT_DAY) + ADD_TIME_PROP(TIME_WEEKDAY_WEDNESDAY, TIME_PROP_DATE | TIME_PROP_ABS, TIME_UNIT_DAY) + ADD_TIME_PROP(TIME_WEEKDAY_THURSDAY, TIME_PROP_DATE | TIME_PROP_ABS, TIME_UNIT_DAY) + ADD_TIME_PROP(TIME_WEEKDAY_FRIDAY, TIME_PROP_DATE | TIME_PROP_ABS, TIME_UNIT_DAY) + ADD_TIME_PROP(TIME_WEEKDAY_SATURDAY, TIME_PROP_DATE | TIME_PROP_ABS, TIME_UNIT_DAY) + + ADD_TIME_PROP(TIME_LABEL_TIME_NOON, TIME_PROP_TIME | TIME_PROP_ABS, TIME_UNIT_SECOND) + ADD_TIME_PROP(TIME_LABEL_TIME_MIDNIGHT, TIME_PROP_TIME | TIME_PROP_ABS, TIME_UNIT_SECOND) + + ADD_TIME_PROP(TIME_UNIT_SECOND, TIME_PROP_TIME | TIME_PROP_ABS, TIME_UNIT_SECOND) + ADD_TIME_PROP(TIME_UNIT_SECOND_REL, TIME_PROP_TIME | TIME_PROP_REL, TIME_UNIT_SECOND) + ADD_TIME_PROP(TIME_UNIT_MINUTE, TIME_PROP_TIME | TIME_PROP_ABS, TIME_UNIT_MINUTE) + ADD_TIME_PROP(TIME_UNIT_MINUTE_REL, TIME_PROP_TIME | TIME_PROP_REL, TIME_UNIT_MINUTE) + ADD_TIME_PROP(TIME_UNIT_HOUR, TIME_PROP_TIME | TIME_PROP_ABS, TIME_UNIT_HOUR) + ADD_TIME_PROP(TIME_UNIT_HOUR_REL, TIME_PROP_TIME | TIME_PROP_REL, TIME_UNIT_HOUR) + ADD_TIME_PROP(TIME_UNIT_AM, TIME_PROP_TIME | TIME_PROP_ABS, TIME_UNIT_HOUR) + ADD_TIME_PROP(TIME_UNIT_PM, TIME_PROP_TIME | TIME_PROP_ABS, TIME_UNIT_HOUR) + ADD_TIME_PROP(TIME_UNIT_DAY, TIME_PROP_DATE | TIME_PROP_REL, TIME_UNIT_DAY) + ADD_TIME_PROP(TIME_UNIT_WEEK, TIME_PROP_DATE | TIME_PROP_REL, TIME_UNIT_WEEK) + ADD_TIME_PROP(TIME_UNIT_MONTH, TIME_PROP_DATE | TIME_PROP_REL, TIME_UNIT_MONTH) + ADD_TIME_PROP(TIME_UNIT_YEAR, TIME_PROP_DATE | TIME_PROP_REL, TIME_UNIT_YEAR) + ADD_TIME_PROP(TIME_UNIT_TZ_MINUTE, TIME_PROP_TIME | TIME_PROP_ABS, TIME_NULL) + ADD_TIME_PROP(TIME_UNIT_TZ_HOUR, TIME_PROP_TIME | TIME_PROP_ABS, TIME_NULL) + + ADD_TIME_PROP(TIME_MONTH_JANUARY, TIME_PROP_DATE | TIME_PROP_ABS, TIME_UNIT_MONTH) + ADD_TIME_PROP(TIME_MONTH_FEBRUARY, TIME_PROP_DATE | TIME_PROP_ABS, TIME_UNIT_MONTH) + ADD_TIME_PROP(TIME_MONTH_MARCH, TIME_PROP_DATE | TIME_PROP_ABS, TIME_UNIT_MONTH) + ADD_TIME_PROP(TIME_MONTH_APRIL, TIME_PROP_DATE | TIME_PROP_ABS, TIME_UNIT_MONTH) + ADD_TIME_PROP(TIME_MONTH_MAY, TIME_PROP_DATE | TIME_PROP_ABS, TIME_UNIT_MONTH) + ADD_TIME_PROP(TIME_MONTH_JUNE, TIME_PROP_DATE | TIME_PROP_ABS, TIME_UNIT_MONTH) + ADD_TIME_PROP(TIME_MONTH_JULY, TIME_PROP_DATE | TIME_PROP_ABS, TIME_UNIT_MONTH) + ADD_TIME_PROP(TIME_MONTH_AUGUST, TIME_PROP_DATE | TIME_PROP_ABS, TIME_UNIT_MONTH) + ADD_TIME_PROP(TIME_MONTH_SEPTEMBER, TIME_PROP_DATE | TIME_PROP_ABS, TIME_UNIT_MONTH) + ADD_TIME_PROP(TIME_MONTH_OCTOBER, TIME_PROP_DATE | TIME_PROP_ABS, TIME_UNIT_MONTH) + ADD_TIME_PROP(TIME_MONTH_NOVEMBER, TIME_PROP_DATE | TIME_PROP_ABS, TIME_UNIT_MONTH) + ADD_TIME_PROP(TIME_MONTH_DECEMBER, TIME_PROP_DATE | TIME_PROP_ABS, TIME_UNIT_MONTH) +}; + +#define TIME_REG_PLURAL_S 0x00000001 /* also recognize plural form with "s" suffix */ + +struct time_reg { + const char *name; + const struct time_prop *prop; + uint32_t reg_flags; +}; + +#define TIME_PROP(id) (_time_props + (id)) + +static const struct time_reg _time_reg[] = { + /* + * Group of tokens representing time frame and used + * with relative date/time to specify different flavours + * of relativity. + */ + {"ago", TIME_PROP(TIME_FRAME_AGO), 0}, + + /* + * Group of tokens labeling some date and used + * instead of direct absolute specification. + */ + {"today", TIME_PROP(TIME_LABEL_DATE_TODAY), 0}, /* 0:00 - 23:59:59 for current date */ + {"yesterday", TIME_PROP(TIME_LABEL_DATE_YESTERDAY), 0}, /* 0:00 - 23:59:59 for current date minus 1 day*/ + + /* + * Group of tokens labeling some date - weekday + * names used to build up date. + */ + {"Sunday", TIME_PROP(TIME_WEEKDAY_SUNDAY), TIME_REG_PLURAL_S}, + {"Sun", TIME_PROP(TIME_WEEKDAY_SUNDAY), 0}, + {"Monday", TIME_PROP(TIME_WEEKDAY_MONDAY), TIME_REG_PLURAL_S}, + {"Mon", TIME_PROP(TIME_WEEKDAY_MONDAY), 0}, + {"Tuesday", TIME_PROP(TIME_WEEKDAY_TUESDAY), TIME_REG_PLURAL_S}, + {"Tue", TIME_PROP(TIME_WEEKDAY_TUESDAY), 0}, + {"Wednesday", TIME_PROP(TIME_WEEKDAY_WEDNESDAY), TIME_REG_PLURAL_S}, + {"Wed", TIME_PROP(TIME_WEEKDAY_WEDNESDAY), 0}, + {"Thursday", TIME_PROP(TIME_WEEKDAY_THURSDAY), TIME_REG_PLURAL_S}, + {"Thu", TIME_PROP(TIME_WEEKDAY_THURSDAY), 0}, + {"Friday", TIME_PROP(TIME_WEEKDAY_FRIDAY), TIME_REG_PLURAL_S}, + {"Fri", TIME_PROP(TIME_WEEKDAY_FRIDAY), 0}, + {"Saturday", TIME_PROP(TIME_WEEKDAY_SATURDAY), TIME_REG_PLURAL_S}, + {"Sat", TIME_PROP(TIME_WEEKDAY_SATURDAY), 0}, + + /* + * Group of tokens labeling some time and used + * instead of direct absolute specification. + */ + {"noon", TIME_PROP(TIME_LABEL_TIME_NOON), TIME_REG_PLURAL_S}, /* 12:00:00 */ + {"midnight", TIME_PROP(TIME_LABEL_TIME_MIDNIGHT), TIME_REG_PLURAL_S}, /* 00:00:00 */ + + /* + * Group of tokens used to build up time. Most of these + * are used either as relative or absolute time units. + * The absolute ones are always used with TIME_FRAME_* + * token, otherwise the unit is relative. + */ + {"second", TIME_PROP(TIME_UNIT_SECOND), TIME_REG_PLURAL_S}, + {"sec", TIME_PROP(TIME_UNIT_SECOND), TIME_REG_PLURAL_S}, + {"s", TIME_PROP(TIME_UNIT_SECOND), 0}, + {"minute", TIME_PROP(TIME_UNIT_MINUTE), TIME_REG_PLURAL_S}, + {"min", TIME_PROP(TIME_UNIT_MINUTE), TIME_REG_PLURAL_S}, + {"m", TIME_PROP(TIME_UNIT_MINUTE), 0}, + {"hour", TIME_PROP(TIME_UNIT_HOUR), TIME_REG_PLURAL_S}, + {"hr", TIME_PROP(TIME_UNIT_HOUR), TIME_REG_PLURAL_S}, + {"h", TIME_PROP(TIME_UNIT_HOUR), 0}, + {"AM", TIME_PROP(TIME_UNIT_AM), 0}, + {"PM", TIME_PROP(TIME_UNIT_PM), 0}, + + /* + * Group of tokens used to build up date. + * These are all relative ones. + */ + {"day", TIME_PROP(TIME_UNIT_DAY), TIME_REG_PLURAL_S}, + {"week", TIME_PROP(TIME_UNIT_WEEK), TIME_REG_PLURAL_S}, + {"month", TIME_PROP(TIME_UNIT_MONTH), TIME_REG_PLURAL_S}, + {"year", TIME_PROP(TIME_UNIT_YEAR), TIME_REG_PLURAL_S}, + {"yr", TIME_PROP(TIME_UNIT_YEAR), TIME_REG_PLURAL_S}, + + /* + * Group of tokes used to build up date. + * These are all absolute. + */ + {"January", TIME_PROP(TIME_MONTH_JANUARY), 0}, + {"Jan", TIME_PROP(TIME_MONTH_JANUARY), 0}, + {"February", TIME_PROP(TIME_MONTH_FEBRUARY), 0}, + {"Feb", TIME_PROP(TIME_MONTH_FEBRUARY), 0}, + {"March", TIME_PROP(TIME_MONTH_MARCH), 0}, + {"Mar", TIME_PROP(TIME_MONTH_MARCH), 0}, + {"April", TIME_PROP(TIME_MONTH_APRIL), 0}, + {"Apr", TIME_PROP(TIME_MONTH_APRIL), 0}, + {"May", TIME_PROP(TIME_MONTH_MAY), 0}, + {"June", TIME_PROP(TIME_MONTH_JUNE), 0}, + {"Jun", TIME_PROP(TIME_MONTH_JUNE), 0}, + {"July", TIME_PROP(TIME_MONTH_JULY), 0}, + {"Jul", TIME_PROP(TIME_MONTH_JULY), 0}, + {"August", TIME_PROP(TIME_MONTH_AUGUST), 0}, + {"Aug", TIME_PROP(TIME_MONTH_AUGUST), 0}, + {"September", TIME_PROP(TIME_MONTH_SEPTEMBER), 0}, + {"Sep", TIME_PROP(TIME_MONTH_SEPTEMBER), 0}, + {"October", TIME_PROP(TIME_MONTH_OCTOBER), 0}, + {"Oct", TIME_PROP(TIME_MONTH_OCTOBER), 0}, + {"November", TIME_PROP(TIME_MONTH_NOVEMBER), 0}, + {"Nov", TIME_PROP(TIME_MONTH_NOVEMBER), 0}, + {"December", TIME_PROP(TIME_MONTH_DECEMBER), 0}, + {"Dec", TIME_PROP(TIME_MONTH_DECEMBER), 0}, + {NULL, TIME_PROP(TIME_NULL), 0}, +}; + +struct time_item { + struct dm_list list; + const struct time_prop *prop; + const char *s; + size_t len; +}; + +struct time_info { + struct dm_pool *mem; + struct dm_list *ti_list; + time_t *now; + time_id_t min_abs_date_granularity; + time_id_t max_abs_date_granularity; + time_id_t min_abs_time_granularity; + time_id_t min_rel_time_granularity; +}; + +static int _is_time_num(time_id_t id) +{ + return ((id > TIME_NUM__START) && (id < TIME_NUM__END)); +} + +/* +static int _is_time_frame(time_id_t id) +{ + return ((id > TIME_FRAME__START) && (id < TIME_FRAME__END)); +} +*/ + +static int _is_time_label_date(time_id_t id) +{ + return ((id > TIME_LABEL_DATE__START) && (id < TIME_LABEL_DATE__END)); +} + +static int _is_time_label_time(time_id_t id) +{ + return ((id > TIME_LABEL_TIME__START) && (id < TIME_LABEL_TIME__END)); +} + +static int _is_time_unit(time_id_t id) +{ + return ((id > TIME_UNIT__START) && (id < TIME_UNIT__END)); +} + +static int _is_time_weekday(time_id_t id) +{ + return ((id > TIME_WEEKDAY__START) && (id < TIME_WEEKDAY__END)); +} + +static int _is_time_month(time_id_t id) +{ + return ((id > TIME_MONTH__START) && (id < TIME_MONTH__END)); +} + +static const char *_skip_space(const char *s) +{ + while (*s && isspace(*s)) + s++; + return s; +} + +/* Move till delim or space */ +static const char *_move_till_item_end(const char *s) +{ + char c = *s; + int is_num = isdigit(c); + + /* + * Allow numbers to be attached to next token, for example + * it's correct to write "12 hours" as well as "12hours". + */ + while (c && !isspace(c) && (is_num ? (is_num = isdigit(c)) : 1)) + c = *++s; + + return s; +} + +static struct time_item *_alloc_time_item(struct dm_pool *mem, time_id_t id, + const char *s, size_t len) +{ + struct time_item *ti; + + if (!(ti = dm_pool_zalloc(mem, sizeof(struct time_item)))) { + log_error("alloc_time_item: dm_pool_zalloc failed"); + return NULL; + } + + ti->prop = &_time_props[id]; + ti->s = s; + ti->len = len; + + return ti; +} + +static int _add_time_part_to_list(struct dm_pool *mem, struct dm_list *list, + time_id_t id, int minus, const char *s, size_t len) +{ + struct time_item *ti1, *ti2; + + if (!(ti1 = _alloc_time_item(mem, minus ? TIME_NUM_MULTIPLIER_NEGATIVE + : TIME_NUM_MULTIPLIER, s, len)) || + !(ti2 = _alloc_time_item(mem, id, s + len, 0))) + return 0; + dm_list_add(list, &ti1->list); + dm_list_add(list, &ti2->list); + + return 1; +} + +static int _get_time(struct dm_pool *mem, const char **str, + struct dm_list *list, int tz) +{ + const char *end, *s = *str; + int r = 0; + + /* hour */ + end = _move_till_item_end(s); + if (!_add_time_part_to_list(mem, list, tz ? TIME_UNIT_TZ_HOUR : TIME_UNIT_HOUR, + tz == -1, s, end - s)) + goto out; + + /* minute */ + if (*end != ':') + /* minute required */ + goto out; + s = end + 1; + end = _move_till_item_end(s); + if (!_add_time_part_to_list(mem, list, tz ? TIME_UNIT_TZ_MINUTE : TIME_UNIT_MINUTE, + tz == -1, s, end - s)) + goto out; + + /* second */ + if (*end != ':') { + /* second not required */ + s = end + 1; + r = 1; + goto out; + } else if (tz) + /* timezone does not have seconds */ + goto out; + + s = end + 1; + end = _move_till_item_end(s); + if (!_add_time_part_to_list(mem, list, TIME_UNIT_SECOND, 0, s, end - s)) + goto out; + + s = end + 1; + r = 1; +out: + *str = s; + return r; +} + +static int _preparse_fuzzy_time(const char *s, struct time_info *info) +{ + struct dm_list *list; + struct time_item *ti; + const char *end; + int fuzzy = 0; + time_id_t id; + size_t len; + int r = 0; + char c; + + if (!(list = dm_pool_alloc(info->mem, sizeof(struct dm_list)))) { + log_error("_preparse_fuzzy_time: dm_pool_alloc failed"); + goto out; + } + dm_list_init(list); + s = _skip_space(s); + + while ((c = *s)) { + /* + * If the string consists of -:+, digits or spaces, + * it's not worth looking for fuzzy names here - + * it's standard YYYY-MM-DD HH:MM:SS +-HH:MM format + * and that is parseable by libdm directly. + */ + if (!(isdigit(c) || (c == '-') || (c == ':') || (c == '+'))) + fuzzy = 1; + + end = _move_till_item_end(s); + + if (isalpha(c)) + id = TIME_STR; + else if (isdigit(c)) { + if (*end == ':') { + /* we have time */ + if (!_get_time(info->mem, &s, list, 0)) + goto out; + continue; + } + /* we have some other number */ + id = TIME_NUM; + } else if ((c == '-') || (c == '+')) { + s++; + /* we have timezone */ + if (!_get_time(info->mem, &s, list, (c == '-') ? -1 : 1)) + goto out; + continue; + } else + goto out; + + len = end - s; + if (!(ti = _alloc_time_item(info->mem, id, s, len))) + goto out; + dm_list_add(list, &ti->list); + s += len; + s = _skip_space(s); + } + + info->ti_list = list; + r = 1; +out: + if (!(r && fuzzy)) { + dm_pool_free(info->mem, list); + return 0; + } + + return 1; +} + +static int _match_time_str(struct dm_list *ti_list, struct time_item *ti) +{ + struct time_item *ti_context_p = (struct time_item *) dm_list_prev(ti_list, &ti->list); + size_t reg_len; + int i; + + ti->prop = TIME_PROP(TIME_NULL); + + for (i = 0; _time_reg[i].name; i++) { + reg_len = strlen(_time_reg[i].name); + if ((ti->len != reg_len) && + !((_time_reg[i].reg_flags & TIME_REG_PLURAL_S) && + (ti->len == reg_len+1) && (ti->s[reg_len] == 's'))) + continue; + + if (!strncasecmp(ti->s, _time_reg[i].name, reg_len)) { + ti->prop = _time_reg[i].prop; + if ((ti->prop->id > TIME_UNIT__START) && (ti->prop->id < TIME_UNIT__END) && + ti_context_p && (ti_context_p->prop->id == TIME_NUM)) + ti_context_p->prop = TIME_PROP(TIME_NUM_MULTIPLIER); + break; + } + } + + return ti->prop->id; +} + +static int _match_time_num(struct dm_list *ti_list, struct time_item *ti) +{ + struct time_item *ti_context_p = (struct time_item *) dm_list_prev(ti_list, &ti->list); + struct time_item *ti_context_n = (struct time_item *) dm_list_next(ti_list, &ti->list); + struct time_item *ti_context_nn = ti_context_n ? (struct time_item *) dm_list_next(ti_list, &ti_context_n->list) : NULL; + + if (ti_context_n && + (ti_context_n->prop->id > TIME_MONTH__START) && + (ti_context_n->prop->id < TIME_MONTH__END)) { + if (ti_context_nn && ti_context_nn->prop->id == TIME_NUM) { + if (ti->len < ti_context_nn->len) { + /* 24 Feb 2015 */ + ti->prop = TIME_PROP(TIME_NUM_DAY); + ti_context_nn->prop = TIME_PROP(TIME_NUM_YEAR); + } else { + /* 2015 Feb 24 */ + ti->prop = TIME_PROP(TIME_NUM_YEAR); + ti_context_nn->prop = TIME_PROP(TIME_NUM_DAY); + } + } else { + if (ti->len <= 2) + /* 24 Feb */ + ti->prop = TIME_PROP(TIME_NUM_DAY); + else + /* 2015 Feb */ + ti->prop = TIME_PROP(TIME_NUM_YEAR); + } + } else if (ti_context_p && + (ti_context_p->prop->id > TIME_MONTH__START) && + (ti_context_p->prop->id < TIME_MONTH__END)) { + if (ti->len <= 2) + /* Feb 24 */ + ti->prop = TIME_PROP(TIME_NUM_DAY); + else + /* Feb 2015 */ + ti->prop = TIME_PROP(TIME_NUM_YEAR); + } else + ti->prop = TIME_PROP(TIME_NUM_YEAR); + + return ti->prop->id; +} + +static void _detect_time_granularity(struct time_info *info, struct time_item *ti) +{ + time_id_t gran = ti->prop->granularity; + int is_date, is_abs, is_rel; + + if (gran == TIME_NULL) + return; + + is_date = ti->prop->prop_flags & TIME_PROP_DATE; + is_abs = ti->prop->prop_flags & TIME_PROP_ABS; + is_rel = ti->prop->prop_flags & TIME_PROP_REL; + + if (is_date && is_abs) { + if (gran > info->max_abs_date_granularity) + info->max_abs_date_granularity = gran; + if (gran < info->min_abs_date_granularity) + info->min_abs_date_granularity = gran; + } else { + if (is_abs && (gran < info->min_abs_time_granularity)) + info->min_abs_time_granularity = gran; + else if (is_rel && (gran < info->min_rel_time_granularity)) + info->min_rel_time_granularity = gran; + } +} + +static void _change_to_relative(struct time_info *info, struct time_item *ti) +{ + struct time_item *ti2; + + ti2 = ti; + while ((ti2 = (struct time_item *) dm_list_prev(info->ti_list, &ti2->list))) { + if (ti2->prop->id == TIME_FRAME_AGO) + break; + + switch (ti2->prop->id) { + case TIME_UNIT_SECOND: + ti2->prop = TIME_PROP(TIME_UNIT_SECOND_REL); + break; + case TIME_UNIT_MINUTE: + ti2->prop = TIME_PROP(TIME_UNIT_MINUTE_REL); + break; + case TIME_UNIT_HOUR: + ti2->prop = TIME_PROP(TIME_UNIT_HOUR_REL); + break; + default: + break; + } + } +} + +static int _recognize_time_items(struct time_info *info) +{ + struct time_item *ti; + + /* + * At first, try to recognize strings. + * Also, if there are any items which may be absolute or + * relative and we have "TIME_FRAME_AGO", change them to relative. + */ + dm_list_iterate_items(ti, info->ti_list) { + if ((ti->prop->id == TIME_STR) && !_match_time_str(info->ti_list, ti)) { + log_error("Unrecognized string in date/time " + "specification at \"%s\".", ti->s); + return 0; + } + if (ti->prop->id == TIME_FRAME_AGO) + _change_to_relative(info, ti); + } + + /* + * Now, recognize any numbers and be sensitive to the context + * given by strings we recognized before. Also, detect time + * granularity used (both for absolute and/or relative parts). + */ + dm_list_iterate_items(ti, info->ti_list) { + if ((ti->prop->id == TIME_NUM) && !_match_time_num(info->ti_list, ti)) { + log_error("Unrecognized number in date/time " + "specification at \"%s\".", ti->s); + return 0; + } + _detect_time_granularity(info, ti); + } + + return 1; +} + +static int _check_time_items(struct time_info *info) +{ + struct time_item *ti; + uint32_t flags; + int rel; + int date_is_relative = -1, time_is_relative = -1; + int label_time = 0, label_date = 0; + + dm_list_iterate_items(ti, info->ti_list) { + flags = ti->prop->prop_flags; + rel = flags & TIME_PROP_REL; + + if (flags & TIME_PROP_DATE) { + if (date_is_relative < 0) + date_is_relative = rel; + else if ((date_is_relative ^ rel) && + (info->max_abs_date_granularity >= info->min_rel_time_granularity)) { + log_error("Mixed absolute and relative date " + "specification found at \"%s\".", ti->s); + return 0; + } + + /* Date label can be used only once and not mixed with other date spec. */ + if (label_date) { + log_error("Ambiguous date specification found at \"%s\".", ti->s); + return 0; + } + + if (_is_time_label_date(ti->prop->id)) + label_date = 1; + } + + else if (flags & TIME_PROP_TIME) { + if (time_is_relative < 0) + time_is_relative = rel; + else if ((time_is_relative ^ rel)) { + log_error("Mixed absolute and relative time " + "specification found at \"%s\".", ti->s); + return 0; + } + + /* Time label can be used only once and not mixed with other time spec. */ + if (label_time) { + log_error("Ambiguous time specification found at \"%s\".", ti->s); + return 0; + } + + if (_is_time_label_time(ti->prop->id)) + label_time = 1; + } + } + + return 1; +} + +#define CACHE_ID_TIME_NOW "time_now" + +static time_t *_get_now(struct dm_report *rh, struct dm_pool *mem) +{ + const void *cached_obj; + time_t *now; + + if (!(cached_obj = dm_report_value_cache_get(rh, CACHE_ID_TIME_NOW))) { + if (!(now = dm_pool_zalloc(mem, sizeof(time_t)))) { + log_error("_get_now: dm_pool_zalloc failed"); + return NULL; + } + time(now); + if (!dm_report_value_cache_set(rh, CACHE_ID_TIME_NOW, now)) { + log_error("_get_now: failed to cache current time"); + return NULL; + } + } else + now = (time_t *) cached_obj; + + return now; +} + +static void _adjust_time_for_granularity(struct time_info *info, struct tm *tm, time_t *t) +{ + switch (info->min_abs_date_granularity) { + case TIME_UNIT_YEAR: + tm->tm_mon = 0; + /* fall through */ + case TIME_UNIT_MONTH: + tm->tm_mday = 1; + break; + default: + break; + } + + switch (info->min_abs_time_granularity) { + case TIME_UNIT_HOUR: + tm->tm_min = 0; + /* fall through */ + case TIME_UNIT_MINUTE: + tm->tm_sec = 0; + break; + case TIME_UNIT__END: + if (info->min_rel_time_granularity == TIME_UNIT__END) + tm->tm_hour = tm->tm_min = tm->tm_sec = 0; + break; + default: + break; + } + + if ((info->min_abs_time_granularity == TIME_UNIT__END) && + (info->min_rel_time_granularity >= TIME_UNIT_DAY) && + (info->min_rel_time_granularity <= TIME_UNIT_YEAR)) + tm->tm_hour = tm->tm_min = tm->tm_sec = 0; +} + +#define SECS_PER_MINUTE 60 +#define SECS_PER_HOUR 3600 +#define SECS_PER_DAY ((time_t)86400) + +static int _days_in_month[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + +static int _is_leap_year(long year) +{ + return (((year % 4==0) && (year % 100 != 0)) || (year % 400 == 0)); +} + +static int _get_days_in_month(long month, long year) +{ + return (month == 2 && _is_leap_year(year)) ? _days_in_month[month-1] + 1 + : _days_in_month[month-1]; +} + +static void _get_resulting_time_span(struct time_info *info, + struct tm *tm, time_t t, + time_t *t_result1, time_t *t_result2) +{ + time_t t1 = mktime(tm) - t; + time_t t2 = t1; + struct tm tmp; + + if (info->min_abs_time_granularity != TIME_UNIT__END) { + if (info->min_abs_time_granularity == TIME_UNIT_MINUTE) + t2 += (SECS_PER_MINUTE - 1); + else if (info->min_abs_time_granularity == TIME_UNIT_HOUR) + t2 += (SECS_PER_HOUR - 1); + } else if (info->min_rel_time_granularity != TIME_UNIT__END) { + if (info->min_rel_time_granularity == TIME_UNIT_MINUTE) + t1 -= (SECS_PER_MINUTE + 1); + else if (info->min_rel_time_granularity == TIME_UNIT_HOUR) + t1 -= (SECS_PER_HOUR + 1); + else if ((info->min_rel_time_granularity >= TIME_UNIT_DAY) && + (info->min_rel_time_granularity <= TIME_UNIT_YEAR)) + t2 += (SECS_PER_DAY - 1); + } else { + if (info->min_abs_date_granularity == TIME_UNIT_MONTH) + t2 += (SECS_PER_DAY * _get_days_in_month(tm->tm_mon + 1, tm->tm_year) - 1); + else if (info->min_abs_date_granularity != TIME_UNIT__END) + t2 += (SECS_PER_DAY - 1); + } + + /* Adjust for DST if needed. */ + localtime_r(&t1, &tmp); + if (tmp.tm_isdst) + t1 -= SECS_PER_HOUR; + localtime_r(&t2, &tmp); + if (tmp.tm_isdst) + t2 -= SECS_PER_HOUR; + + *t_result1 = t1; + *t_result2 = t2; +} + +static int _translate_time_items(struct dm_report *rh, struct time_info *info, + const char **data_out) +{ + struct time_item *ti, *ti_p = NULL; + long multiplier = 1; + struct tm tm_now; + time_id_t id; + long num; + struct tm tm; /* absolute time */ + time_t t = 0; /* offset into past before absolute time */ + time_t t1, t2; + char buf[32]; + + localtime_r(info->now, &tm_now); + tm = tm_now; + tm.tm_isdst = 0; /* we'll adjust for dst later */ + tm.tm_wday = tm.tm_yday = -1; + + dm_list_iterate_items(ti, info->ti_list) { + id = ti->prop->id; + + if (_is_time_num(id)) { + errno = 0; + num = strtol(ti->s, NULL, 10); + if (errno) { + log_error("_translate_time_items: invalid time."); + return 0; + } + switch (id) { + case TIME_NUM_MULTIPLIER_NEGATIVE: + multiplier = -num; + break; + case TIME_NUM_MULTIPLIER: + multiplier = num; + break; + case TIME_NUM_DAY: + tm.tm_mday = num; + break; + case TIME_NUM_YEAR: + tm.tm_year = num - 1900; + break; + default: + break; + } + } else if (_is_time_month(id)) { + tm.tm_mon = id - TIME_MONTH__START - 1; + } else if (_is_time_label_date(id)) { + if (_is_time_weekday(id)) { + num = id - TIME_WEEKDAY__START - 1; + if (tm_now.tm_wday < num) + num = 7 - num + tm_now.tm_wday; + else + num = tm_now.tm_wday - num; + t += num * SECS_PER_DAY; + } else switch (id) { + case TIME_LABEL_DATE_YESTERDAY: + t += SECS_PER_DAY; + break; + case TIME_LABEL_DATE_TODAY: + /* Nothing to do here - we started with today. */ + break; + default: + break; + } + } else if (_is_time_label_time(id)) { + switch (id) { + case TIME_LABEL_TIME_NOON: + tm.tm_hour = 12; + tm.tm_min = tm.tm_sec = 0; + break; + case TIME_LABEL_TIME_MIDNIGHT: + tm.tm_hour = tm.tm_min = tm.tm_sec = 0; + break; + default: + break; + } + } else if (_is_time_unit(id)) { + switch (id) { + case TIME_UNIT_SECOND: + tm.tm_sec = multiplier; + break; + case TIME_UNIT_SECOND_REL: + t += multiplier; + break; + case TIME_UNIT_MINUTE: + tm.tm_min = multiplier; + break; + case TIME_UNIT_MINUTE_REL: + t += (multiplier * SECS_PER_MINUTE); + break; + case TIME_UNIT_HOUR: + tm.tm_hour = multiplier; + break; + case TIME_UNIT_HOUR_REL: + t += (multiplier * SECS_PER_HOUR); + break; + case TIME_UNIT_AM: + if (ti_p && ti_p->prop->id == TIME_NUM_MULTIPLIER) + tm.tm_hour = multiplier; + break; + case TIME_UNIT_PM: + if (ti_p && _is_time_unit(ti_p->prop->id)) + t -= 12 * SECS_PER_HOUR; + else if (ti_p && ti_p->prop->id == TIME_NUM_MULTIPLIER) + tm.tm_hour = multiplier + 12; + break; + case TIME_UNIT_DAY: + t += multiplier * SECS_PER_DAY; + break; + case TIME_UNIT_WEEK: + t += multiplier * 7 * SECS_PER_DAY; + break; + case TIME_UNIT_MONTH: + /* if months > 12, convert to years first */ + num = multiplier / 12; + tm.tm_year -= num; + + num = multiplier % 12; + if (num > (tm.tm_mon + 1)) { + tm.tm_year--; + tm.tm_mon = 12 - num + tm.tm_mon; + } else + tm.tm_mon -= num; + break; + case TIME_UNIT_YEAR: + tm.tm_year -= multiplier; + break; + default: + break; + } + } + + ti_p = ti; + } + + _adjust_time_for_granularity(info, &tm, &t); + _get_resulting_time_span(info, &tm, t, &t1, &t2); + + dm_pool_free(info->mem, info->ti_list); + info->ti_list = NULL; + + if (dm_snprintf(buf, sizeof(buf), "@" FMTd64 ":@" FMTd64, (int64_t)t1, (int64_t)t2) == -1) { + log_error("_translate_time_items: dm_snprintf failed"); + return 0; + } + + if (!(*data_out = dm_pool_strdup(info->mem, buf))) { + log_error("_translate_time_items: dm_pool_strdup failed"); + return 0; + } + + return 1; +} + +static const char *_lv_time_handler_parse_fuzzy_name(struct dm_report *rh, + struct dm_pool *mem, + const char *data_in) +{ + const char *s = data_in; + const char *data_out = NULL; + struct time_info info = {.mem = mem, + .ti_list = NULL, + .now = _get_now(rh, mem), + .min_abs_date_granularity = TIME_UNIT__END, + .max_abs_date_granularity = TIME_UNIT__START, + .min_abs_time_granularity = TIME_UNIT__END, + .min_rel_time_granularity = TIME_UNIT__END}; + + if (!info.now) + goto_out; + + /* recognize top-level parts - string/number/time/timezone? */ + if (!_preparse_fuzzy_time(s, &info)) + goto out; + + /* recognize each part in more detail, also look at the context around if needed */ + if (!_recognize_time_items(&info)) + goto out; + + /* check if the combination of items is allowed or whether it makes sense at all */ + if (!_check_time_items(&info)) + goto out; + + /* translate items into final time range */ + if (!_translate_time_items(rh, &info, &data_out)) + goto out; +out: + if (info.ti_list) + dm_pool_free(info.mem, info.ti_list); + return data_out; +} + +static void *_lv_time_handler_get_dynamic_value(struct dm_report *rh, + struct dm_pool *mem, + const char *data_in) +{ + int64_t t1, t2; + time_t *result; + + if (sscanf(data_in, "@" FMTd64 ":@" FMTd64, &t1, &t2) != 2) { + log_error("Failed to get value for parsed time specification."); + return NULL; + } + + if (!(result = dm_pool_alloc(mem, 2 * sizeof(time_t)))) { + log_error("Failed to allocate space to store time range."); + return NULL; + } + + result[0] = (time_t) t1; /* Validate range for 32b arch ? */ + result[1] = (time_t) t2; + + return result; +} + +static int _lv_time_handler(struct dm_report *rh, struct dm_pool *mem, + uint32_t field_num, + dm_report_reserved_action_t action, + const void *data_in, const void **data_out) +{ + *data_out = NULL; + if (!data_in) + return 1; + + switch (action) { + case DM_REPORT_RESERVED_PARSE_FUZZY_NAME: + *data_out = _lv_time_handler_parse_fuzzy_name(rh, mem, data_in); + break; + case DM_REPORT_RESERVED_GET_DYNAMIC_VALUE: + if (!(*data_out = _lv_time_handler_get_dynamic_value(rh, mem, data_in))) + return 0; + break; + default: + return -1; + } + + return 1; +} + +/* + * Get type reserved value - the value returned is the direct value of that type. + */ +#define GET_TYPE_RESERVED_VALUE(id) _reserved_ ## id + +/* + * Get field reserved value - the value returned is always a pointer (const void *). + */ +#define GET_FIELD_RESERVED_VALUE(id) _reserved_ ## id.value + +/* + * Get first name assigned to the reserved value - this is the one that + * should be reported/displayed. All the other names assigned for the reserved + * value are synonyms recognized in selection criteria. + */ +#define GET_FIRST_RESERVED_NAME(id) _reserved_ ## id ## _names[0] + +/* + * Reserved values and their assigned names. + * The first name is the one that is also used for reporting. + * All names listed are synonyms recognized in selection criteria. + * For binary-based values we map all reserved names listed onto value 1, blank onto value 0. + * + * TYPE_RESERVED_VALUE(type, reserved_value_id, description, value, reserved name, ...) + * FIELD_RESERVED_VALUE(field_id, reserved_value_id, description, value, reserved name, ...) + * FIELD_RESERVED_BINARY_VALUE(field_id, reserved_value_id, description, reserved name for 1, ...) + * + * Note: FIELD_RESERVED_BINARY_VALUE creates: + * - 'reserved_value_id_y' (for 1) + * - 'reserved_value_id_n' (for 0) + */ +#define NUM uint64_t +#define NUM_HND dm_report_reserved_handler +#define HND (dm_report_reserved_handler) +#define NOFLAG 0 +#define NAMED DM_REPORT_FIELD_RESERVED_VALUE_NAMED +#define RANGE DM_REPORT_FIELD_RESERVED_VALUE_RANGE +#define FUZZY DM_REPORT_FIELD_RESERVED_VALUE_FUZZY_NAMES +#define DYNAMIC DM_REPORT_FIELD_RESERVED_VALUE_DYNAMIC_VALUE + +#define TYPE_RESERVED_VALUE(type, flags, id, desc, value, ...) \ + static const char *_reserved_ ## id ## _names[] = { __VA_ARGS__, NULL}; \ + static const type _reserved_ ## id = value; + +#define FIELD_RESERVED_VALUE(flags, field_id, id, desc, value, ...) \ + static const char *_reserved_ ## id ## _names[] = { __VA_ARGS__ , NULL}; \ + static const struct dm_report_field_reserved_value _reserved_ ## id = {field_ ## field_id, value}; + +#define FIELD_RESERVED_BINARY_VALUE(field_id, id, desc, ...) \ + FIELD_RESERVED_VALUE(NAMED, field_id, id ## _y, desc, &_one64, __VA_ARGS__, _str_yes) \ + FIELD_RESERVED_VALUE(NAMED, field_id, id ## _n, desc, &_zero64, __VA_ARGS__, _str_no) + +#include "values.h" + +#undef NUM +#undef NUM_HND +#undef HND +#undef NOFLAG +#undef NAMED +#undef RANGE +#undef TYPE_RESERVED_VALUE +#undef FIELD_RESERVED_VALUE +#undef FIELD_RESERVED_BINARY_VALUE +#undef FUZZY +#undef DYNAMIC + +/* + * Create array of reserved values to be registered with reporting code via + * dm_report_init_with_selection function that initializes report with + * selection criteria. Selection code then recognizes these reserved values + * when parsing selection criteria. +*/ + +#define NUM DM_REPORT_FIELD_TYPE_NUMBER +#define NUM_HND DM_REPORT_FIELD_TYPE_NUMBER +#define HND 0 +#define NOFLAG 0 +#define NAMED DM_REPORT_FIELD_RESERVED_VALUE_NAMED +#define RANGE DM_REPORT_FIELD_RESERVED_VALUE_RANGE +#define FUZZY DM_REPORT_FIELD_RESERVED_VALUE_FUZZY_NAMES +#define DYNAMIC DM_REPORT_FIELD_RESERVED_VALUE_DYNAMIC_VALUE + +#define TYPE_RESERVED_VALUE(type, flags, id, desc, value, ...) {type | flags, &_reserved_ ## id, _reserved_ ## id ## _names, desc}, + +#define FIELD_RESERVED_VALUE(flags, field_id, id, desc, value, ...) {DM_REPORT_FIELD_TYPE_NONE | flags, &_reserved_ ## id, _reserved_ ## id ## _names, desc}, + +#define FIELD_RESERVED_BINARY_VALUE(field_id, id, desc, ...) \ + FIELD_RESERVED_VALUE(NAMED, field_id, id ## _y, desc, &_one64, __VA_ARGS__) \ + FIELD_RESERVED_VALUE(NAMED, field_id, id ## _n, desc, &_zero64, __VA_ARGS__) + +static const struct dm_report_reserved_value _report_reserved_values[] = { + #include "values.h" + {0, NULL, NULL, NULL} }; -static const uint64_t _minusone64 = UINT64_C(-1); -static const int32_t _minusone32 = INT32_C(-1); +#undef NUM +#undef NUM_HND +#undef HND +#undef NOFLAG +#undef NAMED +#undef RANGE +#undef FUZZY +#undef DYNAMIC +#undef TYPE_RESERVED_VALUE +#undef FIELD_RESERVED_VALUE +#undef FIELD_RESERVED_BINARY_VALUE + +static int _field_string(struct dm_report *rh, struct dm_report_field *field, const char *data) +{ + return dm_report_field_string(rh, field, &data); +} + +static int _field_set_value(struct dm_report_field *field, const void *data, const void *sort) +{ + dm_report_field_set_value(field, data, sort); + + return 1; +} + +static int _field_set_string_list(struct dm_report *rh, struct dm_report_field *field, + const struct dm_list *list, void *private, int sorted, + const char *delimiter) +{ + struct cmd_context *cmd = (struct cmd_context *) private; + return sorted ? dm_report_field_string_list(rh, field, list, delimiter ? : cmd->report_list_item_separator) + : dm_report_field_string_list_unsorted(rh, field, list, delimiter ? : cmd->report_list_item_separator); +} /* * Data-munging functions to prepare each data type for display and sorting */ + +/* + * Display either "0"/"1" or ""/"word" based on bin_value, + * cmd->report_binary_values_as_numeric selects the mode to use. +*/ +static int _binary_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)), + struct dm_report_field *field, int bin_value, const char *word, + void *private) +{ + const struct cmd_context *cmd = (const struct cmd_context *) private; + + if (cmd->report_strict_type_mode || cmd->report_binary_values_as_numeric) + /* "0"/"1" */ + return _field_set_value(field, bin_value ? _str_one : _str_zero, bin_value ? &_one64 : &_zero64); + + /* blank/"word" */ + return _field_set_value(field, bin_value ? word : "", bin_value ? &_one64 : &_zero64); +} + +static int _binary_undef_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)), + struct dm_report_field *field, void *private) +{ + const struct cmd_context *cmd = (const struct cmd_context *) private; + + if (cmd->report_strict_type_mode || cmd->report_binary_values_as_numeric) + return _field_set_value(field, GET_FIRST_RESERVED_NAME(num_undef_64), &GET_TYPE_RESERVED_VALUE(num_undef_64)); + + return _field_set_value(field, _str_unknown, &GET_TYPE_RESERVED_VALUE(num_undef_64)); +} + static int _string_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)), struct dm_report_field *field, const void *data, void *private __attribute__((unused))) @@ -46,68 +1310,355 @@ static int _string_disp(struct dm_report *rh, struct dm_pool *mem __attribute__( return dm_report_field_string(rh, field, (const char * const *) data); } -static int _dev_name_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)), +static int _chars_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)), + struct dm_report_field *field, + const void *data, void *private __attribute__((unused))) +{ + return _field_string(rh, field, data); +} + +static int _uuid_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + char *repstr; + + if (!(repstr = id_format_and_copy(mem, data))) + return_0; + + return _field_set_value(field, repstr, NULL); +} + +static int _devminor_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, - const void *data, void *private __attribute__((unused))) + const void *data, void *private) { - const char *name = dev_name(*(const struct device * const *) data); + int devminor = (int) MINOR((*(const struct device * const *) data)->dev); - return dm_report_field_string(rh, field, &name); + return dm_report_field_int(rh, field, &devminor); } -static int _devices_disp(struct dm_report *rh __attribute__((unused)), struct dm_pool *mem, +static int _devmajor_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + int devmajor = (int) MAJOR((*(const struct device * const *) data)->dev); + + return dm_report_field_int(rh, field, &devmajor); +} + +static int _dev_name_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + return _field_string(rh, field, dev_name(*(const struct device * const *) data)); +} + +static int _devices_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, - const void *data, void *private __attribute__((unused))) + const void *data, void *private) { - char *str; - if (!(str = lvseg_devices(mem, (const struct lv_segment *) data))) - return 0; + const struct lv_segment *seg = (const struct lv_segment *) data; + struct dm_list *list; - dm_report_field_set_value(field, str, NULL); + if (!(list = lvseg_devices(mem, seg))) + return_0; - return 1; + return _field_set_string_list(rh, field, list, private, 0, ","); } -static int _peranges_disp(struct dm_report *rh __attribute__((unused)), struct dm_pool *mem, +static int _metadatadevices_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const struct lv_segment *seg = (const struct lv_segment *) data; + struct dm_list *list; + + if (!(list = lvseg_metadata_devices(mem, seg))) + return_0; + + return _field_set_string_list(rh, field, list, private, 0, ","); +} + +static int _peranges_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, - const void *data, void *private __attribute__((unused))) + const void *data, void *private) { - char *str; - if (!(str = lvseg_seg_pe_ranges(mem, (const struct lv_segment *) data))) - return 0; + const struct lv_segment *seg = (const struct lv_segment *) data; + struct dm_list *list; - dm_report_field_set_value(field, str, NULL); + if (!(list = lvseg_seg_pe_ranges(mem, seg))) + return_0; - return 1; + return _field_set_string_list(rh, field, list, private, 0, " "); +} + +static int _leranges_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const struct lv_segment *seg = (const struct lv_segment *) data; + struct dm_list *list; + + if (!(list = lvseg_seg_le_ranges(mem, seg))) + return_0; + + return _field_set_string_list(rh, field, list, private, 0, NULL); } -static int _tags_disp(struct dm_report *rh __attribute__((unused)), struct dm_pool *mem, +static int _metadataleranges_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const struct lv_segment *seg = (const struct lv_segment *) data; + struct dm_list *list; + + if (!(list = lvseg_seg_metadata_le_ranges(mem, seg))) + return_0; + + return _field_set_string_list(rh, field, list, private, 0, NULL); +} + +static int _tags_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, - const void *data, void *private __attribute__((unused))) + const void *data, void *private) { - const struct dm_list *tags = (const struct dm_list *) data; - char *tags_str; + const struct dm_list *tagsl = (const struct dm_list *) data; - if (!(tags_str = tags_format_and_copy(mem, tags))) - return 0; + return _field_set_string_list(rh, field, tagsl, private, 1, NULL); +} + +struct _str_list_append_baton { + struct dm_pool *mem; + struct dm_list *result; +}; + +static int _str_list_append(const char *line, void *baton) +{ + struct _str_list_append_baton *b = baton; + const char *line2 = dm_pool_strdup(b->mem, line); + + if (!line2) + return_0; + + if (!str_list_add(b->mem, b->result, line2)) + return_0; + + return 1; +} + +static int _cache_settings_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const struct lv_segment *seg = (const struct lv_segment *) data; + const struct lv_segment *setting_seg = NULL; + const struct dm_config_node *settings; + struct dm_list *result; + struct _str_list_append_baton baton; + struct dm_list dummy_list; /* dummy list to display "nothing" */ + + if (seg_is_writecache(seg)) { + if (!(result = str_list_create(mem))) + return_0; + + if (!writecache_settings_to_str_list((struct writecache_settings *)&seg->writecache_settings, result, mem)) + return_0; + + return _field_set_string_list(rh, field, result, private, 0, NULL); + } + + if (seg_is_cache(seg) && lv_is_cache_vol(seg->pool_lv)) + setting_seg = seg; + + else if (seg_is_cache_pool(seg)) + setting_seg = seg; + + else if (seg_is_cache(seg)) + setting_seg = first_seg(seg->pool_lv); + + if (!setting_seg || !setting_seg->policy_settings) { + dm_list_init(&dummy_list); + return _field_set_string_list(rh, field, &dummy_list, private, 0, NULL); + /* TODO: once we have support for STR_LIST reserved values, replace with: + * return _field_set_value(field, GET_FIRST_RESERVED_NAME(cache_settings_undef), GET_FIELD_RESERVED_VALUE(cache_settings_undef)); + */ + } + + settings = setting_seg->policy_settings->child; + + if (!(result = str_list_create(mem))) + return_0; + + baton.mem = mem; + baton.result = result; - dm_report_field_set_value(field, tags_str, NULL); + while (settings) { + dm_config_write_one_node(settings, _str_list_append, &baton); + settings = settings->sib; + }; + + return _field_set_string_list(rh, field, result, private, 0, NULL); +} + +static int _do_get_kernel_cache_settings_list(struct dm_pool *mem, + int cache_argc, char **cache_argv, + struct dm_list *result) +{ + const char *key, *value; + char *buf; + size_t buf_len; + int i; + + for (i = 0; i+1 < cache_argc; i += 2) { + key = cache_argv[i]; + value = cache_argv[i+1]; + /* +1 for "=" char and +1 for trailing zero */ + buf_len = strlen(key) + strlen(value) + 2; + if (!(buf = dm_pool_alloc(mem, buf_len))) + return_0; + if (dm_snprintf(buf, buf_len, "%s=%s", key, value) < 0) + return_0; + if (!str_list_add_no_dup_check(mem, result, buf)) + return_0; + } return 1; } +static int _get_kernel_cache_settings_list(struct dm_pool *mem, + struct dm_status_cache *cache_status, + struct dm_list **result) +{ + if (!(*result = str_list_create(mem))) + return_0; + + if (!_do_get_kernel_cache_settings_list(mem, cache_status->core_argc, + cache_status->core_argv, *result)) + return_0; + + if (!_do_get_kernel_cache_settings_list(mem, cache_status->policy_argc, + cache_status->policy_argv, *result)) + return_0; + + return 1; +} + +static int _kernel_cache_settings_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const struct lv_with_info_and_seg_status *lvdm = (const struct lv_with_info_and_seg_status *) data; + struct dm_list dummy_list; /* dummy list to display "nothing" */ + struct dm_list *result; + int r = 0; + + if (lvdm->seg_status.type != SEG_STATUS_CACHE) { + dm_list_init(&dummy_list); + return _field_set_string_list(rh, field, &dummy_list, private, 0, NULL); + } + + if (!(mem = dm_pool_create("reporter_pool", 1024))) + return_0; + + if (!_get_kernel_cache_settings_list(mem, lvdm->seg_status.cache, &result)) + goto_out; + + r = _field_set_string_list(rh, field, result, private, 0, NULL); +out: + dm_pool_destroy(mem); + return r; +} + +static int _kernel_cache_policy_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const struct lv_with_info_and_seg_status *lvdm = (const struct lv_with_info_and_seg_status *) data; + + if ((lvdm->seg_status.type == SEG_STATUS_CACHE) && + lvdm->seg_status.cache->policy_name) + return _field_string(rh, field, lvdm->seg_status.cache->policy_name); + + return _field_set_value(field, GET_FIRST_RESERVED_NAME(cache_policy_undef), + GET_FIELD_RESERVED_VALUE(cache_policy_undef)); +} + +static int _kernelmetadataformat_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const struct lv_with_info_and_seg_status *lvdm = (const struct lv_with_info_and_seg_status *) data; + unsigned format; + + if (lvdm->seg_status.type == SEG_STATUS_CACHE) { + format = (lvdm->seg_status.cache->feature_flags & DM_CACHE_FEATURE_METADATA2); + return dm_report_field_uint64(rh, field, format ? &_two64 : &_one64); + } + + return _field_set_value(field, "", &GET_TYPE_RESERVED_VALUE(num_undef_64)); +} + +static int _cache_policy_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const struct lv_segment *seg = (const struct lv_segment *) data; + const struct lv_segment *setting_seg = NULL; + + if (seg_is_cache(seg) && lv_is_cache_vol(seg->pool_lv)) + setting_seg = seg; + + else if (seg_is_cache_pool(seg)) + setting_seg = seg; + + else if (seg_is_cache(seg)) + setting_seg = first_seg(seg->pool_lv); + + if (!setting_seg || !setting_seg->policy_name) + return _field_set_value(field, GET_FIRST_RESERVED_NAME(cache_policy_undef), + GET_FIELD_RESERVED_VALUE(cache_policy_undef)); + + return _field_string(rh, field, setting_seg->policy_name); +} + static int _modules_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { const struct logical_volume *lv = (const struct logical_volume *) data; - char *modules_str; + struct dm_list *modules; - if (!(modules_str = lv_modules_dup(mem, lv))) + if (!(modules = str_list_create(mem))) { + log_error("modules str_list allocation failed"); return 0; + } - dm_report_field_set_value(field, modules_str, NULL); - return 1; + if (!(list_lv_modules(mem, lv, modules))) + return_0; + + return _field_set_string_list(rh, field, modules, private, 1, NULL); +} + +static int _lvprofile_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const struct logical_volume *lv = (const struct logical_volume *) data; + + if (lv->profile) + return _field_string(rh, field, lv->profile->name); + + return _field_set_value(field, "", NULL); +} + +static int _lvlockargs_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const struct logical_volume *lv = (const struct logical_volume *) data; + + return _field_string(rh, field, lv->lock_args ? : ""); } static int _vgfmt_disp(struct dm_report *rh, struct dm_pool *mem, @@ -116,67 +1667,59 @@ static int _vgfmt_disp(struct dm_report *rh, struct dm_pool *mem, { const struct volume_group *vg = (const struct volume_group *) data; - if (!vg->fid) { - dm_report_field_set_value(field, "", NULL); - return 1; - } + if (vg->fid && vg->fid->fmt) + return _field_string(rh, field, vg->fid->fmt->name); - return _string_disp(rh, mem, field, &vg->fid->fmt->name, private); + return _field_set_value(field, "", NULL); } static int _pvfmt_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { - const struct physical_volume *pv = - (const struct physical_volume *) data; + const struct label *l = (const struct label *) data; - if (!pv->fmt) { - dm_report_field_set_value(field, "", NULL); - return 1; - } + if (l->labeller && l->labeller->fmt) + return _field_string(rh, field, l->labeller->fmt->name); - return _string_disp(rh, mem, field, &pv->fmt->name, private); + return _field_set_value(field, "", NULL); } static int _lvkmaj_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)), struct dm_report_field *field, const void *data, void *private __attribute__((unused))) { - const struct logical_volume *lv = (const struct logical_volume *) data; - int major; + const struct lv_with_info_and_seg_status *lvdm = (const struct lv_with_info_and_seg_status *) data; - if ((major = lv_kernel_major(lv)) >= 0) - return dm_report_field_int(rh, field, &major); + if (lvdm->info.exists && lvdm->info.major >= 0) + return dm_report_field_int(rh, field, &lvdm->info.major); - return dm_report_field_int32(rh, field, &_minusone32); + return dm_report_field_int32(rh, field, &GET_TYPE_RESERVED_VALUE(num_undef_32)); } static int _lvkmin_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)), struct dm_report_field *field, const void *data, void *private __attribute__((unused))) { - const struct logical_volume *lv = (const struct logical_volume *) data; - int minor; + const struct lv_with_info_and_seg_status *lvdm = (const struct lv_with_info_and_seg_status *) data; - if ((minor = lv_kernel_minor(lv)) >= 0) - return dm_report_field_int(rh, field, &minor); + if (lvdm->info.exists && lvdm->info.minor >= 0) + return dm_report_field_int(rh, field, &lvdm->info.minor); - return dm_report_field_int32(rh, field, &_minusone32); + return dm_report_field_int32(rh, field, &GET_TYPE_RESERVED_VALUE(num_undef_32)); } static int _lvstatus_disp(struct dm_report *rh __attribute__((unused)), struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private __attribute__((unused))) { - const struct logical_volume *lv = (const struct logical_volume *) data; + const struct lv_with_info_and_seg_status *lvdm = (const struct lv_with_info_and_seg_status *) data; char *repstr; - if (!(repstr = lv_attr_dup(mem, lv))) - return 0; + if (!(repstr = lv_attr_dup_with_info_and_seg_status(mem, lvdm))) + return_0; - dm_report_field_set_value(field, repstr, NULL); - return 1; + return _field_set_value(field, repstr, NULL); } static int _pvstatus_disp(struct dm_report *rh __attribute__((unused)), struct dm_pool *mem, @@ -188,10 +1731,9 @@ static int _pvstatus_disp(struct dm_report *rh __attribute__((unused)), struct d char *repstr; if (!(repstr = pv_attr_dup(mem, pv))) - return 0; + return_0; - dm_report_field_set_value(field, repstr, NULL); - return 1; + return _field_set_value(field, repstr, NULL); } static int _vgstatus_disp(struct dm_report *rh __attribute__((unused)), struct dm_pool *mem, @@ -202,10 +1744,9 @@ static int _vgstatus_disp(struct dm_report *rh __attribute__((unused)), struct d char *repstr; if (!(repstr = vg_attr_dup(mem, vg))) - return 0; + return_0; - dm_report_field_set_value(field, repstr, NULL); - return 1; + return _field_set_value(field, repstr, NULL); } static int _segtype_disp(struct dm_report *rh __attribute__((unused)), @@ -217,103 +1758,204 @@ static int _segtype_disp(struct dm_report *rh __attribute__((unused)), char *name; if (!(name = lvseg_segtype_dup(mem, seg))) { - log_error("Failed to get segtype."); + log_error("Failed to get segtype name."); return 0; } - dm_report_field_set_value(field, name, NULL); - return 1; -} - -static int _loglv_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)), - struct dm_report_field *field, - const void *data, void *private __attribute__((unused))) -{ - const struct logical_volume *lv = (const struct logical_volume *) data; - const char *name; - - if ((name = lv_mirror_log_dup(mem, lv))) - return dm_report_field_string(rh, field, &name); - - dm_report_field_set_value(field, "", NULL); - return 1; + return _field_set_value(field, name, NULL); } static int _lvname_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, - const void *data, void *private __attribute__((unused))) + const void *data, void *private) { + struct cmd_context *cmd = (struct cmd_context *) private; const struct logical_volume *lv = (const struct logical_volume *) data; + int is_historical = lv_is_historical(lv); + const char *tmp_lvname; char *repstr, *lvname; size_t len; - if (lv_is_visible(lv)) - return dm_report_field_string(rh, field, &lv->name); + if (!is_historical && (lv_is_visible(lv) || !cmd->report_mark_hidden_devices)) + return _field_string(rh, field, lv->name); + + if (is_historical) { + tmp_lvname = lv->this_glv->historical->name; + len = strlen(tmp_lvname) + strlen(HISTORICAL_LV_PREFIX) + 1; + } else { + tmp_lvname = lv->name; + len = strlen(tmp_lvname) + 3; + } - len = strlen(lv->name) + 3; if (!(repstr = dm_pool_zalloc(mem, len))) { log_error("dm_pool_alloc failed"); return 0; } - if (dm_snprintf(repstr, len, "[%s]", lv->name) < 0) { + if (dm_snprintf(repstr, len, "%s%s%s", + is_historical ? HISTORICAL_LV_PREFIX : "[", + tmp_lvname, + is_historical ? "" : "]") < 0) { log_error("lvname snprintf failed"); return 0; } - if (!(lvname = dm_pool_strdup(mem, lv->name))) { + if (!(lvname = dm_pool_strdup(mem, tmp_lvname))) { log_error("dm_pool_strdup failed"); return 0; } - dm_report_field_set_value(field, repstr, lvname); + return _field_set_value(field, repstr, lvname); +} - return 1; +static int _do_loglv_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private, + int uuid) +{ + const struct logical_volume *lv = (const struct logical_volume *) data; + struct logical_volume *mirror_log_lv = lv_mirror_log_lv(lv); + + if (!mirror_log_lv) + return _field_set_value(field, "", NULL); + + if (uuid) + return _uuid_disp(rh, mem, field, &mirror_log_lv->lvid.id[1], private); + + return _lvname_disp(rh, mem, field, mirror_log_lv, private); +} + +static int _loglv_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)), + struct dm_report_field *field, + const void *data, void *private __attribute__((unused))) +{ + return _do_loglv_disp(rh, mem, field, data, private, 0); +} + +static int _loglvuuid_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)), + struct dm_report_field *field, + const void *data, void *private __attribute__((unused))) +{ + return _do_loglv_disp(rh, mem, field, data, private, 1); +} + +static int _lvfullname_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private __attribute__((unused))) +{ + const struct logical_volume *lv = (const struct logical_volume *) data; + char *repstr; + + if (!(repstr = lv_fullname_dup(mem, lv))) + return_0; + + return _field_set_value(field, repstr, NULL); +} + +static int _lvparent_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const struct logical_volume *lv = (const struct logical_volume *) data; + struct logical_volume *parent_lv = lv_parent(lv); + + if (!parent_lv) + return _field_set_value(field, "", NULL); + + return _lvname_disp(rh, mem, field, parent_lv, private); +} + +static int _do_datalv_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)), + struct dm_report_field *field, + const void *data, void *private __attribute__((unused)), + int uuid) +{ + const struct logical_volume *lv = (const struct logical_volume *) data; + struct logical_volume *data_lv = lv_data_lv(lv); + + if (!data_lv) + return _field_set_value(field, "", NULL); + + if (uuid) + return _uuid_disp(rh, mem, field, &data_lv->lvid.id[1], private); + + return _lvname_disp(rh, mem, field, data_lv, private); } static int _datalv_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)), struct dm_report_field *field, const void *data, void *private __attribute__((unused))) { + return _do_datalv_disp(rh, mem, field, data, private, 0); +} + +static int _datalvuuid_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)), + struct dm_report_field *field, + const void *data, void *private __attribute__((unused))) +{ + return _do_datalv_disp(rh, mem, field, data, private, 1); +} + +static int _do_metadatalv_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)), + struct dm_report_field *field, + const void *data, void *private __attribute__((unused)), + int uuid) +{ const struct logical_volume *lv = (const struct logical_volume *) data; + struct logical_volume *metadata_lv = lv_metadata_lv(lv); - if (lv_is_thin_pool(lv)) - return _lvname_disp(rh, mem, field, - seg_lv(first_seg(lv), 0), private); + if (!metadata_lv) + return _field_set_value(field, "", NULL); - dm_report_field_set_value(field, "", NULL); - return 1; + if (uuid) + return _uuid_disp(rh, mem, field, &metadata_lv->lvid.id[1], private); + + return _lvname_disp(rh, mem, field, metadata_lv, private); } static int _metadatalv_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)), struct dm_report_field *field, const void *data, void *private __attribute__((unused))) { + return _do_metadatalv_disp(rh, mem, field, data, private, 0); +} + +static int _metadatalvuuid_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)), + struct dm_report_field *field, + const void *data, void *private __attribute__((unused))) +{ + return _do_metadatalv_disp(rh, mem, field, data, private, 1); +} + +static int _do_poollv_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private, + int uuid) +{ const struct logical_volume *lv = (const struct logical_volume *) data; + struct logical_volume *pool_lv = lv_pool_lv(lv); - if (lv_is_thin_pool(lv)) - return _lvname_disp(rh, mem, field, - first_seg(lv)->metadata_lv, private); + if (!pool_lv) + return _field_set_value(field, "", NULL); - dm_report_field_set_value(field, "", NULL); - return 1; + if (uuid) + return _uuid_disp(rh, mem, field, &pool_lv->lvid.id[1], private); + + return _lvname_disp(rh, mem, field, pool_lv, private); } static int _poollv_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)), struct dm_report_field *field, const void *data, void *private __attribute__((unused))) { - const struct logical_volume *lv = (const struct logical_volume *) data; - struct lv_segment *seg; - - if (lv_is_thin_volume(lv)) - dm_list_iterate_items(seg, &lv->segments) - if (seg_is_thin_volume(seg)) - return _lvname_disp(rh, mem, field, - seg->pool_lv, private); + return _do_poollv_disp(rh, mem, field, data, private, 0); +} - dm_report_field_set_value(field, "", NULL); - return 1; +static int _poollvuuid_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private __attribute__((unused))) +{ + return _do_poollv_disp(rh, mem, field, data, private, 1); } static int _lvpath_disp(struct dm_report *rh, struct dm_pool *mem, @@ -324,56 +1966,346 @@ static int _lvpath_disp(struct dm_report *rh, struct dm_pool *mem, char *repstr; if (!(repstr = lv_path_dup(mem, lv))) - return 0; + return_0; - dm_report_field_set_value(field, repstr, NULL); + return _field_set_value(field, repstr, NULL); +} - return 1; +static int _lvdmpath_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private __attribute__((unused))) +{ + const struct logical_volume *lv = (const struct logical_volume *) data; + char *repstr; + + if (!(repstr = lv_dmpath_dup(mem, lv))) + return_0; + + return _field_set_value(field, repstr, NULL); +} + +static int _do_origin_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private, + int uuid) +{ + const struct logical_volume *lv = (const struct logical_volume *) data; + struct logical_volume *origin_lv = lv_origin_lv(lv); + + if (!origin_lv) + return _field_set_value(field, "", NULL); + + if (uuid) + return _uuid_disp(rh, mem, field, &origin_lv->lvid.id[1], private); + + return _lvname_disp(rh, mem, field, origin_lv, private); } static int _origin_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { - const struct logical_volume *lv = (const struct logical_volume *) data; + return _do_origin_disp(rh, mem, field, data, private, 0); +} - if (lv_is_cow(lv)) - return _lvname_disp(rh, mem, field, origin_from_cow(lv), private); +static int _originuuid_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + return _do_origin_disp(rh, mem, field, data, private, 1); +} + +static const char *_get_glv_str(char *buf, size_t buf_len, + struct generic_logical_volume *glv) +{ + if (!glv->is_historical) + return glv->live->name; + + if (dm_snprintf(buf, buf_len, "%s%s", HISTORICAL_LV_PREFIX, glv->historical->name) < 0) { + log_error("_get_glv_str: dm_snprintf failed"); + return NULL; + } - if (lv_is_thin_volume(lv) && first_seg(lv)->origin) - return _lvname_disp(rh, mem, field, first_seg(lv)->origin, private); + return buf; +} + +static int _find_ancestors(struct _str_list_append_baton *ancestors, + struct generic_logical_volume glv, + int full, int include_historical_lvs) +{ + struct lv_segment *seg; + void *orig_p = glv.live; + const char *ancestor_str; + char buf[NAME_LEN + sizeof(HISTORICAL_LV_PREFIX)]; + + if (glv.is_historical) { + if (full && glv.historical->indirect_origin) + glv = *glv.historical->indirect_origin; + } else if (lv_is_cow(glv.live)) { + glv.live = origin_from_cow(glv.live); + } else if (lv_is_thin_volume(glv.live)) { + seg = first_seg(glv.live); + if (seg->origin) + glv.live = seg->origin; + else if (seg->external_lv) + glv.live = seg->external_lv; + else if (full && seg->indirect_origin) + glv = *seg->indirect_origin; + } + + if (orig_p != glv.live) { + if (!(ancestor_str = _get_glv_str(buf, sizeof(buf), &glv))) + return_0; + if (!glv.is_historical || include_historical_lvs) { + if (!_str_list_append(ancestor_str, ancestors)) + return_0; + } + if (!_find_ancestors(ancestors, glv, full, include_historical_lvs)) + return_0; + } + + return 1; +} + +static int _lvancestors_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + struct cmd_context *cmd = (struct cmd_context *) private; + struct logical_volume *lv = (struct logical_volume *) data; + struct _str_list_append_baton ancestors; + struct generic_logical_volume glv; + + ancestors.mem = mem; + if (!(ancestors.result = str_list_create(mem))) + return_0; + + if ((glv.is_historical = lv_is_historical(lv))) + glv.historical = lv->this_glv->historical; + else + glv.live = lv; + + if (!_find_ancestors(&ancestors, glv, 0, cmd->include_historical_lvs)) { + dm_pool_free(ancestors.mem, ancestors.result); + return_0; + } + + return _field_set_string_list(rh, field, ancestors.result, private, 0, NULL); +} + +static int _lvfullancestors_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + struct cmd_context *cmd = (struct cmd_context *) private; + struct logical_volume *lv = (struct logical_volume *) data; + struct _str_list_append_baton full_ancestors; + struct generic_logical_volume glv; + + full_ancestors.mem = mem; + if (!(full_ancestors.result = str_list_create(mem))) + return_0; + + if ((glv.is_historical = lv_is_historical(lv))) + glv.historical = lv->this_glv->historical; + else + glv.live = lv; + + if (!_find_ancestors(&full_ancestors, glv, 1, cmd->include_historical_lvs)) { + dm_pool_free(full_ancestors.mem, full_ancestors.result); + return_0; + } + + return _field_set_string_list(rh, field, full_ancestors.result, private, 0, NULL); +} + +static int _find_descendants(struct _str_list_append_baton *descendants, + struct generic_logical_volume glv, + int full, int include_historical_lvs) +{ + struct generic_logical_volume glv_next = {0}; + const struct seg_list *sl; + struct lv_segment *seg; + struct glv_list *glvl; + struct dm_list *list; + const char *descendant_str; + char buf[64]; + + if (glv.is_historical) { + if (full) { + list = &glv.historical->indirect_glvs; + dm_list_iterate_items(glvl, list) { + if (!glvl->glv->is_historical || include_historical_lvs) { + if (!(descendant_str = _get_glv_str(buf, sizeof(buf), glvl->glv))) + return_0; + if (!_str_list_append(descendant_str, descendants)) + return_0; + } + if (!_find_descendants(descendants, *glvl->glv, full, include_historical_lvs)) + return_0; + } + } + } else if (lv_is_origin(glv.live)) { + list = &glv.live->snapshot_segs; + dm_list_iterate_items_gen(seg, list, origin_list) { + if ((glv.live = seg->cow)) { + if (!(descendant_str = _get_glv_str(buf, sizeof(buf), &glv))) + return_0; + if (!_str_list_append(descendant_str, descendants)) + return_0; + if (!_find_descendants(descendants, glv, full, include_historical_lvs)) + return_0; + } + } + } else { + list = &glv.live->segs_using_this_lv; + dm_list_iterate_items(sl, list) { + if (lv_is_thin_volume(sl->seg->lv)) { + seg = first_seg(sl->seg->lv); + if ((seg->origin == glv.live) || (seg->external_lv == glv.live)) { + glv_next.live = sl->seg->lv; + if (!(descendant_str = _get_glv_str(buf, sizeof(buf), &glv_next))) + return_0; + if (!_str_list_append(descendant_str, descendants)) + return_0; + if (!_find_descendants(descendants, glv_next, full, include_historical_lvs)) + return_0; + } + } + } + + if (full) { + list = &glv.live->indirect_glvs; + dm_list_iterate_items(glvl, list) { + if (!glvl->glv->is_historical || include_historical_lvs) { + if (!(descendant_str = _get_glv_str(buf, sizeof(buf), glvl->glv))) + return_0; + if (!_str_list_append(descendant_str, descendants)) + return_0; + } + if (!_find_descendants(descendants, *glvl->glv, full, include_historical_lvs)) + return_0; + } + } + } - dm_report_field_set_value(field, "", NULL); return 1; } +static int _lvdescendants_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + struct cmd_context *cmd = (struct cmd_context *) private; + struct logical_volume *lv = (struct logical_volume *) data; + struct _str_list_append_baton descendants; + struct generic_logical_volume glv; + + descendants.mem = mem; + if (!(descendants.result = str_list_create(mem))) + return_0; + + if ((glv.is_historical = lv_is_historical(lv))) + glv.historical = lv->this_glv->historical; + else + glv.live = lv; + + if (!_find_descendants(&descendants, glv, 0, cmd->include_historical_lvs)) { + dm_pool_free(descendants.mem, descendants.result); + return_0; + } + + return _field_set_string_list(rh, field, descendants.result, private, 0, NULL); +} + +static int _lvfulldescendants_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + struct cmd_context *cmd = (struct cmd_context *) private; + struct logical_volume *lv = (struct logical_volume *) data; + struct _str_list_append_baton descendants; + struct generic_logical_volume glv; + + descendants.mem = mem; + if (!(descendants.result = str_list_create(mem))) + return_0; + + if ((glv.is_historical = lv_is_historical(lv))) + glv.historical = lv->this_glv->historical; + else + glv.live = lv; + + if (!_find_descendants(&descendants, glv, 1, cmd->include_historical_lvs)) { + dm_pool_free(descendants.mem, descendants.result); + return_0; + } + + return _field_set_string_list(rh, field, descendants.result, private, 0, NULL); +} + +static int _do_movepv_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private, + int uuid) +{ + const struct logical_volume *lv = (const struct logical_volume *) data; + const char *repstr; + + if (uuid) + repstr = lv_move_pv_uuid_dup(mem, lv); + else + repstr = lv_move_pv_dup(mem, lv); + + if (repstr) + return _field_string(rh, field, repstr); + + return _field_set_value(field, "", NULL); +} + static int _movepv_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)), struct dm_report_field *field, const void *data, void *private __attribute__((unused))) { + return _do_movepv_disp(rh, mem, field, data, private, 0); +} + +static int _movepvuuid_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)), + struct dm_report_field *field, + const void *data, void *private __attribute__((unused))) +{ + return _do_movepv_disp(rh, mem, field, data, private, 1); +} + +static int _do_convertlv_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private, + int uuid) +{ const struct logical_volume *lv = (const struct logical_volume *) data; - const char *name; + const struct logical_volume *convert_lv = lv_convert_lv(lv); - if (!(name = lv_move_pv_dup(mem, lv))) - dm_report_field_set_value(field, "", NULL); - else - return dm_report_field_string(rh, field, &name); - return 1; + if (!convert_lv) + return _field_set_value(field, "", NULL); + + if (uuid) + return _uuid_disp(rh, mem, field, &convert_lv->lvid.id[1], private); + + return _lvname_disp(rh, mem, field, convert_lv, private); } static int _convertlv_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)), struct dm_report_field *field, const void *data, void *private __attribute__((unused))) { - const struct logical_volume *lv = (const struct logical_volume *) data; - const char *name = NULL; - - name = lv_convert_lv_dup(mem, lv); - if (name) - return dm_report_field_string(rh, field, &name); + return _do_convertlv_disp(rh, mem, field, data, private, 0); +} - dm_report_field_set_value(field, "", NULL); - return 1; +static int _convertlvuuid_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)), + struct dm_report_field *field, + const void *data, void *private __attribute__((unused))) +{ + return _do_convertlv_disp(rh, mem, field, data, private, 1); } static int _size32_disp(struct dm_report *rh __attribute__((unused)), struct dm_pool *mem, @@ -382,7 +2314,7 @@ static int _size32_disp(struct dm_report *rh __attribute__((unused)), struct dm_ { const uint32_t size = *(const uint32_t *) data; const char *disp, *repstr; - uint64_t *sortval; + double *sortval; if (!*(disp = display_size_units(private, (uint64_t) size))) return_0; @@ -397,11 +2329,9 @@ static int _size32_disp(struct dm_report *rh __attribute__((unused)), struct dm_ return 0; } - *sortval = (uint64_t) size; + *sortval = (double) size; - dm_report_field_set_value(field, repstr, sortval); - - return 1; + return _field_set_value(field, repstr, sortval); } static int _size64_disp(struct dm_report *rh __attribute__((unused)), @@ -411,7 +2341,7 @@ static int _size64_disp(struct dm_report *rh __attribute__((unused)), { const uint64_t size = *(const uint64_t *) data; const char *disp, *repstr; - uint64_t *sortval; + double *sortval; if (!*(disp = display_size_units(private, size))) return_0; @@ -421,15 +2351,30 @@ static int _size64_disp(struct dm_report *rh __attribute__((unused)), return 0; } - if (!(sortval = dm_pool_alloc(mem, sizeof(uint64_t)))) { + if (!(sortval = dm_pool_alloc(mem, sizeof(double)))) { log_error("dm_pool_alloc failed"); return 0; } - *sortval = size; - dm_report_field_set_value(field, repstr, sortval); + *sortval = (double) size; - return 1; + return _field_set_value(field, repstr, sortval); +} + +static int _lv_size_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const struct logical_volume *lv = (const struct logical_volume *) data; + const struct lv_segment *seg = first_seg(lv); + uint64_t size = lv->le_count; + + if (seg && !lv_is_raid_image(lv)) + size -= (uint64_t) seg->reshape_len * (seg->area_count > 2 ? (seg->area_count - seg->segtype->parity_devs) : 1); + + size *= lv->vg->extent_size; + + return _size64_disp(rh, mem, field, &size, private); } static int _uint32_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)), @@ -439,6 +2384,15 @@ static int _uint32_disp(struct dm_report *rh, struct dm_pool *mem __attribute__( return dm_report_field_uint32(rh, field, data); } +static int _int8_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)), + struct dm_report_field *field, + const void *data, void *private __attribute__((unused))) +{ + const int32_t val = *(const int8_t *)data; + + return dm_report_field_int32(rh, field, &val); +} + static int _int32_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)), struct dm_report_field *field, const void *data, void *private __attribute__((unused))) @@ -446,16 +2400,34 @@ static int _int32_disp(struct dm_report *rh, struct dm_pool *mem __attribute__(( return dm_report_field_int32(rh, field, data); } +static int _lvwhenfull_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private __attribute__((unused))) +{ + const struct logical_volume *lv = (const struct logical_volume *) data; + + if (lv_is_thin_pool(lv)) { + if (lv->status & LV_ERROR_WHEN_FULL) + return _field_set_value(field, GET_FIRST_RESERVED_NAME(lv_when_full_error), + GET_FIELD_RESERVED_VALUE(lv_when_full_error)); + + return _field_set_value(field, GET_FIRST_RESERVED_NAME(lv_when_full_queue), + GET_FIELD_RESERVED_VALUE(lv_when_full_queue)); + } + + return _field_set_value(field, GET_FIRST_RESERVED_NAME(lv_when_full_undef), + GET_FIELD_RESERVED_VALUE(lv_when_full_undef)); +} + static int _lvreadahead_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private __attribute__((unused))) { const struct logical_volume *lv = (const struct logical_volume *) data; - if (lv->read_ahead == DM_READ_AHEAD_AUTO) { - dm_report_field_set_value(field, "auto", &_minusone64); - return 1; - } + if (lv->read_ahead == DM_READ_AHEAD_AUTO) + return _field_set_value(field, GET_FIRST_RESERVED_NAME(lv_read_ahead_auto), + GET_FIELD_RESERVED_VALUE(lv_read_ahead_auto)); return _size32_disp(rh, mem, field, &lv->read_ahead, private); } @@ -465,13 +2437,80 @@ static int _lvkreadahead_disp(struct dm_report *rh, struct dm_pool *mem, const void *data, void *private) { - const struct logical_volume *lv = (const struct logical_volume *) data; - uint32_t read_ahead; + const struct lv_with_info_and_seg_status *lvdm = (const struct lv_with_info_and_seg_status *) data; + + if (!lvdm->info.exists) + return dm_report_field_int32(rh, field, &GET_TYPE_RESERVED_VALUE(num_undef_32)); + + return _size32_disp(rh, mem, field, &lvdm->info.read_ahead, private); +} + +static int _vdo_operating_mode_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const struct lv_with_info_and_seg_status *lvdm = (const struct lv_with_info_and_seg_status *) data; - if ((read_ahead = lv_kernel_read_ahead(lv)) == UINT32_MAX) - return dm_report_field_int32(rh, field, &_minusone32); + if ((lv_is_vdo_pool(lvdm->lv) || lv_is_vdo(lvdm->lv)) && + (lvdm->seg_status.type == SEG_STATUS_VDO_POOL)) + return _field_string(rh, field, get_vdo_operating_mode_name(lvdm->seg_status.vdo_pool.vdo->operating_mode)); - return _size32_disp(rh, mem, field, &read_ahead, private); + return _field_set_value(field, "", &GET_TYPE_RESERVED_VALUE(num_undef_64)); +} + +static int _vdo_compression_state_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const struct lv_with_info_and_seg_status *lvdm = (const struct lv_with_info_and_seg_status *) data; + + if ((lv_is_vdo_pool(lvdm->lv) || lv_is_vdo(lvdm->lv)) && + (lvdm->seg_status.type == SEG_STATUS_VDO_POOL)) + return _field_string(rh, field, get_vdo_compression_state_name(lvdm->seg_status.vdo_pool.vdo->compression_state)); + + return _field_set_value(field, "", &GET_TYPE_RESERVED_VALUE(num_undef_64)); +} + +static int _vdo_index_state_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const struct lv_with_info_and_seg_status *lvdm = (const struct lv_with_info_and_seg_status *) data; + + if ((lv_is_vdo_pool(lvdm->lv) || lv_is_vdo(lvdm->lv)) && + (lvdm->seg_status.type == SEG_STATUS_VDO_POOL)) + return _field_string(rh, field, get_vdo_index_state_name(lvdm->seg_status.vdo_pool.vdo->index_state)); + + return _field_set_value(field, "", &GET_TYPE_RESERVED_VALUE(num_undef_64)); +} + +static int _vdo_used_size_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + uint64_t size; + const struct lv_with_info_and_seg_status *lvdm = (const struct lv_with_info_and_seg_status *) data; + + if ((lv_is_vdo_pool(lvdm->lv) || lv_is_vdo(lvdm->lv)) && + (lvdm->seg_status.type == SEG_STATUS_VDO_POOL)) { + size = lvdm->seg_status.vdo_pool.vdo->used_blocks * DM_VDO_BLOCK_SIZE; + return _size64_disp(rh, mem, field, &size, private); + } + + return _field_set_value(field, "", &GET_TYPE_RESERVED_VALUE(num_undef_64)); +} + +static int _vdo_saving_percent_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const struct lv_with_info_and_seg_status *lvdm = (const struct lv_with_info_and_seg_status *) data; + + if ((lv_is_vdo_pool(lvdm->lv) || lv_is_vdo(lvdm->lv)) && + (lvdm->seg_status.type == SEG_STATUS_VDO_POOL)) + return dm_report_field_percent(rh, field, &lvdm->seg_status.vdo_pool.saving); + + return _field_set_value(field, "", &GET_TYPE_RESERVED_VALUE(num_undef_64)); } static int _vgsize_disp(struct dm_report *rh, struct dm_pool *mem, @@ -479,21 +2518,34 @@ static int _vgsize_disp(struct dm_report *rh, struct dm_pool *mem, const void *data, void *private) { const struct volume_group *vg = (const struct volume_group *) data; - uint64_t size; - - size = (uint64_t) vg_size(vg); + uint64_t size = vg_size(vg); return _size64_disp(rh, mem, field, &size, private); } +static int _segmonitor_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const struct lv_segment *seg = (const struct lv_segment *)data; + char *str; + + if (!(str = lvseg_monitor_dup(mem, seg))) + return_0; + + if (*str) + return _field_set_value(field, str, NULL); + + return _field_set_value(field, GET_FIRST_RESERVED_NAME(seg_monitor_undef), + GET_FIELD_RESERVED_VALUE(seg_monitor_undef)); +} + static int _segstart_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { const struct lv_segment *seg = (const struct lv_segment *) data; - uint64_t start; - - start = lvseg_start(seg); + uint64_t start = lvseg_start(seg); return _size64_disp(rh, mem, field, &start, private); } @@ -509,43 +2561,226 @@ static int _segstartpe_disp(struct dm_report *rh, return dm_report_field_uint32(rh, field, &seg->le); } +/* Hepler: get used stripes = total stripes minux any to remove after reshape */ +static int _get_seg_used_stripes(const struct lv_segment *seg) +{ + uint32_t s; + uint32_t stripes = seg->area_count; + + for (s = seg->area_count - 1; stripes && s; s--) { + if (seg_type(seg, s) == AREA_LV && + seg_lv(seg, s)->status & LV_REMOVE_AFTER_RESHAPE) + stripes--; + else + break; + } + + return stripes; +} + +static int _seg_stripes_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const struct lv_segment *seg = ((const struct lv_segment *) data); + + return dm_report_field_uint32(rh, field, &seg->area_count); +} + +/* Report the number of data stripes, which is less than total stripes (e.g. 2 less for raid6) */ +static int _seg_data_stripes_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const struct lv_segment *seg = (const struct lv_segment *) data; + uint32_t stripes = _get_seg_used_stripes(seg) - seg->segtype->parity_devs; + + /* FIXME: in case of odd numbers of raid10 stripes */ + if (seg_is_raid10(seg)) + stripes /= seg->data_copies; + + return dm_report_field_uint32(rh, field, &stripes); +} + +/* Helper: return the top-level, reshapable raid LV in case @seg belongs to an raid rimage LV */ +static struct logical_volume *_lv_for_raid_image_seg(const struct lv_segment *seg, struct dm_pool *mem) +{ + char *lv_name; + + if (seg_is_reshapable_raid(seg)) + return seg->lv; + + if (seg->lv && + lv_is_raid_image(seg->lv) && !seg->le && + (lv_name = dm_pool_strdup(mem, seg->lv->name))) { + char *p = strchr(lv_name, '_'); + + if (p) { + /* Handle duplicated sub LVs */ + if (strstr(p, "_dup_")) + p = strchr(p + 5, '_'); + + if (p) { + struct lv_list *lvl; + + *p = '\0'; + if ((lvl = find_lv_in_vg(seg->lv->vg, lv_name)) && + seg_is_reshapable_raid(first_seg(lvl->lv))) + return lvl->lv; + + } + } + } + + return NULL; +} + +/* Helper: return the top-level raid LV in case it is reshapale for @seg or @seg if it is */ +static const struct lv_segment *_get_reshapable_seg(const struct lv_segment *seg, struct dm_pool *mem) +{ + return _lv_for_raid_image_seg(seg, mem) ? seg : NULL; +} + +/* Display segment reshape length in current units */ +static int _seg_reshape_len_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const struct lv_segment *seg = _get_reshapable_seg((const struct lv_segment *) data, mem); + + if (seg) { + uint32_t reshape_len = seg->reshape_len * seg->area_count * seg->lv->vg->extent_size; + + return _size32_disp(rh, mem, field, &reshape_len, private); + } + + return _field_set_value(field, "", &GET_TYPE_RESERVED_VALUE(num_undef_64)); +} + +/* Display segment reshape length of in logical extents */ +static int _seg_reshape_len_le_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const struct lv_segment *seg = _get_reshapable_seg((const struct lv_segment *) data, mem); + + if (seg) { + uint32_t reshape_len = seg->reshape_len* seg->area_count; + + return dm_report_field_uint32(rh, field, &reshape_len); + } + + return _field_set_value(field, "", &GET_TYPE_RESERVED_VALUE(num_undef_64)); +} + +/* Display segment data copies (e.g. 3 for raid6) */ +static int _seg_data_copies_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const struct lv_segment *seg = (const struct lv_segment *) data; + + if (seg->data_copies) + return dm_report_field_uint32(rh, field, &seg->data_copies); + + return _field_set_value(field, "", &GET_TYPE_RESERVED_VALUE(num_undef_64)); +} + +/* Helper: display segment data offset/new data offset in sectors */ +static int _segdata_offset(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private, int new_data_offset) +{ + const struct lv_segment *seg = (const struct lv_segment *) data; + struct logical_volume *lv; + + if ((lv = _lv_for_raid_image_seg(seg, mem))) { + uint64_t data_offset = 0; + + if (lv_raid_data_offset(lv, &data_offset)) { + if (new_data_offset && lv_is_raid_image(lv) && !lv_raid_image_in_sync(lv)) + data_offset = data_offset ? 0 : (uint64_t) seg->reshape_len * lv->vg->extent_size; + + return dm_report_field_uint64(rh, field, &data_offset); + } + + } + + return _field_set_value(field, "", &GET_TYPE_RESERVED_VALUE(num_undef_64)); +} + +static int _seg_data_offset_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + return _segdata_offset(rh, mem, field, data, private, 0); +} + +static int _seg_new_data_offset_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + return _segdata_offset(rh, mem, field, data, private, 1); +} + +static int _seg_parity_chunks_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const struct lv_segment *seg = (const struct lv_segment *) data; + uint32_t parity_chunks = seg->segtype->parity_devs ?: seg->data_copies - 1; + + if (parity_chunks) { + uint32_t s, resilient_sub_lvs = 0; + + for (s = 0; s < seg->area_count; s++) { + if (seg_type(seg, s) == AREA_LV) { + struct lv_segment *seg1 = first_seg(seg_lv(seg, s)); + + if (seg1->segtype->parity_devs || + seg1->data_copies > 1) + resilient_sub_lvs++; + } + } + + if (resilient_sub_lvs && resilient_sub_lvs == seg->area_count) + parity_chunks++; + + return dm_report_field_uint32(rh, field, &parity_chunks); + } + + return _field_set_value(field, "", &GET_TYPE_RESERVED_VALUE(num_undef_64)); +} + static int _segsize_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { const struct lv_segment *seg = (const struct lv_segment *) data; - uint64_t size; - - size = lvseg_size(seg); + uint64_t size = lvseg_size(seg); return _size64_disp(rh, mem, field, &size, private); } -static int _chunksize_disp(struct dm_report *rh, struct dm_pool *mem, +static int _segsizepe_disp(struct dm_report *rh, + struct dm_pool *mem __attribute__((unused)), struct dm_report_field *field, - const void *data, void *private) + const void *data, + void *private __attribute__((unused))) { const struct lv_segment *seg = (const struct lv_segment *) data; - uint64_t size; - size = lvseg_chunksize(seg); - - return _size64_disp(rh, mem, field, &size, private); + return dm_report_field_uint32(rh, field, &seg->len); } -static int _thinzero_disp(struct dm_report *rh, struct dm_pool *mem, +static int _chunksize_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { const struct lv_segment *seg = (const struct lv_segment *) data; + uint64_t size = lvseg_chunksize(seg); - /* Suppress thin count if not thin pool */ - if (!seg_is_thin_pool(seg)) { - dm_report_field_set_value(field, "", NULL); - return 1; - } - - return _uint32_disp(rh, mem, field, &seg->zero_new_blocks, private); + return _size64_disp(rh, mem, field, &size, private); } static int _transactionid_disp(struct dm_report *rh, struct dm_pool *mem, @@ -554,13 +2789,22 @@ static int _transactionid_disp(struct dm_report *rh, struct dm_pool *mem, { const struct lv_segment *seg = (const struct lv_segment *) data; - /* Suppress thin count if not thin pool */ - if (!seg_is_thin_pool(seg)) { - dm_report_field_set_value(field, "", NULL); - return 1; - } + if (seg_is_thin_pool(seg) || seg_is_thin_volume(seg)) + return dm_report_field_uint64(rh, field, &seg->transaction_id); + + return _field_set_value(field, "", &GET_TYPE_RESERVED_VALUE(num_undef_64)); +} + +static int _thinid_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const struct lv_segment *seg = (const struct lv_segment *) data; - return dm_report_field_uint64(rh, field, &seg->transaction_id); + if (seg_is_thin_volume(seg)) + return dm_report_field_uint32(rh, field, &seg->device_id); + + return _field_set_value(field, "", &GET_TYPE_RESERVED_VALUE(num_undef_64)); } static int _discards_disp(struct dm_report *rh, struct dm_pool *mem, @@ -575,12 +2819,68 @@ static int _discards_disp(struct dm_report *rh, struct dm_pool *mem, if (seg_is_thin_pool(seg)) { discards_str = get_pool_discards_name(seg->discards); - return dm_report_field_string(rh, field, &discards_str); + return _field_string(rh, field, discards_str); } - dm_report_field_set_value(field, "", NULL); + return _field_set_value(field, "", NULL); +} - return 1; +static int _kdiscards_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const struct lv_with_info_and_seg_status *lvdm = (const struct lv_with_info_and_seg_status *) data; + const char *discards_str; + + if (!(discards_str = lvseg_kernel_discards_dup_with_info_and_seg_status(mem, lvdm))) + return_0; + + if (*discards_str) + return _field_set_value(field, discards_str, NULL); + + return _field_set_value(field, GET_FIRST_RESERVED_NAME(seg_kernel_discards_undef), + GET_FIELD_RESERVED_VALUE(seg_kernel_discards_undef)); +} + +static int _cachemode_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const struct lv_segment *seg = (const struct lv_segment *) data; + + return _field_string(rh, field, display_cache_mode(seg)); +} + +static int _cachemetadataformat_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const struct lv_segment *seg = (const struct lv_segment *) data; + const struct lv_segment *setting_seg = NULL; + const uint64_t *fmt; + + if (seg_is_cache(seg) && lv_is_cache_vol(seg->pool_lv)) + setting_seg = seg; + + else if (seg_is_cache_pool(seg)) + setting_seg = seg; + + else if (seg_is_cache(seg)) + setting_seg = first_seg(seg->pool_lv); + + else + goto undef; + + switch (setting_seg->cache_metadata_format) { + case CACHE_METADATA_FORMAT_1: + case CACHE_METADATA_FORMAT_2: + fmt = (setting_seg->cache_metadata_format == CACHE_METADATA_FORMAT_2) ? &_two64 : &_one64; + return dm_report_field_uint64(rh, field, fmt); + default: /* unselected/undefined for all other cases */; + } + + undef: + return _field_set_value(field, "", &GET_TYPE_RESERVED_VALUE(num_undef_64)); } static int _originsize_disp(struct dm_report *rh, struct dm_pool *mem, @@ -588,11 +2888,12 @@ static int _originsize_disp(struct dm_report *rh, struct dm_pool *mem, const void *data, void *private) { const struct logical_volume *lv = (const struct logical_volume *) data; - uint64_t size; + uint64_t size = lv_origin_size(lv); - size = lv_origin_size(lv); + if (size) + return _size64_disp(rh, mem, field, &size, private); - return _size64_disp(rh, mem, field, &size, private); + return _field_set_value(field, "", &_zero64); } static int _pvused_disp(struct dm_report *rh, struct dm_pool *mem, @@ -601,9 +2902,8 @@ static int _pvused_disp(struct dm_report *rh, struct dm_pool *mem, { const struct physical_volume *pv = (const struct physical_volume *) data; - uint64_t used; - used = pv_used(pv); + uint64_t used = pv_used(pv); return _size64_disp(rh, mem, field, &used, private); } @@ -616,7 +2916,10 @@ static int _pvfree_disp(struct dm_report *rh, struct dm_pool *mem, (const struct physical_volume *) data; uint64_t freespace; - freespace = pv_free(pv); + if (is_orphan(pv) && is_used_pv(pv)) + freespace = 0; + else + freespace = pv_free(pv); return _size64_disp(rh, mem, field, &freespace, private); } @@ -627,9 +2930,7 @@ static int _pvsize_disp(struct dm_report *rh, struct dm_pool *mem, { const struct physical_volume *pv = (const struct physical_volume *) data; - uint64_t size; - - size = pv_size_field(pv); + uint64_t size = pv_size_field(pv); return _size64_disp(rh, mem, field, &size, private); } @@ -638,11 +2939,11 @@ static int _devsize_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { - const struct physical_volume *pv = - (const struct physical_volume *) data; + struct device *dev = *(struct device * const *) data; uint64_t size; - size = pv_dev_size(pv); + if (!dev || !dev->dev || !dev_get_size(dev, &size)) + size = _zero64; return _size64_disp(rh, mem, field, &size, private); } @@ -652,35 +2953,83 @@ static int _vgfree_disp(struct dm_report *rh, struct dm_pool *mem, const void *data, void *private) { const struct volume_group *vg = (const struct volume_group *) data; - uint64_t freespace; - - freespace = (uint64_t) vg_free(vg); + uint64_t freespace = vg_free(vg); return _size64_disp(rh, mem, field, &freespace, private); } -static int _uuid_disp(struct dm_report *rh __attribute__((unused)), struct dm_pool *mem, - struct dm_report_field *field, - const void *data, void *private __attribute__((unused))) +static int _vgsystemid_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) { - char *repstr = NULL; + const struct volume_group *vg = (const struct volume_group *) data; + const char *repstr = (vg->system_id && *vg->system_id) ? vg->system_id : ""; - if (!(repstr = id_format_and_copy(mem, data))) + return _field_string(rh, field, repstr); +} + +static int _vglocktype_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const struct volume_group *vg = (const struct volume_group *) data; + const char *locktype; + + if (!vg->lock_type || !strcmp(vg->lock_type, "none")) + locktype = ""; + else + locktype = vg->lock_type; + + return _field_string(rh, field, locktype); +} + +static int _vglockargs_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const struct volume_group *vg = (const struct volume_group *) data; + + return _field_string(rh, field, vg->lock_args ? : ""); +} + +static int _lvuuid_disp(struct dm_report *rh __attribute__((unused)), struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private __attribute__((unused))) +{ + const struct logical_volume *lv = (const struct logical_volume *) data; + const union lvid *lvid; + char *repstr; + + if (lv_is_historical(lv)) + lvid = &lv->this_glv->historical->lvid; + else + lvid = &lv->lvid; + + if (!(repstr = id_format_and_copy(mem, &lvid->id[1]))) return_0; - dm_report_field_set_value(field, repstr, NULL); - return 1; + return _field_set_value(field, repstr, NULL); +} + +static int _pvuuid_disp(struct dm_report *rh __attribute__((unused)), struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private __attribute__((unused))) +{ + const struct label *label = (const struct label *) data; + + if (!label->dev) + return _field_set_value(field, "", NULL); + + return _uuid_disp(rh, mem, field, label->dev->pvid, private); } static int _pvmdas_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { - uint32_t count; const struct physical_volume *pv = (const struct physical_volume *) data; - - count = pv_mda_count(pv); + uint32_t count = pv_mda_count(pv); return _uint32_disp(rh, mem, field, &count, private); } @@ -689,11 +3038,9 @@ static int _pvmdasused_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { - uint32_t count; const struct physical_volume *pv = (const struct physical_volume *) data; - - count = pv_mda_used_count(pv); + uint32_t count = pv_mda_used_count(pv); return _uint32_disp(rh, mem, field, &count, private); } @@ -703,9 +3050,7 @@ static int _vgmdas_disp(struct dm_report *rh, struct dm_pool *mem, const void *data, void *private) { const struct volume_group *vg = (const struct volume_group *) data; - uint32_t count; - - count = vg_mda_count(vg); + uint32_t count = vg_mda_count(vg); return _uint32_disp(rh, mem, field, &count, private); } @@ -715,9 +3060,7 @@ static int _vgmdasused_disp(struct dm_report *rh, struct dm_pool *mem, const void *data, void *private) { const struct volume_group *vg = (const struct volume_group *) data; - uint32_t count; - - count = vg_mda_used_count(vg); + uint32_t count = vg_mda_used_count(vg); return _uint32_disp(rh, mem, field, &count, private); } @@ -726,28 +3069,46 @@ static int _vgmdacopies_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { + struct cmd_context *cmd = (struct cmd_context *) private; const struct volume_group *vg = (const struct volume_group *) data; - uint32_t count; + uint32_t count = vg_mda_copies(vg); - count = vg_mda_copies(vg); + if (count == VGMETADATACOPIES_UNMANAGED && !cmd->report_strict_type_mode) + return _field_set_value(field, GET_FIRST_RESERVED_NAME(vg_mda_copies_unmanaged), + GET_FIELD_RESERVED_VALUE(vg_mda_copies_unmanaged)); - if (count == VGMETADATACOPIES_UNMANAGED) { - dm_report_field_set_value(field, "unmanaged", &_minusone64); - return 1; - } + return _uint32_disp(rh, mem, field, &count, private); +} + +static int _vgprofile_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const struct volume_group *vg = (const struct volume_group *) data; + + if (vg->profile) + return _field_string(rh, field, vg->profile->name); + + return _field_set_value(field, "", NULL); +} + +static int _vgmissingpvcount_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const struct volume_group *vg = (const struct volume_group *) data; + uint32_t count = vg_missing_pv_count(vg); return _uint32_disp(rh, mem, field, &count, private); } + static int _pvmdafree_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { - const struct physical_volume *pv = - (const struct physical_volume *) data; - uint64_t freespace; - - freespace = pv_mda_free(pv); + const struct label *label = (const struct label *) data; + uint64_t freespace = lvmcache_info_mda_free(label->info); return _size64_disp(rh, mem, field, &freespace, private); } @@ -756,23 +3117,35 @@ static int _pvmdasize_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { - const struct physical_volume *pv = - (const struct physical_volume *) data; - uint64_t min_mda_size; - - min_mda_size = pv_mda_size(pv); + const struct label *label = (const struct label *) data; + uint64_t min_mda_size = lvmcache_smallest_mda_size(label->info); return _size64_disp(rh, mem, field, &min_mda_size, private); } +static int _pvextvsn_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const struct label *label = (const struct label *) data; + struct lvmcache_info *info = label->info; + uint32_t ext_version; + + if (info) { + ext_version = lvmcache_ext_version(info); + return _uint32_disp(rh, mem, field, &ext_version, private); + } + + return _field_set_value(field, "", &GET_TYPE_RESERVED_VALUE(num_undef_64)); +} + + static int _vgmdasize_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { const struct volume_group *vg = (const struct volume_group *) data; - uint64_t min_mda_size; - - min_mda_size = vg_mda_size(vg); + uint64_t min_mda_size = vg_mda_size(vg); return _size64_disp(rh, mem, field, &min_mda_size, private); } @@ -782,9 +3155,7 @@ static int _vgmdafree_disp(struct dm_report *rh, struct dm_pool *mem, const void *data, void *private) { const struct volume_group *vg = (const struct volume_group *) data; - uint64_t freespace; - - freespace = vg_mda_free(vg); + uint64_t freespace = vg_mda_free(vg); return _size64_disp(rh, mem, field, &freespace, private); } @@ -794,9 +3165,7 @@ static int _lvcount_disp(struct dm_report *rh, struct dm_pool *mem, const void *data, void *private) { const struct volume_group *vg = (const struct volume_group *) data; - uint32_t count; - - count = vg_visible_lvs(vg); + uint32_t count = vg_visible_lvs(vg); return _uint32_disp(rh, mem, field, &count, private); } @@ -806,9 +3175,7 @@ static int _lvsegcount_disp(struct dm_report *rh, struct dm_pool *mem, const void *data, void *private) { const struct logical_volume *lv = (const struct logical_volume *) data; - uint32_t count; - - count = dm_list_size(&lv->segments); + uint32_t count = dm_list_size(&lv->segments); return _uint32_disp(rh, mem, field, &count, private); } @@ -818,277 +3185,1118 @@ static int _snapcount_disp(struct dm_report *rh, struct dm_pool *mem, const void *data, void *private) { const struct volume_group *vg = (const struct volume_group *) data; - uint32_t count; - - count = snapshot_count(vg); + uint32_t count = snapshot_count(vg); return _uint32_disp(rh, mem, field, &count, private); } -static int _snpercent_disp(struct dm_report *rh __attribute__((unused)), struct dm_pool *mem, +static int _snpercent_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)), struct dm_report_field *field, const void *data, void *private __attribute__((unused))) { + const struct lv_with_info_and_seg_status *lvdm = (const struct lv_with_info_and_seg_status *) data; + + dm_percent_t percent = lvseg_percent_with_info_and_seg_status(lvdm, PERCENT_GET_DATA); + + return dm_report_field_percent(rh, field, &percent); +} + +static int _copypercent_disp(struct dm_report *rh, + struct dm_pool *mem __attribute__((unused)), + struct dm_report_field *field, + const void *data, void *private __attribute__((unused))) +{ + const struct lv_with_info_and_seg_status *lvdm = (const struct lv_with_info_and_seg_status *) data; + + const struct logical_volume *lv = lvdm->lv; + dm_percent_t percent = DM_PERCENT_INVALID; + + /* TODO: just cache passes through lvseg_percent... */ + if (lv_is_integrity(lv) || lv_is_cache(lv) || lv_is_used_cache_pool(lv) || + (!lv_is_merging_origin(lv) && lv_is_raid(lv) && !seg_is_any_raid0(first_seg(lv)))) + percent = lvseg_percent_with_info_and_seg_status(lvdm, PERCENT_GET_DIRTY); + else if (lv_is_raid(lv) && !seg_is_any_raid0(first_seg(lv))) + /* old way for percentage when merging snapshot into raid origin */ + (void) lv_raid_percent(lv, &percent); + else if (((lv_is_mirror(lv) && + lv_mirror_percent(lv->vg->cmd, lv, 0, &percent, NULL))) && + (percent != DM_PERCENT_INVALID)) + percent = copy_percent(lv); + + return dm_report_field_percent(rh, field, &percent); +} + +static int _raidsyncaction_disp(struct dm_report *rh __attribute__((unused)), + struct dm_pool *mem, + struct dm_report_field *field, + const void *data, + void *private __attribute__((unused))) +{ const struct logical_volume *lv = (const struct logical_volume *) data; - struct lvinfo info; - percent_t snap_percent; - uint64_t *sortval; + char *sync_action; + + if (lv_is_raid(lv) && lv_raid_sync_action(lv, &sync_action)) + return _field_string(rh, field, sync_action); + + return _field_set_value(field, "", NULL); +} + +static int _raidmismatchcount_disp(struct dm_report *rh __attribute__((unused)), + struct dm_pool *mem, + struct dm_report_field *field, + const void *data, + void *private __attribute__((unused))) +{ + const struct logical_volume *lv = (const struct logical_volume *) data; + uint64_t mismatch_count; + + if (lv_is_raid(lv) && lv_raid_mismatch_count(lv, &mismatch_count)) + return dm_report_field_uint64(rh, field, &mismatch_count); + + return _field_set_value(field, "", &GET_TYPE_RESERVED_VALUE(num_undef_64)); +} + +static int _raidwritebehind_disp(struct dm_report *rh __attribute__((unused)), + struct dm_pool *mem, + struct dm_report_field *field, + const void *data, + void *private __attribute__((unused))) +{ + const struct logical_volume *lv = (const struct logical_volume *) data; + + if (lv_is_raid_type(lv) && first_seg(lv)->writebehind) + return dm_report_field_uint32(rh, field, &first_seg(lv)->writebehind); + + return _field_set_value(field, "", &GET_TYPE_RESERVED_VALUE(num_undef_64)); +} + +static int _raidminrecoveryrate_disp(struct dm_report *rh __attribute__((unused)), + struct dm_pool *mem, + struct dm_report_field *field, + const void *data, + void *private __attribute__((unused))) +{ + const struct logical_volume *lv = (const struct logical_volume *) data; + + if (lv_is_raid_type(lv) && first_seg(lv)->min_recovery_rate) + return dm_report_field_uint32(rh, field, + &first_seg(lv)->min_recovery_rate); + + return _field_set_value(field, "", &GET_TYPE_RESERVED_VALUE(num_undef_64)); +} + +static int _raidmaxrecoveryrate_disp(struct dm_report *rh __attribute__((unused)), + struct dm_pool *mem, + struct dm_report_field *field, + const void *data, + void *private __attribute__((unused))) +{ + const struct logical_volume *lv = (const struct logical_volume *) data; + + if (lv_is_raid_type(lv) && first_seg(lv)->max_recovery_rate) + return dm_report_field_uint32(rh, field, + &first_seg(lv)->max_recovery_rate); + + return _field_set_value(field, "", &GET_TYPE_RESERVED_VALUE(num_undef_64)); +} + +static int _raidintegritymode_disp(struct dm_report *rh __attribute__((unused)), + struct dm_pool *mem, + struct dm_report_field *field, + const void *data, + void *private __attribute__((unused))) +{ + struct logical_volume *lv = (struct logical_volume *) data; + struct integrity_settings *settings = NULL; + const char *mode = NULL; char *repstr; - /* Suppress snapshot percentage if not using driver */ - if (!activation()) { - dm_report_field_set_value(field, "", NULL); - return 1; + if (lv_raid_has_integrity(lv)) + lv_get_raid_integrity_settings(lv, &settings); + else if (lv_is_integrity(lv)) + settings = &first_seg(lv)->integrity_settings; + else + goto out; + + if (settings && settings->mode[0]) { + if (settings->mode[0] == 'B') + mode = "bitmap"; + else if (settings->mode[0] == 'J') + mode = "journal"; + + if (mode) { + if (!(repstr = dm_pool_strdup(mem, mode))) { + log_error("Failed to allocate buffer for mode."); + return 0; + } + return _field_set_value(field, repstr, NULL); + } } +out: + return _field_set_value(field, "", NULL); +} - if (!(sortval = dm_pool_alloc(mem, sizeof(uint64_t)))) { - log_error("dm_pool_alloc failed"); - return 0; - } +static int _raidintegrityblocksize_disp(struct dm_report *rh __attribute__((unused)), + struct dm_pool *mem, + struct dm_report_field *field, + const void *data, + void *private __attribute__((unused))) +{ + struct logical_volume *lv = (struct logical_volume *) data; + struct integrity_settings *settings = NULL; - if ((!lv_is_cow(lv) && !lv_is_merging_origin(lv)) || - !lv_info(lv->vg->cmd, lv, 0, &info, 0, 0) || !info.exists) { - *sortval = UINT64_C(0); - dm_report_field_set_value(field, "", sortval); - return 1; + if (lv_raid_has_integrity(lv)) + lv_get_raid_integrity_settings(lv, &settings); + else if (lv_is_integrity(lv)) + settings = &first_seg(lv)->integrity_settings; + + if (!settings) + return dm_report_field_int32(rh, field, &GET_TYPE_RESERVED_VALUE(num_undef_32)); + + return dm_report_field_uint32(rh, field, &settings->block_size); +} + +static int _integritymismatches_disp(struct dm_report *rh __attribute__((unused)), + struct dm_pool *mem, + struct dm_report_field *field, + const void *data, + void *private __attribute__((unused))) +{ + struct logical_volume *lv = (struct logical_volume *) data; + uint64_t mismatches = 0; + + if (lv_is_integrity(lv) && lv_integrity_mismatches(lv->vg->cmd, lv, &mismatches)) + return dm_report_field_uint64(rh, field, &mismatches); + + if (lv_is_raid(lv) && lv_raid_has_integrity(lv) && + lv_raid_integrity_total_mismatches(lv->vg->cmd, lv, &mismatches)) + return dm_report_field_uint64(rh, field, &mismatches); + + return _field_set_value(field, "", &GET_TYPE_RESERVED_VALUE(num_undef_64)); +} + +static int _writecache_block_size_disp(struct dm_report *rh __attribute__((unused)), + struct dm_pool *mem, + struct dm_report_field *field, + const void *data, + void *private __attribute__((unused))) +{ + struct logical_volume *lv = (struct logical_volume *) data; + uint32_t bs = 0; + + if (lv_is_writecache(lv)) { + struct lv_segment *seg = first_seg(lv); + bs = seg->writecache_block_size; } - if (!lv_snapshot_percent(lv, &snap_percent) || - (snap_percent == PERCENT_INVALID) || (snap_percent == PERCENT_MERGE_FAILED)) { - if (!lv_is_merging_origin(lv)) { - *sortval = UINT64_C(100); - dm_report_field_set_value(field, "100.00", sortval); - } else { - /* onactivate merge that hasn't started yet would - * otherwise display incorrect snap% in origin - */ - *sortval = UINT64_C(0); - dm_report_field_set_value(field, "", sortval); - } - return 1; + if (!bs) + return dm_report_field_int32(rh, field, &GET_TYPE_RESERVED_VALUE(num_undef_32)); + + return dm_report_field_uint32(rh, field, &bs); +} + +static int _datapercent_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const struct lv_with_info_and_seg_status *lvdm = (const struct lv_with_info_and_seg_status *) data; + + dm_percent_t percent = lvseg_percent_with_info_and_seg_status(lvdm, PERCENT_GET_DATA); + + return dm_report_field_percent(rh, field, &percent); +} + +static int _metadatapercent_disp(struct dm_report *rh, + struct dm_pool *mem __attribute__((unused)), + struct dm_report_field *field, + const void *data, void *private) +{ + const struct lv_with_info_and_seg_status *lvdm = (const struct lv_with_info_and_seg_status *) data; + dm_percent_t percent; + + switch (lvdm->seg_status.type) { + case SEG_STATUS_CACHE: + case SEG_STATUS_THIN_POOL: + percent = lvseg_percent_with_info_and_seg_status(lvdm, PERCENT_GET_METADATA); + break; + default: + percent = DM_PERCENT_INVALID; } - if (!(repstr = dm_pool_zalloc(mem, 8))) { - log_error("dm_pool_alloc failed"); - return 0; + return dm_report_field_percent(rh, field, &percent); +} + +static int _lvmetadatasize_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const struct logical_volume *lv = (const struct logical_volume *) data; + uint64_t size; + + if (lv_is_cache(lv) && lv_is_cache_vol(first_seg(lv)->pool_lv)) { + size = lv_metadata_size(lv); + return _size64_disp(rh, mem, field, &size, private); } - if (dm_snprintf(repstr, 7, "%.2f", percent_to_float(snap_percent)) < 0) { - log_error("snapshot percentage too large"); - return 0; + if (lv_is_thin_pool(lv) || lv_is_cache_pool(lv)) { + size = lv_metadata_size(lv); + return _size64_disp(rh, mem, field, &size, private); } - *sortval = (uint64_t)(snap_percent * 1000.f); - dm_report_field_set_value(field, repstr, sortval); + return _field_set_value(field, "", &GET_TYPE_RESERVED_VALUE(num_undef_64)); +} - return 1; +static int _thincount_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const struct lv_segment *seg = (const struct lv_segment *) data; + uint32_t count; + + if (seg_is_thin_pool(seg)) { + count = dm_list_size(&seg->lv->segs_using_this_lv); + return _uint32_disp(rh, mem, field, &count, private); + } + + return _field_set_value(field, "", &GET_TYPE_RESERVED_VALUE(num_undef_64)); } -static int _copypercent_disp(struct dm_report *rh __attribute__((unused)), - struct dm_pool *mem, - struct dm_report_field *field, - const void *data, void *private __attribute__((unused))) +static int _lvtime_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) { const struct logical_volume *lv = (const struct logical_volume *) data; - percent_t percent; - uint64_t *sortval; char *repstr; + uint64_t *sortval; - if (!(sortval = dm_pool_alloc(mem, sizeof(uint64_t)))) { - log_error("dm_pool_alloc failed"); + if (!(repstr = lv_creation_time_dup(mem, lv, 0)) || + !(sortval = dm_pool_alloc(mem, sizeof(uint64_t)))) { + log_error("Failed to allocate buffer for time."); return 0; } - if ((!(lv->status & PVMOVE) && !(lv->status & MIRRORED)) || - !lv_mirror_percent(lv->vg->cmd, lv, 0, &percent, - NULL) || (percent == PERCENT_INVALID)) { - *sortval = UINT64_C(0); - dm_report_field_set_value(field, "", sortval); - return 1; - } + *sortval = lv_is_historical(lv) ? lv->this_glv->historical->timestamp : lv->timestamp; + return _field_set_value(field, repstr, sortval); +} - percent = copy_percent(lv); +static int _lvtimeremoved_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const struct logical_volume *lv = (const struct logical_volume *) data; + char *repstr; + uint64_t *sortval; - if (!(repstr = dm_pool_zalloc(mem, 8))) { - log_error("dm_pool_alloc failed"); + if (!(repstr = lv_removal_time_dup(mem, lv, 0)) || + !(sortval = dm_pool_alloc(mem, sizeof(uint64_t)))) { + log_error("Failed to allocate buffer for time."); return 0; } - if (dm_snprintf(repstr, 7, "%.2f", percent_to_float(percent)) < 0) { - log_error("copy percentage too large"); + *sortval = lv_is_historical(lv) ? lv->this_glv->historical->timestamp_removed : 0; + return _field_set_value(field, repstr, sortval); +} + +static int _lvhost_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const struct logical_volume *lv = (const struct logical_volume *) data; + char *repstr; + + if (!(repstr = lv_host_dup(mem, lv))) { + log_error("Failed to allocate buffer for host."); return 0; } - *sortval = (uint64_t)(percent * 1000.f); - dm_report_field_set_value(field, repstr, sortval); + return _field_set_value(field, repstr, NULL); +} - return 1; +/* PV/VG/LV Attributes */ + +static int _pvallocatable_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + int allocatable = (((const struct physical_volume *) data)->status & ALLOCATABLE_PV) != 0; + return _binary_disp(rh, mem, field, allocatable, GET_FIRST_RESERVED_NAME(pv_allocatable_y), private); +} + +static int _pvexported_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + int exported = (((const struct physical_volume *) data)->status & EXPORTED_VG) != 0; + return _binary_disp(rh, mem, field, exported, GET_FIRST_RESERVED_NAME(pv_exported_y), private); } -static int _dtpercent_disp(int metadata, struct dm_report *rh, - struct dm_pool *mem, +static int _pvmissing_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { - const struct logical_volume *lv = (const struct logical_volume *) data; - struct lvinfo info; - percent_t percent; - uint64_t *sortval; + int missing = (((const struct physical_volume *) data)->status & MISSING_PV) != 0; + return _binary_disp(rh, mem, field, missing, GET_FIRST_RESERVED_NAME(pv_missing_y), private); +} + +static int _pvinuse_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const struct physical_volume *pv = (const struct physical_volume *) data; + int used = is_used_pv(pv); + + if (used < 0) + return _binary_undef_disp(rh, mem, field, private); + + return _binary_disp(rh, mem, field, used, GET_FIRST_RESERVED_NAME(pv_in_use_y), private); +} + +static int _pvduplicate_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const struct physical_volume *pv = (const struct physical_volume *) data; + int duplicate = lvmcache_dev_is_unused_duplicate(pv->dev); + + return _binary_disp(rh, mem, field, duplicate, GET_FIRST_RESERVED_NAME(pv_duplicate_y), private); +} + +static int _pvdeviceid_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const struct physical_volume *pv = (const struct physical_volume *) data; char *repstr; - /* Suppress data percent if not thin pool/volume or not using driver */ - if (!lv_info(lv->vg->cmd, lv, 1, &info, 0, 0) || !info.exists) { - dm_report_field_set_value(field, "", NULL); - return 1; - } + if (!pv->device_id) + return _field_set_value(field, "", NULL); - if (!(sortval = dm_pool_zalloc(mem, sizeof(uint64_t)))) { - log_error("Failed to allocate sortval."); + if (!(repstr = pv_deviceid_dup(mem, pv))) { + log_error("Failed to allocate buffer."); return 0; } - if (lv_is_thin_pool(lv)) { - if (!lv_thin_pool_percent(lv, metadata, &percent)) - return_0; - } else { /* thin_volume */ - if (!lv_thin_percent(lv, 0, &percent)) - return_0; + return _field_set_value(field, repstr, NULL); +} + +static int _pvdeviceidtype_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const struct physical_volume *pv = (const struct physical_volume *) data; + char *repstr; + + if (!pv->device_id_type) + return _field_set_value(field, "", NULL); + + if (!(repstr = pv_deviceidtype_dup(mem, pv))) { + log_error("Failed to allocate buffer."); + return 0; } - if (!(repstr = dm_pool_alloc(mem, 8))) { - log_error("Failed to allocate report buffer."); + return _field_set_value(field, repstr, NULL); +} + +static int _vgpermissions_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const char *perms = ((const struct volume_group *) data)->status & LVM_WRITE ? GET_FIRST_RESERVED_NAME(vg_permissions_rw) + : GET_FIRST_RESERVED_NAME(vg_permissions_r); + return _field_string(rh, field, perms); +} + +static int _vgextendable_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + int extendable = (vg_is_resizeable((const struct volume_group *) data)) != 0; + return _binary_disp(rh, mem, field, extendable, GET_FIRST_RESERVED_NAME(vg_extendable_y),private); +} + +static int _vgexported_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + int exported = (vg_is_exported((const struct volume_group *) data)) != 0; + return _binary_disp(rh, mem, field, exported, GET_FIRST_RESERVED_NAME(vg_exported_y), private); +} + +static int _vgautoactivation_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const struct volume_group *vg = (const struct volume_group *)data; + int aa_yes = (vg->status & NOAUTOACTIVATE) ? 0 : 1; + return _binary_disp(rh, mem, field, aa_yes, "enabled", private); +} + +static int _vgpartial_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + int partial = (vg_missing_pv_count((const struct volume_group *) data)) != 0; + return _binary_disp(rh, mem, field, partial, GET_FIRST_RESERVED_NAME(vg_partial_y), private); +} + +static int _vgallocationpolicy_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const char *alloc_policy = get_alloc_string(((const struct volume_group *) data)->alloc) ? : _str_unknown; + return _field_string(rh, field, alloc_policy); +} + +static int _vgclustered_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + int clustered = (vg_is_clustered((const struct volume_group *) data)) != 0; + return _binary_disp(rh, mem, field, clustered, GET_FIRST_RESERVED_NAME(vg_clustered_y), private); +} + +static int _vgshared_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + int shared = (vg_is_shared((const struct volume_group *) data)) != 0; + return _binary_disp(rh, mem, field, shared, GET_FIRST_RESERVED_NAME(vg_shared_y), private); +} + +static int _lvlayout_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const struct logical_volume *lv = (const struct logical_volume *) data; + struct dm_list *lv_layout; + struct dm_list *lv_role; + + if (!lv_layout_and_role(mem, lv, &lv_layout, &lv_role)) { + log_error("Failed to display layout for LV %s/%s.", lv->vg->name, lv->name); return 0; } - if (dm_snprintf(repstr, 8, "%.2f", percent_to_float(percent)) < 0) { - log_error("Data percentage too large."); + return _field_set_string_list(rh, field, lv_layout, private, 0, NULL); +} + +static int _lvrole_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const struct logical_volume *lv = (const struct logical_volume *) data; + struct dm_list *lv_layout; + struct dm_list *lv_role; + + if (!lv_layout_and_role(mem, lv, &lv_layout, &lv_role)) { + log_error("Failed to display role for LV %s/%s.", lv->vg->name, lv->name); return 0; } - *sortval = (uint64_t)(percent * 1000.f); - dm_report_field_set_value(field, repstr, sortval); + return _field_set_string_list(rh, field, lv_role, private, 0, NULL); +} - return 1; +static int _lvinitialimagesync_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const struct logical_volume *lv = (const struct logical_volume *) data; + int initial_image_sync; + + if (lv_is_raid(lv) || lv_is_mirrored(lv)) + initial_image_sync = !lv_is_not_synced(lv); + else + initial_image_sync = 0; + + return _binary_disp(rh, mem, field, initial_image_sync, GET_FIRST_RESERVED_NAME(lv_initial_image_sync_y), private); } -static int _datapercent_disp(struct dm_report *rh, struct dm_pool *mem, +static int _lvimagesynced_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const struct logical_volume *lv = (const struct logical_volume *) data; + int image_synced; + + if (lv_is_raid_image(lv)) + image_synced = !lv_is_visible(lv) && lv_raid_image_in_sync(lv); + else if (lv_is_mirror_image(lv)) + image_synced = lv_mirror_image_in_sync(lv); + else + image_synced = 0; + + return _binary_disp(rh, mem, field, image_synced, GET_FIRST_RESERVED_NAME(lv_image_synced_y), private); +} + +static int _lvmerging_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const struct logical_volume *lv = (const struct logical_volume *) data; + int merging; + + if (lv_is_origin(lv) || lv_is_external_origin(lv)) + merging = lv_is_merging_origin(lv); + else if (lv_is_cow(lv)) + merging = lv_is_merging_cow(lv); + else if (lv_is_thin_volume(lv)) + merging = lv_is_merging_thin_snapshot(lv); + else + merging = 0; + + return _binary_disp(rh, mem, field, merging, GET_FIRST_RESERVED_NAME(lv_merging_y), private); +} + +static int _lvconverting_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + int converting = lv_is_converting((const struct logical_volume *) data); + + return _binary_disp(rh, mem, field, converting, "converting", private); +} + +static int _lvpermissions_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const struct lv_with_info_and_seg_status *lvdm = (const struct lv_with_info_and_seg_status *) data; + const char *perms = ""; + + if (!lv_is_pvmove(lvdm->lv)) { + if (lvdm->lv->status & LVM_WRITE) { + if (!lvdm->info.exists) + perms = _str_unknown; + else if (lvdm->info.read_only) + perms = GET_FIRST_RESERVED_NAME(lv_permissions_r_override); + else + perms = GET_FIRST_RESERVED_NAME(lv_permissions_rw); + } else if (lvdm->lv->status & LVM_READ) + perms = GET_FIRST_RESERVED_NAME(lv_permissions_r); + else + perms = _str_unknown; + } + + return _field_string(rh, field, perms); +} + +static int _lvallocationpolicy_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const char *alloc_policy = get_alloc_string(((const struct logical_volume *) data)->alloc) ? : _str_unknown; + return _field_string(rh, field, alloc_policy); +} + +static int _lvallocationlocked_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + int alloc_locked = (((const struct logical_volume *) data)->status & LOCKED) != 0; + + return _binary_disp(rh, mem, field, alloc_locked, GET_FIRST_RESERVED_NAME(lv_allocation_locked_y), private); +} + +static int _lvfixedminor_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + int fixed_minor = (((const struct logical_volume *) data)->status & FIXED_MINOR) != 0; + + return _binary_disp(rh, mem, field, fixed_minor, GET_FIRST_RESERVED_NAME(lv_fixed_minor_y), private); +} + +static int _lvactive_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { const struct logical_volume *lv = (const struct logical_volume *) data; + int active; - if (lv_is_cow(lv)) - return _snpercent_disp(rh, mem, field, data, private); - - if (lv_is_thin_pool(lv) || lv_is_thin_volume(lv)) - return _dtpercent_disp(0, rh, mem, field, data, private); + if (!activation()) + return _binary_undef_disp(rh, mem, field, private); - dm_report_field_set_value(field, "", NULL); + active = lv_is_active(lv); - return 1; + return _binary_disp(rh, mem, field, active, GET_FIRST_RESERVED_NAME(lv_active_y), private); } -static int _metadatapercent_disp(struct dm_report *rh, struct dm_pool *mem, +static int _lvactivelocally_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { const struct logical_volume *lv = (const struct logical_volume *) data; + int active_locally; - if (lv_is_thin_pool(lv)) - return _dtpercent_disp(1, rh, mem, field, data, private); + if (!activation()) + return _binary_undef_disp(rh, mem, field, private); - dm_report_field_set_value(field, "", NULL); + active_locally = lv_is_active(lv); - return 1; + return _binary_disp(rh, mem, field, active_locally, GET_FIRST_RESERVED_NAME(lv_active_locally_y), private); } -static int _lvmetadatasize_disp(struct dm_report *rh, struct dm_pool *mem, - struct dm_report_field *field, - const void *data, void *private) +static int _lvactiveremotely_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) { const struct logical_volume *lv = (const struct logical_volume *) data; - uint64_t size; + int active_remotely; - if (!lv_is_thin_pool(lv)) { - dm_report_field_set_value(field, "", NULL); - return 1; + if (!activation() || vg_is_shared(lv->vg)) + return _binary_undef_disp(rh, mem, field, private); + + active_remotely = 0; + + return _binary_disp(rh, mem, field, active_remotely, GET_FIRST_RESERVED_NAME(lv_active_remotely_y), private); +} + +static int _lvactiveexclusively_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const struct logical_volume *lv = (const struct logical_volume *) data; + int ex = 0, sh = 0; + + if (!activation()) + return _binary_undef_disp(rh, mem, field, private); + + ex = lv_is_active(lv); + + if (ex && vg_is_shared(lv->vg)) { + ex = 0; + if (!lockd_query_lv(lv->vg->cmd, (struct logical_volume *)lv, &ex, &sh)) + return _binary_undef_disp(rh, mem, field, private); } - size = lv_metadata_size(lv); + return _binary_disp(rh, mem, field, ex, GET_FIRST_RESERVED_NAME(lv_active_exclusively_y), private); +} - return _size64_disp(rh, mem, field, &size, private); +static int _lvmergefailed_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const struct lv_with_info_and_seg_status *lvdm = (const struct lv_with_info_and_seg_status *) data; + + if (lvdm->seg_status.type != SEG_STATUS_SNAPSHOT) + return _binary_undef_disp(rh, mem, field, private); + + return _binary_disp(rh, mem, field, lvdm->seg_status.snapshot->merge_failed, + GET_FIRST_RESERVED_NAME(lv_merge_failed_y), private); } -static int _thincount_disp(struct dm_report *rh, struct dm_pool *mem, - struct dm_report_field *field, - const void *data, void *private) +static int _lvsnapshotinvalid_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const struct lv_with_info_and_seg_status *lvdm = (const struct lv_with_info_and_seg_status *) data; + + if (lvdm->seg_status.type != SEG_STATUS_SNAPSHOT) + return _binary_undef_disp(rh, mem, field, private); + + return _binary_disp(rh, mem, field, lvdm->seg_status.snapshot->invalid, + GET_FIRST_RESERVED_NAME(lv_snapshot_invalid_y), private); +} + +static int _lvsuspended_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const struct lv_with_info_and_seg_status *lvdm = (const struct lv_with_info_and_seg_status *) data; + + if (lvdm->info.exists) + return _binary_disp(rh, mem, field, lvdm->info.suspended, GET_FIRST_RESERVED_NAME(lv_suspended_y), private); + + return _binary_undef_disp(rh, mem, field, private); +} + +static int _lvlivetable_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const struct lv_with_info_and_seg_status *lvdm = (const struct lv_with_info_and_seg_status *) data; + + if (lvdm->info.exists) + return _binary_disp(rh, mem, field, lvdm->info.live_table, GET_FIRST_RESERVED_NAME(lv_live_table_y), private); + + return _binary_undef_disp(rh, mem, field, private); +} + +static int _lvinactivetable_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const struct lv_with_info_and_seg_status *lvdm = (const struct lv_with_info_and_seg_status *) data; + + if (lvdm->info.exists) + return _binary_disp(rh, mem, field, lvdm->info.inactive_table, GET_FIRST_RESERVED_NAME(lv_inactive_table_y), private); + + return _binary_undef_disp(rh, mem, field, private); +} + +static int _lvdeviceopen_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const struct lv_with_info_and_seg_status *lvdm = (const struct lv_with_info_and_seg_status *) data; + + if (lvdm->info.exists) + return _binary_disp(rh, mem, field, lvdm->info.open_count, GET_FIRST_RESERVED_NAME(lv_device_open_y), private); + + return _binary_undef_disp(rh, mem, field, private); +} + +static int _thinzero_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) { const struct lv_segment *seg = (const struct lv_segment *) data; - uint32_t count; - /* Suppress thin count if not thin pool */ - if (!seg_is_thin_pool(seg)) { - dm_report_field_set_value(field, "", NULL); - return 1; + if (seg_is_thin_volume(seg)) + seg = first_seg(seg->pool_lv); + + if (seg_is_thin_pool(seg)) + return _binary_disp(rh, mem, field, (seg->zero_new_blocks == THIN_ZERO_YES), GET_FIRST_RESERVED_NAME(zero_y), private); + + return _binary_undef_disp(rh, mem, field, private); +} + +static int _lvhealthstatus_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const struct lv_with_info_and_seg_status *lvdm = (const struct lv_with_info_and_seg_status *) data; + const struct logical_volume *lv = lvdm->lv; + const char *health = ""; + uint64_t n; + + if (lv_is_partial(lv)) + health = "partial"; + else if (lv_is_raid_type(lv)) { + if (!activation()) + health = "unknown"; + else if (!lv_raid_healthy(lv)) + health = "refresh needed"; + else if (lv_is_raid(lv)) { + if (lv_raid_mismatch_count(lv, &n) && n) + health = "mismatches exist"; + } else if (lv->status & LV_WRITEMOSTLY) + health = "writemostly"; + } else if (lv_is_cache(lv) && (lvdm->seg_status.type != SEG_STATUS_NONE)) { + if (lvdm->seg_status.type != SEG_STATUS_CACHE) + return _field_set_value(field, GET_FIRST_RESERVED_NAME(health_undef), + GET_FIELD_RESERVED_VALUE(health_undef)); + if (lvdm->seg_status.cache->fail) + health = "failed"; + else if (lvdm->seg_status.cache->read_only) + health = "metadata_read_only"; + } else if (lv_is_writecache(lv) && (lvdm->seg_status.type != SEG_STATUS_NONE)) { + if (lvdm->seg_status.type != SEG_STATUS_WRITECACHE) + return _field_set_value(field, GET_FIRST_RESERVED_NAME(health_undef), + GET_FIELD_RESERVED_VALUE(health_undef)); + if (lvdm->seg_status.writecache->error) + health = "error"; + } else if (lv_is_thin_pool(lv) && (lvdm->seg_status.type != SEG_STATUS_NONE)) { + if (lvdm->seg_status.type != SEG_STATUS_THIN_POOL) + return _field_set_value(field, GET_FIRST_RESERVED_NAME(health_undef), + GET_FIELD_RESERVED_VALUE(health_undef)); + if (lvdm->seg_status.thin_pool->fail) + health = "failed"; + else if (lvdm->seg_status.thin_pool->out_of_data_space) + health = "out_of_data"; + else if (lvdm->seg_status.thin_pool->read_only) + health = "metadata_read_only"; } - count = dm_list_size(&seg->lv->segs_using_this_lv); + return _field_string(rh, field, health); +} - return _uint32_disp(rh, mem, field, &count, private); +static int _lvcheckneeded_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const struct lv_with_info_and_seg_status *lvdm = (const struct lv_with_info_and_seg_status *) data; + + if (lv_is_thin_pool(lvdm->lv) && lvdm->seg_status.type == SEG_STATUS_THIN_POOL) + return _binary_disp(rh, mem, field, lvdm->seg_status.thin_pool->needs_check, + GET_FIRST_RESERVED_NAME(lv_check_needed_y), private); + + if (lv_is_cache(lvdm->lv) && lvdm->seg_status.type == SEG_STATUS_CACHE) + return _binary_disp(rh, mem, field, lvdm->seg_status.cache->needs_check, + GET_FIRST_RESERVED_NAME(lv_check_needed_y), private); + + return _binary_undef_disp(rh, mem, field, private); } -static int _lvtime_disp(struct dm_report *rh, struct dm_pool *mem, - struct dm_report_field *field, - const void *data, void *private) +static int _lvskipactivation_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + int skip_activation = (((const struct logical_volume *) data)->status & LV_ACTIVATION_SKIP) != 0; + return _binary_disp(rh, mem, field, skip_activation, "skip activation", private); +} + +static int _lvautoactivation_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + int aa_yes = (((const struct logical_volume *) data)->status & LV_NOAUTOACTIVATE) ? 0 : 1; + return _binary_disp(rh, mem, field, aa_yes, "enabled", private); +} + +static int _lvhistorical_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) { const struct logical_volume *lv = (const struct logical_volume *) data; - char *repstr; - uint64_t *sortval; + return _binary_disp(rh, mem, field, lv_is_historical(lv), "historical", private); +} - if (!(sortval = dm_pool_zalloc(mem, sizeof(uint64_t)))) { - log_error("Failed to allocate sortval."); - return 0; - } +/* + * Macro to generate '_cache_<cache_status_field_name>_disp' reporting function. + * The 'cache_status_field_name' is field name from struct dm_cache_status. + */ +#define GENERATE_CACHE_STATUS_DISP_FN(cache_status_field_name) \ +static int _cache_ ## cache_status_field_name ## _disp (struct dm_report *rh, \ + struct dm_pool *mem, \ + struct dm_report_field *field, \ + const void *data, \ + void *private) \ +{ \ + const struct lv_with_info_and_seg_status *lvdm = (const struct lv_with_info_and_seg_status *) data; \ + if (lvdm->seg_status.type != SEG_STATUS_CACHE) \ + return _field_set_value(field, "", &GET_TYPE_RESERVED_VALUE(num_undef_64)); \ + return dm_report_field_uint64(rh, field, &lvdm->seg_status.cache->cache_status_field_name); \ +} - *sortval = lv->timestamp; - if (!(repstr = lv_time_dup(mem, lv))) - return_0; +GENERATE_CACHE_STATUS_DISP_FN(total_blocks) +GENERATE_CACHE_STATUS_DISP_FN(used_blocks) +GENERATE_CACHE_STATUS_DISP_FN(dirty_blocks) +GENERATE_CACHE_STATUS_DISP_FN(read_hits) +GENERATE_CACHE_STATUS_DISP_FN(read_misses) +GENERATE_CACHE_STATUS_DISP_FN(write_hits) +GENERATE_CACHE_STATUS_DISP_FN(write_misses) - dm_report_field_set_value(field, repstr, sortval); +/* + * Macro to generate '_writecache_<cache_status_field_name>_disp' reporting function. + * The 'writecache_status_field_name' is field name from struct dm_writecache_status. + */ +#define GENERATE_WRITECACHE_STATUS_DISP_FN(writecache_status_field_name) \ +static int _writecache_ ## writecache_status_field_name ## _disp (struct dm_report *rh, \ + struct dm_pool *mem, \ + struct dm_report_field *field, \ + const void *data, \ + void *private) \ +{ \ + const struct lv_with_info_and_seg_status *lvdm = (const struct lv_with_info_and_seg_status *) data; \ + if (lvdm->seg_status.type != SEG_STATUS_WRITECACHE) \ + return _field_set_value(field, "", &GET_TYPE_RESERVED_VALUE(num_undef_64)); \ + return dm_report_field_uint64(rh, field, &lvdm->seg_status.writecache->writecache_status_field_name); \ +} - return 1; +GENERATE_WRITECACHE_STATUS_DISP_FN(total_blocks) +GENERATE_WRITECACHE_STATUS_DISP_FN(free_blocks) +GENERATE_WRITECACHE_STATUS_DISP_FN(writeback_blocks) +GENERATE_WRITECACHE_STATUS_DISP_FN(error) + +/* + * Macro to generate '_vdo_<vdo_field_name>_disp' reporting function. + * The 'vdo_field_name' is field name from struct lv_vdo_status. + */ +#define GENERATE_VDO_FIELD_DISP_FN(vdo_field_name) \ +static int _vdo_ ## vdo_field_name ## _disp (struct dm_report *rh, struct dm_pool *mem, \ + struct dm_report_field *field, \ + const void *data, void *private) \ +{ \ + const struct lv_segment *seg = (const struct lv_segment *) data; \ +\ + if (seg_is_vdo(seg)) \ + seg = first_seg(seg_lv(seg, 0)); \ +\ + if (!seg_is_vdo_pool(seg)) \ + return _field_set_value(field, "", &GET_TYPE_RESERVED_VALUE(num_undef_64)); \ +\ + return dm_report_field_uint32(rh, field, &seg->vdo_params.vdo_field_name); \ } -static int _lvhost_disp(struct dm_report *rh, struct dm_pool *mem, - struct dm_report_field *field, - const void *data, void *private) +GENERATE_VDO_FIELD_DISP_FN(block_map_era_length) +GENERATE_VDO_FIELD_DISP_FN(ack_threads) +GENERATE_VDO_FIELD_DISP_FN(bio_threads) +GENERATE_VDO_FIELD_DISP_FN(bio_rotation) +GENERATE_VDO_FIELD_DISP_FN(cpu_threads) +GENERATE_VDO_FIELD_DISP_FN(hash_zone_threads) +GENERATE_VDO_FIELD_DISP_FN(logical_threads) +GENERATE_VDO_FIELD_DISP_FN(physical_threads) +GENERATE_VDO_FIELD_DISP_FN(max_discard) + +/* + * Macro to generate '_vdo_<vdo_field_name>_disp' reporting function. + * The 'vdo_field_name' is field name from struct lv_vdo_status. + */ +#define GENERATE_VDO_FIELDSZMB_DISP_FN(vdo_field_name) \ +static int _vdo_ ## vdo_field_name ## _disp (struct dm_report *rh, struct dm_pool *mem, \ + struct dm_report_field *field, \ + const void *data, void *private) \ +{ \ + uint64_t size; \ + const struct lv_segment *seg = (const struct lv_segment *) data; \ +\ + if (seg_is_vdo(seg)) \ + seg = first_seg(seg_lv(seg, 0)); \ +\ + if (!seg_is_vdo_pool(seg)) \ + return _field_set_value(field, "", &GET_TYPE_RESERVED_VALUE(num_undef_64)); \ +\ + size = seg->vdo_params.vdo_field_name ## _mb * (UINT64_C(1024) * 1024 >> SECTOR_SHIFT); \ +\ + return _size64_disp(rh, mem, field, &size, private);\ +} + +GENERATE_VDO_FIELDSZMB_DISP_FN(block_map_cache_size) +GENERATE_VDO_FIELDSZMB_DISP_FN(index_memory_size) +GENERATE_VDO_FIELDSZMB_DISP_FN(slab_size) + +static int _vdo_compression_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) { - const struct logical_volume *lv = (const struct logical_volume *) data; - char *repstr; + const struct lv_segment *seg = (const struct lv_segment *) data; \ - if (!(repstr = lv_host_dup(mem, lv))) - return_0; + if (seg_is_vdo(seg)) + seg = first_seg(seg_lv(seg, 0)); - dm_report_field_set_value(field, repstr, repstr); + if (seg_is_vdo_pool(seg)) + return _binary_disp(rh, mem, field, seg->vdo_params.use_compression, + GET_FIRST_RESERVED_NAME(vdo_compression_y), private); - return 1; + return _field_set_value(field, "", &GET_TYPE_RESERVED_VALUE(num_undef_64)); \ +} + +static int _vdo_deduplication_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const struct lv_segment *seg = (const struct lv_segment *) data; \ + + if (seg_is_vdo(seg)) + seg = first_seg(seg_lv(seg, 0)); + + if (seg_is_vdo_pool(seg)) + return _binary_disp(rh, mem, field, seg->vdo_params.use_deduplication, + GET_FIRST_RESERVED_NAME(vdo_deduplication_y), private); + + return _field_set_value(field, "", &GET_TYPE_RESERVED_VALUE(num_undef_64)); \ +} + +static int _vdo_use_metadata_hints_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const struct lv_segment *seg = (const struct lv_segment *) data; + + if (seg_is_vdo(seg)) + seg = first_seg(seg_lv(seg, 0)); + + if (seg_is_vdo_pool(seg)) + return _binary_disp(rh, mem, field, seg->vdo_params.use_metadata_hints, + GET_FIRST_RESERVED_NAME(vdo_use_metadata_hints_y), + private); + + return _field_set_value(field, "", &GET_TYPE_RESERVED_VALUE(num_undef_64)); +} + +static int _vdo_use_sparse_index_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const struct lv_segment *seg = (const struct lv_segment *) data; + + if (seg_is_vdo(seg)) + seg = first_seg(seg_lv(seg, 0)); + + if (seg_is_vdo_pool(seg)) + return _binary_disp(rh, mem, field, seg->vdo_params.use_sparse_index, + GET_FIRST_RESERVED_NAME(vdo_use_sparse_index_y), + private); + + return _field_set_value(field, "", &GET_TYPE_RESERVED_VALUE(num_undef_64)); +} + +static int _vdo_minimum_io_size_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const struct lv_segment *seg = (const struct lv_segment *) data; + + if (seg_is_vdo(seg)) + seg = first_seg(seg_lv(seg, 0)); + + if (seg_is_vdo_pool(seg)) + return _size32_disp(rh, mem, field, &seg->vdo_params.minimum_io_size, private); + + return _field_set_value(field, "", &GET_TYPE_RESERVED_VALUE(num_undef_64)); +} + +static int _vdo_header_size_disp(struct dm_report *rh, + struct dm_pool *mem, + struct dm_report_field *field, + const void *data, + void *private) +{ + const struct lv_segment *seg = (const struct lv_segment *) data; + + if (seg_is_vdo(seg)) + seg = first_seg(seg_lv(seg, 0)); + + if (seg_is_vdo_pool(seg)) + return _size32_disp(rh, mem, field, &seg->vdo_pool_header_size, private); + + return _field_set_value(field, "", &GET_TYPE_RESERVED_VALUE(num_undef_64)); +} + +static int _vdo_write_policy_disp(struct dm_report *rh, + struct dm_pool *mem, + struct dm_report_field *field, + const void *data, + void *private) +{ + const struct lv_segment *seg = (const struct lv_segment *) data; + + if (seg_is_vdo(seg)) + seg = first_seg(seg_lv(seg, 0)); + + if (seg_is_vdo_pool(seg)) + return _field_string(rh, field, get_vdo_write_policy_name(seg->vdo_params.write_policy)); + + return _field_set_value(field, GET_FIRST_RESERVED_NAME(vdo_write_policy_undef), + GET_FIELD_RESERVED_VALUE(vdo_write_policy_undef)); } /* Report object types */ /* necessary for displaying something for PVs not belonging to VG */ static struct format_instance _dummy_fid = { - .metadata_areas_in_use = { &(_dummy_fid.metadata_areas_in_use), &(_dummy_fid.metadata_areas_in_use) }, - .metadata_areas_ignored = { &(_dummy_fid.metadata_areas_ignored), &(_dummy_fid.metadata_areas_ignored) }, + .metadata_areas_in_use = DM_LIST_HEAD_INIT(_dummy_fid.metadata_areas_in_use), + .metadata_areas_ignored = DM_LIST_HEAD_INIT(_dummy_fid.metadata_areas_ignored), }; static struct volume_group _dummy_vg = { .fid = &_dummy_fid, .name = "", .system_id = (char *) "", - .pvs = { &(_dummy_vg.pvs), &(_dummy_vg.pvs) }, - .lvs = { &(_dummy_vg.lvs), &(_dummy_vg.lvs) }, - .tags = { &(_dummy_vg.tags), &(_dummy_vg.tags) }, + .pvs = DM_LIST_HEAD_INIT(_dummy_vg.pvs), + .lvs = DM_LIST_HEAD_INIT(_dummy_vg.lvs), + .historical_lvs = DM_LIST_HEAD_INIT(_dummy_vg.historical_lvs), + .tags = DM_LIST_HEAD_INIT(_dummy_vg.tags), +}; + +static struct volume_group _unknown_vg = { + .fid = &_dummy_fid, + .name = "[unknown]", + .system_id = (char *) "", + .pvs = DM_LIST_HEAD_INIT(_unknown_vg.pvs), + .lvs = DM_LIST_HEAD_INIT(_unknown_vg.lvs), + .historical_lvs = DM_LIST_HEAD_INIT(_unknown_vg.historical_lvs), + .tags = DM_LIST_HEAD_INIT(_unknown_vg.tags), }; static void *_obj_get_vg(void *obj) @@ -1100,7 +4308,12 @@ static void *_obj_get_vg(void *obj) static void *_obj_get_lv(void *obj) { - return ((struct lvm_report_object *)obj)->lv; + return (struct logical_volume *)((struct lvm_report_object *)obj)->lvdm->lv; +} + +static void *_obj_get_lv_with_info_and_seg_status(void *obj) +{ + return ((struct lvm_report_object *)obj)->lvdm; } static void *_obj_get_pv(void *obj) @@ -1108,6 +4321,11 @@ static void *_obj_get_pv(void *obj) return ((struct lvm_report_object *)obj)->pv; } +static void *_obj_get_label(void *obj) +{ + return ((struct lvm_report_object *)obj)->label; +} + static void *_obj_get_seg(void *obj) { return ((struct lvm_report_object *)obj)->seg; @@ -1118,47 +4336,101 @@ static void *_obj_get_pvseg(void *obj) return ((struct lvm_report_object *)obj)->pvseg; } +static void *_obj_get_devtypes(void *obj) +{ + return obj; +} + +static void *_obj_get_cmdlog(void *obj) +{ + return obj; +} + +static const struct dm_report_object_type _log_report_types[] = { + { CMDLOG, "Command Log", "log_", _obj_get_cmdlog }, + { 0, "", "", NULL }, +}; + static const struct dm_report_object_type _report_types[] = { { VGS, "Volume Group", "vg_", _obj_get_vg }, { LVS, "Logical Volume", "lv_", _obj_get_lv }, + { LVSINFO, "Logical Volume Device Info", "lv_", _obj_get_lv_with_info_and_seg_status }, + { LVSSTATUS, "Logical Volume Device Status", "lv_", _obj_get_lv_with_info_and_seg_status }, + { LVSINFOSTATUS, "Logical Volume Device Info and Status Combined", "lv_", _obj_get_lv_with_info_and_seg_status }, { PVS, "Physical Volume", "pv_", _obj_get_pv }, - { LABEL, "Physical Volume Label", "pv_", _obj_get_pv }, + { LABEL, "Physical Volume Label", "pv_", _obj_get_label }, { SEGS, "Logical Volume Segment", "seg_", _obj_get_seg }, { PVSEGS, "Physical Volume Segment", "pvseg_", _obj_get_pvseg }, { 0, "", "", NULL }, }; +static const struct dm_report_object_type _devtypes_report_types[] = { + { DEVTYPES, "Device Types", "devtype_", _obj_get_devtypes }, + { 0, "", "", NULL }, +}; + /* * Import column definitions */ #define STR DM_REPORT_FIELD_TYPE_STRING #define NUM DM_REPORT_FIELD_TYPE_NUMBER +#define BIN DM_REPORT_FIELD_TYPE_NUMBER +#define SIZ DM_REPORT_FIELD_TYPE_SIZE +#define PCT DM_REPORT_FIELD_TYPE_PERCENT +#define TIM DM_REPORT_FIELD_TYPE_TIME +#define STR_LIST DM_REPORT_FIELD_TYPE_STRING_LIST +#define SNUM DM_REPORT_FIELD_TYPE_NUMBER #define FIELD(type, strct, sorttype, head, field, width, func, id, desc, writeable) \ - {type, sorttype, offsetof(type_ ## strct, field), width, \ + {type, sorttype, offsetof(type_ ## strct, field), (width) ? : sizeof(head) - 1, \ #id, head, &_ ## func ## _disp, desc}, +typedef struct cmd_log_item type_cmd_log_item; + typedef struct physical_volume type_pv; typedef struct logical_volume type_lv; typedef struct volume_group type_vg; typedef struct lv_segment type_seg; typedef struct pv_segment type_pvseg; +typedef struct label type_label; + +typedef dev_known_type_t type_devtype; static const struct dm_report_field_type _fields[] = { +/* coverity[unnecessary_header] */ #include "columns.h" {0, 0, 0, 0, "", "", NULL, NULL}, }; +static const struct dm_report_field_type _devtypes_fields[] = { +#include "columns-devtypes.h" +{0, 0, 0, 0, "", "", NULL, NULL}, +}; + +static const struct dm_report_field_type _log_fields[] = { +/* coverity[unnecessary_header] */ +#include "columns-cmdlog.h" +{0, 0, 0, 0, "", "", NULL, NULL}, +}; + #undef STR #undef NUM +#undef BIN +#undef SIZ +#undef STR_LIST +#undef SNUM #undef FIELD void *report_init(struct cmd_context *cmd, const char *format, const char *keys, report_type_t *report_type, const char *separator, int aligned, int buffered, int headings, int field_prefixes, - int quoted, int columns_as_rows) + int quoted, int columns_as_rows, const char *selection, + int multiple_output) { uint32_t report_flags = 0; + const struct dm_report_object_type *types; + const struct dm_report_field_type *fields; + const struct dm_report_reserved_value *reserved_values; void *rh; if (aligned) @@ -1179,8 +4451,26 @@ void *report_init(struct cmd_context *cmd, const char *format, const char *keys, if (columns_as_rows) report_flags |= DM_REPORT_OUTPUT_COLUMNS_AS_ROWS; - rh = dm_report_init(report_type, _report_types, _fields, format, - separator, report_flags, keys, cmd); + if (multiple_output) + report_flags |= DM_REPORT_OUTPUT_MULTIPLE_TIMES; + + if (*report_type & CMDLOG) { + types = _log_report_types; + fields = _log_fields; + reserved_values = NULL; + } else if (*report_type & DEVTYPES) { + types = _devtypes_report_types; + fields = _devtypes_fields; + reserved_values = NULL; + } else { + types = _report_types; + fields = _fields; + reserved_values = _report_reserved_values; + } + + rh = dm_report_init_with_selection(report_type, types, fields, + format, separator, report_flags, keys, + selection, reserved_values, cmd); if (rh && field_prefixes) dm_report_set_output_field_name_prefix(rh, "lvm2_"); @@ -1188,24 +4478,139 @@ void *report_init(struct cmd_context *cmd, const char *format, const char *keys, return rh; } +void *report_init_for_selection(struct cmd_context *cmd, + report_type_t *report_type, + const char *selection_criteria) +{ + return dm_report_init_with_selection(report_type, _report_types, _fields, + "", DEFAULT_REP_SEPARATOR, + DM_REPORT_OUTPUT_FIELD_UNQUOTED, + "", selection_criteria, + _report_reserved_values, + cmd); +} + +int report_get_prefix_and_desc(report_type_t report_type_id, + const char **report_prefix, + const char **report_desc) +{ + const struct dm_report_object_type *report_types, *report_type; + + if (report_type_id & CMDLOG) + report_types = _log_report_types; + else if (report_type_id & DEVTYPES) + report_types = _devtypes_report_types; + else + report_types = _report_types; + + for (report_type = report_types; report_type->id; report_type++) { + if (report_type_id & report_type->id) { + *report_prefix = report_type->prefix; + *report_desc = report_type->desc; + return 1; + } + } + + *report_prefix = *report_desc = ""; + return 0; +} + /* * Create a row of data for an object */ -int report_object(void *handle, struct volume_group *vg, - struct logical_volume *lv, struct physical_volume *pv, - struct lv_segment *seg, struct pv_segment *pvseg) +int report_object(void *handle, int selection_only, const struct volume_group *vg, + 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) { - struct lvm_report_object obj; + struct selection_handle *sh = selection_only ? (struct selection_handle *) handle : NULL; + struct device dummy_device = { .dev = 0 }; + struct label dummy_label = { .dev = &dummy_device }; + struct lvm_report_object obj = { + .vg = (struct volume_group *) vg, + .lvdm = (struct lv_with_info_and_seg_status *) lvdm, + .pv = (struct physical_volume *) pv, + .seg = (struct lv_segment *) seg, + .pvseg = (struct pv_segment *) pvseg, + .label = (struct label *) (label ? : (pv ? pv_label(pv) : NULL)) + }; + + /* FIXME workaround for pv_label going through cache; remove once struct + * physical_volume gains a proper "label" pointer */ + if (!obj.label) { + if (pv) { + if (pv->fmt) + dummy_label.labeller = pv->fmt->labeller; + if (pv->dev) + dummy_label.dev = pv->dev; + else + memcpy(dummy_device.pvid, &pv->id, ID_LEN); + } + obj.label = &dummy_label; + } + + /* Never report orphan VGs. */ + if (vg && is_orphan_vg(vg->name)) { + obj.vg = &_dummy_vg; + if (pv) + _dummy_fid.fmt = pv->fmt; + } - /* The two format fields might as well match. */ - if (!vg && pv) + if (vg && is_orphan_vg(vg->name) && pv && is_used_pv(pv)) { + obj.vg = &_unknown_vg; _dummy_fid.fmt = pv->fmt; + } + + return sh ? dm_report_object_is_selected(sh->selection_rh, &obj, 0, &sh->selected) + : dm_report_object(handle, &obj); +} + +static int _report_devtype_single(void *handle, const dev_known_type_t *devtype) +{ + return dm_report_object(handle, (void *)devtype); +} + +int report_devtypes(void *handle) +{ + int devtypeind = 0; - obj.vg = vg; - obj.lv = lv; - obj.pv = pv; - obj.seg = seg; - obj.pvseg = pvseg; + while (_dev_known_types[devtypeind].name[0]) + if (!_report_devtype_single(handle, &_dev_known_types[devtypeind++])) + return 0; + + return 1; +} + +int report_cmdlog(void *handle, const char *type, const char *context, + const char *object_type_name, const char *object_name, + const char *object_id, const char *object_group, + const char *object_group_id, const char *msg, + int current_errno, int ret_code) +{ + struct cmd_log_item log_item = {_log_seqnum++, type, context, object_type_name, + object_name ? : "", object_id ? : "", + object_group ? : "", object_group_id ? : "", + msg ? : "", current_errno, ret_code}; + + if (handle) + return dm_report_object(handle, &log_item); + + return 1; +} + +void report_reset_cmdlog_seqnum(void) +{ + _log_seqnum = 1; +} + +int report_current_object_cmdlog(const char *type, const char *msg, int32_t ret_code) +{ + log_report_t log_state = log_get_report_state(); - return dm_report_object(handle, &obj); + return report_cmdlog(log_state.report, type, log_get_report_context_name(log_state.context), + log_get_report_object_type_name(log_state.object_type), + log_state.object_name, log_state.object_id, + log_state.object_group, log_state.object_group_id, + msg, stored_errno(), ret_code); } diff --git a/lib/report/report.h b/lib/report/report.h index 26cc2f7..380538a 100644 --- a/lib/report/report.h +++ b/lib/report/report.h @@ -10,37 +10,112 @@ * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _LVM_REPORT_H #define _LVM_REPORT_H -#include "metadata-exported.h" +#include "lib/metadata/metadata-exported.h" +#include "lib/label/label.h" +#include "lib/activate/activate.h" typedef enum { - LVS = 1, - PVS = 2, - VGS = 4, - SEGS = 8, - PVSEGS = 16, - LABEL = 32 + CMDLOG = 1, + FULL = 2, + LVS = 4, + LVSINFO = 8, + LVSSTATUS = 16, + LVSINFOSTATUS = 32, + PVS = 64, + VGS = 128, + SEGS = 256, + PVSEGS = 512, + LABEL = 1024, + DEVTYPES = 2048 } report_type_t; +/* + * The "struct selection_handle" is used only for selection + * of items that should be processed further (not for display!). + * + * It consists of selection reporting handle "selection_rh" + * used for the selection itself (not for display on output!). + * The items are reported directly in memory to a buffer and + * then compared against selection criteria. Once we know the + * result of the selection, the buffer is dropped! + * + * The "orig_report_type" is the original requested report type. + * The "report_type" is the reporting type actually used which + * also counts with report types of the fields used in selection + * criteria. + * + * The "selected" variable is used for propagating the result + * of the selection. + */ +struct selection_handle { + struct dm_report *selection_rh; + report_type_t orig_report_type; + report_type_t report_type; + int selected; +}; + +struct cmd_log_item { + uint32_t seq_num; + const char *type; + const char *context; + const char *object_type_name; + const char *object_name; + const char *object_id; + const char *object_group; + const char *object_group_id; + const char *msg; + int current_errno; + int ret_code; +}; + struct field; struct report_handle; +struct processing_handle; typedef int (*field_report_fn) (struct report_handle * dh, struct field * field, const void *data); +int report_format_init(struct cmd_context *cmd); + void *report_init(struct cmd_context *cmd, const char *format, const char *keys, report_type_t *report_type, const char *separator, int aligned, int buffered, int headings, int field_prefixes, - int quoted, int columns_as_rows); + int quoted, int columns_as_rows, const char *selection, + int multiple_output); +int report_get_single_selection(struct cmd_context *cmd, report_type_t report_type, const char **selection); +void *report_init_for_selection(struct cmd_context *cmd, report_type_t *report_type, + const char *selection); +int report_get_prefix_and_desc(report_type_t report_type_id, + const char **report_prefix, + const char **report_desc); +int report_for_selection(struct cmd_context *cmd, + struct processing_handle *parent_handle, + struct physical_volume *pv, + struct volume_group *vg, + struct logical_volume *lv); void report_free(void *handle); -int report_object(void *handle, struct volume_group *vg, - struct logical_volume *lv, struct physical_volume *pv, - struct lv_segment *seg, struct pv_segment *pvseg); +int report_object(void *handle, int selection_only, const struct volume_group *vg, + 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); +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, + const char *object_id, const char *object_group, + const char *object_group_id, const char *msg, + int current_errno, int ret_code); +void report_reset_cmdlog_seqnum(void); +#define REPORT_OBJECT_CMDLOG_NAME "status" +#define REPORT_OBJECT_CMDLOG_SUCCESS "success" +#define REPORT_OBJECT_CMDLOG_FAILURE "failure" +int report_current_object_cmdlog(const char *type, const char *msg, int32_t ret_code); int report_output(void *handle); #endif diff --git a/lib/report/values.h b/lib/report/values.h new file mode 100644 index 0000000..3efe2b8 --- /dev/null +++ b/lib/report/values.h @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2014 Red Hat, Inc. All rights reserved. + * + * This file is part of LVM2. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU Lesser General Public License v.2.1. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * This file defines reserved names for field values. + * + * This is used for registering reserved names with reporting code that + * uses the exact value defined whenever the reserved name is hit, for + * example during selection criteria processing. + * + * TYPE_RESERVED_VALUE defines reserved value that is not bound to any field, + * but rather it's bound to a certain type. This can be used as a reserved + * value for all fields of that type then. When naming type reserved value, + * please follow this naming scheme: + * <report type name in lowercase>_<reserved_value_name> + * + * FIELD_RESERVED_VALUE defines reserved value bound to a single field. + * When naming reserved value for the field, please follow this naming scheme: + * <field_name>_<reserved_value_name> + * + * FIELD_BINARY_RESERVED_VALUE is similar to FIELD_RESERVED_VALUE but it + * is specifically designed for defintion of reserved names for fields + * with binary values where the reserved names given denote value 1. + * The first reserved_name given is also used for reporting, + * others are synonyms which are recognized in addition. + * + */ + +/* + * TYPE_RESERVED_VALUE(type, flags, reserved_value_id, description, value, reserved_name, ...) + * FIELD_RESERVED_VALUE(field_id, flags, reserved_value_id, description, value, reserved_name, ...) + * FIELD_BINARY_RESERVED_VALUE(field_id, reserved_value_id, description, reserved_name for 1, ...) + */ + +/* *INDENT-OFF* */ + +/* + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + * IMPORTANT NOTE ABOUT ADDING A NEW VALUE FOR REPORTING + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + * + * When adding a new string value to report, try to keep it + * self-descriptive so when it's printed even without the header, + * we can still deduce what it is actually reporting. + * + * If you need more than one descriptive string to mean the same value, + * please define them as reserved values in values.h. + * + * The first reserved value is the one that is printed in reports (unless + * it's a binary value and we have report/binary_values_as_numeric=1 config + * option used OR --binary command line option is used OR we're using an + * output format which must always print binary values in numeric way, + * like json_std output format. + * + * All the other (2nd and further) listed reserved names are synonyms which + * may be also used in selection (-S|--select). + * + * Also, always use proper *_disp functions to display each type of value + * properly. For example, in case of binary values, you should use + * _binary_disp so that we can always switch between numerical (0/1/-1) and + * string representation while reporting the value. + */ + +/* Per-type reserved values usable for all fields of certain type. */ +TYPE_RESERVED_VALUE(NUM, NOFLAG, num_undef_64, "Reserved value for undefined numeric value.", UINT64_C(-1), "-1", "unknown", "undefined", "undef") + +/* Reserved values for PV fields */ +FIELD_RESERVED_BINARY_VALUE(pv_allocatable, pv_allocatable, "", "allocatable") +FIELD_RESERVED_BINARY_VALUE(pv_exported, pv_exported, "", "exported") +FIELD_RESERVED_BINARY_VALUE(pv_missing, pv_missing, "", "missing") +FIELD_RESERVED_BINARY_VALUE(pv_in_use, pv_in_use, "", "used", "in use") +FIELD_RESERVED_BINARY_VALUE(pv_duplicate, pv_duplicate, "", "duplicate") + +/* Reserved values for VG fields */ +FIELD_RESERVED_BINARY_VALUE(vg_extendable, vg_extendable, "", "extendable") +FIELD_RESERVED_BINARY_VALUE(vg_exported, vg_exported, "", "exported") +FIELD_RESERVED_BINARY_VALUE(vg_partial, vg_partial, "", "partial") +FIELD_RESERVED_BINARY_VALUE(vg_clustered, vg_clustered, "", "clustered") +FIELD_RESERVED_BINARY_VALUE(vg_shared, vg_shared, "", "shared") +FIELD_RESERVED_VALUE(NAMED, vg_permissions, vg_permissions_rw, "", "writeable", "writeable", "rw", "read-write") +FIELD_RESERVED_VALUE(NAMED, vg_permissions, vg_permissions_r, "", "read-only", "read-only", "r", "ro") +FIELD_RESERVED_VALUE(NOFLAG, vg_mda_copies, vg_mda_copies_unmanaged, "", &GET_TYPE_RESERVED_VALUE(num_undef_64), "unmanaged") + +/* Reserved values for LV fields */ +FIELD_RESERVED_BINARY_VALUE(lv_initial_image_sync, lv_initial_image_sync, "", "initial image sync", "sync") +FIELD_RESERVED_BINARY_VALUE(lv_image_synced, lv_image_synced, "", "image synced", "synced") +FIELD_RESERVED_BINARY_VALUE(lv_merging, lv_merging, "", "merging") +FIELD_RESERVED_BINARY_VALUE(lv_converting, lv_converting, "", "converting") +FIELD_RESERVED_BINARY_VALUE(lv_allocation_locked, lv_allocation_locked, "", "allocation locked", "locked") +FIELD_RESERVED_BINARY_VALUE(lv_fixed_minor, lv_fixed_minor, "", "fixed minor", "fixed") +FIELD_RESERVED_BINARY_VALUE(lv_active, lv_active, "", "active") +FIELD_RESERVED_BINARY_VALUE(lv_active_locally, lv_active_locally, "", "active locally", "active", "locally") +FIELD_RESERVED_BINARY_VALUE(lv_active_remotely, lv_active_remotely, "", "active remotely", "active", "remotely") +FIELD_RESERVED_BINARY_VALUE(lv_active_exclusively, lv_active_exclusively, "", "active exclusively", "active", "exclusively") +FIELD_RESERVED_BINARY_VALUE(lv_merge_failed, lv_merge_failed, "", "merge failed", "failed") +FIELD_RESERVED_BINARY_VALUE(lv_snapshot_invalid, lv_snapshot_invalid, "", "snapshot invalid", "invalid") +FIELD_RESERVED_BINARY_VALUE(lv_suspended, lv_suspended, "", "suspended") +FIELD_RESERVED_BINARY_VALUE(lv_live_table, lv_live_table, "", "live table present", "live table", "live") +FIELD_RESERVED_BINARY_VALUE(lv_inactive_table, lv_inactive_table, "", "inactive table present", "inactive table", "inactive") +FIELD_RESERVED_BINARY_VALUE(lv_device_open, lv_device_open, "", "open") +FIELD_RESERVED_BINARY_VALUE(lv_skip_activation, lv_skip_activation, "", "skip activation", "skip") +FIELD_RESERVED_BINARY_VALUE(zero, zero, "", "zero") +FIELD_RESERVED_BINARY_VALUE(lv_check_needed, lv_check_needed, "", "check needed", "needed") +FIELD_RESERVED_BINARY_VALUE(vdo_compression, vdo_compression, "", "enabled" ) +FIELD_RESERVED_BINARY_VALUE(vdo_deduplication, vdo_deduplication, "", "enabled" ) +FIELD_RESERVED_BINARY_VALUE(vdo_use_metadata_hints, vdo_use_metadata_hints, "", "enabled" ) +FIELD_RESERVED_BINARY_VALUE(vdo_use_sparse_index, vdo_use_sparse_index, "", "enabled" ) +FIELD_RESERVED_VALUE(NAMED, lv_permissions, lv_permissions_rw, "", "writeable", "writeable", "rw", "read-write") +FIELD_RESERVED_VALUE(NAMED, lv_permissions, lv_permissions_r, "", "read-only", "read-only", "r", "ro") +FIELD_RESERVED_VALUE(NAMED, lv_permissions, lv_permissions_r_override, "", "read-only-override", "read-only-override", "ro-override", "r-override", "R") +FIELD_RESERVED_VALUE(NOFLAG, lv_read_ahead, lv_read_ahead_auto, "", &_siz_max, "auto") +FIELD_RESERVED_VALUE(NAMED, lv_when_full, lv_when_full_error, "", "error", "error", "error when full", "error if no space") +FIELD_RESERVED_VALUE(NAMED, lv_when_full, lv_when_full_queue, "", "queue", "queue", "queue when full", "queue if no space") +FIELD_RESERVED_VALUE(NOFLAG, lv_when_full, lv_when_full_undef, "", "", "", "undefined") +FIELD_RESERVED_VALUE(NAMED | RANGE | FUZZY | DYNAMIC, lv_time, lv_time_fuzzy, "", _lv_time_handler, NULL) +FIELD_RESERVED_VALUE(NAMED | RANGE | FUZZY | DYNAMIC, lv_time_removed, lv_time_removed_fuzzy, "", _lv_time_handler, NULL) + +/* Reserved values for SEG fields */ +FIELD_RESERVED_VALUE(NOFLAG, cache_policy, cache_policy_undef, "", "", "", "undefined") +FIELD_RESERVED_VALUE(NOFLAG, seg_monitor, seg_monitor_undef, "", "", "", "undefined") +FIELD_RESERVED_VALUE(NOFLAG, lv_health_status, health_undef, "", "", "", "undefined") +FIELD_RESERVED_VALUE(NOFLAG, kernel_discards, seg_kernel_discards_undef, "", "", "", "undefined") +FIELD_RESERVED_VALUE(NOFLAG, vdo_write_policy, vdo_write_policy_undef, "", "", "", "undefined") +/* TODO the following 2 need STR_LIST support for reserved values +FIELD_RESERVED_VALUE(cache_settings, cache_settings_default, "", "default", "default") +FIELD_RESERVED_VALUE(cache_settings, cache_settings_undef, "", "undefined", "undefined") */ + +/* *INDENT-ON* */ |