summaryrefslogtreecommitdiff
path: root/lib/report
diff options
context:
space:
mode:
Diffstat (limited to 'lib/report')
-rw-r--r--lib/report/columns-cmdlog.h40
-rw-r--r--lib/report/columns-devtypes.h32
-rw-r--r--lib/report/columns.h418
-rw-r--r--lib/report/properties.c775
-rw-r--r--lib/report/properties.h26
-rw-r--r--lib/report/report.c4257
-rw-r--r--lib/report/report.h99
-rw-r--r--lib/report/values.h139
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* */