1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-09-26 01:44:19 +03:00

Compare commits

..

1 Commits

Author SHA1 Message Date
Marian Csontos
b51b031157 spec: Update python bindings and dbus-service
The workaround for python3 is no longer needed.
2016-02-18 14:51:09 +01:00
622 changed files with 20752 additions and 50601 deletions

View File

@@ -95,7 +95,7 @@ endif
DISTCLEAN_TARGETS += cscope.out
CLEAN_DIRS += autom4te.cache
check check_system check_cluster check_local check_lvmetad check_lvmpolld check_lvmlockd_test check_lvmlockd_dlm check_lvmlockd_sanlock unit: all
check check_system check_cluster check_local check_lvmetad check_lvmpolld unit: all
$(MAKE) -C test $(@)
conf.generate: tools
@@ -166,11 +166,8 @@ install_tmpfiles_configuration:
LCOV_TRACES = libdm.info lib.info liblvm.info tools.info \
libdaemon/client.info libdaemon/server.info \
daemons/clvmd.info \
daemons/dmeventd.info \
daemons/lvmetad.info \
daemons/lvmlockd.info \
daemons/lvmpolld.info
daemons/clvmd.info daemons/dmeventd.info \
daemons/lvmetad.info
CLEAN_TARGETS += $(LCOV_TRACES)

View File

@@ -1 +1 @@
2.02.169(2)-git (2016-11-30)
2.02.143(2)-git (2016-02-15)

View File

@@ -1 +1 @@
1.02.138-git (2016-11-30)
1.02.117-git (2016-02-15)

391
WHATS_NEW
View File

@@ -1,394 +1,5 @@
Version 2.02.169 -
Version 2.02.143 -
=====================================
Avoid parallel usage of cpg_mcast_joined() in clvmd with corosync.
Support raid6_{ls,rs,la,ra}_6 segment types and conversions from/to it.
Support raid6_n_6 segment type and conversions from/to it.
Support raid5_n segment type and conversions from/to it.
Support new internal command _dmeventd_thin_command.
Introduce new dmeventd/thin_command configurable setting.
Use new default units 'r' for displaying sizes.
Also unmount mount point on top of MD device if using blkdeactivate -u.
Restore check preventing resize of cache type volumes (2.02.158).
Add missing udev sync when flushing dirty cache content.
vgchange -p accepts only uint32 numbers.
Report thin LV date for merged LV when the merge is in progress.
Detect if snapshot merge really started before polling for progress.
Checking LV for merging origin requires also it has merged snapshot.
Extend validation of metadata processing.
Enable usage of cached volumes as snapshot origin LV.
Fix displayed lv name when splitting snapshot (2.02.146).
Warn about command not making metadata backup just once per command.
Enable usage of cached volume as thin volume's external origin.
Support cache volume activation with -real layer.
Improve search of lock-holder for external origin and thin-pool.
Support status checking of cache volume used in layer.
Avoid shifting by one number of blocks when clearing dirty cache volume.
Extend metadata validation of external origin LV use count.
Fix dm table when the last user of active external origin is removed.
Improve reported lvs status for active external origin volume.
Fix table load for splitted RAID LV and require explicit activation.
Always active splitted RAID LV exclusively locally.
Do not use LV RAID status bit for segment status.
Check segtype directly instead of checking RAID in segment status.
Reusing exiting code for raid image removal.
Fix pvmove leaving -pvmove0 error device in clustered VG.
Avoid adding extra '_' at end of raid extracted images or metadata.
Optimize another _rmeta clearing code.
Fix deactivation of raid orphan devices for clustered VG.
Fix lvconvert raid1 to mirror table reload order.
Add internal function for separate mirror log preparation.
Fix segfault in lvmetad from missing NULL in daemon_reply_simple.
Simplify internal _info_run() and use _setup_task_run() for mknod.
Better API for internal function _setup_task_run.
Avoid using lv_has_target_type() call within lv_info_with_seg_status.
Simplify internal lv_info_with_seg_status API.
Decide which status is needed in one place for lv_info_with_seg_status.
Fix matching of LV segment when checking for it info status.
Report log_warn when status cannot be parsed.
Test segment type before accessing segment members when checking status.
Implement compatible target function for stripe segment.
Use status info to report merge failed and snapshot invalid lvs fields.
Version 2.02.168 - 30th November 2016
=====================================
Display correct sync_percent on large RaidLVs
lvmdbusd --blackboxsize <n> added, used to override default size of 16
Allow a transiently failed RaidLV to be refreshed
Use lv_update_and_reload() inside mirror code where it applies.
Preserve mirrored status for temporary layered mirrors.
Use transient raid check before repairing raid volume.
Implement transient status check for raid volumes.
Only log msg as debug if lvm2-lvmdbusd unit missing for D-Bus notification.
Avoid duplicated underscore in name of extracted LV image.
Missing stripe filler now could be also 'zero'.
lvconvert --repair accepts --interval and --background option.
More efficiently prepare _rmeta devices when creating a new raid LV.
Version 2.02.167 - 5th November 2016
====================================
Use log_error in regex and sysfs filter to describe reason of failure.
Fix blkdeactivate to deactivate dev stack if dev on top already unmounted.
Prevent non-synced raid1 repair unless --force
Prevent raid4 creation/conversion on non-supporting kernels
Add direct striped -> raid4 conversion
Fix raid4 parity image pair position on conversions from striped/raid0*
Fix a few unconverted return code values for some lvconvert error path.
Disable lvconvert of thin pool to raid while active.
Disable systemd service start rate limiting for lvm2-pvscan@.service.
Version 2.02.166 - 26th September 2016
======================================
Fix lvm2-activation-generator to read all LVM2 config sources. (2.02.155)
Fix lvchange-rebuild-raid.sh to cope with older target versions.
Use dm_config_parse_without_dup_node_check() to speedup metadata reading.
Fix lvconvert --repair regression
Fix reported origin lv field for cache volumes. (2.02.133)
Always specify snapshot cow LV for monitoring not internal LV. (2.02.165)
Fix lvchange --discard|--zero for active thin-pool.
Enforce 4MiB or 25% metadata free space for thin pool operations.
Fix lock-holder device for thin pool with inactive thin volumes.
Use --alloc normal for mirror logs even if the mimages were stricter.
Use O_DIRECT to gather metadata in lvmdump.
Ignore creation_time when checking for matching metadata for lvmetad.
Fix possible NULL pointer derefence when checking for monitoring.
Add lvmreport(7) man page.
Don't install lvmraid(7) man page when raid excluded. (2.02.165)
Report 0% as dirty (copy%) for cache without any used block.
Fix lvm2api reporting of cache data and metadata percent.
Restore reporting of metadata usage for cache volumes (2.02.155).
Support raid scrubbing on cache origin LV.
Version 2.02.165 - 7th September 2016
=====================================
Add lvmraid(7) man page.
Use udev db to check for mpath components before running pvscan for lvmetad.
Use lsblk -s and lsblk -O in lvmdump only if these options are supported.
Fix number of stripes shown in lvcreate raid10 message when too many.
Change lvmdbusd to use new lvm shell facilities.
Do not monitor cache-pool metadata when LV is just being cleared.
Add allocation/cache_pool_max_chunks to prevent misuse of cache target.
Give error not segfault in lvconvert --splitmirrors when PV lies outside LV.
Fix typo in report/columns_as_rows config option name recognition (2.02.99).
Avoid PV tags when checking allocation against parallel PVs.
Disallow mirror conversions of raid10 volumes.
Fix dmeventd unmonitoring when segment type (and dso) changes.
Don't allow lvconvert --repair on raid0 devices or attempt to monitor them.
No longer adjust incorrect number of raid stripes supplied to lvcreate.
Move lcm and gcd to lib/misc.
Fix vgsplit of external origins. (2.02.162)
Prohibit creation of RAID LVs unless VG extent size is at least the page size.
Suppress some unnecessary --stripesize parameter warnings.
Fix 'pvmove -n name ...' to prohibit collocation of RAID SubLVs
Version 2.02.164 - 15th August 2016
===================================
Fix selection of PVs when allocating raid0_meta.
Fix sdbus socket leak leading to hang in lvmnotify.
Specify max stripes for raid LV types: raid0:64; 1:10; 4,5:63; 6:62; 10:32.
Avoid double suffix when naming _rmeta LV paired with _rimage LV.
Version 2.02.163 - 10th August 2016
===================================
Add profile for lvmdbusd which uses lvm shell json report output.
Restrict in-command modification of some parms in lvm shell.
Apply LVM_COMMAND_PROFILE early for lvm shell.
Refactor reporting so lvm shell log report collects whole of cmd execution.
Support LVM_*_FD envvars to redirect output to file descriptors.
Limit use of --corelog and --mirrorlog to mirrors in lvconvert.
Reject --nosync option for RAID6 LVs in lvcreate.
Do not refresh whole cmd context if profile dropped after processing LVM cmd.
Support straightforward lvconvert between striped and raid4 LVs.
Support straightforward lvconvert between raid1 and mirror LVs.
Report supported conversions when asked for unsupported raid lvconvert.
Add "--rebuild PV" option to lvchange to allow for PV selective rebuilds.
Preserve existing mirror region size when using --repair.
Forbid stripe parameters with lvconvert --repair.
Unify stripe size validation into get_stripe_params to catch missing cases.
Further lvconvert validation logic refactoring.
Version 2.02.162 - 28th July 2016
=================================
Extend vg_validate also to check raid configurations thoroughly.
Support lvconvert -Zn also when doing full cache pool conversion.
Suppress not zeroing warn when converting to thin LV for non-zeroing tpool.
Fix automatic updates of PV extension headers to newest version.
Improve lvconvert --trackchanges validation to require --splitmirrors 1.
Add note about lastlog built-in command to lvm man page.
Fix unrecognised segtype flag message.
lvconvert not clears cache pool metadata ONLY with -Zn.
Add allocation/raid_stripe_all_devices to reinstate previous behaviour.
Create raid stripes across fixed small numbers of PVs instead of all PVs.
Enabled lvconvert --uncache to work with partial VG.
Disallow lvconvert --replace with raid0* LVs.
Fix some lvmetad changed VG metadata notifications that sent uncommitted data.
Version 2.02.161 - 15th July 2016
=================================
Prohibit some lvchange/lvresize that were failing on raid0 volumes.
Fix segfaults in complex vgsplits. (2.02.159)
Reformat unwieldy lvconvert man page.
Allow --force to be passed through to pvcreate from vgcreate. (2.02.144)
Fix lvresize of filesystem when LV has already right size (2.02.141)
New LVM_LOG_FILE_MAX_LINES env var to limit max size of created logs.
Version 2.02.160 - 6th July 2016
================================
Minor fixes from coverity.
Version 2.02.159 - 6th July 2016
================================
Add raid0_meta segment type that provides metadata space for raid conversions.
Fix created link for a used pool for vgmknode.
Introduce and use is_power_of_2 macro.
Support conversions between striped and raid0 segment types.
Add infrastructure for raid takeover lvconvert options.
Version 2.02.158 - 25th June 2016
=================================
Add a more efficient native vgimportclone command to replace the script.
Make lvmlockd always attempt to connect to lvmetad if no connection exists.
Let lvmetad handle new connections after shutdown signal.
Disable lvmetad when vgcfgrestore begins and enable it again after.
Make pvscan do activation if lvmetad is configured but not running.
Fix rescanning the PVs for a single VG when using lvmetad.
Pool metadata lvresize uses now same code as resize of normal volume.
Preserve monitoring status when updating thin-pool metadata.
Return 0 (inactive) when status cannot be queried in _lv_active().
Switch to log_warn() for failing activation status query.
Replace vgimportclone script with binary.
While lvmetad is shutting down, continue handling all connections cleanly.
Refactor lvconvert argument handling code.
Notify lvmetad when vgcfgrestore changes VG metadata.
Add --logonly option to report only cmd log for a command, not other reports.
Add log/command_log_selection to configure default selection used on cmd log.
Use 'orphan' object type in cmd log for groups to collect PVs not yet in VGs.
Add lvm lastlog command for query and display of last cmd's log in lvm shell.
Report per-object return codes via cmd log while processing multiple objects.
Annotate processing code with log report hooks for per-object command log.
Also pass common printed messages (besides warnings and errors) to log report.
Log warnings and errors via report during cmd processing if this is enabled.
Make it possible to iterate over internal 'orphan' VGs in process_each_vg fn.
Make -S|--select option groupable that allows this option to be repeated.
Make -O|--sort option groupable that allows this option to be repeated.
Add --configreport option to select report for which next options are applied.
Add support for priorities on grouping command arguments.
Add report/{pvs,vgs,lvs,pvsegs,segs}_{cols,sort}_full to lvm.conf.
Add lvm fullreport command for joined PV, VG, LV and segment report per VG.
Integrate report group handling and cmd log report into cmd processing code.
Add log/report_command_log to lvm.conf to enable or disable cmd log report.
Add log/report_output_format to lvm.conf for default report output format.
Recognize --reportformat {basic|json} option to select report output format.
Add log/command_log_{sort,cols} to lvm.conf to configure command log report.
Add log_object_{type,name,id,group,group_id} fields to cmd log.
Add log_{seq_num,type,context,message,errno,ret_code} fields to cmd log.
Add CMDLOG report type - a separate report type for command logging.
Version 2.02.157 - 17th June 2016
=================================
Change pvscan --cache -aay to scan locally if lvmetad fails.
Version 2.02.156 - 11th June 2016
=================================
Don't allow duplicate orphan PVs to be used with vgcreate/vgextend/pvcreate.
Improve handling of lvmetad update failures.
Yes/No prompt accepts '^[ ^t]*([Yy]([Ee]([Ss]|)|)|[Nn]([Oo]|))[ ^t]*$'.
If available, also collect output from lsblk command when running lvmdump -s.
Version 2.02.155 - 3rd June 2016
================================
Reject PV tags on pvmove cmdline because only 1 PV is supported. (2.02.141)
Fix compilation error when building with configure --disable-devmapper.
Fix lvmconfig --type diff to display complete diff if config cascade used.
Automatically filter out partitioned loop devices with partscan (losetup -P).
Fix lvm devtypes internal error if -S used with field name from pvs/vgs/lvs.
When reporting Data%,Snap%,Meta%,Cpy%Sync use single ioctl per LV.
Add lvseg_percent_with_info_and_seg_status() for percent retrieval.
Enhance internal seg_status handling to understand snapshots better.
When refresh failed in suspend, call resume upon error path.
Support passthrough cache mode when waiting for clean cache.
Check cache status only for 'in-use' cache pools.
Extend setup_task() to preset flushing for dm_task object.
When checking LV is a merging COW, validate its a COW LV first.
Correcting value in copy_percent() for 100%.
Update vgreduce to use process_each_vg.
Update lvconvert to use process_each_lv.
Update pvscan to use process_each_vg for autoactivation.
Add basic support for --type raid0 using md.
Add support for lvchange --cachemode for cached LV.
Fix liblvm2app error handling when setting up context.
Delay liblvm2app init in python code until it is needed.
Simplify thread locking in lvmetad to fix locking problems.
Allow pvremove -ff to remove a duplicate PV.
Fix lvm2-activation-generator to read lvm.conf without full command setup.
Allow a minimal context to be used in lvm2app for reading lvm.conf.
Version 2.02.154 - 14th May 2016
================================
Fix liblvm segfault after failure initialising lvmetad connection.
Retry open without O_NOATIME if it fails (not file owner/CAP_FOWNER).
Split _report into one fn for options and arguments and one for processing.
Version 2.02.153 - 7th May 2016
===============================
Change warning messages related to duplicate PVs.
A named device is always processed itself, not switched for a duplicate.
Add PV attr "d" and report field "duplicate" for duplicate PVs.
Add config setting to disallow VG changes when duplicate PVs exist.
Use device size and active LVs to choose the preferred duplicate PV.
Disable lvmetad when duplicate PVs are seen.
Support --chunksize option also when caching LV when possible.
Add function to check for target presence and version via 1 ioctl.
Version 2.02.152 - 30th April 2016
==================================
Use any inherited tags when wiping metadata sub LVs to ensure activation.
Add str_list_wipe.
Improve support for interrupting procesing of volumes during lvchange.
Use failed command return code when lvchanging read-only volume.
Show creation transaction_id and zeroing state of pool with thin volume.
Stop checking for dm_cache_mq policy with cache target 1.9 (alias to smq).
Check first /sys/module/dm_* dir existance before using modprobe.
Remove mpath from 10-dm.rules, superseded by 11-dm-mpath.rules (mpath>=0.6.0).
Version 2.02.151 - 23rd April 2016
==================================
Fix error path after reusing of _setup_task (2.02.150).
Fix memory access for empty sysfs values (2.02.149).
Disable lvmetad when lvm1 metadata is seen, so commands revert to scanning.
Suppress errors when snapshot merge gets delayed because volume is in use.
Avoid internal snapshot LV names in messages.
Autodetect and use /run/lock dir when available instead of /var/lock.
lvchange --refresh for merging thin origin will retry to deactivate snapshot.
Recognize in-progress snapshot merge for thin volumes from dm table.
Avoid deciding to initiate a pending snapshot merge during resume.
Improve retrying lvmetad requests while lvmetad is being updated.
Read devices instead of using the lvmetad cache if rescan fails.
Move lvmetad token/filter check and device rescan to the start of commands.
Don't try deactivating fictional internal LV before snapshot merge. (2.02.105)
When not obtaining devs from udev, check they exist before caching them.
Detect device mismatch also when compiling without udev support.
Version 2.02.150 - 9th April 2016
=================================
Avoid using flushing dm status ioctl when checking for usable DM device.
Check for devices without LVM- uuid prefix only with kernels < 3.X.
Reuse %FREE size aproximation with lvcreate -l%PVS thin-pool.
Allow the lvmdump directory to exist already provided it is empty.
Show lvconverted percentage with 2 decimal digits.
Fix regression in suspend when repairing --type mirror (2.02.133).
Version 2.02.149 - 1st April 2016
=================================
Do not flush thin-pool when checking metadata fullness.
Remove spurious error about no value in /sys/dev/block/major:minor/dm/uuid.
Fix device mismatch detection for LV if persistent .cache file is used.
Fix holder device not being found in /dev while sysfs has it during dev scan.
Version 2.02.148 - 26th March 2016
==================================
Introduce TARGET_NAME and MODULE NAME macros.
Replace hard-coded module and target names with macros.
Add pv_major and pv_minor report fields.
Detect and warn about mismatch between devices used and assumed for an LV.
Version 2.02.147 - 19th March 2016
==================================
If available, use /proc/self/mountinfo to detect mounted volume in fsadm.
Fix resize of stacked raid thin data volume (2.02.141).
Fix test for lvremove failure in lvconvert --uncache (2.02.146).
Version 2.02.146 - 11th March 2016
==================================
More man page cleanups in lvconvert.
Fix makefile vpath in /udev when generating udev rules files.
Another attempt to improve VG name parsing for lvconvert (2.02.144).
Use new cache status info and skip flushing for failed cache.
Support --uncache with missing PVs.
Tidy report field names, headings and widths.
Add vgscan --notifydbus to send a dbus notification.
Add dbus notification from commands after a PV/VG/LV changes state.
Version 2.02.145 - 4th March 2016
=================================
Make it possible to use lvremove and lvrename on historical LVs.
For historical LVs, report 'none' for lv_layout and 'history' for lv_role.
Add full_{ancestors,descendants} fields to report LV ancestry with history.
Report (h)istorical state within 5th bit (State) of the lv_attr field.
Add lv_historical reporting field to report if LV is historical or not.
Add lv_time_removed reporting field to display removal time for hist. LVs.
Report lv_name, lv_uuid, vg_name, lv_time for historical LVs.
Add --nohistory switch to lvremove to disable history recording on demand.
Add -H|--history switch to lvs and lvdisplay to include historical LVs.
Create historical LVs out of removed thin snapshot LVs and record in history.
Add metadata/lvs_history_retention_time for automatic removal of hist. LVs.
Add metadata/record_lvs_history config for switching LV history recording.
Add support and infrastructure for tracking historical LVs.
Improve lvconvert man page.
Add kernel_cache_policy lvs field.
Display [unknown] instead of 'unknown device' in pvs output.
Fix error path when pvcreate allocation fails (2.02.144).
Display [unknown] instead of blank for unknown VG names in pvs output.
Version 2.02.144 - 26th February 2016
=====================================
Use new PV processing code in pvcreate/vgcreate/vgextend/pvremove.
Add new PV processing code that prompts user without locks held.
Prevent lvmlockd blocking with new flag requiring sanlock 3.3.0.
Only show (u)sed pv_attr char when PV is not (a)llocatable. (2.02.143)
Update makefile to generate lcov output also for lvmpolld and lvmlockd.
Fix SystemdService lvm2-lvmdbusd.service name.
Improve support for env LVM_VG_NAME for reference VG name in lvconvert.
Fix regression when lvresize accepted zero sizes. (2.02.141)
Always warn user about PV in use even when pvremove uses --force --force.
Use uninitialized pool header detection in all cases.
Fix read error detection when checking for uninitialized thin-pool header.
Fix error path for internal error in lvmetad VG lookup code.
Version 2.02.143 - 21st February 2016
=====================================
Fix error path when sending thin-pool message fails in update_pool_lv().
Support reporting CheckNeeded and Fail state for thin-pool and thin LV.
For failing thin-pool and thin volume correctly report percentage as INVALID.
Report -1, not 'unkown' for lv_{snapshot_invalid,merge_failed} with --binary.
Add configure --enable-dbus-service for an LVM D-Bus service.
Replace configure --enable-python_bindings with python2 and python3 versions.

View File

@@ -1,150 +1,5 @@
Version 1.02.138 -
Version 1.02.117 -
=====================================
Support configurable command executed from dmeventd thin plugin.
Support new R|r human readable units output format.
Thin dmeventd plugin reacts faster on lvextend failure path with umount.
Add dm_stats_bind_from_fd() to bind a stats handle from a file descriptor.
Do not try call callback when reverting activation on error path.
Fix file mapping for extents with physically adjacent extents.
Validation vsnprintf result in runtime translate of dm_log (1.02.136).
Separate filemap extent allocation from region table.
Fix segmentation fault when filemap region creation fails.
Fix performance of region cleanup for failed filemap creation.
Fix very slow region deletion with many regions.
Version 1.02.137 - 30th November 2016
=====================================
Document raid status values.
Always exit dmsetup with success when asked to display help/version.
Version 1.02.136 - 5th November 2016
====================================
Log failure of raid device with log_error level.
Use dm_log_with_errno and translate runtime to dm_log only when needed.
Make log messages from dm and lvm library different from dmeventd.
Notice and Info messages are again logged from dmeventd and its plugins.
Dmeventd now also respects DM_ABORT_ON_INTERNAL_ERRORS as libdm based tool.
Report as non default dm logging also when logging with errno was changed.
Use log_level() macro to consistently decode message log level in dmeventd.
Still produce output when dmsetup dependency tree building finds dev missing.
Check and report pthread_sigmask() failure in dmeventd.
Check mem alloc fail in _canonicalize_field_ids().
Use unsigned math when checking more then 31 legs of raid.
Fix 'dmstats delete' with dmsetup older than v1.02.129
Fix stats walk segfault with dmsetup older than v1.02.129
Version 1.02.135 - 26th September 2016
======================================
Fix man entry for dmsetup status.
Introduce new dm_config_parse_without_dup_node_check().
Don't omit last entry in dmstats list --group.
Version 1.02.134 - 7th September 2016
=====================================
Improve explanation of udev fallback in libdevmapper.h.
Version 1.02.133 - 10th August 2016
===================================
Add dm_report_destroy_rows/dm_report_group_output_and_pop_all for lvm shell.
Adjust group handling and json production for lvm shell.
Version 1.02.132 - 28th July 2016
=================================
Fix json reporting to escape '"' character that may appear in reported string.
Version 1.02.131 - 15th July 2016
=================================
Disable queueing on mpath devs in blk-availability systemd service/initscript.
Add new -m|--mpathoption disablequeueing to blkdeactivate.
Automatically group regions with 'create --segments' unless --nogroup.
Fix resource leak when deleting the first member of a group.
Allow --bounds with 'create --filemap' for dmstats.
Enable creation of filemap regions with histograms.
Enable histogram aggregation for regions with more than one area.
Enable histogram aggregation for groups of regions.
Add a --filemap option to 'dmstats create' to allow mapping of files.
Add dm_stats_create_regions_from_fd() to map file extents to regions.
Version 1.02.130 - 6th July 2016
================================
Minor fixes from coverity.
Version 1.02.129 - 6th July 2016
================================
Update default dmstats field selections for groups.
Add 'obj_type', 'group_id', and 'statsname' fields to dmstats reports.
Add --area, --region, and --group to dmstats to control object selection.
Add --alias, --groupid, --regions to dmstats for group creation and deletion.
Add 'group' and 'ungroup' commands to dmstats.
Allow dm_stats_delete_group() to optionally delete all group members.
Add dm_stats_get_object_type() to return the type of object present.
Add dm_stats_walk_init() allowing control of objects visited by walks.
Add dm_stats_get_group_descriptor() to return the member list as a string.
Introduce dm_stats_get_nr_groups() and dm_stats_group_present().
Add dm_stats_{get,set}_alias() to set and retrieve alias names for groups.
Add dm_stats_get_group_id() to return the group ID for a given region.
Add dm_stats_{create,delete}_group() to allow grouping of stats regions.
Add enum-driven dm_stats_get_{metric,counter}() interfaces.
Add dm_bitset_parse_list() to parse a string representation of a bitset.
Thin dmeventd plugin umounts lvm2 volume only when pool is 95% or more.
Version 1.02.128 - 25th June 2016
=================================
Recognize 'all' keyword used in selection as synonym for "" (no selection).
Add dm_report_set_selection to set selection for multiple output of report.
Add DM_REPORT_OUTPUT_MULTIPLE_TIMES flag for multiple output of same report.
Move field width handling/sort init from dm_report_object to dm_report_output.
Add _LOG_BYPASS_REPORT flag for bypassing any log report currently set.
Introduce DM_REPORT_GROUP_JSON for report group with JSON output format.
Introduce DM_REPORT_GROUP_BASIC for report group with basic report output.
Introduce DM_REPORT_GROUP_SINGLE for report group having single report only.
Add dm_report_group_{create,push,pop,destroy} to support report grouping.
Version 1.02.127 - 11th June 2016
=================================
Fix blkdeactivate regression causing skipping of dm + md devices. (1.02.126)
Version 1.02.126 - 3rd June 2016
================================
Report passthrough caching mode when parsing cache mode.
Version 1.02.125 - 14th May 2016
================================
Show library version in message even if dm driver version is unavailable.
Version 1.02.124 - 30th April 2016
==================================
Add dm_udev_wait_immediate to libdevmapper for waiting outside the library.
Version 1.02.123 - 23rd April 2016
==================================
Do not strip LVM- when debug reporting not found uuid.
Version 1.02.122 - 9th April 2016
=================================
Change log_debug ioctl flags from single characters into words.
Version 1.02.121 - 26th March 2016
==================================
Adjust raid status function.
Version 1.02.120 - 11th March 2016
==================================
Improve parsing of cache status and report Fail, Error, needs_check, ro.
Version 1.02.119 - 4th March 2016
=================================
Fix dm_config_write_node and variants to return error on subsection failures.
Remove 4096 char limit due to buffer size if writing dm_config_node.
Version 1.02.118 - 26th February 2016
=====================================
Fix string boundary check in _get_canonical_field_name().
Always initialized hist struct in _stats_parse_histogram().
Version 1.02.117 - 21st February 2016
=====================================
Improve status parsing for thin-pool and thin devices.
Version 1.02.116 - 15th February 2016
=====================================
@@ -207,7 +62,7 @@ Version 1.02.110 - 30th October 2015
Correct use of max_write_behind parameter when generating raid target line.
Fix dm-event systemd service to make sure it is executed before mounting.
Version 1.02.109 - 22nd September 2015
Version 1.02.109 - 22nd September 2016
======================================
Update man pages for dmsetup and dmstats.
Improve help text for dmsetup.

View File

@@ -61,174 +61,3 @@ AC_DEFUN([AC_TRY_LDFLAGS],
ifelse([$4], [], [:], [$4])
fi
])
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_gcc_builtin.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_GCC_BUILTIN(BUILTIN)
#
# DESCRIPTION
#
# This macro checks if the compiler supports one of GCC's built-in
# functions; many other compilers also provide those same built-ins.
#
# The BUILTIN parameter is the name of the built-in function.
#
# If BUILTIN is supported define HAVE_<BUILTIN>. Keep in mind that since
# builtins usually start with two underscores they will be copied over
# into the HAVE_<BUILTIN> definition (e.g. HAVE___BUILTIN_EXPECT for
# __builtin_expect()).
#
# The macro caches its result in the ax_cv_have_<BUILTIN> variable (e.g.
# ax_cv_have___builtin_expect).
#
# The macro currently supports the following built-in functions:
#
# __builtin_assume_aligned
# __builtin_bswap16
# __builtin_bswap32
# __builtin_bswap64
# __builtin_choose_expr
# __builtin___clear_cache
# __builtin_clrsb
# __builtin_clrsbl
# __builtin_clrsbll
# __builtin_clz
# __builtin_clzl
# __builtin_clzll
# __builtin_complex
# __builtin_constant_p
# __builtin_ctz
# __builtin_ctzl
# __builtin_ctzll
# __builtin_expect
# __builtin_ffs
# __builtin_ffsl
# __builtin_ffsll
# __builtin_fpclassify
# __builtin_huge_val
# __builtin_huge_valf
# __builtin_huge_vall
# __builtin_inf
# __builtin_infd128
# __builtin_infd32
# __builtin_infd64
# __builtin_inff
# __builtin_infl
# __builtin_isinf_sign
# __builtin_nan
# __builtin_nand128
# __builtin_nand32
# __builtin_nand64
# __builtin_nanf
# __builtin_nanl
# __builtin_nans
# __builtin_nansf
# __builtin_nansl
# __builtin_object_size
# __builtin_parity
# __builtin_parityl
# __builtin_parityll
# __builtin_popcount
# __builtin_popcountl
# __builtin_popcountll
# __builtin_powi
# __builtin_powif
# __builtin_powil
# __builtin_prefetch
# __builtin_trap
# __builtin_types_compatible_p
# __builtin_unreachable
#
# Unsuppored built-ins will be tested with an empty parameter set and the
# result of the check might be wrong or meaningless so use with care.
#
# LICENSE
#
# Copyright (c) 2013 Gabriele Svelto <gabriele.svelto@gmail.com>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 3
AC_DEFUN([AX_GCC_BUILTIN], [
AS_VAR_PUSHDEF([ac_var], [ax_cv_have_$1])
AC_CACHE_CHECK([for $1], [ac_var], [
AC_LINK_IFELSE([AC_LANG_PROGRAM([], [
m4_case([$1],
[__builtin_assume_aligned], [$1("", 0)],
[__builtin_bswap16], [$1(0)],
[__builtin_bswap32], [$1(0)],
[__builtin_bswap64], [$1(0)],
[__builtin_choose_expr], [$1(0, 0, 0)],
[__builtin___clear_cache], [$1("", "")],
[__builtin_clrsb], [$1(0)],
[__builtin_clrsbl], [$1(0)],
[__builtin_clrsbll], [$1(0)],
[__builtin_clz], [$1(0)],
[__builtin_clzl], [$1(0)],
[__builtin_clzll], [$1(0)],
[__builtin_complex], [$1(0.0, 0.0)],
[__builtin_constant_p], [$1(0)],
[__builtin_ctz], [$1(0)],
[__builtin_ctzl], [$1(0)],
[__builtin_ctzll], [$1(0)],
[__builtin_expect], [$1(0, 0)],
[__builtin_ffs], [$1(0)],
[__builtin_ffsl], [$1(0)],
[__builtin_ffsll], [$1(0)],
[__builtin_fpclassify], [$1(0, 1, 2, 3, 4, 0.0)],
[__builtin_huge_val], [$1()],
[__builtin_huge_valf], [$1()],
[__builtin_huge_vall], [$1()],
[__builtin_inf], [$1()],
[__builtin_infd128], [$1()],
[__builtin_infd32], [$1()],
[__builtin_infd64], [$1()],
[__builtin_inff], [$1()],
[__builtin_infl], [$1()],
[__builtin_isinf_sign], [$1(0.0)],
[__builtin_nan], [$1("")],
[__builtin_nand128], [$1("")],
[__builtin_nand32], [$1("")],
[__builtin_nand64], [$1("")],
[__builtin_nanf], [$1("")],
[__builtin_nanl], [$1("")],
[__builtin_nans], [$1("")],
[__builtin_nansf], [$1("")],
[__builtin_nansl], [$1("")],
[__builtin_object_size], [$1("", 0)],
[__builtin_parity], [$1(0)],
[__builtin_parityl], [$1(0)],
[__builtin_parityll], [$1(0)],
[__builtin_popcount], [$1(0)],
[__builtin_popcountl], [$1(0)],
[__builtin_popcountll], [$1(0)],
[__builtin_powi], [$1(0, 0)],
[__builtin_powif], [$1(0, 0)],
[__builtin_powil], [$1(0, 0)],
[__builtin_prefetch], [$1("")],
[__builtin_trap], [$1()],
[__builtin_types_compatible_p], [$1(int, int)],
[__builtin_unreachable], [$1()],
[m4_warn([syntax], [Unsupported built-in $1, the test may fail])
$1()]
)
])],
[AS_VAR_SET([ac_var], [yes])],
[AS_VAR_SET([ac_var], [no])])
])
AS_IF([test yes = AS_VAR_GET([ac_var])],
[AC_DEFINE_UNQUOTED(AS_TR_CPP(HAVE_$1), 1,
[Define to 1 if the system has the `$1' built-in function])], [])
AS_VAR_POPDEF([ac_var])
])

1
aclocal.m4 vendored
View File

@@ -536,5 +536,4 @@ AC_DEFUN([AM_RUN_LOG],
echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
(exit $ac_status); }])
m4_include([acinclude.m4])

View File

@@ -24,8 +24,7 @@ PROFILES=$(PROFILE_TEMPLATES) \
$(srcdir)/cache-mq.profile \
$(srcdir)/cache-smq.profile \
$(srcdir)/thin-generic.profile \
$(srcdir)/thin-performance.profile \
$(srcdir)/lvmdbusd.profile
$(srcdir)/thin-performance.profile
include $(top_builddir)/make.tmpl

View File

@@ -16,20 +16,15 @@ allocation {
cache_settings {
}
}
log {
report_command_log=0
command_log_sort="log_seq_num"
command_log_cols="log_seq_num,log_type,log_context,log_object_type,log_object_name,log_object_id,log_object_group,log_object_group_id,log_message,log_errno,log_ret_code"
command_log_selection="!(log_type=status && message=success)"
}
global {
units="h"
si_unit_consistency=1
suffix=1
lvdisplay_shows_full_device_path=0
}
report {
output_format="basic"
compact_output=0
compact_output_cols=""
aligned=1
@@ -39,7 +34,7 @@ report {
list_item_separator=","
prefixes=0
quoted=1
columns_as_rows=0
colums_as_rows=0
binary_values_as_numeric=0
time_format="%Y-%m-%d %T %z"
devtypes_sort="devtype_name"
@@ -60,15 +55,5 @@ report {
pvsegs_sort="pv_name,pvseg_start"
pvsegs_cols="pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,pvseg_start,pvseg_size"
pvsegs_cols_verbose="pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,pvseg_start,pvseg_size,lv_name,seg_start_pe,segtype,seg_pe_ranges"
vgs_cols_full="vg_all"
pvs_cols_full="pv_all"
lvs_cols_full="lv_all"
pvsegs_cols_full="pvseg_all,pv_uuid,lv_uuid"
segs_cols_full="seg_all,lv_uuid"
vgs_sort_full="vg_name"
pvs_sort_full="pv_name"
lvs_sort_full="vg_name,lv_name"
pvsegs_sort_full="pv_uuid,pvseg_start"
segs_sort_full="lv_uuid,seg_start"
mark_hidden_devices=1
}

View File

@@ -299,19 +299,6 @@ devices {
# generally do. If enabled, discards will only be issued if both the
# storage and kernel provide support.
issue_discards = 0
# Configuration option devices/allow_changes_with_duplicate_pvs.
# Allow VG modification while a PV appears on multiple devices.
# When a PV appears on multiple devices, LVM attempts to choose the
# best device to use for the PV. If the devices represent the same
# underlying storage, the choice has minimal consequence. If the
# devices represent different underlying storage, the wrong choice
# can result in data loss if the VG is modified. Disabling this
# setting is the safest option because it prevents modifying a VG
# or activating LVs in it while a PV appears on multiple devices.
# Enabling this setting allows the VG to be used as usual even with
# uncertain devices.
allow_changes_with_duplicate_pvs = 0
}
# Configuration section allocation.
@@ -377,14 +364,6 @@ allocation {
# The default setting changed in version 2.02.85.
mirror_logs_require_separate_pvs = 0
# Configuration option allocation/raid_stripe_all_devices.
# Stripe across all PVs when RAID stripes are not specified.
# If enabled, all PVs in the VG or on the command line are used for raid0/4/5/6/10
# when the command does not specify the number of stripes to use.
# This was the default behaviour until release 2.02.162.
# This configuration option has an automatic default value.
# raid_stripe_all_devices = 0
# Configuration option allocation/cache_pool_metadata_require_separate_pvs.
# Cache pool metadata and data will always use different PVs.
cache_pool_metadata_require_separate_pvs = 0
@@ -428,12 +407,6 @@ allocation {
# 32KiB to 1GiB in multiples of 32.
# This configuration option does not have a default value defined.
# Configuration option allocation/cache_pool_max_chunks.
# The maximum number of chunks in a cache pool.
# For cache target v1.9 the recommended maximumm is 1000000 chunks.
# Using cache pool with more chunks may degrade cache performance.
# This configuration option does not have a default value defined.
# Configuration option allocation/thin_pool_metadata_require_separate_pvs.
# Thin pool metdata and data will always use different PVs.
thin_pool_metadata_require_separate_pvs = 0
@@ -492,55 +465,6 @@ allocation {
# How LVM log information is reported.
log {
# Configuration option log/report_command_log.
# Enable or disable LVM log reporting.
# If enabled, LVM will collect a log of operations, messages,
# per-object return codes with object identification and associated
# error numbers (errnos) during LVM command processing. Then the
# log is either reported solely or in addition to any existing
# reports, depending on LVM command used. If it is a reporting command
# (e.g. pvs, vgs, lvs, lvm fullreport), then the log is reported in
# addition to any existing reports. Otherwise, there's only log report
# on output. For all applicable LVM commands, you can request that
# the output has only log report by using --logonly command line
# option. Use log/command_log_cols and log/command_log_sort settings
# to define fields to display and sort fields for the log report.
# You can also use log/command_log_selection to define selection
# criteria used each time the log is reported.
# This configuration option has an automatic default value.
# report_command_log = 0
# Configuration option log/command_log_sort.
# List of columns to sort by when reporting command log.
# See <lvm command> --logonly --configreport log -o help
# for the list of possible fields.
# This configuration option has an automatic default value.
# command_log_sort = "log_seq_num"
# Configuration option log/command_log_cols.
# List of columns to report when reporting command log.
# See <lvm command> --logonly --configreport log -o help
# for the list of possible fields.
# This configuration option has an automatic default value.
# command_log_cols = "log_seq_num,log_type,log_context,log_object_type,log_object_name,log_object_id,log_object_group,log_object_group_id,log_message,log_errno,log_ret_code"
# Configuration option log/command_log_selection.
# Selection criteria used when reporting command log.
# You can define selection criteria that are applied each
# time log is reported. This way, it is possible to control the
# amount of log that is displayed on output and you can select
# only parts of the log that are important for you. To define
# selection criteria, use fields from log report. See also
# <lvm command> --logonly --configreport log -S help for the
# list of possible fields and selection operators. You can also
# define selection criteria for log report on command line directly
# using <lvm command> --configreport log -S <selection criteria>
# which has precedence over log/command_log_selection setting.
# For more information about selection criteria in general, see
# lvm(8) man page.
# This configuration option has an automatic default value.
# command_log_selection = "!(log_type=status && message=success)"
# Configuration option log/verbose.
# Controls the messages sent to stdout or stderr.
verbose = 0
@@ -601,7 +525,7 @@ log {
# debug output if the class is listed here. Classes currently
# available: memory, devices, activation, allocation, lvmetad,
# metadata, cache, locking, lvmpolld. Use "all" to see everything.
debug_classes = [ "memory", "devices", "activation", "allocation", "lvmetad", "metadata", "cache", "locking", "lvmpolld", "dbus" ]
debug_classes = [ "memory", "devices", "activation", "allocation", "lvmetad", "metadata", "cache", "locking", "lvmpolld" ]
}
# Configuration section backup.
@@ -665,7 +589,7 @@ global {
# Configuration option global/units.
# Default value for --units argument.
units = "r"
units = "h"
# Configuration option global/si_unit_consistency.
# Distinguish between powers of 1024 and 1000 bytes.
@@ -927,23 +851,13 @@ global {
# devices/global_filter.
use_lvmetad = @DEFAULT_USE_LVMETAD@
# Configuration option global/lvmetad_update_wait_time.
# The number of seconds a command will wait for lvmetad update to finish.
# After waiting for this period, a command will not use lvmetad, and
# will revert to disk scanning.
# This configuration option has an automatic default value.
# lvmetad_update_wait_time = 10
# Configuration option global/use_lvmlockd.
# Use lvmlockd for locking among hosts using LVM on shared storage.
# Applicable only if LVM is compiled with lockd support in which
# case there is also lvmlockd(8) man page available for more
# information.
# See lvmlockd(8) for more information.
use_lvmlockd = 0
# Configuration option global/lvmlockd_lock_retries.
# Retry lvmlockd lock requests this many times.
# Applicable only if LVM is compiled with lockd support
# This configuration option has an automatic default value.
# lvmlockd_lock_retries = 3
@@ -953,8 +867,7 @@ global {
# LVs have been created, the internal LV needs to be extended. lvcreate
# will automatically extend the internal LV when needed by the amount
# specified here. Setting this to 0 disables the automatic extension
# and can cause lvcreate to fail. Applicable only if LVM is compiled
# with lockd support
# and can cause lvcreate to fail.
# This configuration option has an automatic default value.
# sanlock_lv_extend = 256
@@ -1101,14 +1014,7 @@ global {
# a native systemd service, which allows it to be started on demand,
# and to use its own control group. When this option is disabled, LVM
# commands will supervise long running operations by forking themselves.
# Applicable only if LVM is compiled with lvmpolld support.
use_lvmpolld = @DEFAULT_USE_LVMPOLLD@
# Configuration option global/notify_dbus.
# Enable D-Bus notification from LVM commands.
# When enabled, an LVM command that changes PVs, changes VG metadata,
# or changes the activation state of an LV will send a notification.
notify_dbus = 1
}
# Configuration section activation.
@@ -1156,8 +1062,7 @@ activation {
# Configuration option activation/missing_stripe_filler.
# Method to fill missing stripes when activating an incomplete LV.
# Using 'error' will make inaccessible parts of the device return I/O
# errors on access. Using 'zero' will return success (and zero) on I/O
# You can instead use a device path, in which case,
# errors on access. You can instead use a device path, in which case,
# that device will be used in place of missing stripes. Using anything
# other than 'error' with mirrored or snapshotted volumes is likely to
# result in data corruption.
@@ -1521,22 +1426,6 @@ activation {
# This configuration option has an automatic default value.
# check_pv_device_sizes = 1
# Configuration option metadata/record_lvs_history.
# When enabled, LVM keeps history records about removed LVs in
# metadata. The information that is recorded in metadata for
# historical LVs is reduced when compared to original
# information kept in metadata for live LVs. Currently, this
# feature is supported for thin and thin snapshot LVs only.
# This configuration option has an automatic default value.
# record_lvs_history = 0
# Configuration option metadata/lvs_history_retention_time.
# Retention time in seconds after which a record about individual
# historical logical volume is automatically destroyed.
# A value of 0 disables this feature.
# This configuration option has an automatic default value.
# lvs_history_retention_time = 0
# Configuration option metadata/pvmetadatacopies.
# Number of copies of metadata to store on each PV.
# The --pvmetadatacopies option overrides this setting.
@@ -1615,22 +1504,6 @@ activation {
# This configuration section has an automatic default value.
# report {
# Configuration option report/output_format.
# Format of LVM command's report output.
# If there is more than one report per command, then the format
# is applied for all reports. You can also change output format
# directly on command line using --reportformat option which
# has precedence over log/output_format setting.
# Accepted values:
# basic
# Original format with columns and rows. If there is more than
# one report per command, each report is prefixed with report's
# name for identification.
# json
# JSON format.
# This configuration option has an automatic default value.
# output_format = "basic"
# Configuration option report/compact_output.
# Do not print empty values for all report fields.
# If enabled, all fields that don't have a value set for any of the
@@ -1691,11 +1564,11 @@ activation {
# This configuration option has an automatic default value.
# quoted = 1
# Configuration option report/columns_as_rows.
# Configuration option report/colums_as_rows.
# Output each column as a row.
# If set, this also implies report/prefixes=1.
# This configuration option has an automatic default value.
# columns_as_rows = 0
# colums_as_rows = 0
# Configuration option report/binary_values_as_numeric.
# Use binary values 0 or 1 instead of descriptive literal values.
@@ -1947,76 +1820,10 @@ activation {
# This configuration option has an automatic default value.
# pvsegs_cols_verbose = "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,pvseg_start,pvseg_size,lv_name,seg_start_pe,segtype,seg_pe_ranges"
# Configuration option report/vgs_cols_full.
# List of columns to report for lvm fullreport's 'vgs' subreport.
# See 'vgs -o help' for the list of possible fields.
# This configuration option has an automatic default value.
# vgs_cols_full = "vg_all"
# Configuration option report/pvs_cols_full.
# List of columns to report for lvm fullreport's 'vgs' subreport.
# See 'pvs -o help' for the list of possible fields.
# This configuration option has an automatic default value.
# pvs_cols_full = "pv_all"
# Configuration option report/lvs_cols_full.
# List of columns to report for lvm fullreport's 'lvs' subreport.
# See 'lvs -o help' for the list of possible fields.
# This configuration option has an automatic default value.
# lvs_cols_full = "lv_all"
# Configuration option report/pvsegs_cols_full.
# List of columns to report for lvm fullreport's 'pvseg' subreport.
# See 'pvs --segments -o help' for the list of possible fields.
# This configuration option has an automatic default value.
# pvsegs_cols_full = "pvseg_all,pv_uuid,lv_uuid"
# Configuration option report/segs_cols_full.
# List of columns to report for lvm fullreport's 'seg' subreport.
# See 'lvs --segments -o help' for the list of possible fields.
# This configuration option has an automatic default value.
# segs_cols_full = "seg_all,lv_uuid"
# Configuration option report/vgs_sort_full.
# List of columns to sort by when reporting lvm fullreport's 'vgs' subreport.
# See 'vgs -o help' for the list of possible fields.
# This configuration option has an automatic default value.
# vgs_sort_full = "vg_name"
# Configuration option report/pvs_sort_full.
# List of columns to sort by when reporting lvm fullreport's 'vgs' subreport.
# See 'pvs -o help' for the list of possible fields.
# This configuration option has an automatic default value.
# pvs_sort_full = "pv_name"
# Configuration option report/lvs_sort_full.
# List of columns to sort by when reporting lvm fullreport's 'lvs' subreport.
# See 'lvs -o help' for the list of possible fields.
# This configuration option has an automatic default value.
# lvs_sort_full = "vg_name,lv_name"
# Configuration option report/pvsegs_sort_full.
# List of columns to sort by when reporting for lvm fullreport's 'pvseg' subreport.
# See 'pvs --segments -o help' for the list of possible fields.
# This configuration option has an automatic default value.
# pvsegs_sort_full = "pv_uuid,pvseg_start"
# Configuration option report/segs_sort_full.
# List of columns to sort by when reporting lvm fullreport's 'seg' subreport.
# See 'lvs --segments -o help' for the list of possible fields.
# This configuration option has an automatic default value.
# segs_sort_full = "lv_uuid,seg_start"
# Configuration option report/mark_hidden_devices.
# Use brackets [] to mark hidden devices.
# This configuration option has an automatic default value.
# mark_hidden_devices = 1
# Configuration option report/two_word_unknown_device.
# Use the two words 'unknown device' in place of '[unknown]'.
# This is displayed when the device for a PV is not known.
# This configuration option has an automatic default value.
# two_word_unknown_device = 0
# }
# Configuration section dmeventd.
@@ -2049,14 +1856,6 @@ dmeventd {
# warning is repeated when 85%, 90% and 95% of the pool is filled.
thin_library = "libdevmapper-event-lvm2thin.so"
# Configuration option dmeventd/thin_command.
# The plugin runs command with each 5% increment when thin-pool data volume
# or metadata volume gets above 50%.
# Command which starts with 'lvm ' prefix is internal lvm command.
# You can write your own handler to customise behaviour in more details.
# This configuration option has an automatic default value.
# thin_command = "lvm lvextend --use-policies"
# Configuration option dmeventd/executable.
# The full path to the dmeventd binary.
# This configuration option has an automatic default value.

View File

@@ -1,50 +0,0 @@
#
# DO NOT EDIT THIS FILE!
#
# LVM configuration profile used by lvmdbusd daemon.
#
# This sets up LVM to produce output in the most suitable format for processing
# by lvmdbusd daemon which utilizes LVM shell to execute LVM commands.
#
# Do not edit this file in any way. This profile is distributed together with
# lvmdbusd and it contains configuration that is important for lvmdbusd to
# cooperate and interface with LVM correctly.
#
global {
# use bytes for expected and deterministic output
units=b
# no need for suffix if we have units set
suffix=0
}
report {
compact_output=0
compact_output_cols=""
binary_values_as_numeric=0
# time in number of seconds since the Epoch
time_format="%s"
mark_hidden_devices=1
# lvmdbusd expects JSON output
output_format=json
# *_cols_full for lvm fullreport's fields which lvmdbusd relies on to update its state
vgs_cols_full="vg_name,vg_uuid,vg_fmt,vg_size,vg_free,vg_sysid,vg_extent_size,vg_extent_count,vg_free_count,vg_profile,max_lv,max_pv,pv_count,lv_count,snap_count,vg_seqno,vg_mda_count,vg_mda_free,vg_mda_size,vg_mda_used_count,vg_attr,vg_tags"
pvs_cols_full="pv_name,pv_uuid,pv_fmt,pv_size,pv_free,pv_used,dev_size,pv_mda_size,pv_mda_free,pv_ba_start,pv_ba_size,pe_start,pv_pe_count,pv_pe_alloc_count,pv_attr,pv_tags,vg_name,vg_uuid"
lvs_cols_full="lv_uuid,lv_name,lv_path,lv_size,vg_name,pool_lv_uuid,pool_lv,origin_uuid,origin,data_percent,lv_attr,lv_tags,vg_uuid,lv_active,data_lv,metadata_lv,lv_parent,lv_role,lv_layout"
pvsegs_cols_full="pvseg_start,pvseg_size,segtype,pv_uuid,lv_uuid,pv_name"
segs_cols_full="seg_pe_ranges,segtype,lv_uuid"
vgs_sort_full="vg_name"
pvs_sort_full="pv_name"
lvs_sort_full="vg_name,lv_name"
pvsegs_sort_full="pv_uuid,pvseg_start"
segs_sort_full="lv_uuid,seg_start"
}
log {
# lvmdbusd relies on command log report to inspect LVM command's execution status
report_command_log=1
# display only outermost LVM shell-related log that lvmdbusd inspects first after LVM command execution (it calls 'lastlog' for more detailed log afterwards if needed)
command_log_selection="log_context=shell"
command_log_cols="log_seq_num,log_type,log_context,log_object_type,log_object_name,log_object_id,log_object_group,log_object_group_id,log_message,log_errno,log_ret_code"
command_log_sort="log_seq_num"
}

View File

@@ -51,7 +51,6 @@ local {
# Configuration option local/host_id.
# The lvmlockd sanlock host_id.
# This must be unique among all hosts, and must be between 1 and 2000.
# Applicable only if LVM is compiled with lockd support
# This configuration option has an automatic default value.
# host_id = 0
}

211
configure vendored
View File

@@ -676,7 +676,6 @@ PTHREAD_LIBS
M_LIBS
POOL
PKGCONFIG
ODIRECT
OCFDIR
OCF
MIRRORS
@@ -736,7 +735,6 @@ CLDWHOLEARCHIVE
CLDNOWHOLEARCHIVE
CLDFLAGS
CACHE
BUILD_NOTIFYDBUS
BUILD_LOCKDDLM
BUILD_LOCKDSANLOCK
BUILD_LVMLOCKD
@@ -769,8 +767,6 @@ SYSTEMD_LIBS
SYSTEMD_CFLAGS
BLKID_LIBS
BLKID_CFLAGS
NOTIFY_DBUS_LIBS
NOTIFY_DBUS_CFLAGS
LOCKD_DLM_LIBS
LOCKD_DLM_CFLAGS
LOCKD_SANLOCK_LIBS
@@ -958,7 +954,6 @@ enable_use_lvmetad
with_lvmetad_pidfile
enable_use_lvmpolld
with_lvmpolld_pidfile
enable_notify_dbus
enable_blkid_wiping
enable_udev_systemd_background_jobs
enable_udev_sync
@@ -1044,8 +1039,6 @@ LOCKD_SANLOCK_CFLAGS
LOCKD_SANLOCK_LIBS
LOCKD_DLM_CFLAGS
LOCKD_DLM_LIBS
NOTIFY_DBUS_CFLAGS
NOTIFY_DBUS_LIBS
BLKID_CFLAGS
BLKID_LIBS
SYSTEMD_CFLAGS
@@ -1692,7 +1685,6 @@ Optional Features:
--disable-use-lvmlockd disable usage of LVM lock daemon
--disable-use-lvmetad disable usage of LVM Metadata Daemon
--disable-use-lvmpolld disable usage of LVM Poll Daemon
--enable-notify-dbus enable LVM notification using dbus
--disable-blkid_wiping disable libblkid detection of signatures when wiping
and use native code instead
--disable-udev-systemd-background-jobs
@@ -1821,7 +1813,7 @@ Optional Packages:
--with-default-cache-subdir=SUBDIR
default metadata cache subdir [cache]
--with-default-locking-dir=DIR
default locking directory [autodetect_lock_dir/lvm]
default locking directory [/var/lock/lvm]
--with-default-data-alignment=NUM
set the default data alignment in MiB [1]
--with-interface=IFACE choose kernel interface (ioctl) [ioctl]
@@ -1885,10 +1877,6 @@ Some influential environment variables:
C compiler flags for LOCKD_DLM, overriding pkg-config
LOCKD_DLM_LIBS
linker flags for LOCKD_DLM, overriding pkg-config
NOTIFY_DBUS_CFLAGS
C compiler flags for NOTIFY_DBUS, overriding pkg-config
NOTIFY_DBUS_LIBS
linker flags for NOTIFY_DBUS, overriding pkg-config
BLKID_CFLAGS
C compiler flags for BLKID, overriding pkg-config
BLKID_LIBS linker flags for BLKID, overriding pkg-config
@@ -3169,8 +3157,8 @@ case "$host_os" in
LDDEPS="$LDDEPS .export.sym"
LIB_SUFFIX=so
DEVMAPPER=yes
BUILD_LVMETAD=no
BUILD_LVMPOLLD=no
LVMETAD=no
LVMPOLLD=no
LOCKDSANLOCK=no
LOCKDDLM=no
ODIRECT=yes
@@ -5876,7 +5864,7 @@ fi
done
for ac_header in termios.h sys/statvfs.h sys/timerfd.h linux/magic.h linux/fiemap.h
for ac_header in termios.h sys/statvfs.h sys/timerfd.h
do :
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
@@ -6321,50 +6309,6 @@ _ACEOF
esac
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for __builtin_clz" >&5
$as_echo_n "checking for __builtin_clz... " >&6; }
if ${ax_cv_have___builtin_clz+:} false; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
int
main ()
{
__builtin_clz(0)
;
return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
ax_cv_have___builtin_clz=yes
else
ax_cv_have___builtin_clz=no
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_have___builtin_clz" >&5
$as_echo "$ax_cv_have___builtin_clz" >&6; }
if test yes = $ax_cv_have___builtin_clz; then :
cat >>confdefs.h <<_ACEOF
#define HAVE___BUILTIN_CLZ 1
_ACEOF
fi
################################################################################
for ac_func in ftruncate gethostname getpagesize gettimeofday localtime_r \
memchr memset mkdir mkfifo munmap nl_langinfo realpath rmdir setenv \
@@ -11531,9 +11475,10 @@ if test "${enable_lvmetad+set}" = set; then :
enableval=$enable_lvmetad; LVMETAD=$enableval
fi
test -n "$LVMETAD" && BUILD_LVMETAD=$LVMETAD
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $BUILD_LVMETAD" >&5
$as_echo "$BUILD_LVMETAD" >&6; }
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $LVMETAD" >&5
$as_echo "$LVMETAD" >&6; }
BUILD_LVMETAD=$LVMETAD
################################################################################
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build lvmpolld" >&5
@@ -11543,9 +11488,10 @@ if test "${enable_lvmpolld+set}" = set; then :
enableval=$enable_lvmpolld; LVMPOLLD=$enableval
fi
test -n "$LVMPOLLD" && BUILD_LVMPOLLD=$LVMPOLLD
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $BUILD_LVMPOLLD" >&5
$as_echo "$BUILD_LVMPOLLD" >&6; }
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $LVMPOLLD" >&5
$as_echo "$LVMPOLLD" >&6; }
BUILD_LVMPOLLD=$LVMPOLLD
################################################################################
BUILD_LVMLOCKD=no
@@ -11572,12 +11518,12 @@ if test -n "$LOCKD_SANLOCK_CFLAGS"; then
pkg_cv_LOCKD_SANLOCK_CFLAGS="$LOCKD_SANLOCK_CFLAGS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
{ { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libsanlock_client >= 3.3.0\""; } >&5
($PKG_CONFIG --exists --print-errors "libsanlock_client >= 3.3.0") 2>&5
{ { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libsanlock_client\""; } >&5
($PKG_CONFIG --exists --print-errors "libsanlock_client") 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_LOCKD_SANLOCK_CFLAGS=`$PKG_CONFIG --cflags "libsanlock_client >= 3.3.0" 2>/dev/null`
pkg_cv_LOCKD_SANLOCK_CFLAGS=`$PKG_CONFIG --cflags "libsanlock_client" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
else
pkg_failed=yes
@@ -11589,12 +11535,12 @@ if test -n "$LOCKD_SANLOCK_LIBS"; then
pkg_cv_LOCKD_SANLOCK_LIBS="$LOCKD_SANLOCK_LIBS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
{ { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libsanlock_client >= 3.3.0\""; } >&5
($PKG_CONFIG --exists --print-errors "libsanlock_client >= 3.3.0") 2>&5
{ { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libsanlock_client\""; } >&5
($PKG_CONFIG --exists --print-errors "libsanlock_client") 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_LOCKD_SANLOCK_LIBS=`$PKG_CONFIG --libs "libsanlock_client >= 3.3.0" 2>/dev/null`
pkg_cv_LOCKD_SANLOCK_LIBS=`$PKG_CONFIG --libs "libsanlock_client" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
else
pkg_failed=yes
@@ -11615,9 +11561,9 @@ else
_pkg_short_errors_supported=no
fi
if test $_pkg_short_errors_supported = yes; then
LOCKD_SANLOCK_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libsanlock_client >= 3.3.0" 2>&1`
LOCKD_SANLOCK_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libsanlock_client" 2>&1`
else
LOCKD_SANLOCK_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libsanlock_client >= 3.3.0" 2>&1`
LOCKD_SANLOCK_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libsanlock_client" 2>&1`
fi
# Put the nasty error message in config.log where it belongs
echo "$LOCKD_SANLOCK_PKG_ERRORS" >&5
@@ -11738,17 +11684,11 @@ $as_echo_n "checking whether to build lvmlockd... " >&6; }
$as_echo "$BUILD_LVMLOCKD" >&6; }
if test "$BUILD_LVMLOCKD" = yes; then
if test "$LVMPOLLD" = no; then :
as_fn_error $? "cannot build lvmlockd with --disable-lvmpolld." "$LINENO" 5
fi
if test "$LVMETAD" = no; then :
as_fn_error $? "cannot build lvmlockd with --disable-lvmetad." "$LINENO" 5
fi
if test "$BUILD_LVMPOLLD" = no; then :
if test -n "$BUILD_LVMPOLLD"; then :
BUILD_LVMPOLLD=yes; { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Enabling lvmpolld - required by lvmlockd." >&5
$as_echo "$as_me: WARNING: Enabling lvmpolld - required by lvmlockd." >&2;}
fi
if test "$BUILD_LVMETAD" = no; then :
if test -n "$BUILD_LVMETAD"; then :
BUILD_LVMETAD=yes; { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Enabling lvmetad - required by lvmlockd." >&5
$as_echo "$as_me: WARNING: Enabling lvmetad - required by lvmlockd." >&2;}
fi
@@ -11876,101 +11816,6 @@ cat >>confdefs.h <<_ACEOF
_ACEOF
################################################################################
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build notifydbus" >&5
$as_echo_n "checking whether to build notifydbus... " >&6; }
# Check whether --enable-notify-dbus was given.
if test "${enable_notify_dbus+set}" = set; then :
enableval=$enable_notify_dbus; NOTIFYDBUS=$enableval
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $NOTIFYDBUS" >&5
$as_echo "$NOTIFYDBUS" >&6; }
BUILD_NOTIFYDBUS=$NOTIFYDBUS
if test "$BUILD_NOTIFYDBUS" = yes; then
$as_echo "#define NOTIFYDBUS_SUPPORT 1" >>confdefs.h
LIBS="-lsystemd $LIBS"
fi
################################################################################
if test "$BUILD_NOTIFYDBUS" = yes; then
pkg_failed=no
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for NOTIFY_DBUS" >&5
$as_echo_n "checking for NOTIFY_DBUS... " >&6; }
if test -n "$NOTIFY_DBUS_CFLAGS"; then
pkg_cv_NOTIFY_DBUS_CFLAGS="$NOTIFY_DBUS_CFLAGS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
{ { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"systemd >= 221\""; } >&5
($PKG_CONFIG --exists --print-errors "systemd >= 221") 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_NOTIFY_DBUS_CFLAGS=`$PKG_CONFIG --cflags "systemd >= 221" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
else
pkg_failed=yes
fi
else
pkg_failed=untried
fi
if test -n "$NOTIFY_DBUS_LIBS"; then
pkg_cv_NOTIFY_DBUS_LIBS="$NOTIFY_DBUS_LIBS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
{ { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"systemd >= 221\""; } >&5
($PKG_CONFIG --exists --print-errors "systemd >= 221") 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_NOTIFY_DBUS_LIBS=`$PKG_CONFIG --libs "systemd >= 221" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
else
pkg_failed=yes
fi
else
pkg_failed=untried
fi
if test $pkg_failed = yes; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
_pkg_short_errors_supported=yes
else
_pkg_short_errors_supported=no
fi
if test $_pkg_short_errors_supported = yes; then
NOTIFY_DBUS_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "systemd >= 221" 2>&1`
else
NOTIFY_DBUS_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "systemd >= 221" 2>&1`
fi
# Put the nasty error message in config.log where it belongs
echo "$NOTIFY_DBUS_PKG_ERRORS" >&5
$bailout
elif test $pkg_failed = untried; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
$bailout
else
NOTIFY_DBUS_CFLAGS=$pkg_cv_NOTIFY_DBUS_CFLAGS
NOTIFY_DBUS_LIBS=$pkg_cv_NOTIFY_DBUS_LIBS
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
HAVE_NOTIFY_DBUS=yes
fi
fi
################################################################################
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable libblkid detection of signatures when wiping" >&5
@@ -15162,12 +15007,7 @@ _ACEOF
if test "${with_default_locking_dir+set}" = set; then :
withval=$with_default_locking_dir; DEFAULT_LOCK_DIR=$withval
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for default lock directory" >&5
$as_echo_n "checking for default lock directory... " >&6; }
DEFAULT_LOCK_DIR="$RUN_DIR/lock/lvm"
test -d "$RUN_DIR/lock" || DEFAULT_LOCK_DIR="/var/lock/lvm"
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $DEFAULT_LOCK_DIR" >&5
$as_echo "$DEFAULT_LOCK_DIR" >&6; }
DEFAULT_LOCK_DIR="/var/lock/lvm"
fi
@@ -15382,13 +15222,11 @@ LVM_LIBAPI=`echo "$VER" | $AWK -F '[()]' '{print $2}'`
################################################################################
ac_config_files="$ac_config_files Makefile make.tmpl daemons/Makefile daemons/clvmd/Makefile daemons/cmirrord/Makefile daemons/dmeventd/Makefile daemons/dmeventd/libdevmapper-event.pc daemons/dmeventd/plugins/Makefile daemons/dmeventd/plugins/lvm2/Makefile daemons/dmeventd/plugins/raid/Makefile daemons/dmeventd/plugins/mirror/Makefile daemons/dmeventd/plugins/snapshot/Makefile daemons/dmeventd/plugins/thin/Makefile daemons/lvmdbusd/Makefile daemons/lvmdbusd/path.py daemons/lvmetad/Makefile daemons/lvmpolld/Makefile daemons/lvmlockd/Makefile conf/Makefile conf/example.conf conf/lvmlocal.conf conf/command_profile_template.profile conf/metadata_profile_template.profile include/.symlinks include/Makefile lib/Makefile lib/format1/Makefile lib/format_pool/Makefile lib/locking/Makefile lib/mirror/Makefile lib/replicator/Makefile include/lvm-version.h lib/raid/Makefile lib/snapshot/Makefile lib/thin/Makefile lib/cache_segtype/Makefile libdaemon/Makefile libdaemon/client/Makefile libdaemon/server/Makefile libdm/Makefile libdm/libdevmapper.pc liblvm/Makefile liblvm/liblvm2app.pc man/Makefile po/Makefile python/Makefile python/setup.py scripts/blkdeactivate.sh scripts/blk_availability_init_red_hat scripts/blk_availability_systemd_red_hat.service scripts/clvmd_init_red_hat scripts/cmirrord_init_red_hat scripts/com.redhat.lvmdbus1.service scripts/dm_event_systemd_red_hat.service scripts/dm_event_systemd_red_hat.socket scripts/lvm2_cluster_activation_red_hat.sh scripts/lvm2_cluster_activation_systemd_red_hat.service scripts/lvm2_clvmd_systemd_red_hat.service scripts/lvm2_cmirrord_systemd_red_hat.service scripts/lvm2_lvmdbusd_systemd_red_hat.service scripts/lvm2_lvmetad_init_red_hat scripts/lvm2_lvmetad_systemd_red_hat.service scripts/lvm2_lvmetad_systemd_red_hat.socket scripts/lvm2_lvmpolld_init_red_hat scripts/lvm2_lvmpolld_systemd_red_hat.service scripts/lvm2_lvmpolld_systemd_red_hat.socket scripts/lvm2_lvmlockd_systemd_red_hat.service scripts/lvm2_lvmlocking_systemd_red_hat.service scripts/lvm2_monitoring_init_red_hat scripts/lvm2_monitoring_systemd_red_hat.service scripts/lvm2_pvscan_systemd_red_hat@.service scripts/lvm2_tmpfiles_red_hat.conf scripts/lvmdump.sh scripts/Makefile test/Makefile test/api/Makefile test/unit/Makefile tools/Makefile udev/Makefile unit-tests/datastruct/Makefile unit-tests/regex/Makefile unit-tests/mm/Makefile"
ac_config_files="$ac_config_files Makefile make.tmpl daemons/Makefile daemons/clvmd/Makefile daemons/cmirrord/Makefile daemons/dmeventd/Makefile daemons/dmeventd/libdevmapper-event.pc daemons/dmeventd/plugins/Makefile daemons/dmeventd/plugins/lvm2/Makefile daemons/dmeventd/plugins/raid/Makefile daemons/dmeventd/plugins/mirror/Makefile daemons/dmeventd/plugins/snapshot/Makefile daemons/dmeventd/plugins/thin/Makefile daemons/lvmdbusd/Makefile daemons/lvmdbusd/path.py daemons/lvmetad/Makefile daemons/lvmpolld/Makefile daemons/lvmlockd/Makefile conf/Makefile conf/example.conf conf/lvmlocal.conf conf/command_profile_template.profile conf/metadata_profile_template.profile include/.symlinks include/Makefile lib/Makefile lib/format1/Makefile lib/format_pool/Makefile lib/locking/Makefile lib/mirror/Makefile lib/replicator/Makefile include/lvm-version.h lib/raid/Makefile lib/snapshot/Makefile lib/thin/Makefile lib/cache_segtype/Makefile libdaemon/Makefile libdaemon/client/Makefile libdaemon/server/Makefile libdm/Makefile libdm/libdevmapper.pc liblvm/Makefile liblvm/liblvm2app.pc man/Makefile po/Makefile python/Makefile python/setup.py scripts/blkdeactivate.sh scripts/blk_availability_init_red_hat scripts/blk_availability_systemd_red_hat.service scripts/clvmd_init_red_hat scripts/cmirrord_init_red_hat scripts/com.redhat.lvmdbus1.service scripts/dm_event_systemd_red_hat.service scripts/dm_event_systemd_red_hat.socket scripts/lvm2_cluster_activation_red_hat.sh scripts/lvm2_cluster_activation_systemd_red_hat.service scripts/lvm2_clvmd_systemd_red_hat.service scripts/lvm2_cmirrord_systemd_red_hat.service scripts/lvm2_lvmdbusd_systemd_red_hat.service scripts/lvm2_lvmetad_init_red_hat scripts/lvm2_lvmetad_systemd_red_hat.service scripts/lvm2_lvmetad_systemd_red_hat.socket scripts/lvm2_lvmpolld_init_red_hat scripts/lvm2_lvmpolld_systemd_red_hat.service scripts/lvm2_lvmpolld_systemd_red_hat.socket scripts/lvm2_lvmlockd_systemd_red_hat.service scripts/lvm2_lvmlocking_systemd_red_hat.service scripts/lvm2_monitoring_init_red_hat scripts/lvm2_monitoring_systemd_red_hat.service scripts/lvm2_pvscan_systemd_red_hat@.service scripts/lvm2_tmpfiles_red_hat.conf scripts/Makefile test/Makefile test/api/Makefile test/unit/Makefile tools/Makefile udev/Makefile unit-tests/datastruct/Makefile unit-tests/regex/Makefile unit-tests/mm/Makefile"
cat >confcache <<\_ACEOF
# This file is a shell script that caches the results of configure
@@ -16155,7 +15993,6 @@ do
"scripts/lvm2_monitoring_systemd_red_hat.service") CONFIG_FILES="$CONFIG_FILES scripts/lvm2_monitoring_systemd_red_hat.service" ;;
"scripts/lvm2_pvscan_systemd_red_hat@.service") CONFIG_FILES="$CONFIG_FILES scripts/lvm2_pvscan_systemd_red_hat@.service" ;;
"scripts/lvm2_tmpfiles_red_hat.conf") CONFIG_FILES="$CONFIG_FILES scripts/lvm2_tmpfiles_red_hat.conf" ;;
"scripts/lvmdump.sh") CONFIG_FILES="$CONFIG_FILES scripts/lvmdump.sh" ;;
"scripts/Makefile") CONFIG_FILES="$CONFIG_FILES scripts/Makefile" ;;
"test/Makefile") CONFIG_FILES="$CONFIG_FILES test/Makefile" ;;
"test/api/Makefile") CONFIG_FILES="$CONFIG_FILES test/api/Makefile" ;;

View File

@@ -37,8 +37,8 @@ case "$host_os" in
LDDEPS="$LDDEPS .export.sym"
LIB_SUFFIX=so
DEVMAPPER=yes
BUILD_LVMETAD=no
BUILD_LVMPOLLD=no
LVMETAD=no
LVMPOLLD=no
LOCKDSANLOCK=no
LOCKDDLM=no
ODIRECT=yes
@@ -103,7 +103,7 @@ AC_CHECK_HEADERS([assert.h ctype.h dirent.h errno.h fcntl.h float.h \
sys/time.h sys/types.h sys/utsname.h sys/wait.h time.h \
unistd.h], , [AC_MSG_ERROR(bailing out)])
AC_CHECK_HEADERS(termios.h sys/statvfs.h sys/timerfd.h linux/magic.h linux/fiemap.h)
AC_CHECK_HEADERS(termios.h sys/statvfs.h sys/timerfd.h)
case "$host_os" in
linux*)
@@ -134,7 +134,6 @@ AC_TYPE_UINT8_T
AC_TYPE_UINT16_T
AC_TYPE_UINT32_T
AC_TYPE_UINT64_T
AX_GCC_BUILTIN([__builtin_clz])
################################################################################
dnl -- Check for functions
@@ -1130,8 +1129,9 @@ AC_ARG_ENABLE(lvmetad,
AC_HELP_STRING([--enable-lvmetad],
[enable the LVM Metadata Daemon]),
LVMETAD=$enableval)
test -n "$LVMETAD" && BUILD_LVMETAD=$LVMETAD
AC_MSG_RESULT($BUILD_LVMETAD)
AC_MSG_RESULT($LVMETAD)
BUILD_LVMETAD=$LVMETAD
################################################################################
dnl -- Build lvmpolld
@@ -1140,8 +1140,9 @@ AC_ARG_ENABLE(lvmpolld,
AC_HELP_STRING([--enable-lvmpolld],
[enable the LVM Polling Daemon]),
LVMPOLLD=$enableval)
test -n "$LVMPOLLD" && BUILD_LVMPOLLD=$LVMPOLLD
AC_MSG_RESULT($BUILD_LVMPOLLD)
AC_MSG_RESULT($LVMPOLLD)
BUILD_LVMPOLLD=$LVMPOLLD
################################################################################
BUILD_LVMLOCKD=no
@@ -1158,7 +1159,7 @@ BUILD_LOCKDSANLOCK=$LOCKDSANLOCK
dnl -- Look for sanlock libraries
if test "$BUILD_LOCKDSANLOCK" = yes; then
PKG_CHECK_MODULES(LOCKD_SANLOCK, libsanlock_client >= 3.3.0, [HAVE_LOCKD_SANLOCK=yes], $bailout)
PKG_CHECK_MODULES(LOCKD_SANLOCK, libsanlock_client, [HAVE_LOCKD_SANLOCK=yes], $bailout)
AC_DEFINE([LOCKDSANLOCK_SUPPORT], 1, [Define to 1 to include code that uses lvmlockd sanlock option.])
BUILD_LVMLOCKD=yes
fi
@@ -1187,10 +1188,8 @@ AC_MSG_CHECKING(whether to build lvmlockd)
AC_MSG_RESULT($BUILD_LVMLOCKD)
if test "$BUILD_LVMLOCKD" = yes; then
AS_IF([test "$LVMPOLLD" = no], [AC_MSG_ERROR([cannot build lvmlockd with --disable-lvmpolld.])])
AS_IF([test "$LVMETAD" = no], [AC_MSG_ERROR([cannot build lvmlockd with --disable-lvmetad.])])
AS_IF([test "$BUILD_LVMPOLLD" = no], [BUILD_LVMPOLLD=yes; AC_MSG_WARN([Enabling lvmpolld - required by lvmlockd.])])
AS_IF([test "$BUILD_LVMETAD" = no], [BUILD_LVMETAD=yes; AC_MSG_WARN([Enabling lvmetad - required by lvmlockd.])])
AS_IF([test -n "$BUILD_LVMPOLLD"], [BUILD_LVMPOLLD=yes; AC_MSG_WARN([Enabling lvmpolld - required by lvmlockd.])])
AS_IF([test -n "$BUILD_LVMETAD"], [BUILD_LVMETAD=yes; AC_MSG_WARN([Enabling lvmetad - required by lvmlockd.])])
AC_MSG_CHECKING([defaults for use_lvmlockd])
AC_ARG_ENABLE(use_lvmlockd,
AC_HELP_STRING([--disable-use-lvmlockd],
@@ -1269,28 +1268,6 @@ fi
AC_DEFINE_UNQUOTED(DEFAULT_USE_LVMPOLLD, [$DEFAULT_USE_LVMPOLLD],
[Use lvmpolld by default.])
################################################################################
dnl -- Build notifydbus
AC_MSG_CHECKING(whether to build notifydbus)
AC_ARG_ENABLE(notify-dbus,
AC_HELP_STRING([--enable-notify-dbus],
[enable LVM notification using dbus]),
NOTIFYDBUS=$enableval)
AC_MSG_RESULT($NOTIFYDBUS)
BUILD_NOTIFYDBUS=$NOTIFYDBUS
if test "$BUILD_NOTIFYDBUS" = yes; then
AC_DEFINE([NOTIFYDBUS_SUPPORT], 1, [Define to 1 to include code that uses dbus notification.])
LIBS="-lsystemd $LIBS"
fi
################################################################################
dnl -- Look for dbus libraries
if test "$BUILD_NOTIFYDBUS" = yes; then
PKG_CHECK_MODULES(NOTIFY_DBUS, systemd >= 221, [HAVE_NOTIFY_DBUS=yes], $bailout)
fi
################################################################################
dnl -- Enable blkid wiping functionality
@@ -1934,12 +1911,8 @@ AC_DEFINE_UNQUOTED(DEFAULT_CACHE_SUBDIR, ["$DEFAULT_CACHE_SUBDIR"],
AC_ARG_WITH(default-locking-dir,
AC_HELP_STRING([--with-default-locking-dir=DIR],
[default locking directory [autodetect_lock_dir/lvm]]),
DEFAULT_LOCK_DIR=$withval,
[AC_MSG_CHECKING(for default lock directory)
DEFAULT_LOCK_DIR="$RUN_DIR/lock/lvm"
test -d "$RUN_DIR/lock" || DEFAULT_LOCK_DIR="/var/lock/lvm"
AC_MSG_RESULT($DEFAULT_LOCK_DIR)])
[default locking directory [/var/lock/lvm]]),
DEFAULT_LOCK_DIR=$withval, DEFAULT_LOCK_DIR="/var/lock/lvm")
AC_DEFINE_UNQUOTED(DEFAULT_LOCK_DIR, ["$DEFAULT_LOCK_DIR"],
[Name of default locking directory.])
@@ -1992,7 +1965,6 @@ AC_SUBST(BUILD_LVMPOLLD)
AC_SUBST(BUILD_LVMLOCKD)
AC_SUBST(BUILD_LOCKDSANLOCK)
AC_SUBST(BUILD_LOCKDDLM)
AC_SUBST(BUILD_NOTIFYDBUS)
AC_SUBST(CACHE)
AC_SUBST(CFLAGS)
AC_SUBST(CFLOW_CMD)
@@ -2069,7 +2041,6 @@ AC_SUBST(MIRRORS)
AC_SUBST(MSGFMT)
AC_SUBST(OCF)
AC_SUBST(OCFDIR)
AC_SUBST(ODIRECT)
AC_SUBST(PKGCONFIG)
AC_SUBST(POOL)
AC_SUBST(M_LIBS)
@@ -2215,7 +2186,6 @@ scripts/lvm2_monitoring_init_red_hat
scripts/lvm2_monitoring_systemd_red_hat.service
scripts/lvm2_pvscan_systemd_red_hat@.service
scripts/lvm2_tmpfiles_red_hat.conf
scripts/lvmdump.sh
scripts/Makefile
test/Makefile
test/api/Makefile

View File

@@ -41,11 +41,11 @@ ifeq ("@BUILD_LVMPOLLD@", "yes")
endif
ifeq ("@BUILD_LVMLOCKD@", "yes")
SUBDIRS += lvmlockd
SUBDIRS += lvmlockd
endif
ifeq ("@BUILD_LVMDBUSD@", "yes")
SUBDIRS += lvmdbusd
SUBDIRS += lvmdbusd
endif
ifeq ($(MAKECMDGOALS),distclean)

View File

@@ -50,7 +50,7 @@ struct clvm_header {
#define CLVMD_FLAG_REMOTE 8 /* Do this on all nodes except for the local node */
/* Name of the local socket to communicate between lvm and clvmd */
#define CLVMD_SOCKNAME DEFAULT_RUN_DIR "/clvmd.sock"
static const char CLVMD_SOCKNAME[]= DEFAULT_RUN_DIR "/clvmd.sock";
/* Internal commands & replies */
#define CLVMD_CMD_REPLY 1

View File

@@ -532,7 +532,6 @@ static int _cluster_fd_callback(struct local_client *fd, char *buf, int len,
static int _cluster_send_message(const void *buf, int msglen, const char *csid,
const char *errtext)
{
static pthread_mutex_t _mutex = PTHREAD_MUTEX_INITIALIZER;
struct iovec iov[2];
cs_error_t err;
int target_node;
@@ -547,10 +546,7 @@ static int _cluster_send_message(const void *buf, int msglen, const char *csid,
iov[1].iov_base = (char *)buf;
iov[1].iov_len = msglen;
pthread_mutex_lock(&_mutex);
err = cpg_mcast_joined(cpg_handle, CPG_TYPE_AGREED, iov, 2);
pthread_mutex_unlock(&_mutex);
return cs_to_errno(err);
}

View File

@@ -1440,7 +1440,7 @@ static void cpg_leave_callback(struct clog_cpg *match,
free(rq);
}
}
for (i = 0, j = 0; (int) i < match->checkpoints_needed; i++, j++) {
for (i = 0, j = 0; i < match->checkpoints_needed; i++, j++) {
match->checkpoint_requesters[j] = match->checkpoint_requesters[i];
if (match->checkpoint_requesters[i] == left->nodeid) {
LOG_ERROR("[%s] Removing pending ckpt from needed list (%u is leaving)",

View File

@@ -12,7 +12,6 @@
#include "logging.h"
#include "functions.h"
#include <sys/sysmacros.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
@@ -574,12 +573,6 @@ static int clog_ctr(struct dm_ulog_request *rq)
for (argc = 0, p = rq->data; (p = strstr(p, " ")); p++, argc++)
*p = '\0';
if (!argc) {
LOG_ERROR("Received constructor request with bad data %s",
rq->data);
return -EINVAL;
}
argv = malloc(argc * sizeof(char *));
if (!argv)
return -ENOMEM;

View File

@@ -99,28 +99,13 @@ static time_t _idle_since = 0;
static char **_initial_registrations = 0;
/* FIXME Make configurable at runtime */
/* All libdm messages */
__attribute__((format(printf, 5, 6)))
static void _libdm_log(int level, const char *file, int line,
int dm_errno_or_class, const char *format, ...)
{
va_list ap;
va_start(ap, format);
dm_event_log("#dm", level, file, line, dm_errno_or_class, format, ap);
va_end(ap);
}
/* All dmeventd messages */
#undef LOG_MESG
#define LOG_MESG(l, f, ln, e, x...) _dmeventd_log(l, f, ln, e, ## x)
__attribute__((format(printf, 5, 6)))
__attribute__((format(printf, 4, 5)))
static void _dmeventd_log(int level, const char *file, int line,
int dm_errno_or_class, const char *format, ...)
const char *format, ...)
{
va_list ap;
va_start(ap, format);
dm_event_log("dmeventd", level, file, line, dm_errno_or_class, format, ap);
dm_event_log("dm", level, file, line, 0, format, ap);
va_end(ap);
}
@@ -844,6 +829,17 @@ static void _print_sigset(const char *prefix, const sigset_t *sigset)
}
#endif
static sigset_t _unblock_sigalrm(void)
{
sigset_t set, old;
sigemptyset(&set);
sigaddset(&set, SIGALRM);
pthread_sigmask(SIG_UNBLOCK, &set, &old);
return old;
}
enum {
DM_WAIT_RETRY,
DM_WAIT_INTR,
@@ -853,7 +849,7 @@ enum {
/* Wait on a device until an event occurs. */
static int _event_wait(struct thread_status *thread)
{
sigset_t set, old;
sigset_t set;
int ret = DM_WAIT_RETRY;
struct dm_info info;
@@ -863,12 +859,7 @@ static int _event_wait(struct thread_status *thread)
* This is so that you can break out of waiting on an event,
* either for a timeout event, or to cancel the thread.
*/
sigemptyset(&set);
sigaddset(&set, SIGALRM);
if (pthread_sigmask(SIG_UNBLOCK, &set, &old) != 0) {
log_sys_error("pthread_sigmask", "unblock alarm");
return ret; /* What better */
}
set = _unblock_sigalrm();
if (dm_task_run(thread->wait_task)) {
thread->current_events |= DM_EVENT_DEVICE_ERROR;
@@ -892,11 +883,10 @@ static int _event_wait(struct thread_status *thread)
}
}
if (pthread_sigmask(SIG_SETMASK, &old, NULL) != 0)
log_sys_error("pthread_sigmask", "block alarm");
pthread_sigmask(SIG_SETMASK, &set, NULL);
#ifdef DEBUG_SIGNALS
_print_sigset("dmeventd blocking ", &old);
_print_sigset("dmeventd blocking ", &set);
#endif
DEBUGLOG("Completed waitevent task for %s.", thread->device.name);
@@ -2206,7 +2196,7 @@ int main(int argc, char *argv[])
openlog("dmeventd", LOG_PID, LOG_DAEMON);
dm_event_log_set(_debug_level, _use_syslog);
dm_log_with_errno_init(_libdm_log);
dm_log_init(_dmeventd_log);
(void) dm_prepare_selinux_context(DMEVENTD_PIDFILE, S_IFREG);
if (dm_create_lockfile(DMEVENTD_PIDFILE) == 0)

View File

@@ -855,9 +855,9 @@ int dm_event_get_version(struct dm_event_fifos *fifos, int *version) {
return 1;
}
void dm_event_log_set(int debug_log_level, int use_syslog)
void dm_event_log_set(int debug_level, int use_syslog)
{
_debug_level = debug_log_level;
_debug_level = debug_level;
_use_syslog = use_syslog;
}
@@ -865,38 +865,28 @@ void dm_event_log(const char *subsys, int level, const char *file,
int line, int dm_errno_or_class,
const char *format, va_list ap)
{
static int _abort_on_internal_errors = -1;
static pthread_mutex_t _log_mutex = PTHREAD_MUTEX_INITIALIZER;
static time_t start = 0;
const char *indent = "";
FILE *stream = log_stderr(level) ? stderr : stdout;
FILE *stream = stdout;
int prio;
time_t now;
int log_with_debug = 0;
if (subsys[0] == '#') {
/* Subsystems starting with '#' are logged
* only when debugging is enabled. */
log_with_debug++;
subsys++;
}
switch (log_level(level)) {
switch (level & ~(_LOG_STDERR | _LOG_ONCE)) {
case _LOG_DEBUG:
/* Never shown without -ddd */
if (_debug_level < 3)
return;
prio = LOG_DEBUG;
indent = " ";
break;
case _LOG_INFO:
if (log_with_debug && _debug_level < 2)
if (_debug_level < 2)
return;
prio = LOG_INFO;
indent = " ";
break;
case _LOG_NOTICE:
if (log_with_debug && _debug_level < 1)
if (_debug_level < 1)
return;
prio = LOG_NOTICE;
indent = " ";
@@ -922,13 +912,12 @@ void dm_event_log(const char *subsys, int level, const char *file,
if (!start)
start = now;
now -= start;
if (_debug_level)
fprintf(stream, "[%2d:%02d] %8x:%-6s%s",
(int)now / 60, (int)now % 60,
// TODO: Maybe use shorter ID
// ((int)(pthread_self()) >> 6) & 0xffff,
(int)pthread_self(), subsys,
(_debug_level > 3) ? "" : indent);
fprintf(stream, "[%2d:%02d] %8x:%-6s%s",
(int)now / 60, (int)now % 60,
// TODO: Maybe use shorter ID
// ((int)(pthread_self()) >> 6) & 0xffff,
(int)pthread_self(), subsys,
(_debug_level > 3) ? "" : indent);
if (_debug_level > 3)
fprintf(stream, "%28s:%4d %s", file, line, indent);
vfprintf(stream, _(format), ap);
@@ -937,15 +926,6 @@ void dm_event_log(const char *subsys, int level, const char *file,
}
pthread_mutex_unlock(&_log_mutex);
if (_abort_on_internal_errors < 0)
/* Set when env DM_ABORT_ON_INTERNAL_ERRORS is not "0" */
_abort_on_internal_errors =
strcmp(getenv("DM_ABORT_ON_INTERNAL_ERRORS") ? : "0", "0");
if (_abort_on_internal_errors &&
!strncmp(format, INTERNAL_ERROR, sizeof(INTERNAL_ERROR) - 1))
abort();
}
#if 0 /* left out for now */

View File

@@ -106,7 +106,7 @@ int dm_event_register_handler(const struct dm_event_handler *dmevh);
int dm_event_unregister_handler(const struct dm_event_handler *dmevh);
/* Set debug level for logging, and whether to log on stdout/stderr or syslog */
void dm_event_log_set(int debug_log_level, int use_syslog);
void dm_event_log_set(int debug_level, int use_syslog);
/* Log messages acroding to current debug level */
__attribute__((format(printf, 6, 0)))

View File

@@ -32,7 +32,7 @@ static int _register_count = 0;
static struct dm_pool *_mem_pool = NULL;
static void *_lvm_handle = NULL;
DM_EVENT_LOG_FN("#lvm")
DM_EVENT_LOG_FN("lvm")
static void _lvm2_print_log(int level, const char *file, int line,
int dm_errno_or_class, const char *msg)
@@ -121,7 +121,6 @@ int dmeventd_lvm2_run(const char *cmdline)
int dmeventd_lvm2_command(struct dm_pool *mem, char *buffer, size_t size,
const char *cmd, const char *device)
{
static char _internal_prefix[] = "_dmeventd_";
char *vg = NULL, *lv = NULL, *layer;
int r;
@@ -136,21 +135,6 @@ int dmeventd_lvm2_command(struct dm_pool *mem, char *buffer, size_t size,
(layer = strstr(lv, "_mlog")))
*layer = '\0';
if (!strncmp(cmd, _internal_prefix, sizeof(_internal_prefix) - 1)) {
dmeventd_lvm2_lock();
/* output of internal command passed via env var */
if (!dmeventd_lvm2_run(cmd))
cmd = NULL;
else if ((cmd = getenv(cmd)))
cmd = dm_pool_strdup(mem, cmd); /* copy with lock */
dmeventd_lvm2_unlock();
if (!cmd) {
log_error("Unable to find configured command.");
return 0;
}
}
r = dm_snprintf(buffer, size, "%s %s/%s", cmd, vg, lv);
dm_pool_free(mem, vg);

View File

@@ -15,7 +15,7 @@
#include "lib.h"
#include "libdevmapper-event.h"
#include "dmeventd_lvm.h"
#include "activate.h" /* For TARGET_NAME* */
#include "defaults.h"
/* FIXME Reformat to 80 char lines. */
@@ -73,10 +73,8 @@ static int _get_mirror_event(struct dso_state *state, char *params)
unsigned i;
struct dm_status_mirror *ms;
if (!dm_get_status_mirror(state->mem, params, &ms)) {
log_error("Unable to parse mirror status string.");
return ME_IGNORE;
}
if (!dm_get_status_mirror(state->mem, params, &ms))
goto_out;
/* Check for bad mirror devices */
for (i = 0; i < ms->dev_count; ++i)
@@ -97,23 +95,27 @@ static int _get_mirror_event(struct dso_state *state, char *params)
dm_pool_free(state->mem, ms);
return r;
out:
log_error("Unable to parse mirror status string.");
return ME_IGNORE;
}
static int _remove_failed_devices(const char *cmd_lvscan, const char *cmd_lvconvert,
const char *device)
static int _remove_failed_devices(const char *cmd_lvscan, const char *cmd_lvconvert)
{
int r;
if (!dmeventd_lvm2_run_with_lock(cmd_lvscan))
log_warn("WARNING: Re-scan of mirrored device %s failed.", device);
log_info("Re-scan of mirrored device failed.");
/* if repair goes OK, report success even if lvscan has failed */
if (!dmeventd_lvm2_run_with_lock(cmd_lvconvert)) {
log_error("Repair of mirrored device %s failed.", device);
return 0;
}
r = dmeventd_lvm2_run_with_lock(cmd_lvconvert);
log_info("Repair of mirrored device %s finished successfully.", device);
log_info("Repair of mirrored device %s.",
(r) ? "finished successfully" : "failed");
return 1;
return r;
}
void process_event(struct dm_task *dmt,
@@ -136,7 +138,7 @@ void process_event(struct dm_task *dmt,
continue;
}
if (strcmp(target_type, TARGET_NAME_MIRROR)) {
if (strcmp(target_type, "mirror")) {
log_info("%s has unmirrored portion.", device);
continue;
}
@@ -152,8 +154,7 @@ void process_event(struct dm_task *dmt,
case ME_FAILURE:
log_error("Device failure in %s.", device);
if (!_remove_failed_devices(state->cmd_lvscan,
state->cmd_lvconvert,
device))
state->cmd_lvconvert))
/* FIXME Why are all the error return codes unused? Get rid of them? */
log_error("Failed to remove faulty devices in %s.",
device);
@@ -167,7 +168,7 @@ void process_event(struct dm_task *dmt,
break;
default:
/* FIXME Provide value then! */
log_warn("WARNING: %s received unknown event.", device);
log_info("Unknown event received.");
}
} while (next);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2005-2016 Red Hat, Inc. All rights reserved.
* Copyright (C) 2005-2015 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
@@ -13,20 +13,14 @@
*/
#include "lib.h"
#include "defaults.h"
#include "dmeventd_lvm.h"
#include "libdevmapper-event.h"
/* Hold enough elements for the mximum number of RAID images */
#define RAID_DEVS_ELEMS ((DEFAULT_RAID_MAX_IMAGES + 63) / 64)
struct dso_state {
struct dm_pool *mem;
char cmd_lvscan[512];
char cmd_lvconvert[512];
uint64_t raid_devs[RAID_DEVS_ELEMS];
int failed;
int warned;
};
DM_EVENT_LOG_FN("raid")
@@ -37,50 +31,29 @@ static int _process_raid_event(struct dso_state *state, char *params, const char
{
struct dm_status_raid *status;
const char *d;
int dead = 0, r = 1;
uint32_t dev;
if (!dm_get_status_raid(state->mem, params, &status)) {
log_error("Failed to process status line for %s.", device);
return 0;
}
d = status->dev_health;
while ((d = strchr(d, 'D'))) {
dev = (uint32_t)(d - status->dev_health);
if (!(state->raid_devs[dev / 64] & (UINT64_C(1) << (dev % 64)))) {
state->raid_devs[dev / 64] |= (UINT64_C(1) << (dev % 64));
log_warn("WARNING: Device #%u of %s array, %s, has failed.",
dev, status->raid_type, device);
}
d++;
dead = 1;
}
if (dead) {
if (status->insync_regions < status->total_regions) {
if (!state->warned) {
state->warned = 1;
log_warn("WARNING: waiting for resynchronization to finish "
"before initiating repair on RAID device %s.", device);
}
goto out; /* Not yet done syncing with accessible devices */
}
if ((d = strchr(status->dev_health, 'D'))) {
if (state->failed)
goto out; /* already reported */
log_error("Device #%d of %s array, %s, has failed.",
(int)(d - status->dev_health),
status->raid_type, device);
state->failed = 1;
if (!dmeventd_lvm2_run_with_lock(state->cmd_lvscan))
log_warn("WARNING: Re-scan of RAID device %s failed.", device);
/* if repair goes OK, report success even if lvscan has failed */
if (!dmeventd_lvm2_run_with_lock(state->cmd_lvconvert)) {
log_error("Repair of RAID device %s failed.", device);
r = 0;
log_info("Repair of RAID device %s failed.", device);
dm_pool_free(state->mem, status);
return 0;
}
} else {
state->failed = 0;
@@ -91,7 +64,7 @@ static int _process_raid_event(struct dso_state *state, char *params, const char
out:
dm_pool_free(state->mem, status);
return r;
return 1;
}
void process_event(struct dm_task *dmt,

View File

@@ -16,7 +16,6 @@
#include "dmeventd_lvm.h"
#include "libdevmapper-event.h"
#include <sys/sysmacros.h>
#include <sys/wait.h>
#include <stdarg.h>
#include <pthread.h>
@@ -149,8 +148,8 @@ static void _umount(const char *device, int major, int minor)
continue; /* can't stat, skip this one */
if (S_ISBLK(st.st_mode) &&
(int) major(st.st_rdev) == major &&
(int) minor(st.st_rdev) == minor) {
major(st.st_rdev) == major &&
minor(st.st_rdev) == minor) {
log_error("Unmounting invalid snapshot %s from %s.", device, words[1]);
if (!_run(UMOUNT_COMMAND, "-fl", words[1], NULL))
log_error("Failed to umount snapshot %s from %s: %s.",

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2011-2017 Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-2015 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
@@ -30,9 +30,6 @@
/* First warning when thin data or metadata is 80% full. */
#define WARNING_THRESH (DM_PERCENT_1 * 80)
/* Umount thin LVs when thin data or metadata LV is >=
* and lvextend --use-policies has failed. */
#define UMOUNT_THRESH (DM_PERCENT_1 * 95)
/* Run a check every 5%. */
#define CHECK_STEP (DM_PERCENT_1 * 5)
/* Do not bother checking thin data or metadata is less than 50% full. */
@@ -40,123 +37,221 @@
#define UMOUNT_COMMAND "/bin/umount"
#define MAX_FAILS (256) /* ~42 mins between cmd call retry with 10s delay */
#define MAX_FAILS (10)
#define THIN_DEBUG 0
struct dso_state {
struct dm_pool *mem;
int metadata_percent_check;
int metadata_percent;
int metadata_warn_once;
int data_percent_check;
int data_percent;
int data_warn_once;
uint64_t known_metadata_size;
uint64_t known_data_size;
unsigned fails;
unsigned max_fails;
int restore_sigset;
sigset_t old_sigset;
pid_t pid;
char **argv;
char cmd_str[1024];
};
DM_EVENT_LOG_FN("thin")
#define UUID_PREFIX "LVM-"
static int _run_command(struct dso_state *state)
/* Get dependencies for device, and try to find matching device */
static int _has_deps(const char *name, int tp_major, int tp_minor, int *dev_minor)
{
char val[3][36];
char *env[] = { val[0], val[1], val[2], NULL };
int i;
struct dm_task *dmt;
const struct dm_deps *deps;
struct dm_info info;
int major, minor;
int r = 0;
/* Mark for possible lvm2 command we are running from dmeventd
* lvm2 will not try to talk back to dmeventd while processing it */
(void) dm_snprintf(val[0], sizeof(val[0]), "LVM_RUN_BY_DMEVENTD=1");
if (!(dmt = dm_task_create(DM_DEVICE_DEPS)))
return 0;
if (state->data_percent) {
/* Prepare some known data to env vars for easy use */
(void) dm_snprintf(val[1], sizeof(val[1]), "DMEVENTD_THIN_POOL_DATA=%d",
state->data_percent / DM_PERCENT_1);
(void) dm_snprintf(val[2], sizeof(val[2]), "DMEVENTD_THIN_POOL_METADATA=%d",
state->metadata_percent / DM_PERCENT_1);
} else {
/* For an error event it's for a user to check status and decide */
env[1] = NULL;
log_debug("Error event processing");
if (!dm_task_set_name(dmt, name))
goto out;
if (!dm_task_no_open_count(dmt))
goto out;
if (!dm_task_run(dmt))
goto out;
if (!dm_task_get_info(dmt, &info))
goto out;
if (!(deps = dm_task_get_deps(dmt)))
goto out;
if (!info.exists || deps->count != 1)
goto out;
major = (int) MAJOR(deps->device[0]);
minor = (int) MINOR(deps->device[0]);
if ((major != tp_major) || (minor != tp_minor))
goto out;
*dev_minor = info.minor;
#if THIN_DEBUG
{
char dev_name[PATH_MAX];
if (dm_device_get_name(major, minor, 0, dev_name, sizeof(dev_name)))
log_debug("Found %s (%u:%u) depends on %s.",
name, major, *dev_minor, dev_name);
}
#endif
r = 1;
out:
dm_task_destroy(dmt);
return r;
}
/* Get all active devices */
static int _find_all_devs(dm_bitset_t bs, int tp_major, int tp_minor)
{
struct dm_task *dmt;
struct dm_names *names;
unsigned next = 0;
int minor, r = 1;
if (!(dmt = dm_task_create(DM_DEVICE_LIST)))
return 0;
if (!dm_task_run(dmt)) {
r = 0;
goto out;
}
log_verbose("Executing command: %s", state->cmd_str);
if (!(names = dm_task_get_names(dmt))) {
r = 0;
goto out;
}
/* TODO:
* Support parallel run of 'task' and it's waitpid maintainence
* ATM we can't handle signaling of SIGALRM
* as signalling is not allowed while 'process_event()' is running
*/
if (!(state->pid = fork())) {
/* child */
(void) close(0);
for (i = 3; i < 255; ++i) (void) close(i);
execve(state->argv[0], state->argv, env);
_exit(errno);
} else if (state->pid == -1) {
log_error("Can't fork command %s.", state->cmd_str);
state->fails = 1;
return 0;
if (!names->dev)
goto out;
do {
names = (struct dm_names *)((char *) names + next);
if (_has_deps(names->name, tp_major, tp_minor, &minor))
dm_bit_set(bs, minor);
next = names->next;
} while (next);
out:
dm_task_destroy(dmt);
return r;
}
static int _run(const char *cmd, ...)
{
va_list ap;
int argc = 1; /* for argv[0], i.e. cmd */
int i = 0;
const char **argv;
pid_t pid = fork();
int status;
if (pid == 0) { /* child */
va_start(ap, cmd);
while (va_arg(ap, const char *))
++argc;
va_end(ap);
/* + 1 for the terminating NULL */
argv = alloca(sizeof(const char *) * (argc + 1));
argv[0] = cmd;
va_start(ap, cmd);
while ((argv[++i] = va_arg(ap, const char *)));
va_end(ap);
execvp(cmd, (char **)argv);
log_sys_error("exec", cmd);
exit(127);
}
if (pid > 0) { /* parent */
if (waitpid(pid, &status, 0) != pid)
return 0; /* waitpid failed */
if (!WIFEXITED(status) || WEXITSTATUS(status))
return 0; /* the child failed */
}
if (pid < 0)
return 0; /* fork failed */
return 1; /* all good */
}
struct mountinfo_s {
const char *device;
struct dm_info info;
dm_bitset_t minors; /* Bitset for active thin pool minors */
};
static int _umount_device(char *buffer, unsigned major, unsigned minor,
char *target, void *cb_data)
{
struct mountinfo_s *data = cb_data;
if ((major == data->info.major) && dm_bit(data->minors, minor)) {
log_info("Unmounting thin volume %s from %s.",
data->device, target);
if (!_run(UMOUNT_COMMAND, "-fl", target, NULL))
log_error("Failed to umount thin %s from %s: %s.",
data->device, target, strerror(errno));
}
return 1;
}
static int _use_policy(struct dm_task *dmt, struct dso_state *state)
/*
* Find all thin pool users and try to umount them.
* TODO: work with read-only thin pool support
*/
static void _umount(struct dm_task *dmt)
{
/* TODO: Convert to use hash to reduce memory usage */
static const size_t MINORS = (1U << 20); /* 20 bit */
struct mountinfo_s data = { NULL };
if (!dm_task_get_info(dmt, &data.info))
return;
data.device = dm_task_get_name(dmt);
if (!(data.minors = dm_bitset_create(NULL, MINORS))) {
log_error("Failed to allocate bitset. Not unmounting %s.", data.device);
goto out;
}
if (!_find_all_devs(data.minors, data.info.major, data.info.minor)) {
log_error("Failed to detect mounted volumes for %s.", data.device);
goto out;
}
if (!dm_mountinfo_read(_umount_device, &data)) {
log_error("Could not parse mountinfo file.");
goto out;
}
out:
if (data.minors)
dm_bitset_destroy(data.minors);
}
static void _use_policy(struct dm_task *dmt, struct dso_state *state)
{
#if THIN_DEBUG
log_debug("dmeventd executes: %s.", state->cmd_str);
log_info("dmeventd executes: %s.", state->cmd_str);
#endif
if (state->argv)
return _run_command(state);
if (!dmeventd_lvm2_run_with_lock(state->cmd_str)) {
log_error("Failed command for %s.", dm_task_get_name(dmt));
state->fails = 1;
return 0;
}
state->fails = 0;
return 1;
}
/* Check if executed command has finished
* Only 1 command may run */
static int _wait_for_pid(struct dso_state *state)
{
int status = 0;
if (state->pid == -1)
return 1;
if (!waitpid(state->pid, &status, WNOHANG))
return 0;
/* Wait for finish */
if (WIFEXITED(status)) {
log_verbose("Child %d exited with status %d.",
state->pid, WEXITSTATUS(status));
state->fails = WEXITSTATUS(status) ? 1 : 0;
} else {
if (WIFSIGNALED(status))
log_verbose("Child %d was terminated with status %d.",
state->pid, WTERMSIG(status));
state->fails = 1;
}
state->pid = -1;
return 1;
log_error("Failed to extend thin pool %s.",
dm_task_get_name(dmt));
_umount(dmt);
state->fails++;
} else
state->fails = 0;
}
void process_event(struct dm_task *dmt,
@@ -164,6 +259,7 @@ void process_event(struct dm_task *dmt,
void **user)
{
const char *device = dm_task_get_name(dmt);
int percent;
struct dso_state *state = *user;
struct dm_status_thin_pool *tps = NULL;
void *next = NULL;
@@ -171,48 +267,16 @@ void process_event(struct dm_task *dmt,
char *target_type = NULL;
char *params;
int needs_policy = 0;
struct dm_task *new_dmt = NULL;
#if THIN_DEBUG
log_debug("Watch for tp-data:%.2f%% tp-metadata:%.2f%%.",
dm_percent_to_float(state->data_percent_check),
dm_percent_to_float(state->metadata_percent_check));
#endif
if (!_wait_for_pid(state)) {
log_warn("WARNING: Skipping event, child %d is still running (%s).",
state->pid, state->cmd_str);
#if 0
/* No longer monitoring, waiting for remove */
if (!state->meta_percent_check && !state->data_percent_check)
return;
}
#endif
if (event & DM_EVENT_DEVICE_ERROR) {
/* Error -> no need to check and do instant resize */
state->data_percent = state->metadata_percent = 0;
if (_use_policy(dmt, state))
goto out;
stack;
/*
* Rather update oldish status
* since after 'command' processing
* percentage info could have changed a lot.
* If we would get above UMOUNT_THRESH
* we would wait for next sigalarm.
*/
if (!(new_dmt = dm_task_create(DM_DEVICE_STATUS)))
goto_out;
if (!dm_task_set_uuid(new_dmt, dm_task_get_uuid(dmt)))
goto_out;
/* Non-blocking status read */
if (!dm_task_no_flush(new_dmt))
log_warn("WARNING: Can't set no_flush for dm status.");
if (!dm_task_run(new_dmt))
goto_out;
dmt = new_dmt;
_use_policy(dmt, state);
goto out;
}
dm_get_next_target(dmt, next, &start, &length, &target_type, &params);
@@ -224,6 +288,7 @@ void process_event(struct dm_task *dmt,
if (!dm_get_status_thin_pool(state->mem, params, &tps)) {
log_error("Failed to parse status.");
_umount(dmt);
goto out;
}
@@ -238,68 +303,41 @@ void process_event(struct dm_task *dmt,
if (state->known_metadata_size != tps->total_metadata_blocks) {
state->metadata_percent_check = CHECK_MINIMUM;
state->known_metadata_size = tps->total_metadata_blocks;
state->fails = 0;
}
if (state->known_data_size != tps->total_data_blocks) {
state->data_percent_check = CHECK_MINIMUM;
state->known_data_size = tps->total_data_blocks;
state->fails = 0;
}
/*
* Trigger action when threshold boundary is exceeded.
* Report 80% threshold warning when it's used above 80%.
* Only 100% is exception as it cannot be surpased so policy
* action is called for: >50%, >55% ... >95%, 100%
*/
state->metadata_percent = dm_make_percent(tps->used_metadata_blocks, tps->total_metadata_blocks);
if (state->metadata_percent <= WARNING_THRESH)
state->metadata_warn_once = 0; /* Dropped bellow threshold, reset warn once */
else if (!state->metadata_warn_once++) /* Warn once when raised above threshold */
log_warn("WARNING: Thin pool %s metadata is now %.2f%% full.",
device, dm_percent_to_float(state->metadata_percent));
if (state->metadata_percent > CHECK_MINIMUM) {
/* Run action when usage raised more than CHECK_STEP since the last time */
if (state->metadata_percent > state->metadata_percent_check)
needs_policy = 1;
state->metadata_percent_check = (state->metadata_percent / CHECK_STEP + 1) * CHECK_STEP;
if (state->metadata_percent_check == DM_PERCENT_100)
state->metadata_percent_check--; /* Can't get bigger then 100% */
} else
state->metadata_percent_check = CHECK_MINIMUM;
percent = dm_make_percent(tps->used_metadata_blocks, tps->total_metadata_blocks);
if (percent >= state->metadata_percent_check) {
/*
* Usage has raised more than CHECK_STEP since the last
* time. Run actions.
*/
state->metadata_percent_check = (percent / CHECK_STEP) * CHECK_STEP + CHECK_STEP;
state->data_percent = dm_make_percent(tps->used_data_blocks, tps->total_data_blocks);
if (state->data_percent <= WARNING_THRESH)
state->data_warn_once = 0;
else if (!state->data_warn_once++)
log_warn("WARNING: Thin pool %s data is now %.2f%% full.",
device, dm_percent_to_float(state->data_percent));
if (state->data_percent > CHECK_MINIMUM) {
/* Run action when usage raised more than CHECK_STEP since the last time */
if (state->data_percent > state->data_percent_check)
needs_policy = 1;
state->data_percent_check = (state->data_percent / CHECK_STEP + 1) * CHECK_STEP;
if (state->data_percent_check == DM_PERCENT_100)
state->data_percent_check--; /* Can't get bigger then 100% */
} else
state->data_percent_check = CHECK_MINIMUM;
/* FIXME: extension of metadata needs to be written! */
if (percent >= WARNING_THRESH) /* Print a warning to syslog. */
log_warn("WARNING: Thin pool %s metadata is now %.2f%% full.",
device, dm_percent_to_float(percent));
needs_policy = 1;
}
/* Reduce number of _use_policy() calls by power-of-2 factor till frequency of MAX_FAILS is reached.
* Avoids too high number of error retries, yet shows some status messages in log regularly.
* i.e. PV could have been pvmoved and VG/LV was locked for a while...
*/
if (state->fails) {
if (state->fails++ <= state->max_fails) {
log_debug("Postponing frequently failing policy (%u <= %u).",
state->fails - 1, state->max_fails);
return;
}
if (state->max_fails < MAX_FAILS)
state->max_fails <<= 1;
state->fails = needs_policy = 1; /* Retry failing command */
} else
state->max_fails = 1; /* Reset on success */
percent = dm_make_percent(tps->used_data_blocks, tps->total_data_blocks);
if (percent >= state->data_percent_check) {
/*
* Usage has raised more than CHECK_STEP since
* the last time. Run actions.
*/
state->data_percent_check = (percent / CHECK_STEP) * CHECK_STEP + CHECK_STEP;
if (percent >= WARNING_THRESH) /* Print a warning to syslog. */
log_warn("WARNING: Thin pool %s data is now %.2f%% full.",
device, dm_percent_to_float(percent));
needs_policy = 1;
}
if (needs_policy)
_use_policy(dmt, state);
@@ -307,43 +345,12 @@ out:
if (tps)
dm_pool_free(state->mem, tps);
if (new_dmt)
dm_task_destroy(new_dmt);
}
/* Handle SIGCHLD for a thread */
static void _sig_child(int signum __attribute__((unused)))
{
/* empty SIG_IGN */;
}
/* Setup handler for SIGCHLD when executing external command
* to get quick 'waitpid()' reaction
* It will interrupt syscall just like SIGALRM and
* invoke process_event().
*/
static void _init_thread_signals(struct dso_state *state)
{
struct sigaction act = { .sa_handler = _sig_child };
sigset_t my_sigset;
sigemptyset(&my_sigset);
if (sigaction(SIGCHLD, &act, NULL))
log_warn("WARNING: Failed to set SIGCHLD action.");
else if (sigaddset(&my_sigset, SIGCHLD))
log_warn("WARNING: Failed to add SIGCHLD to set.");
else if (pthread_sigmask(SIG_UNBLOCK, &my_sigset, &state->old_sigset))
log_warn("WARNING: Failed to unblock SIGCHLD.");
else
state->restore_sigset = 1;
}
static void _restore_thread_signals(struct dso_state *state)
{
if (state->restore_sigset &&
pthread_sigmask(SIG_SETMASK, &state->old_sigset, NULL))
log_warn("WARNING: Failed to block SIGCHLD.");
if (state->fails >= MAX_FAILS) {
log_warn("WARNING: Dropping monitoring of %s. "
"lvm2 command fails too often (%u times in raw).",
device, state->fails);
pthread_kill(pthread_self(), SIGALRM);
}
}
int register_device(const char *device,
@@ -353,43 +360,27 @@ int register_device(const char *device,
void **user)
{
struct dso_state *state;
int maxcmd;
char *str;
if (!dmeventd_lvm2_init_with_pool("thin_pool_state", state))
goto_bad;
if (!dmeventd_lvm2_command(state->mem, state->cmd_str,
sizeof(state->cmd_str),
"_dmeventd_thin_command", device)) {
"lvextend --use-policies",
device)) {
dmeventd_lvm2_exit_with_pool(state);
goto_bad;
}
if (strncmp(state->cmd_str, "lvm ", 4)) {
maxcmd = 2; /* space for last NULL element */
for (str = state->cmd_str; *str; str++)
if (*str == ' ')
maxcmd++;
if (!(str = dm_pool_strdup(state->mem, state->cmd_str)) ||
!(state->argv = dm_pool_zalloc(state->mem, maxcmd * sizeof(char *)))) {
log_error("Failed to allocate memory for command.");
goto bad;
}
dm_split_words(str, maxcmd - 1, 0, state->argv);
_init_thread_signals(state);
} else
memmove(state->cmd_str, state->cmd_str + 4, strlen(state->cmd_str + 4) + 1);
state->pid = -1;
state->metadata_percent_check = CHECK_MINIMUM;
state->data_percent_check = CHECK_MINIMUM;
*user = state;
log_info("Monitoring thin pool %s.", device);
log_info("Monitoring thin %s.", device);
return 1;
bad:
log_error("Failed to monitor thin pool %s.", device);
log_error("Failed to monitor thin %s.", device);
return 0;
}
@@ -401,31 +392,9 @@ int unregister_device(const char *device,
void **user)
{
struct dso_state *state = *user;
int i;
for (i = 0; !_wait_for_pid(state) && (i < 6); ++i) {
if (i == 0)
/* Give it 2 seconds, then try to terminate & kill it */
log_verbose("Child %d still not finished (%s) waiting.",
state->pid, state->cmd_str);
else if (i == 3) {
log_warn("WARNING: Terminating child %d.", state->pid);
kill(state->pid, SIGINT);
kill(state->pid, SIGTERM);
} else if (i == 5) {
log_warn("WARNING: Killing child %d.", state->pid);
kill(state->pid, SIGKILL);
}
sleep(1);
}
if (state->pid != -1)
log_warn("WARNING: Cannot kill child %d!", state->pid);
_restore_thread_signals(state);
dmeventd_lvm2_exit_with_pool(state);
log_info("No longer monitoring thin pool %s.", device);
log_info("No longer monitoring thin %s.", device);
return 1;
}

View File

@@ -1 +0,0 @@
path.py

View File

@@ -33,6 +33,7 @@ LVMDBUS_SRCDIR_FILES = \
manager.py \
objectmanager.py \
pv.py \
refresh.py \
request.py \
state.py \
udevwatch.py \
@@ -56,11 +57,9 @@ install_lvmdbusd:
$(INSTALL_DATA) $(LVMDBUS_BUILDDIR_FILES) $(DESTDIR)$(lvmdbusdir)
PYTHON=$(PYTHON3) $(PYCOMPILE) --destdir "$(DESTDIR)" --basedir "$(lvmdbusdir)" $(LVMDBUS_SRCDIR_FILES) $(LVMDBUS_BUILDDIR_FILES)
$(CHMOD) 755 $(DESTDIR)$(lvmdbusdir)/__pycache__
$(CHMOD) 444 $(DESTDIR)$(lvmdbusdir)/__pycache__/*.py[co]
$(CHMOD) 444 $(DESTDIR)$(lvmdbusdir)/__pycache__/*.pyc $(DESTDIR)$(lvmdbusdir)/__pycache__/*.pyo
install_lvm2: install_lvmdbusd
install: install_lvm2
DISTCLEAN_TARGETS+= \
$(LVMDBUS_BUILDDIR_FILES)

View File

@@ -8,7 +8,6 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import dbus
import dbus.service
from . import cfg
from .utils import get_properties, add_properties, get_object_property_diff, \
log_debug
@@ -159,7 +158,10 @@ class AutomatedProperties(dbus.service.Object):
cfg.om.lookup_update(self, new_id[0], new_id[1])
# Grab the properties values, then replace the state of the object
# and retrieve the new values.
# and retrieve the new values
# TODO: We need to add locking to prevent concurrent access to the
# properties so that a client is not accessing while we are
# replacing.
o_prop = get_properties(self)
self.state = new_state
n_prop = get_properties(self)

View File

@@ -7,13 +7,18 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import threading
import subprocess
from . import cfg
import time
from .cmdhandler import options_to_cli_args
import dbus
from .utils import pv_range_append, pv_dest_ranges, log_error, log_debug
import os
import threading
from .job import Job, JobState
from .utils import pv_range_append, pv_dest_ranges
from .request import RequestEntry
_rlock = threading.RLock()
_thread_list = list()
def pv_move_lv_cmd(move_options, lv_full_name,
@@ -37,47 +42,40 @@ def lv_merge_cmd(merge_options, lv_full_name):
return cmd
def _move_merge(interface_name, command, job_state):
# We need to execute these command stand alone by forking & exec'ing
# the command always as we will be getting periodic output from them on
# the status of the long running operation.
command.insert(0, cfg.LVM_CMD)
process = subprocess.Popen(command, stdout=subprocess.PIPE,
env=os.environ,
stderr=subprocess.PIPE, close_fds=True)
def _create_background_dbus_job(job_state):
job_obj = Job(None, job_state)
cfg.om.register_object(job_obj)
return job_obj.dbus_object_path()
log_debug("Background process for %s is %d" %
(str(command), process.pid))
lines_iterator = iter(process.stdout.readline, b"")
for line in lines_iterator:
line_str = line.decode("utf-8")
def _move_merge(interface_name, cmd, time_out, skip_first_line=False):
# Create job object to be used while running the command
rc = '/'
job_state = JobState(None)
add(cmd, job_state, skip_first_line)
# Check to see if the line has the correct number of separators
try:
if line_str.count(':') == 2:
(device, ignore, percentage) = line_str.split(':')
job_state.Percent = round(
float(percentage.strip()[:-1]), 1)
except ValueError:
log_error("Trying to parse percentage which failed for %s" %
line_str)
out = process.communicate()
if process.returncode == 0:
job_state.Percent = 100
if time_out == -1:
# Waiting forever
done = job_state.Wait(time_out)
if not done:
ec, err_msg = job_state.GetError
raise dbus.exceptions.DBusException(
interface_name,
'Exit code %s, stderr = %s' % (str(ec), err_msg))
elif time_out == 0:
# Immediately create and return a job
rc = _create_background_dbus_job(job_state)
else:
raise dbus.exceptions.DBusException(
interface_name,
'Exit code %s, stderr = %s' % (str(process.returncode), out[1]))
# Willing to wait for a bit
done = job_state.Wait(time_out)
if not done:
rc = _create_background_dbus_job(job_state)
cfg.load()
return '/'
return rc
def move(interface_name, lv_name, pv_src_obj, pv_source_range,
pv_dests_and_ranges, move_options, job_state):
pv_dests_and_ranges, move_options, time_out):
"""
Common code for the pvmove handling.
:param interface_name: What dbus interface we are providing for
@@ -86,8 +84,8 @@ def move(interface_name, lv_name, pv_src_obj, pv_source_range,
:param pv_source_range: (0,0 to ignore, else start, end segments)
:param pv_dests_and_ranges: Array of PV object paths and start/end segs
:param move_options: Hash with optional arguments
:param job_state: Used to convey information about jobs between processes
:return: '/' When complete, the empty object path
:param time_out:
:return: Object path to job object
"""
pv_dests = []
pv_src = cfg.om.get_object_by_path(pv_src_obj)
@@ -105,38 +103,93 @@ def move(interface_name, lv_name, pv_src_obj, pv_source_range,
pv_dests.append((pv_dbus_obj.lvm_id, pr[1], pr[2]))
# Generate the command line for this command, but don't
# execute it.
cmd = pv_move_lv_cmd(move_options,
lv_name,
pv_src.lvm_id,
pv_source_range,
pv_dests)
return _move_merge(interface_name, cmd, job_state)
return _move_merge(interface_name, cmd, time_out)
else:
raise dbus.exceptions.DBusException(
interface_name, 'pv_src_obj (%s) not found' % pv_src_obj)
def merge(interface_name, lv_uuid, lv_name, merge_options, job_state):
def merge(interface_name, lv_uuid, lv_name, merge_options, time_out):
# Make sure we have a dbus object representing it
dbo = cfg.om.get_object_by_uuid_lvm_id(lv_uuid, lv_name)
if dbo:
cmd = lv_merge_cmd(merge_options, dbo.lvm_id)
return _move_merge(interface_name, cmd, job_state)
return _move_merge(interface_name, cmd, time_out, True)
else:
raise dbus.exceptions.DBusException(
interface_name,
'LV with uuid %s and name %s not present!' % (lv_uuid, lv_name))
def _run_cmd(req):
log_debug(
"_run_cmd: Running method: %s with args %s" %
(str(req.method), str(req.arguments)))
req.run_cmd()
log_debug("_run_cmd: complete!")
def background_reaper():
while cfg.run.value != 0:
with _rlock:
num_threads = len(_thread_list) - 1
if num_threads >= 0:
for i in range(num_threads, -1, -1):
_thread_list[i].join(0)
if not _thread_list[i].is_alive():
_thread_list.pop(i)
time.sleep(3)
def cmd_runner(request):
t = threading.Thread(target=_run_cmd, args=(request,))
def process_background_result(job_object, exit_code, error_msg):
cfg.load()
job_object.set_result(exit_code, error_msg)
return None
# noinspection PyUnusedLocal
def empty_cb(disregard):
pass
def background_execute(command, background_job, skip_first_line=False):
process = subprocess.Popen(command, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, close_fds=True)
lines_iterator = iter(process.stdout.readline, b"")
for line in lines_iterator:
# Merge ouputs a line before updates, move does not
if skip_first_line:
skip_first_line = False
continue
if len(line) > 10:
(device, ignore, percentage) = line.decode("utf-8").split(':')
background_job.Percent = round(float(percentage.strip()[:-1]), 1)
out = process.communicate()
# print "DEBUG: EC %d, STDOUT %s, STDERR %s" % \
# (process.returncode, out[0], out[1])
if process.returncode == 0:
background_job.Percent = 100
# Queue up the result so that it gets executed in same thread as others.
r = RequestEntry(
-1, process_background_result,
(background_job, process.returncode, out[1]),
empty_cb, empty_cb, False)
cfg.worker_q.put(r)
def add(command, reporting_job, skip_first_line=False):
# Create the thread, get it running and then add it to the list
t = threading.Thread(
target=background_execute,
name="thread: " + ' '.join(command),
args=(command, reporting_job, skip_first_line))
t.start()
with _rlock:
_thread_list.append(t)

View File

@@ -11,8 +11,10 @@ import os
import multiprocessing
import queue
import itertools
from lvmdbusd import path
try:
from . import path
except SystemError:
import path
LVM_CMD = os.getenv('LVM_BINARY', path.LVM_BINARY)
@@ -22,28 +24,24 @@ om = None
# This is the global bus connection
bus = None
# Command line args
args = None
# Set to true if we are depending on external events for updates
ee = False
# Shared state variable across all processes
run = multiprocessing.Value('i', 1)
# If this is set to true, the current setup support lvm shell and we are
# running in that mode of operation
SHELL_IN_USE = None
# Debug
DEBUG = True
# Use lvm shell
USE_SHELL = False
# Lock used by pprint
stdout_lock = multiprocessing.Lock()
kick_q = multiprocessing.Queue()
worker_q = queue.Queue()
# Main event loop
loop = None
BUS_NAME = os.getenv('LVM_DBUS_NAME', 'com.redhat.lvmdbus1')
BASE_INTERFACE = 'com.redhat.lvmdbus1'
PV_INTERFACE = BASE_INTERFACE + '.Pv'
VG_INTERFACE = BASE_INTERFACE + '.Vg'
@@ -77,10 +75,6 @@ hidden_lv = itertools.count()
# Used to prevent circular imports...
load = None
event = None
# Global cached state
db = None
# lvm flight recorder
blackbox = None

View File

@@ -11,18 +11,15 @@ from subprocess import Popen, PIPE
import time
import threading
from itertools import chain
import collections
import traceback
import os
from lvmdbusd import cfg
from lvmdbusd.utils import pv_dest_ranges, log_debug, log_error
from lvmdbusd.lvm_shell_proxy import LVMShellProxy
try:
import simplejson as json
except ImportError:
import json
from . import cfg
from .utils import pv_dest_ranges, log_debug, log_error
from .lvm_shell_proxy import LVMShellProxy
except SystemError:
import cfg
from utils import pv_dest_ranges, log_debug, log_error
from lvm_shell_proxy import LVMShellProxy
SEP = '{|}'
@@ -31,46 +28,11 @@ total_count = 0
# We need to prevent different threads from using the same lvm shell
# at the same time.
cmd_lock = threading.RLock()
cmd_lock = threading.Lock()
class LvmExecutionMeta(object):
def __init__(self, start, ended, cmd, ec, stdout_txt, stderr_txt):
self.start = start
self.ended = ended
self.cmd = cmd
self.ec = ec
self.stdout_txt = stdout_txt
self.stderr_txt = stderr_txt
def __str__(self):
return "EC= %d for %s\n" \
"STARTED: %f, ENDED: %f\n" \
"STDOUT=%s\n" \
"STDERR=%s\n" % \
(self.ec, str(self.cmd), self.start, self.ended, self.stdout_txt,
self.stderr_txt)
class LvmFlightRecorder(object):
def __init__(self, size=16):
self.queue = collections.deque(maxlen=size)
def add(self, lvm_exec_meta):
self.queue.append(lvm_exec_meta)
def dump(self):
with cmd_lock:
if len(self.queue):
log_error("LVM dbus flight recorder START")
for c in self.queue:
log_error(str(c))
log_error("LVM dbus flight recorder END")
cfg.blackbox = LvmFlightRecorder()
# The actual method which gets called to invoke the lvm command, can vary
# from forking a new process to using lvm shell
_t_call = None
def _debug_c(cmd, exit_code, out):
@@ -94,8 +56,7 @@ def call_lvm(command, debug=False):
# in different locations on the same box
command.insert(0, cfg.LVM_CMD)
process = Popen(command, stdout=PIPE, stderr=PIPE, close_fds=True,
env=os.environ)
process = Popen(command, stdout=PIPE, stderr=PIPE, close_fds=True)
out = process.communicate()
stdout_text = bytes(out[0]).decode("utf-8")
@@ -104,48 +65,37 @@ def call_lvm(command, debug=False):
if debug or process.returncode != 0:
_debug_c(command, process.returncode, (stdout_text, stderr_text))
return process.returncode, stdout_text, stderr_text
if process.returncode == 0:
if cfg.DEBUG and out[1] and len(out[1]):
log_error('WARNING: lvm is out-putting text to STDERR on success!')
_debug_c(command, process.returncode, (stdout_text, stderr_text))
# The actual method which gets called to invoke the lvm command, can vary
# from forking a new process to using lvm shell
_t_call = call_lvm
return process.returncode, stdout_text, stderr_text
def _shell_cfg():
global _t_call
# noinspection PyBroadException
try:
lvm_shell = LVMShellProxy()
_t_call = lvm_shell.call_lvm
cfg.SHELL_IN_USE = lvm_shell
return True
except Exception:
_t_call = call_lvm
cfg.SHELL_IN_USE = None
log_error(traceback.format_exc())
log_error("Unable to utilize lvm shell, dropping back to fork & exec")
return False
log_debug('Using lvm shell!')
lvm_shell = LVMShellProxy()
_t_call = lvm_shell.call_lvm
if cfg.USE_SHELL:
_shell_cfg()
else:
_t_call = call_lvm
def set_execution(shell):
global _t_call
with cmd_lock:
# If the user requested lvm shell and we are currently setup that
# way, just return
if cfg.SHELL_IN_USE and shell:
return True
else:
if not shell and cfg.SHELL_IN_USE:
cfg.SHELL_IN_USE.exit_shell()
cfg.SHELL_IN_USE = None
_t_call = call_lvm
_t_call = None
if shell:
if cfg.args.use_json:
return _shell_cfg()
else:
return False
return True
log_debug('Using lvm shell!')
lvm_shell = LVMShellProxy()
_t_call = lvm_shell.call_lvm
else:
_t_call = call_lvm
def time_wrapper(command, debug=False):
@@ -155,10 +105,9 @@ def time_wrapper(command, debug=False):
with cmd_lock:
start = time.time()
results = _t_call(command, debug)
ended = time.time()
total_time += (ended - start)
total_time += (time.time() - start)
total_count += 1
cfg.blackbox.add(LvmExecutionMeta(start, ended, command, *results))
return results
@@ -225,10 +174,6 @@ def pv_remove(device, remove_options):
return call(cmd)
def _qt(tag_name):
return '@%s' % tag_name
def _tag(operation, what, add, rm, tag_options):
cmd = [operation]
cmd.extend(options_to_cli_args(tag_options))
@@ -239,11 +184,9 @@ def _tag(operation, what, add, rm, tag_options):
cmd.append(what)
if add:
cmd.extend(list(chain.from_iterable(
('--addtag', _qt(x)) for x in add)))
cmd.extend(list(chain.from_iterable(('--addtag', x) for x in add)))
if rm:
cmd.extend(list(chain.from_iterable(
('--deltag', _qt(x)) for x in rm)))
cmd.extend(list(chain.from_iterable(('--deltag', x) for x in rm)))
return call(cmd, False)
@@ -295,7 +238,7 @@ def vg_lv_snapshot(vg_name, snapshot_options, name, size_bytes):
return call(cmd)
def _vg_lv_create_common_cmd(create_options, size_bytes, thin_pool):
def vg_lv_create_linear(vg_name, create_options, name, size_bytes, thin_pool):
cmd = ['lvcreate']
cmd.extend(options_to_cli_args(create_options))
@@ -303,18 +246,20 @@ def _vg_lv_create_common_cmd(create_options, size_bytes, thin_pool):
cmd.extend(['--size', str(size_bytes) + 'B'])
else:
cmd.extend(['--thin', '--size', str(size_bytes) + 'B'])
return cmd
def vg_lv_create_linear(vg_name, create_options, name, size_bytes, thin_pool):
cmd = _vg_lv_create_common_cmd(create_options, size_bytes, thin_pool)
cmd.extend(['--name', name, vg_name])
return call(cmd)
def vg_lv_create_striped(vg_name, create_options, name, size_bytes,
num_stripes, stripe_size_kb, thin_pool):
cmd = _vg_lv_create_common_cmd(create_options, size_bytes, thin_pool)
cmd = ['lvcreate']
cmd.extend(options_to_cli_args(create_options))
if not thin_pool:
cmd.extend(['--size', str(size_bytes) + 'B'])
else:
cmd.extend(['--thin', '--size', str(size_bytes) + 'B'])
cmd.extend(['--stripes', str(num_stripes)])
if stripe_size_kb != 0:
@@ -352,8 +297,7 @@ def vg_lv_create_raid(vg_name, create_options, name, raid_type, size_bytes,
size_bytes, num_stripes, stripe_size_kb)
def vg_lv_create_mirror(
vg_name, create_options, name, size_bytes, num_copies):
def vg_lv_create_mirror(vg_name, create_options, name, size_bytes, num_copies):
cmd = ['lvcreate']
cmd.extend(options_to_cli_args(create_options))
@@ -422,7 +366,7 @@ def lv_cache_lv(cache_pool_full_name, lv_full_name, cache_options):
# lvconvert --type cache --cachepool VG/CachePoolLV VG/OriginLV
cmd = ['lvconvert']
cmd.extend(options_to_cli_args(cache_options))
cmd.extend(['-y', '--type', 'cache', '--cachepool',
cmd.extend(['--type', 'cache', '--cachepool',
cache_pool_full_name, lv_full_name])
return call(cmd)
@@ -442,84 +386,19 @@ def lv_detach_cache(lv_full_name, detach_options, destroy_cache):
return call(cmd)
def supports_json():
cmd = ['help']
rc, out, err = call(cmd)
if rc == 0:
if cfg.SHELL_IN_USE:
return True
else:
if 'fullreport' in err:
return True
return False
def lvm_full_report_json():
pv_columns = ['pv_name', 'pv_uuid', 'pv_fmt', 'pv_size', 'pv_free',
'pv_used', 'dev_size', 'pv_mda_size', 'pv_mda_free',
'pv_ba_start', 'pv_ba_size', 'pe_start', 'pv_pe_count',
'pv_pe_alloc_count', 'pv_attr', 'pv_tags', 'vg_name',
'vg_uuid', 'pv_missing']
pv_seg_columns = ['pvseg_start', 'pvseg_size', 'segtype',
'pv_uuid', 'lv_uuid', 'pv_name']
vg_columns = ['vg_name', 'vg_uuid', 'vg_fmt', 'vg_size', 'vg_free',
'vg_sysid', 'vg_extent_size', 'vg_extent_count',
'vg_free_count', 'vg_profile', 'max_lv', 'max_pv',
'pv_count', 'lv_count', 'snap_count', 'vg_seqno',
'vg_mda_count', 'vg_mda_free', 'vg_mda_size',
'vg_mda_used_count', 'vg_attr', 'vg_tags']
lv_columns = ['lv_uuid', 'lv_name', 'lv_path', 'lv_size',
'vg_name', 'pool_lv_uuid', 'pool_lv', 'origin_uuid',
'origin', 'data_percent',
'lv_attr', 'lv_tags', 'vg_uuid', 'lv_active', 'data_lv',
'metadata_lv', 'lv_parent', 'lv_role', 'lv_layout',
'snap_percent', 'metadata_percent', 'copy_percent',
'sync_percent', 'lv_metadata_size', 'move_pv', 'move_pv_uuid']
lv_seg_columns = ['seg_pe_ranges', 'segtype', 'lv_uuid']
cmd = _dc('fullreport', [
'-a', # Need hidden too
'--configreport', 'pv', '-o', ','.join(pv_columns),
'--configreport', 'vg', '-o', ','.join(vg_columns),
'--configreport', 'lv', '-o', ','.join(lv_columns),
'--configreport', 'seg', '-o', ','.join(lv_seg_columns),
'--configreport', 'pvseg', '-o', ','.join(pv_seg_columns),
'--reportformat', 'json'
])
rc, out, err = call(cmd)
if rc == 0:
# With the current implementation, if we are using the shell then we
# are using JSON and JSON is returned back to us as it was parsed to
# figure out if we completed OK or not
if cfg.SHELL_IN_USE:
assert(type(out) == dict)
return out
else:
return json.loads(out)
return None
def pv_retrieve_with_segs(device=None):
d = []
err = ""
out = ""
rc = 0
columns = ['pv_name', 'pv_uuid', 'pv_fmt', 'pv_size', 'pv_free',
'pv_used', 'dev_size', 'pv_mda_size', 'pv_mda_free',
'pv_ba_start', 'pv_ba_size', 'pe_start', 'pv_pe_count',
'pv_pe_alloc_count', 'pv_attr', 'pv_tags', 'vg_name',
'vg_uuid', 'pvseg_start', 'pvseg_size', 'segtype', 'pv_missing']
'vg_uuid', 'pv_seg_start', 'pvseg_size', 'segtype']
# Lvm has some issues where it returns failure when querying pvs when other
# operations are in process, see:
# https://bugzilla.redhat.com/show_bug.cgi?id=1274085
for i in range(0, 10):
while True:
cmd = _dc('pvs', ['-o', ','.join(columns)])
if device:
@@ -534,13 +413,6 @@ def pv_retrieve_with_segs(device=None):
time.sleep(0.2)
log_debug("LVM Bug workaround, retrying pvs command...")
if rc != 0:
msg = "We were unable to get pvs to return without error after " \
"trying 10 times, RC=%d, STDERR=(%s), STDOUT=(%s)" % \
(rc, err, out)
log_error(msg)
raise RuntimeError(msg)
return d
@@ -727,9 +599,7 @@ def lv_retrieve_with_segments():
'origin', 'data_percent',
'lv_attr', 'lv_tags', 'vg_uuid', 'lv_active', 'data_lv',
'metadata_lv', 'seg_pe_ranges', 'segtype', 'lv_parent',
'lv_role', 'lv_layout',
'snap_percent', 'metadata_percent', 'copy_percent',
'sync_percent', 'lv_metadata_size', 'move_pv', 'move_pv_uuid']
'lv_role', 'lv_layout']
cmd = _dc('lvs', ['-a', '-o', ','.join(columns)])
rc, out, err = call(cmd)
@@ -746,4 +616,4 @@ if __name__ == '__main__':
pv_data = pv_retrieve_with_segs()
for p in pv_data:
print(str(p))
log_debug(str(p))

View File

@@ -11,151 +11,20 @@ from .pv import load_pvs
from .vg import load_vgs
from .lv import load_lvs
from . import cfg
from .utils import MThreadRunner, log_debug, log_error
import threading
import queue
import traceback
def _main_thread_load(refresh=True, emit_signal=True):
def load(refresh=True, emit_signal=True, cache_refresh=True, log=True):
num_total_changes = 0
num_total_changes += load_pvs(
refresh=refresh,
emit_signal=emit_signal,
cache_refresh=False)[1]
num_total_changes += load_vgs(
refresh=refresh,
emit_signal=emit_signal,
cache_refresh=False)[1]
num_total_changes += load_lvs(
refresh=refresh,
emit_signal=emit_signal,
cache_refresh=False)[1]
return num_total_changes
def load(refresh=True, emit_signal=True, cache_refresh=True, log=True,
need_main_thread=True):
# Go through and load all the PVs, VGs and LVs
if cache_refresh:
cfg.db.refresh(log)
if need_main_thread:
rc = MThreadRunner(_main_thread_load, refresh, emit_signal).done()
else:
rc = _main_thread_load(refresh, emit_signal)
num_total_changes += load_pvs(refresh=refresh, emit_signal=emit_signal,
cache_refresh=False)[1]
num_total_changes += load_vgs(refresh=refresh, emit_signal=emit_signal,
cache_refresh=False)[1]
num_total_changes += load_lvs(refresh=refresh, emit_signal=emit_signal,
cache_refresh=False)[1]
return rc
# Even though lvm can handle multiple changes concurrently it really doesn't
# make sense to make a 1-1 fetch of data for each change of lvm because when
# we fetch the data once all previous changes are reflected.
class StateUpdate(object):
class UpdateRequest(object):
def __init__(self, refresh, emit_signal, cache_refresh, log,
need_main_thread):
self.is_done = False
self.refresh = refresh
self.emit_signal = emit_signal
self.cache_refresh = cache_refresh
self.log = log
self.need_main_thread = need_main_thread
self.result = None
self.cond = threading.Condition(threading.Lock())
def done(self):
with self.cond:
if not self.is_done:
self.cond.wait()
return self.result
def set_result(self, result):
with self.cond:
self.result = result
self.is_done = True
self.cond.notify_all()
@staticmethod
def update_thread(obj):
while cfg.run.value != 0:
# noinspection PyBroadException
try:
queued_requests = []
refresh = True
emit_signal = True
cache_refresh = True
log = True
need_main_thread = True
with obj.lock:
wait = not obj.deferred
obj.deferred = False
if wait:
queued_requests.append(obj.queue.get(True, 2))
# Ok we have one or the deferred queue has some,
# check if any others
try:
while True:
queued_requests.append(obj.queue.get(False))
except queue.Empty:
pass
if len(queued_requests) > 1:
log_debug("Processing %d updates!" % len(queued_requests),
'bg_black', 'fg_light_green')
# We have what we can, run the update with the needed options
for i in queued_requests:
if not i.refresh:
refresh = False
if not i.emit_signal:
emit_signal = False
if not i.cache_refresh:
cache_refresh = False
if not i.log:
log = False
if not i.need_main_thread:
need_main_thread = False
num_changes = load(refresh, emit_signal, cache_refresh, log,
need_main_thread)
# Update is done, let everyone know!
for i in queued_requests:
i.set_result(num_changes)
except queue.Empty:
pass
except Exception:
st = traceback.format_exc()
log_error("update_thread exception: \n%s" % st)
def __init__(self):
self.lock = threading.RLock()
self.queue = queue.Queue()
self.deferred = False
# Do initial load
load(refresh=False, emit_signal=False, need_main_thread=False)
self.thread = threading.Thread(target=StateUpdate.update_thread,
args=(self,))
def load(self, refresh=True, emit_signal=True, cache_refresh=True,
log=True, need_main_thread=True):
# Place this request on the queue and wait for it to be completed
req = StateUpdate.UpdateRequest(refresh, emit_signal, cache_refresh,
log, need_main_thread)
self.queue.put(req)
return req.done()
def event(self):
with self.lock:
self.deferred = True
return num_total_changes

View File

@@ -8,68 +8,24 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from .automatedproperties import AutomatedProperties
from .utils import job_obj_path_generate, mt_async_result, mt_run_no_wait
from .utils import job_obj_path_generate
from . import cfg
from .cfg import JOB_INTERFACE
import dbus
import threading
# noinspection PyUnresolvedReferences
from gi.repository import GLib
# Class that handles a client waiting for something to be complete. We either
# get a timeout or the operation is done.
class WaitingClient(object):
# A timeout occurred
@staticmethod
def _timeout(wc):
with wc.rlock:
if wc.in_use:
wc.in_use = False
# Remove ourselves from waiting client
wc.job_state.remove_waiting_client(wc)
wc.timer_id = -1
mt_async_result(wc.cb, wc.job_state.Complete)
wc.job_state = None
def __init__(self, job_state, tmo, cb, cbe):
self.rlock = threading.RLock()
self.job_state = job_state
self.cb = cb
self.cbe = cbe
self.in_use = True # Indicates if object is in play
self.timer_id = -1
if tmo > 0:
self.timer_id = GLib.timeout_add_seconds(
tmo, WaitingClient._timeout, self)
# The job finished before the timer popped and we are being notified that
# it's done
def notify(self):
with self.rlock:
if self.in_use:
self.in_use = False
# Clear timer
if self.timer_id != -1:
GLib.source_remove(self.timer_id)
self.timer_id = -1
mt_async_result(self.cb, self.job_state.Complete)
self.job_state = None
# noinspection PyPep8Naming
class JobState(object):
def __init__(self, request=None):
def __init__(self, request):
self.rlock = threading.RLock()
self._percent = 0
self._complete = False
self._request = request
self._cond = threading.Condition(self.rlock)
self._ec = 0
self._stderr = ''
self._waiting_clients = []
# This is an lvm command that is just taking too long and doesn't
# support background operation
@@ -92,6 +48,8 @@ class JobState(object):
with self.rlock:
if self._request:
self._complete = self._request.is_done()
if self._complete:
self._percent = 100
return self._complete
@@ -99,8 +57,7 @@ class JobState(object):
def Complete(self, value):
with self.rlock:
self._complete = value
self._percent = 100
self.notify_waiting_clients()
self._cond.notify_all()
@property
def GetError(self):
@@ -114,10 +71,29 @@ class JobState(object):
else:
return (-1, 'Job is not complete!')
def set_result(self, ec, msg):
with self.rlock:
self.Complete = True
self._ec = ec
self._stderr = msg
def dtor(self):
with self.rlock:
self._request = None
def Wait(self, timeout):
try:
with self._cond:
# Check to see if we are done, before we wait
if not self.Complete:
if timeout != -1:
self._cond.wait(timeout)
else:
self._cond.wait()
return self.Complete
except RuntimeError:
return False
@property
def Result(self):
with self.rlock:
@@ -125,40 +101,10 @@ class JobState(object):
return self._request.result()
return '/'
def add_waiting_client(self, client):
with self.rlock:
# Avoid race condition where it goes complete before we get added
# to the list of waiting clients
if self.Complete:
client.notify()
else:
self._waiting_clients.append(client)
def remove_waiting_client(self, client):
# If a waiting client timer pops before the job is done we will allow
# the client to remove themselves from the list. As we have a lock
# here and a lock in the waiting client too, and they can be obtained
# in different orders, a dead lock can occur.
# As this remove is really optional, we will try to acquire the lock
# and remove. If we are unsuccessful it's not fatal, we just delay
# the time when the objects can be garbage collected by python
if self.rlock.acquire(False):
try:
self._waiting_clients.remove(client)
finally:
self.rlock.release()
def notify_waiting_clients(self):
with self.rlock:
for c in self._waiting_clients:
c.notify()
self._waiting_clients = []
# noinspection PyPep8Naming
class Job(AutomatedProperties):
_Percent_meta = ('d', JOB_INTERFACE)
_Percent_meta = ('y', JOB_INTERFACE)
_Complete_meta = ('b', JOB_INTERFACE)
_Result_meta = ('o', JOB_INTERFACE)
_GetError_meta = ('(is)', JOB_INTERFACE)
@@ -174,25 +120,26 @@ class Job(AutomatedProperties):
@property
def Percent(self):
return dbus.Double(float(self.state.Percent))
return self.state.Percent
@Percent.setter
def Percent(self, value):
self.state.Percent = value
@property
def Complete(self):
return dbus.Boolean(self.state.Complete)
@staticmethod
def _signal_complete(obj):
obj.PropertiesChanged(
JOB_INTERFACE, dict(Complete=dbus.Boolean(obj.state.Complete)), [])
return self.state.Complete
@Complete.setter
def Complete(self, value):
self.state.Complete = value
mt_run_no_wait(Job._signal_complete, self)
@property
def GetError(self):
return dbus.Struct(self.state.GetError, signature="(is)")
return self.state.GetError
def set_result(self, ec, msg):
self.state.set_result(ec, msg)
@dbus.service.method(dbus_interface=JOB_INTERFACE)
def Remove(self):
@@ -205,18 +152,13 @@ class Job(AutomatedProperties):
@dbus.service.method(dbus_interface=JOB_INTERFACE,
in_signature='i',
out_signature='b',
async_callbacks=('cb', 'cbe'))
def Wait(self, timeout, cb, cbe):
if timeout == 0 or self.state.Complete:
cb(dbus.Boolean(self.state.Complete))
else:
self.state.add_waiting_client(
WaitingClient(self.state, timeout, cb, cbe))
out_signature='b')
def Wait(self, timeout):
return self.state.Wait(timeout)
@property
def Result(self):
return dbus.ObjectPath(self.state.Result)
return self.state.Result
@property
def lvm_id(self):

View File

@@ -21,41 +21,7 @@ from .utils import n, n32
from .loader import common
from .state import State
from . import background
from .utils import round_size, mt_remove_dbus_objects
from .job import JobState
# Try and build a key for a LV, so that we sort the LVs with least dependencies
# first. This may be error prone because of the flexibility LVM
# provides and what you can stack.
def get_key(i):
name = i['lv_name']
parent = i['lv_parent']
pool = i['pool_lv']
a1 = ""
a2 = ""
if name[0] == '[':
a1 = '#'
# We have a parent
if parent:
# Check if parent is hidden
if parent[0] == '[':
a2 = '##'
else:
a2 = '#'
# If a LV has a pool, then it should be sorted/loaded after the pool
# lv, unless it's a hidden too, then after other hidden, but before visible
if pool:
if pool[0] != '[':
a2 += '~'
else:
a1 = '$' + a1
return "%s%s%s" % (a1, a2, name)
from .utils import round_size
# noinspection PyUnusedLocal
@@ -65,13 +31,7 @@ def lvs_state_retrieve(selection, cache_refresh=True):
if cache_refresh:
cfg.db.refresh()
# When building up the model, it's best to process LVs with the least
# dependencies to those that are dependant upon other LVs. Otherwise, when
# we are trying to gather information we could be in a position where we
# don't have information available yet.
lvs = sorted(cfg.db.fetch_lvs(selection), key=get_key)
for l in lvs:
for l in cfg.db.fetch_lvs(selection):
rc.append(LvState(
l['lv_uuid'], l['lv_name'],
l['lv_path'], n(l['lv_size']),
@@ -81,14 +41,7 @@ def lvs_state_retrieve(selection, cache_refresh=True):
n32(l['data_percent']), l['lv_attr'],
l['lv_tags'], l['lv_active'], l['data_lv'],
l['metadata_lv'], l['segtype'], l['lv_role'],
l['lv_layout'],
n32(l['snap_percent']),
n32(l['metadata_percent']),
n32(l['copy_percent']),
n32(l['sync_percent']),
n(l['lv_metadata_size']),
l['move_pv'],
l['move_pv_uuid']))
l['lv_layout']))
return rc
@@ -108,15 +61,9 @@ class LvState(State):
rc = []
for pv in sorted(cfg.db.lv_contained_pv(uuid)):
(pv_uuid, pv_name, pv_segs) = pv
pv_obj = cfg.om.get_object_path_by_uuid_lvm_id(pv_uuid, pv_name)
segs_decorate = []
for i in pv_segs:
segs_decorate.append((dbus.UInt64(i[0]),
dbus.UInt64(i[1]),
dbus.String(i[2])))
rc.append((dbus.ObjectPath(pv_obj), segs_decorate))
pv_obj = cfg.om.get_object_path_by_lvm_id(
pv_uuid, pv_name, gen_new=False)
rc.append((pv_obj, pv_segs))
return dbus.Array(rc, signature="(oa(tts))")
@@ -137,28 +84,27 @@ class LvState(State):
for l in cfg.db.hidden_lvs(self.Uuid):
full_name = "%s/%s" % (vg_name, l[1])
op = cfg.om.get_object_path_by_uuid_lvm_id(l[0], full_name)
op = cfg.om.get_object_path_by_lvm_id(
l[0], full_name, gen_new=False)
assert op
rc.append(dbus.ObjectPath(op))
rc.append(op)
return rc
def __init__(self, Uuid, Name, Path, SizeBytes,
vg_name, vg_uuid, pool_lv_uuid, PoolLv,
origin_uuid, OriginLv, DataPercent, Attr, Tags, active,
data_lv, metadata_lv, segtypes, role, layout, SnapPercent,
MetaDataPercent, CopyPercent, SyncPercent, MetaDataSizeBytes,
move_pv, move_pv_uuid):
data_lv, metadata_lv, segtypes, role, layout):
utils.init_class_from_arguments(self)
# The segtypes is possibly an array with potentially dupes or a single
# value
self._segs = dbus.Array([], signature='s')
if not isinstance(segtypes, list):
self._segs.append(dbus.String(segtypes))
self._segs.append(segtypes)
else:
self._segs.extend([dbus.String(x) for x in set(segtypes)])
self._segs.extend(set(segtypes))
self.Vg = cfg.om.get_object_path_by_uuid_lvm_id(
self.Vg = cfg.om.get_object_path_by_lvm_id(
vg_uuid, vg_name, vg_obj_path_generate)
self.Devices = LvState._pv_devices(self.Uuid)
@@ -166,14 +112,15 @@ class LvState(State):
if PoolLv:
gen = utils.lv_object_path_method(Name, (Attr, layout, role))
self.PoolLv = cfg.om.get_object_path_by_uuid_lvm_id(
pool_lv_uuid, '%s/%s' % (vg_name, PoolLv), gen)
self.PoolLv = cfg.om.get_object_path_by_lvm_id(
pool_lv_uuid, '%s/%s' % (vg_name, PoolLv),
gen)
else:
self.PoolLv = '/'
if OriginLv:
self.OriginLv = \
cfg.om.get_object_path_by_uuid_lvm_id(
cfg.om.get_object_path_by_lvm_id(
origin_uuid, '%s/%s' % (vg_name, OriginLv),
vg_obj_path_generate)
else:
@@ -190,6 +137,8 @@ class LvState(State):
self.Name, (self.Attr, self.layout, self.role))
def _object_type_create(self):
if self.Name[0] == '[':
return LvCommon
if self.Attr[0] == 't':
return LvThinPool
elif self.Attr[0] == 'C':
@@ -197,8 +146,6 @@ class LvState(State):
return LvCachePool
else:
return LvCacheLv
elif self.Name[0] == '[':
return LvCommon
elif self.OriginLv != '/':
return LvSnapShot
else:
@@ -206,7 +153,7 @@ class LvState(State):
def create_dbus_object(self, path):
if not path:
path = cfg.om.get_object_path_by_uuid_lvm_id(
path = cfg.om.get_object_path_by_lvm_id(
self.Uuid, self.lvm_id, self._object_path_create())
obj_ctor = self._object_type_create()
@@ -223,23 +170,15 @@ class LvState(State):
@utils.dbus_property(LV_COMMON_INTERFACE, 'Name', 's')
@utils.dbus_property(LV_COMMON_INTERFACE, 'Path', 's')
@utils.dbus_property(LV_COMMON_INTERFACE, 'SizeBytes', 't')
@utils.dbus_property(LV_COMMON_INTERFACE, 'DataPercent', 'u')
@utils.dbus_property(LV_COMMON_INTERFACE, 'SegType', 'as')
@utils.dbus_property(LV_COMMON_INTERFACE, 'Vg', 'o')
@utils.dbus_property(LV_COMMON_INTERFACE, 'OriginLv', 'o')
@utils.dbus_property(LV_COMMON_INTERFACE, 'PoolLv', 'o')
@utils.dbus_property(LV_COMMON_INTERFACE, 'Devices', "a(oa(tts))")
@utils.dbus_property(LV_COMMON_INTERFACE, 'HiddenLvs', "ao")
@utils.dbus_property(LV_COMMON_INTERFACE, 'Attr', 's')
@utils.dbus_property(LV_COMMON_INTERFACE, 'DataPercent', 'u')
@utils.dbus_property(LV_COMMON_INTERFACE, 'SnapPercent', 'u')
@utils.dbus_property(LV_COMMON_INTERFACE, 'DataPercent', 'u')
@utils.dbus_property(LV_COMMON_INTERFACE, 'MetaDataPercent', 'u')
@utils.dbus_property(LV_COMMON_INTERFACE, 'CopyPercent', 'u')
@utils.dbus_property(LV_COMMON_INTERFACE, 'SyncPercent', 'u')
@utils.dbus_property(LV_COMMON_INTERFACE, 'MetaDataSizeBytes', 't')
class LvCommon(AutomatedProperties):
_Tags_meta = ("as", LV_COMMON_INTERFACE)
_Roles_meta = ("as", LV_COMMON_INTERFACE)
_IsThinVolume_meta = ("b", LV_COMMON_INTERFACE)
_IsThinPool_meta = ("b", LV_COMMON_INTERFACE)
_Active_meta = ("b", LV_COMMON_INTERFACE)
@@ -252,45 +191,12 @@ class LvCommon(AutomatedProperties):
_FixedMinor_meta = ('b', LV_COMMON_INTERFACE)
_ZeroBlocks_meta = ('b', LV_COMMON_INTERFACE)
_SkipActivation_meta = ('b', LV_COMMON_INTERFACE)
_MovePv_meta = ('o', LV_COMMON_INTERFACE)
def _get_move_pv(self):
path = None
# It's likely that the move_pv is empty
if self.state.move_pv_uuid and self.state.move_pv:
path = cfg.om.get_object_path_by_uuid_lvm_id(
self.state.move_pv_uuid, self.state.move_pv)
if not path:
path = '/'
return path
# noinspection PyUnusedLocal,PyPep8Naming
def __init__(self, object_path, object_state):
super(LvCommon, self).__init__(object_path, lvs_state_retrieve)
self.set_interface(LV_COMMON_INTERFACE)
self.state = object_state
self._move_pv = self._get_move_pv()
@staticmethod
def handle_execute(rc, out, err):
if rc == 0:
cfg.load()
else:
# Need to work on error handling, need consistent
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
@staticmethod
def validate_dbus_object(lv_uuid, lv_name):
dbo = cfg.om.get_object_by_uuid_lvm_id(lv_uuid, lv_name)
if not dbo:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'LV with uuid %s and name %s not present!' %
(lv_uuid, lv_name))
return dbo
@property
def VolumeType(self):
@@ -305,16 +211,14 @@ class LvCommon(AutomatedProperties):
'V': 'thin Volume', 't': 'thin pool', 'T': 'Thin pool data',
'e': 'raid or pool metadata or pool metadata spare',
'-': 'Unspecified'}
return dbus.Struct((self.state.Attr[0], type_map[self.state.Attr[0]]),
signature="as")
return (self.state.Attr[0], type_map[self.state.Attr[0]])
@property
def Permissions(self):
type_map = {'w': 'writable', 'r': 'read-only',
'R': 'Read-only activation of non-read-only volume',
'-': 'Unspecified'}
return dbus.Struct((self.state.Attr[1], type_map[self.state.Attr[1]]),
signature="(ss)")
return (self.state.Attr[1], type_map[self.state.Attr[1]])
@property
def AllocationPolicy(self):
@@ -323,12 +227,11 @@ class LvCommon(AutomatedProperties):
'i': 'inherited', 'I': 'inherited locked',
'l': 'cling', 'L': 'cling locked',
'n': 'normal', 'N': 'normal locked', '-': 'Unspecified'}
return dbus.Struct((self.state.Attr[2], type_map[self.state.Attr[2]]),
signature="(ss)")
return (self.state.Attr[2], type_map[self.state.Attr[2]])
@property
def FixedMinor(self):
return dbus.Boolean(self.state.Attr[3] == 'm')
return self.state.Attr[3] == 'm'
@property
def State(self):
@@ -339,32 +242,29 @@ class LvCommon(AutomatedProperties):
'd': 'mapped device present without tables',
'i': 'mapped device present with inactive table',
'X': 'unknown', '-': 'Unspecified'}
return dbus.Struct((self.state.Attr[4], type_map[self.state.Attr[4]]),
signature="(ss)")
return (self.state.Attr[4], type_map[self.state.Attr[4]])
@property
def TargetType(self):
type_map = {'C': 'Cache', 'm': 'mirror', 'r': 'raid',
's': 'snapshot', 't': 'thin', 'u': 'unknown',
'v': 'virtual', '-': 'Unspecified'}
return dbus.Struct((self.state.Attr[6], type_map[self.state.Attr[6]]),
signature="(ss)")
return (self.state.Attr[6], type_map[self.state.Attr[6]])
@property
def ZeroBlocks(self):
return dbus.Boolean(self.state.Attr[7] == 'z')
return self.state.Attr[7] == 'z'
@property
def Health(self):
type_map = {'p': 'partial', 'r': 'refresh',
'm': 'mismatches', 'w': 'writemostly',
'X': 'X unknown', '-': 'Unspecified'}
return dbus.Struct((self.state.Attr[8], type_map[self.state.Attr[8]]),
signature="(ss)")
return (self.state.Attr[8], type_map[self.state.Attr[8]])
@property
def SkipActivation(self):
return dbus.Boolean(self.state.Attr[9] == 'k')
return self.state.Attr[9] == 'k'
def vg_name_lookup(self):
return self.state.vg_name_lookup()
@@ -380,45 +280,32 @@ class LvCommon(AutomatedProperties):
def Tags(self):
return utils.parse_tags(self.state.Tags)
@property
def Roles(self):
return utils.parse_tags(self.state.role)
@property
def lvm_id(self):
return self.state.lvm_id
@property
def IsThinVolume(self):
return dbus.Boolean(self.state.Attr[0] == 'V')
return self.state.Attr[0] == 'V'
@property
def IsThinPool(self):
return dbus.Boolean(self.state.Attr[0] == 't')
return self.state.Attr[0] == 't'
@property
def Active(self):
return dbus.Boolean(self.state.active == "active")
return self.state.active == "active"
@property
def MovePv(self):
return dbus.ObjectPath(self._move_pv)
@dbus.service.method(
dbus_interface=LV_COMMON_INTERFACE,
in_signature='ia{sv}',
out_signature='o')
def _Future(self, tmo, open_options):
raise dbus.exceptions.DBusException(LV_COMMON_INTERFACE, 'Do not use!')
# noinspection PyPep8Naming
class Lv(LvCommon):
def _fetch_hidden(self, name):
# The name is vg/name
full_name = "%s/%s" % (self.vg_name_lookup(), name)
return cfg.om.get_object_path_by_lvm_id(full_name)
def _get_data_meta(self):
# Get the data
return (self._fetch_hidden(self.state.data_lv),
self._fetch_hidden(self.state.metadata_lv))
# noinspection PyUnusedLocal,PyPep8Naming
def __init__(self, object_path, object_state):
super(Lv, self).__init__(object_path, object_state)
@@ -428,10 +315,25 @@ class Lv(LvCommon):
@staticmethod
def _remove(lv_uuid, lv_name, remove_options):
# Make sure we have a dbus object representing it
LvCommon.validate_dbus_object(lv_uuid, lv_name)
# Remove the LV, if successful then remove from the model
rc, out, err = cmdhandler.lv_remove(lv_name, remove_options)
LvCommon.handle_execute(rc, out, err)
dbo = cfg.om.get_object_by_uuid_lvm_id(lv_uuid, lv_name)
if dbo:
# Remove the LV, if successful then remove from the model
rc, out, err = cmdhandler.lv_remove(lv_name, remove_options)
if rc == 0:
cfg.om.remove_object(dbo, True)
cfg.load()
else:
# Need to work on error handling, need consistent
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'LV with uuid %s and name %s not present!' %
(lv_uuid, lv_name))
return '/'
@dbus.service.method(
@@ -449,11 +351,24 @@ class Lv(LvCommon):
@staticmethod
def _rename(lv_uuid, lv_name, new_name, rename_options):
# Make sure we have a dbus object representing it
LvCommon.validate_dbus_object(lv_uuid, lv_name)
# Rename the logical volume
rc, out, err = cmdhandler.lv_rename(lv_name, new_name,
rename_options)
LvCommon.handle_execute(rc, out, err)
dbo = cfg.om.get_object_by_uuid_lvm_id(lv_uuid, lv_name)
if dbo:
# Rename the logical volume
rc, out, err = cmdhandler.lv_rename(lv_name, new_name,
rename_options)
if rc == 0:
cfg.load()
else:
# Need to work on error handling, need consistent
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'LV with uuid %s and name %s not present!' %
(lv_uuid, lv_name))
return '/'
@dbus.service.method(
@@ -473,41 +388,53 @@ class Lv(LvCommon):
@dbus.service.method(
dbus_interface=LV_INTERFACE,
in_signature='o(tt)a(ott)ia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
out_signature='o')
def Move(self, pv_src_obj, pv_source_range,
pv_dests_and_ranges,
tmo, move_options, cb, cbe):
job_state = JobState()
r = RequestEntry(
tmo, background.move,
(LV_INTERFACE, self.lvm_id, pv_src_obj, pv_source_range,
pv_dests_and_ranges, move_options, job_state), cb, cbe, False,
job_state)
background.cmd_runner(r)
tmo, move_options):
return background.move(
LV_INTERFACE, self.lvm_id, pv_src_obj,
pv_source_range, pv_dests_and_ranges,
move_options, tmo)
@staticmethod
def _snap_shot(lv_uuid, lv_name, name, optional_size,
snapshot_options):
# Make sure we have a dbus object representing it
dbo = LvCommon.validate_dbus_object(lv_uuid, lv_name)
# If you specify a size you get a 'thick' snapshot even if
# it is a thin lv
if not dbo.IsThinVolume:
if optional_size == 0:
space = dbo.SizeBytes / 80
remainder = space % 512
optional_size = space + 512 - remainder
dbo = cfg.om.get_object_by_uuid_lvm_id(lv_uuid, lv_name)
rc, out, err = cmdhandler.vg_lv_snapshot(
lv_name, snapshot_options, name, optional_size)
LvCommon.handle_execute(rc, out, err)
full_name = "%s/%s" % (dbo.vg_name_lookup(), name)
return cfg.om.get_object_path_by_lvm_id(full_name)
if dbo:
# If you specify a size you get a 'thick' snapshot even if
# it is a thin lv
if not dbo.IsThinVolume:
if optional_size == 0:
# TODO: Should we pick a sane default or force user to
# make a decision?
space = dbo.SizeBytes / 80
remainder = space % 512
optional_size = space + 512 - remainder
rc, out, err = cmdhandler.vg_lv_snapshot(
lv_name, snapshot_options, name, optional_size)
if rc == 0:
return_path = '/'
full_name = "%s/%s" % (dbo.vg_name_lookup(), name)
lvs = load_lvs([full_name], emit_signal=True)[0]
for l in lvs:
return_path = l.dbus_object_path()
# Refresh self and all included PVs
cfg.load(cache_refresh=False)
return return_path
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'LV with uuid %s and name %s not present!' %
(lv_uuid, lv_name))
@dbus.service.method(
dbus_interface=LV_INTERFACE,
@@ -530,24 +457,38 @@ class Lv(LvCommon):
resize_options):
# Make sure we have a dbus object representing it
pv_dests = []
dbo = LvCommon.validate_dbus_object(lv_uuid, lv_name)
dbo = cfg.om.get_object_by_uuid_lvm_id(lv_uuid, lv_name)
# If we have PVs, verify them
if len(pv_dests_and_ranges):
for pr in pv_dests_and_ranges:
pv_dbus_obj = cfg.om.get_object_by_path(pr[0])
if not pv_dbus_obj:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'PV Destination (%s) not found' % pr[0])
if dbo:
# If we have PVs, verify them
if len(pv_dests_and_ranges):
for pr in pv_dests_and_ranges:
pv_dbus_obj = cfg.om.get_object_by_path(pr[0])
if not pv_dbus_obj:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'PV Destination (%s) not found' % pr[0])
pv_dests.append((pv_dbus_obj.lvm_id, pr[1], pr[2]))
pv_dests.append((pv_dbus_obj.lvm_id, pr[1], pr[2]))
size_change = new_size_bytes - dbo.SizeBytes
rc, out, err = cmdhandler.lv_resize(dbo.lvm_id, size_change,
pv_dests, resize_options)
LvCommon.handle_execute(rc, out, err)
return "/"
size_change = new_size_bytes - dbo.SizeBytes
rc, out, err = cmdhandler.lv_resize(dbo.lvm_id, size_change,
pv_dests, resize_options)
if rc == 0:
# Refresh what's changed
cfg.load()
return "/"
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'LV with uuid %s and name %s not present!' %
(lv_uuid, lv_name))
@dbus.service.method(
dbus_interface=LV_INTERFACE,
@@ -580,11 +521,23 @@ class Lv(LvCommon):
def _lv_activate_deactivate(uuid, lv_name, activate, control_flags,
options):
# Make sure we have a dbus object representing it
LvCommon.validate_dbus_object(uuid, lv_name)
rc, out, err = cmdhandler.activate_deactivate(
'lvchange', lv_name, activate, control_flags, options)
LvCommon.handle_execute(rc, out, err)
return '/'
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, lv_name)
if dbo:
rc, out, err = cmdhandler.activate_deactivate(
'lvchange', lv_name, activate, control_flags, options)
if rc == 0:
dbo.refresh()
return '/'
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'LV with uuid %s and name %s not present!' %
(uuid, lv_name))
@dbus.service.method(
dbus_interface=LV_INTERFACE,
@@ -616,11 +569,25 @@ class Lv(LvCommon):
@staticmethod
def _add_rm_tags(uuid, lv_name, tags_add, tags_del, tag_options):
# Make sure we have a dbus object representing it
LvCommon.validate_dbus_object(uuid, lv_name)
rc, out, err = cmdhandler.lv_tag(
lv_name, tags_add, tags_del, tag_options)
LvCommon.handle_execute(rc, out, err)
return '/'
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, lv_name)
if dbo:
rc, out, err = cmdhandler.lv_tag(
lv_name, tags_add, tags_del, tag_options)
if rc == 0:
dbo.refresh()
return '/'
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'LV with uuid %s and name %s not present!' %
(uuid, lv_name))
@dbus.service.method(
dbus_interface=LV_INTERFACE,
@@ -662,6 +629,23 @@ class LvThinPool(Lv):
_DataLv_meta = ("o", THIN_POOL_INTERFACE)
_MetaDataLv_meta = ("o", THIN_POOL_INTERFACE)
def _fetch_hidden(self, name):
# The name is vg/name
full_name = "%s/%s" % (self.vg_name_lookup(), name)
o = cfg.om.get_object_by_lvm_id(full_name)
if o:
return o.dbus_object_path()
return '/'
def _get_data_meta(self):
# Get the data
return (self._fetch_hidden(self.state.data_lv),
self._fetch_hidden(self.state.metadata_lv))
def __init__(self, object_path, object_state):
super(LvThinPool, self).__init__(object_path, object_state)
self.set_interface(THIN_POOL_INTERFACE)
@@ -669,22 +653,37 @@ class LvThinPool(Lv):
@property
def DataLv(self):
return dbus.ObjectPath(self._data_lv)
return self._data_lv
@property
def MetaDataLv(self):
return dbus.ObjectPath(self._metadata_lv)
return self._metadata_lv
@staticmethod
def _lv_create(lv_uuid, lv_name, name, size_bytes, create_options):
# Make sure we have a dbus object representing it
dbo = LvCommon.validate_dbus_object(lv_uuid, lv_name)
dbo = cfg.om.get_object_by_uuid_lvm_id(lv_uuid, lv_name)
rc, out, err = cmdhandler.lv_lv_create(
lv_name, create_options, name, size_bytes)
LvCommon.handle_execute(rc, out, err)
full_name = "%s/%s" % (dbo.vg_name_lookup(), name)
return cfg.om.get_object_path_by_lvm_id(full_name)
lv_created = '/'
if dbo:
rc, out, err = cmdhandler.lv_lv_create(
lv_name, create_options, name, size_bytes)
if rc == 0:
full_name = "%s/%s" % (dbo.vg_name_lookup(), name)
lvs = load_lvs([full_name], emit_signal=True)[0]
for l in lvs:
lv_created = l.dbus_object_path()
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'LV with uuid %s and name %s not present!' %
(lv_uuid, lv_name))
return lv_created
@dbus.service.method(
dbus_interface=THIN_POOL_INTERFACE,
@@ -703,31 +702,20 @@ class LvThinPool(Lv):
# noinspection PyPep8Naming
class LvCachePool(Lv):
_DataLv_meta = ("o", CACHE_POOL_INTERFACE)
_MetaDataLv_meta = ("o", CACHE_POOL_INTERFACE)
def __init__(self, object_path, object_state):
super(LvCachePool, self).__init__(object_path, object_state)
self.set_interface(CACHE_POOL_INTERFACE)
self._data_lv, self._metadata_lv = self._get_data_meta()
@property
def DataLv(self):
return dbus.ObjectPath(self._data_lv)
@property
def MetaDataLv(self):
return dbus.ObjectPath(self._metadata_lv)
@staticmethod
def _cache_lv(lv_uuid, lv_name, lv_object_path, cache_options):
# Make sure we have a dbus object representing cache pool
dbo = LvCommon.validate_dbus_object(lv_uuid, lv_name)
dbo = cfg.om.get_object_by_uuid_lvm_id(lv_uuid, lv_name)
# Make sure we have dbus object representing lv to cache
lv_to_cache = cfg.om.get_object_by_path(lv_object_path)
if lv_to_cache:
if dbo and lv_to_cache:
fcn = lv_to_cache.lv_full_name()
rc, out, err = cmdhandler.lv_cache_lv(
dbo.lv_full_name(), fcn, cache_options)
@@ -735,18 +723,28 @@ class LvCachePool(Lv):
# When we cache an LV, the cache pool and the lv that is getting
# cached need to be removed from the object manager and
# re-created as their interfaces have changed!
mt_remove_dbus_objects((dbo, lv_to_cache))
cfg.om.remove_object(dbo, emit_signal=True)
cfg.om.remove_object(lv_to_cache, emit_signal=True)
cfg.load()
lv_converted = cfg.om.get_object_path_by_lvm_id(fcn)
lv_converted = \
cfg.om.get_object_by_lvm_id(fcn).dbus_object_path()
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE, 'LV to cache with object path %s not present!' %
lv_object_path)
msg = ""
if not dbo:
dbo += 'CachePool LV with uuid %s and name %s not present!' % \
(lv_uuid, lv_name)
if not lv_to_cache:
dbo += 'LV to cache with object path %s not present!' % \
(lv_object_path)
raise dbus.exceptions.DBusException(LV_INTERFACE, msg)
return lv_converted
@dbus.service.method(
@@ -772,30 +770,39 @@ class LvCacheLv(Lv):
@property
def CachePool(self):
return dbus.ObjectPath(self.state.PoolLv)
return self.state.PoolLv
@staticmethod
def _detach_lv(lv_uuid, lv_name, detach_options, destroy_cache):
# Make sure we have a dbus object representing cache pool
dbo = LvCommon.validate_dbus_object(lv_uuid, lv_name)
dbo = cfg.om.get_object_by_uuid_lvm_id(lv_uuid, lv_name)
# Get current cache name
cache_pool = cfg.om.get_object_by_path(dbo.CachePool)
if dbo:
rc, out, err = cmdhandler.lv_detach_cache(
dbo.lv_full_name(), detach_options, destroy_cache)
if rc == 0:
# The cache pool gets removed as hidden and put back to
# visible, so lets delete
mt_remove_dbus_objects((cache_pool, dbo))
cfg.load()
# Get current cache name
cache_pool = cfg.om.get_object_by_path(dbo.CachePool)
uncached_lv_path = cfg.om.get_object_path_by_lvm_id(lv_name)
rc, out, err = cmdhandler.lv_detach_cache(
dbo.lv_full_name(), detach_options, destroy_cache)
if rc == 0:
# The cache pool gets removed as hidden and put back to
# visible, so lets delete
cfg.om.remove_object(cache_pool, emit_signal=True)
cfg.om.remove_object(dbo, emit_signal=True)
cfg.load()
uncached_lv_path = \
cfg.om.get_object_by_lvm_id(lv_name).dbus_object_path()
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
'LV with uuid %s and name %s not present!' %
(lv_uuid, lv_name))
return uncached_lv_path
@dbus.service.method(
@@ -820,13 +827,7 @@ class LvSnapShot(Lv):
@dbus.service.method(
dbus_interface=SNAPSHOT_INTERFACE,
in_signature='ia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
def Merge(self, tmo, merge_options, cb, cbe):
job_state = JobState()
r = RequestEntry(tmo, background.merge,
(SNAPSHOT_INTERFACE, self.Uuid, self.lvm_id,
merge_options, job_state), cb, cbe, False,
job_state)
background.cmd_runner(r)
out_signature='o')
def Merge(self, tmo, merge_options):
return background.merge(SNAPSHOT_INTERFACE, self.Uuid, self.lvm_id,
merge_options, tmo)

View File

@@ -14,22 +14,17 @@
import subprocess
import shlex
from fcntl import fcntl, F_GETFL, F_SETFL
import os
from os import O_NONBLOCK
import traceback
import sys
import tempfile
import time
import select
import copy
import re
try:
import simplejson as json
except ImportError:
import json
from lvmdbusd.cfg import LVM_CMD
from lvmdbusd.utils import log_debug, log_error
from .cfg import LVM_CMD
from .utils import log_debug, log_error
except:
from cfg import LVM_CMD
from utils import log_debug, log_error
SHELL_PROMPT = "lvm> "
@@ -42,81 +37,43 @@ def _quote_arg(arg):
class LVMShellProxy(object):
@staticmethod
def _read(stream):
tmp = stream.read()
if tmp:
return tmp.decode("utf-8")
return ''
# Read until we get prompt back and a result
# @param: no_output Caller expects no output to report FD
# Returns stdout, report, stderr (report is JSON!)
def _read_until_prompt(self, no_output=False):
def _read_until_prompt(self):
prev_ec = None
stdout = ""
report = ""
stderr = ""
keep_reading = True
extra_passes = 3
report_json = {}
prev_report_len = 0
# Try reading from all FDs to prevent one from filling up and causing
# a hang. Keep reading until we get the prompt back and the report
# FD does not contain valid JSON
while keep_reading:
while not stdout.endswith(SHELL_PROMPT):
try:
rd_fd = [
self.lvm_shell.stdout.fileno(),
self.report_stream.fileno(),
self.lvm_shell.stderr.fileno()]
ready = select.select(rd_fd, [], [], 2)
for r in ready[0]:
if r == self.lvm_shell.stdout.fileno():
stdout += LVMShellProxy._read(self.lvm_shell.stdout)
elif r == self.report_stream.fileno():
report += LVMShellProxy._read(self.report_stream)
elif r == self.lvm_shell.stderr.fileno():
stderr += LVMShellProxy._read(self.lvm_shell.stderr)
# Check to see if the lvm process died on us
if self.lvm_shell.poll():
raise Exception(self.lvm_shell.returncode, "%s" % stderr)
if stdout.endswith(SHELL_PROMPT):
if no_output:
keep_reading = False
else:
cur_report_len = len(report)
if cur_report_len != 0:
# Only bother to parse if we have more data
if prev_report_len != cur_report_len:
prev_report_len = cur_report_len
# Parse the JSON if it's good we are done,
# if not we will try to read some more.
try:
report_json = json.loads(report)
keep_reading = False
except ValueError:
pass
if keep_reading:
extra_passes -= 1
if extra_passes <= 0:
if len(report):
raise ValueError("Invalid json: %s" %
report)
else:
raise ValueError(
"lvm returned no JSON output!")
except IOError as ioe:
log_debug(str(ioe))
tmp = self.lvm_shell.stdout.read()
if tmp:
stdout += tmp.decode("utf-8")
except IOError:
# nothing written yet
pass
return stdout, report_json, stderr
# strip the prompt from the STDOUT before returning and grab the exit
# code if it's available
m = self.re.match(stdout)
if m:
prev_ec = int(m.group(2))
strip_idx = -1 * len(m.group(1))
else:
strip_idx = -1 * len(SHELL_PROMPT)
return stdout[:strip_idx], prev_ec
def _read_line(self):
while True:
try:
tmp = self.lvm_shell.stdout.readline()
if tmp:
return tmp.decode("utf-8")
except IOError:
pass
def _discard_echo(self, expected):
line = ""
while line != expected:
# GNU readline inserts some interesting characters at times...
line += self._read_line().replace(' \r', '')
def _write_cmd(self, cmd):
cmd_bytes = bytes(cmd, "utf-8")
@@ -124,88 +81,39 @@ class LVMShellProxy(object):
assert (num_written == len(cmd_bytes))
self.lvm_shell.stdin.flush()
@staticmethod
def _make_non_block(stream):
flags = fcntl(stream, F_GETFL)
fcntl(stream, F_SETFL, flags | os.O_NONBLOCK)
def _lvm_echos(self):
echo = False
cmd = "version\n"
self._write_cmd(cmd)
line = self._read_line()
if line == cmd:
echo = True
self._read_until_prompt()
return echo
def __init__(self):
# Create a temp directory
tmp_dir = tempfile.mkdtemp(prefix="lvmdbus_")
tmp_file = "%s/lvmdbus_report" % (tmp_dir)
try:
# Lets create fifo for the report output
os.mkfifo(tmp_file, 0o600)
except FileExistsError:
pass
# We have to open non-blocking as the other side isn't open until
# we actually fork the process.
self.report_fd = os.open(tmp_file, os.O_NONBLOCK)
self.report_stream = os.fdopen(self.report_fd, 'rb', 0)
# Setup the environment for using our own socket for reporting
local_env = copy.deepcopy(os.environ)
local_env["LVM_REPORT_FD"] = "32"
local_env["LVM_COMMAND_PROFILE"] = "lvmdbusd"
# Disable the abort logic if lvm logs too much, which easily happens
# when utilizing the lvm shell.
local_env["LVM_LOG_FILE_MAX_LINES"] = "0"
self.re = re.compile(".*(\[(-?[0-9]+)\] lvm> $)", re.DOTALL)
# run the lvm shell
self.lvm_shell = subprocess.Popen(
[LVM_CMD + " 32>%s" % tmp_file],
stdin=subprocess.PIPE, stdout=subprocess.PIPE, env=local_env,
stderr=subprocess.PIPE, close_fds=True, shell=True)
[LVM_CMD], stdin=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, close_fds=True)
flags = fcntl(self.lvm_shell.stdout, F_GETFL)
fcntl(self.lvm_shell.stdout, F_SETFL, flags | O_NONBLOCK)
flags = fcntl(self.lvm_shell.stderr, F_GETFL)
fcntl(self.lvm_shell.stderr, F_SETFL, flags | O_NONBLOCK)
try:
LVMShellProxy._make_non_block(self.lvm_shell.stdout)
LVMShellProxy._make_non_block(self.lvm_shell.stderr)
# wait for the first prompt
self._read_until_prompt()
# wait for the first prompt
errors = self._read_until_prompt(no_output=True)[2]
if errors and len(errors):
raise RuntimeError(errors)
except:
raise
finally:
# These will get deleted when the FD count goes to zero so we
# can be sure to clean up correctly no matter how we finish
os.unlink(tmp_file)
os.rmdir(tmp_dir)
def get_error_msg(self):
# We got an error, lets go fetch the error message
self._write_cmd('lastlog\n')
# read everything from the STDOUT to the next prompt
stdout, report_json, stderr = self._read_until_prompt()
if 'log' in report_json:
error_msg = ""
# Walk the entire log array and build an error string
for log_entry in report_json['log']:
if log_entry['log_type'] == "error":
if error_msg:
error_msg += ', ' + log_entry['log_message']
else:
error_msg = log_entry['log_message']
return error_msg
return 'No error reason provided! (missing "log" section)'
# Check to see if the version of LVM we are using is running with
# gnu readline which will echo our writes from stdin to stdout
self.echo = self._lvm_echos()
def call_lvm(self, argv, debug=False):
rc = 1
error_msg = ""
if self.lvm_shell.poll():
raise Exception(
self.lvm_shell.returncode,
"Underlying lvm shell process is not present!")
# create the command string
cmd = " ".join(_quote_arg(arg) for arg in argv)
cmd += "\n"
@@ -213,34 +121,46 @@ class LVMShellProxy(object):
# run the command by writing it to the shell's STDIN
self._write_cmd(cmd)
# read everything from the STDOUT to the next prompt
stdout, report_json, stderr = self._read_until_prompt()
# If lvm is utilizing gnu readline, it echos stdin to stdout
if self.echo:
self._discard_echo(cmd)
# Parse the report to see what happened
if 'log' in report_json:
if report_json['log'][-1:][0]['log_ret_code'] == '1':
rc = 0
# read everything from the STDOUT to the next prompt
stdout, exit_code = self._read_until_prompt()
# read everything from STDERR if there's something (we waited for the
# prompt on STDOUT so there should be all or nothing at this point on
# STDERR)
stderr = None
try:
t_error = self.lvm_shell.stderr.read()
if t_error:
stderr = t_error.decode("utf-8")
except IOError:
# nothing on STDERR
pass
if exit_code is not None:
rc = exit_code
else:
# LVM does write to stderr even when it did complete successfully,
# so without having the exit code in the prompt we can never be
# sure.
if stderr:
rc = 1
else:
error_msg = self.get_error_msg()
rc = 0
if debug or rc != 0:
log_error(('CMD: %s' % cmd))
log_error(("EC = %d" % rc))
log_error(("ERROR_MSG=\n %s\n" % error_msg))
log_error(("STDOUT=\n %s\n" % stdout))
log_error(("STDERR=\n %s\n" % stderr))
return rc, report_json, error_msg
def exit_shell(self):
try:
self._write_cmd('exit\n')
except Exception as e:
log_error(str(e))
return (rc, stdout, stderr)
def __del__(self):
try:
self.lvm_shell.terminate()
except:
pass
self.lvm_shell.terminate()
if __name__ == "__main__":
@@ -250,18 +170,15 @@ if __name__ == "__main__":
while in_line:
in_line = input("lvm> ")
if in_line:
start = time.time()
ret, out, err = shell.call_lvm(in_line.split())
end = time.time()
print(("RC: %d" % ret))
ret, out, err, = shell.call_lvm(in_line.split())
print(("RET: %d" % ret))
print(("OUT:\n%s" % out))
print(("ERR:\n%s" % err))
print("Command = %f seconds" % (end - start))
except KeyboardInterrupt:
pass
except EOFError:
pass
except Exception:
traceback.print_exc(file=sys.stdout)
finally:
print()

View File

@@ -12,15 +12,17 @@
from collections import OrderedDict
import pprint as prettyprint
import os
import sys
from lvmdbusd import cmdhandler
from lvmdbusd.utils import log_debug, log_error
try:
from . import cmdhandler
from .utils import log_debug
except SystemError:
import cmdhandler
from utils import log_debug
class DataStore(object):
def __init__(self, usejson=True):
def __init__(self):
self.pvs = {}
self.vgs = {}
self.lvs = {}
@@ -38,11 +40,6 @@ class DataStore(object):
# self.refresh()
self.num_refreshes = 0
if usejson:
self.json = cmdhandler.supports_json()
else:
self.json = usejson
@staticmethod
def _insert_record(table, key, record, allowed_multiple):
if key in table:
@@ -69,7 +66,18 @@ class DataStore(object):
table[key] = record
@staticmethod
def _pvs_parse_common(c_pvs, c_pvs_in_vgs, c_lookup):
def _parse_pvs(_pvs):
pvs = sorted(_pvs, key=lambda pk: pk['pv_name'])
c_pvs = OrderedDict()
c_lookup = {}
c_pvs_in_vgs = {}
for p in pvs:
DataStore._insert_record(
c_pvs, p['pv_uuid'], p,
['pv_seg_start', 'pvseg_size', 'segtype'])
for p in c_pvs.values():
# Capture which PVs are associated with which VG
if p['vg_uuid'] not in c_pvs_in_vgs:
@@ -82,61 +90,6 @@ class DataStore(object):
# Lookup for translating between /dev/<name> and pv uuid
c_lookup[p['pv_name']] = p['pv_uuid']
@staticmethod
def _parse_pvs(_pvs):
pvs = sorted(_pvs, key=lambda pk: pk['pv_name'])
c_pvs = OrderedDict()
c_lookup = {}
c_pvs_in_vgs = {}
for p in pvs:
DataStore._insert_record(
c_pvs, p['pv_uuid'], p,
['pvseg_start', 'pvseg_size', 'segtype'])
DataStore._pvs_parse_common(c_pvs, c_pvs_in_vgs, c_lookup)
return c_pvs, c_lookup, c_pvs_in_vgs
@staticmethod
def _parse_pvs_json(_all):
c_pvs = OrderedDict()
c_lookup = {}
c_pvs_in_vgs = {}
# Each item item in the report is a collection of information pertaining
# to the vg
for r in _all['report']:
tmp_pv = []
# Get the pv data for this VG.
if 'pv' in r:
tmp_pv.extend(r['pv'])
# Sort them
sorted_tmp_pv = sorted(tmp_pv, key=lambda pk: pk['pv_name'])
# Add them to result set
for p in sorted_tmp_pv:
c_pvs[p['pv_uuid']] = p
if 'pvseg' in r:
for s in r['pvseg']:
r = c_pvs[s['pv_uuid']]
r.setdefault('pvseg_start', []).append(s['pvseg_start'])
r.setdefault('pvseg_size', []).append(s['pvseg_size'])
r.setdefault('segtype', []).append(s['segtype'])
# TODO: Remove this bug work around when we have orphan segs.
for i in c_pvs.values():
if 'pvseg_start' not in i:
i['pvseg_start'] = '0'
i['pvseg_size'] = i['pv_pe_count']
i['segtype'] = 'free'
DataStore._pvs_parse_common(c_pvs, c_pvs_in_vgs, c_lookup)
return c_pvs, c_lookup, c_pvs_in_vgs
@staticmethod
@@ -153,31 +106,20 @@ class DataStore(object):
return c_vgs, c_lookup
@staticmethod
def _parse_vgs_json(_all):
def _parse_lvs(_lvs):
lvs = sorted(_lvs, key=lambda vk: vk['lv_name'])
tmp_vg = []
for r in _all['report']:
# Get the pv data for this VG.
if 'vg' in r:
tmp_vg.extend(r['vg'])
c_lvs = OrderedDict()
c_lvs_in_vgs = {}
c_lvs_hidden = {}
c_lv_full_lookup = {}
# Sort for consistent output, however this is optional
vgs = sorted(tmp_vg, key=lambda vk: vk['vg_name'])
c_vgs = OrderedDict()
c_lookup = {}
for i in vgs:
c_lookup[i['vg_name']] = i['vg_uuid']
c_vgs[i['vg_uuid']] = i
return c_vgs, c_lookup
@staticmethod
def _parse_lvs_common(c_lvs, c_lv_full_lookup):
c_lvs_in_vgs = OrderedDict()
c_lvs_hidden = OrderedDict()
for i in lvs:
full_name = "%s/%s" % (i['vg_name'], i['lv_name'])
c_lv_full_lookup[full_name] = i['lv_uuid']
DataStore._insert_record(
c_lvs, i['lv_uuid'], i,
['seg_pe_ranges', 'segtype'])
for i in c_lvs.values():
if i['vg_uuid'] not in c_lvs_in_vgs:
@@ -207,48 +149,6 @@ class DataStore(object):
return c_lvs, c_lvs_in_vgs, c_lvs_hidden, c_lv_full_lookup
@staticmethod
def _parse_lvs(_lvs):
lvs = sorted(_lvs, key=lambda vk: vk['lv_name'])
c_lvs = OrderedDict()
c_lv_full_lookup = OrderedDict()
for i in lvs:
full_name = "%s/%s" % (i['vg_name'], i['lv_name'])
c_lv_full_lookup[full_name] = i['lv_uuid']
DataStore._insert_record(
c_lvs, i['lv_uuid'], i,
['seg_pe_ranges', 'segtype'])
return DataStore._parse_lvs_common(c_lvs, c_lv_full_lookup)
@staticmethod
def _parse_lvs_json(_all):
c_lvs = OrderedDict()
c_lv_full_lookup = {}
# Each item item in the report is a collection of information pertaining
# to the vg
for r in _all['report']:
# Get the lv data for this VG.
if 'lv' in r:
# Add them to result set
for i in r['lv']:
full_name = "%s/%s" % (i['vg_name'], i['lv_name'])
c_lv_full_lookup[full_name] = i['lv_uuid']
c_lvs[i['lv_uuid']] = i
# Add in the segment data
if 'seg' in r:
for s in r['seg']:
r = c_lvs[s['lv_uuid']]
r.setdefault('seg_pe_ranges', []).append(s['seg_pe_ranges'])
r.setdefault('segtype', []).append(s['segtype'])
return DataStore._parse_lvs_common(c_lvs, c_lv_full_lookup)
@staticmethod
def _make_list(l):
if not isinstance(l, list):
@@ -372,27 +272,19 @@ class DataStore(object):
:param log Add debug log entry/exit messages
:return: None
"""
self.num_refreshes += 1
if log:
log_debug("lvmdb - refresh entry")
self.num_refreshes += 1
# Grab everything first then parse it
if self.json:
# Do a single lvm retrieve for everything in json
a = cmdhandler.lvm_full_report_json()
_raw_pvs = cmdhandler.pv_retrieve_with_segs()
_raw_vgs = cmdhandler.vg_retrieve(None)
_raw_lvs = cmdhandler.lv_retrieve_with_segments()
_pvs, _pvs_lookup, _pvs_in_vgs = self._parse_pvs_json(a)
_vgs, _vgs_lookup = self._parse_vgs_json(a)
_lvs, _lvs_in_vgs, _lvs_hidden, _lvs_lookup = self._parse_lvs_json(a)
else:
_raw_pvs = cmdhandler.pv_retrieve_with_segs()
_raw_vgs = cmdhandler.vg_retrieve(None)
_raw_lvs = cmdhandler.lv_retrieve_with_segments()
_pvs, _pvs_lookup, _pvs_in_vgs = self._parse_pvs(_raw_pvs)
_vgs, _vgs_lookup = self._parse_vgs(_raw_vgs)
_lvs, _lvs_in_vgs, _lvs_hidden, _lvs_lookup = self._parse_lvs(_raw_lvs)
_pvs, _pvs_lookup, _pvs_in_vgs = self._parse_pvs(_raw_pvs)
_vgs, _vgs_lookup = self._parse_vgs(_raw_vgs)
_lvs, _lvs_in_vgs, _lvs_hidden, _lvs_lookup = self._parse_lvs(_raw_lvs)
# Set all
self.pvs = _pvs
@@ -418,20 +310,9 @@ class DataStore(object):
else:
rc = []
for s in pv_name:
# Ths user could be using a symlink instead of the actual
# block device, make sure we are using actual block device file
# if the pv name isn't in the lookup
if s not in self.pv_path_to_uuid:
s = os.path.realpath(s)
rc.append(self.pvs[self.pv_path_to_uuid[s]])
return rc
def pv_missing(self, pv_uuid):
if pv_uuid in self.pvs:
if self.pvs[pv_uuid]['pv_missing'] == '':
return False
return True
def fetch_vgs(self, vg_name):
if not vg_name:
return self.vgs.values()
@@ -451,18 +332,18 @@ class DataStore(object):
rc.append(self.lvs[self.lv_full_name_to_uuid[s]])
return rc
except KeyError as ke:
log_error("Key %s not found!" % (str(lv_names)))
log_error("lv name to uuid lookup")
print("Key %s not found!" % (str(lv_names)))
print("lv name to uuid lookup")
for keys in sorted(self.lv_full_name_to_uuid.keys()):
log_error("%s" % (keys))
log_error("lvs entries by uuid")
print("%s" % (keys))
print("lvs entries by uuid")
for keys in sorted(self.lvs.keys()):
log_error("%s" % (keys))
print("%s" % (keys))
raise ke
def pv_pe_segments(self, pv_uuid):
pv = self.pvs[pv_uuid]
return list(zip(pv['pvseg_start'], pv['pvseg_size']))
return list(zip(pv['pv_seg_start'], pv['pvseg_size']))
def pv_contained_lv(self, pv_device):
rc = []
@@ -503,21 +384,12 @@ class DataStore(object):
if __name__ == "__main__":
pp = prettyprint.PrettyPrinter(indent=4)
use_json = False
if len(sys.argv) != 1:
print(len(sys.argv))
use_json = True
ds = DataStore(use_json)
ds = DataStore()
ds.refresh()
print("PVS")
for v in ds.pvs.values():
pp.pprint(v)
print('PV missing is %s' % ds.pv_missing(v['pv_uuid']))
print("VGS")
for v in ds.vgs.values():
pp.pprint(v)

View File

@@ -10,7 +10,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys
from lvmdbusd import main
import lvmdbusd
if __name__ == '__main__':
sys.exit(main())
sys.exit(lvmdbusd.main())

View File

@@ -10,26 +10,24 @@
from . import cfg
from . import objectmanager
from . import utils
from .cfg import BUS_NAME, BASE_INTERFACE, BASE_OBJ_PATH, MANAGER_OBJ_PATH
from .cfg import BASE_INTERFACE, BASE_OBJ_PATH, MANAGER_OBJ_PATH
import threading
from . import cmdhandler
import time
import signal
import dbus
import dbus.mainloop.glib
from . import lvmdb
# noinspection PyUnresolvedReferences
from gi.repository import GLib
from .fetch import StateUpdate
from gi.repository import GObject
from .fetch import load
from .manager import Manager
from .background import background_reaper
import traceback
import queue
from . import udevwatch
from .utils import log_debug, log_error
import argparse
import os
import sys
from .cmdhandler import LvmFlightRecorder
from . import udevwatch
from .utils import log_debug
import argparse
class Lvm(objectmanager.ObjectManager):
@@ -39,77 +37,49 @@ class Lvm(objectmanager.ObjectManager):
def process_request():
while cfg.run.value != 0:
# noinspection PyBroadException
try:
req = cfg.worker_q.get(True, 5)
start = cfg.db.num_refreshes
log_debug(
"Running method: %s with args %s" %
(str(req.method), str(req.arguments)))
req.run_cmd()
log_debug("Method complete ")
end = cfg.db.num_refreshes
if end - start > 1:
log_debug(
"Inspect method %s for too many refreshes" %
(str(req.method)))
log_debug("Complete ")
except queue.Empty:
pass
except Exception:
st = traceback.format_exc()
utils.log_error("process_request exception: \n%s" % st)
def check_bb_size(value):
v = int(value)
if v < 0:
raise argparse.ArgumentTypeError(
"positive integers only ('%s' invalid)" % value)
return v
traceback.print_exc(file=sys.stdout)
pass
def main():
start = time.time()
# Add simple command line handling
parser = argparse.ArgumentParser()
parser.add_argument(
"--udev", action='store_true',
help="Use udev for updating state",
default=False,
dest='use_udev')
parser.add_argument(
"--debug", action='store_true',
help="Dump debug messages", default=False,
dest='debug')
parser.add_argument(
"--nojson", action='store_false',
help="Do not use LVM JSON output (disables lvmshell)", default=True,
dest='use_json')
parser.add_argument(
"--lvmshell", action='store_true',
help="Use the lvm shell, not fork & exec lvm",
default=False,
dest='use_lvm_shell')
parser.add_argument(
"--blackboxsize",
help="Size of the black box flight recorder, 0 to disable",
default=10,
type=check_bb_size,
dest='bb_size')
parser.add_argument("--udev", action='store_true',
help="Use udev for updating state", default=False,
dest='use_udev')
parser.add_argument("--debug", action='store_true',
help="Dump debug messages", default=False,
dest='debug')
use_session = os.getenv('LVMDBUSD_USE_SESSION', False)
args = parser.parse_args()
# Ensure that we get consistent output for parsing stdout/stderr
os.environ["LC_ALL"] = "C"
cfg.args = parser.parse_args()
# We create a flight recorder in cmdhandler too, but we replace it here
# as the user may be specifying a different size. The default one in
# cmdhandler is for when we are running other code with a different main.
cfg.blackbox = LvmFlightRecorder(cfg.args.bb_size)
if cfg.args.use_lvm_shell and not cfg.args.use_json:
log_error("You cannot specify --lvmshell and --nojson")
sys.exit(1)
cfg.DEBUG = args.debug
# List of threads that we start up
thread_list = []
start = time.time()
# Install signal handlers
for s in [signal.SIGHUP, signal.SIGINT]:
try:
@@ -118,62 +88,53 @@ def main():
pass
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
GObject.threads_init()
dbus.mainloop.glib.threads_init()
cmdhandler.set_execution(cfg.args.use_lvm_shell)
if use_session:
cfg.bus = dbus.SessionBus()
else:
cfg.bus = dbus.SystemBus()
cfg.bus = dbus.SystemBus()
# The base name variable needs to exist for things to work.
# noinspection PyUnusedLocal
base_name = dbus.service.BusName(BUS_NAME, cfg.bus)
base_name = dbus.service.BusName(BASE_INTERFACE, cfg.bus)
cfg.om = Lvm(BASE_OBJ_PATH)
cfg.om.register_object(Manager(MANAGER_OBJ_PATH))
cfg.db = lvmdb.DataStore(cfg.args.use_json)
cfg.load = load
# Using a thread to process requests, we cannot hang the dbus library
# thread that is handling the dbus interface
cfg.db = lvmdb.DataStore()
# Start up thread to monitor pv moves
thread_list.append(
threading.Thread(target=background_reaper, name="pv_move_reaper"))
# Using a thread to process requests.
thread_list.append(threading.Thread(target=process_request))
# Have a single thread handling updating lvm and the dbus model so we
# don't have multiple threads doing this as the same time
updater = StateUpdate()
thread_list.append(updater.thread)
cfg.load(refresh=False, emit_signal=False)
cfg.loop = GObject.MainLoop()
cfg.load = updater.load
cfg.event = updater.event
cfg.loop = GLib.MainLoop()
for thread in thread_list:
thread.damon = True
thread.start()
# Add udev watching
if cfg.args.use_udev:
log_debug('Utilizing udev to trigger updates')
# In all cases we are going to monitor for udev until we get an
# ExternalEvent. In the case where we get an external event and the user
# didn't specify --udev we will stop monitoring udev
udevwatch.add()
for process in thread_list:
process.damon = True
process.start()
end = time.time()
log_debug(
'Service ready! total time= %.4f, lvm time= %.4f count= %d' %
'Service ready! total time= %.2f, lvm time= %.2f count= %d' %
(end - start, cmdhandler.total_time, cmdhandler.total_count),
'bg_black', 'fg_light_green')
# Add udev watching
if args.use_udev:
log_debug('Utilizing udev to trigger updates')
udevwatch.add()
try:
if cfg.run.value != 0:
cfg.loop.run()
udevwatch.remove()
for thread in thread_list:
thread.join()
if args.use_udev:
udevwatch.remove()
for process in thread_list:
process.join()
except KeyboardInterrupt:
utils.handler(signal.SIGINT, None)
return 0

View File

@@ -14,13 +14,14 @@ from .cfg import MANAGER_INTERFACE
import dbus
from . import cfg
from . import cmdhandler
from .fetch import load_pvs, load_vgs
from .request import RequestEntry
from . import udevwatch
from .refresh import event_add
# noinspection PyPep8Naming
class Manager(AutomatedProperties):
_Version_meta = ("s", MANAGER_INTERFACE)
_Version_meta = ("t", MANAGER_INTERFACE)
def __init__(self, object_path):
super(Manager, self).__init__(object_path)
@@ -28,31 +29,31 @@ class Manager(AutomatedProperties):
@property
def Version(self):
return dbus.String('1.0.0')
@staticmethod
def handle_execute(rc, out, err):
if rc == 0:
cfg.load()
else:
# Need to work on error handling, need consistent
raise dbus.exceptions.DBusException(
MANAGER_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
return '1.0.0'
@staticmethod
def _pv_create(device, create_options):
# Check to see if we are already trying to create a PV for an existing
# PV
pv = cfg.om.get_object_path_by_uuid_lvm_id(device, device)
pv = cfg.om.get_object_path_by_lvm_id(
device, device, None, False)
if pv:
raise dbus.exceptions.DBusException(
MANAGER_INTERFACE, "PV Already exists!")
created_pv = []
rc, out, err = cmdhandler.pv_create(create_options, [device])
Manager.handle_execute(rc, out, err)
return cfg.om.get_object_path_by_lvm_id(device)
if rc == 0:
pvs = load_pvs([device], emit_signal=True)[0]
for p in pvs:
created_pv = p.dbus_object_path()
else:
raise dbus.exceptions.DBusException(
MANAGER_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
return created_pv
@dbus.service.method(
dbus_interface=MANAGER_INTERFACE,
@@ -79,8 +80,20 @@ class Manager(AutomatedProperties):
MANAGER_INTERFACE, 'object path = %s not found' % p)
rc, out, err = cmdhandler.vg_create(create_options, pv_devices, name)
Manager.handle_execute(rc, out, err)
return cfg.om.get_object_path_by_lvm_id(name)
created_vg = "/"
if rc == 0:
vgs = load_vgs([name], emit_signal=True)[0]
for v in vgs:
created_vg = v.dbus_object_path()
# Update the PVS
load_pvs(refresh=True, emit_signal=True, cache_refresh=False)
else:
raise dbus.exceptions.DBusException(
MANAGER_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
return created_vg
@dbus.service.method(
dbus_interface=MANAGER_INTERFACE,
@@ -101,10 +114,6 @@ class Manager(AutomatedProperties):
# This is a diagnostic and should not be run in normal operation, so
# lets remove the log entries for refresh as it's implied.
# Run an internal diagnostic on the object manager look up tables
lc = cfg.om.validate_lookups()
rc = cfg.load(log=False)
if rc != 0:
@@ -112,7 +121,7 @@ class Manager(AutomatedProperties):
'bg_black', 'fg_light_red')
else:
utils.log_debug('Manager.Refresh - exit %d' % (rc))
return rc + lc
return rc
@dbus.service.method(
dbus_interface=MANAGER_INTERFACE,
@@ -150,44 +159,29 @@ class Manager(AutomatedProperties):
:param key: The lookup value
:return: Return the object path. If object not found you will get '/'
"""
p = cfg.om.get_object_path_by_uuid_lvm_id(key, key)
p = cfg.om.get_object_path_by_lvm_id(
key, key, gen_new=False)
if p:
return p
return '/'
@staticmethod
def _use_lvm_shell(yes_no):
return dbus.Boolean(cmdhandler.set_execution(yes_no))
@dbus.service.method(
dbus_interface=MANAGER_INTERFACE,
in_signature='b', out_signature='b',
async_callbacks=('cb', 'cbe'))
def UseLvmShell(self, yes_no, cb, cbe):
in_signature='b')
def UseLvmShell(self, yes_no):
"""
Allow the client to enable/disable lvm shell, used for testing
:param yes_no:
:param cb: dbus python call back parameter, not client visible
:param cbe: dbus python error call back parameter, not client visible
:return: Nothing
"""
r = RequestEntry(-1, Manager._use_lvm_shell, (yes_no,), cb, cbe, False)
cfg.worker_q.put(r)
cmdhandler.set_execution(yes_no)
@dbus.service.method(
dbus_interface=MANAGER_INTERFACE,
in_signature='s', out_signature='i')
def ExternalEvent(self, command):
# If a user didn't explicitly specify udev, we will turn it off now.
if not cfg.args.use_udev:
if udevwatch.remove():
utils.log_debug("ExternalEvent received, disabling "
"udev monitoring")
# We are dependent on external events now to stay current!
cfg.ee = True
utils.log_debug("ExternalEvent %s" % command)
cfg.event()
event_add((command,))
return dbus.Int32(0)
@staticmethod
@@ -197,8 +191,15 @@ class Manager(AutomatedProperties):
activate, cache, device_path,
major_minor, scan_options)
Manager.handle_execute(rc, out, err)
return '/'
if rc == 0:
# This could potentially change the state quite a bit, so lets
# update everything to be safe
cfg.load()
return '/'
else:
raise dbus.exceptions.DBusException(
MANAGER_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
@dbus.service.method(
dbus_interface=MANAGER_INTERFACE,

View File

@@ -11,10 +11,8 @@ import sys
import threading
import traceback
import dbus
import os
import copy
from . import cfg
from .utils import log_debug, pv_obj_path_generate, log_error
from .utils import log_debug
from .automatedproperties import AutomatedProperties
@@ -71,37 +69,12 @@ class ObjectManager(AutomatedProperties):
log_debug(('SIGNAL: InterfacesRemoved(%s, %s)' %
(str(object_path), str(interface_list))))
def validate_lookups(self):
with self.rlock:
tmp_lookups = copy.deepcopy(self._id_to_object_path)
# iterate over all we know, removing from the copy. If all is well
# we will have zero items left over
for path, md in self._objects.items():
obj, lvm_id, uuid = md
if lvm_id:
assert path == tmp_lookups[lvm_id]
del tmp_lookups[lvm_id]
if uuid:
assert path == tmp_lookups[uuid]
del tmp_lookups[uuid]
rc = len(tmp_lookups)
if rc:
# Error condition
log_error("_id_to_object_path has extraneous lookups!")
for key, path in tmp_lookups.items():
log_error("Key= %s, path= %s" % (key, path))
return rc
def _lookup_add(self, obj, path, lvm_id, uuid):
"""
Store information about what we added to the caches so that we
can remove it cleanly
:param obj: The dbus object we are storing
:param lvm_id: The lvm id for the asset
:param lvm_id: The user name for the asset
:param uuid: The uuid for the asset
:return:
"""
@@ -111,12 +84,7 @@ class ObjectManager(AutomatedProperties):
self._lookup_remove(path)
self._objects[path] = (obj, lvm_id, uuid)
# Make sure we have one or the other
assert lvm_id or uuid
if lvm_id:
self._id_to_object_path[lvm_id] = path
self._id_to_object_path[lvm_id] = path
if uuid:
self._id_to_object_path[uuid] = path
@@ -125,13 +93,8 @@ class ObjectManager(AutomatedProperties):
# Note: Only called internally, lock implied
if obj_path in self._objects:
(obj, lvm_id, uuid) = self._objects[obj_path]
if lvm_id in self._id_to_object_path:
del self._id_to_object_path[lvm_id]
if uuid in self._id_to_object_path:
del self._id_to_object_path[uuid]
del self._id_to_object_path[lvm_id]
del self._id_to_object_path[uuid]
del self._objects[obj_path]
def lookup_update(self, dbus_obj, new_uuid, new_lvm_id):
@@ -160,8 +123,8 @@ class ObjectManager(AutomatedProperties):
with self.rlock:
path, props = dbus_object.emit_data()
# print('Registering object path %s for %s' %
# (path, dbus_object.lvm_id))
# print 'Registering object path %s for %s' %
# (path, dbus_object.lvm_id)
# We want fast access to the object by a number of different ways
# so we use multiple hashs with different keys
@@ -209,7 +172,7 @@ class ObjectManager(AutomatedProperties):
def get_object_by_uuid_lvm_id(self, uuid, lvm_id):
with self.rlock:
return self.get_object_by_path(
self.get_object_path_by_uuid_lvm_id(uuid, lvm_id))
self.get_object_path_by_lvm_id(uuid, lvm_id, None, False))
def get_object_by_lvm_id(self, lvm_id):
"""
@@ -221,132 +184,74 @@ class ObjectManager(AutomatedProperties):
return self.get_object_by_path(self._id_to_object_path[lvm_id])
return None
def get_object_path_by_lvm_id(self, lvm_id):
"""
Given an lvm identifier, return the object path for it
:param lvm_id: The lvm identifier
:return: Object path or '/' if not found
"""
with self.rlock:
if lvm_id in self._id_to_object_path:
return self._id_to_object_path[lvm_id]
return '/'
def _uuid_verify(self, path, uuid, lvm_id):
def _uuid_verify(self, path, lvm_id, uuid):
"""
Ensure uuid is present for a successful lvm_id lookup
NOTE: Internal call, assumes under object manager lock
:param path: Path to object we looked up
:param uuid: lvm uuid to verify
:param lvm_id: lvm_id used to find object
:param uuid: lvm uuid to verify
:return: None
"""
# This gets called when we found an object based on lvm_id, ensure
# uuid is correct too, as they can change. There is no durable
# non-changeable name in lvm
# uuid is correct too, as they can change
if lvm_id != uuid:
if uuid and uuid not in self._id_to_object_path:
if uuid not in self._id_to_object_path:
obj = self.get_object_by_path(path)
self._lookup_add(obj, path, lvm_id, uuid)
def _lvm_id_verify(self, path, uuid, lvm_id):
def get_object_path_by_lvm_id(self, uuid, lvm_id, path_create=None,
gen_new=True):
"""
Ensure lvm_id is present for a successful uuid lookup
NOTE: Internal call, assumes under object manager lock
:param path: Path to object we looked up
:param uuid: uuid used to find object
:param lvm_id: lvm_id to verify
:return: None
"""
# This gets called when we found an object based on uuid, ensure
# lvm_id is correct too, as they can change. There is no durable
# non-changeable name in lvm
if lvm_id != uuid:
if lvm_id and lvm_id not in self._id_to_object_path:
obj = self.get_object_by_path(path)
self._lookup_add(obj, path, lvm_id, uuid)
def _id_lookup(self, the_id):
path = None
if the_id:
# The _id_to_object_path contains hash keys for everything, so
# uuid and lvm_id
if the_id in self._id_to_object_path:
path = self._id_to_object_path[the_id]
else:
if "/" in the_id:
if the_id.startswith('/'):
# We could have a pv device path lookup that failed,
# lets try canonical form and try again.
canonical = os.path.realpath(the_id)
if canonical in self._id_to_object_path:
path = self._id_to_object_path[canonical]
else:
vg, lv = the_id.split("/", 1)
int_lvm_id = vg + "/" + ("[%s]" % lv)
if int_lvm_id in self._id_to_object_path:
path = self._id_to_object_path[int_lvm_id]
return path
def get_object_path_by_uuid_lvm_id(self, uuid, lvm_id, path_create=None):
"""
For a given lvm asset return the dbus object path registered for it.
This method first looks up by uuid and then by lvm_id. You
can search by just one by setting uuid == lvm_id (uuid or lvm_id).
If the object is not found and path_create is a not None, the
path_create function will be called to create a new object path and
register it with the object manager for the specified uuid & lvm_id.
Note: If path create is not None, uuid and lvm_id cannot be equal
:param uuid: The uuid for the lvm object we are searching for
:param lvm_id: The lvm name (eg. pv device path, vg name, lv full name)
:param path_create: If not None, create the path using this function if
we fail to find the object by uuid or lvm_id.
:returns None if lvm asset not found and path_create == None otherwise
a valid dbus object path
For a given lvm asset return the dbus object registered to it. If the
object is not found and gen_new == True and path_create is a valid
function we will create a new path, register it and return it.
:param uuid: The uuid for the lvm object
:param lvm_id: The lvm name
:param path_create: If true create an object path if not found
:param gen_new: The function used to create the new path
"""
with self.rlock:
assert lvm_id
assert uuid
if path_create:
assert uuid != lvm_id
if gen_new:
assert path_create
# Check for Manager.LookUpByLvmId query, we cannot
# check/verify/update the uuid and lvm_id lookups so don't!
if uuid == lvm_id:
path = self._id_lookup(lvm_id)
path = None
if lvm_id in self._id_to_object_path:
path = self._id_to_object_path[lvm_id]
self._uuid_verify(path, lvm_id, uuid)
return path
if "/" in lvm_id:
vg, lv = lvm_id.split("/", 1)
int_lvm_id = vg + "/" + ("[%s]" % lv)
if int_lvm_id in self._id_to_object_path:
path = self._id_to_object_path[int_lvm_id]
self._uuid_verify(path, int_lvm_id, uuid)
return path
if uuid and uuid in self._id_to_object_path:
# If we get here it indicates that we found the object, but
# the lvm_id lookup failed. In the case of a rename, the uuid
# will be correct, but the lvm_id will be wrong and vise versa.
# If the lvm_id does not equal the uuid, lets fix up the table
# so that lookups will be handled correctly.
path = self._id_to_object_path[uuid]
# In some cases we are looking up by one or the other, don't
# update when they are the same.
if uuid != lvm_id:
obj = self.get_object_by_path(path)
self._lookup_add(obj, path, lvm_id, uuid)
else:
# We have a uuid and a lvm_id we can do sanity checks to ensure
# that they are consistent
if gen_new:
path = path_create()
self._lookup_add(None, path, lvm_id, uuid)
# If a PV is missing it's device path is '[unknown]' or some
# other text derivation of unknown. When we find that a PV is
# missing we will clear out the lvm_id as it's likely not unique
# and thus not useful and potentially harmful for lookups.
if path_create == pv_obj_path_generate and \
cfg.db.pv_missing(uuid):
lvm_id = None
# Lets check for the uuid first
path = self._id_lookup(uuid)
if path:
# Verify the lvm_id is sane
self._lvm_id_verify(path, uuid, lvm_id)
else:
# Unable to find by UUID, lets lookup by lvm_id
path = self._id_lookup(lvm_id)
if path:
# Verify the uuid is sane
self._uuid_verify(path, uuid, lvm_id)
else:
# We have exhausted all lookups, let's create if we can
if path_create:
path = path_create()
self._lookup_add(None, path, lvm_id, uuid)
# print('get_object_path_by_lvm_id(%s, %s, %s, %s: return %s' %
# (uuid, lvm_id, str(path_create), str(gen_new), path))
# pprint('get_object_path_by_lvm_id(%s, %s, %s, %s: return %s' %
# (uuid, lvm_id, str(path_create), str(gen_new), path))
return path

View File

@@ -55,6 +55,9 @@ class PvState(State):
return self.lvm_path
def _lv_object_list(self, vg_name):
# Note we are returning "a(oa(tts))"
rc = []
if vg_name:
for lv in sorted(cfg.db.pv_contained_lv(self.lvm_id)):
@@ -62,11 +65,11 @@ class PvState(State):
full_name = "%s/%s" % (vg_name, lv_name)
path_create = lv_object_path_method(lv_name, meta)
lv_path = cfg.om.get_object_path_by_uuid_lvm_id(
lv_path = cfg.om.get_object_path_by_lvm_id(
lv_uuid, full_name, path_create)
rc.append((lv_path, segs))
return rc
return dbus.Array(rc, signature="(oa(tts))")
# noinspection PyUnusedLocal,PyPep8Naming
def __init__(self, lvm_path, Uuid, Name,
@@ -80,7 +83,7 @@ class PvState(State):
self.lv = self._lv_object_list(vg_name)
if vg_name:
self.vg_path = cfg.om.get_object_path_by_uuid_lvm_id(
self.vg_path = cfg.om.get_object_path_by_lvm_id(
vg_uuid, vg_name, vg_obj_path_generate)
else:
self.vg_path = '/'
@@ -90,8 +93,8 @@ class PvState(State):
def create_dbus_object(self, path):
if not path:
path = cfg.om.get_object_path_by_uuid_lvm_id(self.Uuid, self.Name,
pv_obj_path_generate)
path = cfg.om.get_object_path_by_lvm_id(self.Uuid, self.Name,
pv_obj_path_generate)
return Pv(path, self)
# noinspection PyMethodMayBeStatic
@@ -135,30 +138,23 @@ class Pv(AutomatedProperties):
def _remove(pv_uuid, pv_name, remove_options):
# Remove the PV, if successful then remove from the model
# Make sure we have a dbus object representing it
Pv.validate_dbus_object(pv_uuid, pv_name)
rc, out, err = cmdhandler.pv_remove(pv_name, remove_options)
Pv.handle_execute(rc, out, err)
return '/'
@staticmethod
def handle_execute(rc, out, err):
if rc == 0:
cfg.load()
else:
# Need to work on error handling, need consistent
raise dbus.exceptions.DBusException(
PV_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
@staticmethod
def validate_dbus_object(pv_uuid, pv_name):
dbo = cfg.om.get_object_by_uuid_lvm_id(pv_uuid, pv_name)
if not dbo:
if dbo:
rc, out, err = cmdhandler.pv_remove(pv_name, remove_options)
if rc == 0:
cfg.om.remove_object(dbo, True)
else:
# Need to work on error handling, need consistent
raise dbus.exceptions.DBusException(
PV_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
PV_INTERFACE,
'PV with uuid %s and name %s not present!' %
(pv_uuid, pv_name))
return dbo
return '/'
@dbus.service.method(
dbus_interface=PV_INTERFACE,
@@ -175,11 +171,22 @@ class Pv(AutomatedProperties):
@staticmethod
def _resize(pv_uuid, pv_name, new_size_bytes, resize_options):
# Make sure we have a dbus object representing it
Pv.validate_dbus_object(pv_uuid, pv_name)
dbo = cfg.om.get_object_by_uuid_lvm_id(pv_uuid, pv_name)
rc, out, err = cmdhandler.pv_resize(pv_name, new_size_bytes,
if dbo:
rc, out, err = cmdhandler.pv_resize(pv_name, new_size_bytes,
resize_options)
Pv.handle_execute(rc, out, err)
if rc == 0:
dbo.refresh()
else:
raise dbus.exceptions.DBusException(
PV_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
PV_INTERFACE,
'PV with uuid %s and name %s not present!' %
(pv_uuid, pv_name))
return '/'
@dbus.service.method(
@@ -197,10 +204,21 @@ class Pv(AutomatedProperties):
@staticmethod
def _allocation_enabled(pv_uuid, pv_name, yes_no, allocation_options):
# Make sure we have a dbus object representing it
Pv.validate_dbus_object(pv_uuid, pv_name)
rc, out, err = cmdhandler.pv_allocatable(
pv_name, yes_no, allocation_options)
Pv.handle_execute(rc, out, err)
dbo = cfg.om.get_object_by_uuid_lvm_id(pv_uuid, pv_name)
if dbo:
rc, out, err = cmdhandler.pv_allocatable(
pv_name, yes_no, allocation_options)
if rc == 0:
cfg.load()
else:
raise dbus.exceptions.DBusException(
PV_INTERFACE, 'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
PV_INTERFACE,
'PV with uuid %s and name %s not present!' %
(pv_uuid, pv_name))
return '/'
@dbus.service.method(
@@ -223,20 +241,26 @@ class Pv(AutomatedProperties):
@property
def PeSegments(self):
if len(self.state.pe_segments):
return dbus.Array(self.state.pe_segments, signature='(tt)')
return self.state.pe_segments
return dbus.Array([], '(tt)')
@property
def Exportable(self):
return dbus.Boolean(self.state.attr[1] == 'x')
if self.state.attr[1] == 'x':
return True
return False
@property
def Allocatable(self):
return dbus.Boolean(self.state.attr[0] == 'a')
if self.state.attr[0] == 'a':
return True
return False
@property
def Missing(self):
return dbus.Boolean(self.state.attr[2] == 'm')
if self.state.attr[2] == 'm':
return True
return False
def object_path(self):
return self._object_path
@@ -251,8 +275,8 @@ class Pv(AutomatedProperties):
@property
def Lv(self):
return dbus.Array(self.state.lv, signature="(oa(tts))")
return self.state.lv
@property
def Vg(self):
return dbus.ObjectPath(self.state.vg_path)
return self.state.vg_path

View File

@@ -0,0 +1,45 @@
# Copyright (C) 2015-2016 Red Hat, Inc. All rights reserved.
#
# 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 General Public License v.2.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# Try and minimize the refreshes we do.
import threading
from .request import RequestEntry
from . import cfg
from . import utils
_rlock = threading.RLock()
_count = 0
def handle_external_event(command):
utils.log_debug("External event: '%s'" % command)
event_complete()
cfg.load()
def event_add(params):
global _rlock
global _count
with _rlock:
if _count == 0:
_count += 1
r = RequestEntry(
-1, handle_external_event,
params, None, None, False)
cfg.worker_q.put(r)
def event_complete():
global _rlock
global _count
with _rlock:
if _count > 0:
_count -= 1
return _count

View File

@@ -9,16 +9,17 @@
import threading
# noinspection PyUnresolvedReferences
from gi.repository import GLib
from gi.repository import GObject
from .job import Job
from . import cfg
import traceback
from .utils import log_error, mt_async_result
from .utils import log_error
class RequestEntry(object):
def __init__(self, tmo, method, arguments, cb, cb_error,
return_tuple=True, job_state=None):
return_tuple=True):
self.tmo = tmo
self.method = method
self.arguments = arguments
self.cb = cb
@@ -28,39 +29,31 @@ class RequestEntry(object):
self.lock = threading.RLock()
self.done = False
self._result = None
self._job = None
self._job = False
self._rc = 0
self._rc_error = None
self._return_tuple = return_tuple
self._job_state = job_state
if tmo < 0:
if self.tmo < 0:
# Client is willing to block forever
pass
elif tmo == 0:
self._return_job()
else:
# Note: using 990 instead of 1000 for second to ms conversion to
# account for overhead. Goal is to return just before the
# timeout amount has expired. Better to be a little early than
# late.
self.timer_id = GLib.timeout_add(
tmo * 990, RequestEntry._request_timeout, self)
self.timer_id = GObject.timeout_add_seconds(
tmo, RequestEntry._request_timeout, self)
@staticmethod
def _request_timeout(r):
"""
Method which gets called when the timer runs out!
:param r: RequestEntry which timed out
:return: Result of timer_expired
:return: Nothing
"""
return r.timer_expired()
r.timer_expired()
def _return_job(self):
# Return job is only called when we create a request object or when
# we pop a timer. In both cases we are running in the correct context
# and do not need to schedule the call back in main context.
self._job = Job(self, self._job_state)
self._job = Job(self)
cfg.om.register_object(self._job, True)
if self._return_tuple:
self.cb(('/', self._job.dbus_object_path()))
@@ -71,14 +64,13 @@ class RequestEntry(object):
try:
result = self.method(*self.arguments)
self.register_result(result)
except Exception as e:
except Exception:
# Use the request entry to return the result as the client may
# have gotten a job by the time we hit an error
# Lets get the stacktrace and set that to the error message
st = traceback.format_exc()
cfg.blackbox.dump()
log_error("Exception returned to client: \n%s" % st)
self.register_error(-1, str(e), e)
self.register_error(-1, st)
def is_done(self):
with self.lock:
@@ -95,17 +87,16 @@ class RequestEntry(object):
return self._result
return '/'
def _reg_ending(self, result, error_rc=0, error_msg=None,
error_exception=None):
def _reg_ending(self, result, error_rc=0, error=None):
with self.lock:
self.done = True
if self.timer_id != -1:
# Try to prevent the timer from firing
GLib.source_remove(self.timer_id)
GObject.source_remove(self.timer_id)
self._result = result
self._rc = error_rc
self._rc_error = error_msg
self._rc_error = error
if not self._job:
# We finished and there is no job, so return result or error
@@ -116,27 +107,20 @@ class RequestEntry(object):
if error_rc == 0:
if self.cb:
if self._return_tuple:
mt_async_result(self.cb, (result, '/'))
self.cb((result, '/'))
else:
mt_async_result(self.cb, result)
self.cb(result)
else:
if self.cb_error:
if not error_exception:
if not error_msg:
error_exception = Exception(
"An error occurred, but no reason was "
"given, see service logs!")
else:
error_exception = Exception(error_msg)
mt_async_result(self.cb_error, error_exception)
self.cb_error(self._rc_error)
else:
# We have a job and it's complete, indicate that it's done.
# TODO: We need to signal the job is done too.
self._job.Complete = True
self._job = None
def register_error(self, error_rc, error_message, error_exception):
self._reg_ending('/', error_rc, error_message, error_exception)
def register_error(self, error_rc, error):
self._reg_ending(None, error_rc, error)
def register_result(self, result):
self._reg_ending(result)

View File

@@ -8,11 +8,10 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import pyudev
import threading
from .refresh import event_add
from . import cfg
observer = None
observer_lock = threading.RLock()
# noinspection PyUnusedLocal
@@ -37,24 +36,19 @@ def filter_event(action, device):
refresh = True
if refresh:
cfg.event()
event_add(('udev',))
def add():
with observer_lock:
global observer
context = pyudev.Context()
monitor = pyudev.Monitor.from_netlink(context)
monitor.filter_by('block')
observer = pyudev.MonitorObserver(monitor, filter_event)
observer.start()
global observer
context = pyudev.Context()
monitor = pyudev.Monitor.from_netlink(context)
monitor.filter_by('block')
observer = pyudev.MonitorObserver(monitor, filter_event)
observer.start()
def remove():
with observer_lock:
global observer
if observer:
observer.stop()
observer = None
return True
return False
global observer
observer.stop()
observer = None

View File

@@ -13,14 +13,15 @@ import inspect
import ctypes
import os
import string
import datetime
import dbus
from lvmdbusd import cfg
# noinspection PyUnresolvedReferences
from gi.repository import GLib
import threading
import dbus.service
import dbus.mainloop.glib
try:
from . import cfg
except SystemError:
import cfg
STDOUT_TTY = os.isatty(sys.stdout.fileno())
@@ -148,27 +149,17 @@ def add_properties(xml, interface, props):
:param props: Output from get_properties
:return: updated XML string
"""
root = Et.fromstring(xml)
if props:
root = Et.fromstring(xml)
interface_element = None
# Check to see if interface is present
for c in root:
# print c.attrib['name']
if c.attrib['name'] == interface:
interface_element = c
break
# Interface is not present, lets create it so we have something to
# attach the properties too
if interface_element is None:
interface_element = Et.Element("interface", name=interface)
root.append(interface_element)
# Add the properties
for p in props:
temp = '<property type="%s" name="%s" access="%s"/>\n' % \
(p['p_t'], p['p_name'], p['p_access'])
interface_element.append(Et.fromstring(temp))
for p in props:
temp = '<property type="%s" name="%s" access="%s"/>\n' % \
(p['p_t'], p['p_name'], p['p_access'])
c.append(Et.fromstring(temp))
return Et.tostring(root, encoding='utf8')
return xml
@@ -244,7 +235,7 @@ def parse_tags(tags):
if len(tags):
if ',' in tags:
return tags.split(',')
return dbus.Array(sorted([tags]), signature='s')
return sorted([tags])
return dbus.Array([], signature='s')
@@ -252,13 +243,7 @@ def _common_log(msg, *attributes):
cfg.stdout_lock.acquire()
tid = ctypes.CDLL('libc.so.6').syscall(186)
if STDOUT_TTY:
msg = "%s: %d:%d - %s" % \
(datetime.datetime.now().strftime("%b %d %H:%M:%S.%f"),
os.getpid(), tid, msg)
else:
msg = "%d:%d - %s" % (os.getpid(), tid, msg)
msg = "%d:%d - %s" % (os.getpid(), tid, msg)
if STDOUT_TTY and attributes:
print(color(msg, *attributes))
@@ -273,7 +258,7 @@ def _common_log(msg, *attributes):
# @param msg Message to output to stdout
# @return None
def log_debug(msg, *attributes):
if cfg.args and cfg.args.debug:
if cfg.DEBUG:
_common_log(msg, *attributes)
@@ -404,7 +389,7 @@ def round_size(size_bytes):
return size_bytes + bs - remainder
_ALLOWABLE_CH = string.ascii_letters + string.digits + '#+-.:=@_\/%'
_ALLOWABLE_CH = string.ascii_letters + string.digits + '#+.:=@_\/%'
_ALLOWABLE_CH_SET = set(_ALLOWABLE_CH)
_ALLOWABLE_VG_LV_CH = string.ascii_letters + string.digits + '.-_+'
@@ -497,71 +482,3 @@ def validate_tag(interface, tag):
raise dbus.exceptions.DBusException(
interface, 'tag (%s) contains invalid character, allowable set(%s)'
% (tag, _ALLOWABLE_TAG_CH))
# The methods below which start with mt_* are used to execute the desired code
# on the the main thread of execution to alleviate any issues the dbus-python
# library with regards to multi-threaded access. Essentially, we are trying to
# ensure all dbus library interaction is done from the same thread!
def _async_result(call_back, results):
log_debug('Results = %s' % str(results))
call_back(results)
# Return result in main thread
def mt_async_result(call_back, results):
GLib.idle_add(_async_result, call_back, results)
# Take the supplied function and run it on the main thread and not wait for
# a result!
def mt_run_no_wait(function, param):
GLib.idle_add(function, param)
# Run the supplied function and arguments on the main thread and wait for them
# to complete while allowing the ability to get the return value too.
#
# Example:
# result = MThreadRunner(foo, arg1, arg2).done()
#
class MThreadRunner(object):
@staticmethod
def runner(obj):
# noinspection PyProtectedMember
obj._run()
with obj.cond:
obj.function_complete = True
obj.cond.notify_all()
def __init__(self, function, *args):
self.f = function
self.rc = None
self.args = args
self.function_complete = False
self.cond = threading.Condition(threading.Lock())
def done(self):
GLib.idle_add(MThreadRunner.runner, self)
with self.cond:
if not self.function_complete:
self.cond.wait()
return self.rc
def _run(self):
if len(self.args):
self.rc = self.f(*self.args)
else:
self.rc = self.f()
def _remove_objects(dbus_objects_rm):
for o in dbus_objects_rm:
cfg.om.remove_object(o, emit_signal=True)
# Remove dbus objects from main thread
def mt_remove_dbus_objects(objs):
MThreadRunner(_remove_objects, objs).done()

View File

@@ -19,8 +19,7 @@ from .request import RequestEntry
from .loader import common
from .state import State
from . import background
from .utils import round_size, mt_remove_dbus_objects
from .job import JobState
from .utils import round_size
# noinspection PyUnusedLocal
@@ -67,7 +66,7 @@ class VgState(State):
gen = utils.lv_object_path_method(lv_name, meta)
lv_path = cfg.om.get_object_path_by_uuid_lvm_id(
lv_path = cfg.om.get_object_path_by_lvm_id(
lv_uuid, full_name, gen)
rc.append(lv_path)
return dbus.Array(rc, signature='o')
@@ -76,9 +75,9 @@ class VgState(State):
rc = []
for p in cfg.db.pvs_in_vg(self.Uuid):
(pv_name, pv_uuid) = p
rc.append(cfg.om.get_object_path_by_uuid_lvm_id(
rc.append(cfg.om.get_object_path_by_lvm_id(
pv_uuid, pv_name, pv_obj_path_generate))
return rc
return dbus.Array(rc, signature='o')
def __init__(self, Uuid, Name, Fmt,
SizeBytes, FreeBytes, SysId, ExtentSizeBytes,
@@ -91,7 +90,7 @@ class VgState(State):
def create_dbus_object(self, path):
if not path:
path = cfg.om.get_object_path_by_uuid_lvm_id(
path = cfg.om.get_object_path_by_lvm_id(
self.Uuid, self.Name, vg_obj_path_generate)
return Vg(path, self)
@@ -145,35 +144,34 @@ class Vg(AutomatedProperties):
@staticmethod
def fetch_new_lv(vg_name, lv_name):
return cfg.om.get_object_path_by_lvm_id("%s/%s" % (vg_name, lv_name))
full_name = "%s/%s" % (vg_name, lv_name)
@staticmethod
def handle_execute(rc, out, err):
if rc == 0:
cfg.load()
else:
# Need to work on error handling, need consistent
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
cfg.load()
l = cfg.om.get_object_by_lvm_id(full_name)
created_lv = l.dbus_object_path()
@staticmethod
def validate_dbus_object(vg_uuid, vg_name):
dbo = cfg.om.get_object_by_uuid_lvm_id(vg_uuid, vg_name)
if not dbo:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'VG with uuid %s and name %s not present!' %
(vg_uuid, vg_name))
return dbo
return created_lv
@staticmethod
def _rename(uuid, vg_name, new_name, rename_options):
# Make sure we have a dbus object representing it
Vg.validate_dbus_object(uuid, vg_name)
rc, out, err = cmdhandler.vg_rename(
vg_name, new_name, rename_options)
Vg.handle_execute(rc, out, err)
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
if dbo:
rc, out, err = cmdhandler.vg_rename(vg_name, new_name,
rename_options)
if rc == 0:
cfg.load()
else:
# Need to work on error handling, need consistent
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'VG with uuid %s and name %s not present!' %
(uuid, vg_name))
return '/'
@dbus.service.method(
@@ -190,10 +188,31 @@ class Vg(AutomatedProperties):
@staticmethod
def _remove(uuid, vg_name, remove_options):
# Make sure we have a dbus object representing it
Vg.validate_dbus_object(uuid, vg_name)
# Remove the VG, if successful then remove from the model
rc, out, err = cmdhandler.vg_remove(vg_name, remove_options)
Vg.handle_execute(rc, out, err)
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
if dbo:
# Remove the VG, if successful then remove from the model
rc, out, err = cmdhandler.vg_remove(vg_name, remove_options)
if rc == 0:
# Remove the VG
cfg.om.remove_object(dbo, True)
# If an LV has hidden LVs, things can get quite involved,
# especially if it's the last thin pool to get removed, so
# lets refresh all
cfg.load()
else:
# Need to work on error handling, need consistent
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'VG with uuid %s and name %s not present!' %
(uuid, vg_name))
return '/'
@dbus.service.method(
@@ -208,9 +227,29 @@ class Vg(AutomatedProperties):
@staticmethod
def _change(uuid, vg_name, change_options):
Vg.validate_dbus_object(uuid, vg_name)
rc, out, err = cmdhandler.vg_change(change_options, vg_name)
Vg.handle_execute(rc, out, err)
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
if dbo:
rc, out, err = cmdhandler.vg_change(change_options, vg_name)
# To use an example with d-feet (Method input)
# {"activate": __import__('gi.repository.GLib', globals(),
# locals(), ['Variant']).Variant("s", "n")}
if rc == 0:
dbo.refresh()
if (('activate' in change_options) or ('-a' in change_options)):
cfg.load()
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'VG with uuid %s and name %s not present!' %
(uuid, vg_name))
return '/'
# TODO: This should be broken into a number of different methods
@@ -231,24 +270,34 @@ class Vg(AutomatedProperties):
@staticmethod
def _reduce(uuid, vg_name, missing, pv_object_paths, reduce_options):
# Make sure we have a dbus object representing it
Vg.validate_dbus_object(uuid, vg_name)
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
pv_devices = []
if dbo:
pv_devices = []
# If pv_object_paths is not empty, then get the device paths
if pv_object_paths and len(pv_object_paths) > 0:
for pv_op in pv_object_paths:
pv = cfg.om.get_object_by_path(pv_op)
if pv:
pv_devices.append(pv.lvm_id)
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'PV Object path not found = %s!' % pv_op)
# If pv_object_paths is not empty, then get the device paths
if pv_object_paths and len(pv_object_paths) > 0:
for pv_op in pv_object_paths:
pv = cfg.om.get_object_by_path(pv_op)
if pv:
pv_devices.append(pv.lvm_id)
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'PV Object path not found = %s!' % pv_op)
rc, out, err = cmdhandler.vg_reduce(vg_name, missing, pv_devices,
reduce_options)
Vg.handle_execute(rc, out, err)
rc, out, err = cmdhandler.vg_reduce(vg_name, missing, pv_devices,
reduce_options)
if rc == 0:
cfg.load()
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE, 'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'VG with uuid %s and name %s not present!' %
(uuid, vg_name))
return '/'
@dbus.service.method(
@@ -265,26 +314,36 @@ class Vg(AutomatedProperties):
@staticmethod
def _extend(uuid, vg_name, pv_object_paths, extend_options):
# Make sure we have a dbus object representing it
Vg.validate_dbus_object(uuid, vg_name)
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
extend_devices = []
if dbo:
extend_devices = []
for i in pv_object_paths:
pv = cfg.om.get_object_by_path(i)
if pv:
extend_devices.append(pv.lvm_id)
for i in pv_object_paths:
pv = cfg.om.get_object_by_path(i)
if pv:
extend_devices.append(pv.lvm_id)
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE, 'PV Object path not found = %s!' % i)
if len(extend_devices):
rc, out, err = cmdhandler.vg_extend(vg_name, extend_devices,
extend_options)
if rc == 0:
cfg.load()
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE, 'PV Object path not found = %s!' % i)
if len(extend_devices):
rc, out, err = cmdhandler.vg_extend(vg_name, extend_devices,
extend_options)
Vg.handle_execute(rc, out, err)
VG_INTERFACE, 'No pv_object_paths provided!')
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE, 'No pv_object_paths provided!')
VG_INTERFACE,
'VG with uuid %s and name %s not present!' %
(uuid, vg_name))
return '/'
@dbus.service.method(
@@ -301,44 +360,45 @@ class Vg(AutomatedProperties):
@dbus.service.method(
dbus_interface=VG_INTERFACE,
in_signature='o(tt)a(ott)ia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
out_signature='o')
def Move(self, pv_src_obj, pv_source_range, pv_dests_and_ranges,
tmo, move_options, cb, cbe):
job_state = JobState()
r = RequestEntry(
tmo, background.move,
(VG_INTERFACE, None, pv_src_obj, pv_source_range,
pv_dests_and_ranges, move_options, job_state), cb, cbe, False,
job_state)
cfg.worker_q.put(r)
tmo, move_options):
return background.move(
VG_INTERFACE, None, pv_src_obj, pv_source_range,
pv_dests_and_ranges, move_options, tmo)
@staticmethod
def _lv_create(uuid, vg_name, name, size_bytes, pv_dests_and_ranges,
create_options):
# Make sure we have a dbus object representing it
pv_dests = []
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
Vg.validate_dbus_object(uuid, vg_name)
if dbo:
if len(pv_dests_and_ranges):
for pr in pv_dests_and_ranges:
pv_dbus_obj = cfg.om.get_object_by_path(pr[0])
if not pv_dbus_obj:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'PV Destination (%s) not found' % pr[0])
if len(pv_dests_and_ranges):
for pr in pv_dests_and_ranges:
pv_dbus_obj = cfg.om.get_object_by_path(pr[0])
if not pv_dbus_obj:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'PV Destination (%s) not found' % pr[0])
pv_dests.append((pv_dbus_obj.lvm_id, pr[1], pr[2]))
pv_dests.append((pv_dbus_obj.lvm_id, pr[1], pr[2]))
rc, out, err = cmdhandler.vg_lv_create(
vg_name, create_options, name, size_bytes, pv_dests)
rc, out, err = cmdhandler.vg_lv_create(
vg_name, create_options, name, size_bytes, pv_dests)
Vg.handle_execute(rc, out, err)
return Vg.fetch_new_lv(vg_name, name)
if rc == 0:
return Vg.fetch_new_lv(vg_name, name)
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'VG with uuid %s and name %s not present!' %
(uuid, vg_name))
@dbus.service.method(
dbus_interface=VG_INTERFACE,
@@ -374,13 +434,25 @@ class Vg(AutomatedProperties):
def _lv_create_linear(uuid, vg_name, name, size_bytes,
thin_pool, create_options):
# Make sure we have a dbus object representing it
Vg.validate_dbus_object(uuid, vg_name)
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
rc, out, err = cmdhandler.vg_lv_create_linear(
vg_name, create_options, name, size_bytes, thin_pool)
if dbo:
rc, out, err = cmdhandler.vg_lv_create_linear(
vg_name, create_options, name, size_bytes, thin_pool)
Vg.handle_execute(rc, out, err)
return Vg.fetch_new_lv(vg_name, name)
if rc == 0:
created_lv = Vg.fetch_new_lv(vg_name, name)
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'VG with uuid %s and name %s not present!' %
(uuid, vg_name))
return created_lv
@dbus.service.method(
dbus_interface=VG_INTERFACE,
@@ -400,12 +472,24 @@ class Vg(AutomatedProperties):
def _lv_create_striped(uuid, vg_name, name, size_bytes, num_stripes,
stripe_size_kb, thin_pool, create_options):
# Make sure we have a dbus object representing it
Vg.validate_dbus_object(uuid, vg_name)
rc, out, err = cmdhandler.vg_lv_create_striped(
vg_name, create_options, name, size_bytes,
num_stripes, stripe_size_kb, thin_pool)
Vg.handle_execute(rc, out, err)
return Vg.fetch_new_lv(vg_name, name)
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
if dbo:
rc, out, err = cmdhandler.vg_lv_create_striped(
vg_name, create_options, name, size_bytes,
num_stripes, stripe_size_kb, thin_pool)
if rc == 0:
created_lv = Vg.fetch_new_lv(vg_name, name)
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE, 'VG with uuid %s and name %s not present!' %
(uuid, vg_name))
return created_lv
@dbus.service.method(
dbus_interface=VG_INTERFACE,
@@ -428,11 +512,25 @@ class Vg(AutomatedProperties):
def _lv_create_mirror(uuid, vg_name, name, size_bytes,
num_copies, create_options):
# Make sure we have a dbus object representing it
Vg.validate_dbus_object(uuid, vg_name)
rc, out, err = cmdhandler.vg_lv_create_mirror(
vg_name, create_options, name, size_bytes, num_copies)
Vg.handle_execute(rc, out, err)
return Vg.fetch_new_lv(vg_name, name)
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
if dbo:
rc, out, err = cmdhandler.vg_lv_create_mirror(
vg_name, create_options, name, size_bytes, num_copies)
if rc == 0:
created_lv = Vg.fetch_new_lv(vg_name, name)
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'VG with uuid %s and name %s not present!' %
(uuid, vg_name))
return created_lv
@dbus.service.method(
dbus_interface=VG_INTERFACE,
@@ -453,12 +551,26 @@ class Vg(AutomatedProperties):
def _lv_create_raid(uuid, vg_name, name, raid_type, size_bytes,
num_stripes, stripe_size_kb, create_options):
# Make sure we have a dbus object representing it
Vg.validate_dbus_object(uuid, vg_name)
rc, out, err = cmdhandler.vg_lv_create_raid(
vg_name, create_options, name, raid_type, size_bytes,
num_stripes, stripe_size_kb)
Vg.handle_execute(rc, out, err)
return Vg.fetch_new_lv(vg_name, name)
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
if dbo:
rc, out, err = cmdhandler.vg_lv_create_raid(
vg_name, create_options, name, raid_type, size_bytes,
num_stripes, stripe_size_kb)
if rc == 0:
created_lv = Vg.fetch_new_lv(vg_name, name)
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'VG with uuid %s and name %s not present!' %
(uuid, vg_name))
return created_lv
@dbus.service.method(
dbus_interface=VG_INTERFACE,
@@ -479,27 +591,35 @@ class Vg(AutomatedProperties):
def _create_pool(uuid, vg_name, meta_data_lv, data_lv,
create_options, create_method):
# Make sure we have a dbus object representing it
Vg.validate_dbus_object(uuid, vg_name)
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
# Retrieve the full names for the metadata and data lv
md = cfg.om.get_object_by_path(meta_data_lv)
data = cfg.om.get_object_by_path(data_lv)
if md and data:
if dbo and md and data:
new_name = data.Name
rc, out, err = create_method(
md.lv_full_name(), data.lv_full_name(), create_options)
if rc == 0:
mt_remove_dbus_objects((md, data))
cfg.om.remove_object(md, emit_signal=True)
cfg.om.remove_object(data, emit_signal=True)
Vg.handle_execute(rc, out, err)
cache_pool_lv = Vg.fetch_new_lv(vg_name, new_name)
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
msg = ""
if not dbo:
msg += 'VG with uuid %s and name %s not present!' % \
(uuid, vg_name)
if not md:
msg += 'Meta data LV with object path %s not present!' % \
(meta_data_lv)
@@ -510,7 +630,7 @@ class Vg(AutomatedProperties):
raise dbus.exceptions.DBusException(VG_INTERFACE, msg)
return Vg.fetch_new_lv(vg_name, new_name)
return cache_pool_lv
@dbus.service.method(
dbus_interface=VG_INTERFACE,
@@ -544,21 +664,33 @@ class Vg(AutomatedProperties):
pv_devices = []
# Make sure we have a dbus object representing it
Vg.validate_dbus_object(uuid, vg_name)
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
# Check for existence of pv object paths
for p in pv_object_paths:
pv = cfg.om.get_object_by_path(p)
if pv:
pv_devices.append(pv.Name)
if dbo:
# Check for existence of pv object paths
for p in pv_object_paths:
pv = cfg.om.get_object_by_path(p)
if pv:
pv_devices.append(pv.Name)
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE, 'PV object path = %s not found' % p)
rc, out, err = cmdhandler.pv_tag(
pv_devices, tags_add, tags_del, tag_options)
if rc == 0:
cfg.load()
return '/'
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE, 'PV object path = %s not found' % p)
VG_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
rc, out, err = cmdhandler.pv_tag(
pv_devices, tags_add, tags_del, tag_options)
Vg.handle_execute(rc, out, err)
return '/'
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'VG with uuid %s and name %s not present!' %
(uuid, vg_name))
@dbus.service.method(
dbus_interface=VG_INTERFACE,
@@ -596,12 +728,25 @@ class Vg(AutomatedProperties):
@staticmethod
def _vg_add_rm_tags(uuid, vg_name, tags_add, tags_del, tag_options):
# Make sure we have a dbus object representing it
Vg.validate_dbus_object(uuid, vg_name)
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
rc, out, err = cmdhandler.vg_tag(
vg_name, tags_add, tags_del, tag_options)
Vg.handle_execute(rc, out, err)
return '/'
if dbo:
rc, out, err = cmdhandler.vg_tag(
vg_name, tags_add, tags_del, tag_options)
if rc == 0:
dbo.refresh()
return '/'
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'VG with uuid %s and name %s not present!' %
(uuid, vg_name))
@dbus.service.method(
dbus_interface=VG_INTERFACE,
@@ -638,10 +783,23 @@ class Vg(AutomatedProperties):
@staticmethod
def _vg_change_set(uuid, vg_name, method, value, options):
# Make sure we have a dbus object representing it
Vg.validate_dbus_object(uuid, vg_name)
rc, out, err = method(vg_name, value, options)
Vg.handle_execute(rc, out, err)
return '/'
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
if dbo:
rc, out, err = method(vg_name, value, options)
if rc == 0:
dbo.refresh()
return '/'
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'VG with uuid %s and name %s not present!' %
(uuid, vg_name))
@dbus.service.method(
dbus_interface=VG_INTERFACE,
@@ -681,7 +839,9 @@ class Vg(AutomatedProperties):
cfg.worker_q.put(r)
def _attribute(self, pos, ch):
return dbus.Boolean(self.state.attr[pos] == ch)
if self.state.attr[pos] == ch:
return True
return False
@dbus.service.method(
dbus_interface=VG_INTERFACE,
@@ -699,11 +859,23 @@ class Vg(AutomatedProperties):
def _vg_activate_deactivate(uuid, vg_name, activate, control_flags,
options):
# Make sure we have a dbus object representing it
Vg.validate_dbus_object(uuid, vg_name)
rc, out, err = cmdhandler.activate_deactivate(
'vgchange', vg_name, activate, control_flags, options)
Vg.handle_execute(rc, out, err)
return '/'
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
if dbo:
rc, out, err = cmdhandler.activate_deactivate(
'vgchange', vg_name, activate, control_flags, options)
if rc == 0:
cfg.load()
return '/'
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'VG with uuid %s and name %s not present!' %
(uuid, vg_name))
@dbus.service.method(
dbus_interface=VG_INTERFACE,
@@ -735,11 +907,11 @@ class Vg(AutomatedProperties):
@property
def Pvs(self):
return dbus.Array(self.state.Pvs, signature='o')
return self.state.Pvs
@property
def Lvs(self):
return dbus.Array(self.state.Lvs, signature='o')
return self.state.Lvs
@property
def lvm_id(self):

View File

@@ -37,12 +37,11 @@ int main(int argc, char **argv)
printf("lvmetactl dump\n");
printf("lvmetactl pv_list\n");
printf("lvmetactl vg_list\n");
printf("lvmetactl get_global_info\n");
printf("lvmetactl vg_lookup_name <name>\n");
printf("lvmetactl vg_lookup_uuid <uuid>\n");
printf("lvmetactl pv_lookup_uuid <uuid>\n");
printf("lvmetactl set_global_invalid 0|1\n");
printf("lvmetactl set_global_disable 0|1\n");
printf("lvmetactl get_global_invalid\n");
printf("lvmetactl set_vg_version <uuid> <name> <version>\n");
printf("lvmetactl vg_lock_type <uuid>\n");
return -1;
@@ -55,32 +54,18 @@ int main(int argc, char **argv)
if (!strcmp(cmd, "dump")) {
reply = daemon_send_simple(h, "dump",
"token = %s", "skip",
"pid = " FMTd64, (int64_t)getpid(),
"cmd = %s", "lvmetactl",
NULL);
printf("%s\n", reply.buffer.mem);
} else if (!strcmp(cmd, "pv_list")) {
reply = daemon_send_simple(h, "pv_list",
"token = %s", "skip",
"pid = " FMTd64, (int64_t)getpid(),
"cmd = %s", "lvmetactl",
NULL);
printf("%s\n", reply.buffer.mem);
} else if (!strcmp(cmd, "vg_list")) {
reply = daemon_send_simple(h, "vg_list",
"token = %s", "skip",
"pid = " FMTd64, (int64_t)getpid(),
"cmd = %s", "lvmetactl",
NULL);
printf("%s\n", reply.buffer.mem);
} else if (!strcmp(cmd, "get_global_info")) {
reply = daemon_send_simple(h, "get_global_info",
"token = %s", "skip",
"pid = " FMTd64, (int64_t)getpid(),
"cmd = %s", "lvmetactl",
NULL);
printf("%s\n", reply.buffer.mem);
@@ -94,26 +79,14 @@ int main(int argc, char **argv)
reply = daemon_send_simple(h, "set_global_info",
"global_invalid = " FMTd64, (int64_t) val,
"token = %s", "skip",
"pid = " FMTd64, (int64_t)getpid(),
"cmd = %s", "lvmetactl",
NULL);
print_reply(reply);
} else if (!strcmp(cmd, "set_global_disable")) {
if (argc < 3) {
printf("set_global_disable 0|1\n");
return -1;
}
val = atoi(argv[2]);
reply = daemon_send_simple(h, "set_global_info",
"global_disable = " FMTd64, (int64_t) val,
"disable_reason = %s", LVMETAD_DISABLE_REASON_DIRECT,
} else if (!strcmp(cmd, "get_global_invalid")) {
reply = daemon_send_simple(h, "get_global_info",
"token = %s", "skip",
"pid = " FMTd64, (int64_t)getpid(),
"cmd = %s", "lvmetactl",
NULL);
print_reply(reply);
printf("%s\n", reply.buffer.mem);
} else if (!strcmp(cmd, "set_vg_version")) {
if (argc < 5) {
@@ -135,24 +108,18 @@ int main(int argc, char **argv)
"name = %s", name,
"version = " FMTd64, (int64_t) ver,
"token = %s", "skip",
"pid = " FMTd64, (int64_t)getpid(),
"cmd = %s", "lvmetactl",
NULL);
} else if (uuid) {
reply = daemon_send_simple(h, "set_vg_info",
"uuid = %s", uuid,
"version = " FMTd64, (int64_t) ver,
"token = %s", "skip",
"pid = " FMTd64, (int64_t)getpid(),
"cmd = %s", "lvmetactl",
NULL);
} else if (name) {
reply = daemon_send_simple(h, "set_vg_info",
"name = %s", name,
"version = " FMTd64, (int64_t) ver,
"token = %s", "skip",
"pid = " FMTd64, (int64_t)getpid(),
"cmd = %s", "lvmetactl",
NULL);
} else {
printf("name or uuid required\n");
@@ -171,8 +138,6 @@ int main(int argc, char **argv)
reply = daemon_send_simple(h, "vg_lookup",
"name = %s", name,
"token = %s", "skip",
"pid = " FMTd64, (int64_t)getpid(),
"cmd = %s", "lvmetactl",
NULL);
printf("%s\n", reply.buffer.mem);
@@ -186,8 +151,6 @@ int main(int argc, char **argv)
reply = daemon_send_simple(h, "vg_lookup",
"uuid = %s", uuid,
"token = %s", "skip",
"pid = " FMTd64, (int64_t)getpid(),
"cmd = %s", "lvmetactl",
NULL);
printf("%s\n", reply.buffer.mem);
@@ -204,8 +167,6 @@ int main(int argc, char **argv)
reply = daemon_send_simple(h, "vg_lookup",
"uuid = %s", uuid,
"token = %s", "skip",
"pid = " FMTd64, (int64_t)getpid(),
"cmd = %s", "lvmetactl",
NULL);
/* printf("%s\n", reply.buffer.mem); */
@@ -232,8 +193,6 @@ int main(int argc, char **argv)
reply = daemon_send_simple(h, "pv_lookup",
"uuid = %s", uuid,
"token = %s", "skip",
"pid = " FMTd64, (int64_t)getpid(),
"cmd = %s", "lvmetactl",
NULL);
printf("%s\n", reply.buffer.mem);

View File

@@ -19,13 +19,6 @@
#define LVMETAD_SOCKET DEFAULT_RUN_DIR "/lvmetad.socket"
#define LVMETAD_TOKEN_UPDATE_IN_PROGRESS "update in progress"
#define LVMETAD_DISABLE_REASON_DIRECT "DIRECT"
#define LVMETAD_DISABLE_REASON_LVM1 "LVM1"
#define LVMETAD_DISABLE_REASON_DUPLICATES "DUPLICATES"
#define LVMETAD_DISABLE_REASON_VGRESTORE "VGRESTORE"
struct volume_group;
/* Different types of replies we may get from lvmetad. */

File diff suppressed because it is too large Load Diff

View File

@@ -75,10 +75,7 @@ int scan(daemon_handle h, char *fn) {
}
char uuid[64];
if (!id_write_format(dev->pvid, uuid, 64)) {
fprintf(stderr, "[C] Failed to format PV UUID for %s", dev_name(dev));
return;
}
id_write_format(dev->pvid, uuid, 64);
fprintf(stderr, "[C] found PV: %s\n", uuid);
struct lvmcache_info *info = (struct lvmcache_info *) label->info;
struct physical_volume pv = { 0, };

View File

@@ -77,7 +77,7 @@ static void save_client_info(char *line)
uint32_t client_id = 0;
char name[MAX_NAME+1] = { 0 };
(void) sscanf(line, "info=client pid=%u fd=%d pi=%d id=%u name=%s",
sscanf(line, "info=client pid=%u fd=%d pi=%d id=%u name=%s",
&pid, &fd, &pi, &client_id, name);
clients[num_clients].client_id = client_id;
@@ -110,7 +110,7 @@ static void format_info_ls(char *line)
char lock_args[MAX_ARGS+1] = { 0 };
char lock_type[MAX_NAME+1] = { 0 };
(void) sscanf(line, "info=ls ls_name=%s vg_name=%s vg_uuid=%s vg_sysid=%s vg_args=%s lm_type=%s",
sscanf(line, "info=ls ls_name=%s vg_name=%s vg_uuid=%s vg_sysid=%s vg_args=%s lm_type=%s",
ls_name, vg_name, vg_uuid, vg_sysid, lock_args, lock_type);
if (!first_ls)
@@ -131,7 +131,7 @@ static void format_info_ls_action(char *line)
uint32_t pid = 0;
char cl_name[MAX_NAME+1] = { 0 };
(void) sscanf(line, "info=ls_action client_id=%u %s %s op=%s",
sscanf(line, "info=ls_action client_id=%u %s %s op=%s",
&client_id, flags, version, op);
find_client_info(client_id, &pid, cl_name);
@@ -147,7 +147,7 @@ static void format_info_r(char *line, char *r_name_out, char *r_type_out)
char sh_count[MAX_NAME+1] = { 0 };
uint32_t ver = 0;
(void) sscanf(line, "info=r name=%s type=%s mode=%s %s version=%u",
sscanf(line, "info=r name=%s type=%s mode=%s %s version=%u",
r_name, r_type, mode, sh_count, &ver);
strcpy(r_name_out, r_name);
@@ -185,7 +185,7 @@ static void format_info_lk(char *line, char *r_name, char *r_type)
return;
}
(void) sscanf(line, "info=lk mode=%s version=%u %s client_id=%u",
sscanf(line, "info=lk mode=%s version=%u %s client_id=%u",
mode, &ver, flags, &client_id);
find_client_info(client_id, &pid, cl_name);
@@ -221,7 +221,7 @@ static void format_info_r_action(char *line, char *r_name, char *r_type)
return;
}
(void) sscanf(line, "info=r_action client_id=%u %s %s op=%s rt=%s mode=%s %s %s %s",
sscanf(line, "info=r_action client_id=%u %s %s op=%s rt=%s mode=%s %s %s %s",
&client_id, flags, version, op, rt, mode, lm, result, lm_rv);
find_client_info(client_id, &pid, cl_name);

View File

@@ -306,13 +306,7 @@ static const char *_syslog_num_to_name(int num)
static uint64_t monotime(void)
{
struct timespec ts;
if (clock_gettime(CLOCK_MONOTONIC, &ts)) {
log_error("clock_gettime failed to get timestamp %s.",
strerror(errno));
ts.tv_sec = 0;
}
clock_gettime(CLOCK_MONOTONIC, &ts);
return ts.tv_sec;
}
@@ -323,7 +317,7 @@ static void log_save_line(int len, char *line,
unsigned int w = *wrap;
int i;
if (len < (int) (LOG_DUMP_SIZE - p)) {
if (len < LOG_DUMP_SIZE - p) {
memcpy(log_buf + p, line, len);
p += len;
@@ -1013,7 +1007,6 @@ static daemon_reply send_lvmetad(const char *id, ...)
daemon_reply reply;
va_list ap;
int retries = 0;
int err;
va_start(ap, id);
@@ -1023,28 +1016,20 @@ static daemon_reply send_lvmetad(const char *id, ...)
*/
pthread_mutex_lock(&lvmetad_mutex);
retry:
if (!lvmetad_connected) {
lvmetad_handle = lvmetad_open(NULL);
if (lvmetad_handle.error || lvmetad_handle.socket_fd < 0) {
err = lvmetad_handle.error ?: lvmetad_handle.socket_fd;
pthread_mutex_unlock(&lvmetad_mutex);
log_error("lvmetad_open reconnect error %d", err);
memset(&reply, 0, sizeof(reply));
reply.error = err;
va_end(ap);
return reply;
} else {
log_debug("lvmetad reconnected");
lvmetad_connected = 1;
}
}
reply = daemon_send_simple_v(lvmetad_handle, id, ap);
/* lvmetad may have been restarted */
if ((reply.error == ECONNRESET) && (retries < 2)) {
daemon_close(lvmetad_handle);
lvmetad_connected = 0;
lvmetad_handle = lvmetad_open(NULL);
if (lvmetad_handle.error || lvmetad_handle.socket_fd < 0) {
log_error("lvmetad_open reconnect error %d", lvmetad_handle.error);
} else {
log_debug("lvmetad reconnected");
lvmetad_connected = 1;
}
retries++;
goto retry;
}
@@ -1249,6 +1234,10 @@ static int res_lock(struct lockspace *ls, struct resource *r, struct action *act
rv = -EREMOVED;
}
if (!lvmetad_connected && inval_meta)
log_debug("S %s R %s res_lock no lvmetad connection to invalidate",
ls->name, r->name);
/*
* r is vglk: tell lvmetad to set the vg invalid
* flag, and provide the new r_version. If lvmetad finds
@@ -1264,7 +1253,7 @@ static int res_lock(struct lockspace *ls, struct resource *r, struct action *act
* caches, and tell lvmetad to set global invalid to 0.
*/
if (inval_meta && (r->type == LD_RT_VG)) {
if (lvmetad_connected && inval_meta && (r->type == LD_RT_VG)) {
daemon_reply reply;
char *uuid;
@@ -1288,7 +1277,7 @@ static int res_lock(struct lockspace *ls, struct resource *r, struct action *act
daemon_reply_destroy(reply);
}
if (inval_meta && (r->type == LD_RT_GL)) {
if (lvmetad_connected && inval_meta && (r->type == LD_RT_GL)) {
daemon_reply reply;
log_debug("S %s R %s res_lock set lvmetad global invalid",
@@ -1654,9 +1643,6 @@ static int res_able(struct lockspace *ls, struct resource *r,
}
rv = lm_able_gl_sanlock(ls, act->op == LD_OP_ENABLE);
if (!rv && (act->op == LD_OP_ENABLE))
gl_vg_removed = 0;
out:
return rv;
}
@@ -2283,7 +2269,6 @@ static void *lockspace_thread_main(void *arg_in)
struct action *act_op_free = NULL;
struct list_head tmp_act;
struct list_head act_close;
char tmp_name[MAX_NAME+1];
int free_vg = 0;
int drop_vg = 0;
int error = 0;
@@ -2630,10 +2615,8 @@ out_act:
if (free_vg && ls->sanlock_gl_enabled && act_op_free) {
pthread_mutex_lock(&lockspaces_mutex);
if (other_sanlock_vgs_exist(ls)) {
if (other_sanlock_vgs_exist(ls))
act_op_free->flags |= LD_AF_WARN_GL_REMOVED;
gl_vg_removed = 1;
}
pthread_mutex_unlock(&lockspaces_mutex);
}
@@ -2651,10 +2634,6 @@ out_act:
ls->drop_vg = drop_vg;
if (ls->lm_type == LD_LM_DLM && !strcmp(ls->name, gl_lsname_dlm))
global_dlm_lockspace_exists = 0;
/* Avoid a name collision of the same lockspace is added again before this thread is cleaned up. */
memset(tmp_name, 0, sizeof(tmp_name));
snprintf(tmp_name, MAX_NAME, "REM:%s", ls->name);
memcpy(ls->name, tmp_name, MAX_NAME);
pthread_mutex_unlock(&lockspaces_mutex);
/* worker_thread will join this thread, and free the ls */
@@ -3134,8 +3113,6 @@ static int for_each_lockspace(int do_stop, int do_free, int do_force)
/* FIXME: will free_vg ever not be set? */
log_debug("free ls %s", ls->name);
if (ls->free_vg) {
/* In future we may need to free ls->actions here */
free_ls_resources(ls);
@@ -3356,10 +3333,7 @@ static void *worker_thread_main(void *arg_in)
while (1) {
pthread_mutex_lock(&worker_mutex);
if (clock_gettime(CLOCK_REALTIME, &ts)) {
log_error("clock_gettime failed.");
ts.tv_sec = ts.tv_nsec = 0;
}
clock_gettime(CLOCK_REALTIME, &ts);
ts.tv_sec += delay_sec;
rv = 0;
act = NULL;
@@ -3391,11 +3365,6 @@ static void *worker_thread_main(void *arg_in)
int run_sanlock = lm_is_running_sanlock();
int run_dlm = lm_is_running_dlm();
if (daemon_test) {
run_sanlock = gl_use_sanlock;
run_dlm = gl_use_dlm;
}
if (run_sanlock && run_dlm)
act->result = -EXFULL;
else if (!run_sanlock && !run_dlm)
@@ -3673,7 +3642,7 @@ static int client_send_result(struct client *cl, struct action *act)
if (act->flags & LD_AF_DUP_GL_LS)
strcat(result_flags, "DUP_GL_LS,");
if ((act->flags & LD_AF_WARN_GL_REMOVED) || gl_vg_removed)
if (act->flags & LD_AF_WARN_GL_REMOVED)
strcat(result_flags, "WARN_GL_REMOVED,");
if (act->op == LD_OP_INIT) {
@@ -4431,7 +4400,7 @@ static void client_recv_action(struct client *cl)
return;
}
req.cft = config_tree_from_string_without_dup_node_check(req.buffer.mem);
req.cft = dm_config_from_string(req.buffer.mem);
if (!req.cft) {
log_error("client recv %u config_from_string error", cl->id);
buffer_destroy(&req.buffer);

View File

@@ -320,7 +320,6 @@ static inline int list_empty(const struct list_head *head)
EXTERN int gl_type_static;
EXTERN int gl_use_dlm;
EXTERN int gl_use_sanlock;
EXTERN int gl_vg_removed;
EXTERN char gl_lsname_dlm[MAX_NAME+1];
EXTERN char gl_lsname_sanlock[MAX_NAME+1];
EXTERN int global_dlm_lockspace_exists;

View File

@@ -206,7 +206,7 @@ int lm_data_size_sanlock(void)
#define VG_LOCK_BEGIN UINT64_C(66)
#define LV_LOCK_BEGIN UINT64_C(67)
static uint64_t daemon_test_lv_count;
static unsigned int daemon_test_lv_count;
static int lock_lv_name_from_args(char *vg_args, char *lock_lv_name)
{
@@ -276,8 +276,8 @@ static int read_host_id_file(void)
*sep = '\0';
memset(key_str, 0, sizeof(key_str));
memset(val_str, 0, sizeof(val_str));
(void) sscanf(key, "%s", key_str);
(void) sscanf(val, "%s", val_str);
sscanf(key, "%s", key_str);
sscanf(val, "%s", val_str);
if (!strcmp(key_str, "host_id")) {
host_id = atoi(val_str);
@@ -1416,12 +1416,14 @@ int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
if (adopt)
flags |= SANLK_ACQUIRE_ORPHAN_ONLY;
#ifdef SANLOCK_HAS_ACQUIRE_OWNER_NOWAIT
/*
* Don't block waiting for a failed lease to expire since it causes
* sanlock_acquire to block for a long time, which would prevent this
* thread from processing other lock requests.
*/
flags |= SANLK_ACQUIRE_OWNER_NOWAIT;
#endif
memset(&opt, 0, sizeof(opt));
sprintf(opt.owner_name, "%s", "lvmlockd");
@@ -1496,6 +1498,7 @@ int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
return -EAGAIN;
}
#ifdef SANLOCK_HAS_ACQUIRE_OWNER_NOWAIT
if (rv == SANLK_ACQUIRE_OWNED_RETRY) {
/*
* The lock is held by a failed host, and will eventually
@@ -1514,7 +1517,7 @@ int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
*retry = 0;
return -EAGAIN;
}
#endif
if (rv < 0) {
log_error("S %s R %s lock_san acquire error %d",
ls->name, r->name, rv);

View File

@@ -31,7 +31,7 @@ const char *polling_op(enum poll_type type)
static int add_to_cmd_arr(const char ***cmdargv, const char *str, unsigned *ind)
{
const char **newargv;
const char **newargv = *cmdargv;
if (*ind && !(*ind % MIN_ARGV_SIZE)) {
newargv = dm_realloc(*cmdargv, (*ind / MIN_ARGV_SIZE + 1) * MIN_ARGV_SIZE * sizeof(char *));

View File

@@ -19,8 +19,6 @@
#include <fcntl.h>
#include <signal.h>
static const char LVM_SYSTEM_DIR[] = "LVM_SYSTEM_DIR=";
static char *_construct_full_lvname(const char *vgname, const char *lvname)
{
char *name;
@@ -54,7 +52,7 @@ static char *_construct_lvm_system_dir_env(const char *sysdir)
*env = '\0';
if (sysdir && dm_snprintf(env, l, "%s%s", LVM_SYSTEM_DIR, sysdir) < 0) {
if (sysdir && dm_snprintf(env, l, "LVM_SYSTEM_DIR=%s", sysdir) < 0) {
dm_free(env);
env = NULL;
}
@@ -261,8 +259,8 @@ static void _pdlv_locked_dump(struct buffer *buff, const struct lvmpolld_lv *pdl
buffer_append(buff, tmp);
if (dm_snprintf(tmp, sizeof(tmp), "\t\tlvm_command_interval=\"%s\"\n", pdlv->sinterval ?: "<undefined>") > 0)
buffer_append(buff, tmp);
if (dm_snprintf(tmp, sizeof(tmp), "\t\t%s\"%s\"\n", LVM_SYSTEM_DIR,
(*pdlv->lvm_system_dir_env ? (pdlv->lvm_system_dir_env + (sizeof(LVM_SYSTEM_DIR) - 1)) : "<undefined>")) > 0)
if (dm_snprintf(tmp, sizeof(tmp), "\t\tLVM_SYSTEM_DIR=\"%s\"\n",
(*pdlv->lvm_system_dir_env ? (pdlv->lvm_system_dir_env + strlen("LVM_SYSTEM_DIR=")) : "<undefined>")) > 0)
buffer_append(buff, tmp);
if (dm_snprintf(tmp, sizeof(tmp), "\t\tlvm_command_pid=%d\n", pdlv->cmd_pid) > 0)
buffer_append(buff, tmp);

View File

@@ -11,7 +11,7 @@ Every bio that is mapped by the target is referred to the policy.
The policy can return a simple HIT or MISS or issue a migration.
Currently there's no way for the policy to issue background work,
e.g. to start writing back dirty blocks that are going to be evicted
e.g. to start writing back dirty blocks that are going to be evicte
soon.
Because we map bios, rather than requests it's easy for the policy
@@ -25,77 +25,53 @@ trying to see when the io scheduler has let the ios run.
Overview of supplied cache replacement policies
===============================================
multiqueue (mq)
---------------
multiqueue
----------
This policy is now an alias for smq (see below).
This policy is the default.
The following tunables are accepted, but have no effect:
The multiqueue policy has three sets of 16 queues: one set for entries
waiting for the cache and another two for those in the cache (a set for
clean entries and a set for dirty entries).
Cache entries in the queues are aged based on logical time. Entry into
the cache is based on variable thresholds and queue selection is based
on hit count on entry. The policy aims to take different cache miss
costs into account and to adjust to varying load patterns automatically.
Message and constructor argument pairs are:
'sequential_threshold <#nr_sequential_ios>'
'random_threshold <#nr_random_ios>'
'read_promote_adjustment <value>'
'write_promote_adjustment <value>'
'discard_promote_adjustment <value>'
Stochastic multiqueue (smq)
---------------------------
The sequential threshold indicates the number of contiguous I/Os
required before a stream is treated as sequential. Once a stream is
considered sequential it will bypass the cache. The random threshold
is the number of intervening non-contiguous I/Os that must be seen
before the stream is treated as random again.
This policy is the default.
The sequential and random thresholds default to 512 and 4 respectively.
The stochastic multi-queue (smq) policy addresses some of the problems
with the multiqueue (mq) policy.
Large, sequential I/Os are probably better left on the origin device
since spindles tend to have good sequential I/O bandwidth. The
io_tracker counts contiguous I/Os to try to spot when the I/O is in one
of these sequential modes. But there are use-cases for wanting to
promote sequential blocks to the cache (e.g. fast application startup).
If sequential threshold is set to 0 the sequential I/O detection is
disabled and sequential I/O will no longer implicitly bypass the cache.
Setting the random threshold to 0 does _not_ disable the random I/O
stream detection.
The smq policy (vs mq) offers the promise of less memory utilization,
improved performance and increased adaptability in the face of changing
workloads. smq also does not have any cumbersome tuning knobs.
Users may switch from "mq" to "smq" simply by appropriately reloading a
DM table that is using the cache target. Doing so will cause all of the
mq policy's hints to be dropped. Also, performance of the cache may
degrade slightly until smq recalculates the origin device's hotspots
that should be cached.
Memory usage:
The mq policy used a lot of memory; 88 bytes per cache block on a 64
bit machine.
smq uses 28bit indexes to implement it's data structures rather than
pointers. It avoids storing an explicit hit count for each block. It
has a 'hotspot' queue, rather than a pre-cache, which uses a quarter of
the entries (each hotspot block covers a larger area than a single
cache block).
All this means smq uses ~25bytes per cache block. Still a lot of
memory, but a substantial improvement nontheless.
Level balancing:
mq placed entries in different levels of the multiqueue structures
based on their hit count (~ln(hit count)). This meant the bottom
levels generally had the most entries, and the top ones had very
few. Having unbalanced levels like this reduced the efficacy of the
multiqueue.
smq does not maintain a hit count, instead it swaps hit entries with
the least recently used entry from the level above. The overall
ordering being a side effect of this stochastic process. With this
scheme we can decide how many entries occupy each multiqueue level,
resulting in better promotion/demotion decisions.
Adaptability:
The mq policy maintained a hit count for each cache block. For a
different block to get promoted to the cache it's hit count has to
exceed the lowest currently in the cache. This meant it could take a
long time for the cache to adapt between varying IO patterns.
smq doesn't maintain hit counts, so a lot of this problem just goes
away. In addition it tracks performance of the hotspot queue, which
is used to decide which blocks to promote. If the hotspot queue is
performing badly then it starts moving entries more quickly between
levels. This lets it adapt to new IO patterns very quickly.
Performance:
Testing smq shows substantially better performance than mq.
Internally the mq policy determines a promotion threshold. If the hit
count of a block not in the cache goes above this threshold it gets
promoted to the cache. The read, write and discard promote adjustment
tunables allow you to tweak the promotion threshold by adding a small
value based on the io type. They default to 4, 8 and 1 respectively.
If you're trying to quickly warm a new cache device you may wish to
reduce these to encourage promotion. Remember to switch them back to
their defaults after the cache fills though.
cleaner
-------

View File

@@ -221,7 +221,6 @@ Status
<#read hits> <#read misses> <#write hits> <#write misses>
<#demotions> <#promotions> <#dirty> <#features> <features>*
<#core args> <core args>* <policy name> <#policy args> <policy args>*
<cache metadata mode>
metadata block size : Fixed block size for each metadata block in
sectors
@@ -252,18 +251,8 @@ core args : Key/value pairs for tuning the core
e.g. migration_threshold
policy name : Name of the policy
#policy args : Number of policy arguments to follow (must be even)
policy args : Key/value pairs e.g. sequential_threshold
cache metadata mode : ro if read-only, rw if read-write
In serious cases where even a read-only mode is deemed unsafe
no further I/O will be permitted and the status will just
contain the string 'Fail'. The userspace recovery tools
should then be used.
needs_check : 'needs_check' if set, '-' if not set
A metadata operation has failed, resulting in the needs_check
flag being set in the metadata's superblock. The metadata
device must be deactivated and checked/repaired before the
cache can be made fully operational again. '-' indicates
needs_check is not set.
policy args : Key/value pairs
e.g. sequential_threshold
Messages
--------

View File

@@ -8,7 +8,6 @@ Parameters:
<device> <offset> <delay> [<write_device> <write_offset> <write_delay>]
With separate write parameters, the first set is only used for reads.
Offsets are specified in sectors.
Delays are specified in milliseconds.
Example scripts

View File

@@ -209,37 +209,6 @@ include:
"repair" - Initiate a repair of the array.
"reshape"- Currently unsupported (-EINVAL).
Discard Support
---------------
The implementation of discard support among hardware vendors varies.
When a block is discarded, some storage devices will return zeroes when
the block is read. These devices set the 'discard_zeroes_data'
attribute. Other devices will return random data. Confusingly, some
devices that advertise 'discard_zeroes_data' will not reliably return
zeroes when discarded blocks are read! Since RAID 4/5/6 uses blocks
from a number of devices to calculate parity blocks and (for performance
reasons) relies on 'discard_zeroes_data' being reliable, it is important
that the devices be consistent. Blocks may be discarded in the middle
of a RAID 4/5/6 stripe and if subsequent read results are not
consistent, the parity blocks may be calculated differently at any time;
making the parity blocks useless for redundancy. It is important to
understand how your hardware behaves with discards if you are going to
enable discards with RAID 4/5/6.
Since the behavior of storage devices is unreliable in this respect,
even when reporting 'discard_zeroes_data', by default RAID 4/5/6
discard support is disabled -- this ensures data integrity at the
expense of losing some performance.
Storage devices that properly support 'discard_zeroes_data' are
increasingly whitelisted in the kernel and can thus be trusted.
For trusted devices, the following dm-raid module parameter can be set
to safely enable discard support for RAID 4/5/6:
'devices_handle_discards_safely'
Version History
---------------
1.0.0 Initial version. Support for RAID 4/5/6
@@ -255,5 +224,3 @@ Version History
New status (STATUSTYPE_INFO) fields: sync_action and mismatch_cnt.
1.5.1 Add ability to restore transiently failed devices on resume.
1.5.2 'mismatch_cnt' is zero unless [last_]sync_action is "check".
1.6.0 Add discard support (and devices_handle_discard_safely module param).
1.7.0 Add support for MD RAID0 mappings.

View File

@@ -41,13 +41,9 @@ useless and be disabled, returning errors. So it is important to monitor
the amount of free space and expand the <COW device> before it fills up.
<persistent?> is P (Persistent) or N (Not persistent - will not survive
after reboot). O (Overflow) can be added as a persistent store option
to allow userspace to advertise its support for seeing "Overflow" in the
snapshot status. So supported store types are "P", "PO" and "N".
The difference between persistent and transient is with transient
snapshots less metadata must be saved on disk - they can be kept in
memory by the kernel.
after reboot).
The difference is that for transient snapshots less metadata must be
saved on disk - they can be kept in memory by the kernel.
* snapshot-merge <origin> <COW device> <persistent> <chunksize>

View File

@@ -13,14 +13,9 @@ the range specified.
The I/O statistics counters for each step-sized area of a region are
in the same format as /sys/block/*/stat or /proc/diskstats (see:
Documentation/iostats.txt). But two extra counters (12 and 13) are
provided: total time spent reading and writing. When the histogram
argument is used, the 14th parameter is reported that represents the
histogram of latencies. All these counters may be accessed by sending
the @stats_print message to the appropriate DM device via dmsetup.
The reported times are in milliseconds and the granularity depends on
the kernel ticks. When the option precise_timestamps is used, the
reported times are in nanoseconds.
provided: total time spent reading and writing in milliseconds. All
these counters may be accessed by sending the @stats_print message to
the appropriate DM device via dmsetup.
Each region has a corresponding unique identifier, which we call a
region_id, that is assigned when the region is created. The region_id
@@ -38,9 +33,7 @@ memory is used by reading
Messages
========
@stats_create <range> <step>
[<number_of_optional_arguments> <optional_arguments>...]
[<program_id> [<aux_data>]]
@stats_create <range> <step> [<program_id> [<aux_data>]]
Create a new region and return the region_id.
@@ -55,29 +48,6 @@ Messages
"/<number_of_areas>" - the range is subdivided into the specified
number of areas.
<number_of_optional_arguments>
The number of optional arguments
<optional_arguments>
The following optional arguments are supported
precise_timestamps - use precise timer with nanosecond resolution
instead of the "jiffies" variable. When this argument is
used, the resulting times are in nanoseconds instead of
milliseconds. Precise timestamps are a little bit slower
to obtain than jiffies-based timestamps.
histogram:n1,n2,n3,n4,... - collect histogram of latencies. The
numbers n1, n2, etc are times that represent the boundaries
of the histogram. If precise_timestamps is not used, the
times are in milliseconds, otherwise they are in
nanoseconds. For each range, the kernel will report the
number of requests that completed within this range. For
example, if we use "histogram:10,20,30", the kernel will
report four numbers a:b:c:d. a is the number of requests
that took 0-10 ms to complete, b is the number of requests
that took 10-20 ms to complete, c is the number of requests
that took 20-30 ms to complete and d is the number of
requests that took more than 30 ms to complete.
<program_id>
An optional parameter. A name that uniquely identifies
the userspace owner of the range. This groups ranges together
@@ -85,9 +55,6 @@ Messages
created and ignore those created by others.
The kernel returns this string back in the output of
@stats_list message, but it doesn't use it for anything else.
If we omit the number of optional arguments, program id must not
be a number, otherwise it would be interpreted as the number of
optional arguments.
<aux_data>
An optional parameter. A word that provides auxiliary data
@@ -121,10 +88,6 @@ Messages
Output format:
<region_id>: <start_sector>+<length> <step> <program_id> <aux_data>
precise_timestamps histogram:n1,n2,n3,...
The strings "precise_timestamps" and "histogram" are printed only
if they were specified when creating the region.
@stats_print <region_id> [<starting_line> <number_of_lines>]
@@ -205,7 +168,7 @@ statistics on them:
dmsetup message vol 0 @stats_create - /100
Set the auxiliary data string to "foo bar baz" (the escape for each
Set the auxillary data string to "foo bar baz" (the escape for each
space must also be escaped, otherwise the shell will consume them):
dmsetup message vol 0 @stats_set_aux 0 foo\\ bar\\ baz

View File

@@ -296,7 +296,7 @@ ii) Status
underlying device. When this is enabled when loading the table,
it can get disabled if the underlying device doesn't support it.
ro|rw|out_of_data_space
ro|rw
If the pool encounters certain types of device failures it will
drop into a read-only metadata mode in which no changes to
the pool metadata (like allocating new blocks) are permitted.
@@ -314,13 +314,6 @@ ii) Status
module parameter can be used to change this timeout -- it
defaults to 60 seconds but may be disabled using a value of 0.
needs_check
A metadata operation has failed, resulting in the needs_check
flag being set in the metadata's superblock. The metadata
device must be deactivated and checked/repaired before the
thin-pool can be made fully operational again. '-' indicates
needs_check is not set.
iii) Messages
create_thin <dev id>

View File

@@ -18,11 +18,11 @@ Construction Parameters
0 is the original format used in the Chromium OS.
The salt is appended when hashing, digests are stored continuously and
the rest of the block is padded with zeroes.
the rest of the block is padded with zeros.
1 is the current format that should be used for new devices.
The salt is prepended when hashing and each digest is
padded with zeroes to the power of two.
padded with zeros to the power of two.
<dev>
This is the device containing data, the integrity of which needs to be
@@ -79,37 +79,6 @@ restart_on_corruption
not compatible with ignore_corruption and requires user space support to
avoid restart loops.
ignore_zero_blocks
Do not verify blocks that are expected to contain zeroes and always return
zeroes instead. This may be useful if the partition contains unused blocks
that are not guaranteed to contain zeroes.
use_fec_from_device <fec_dev>
Use forward error correction (FEC) to recover from corruption if hash
verification fails. Use encoding data from the specified device. This
may be the same device where data and hash blocks reside, in which case
fec_start must be outside data and hash areas.
If the encoding data covers additional metadata, it must be accessible
on the hash device after the hash blocks.
Note: block sizes for data and hash devices must match. Also, if the
verity <dev> is encrypted the <fec_dev> should be too.
fec_roots <num>
Number of generator roots. This equals to the number of parity bytes in
the encoding data. For example, in RS(M, N) encoding, the number of roots
is M-N.
fec_blocks <num>
The number of encoding data blocks on the FEC device. The block size for
the FEC device is <data_block_size>.
fec_start <offset>
This is the offset, in <data_block_size> blocks, from the start of the
FEC device to the beginning of the encoding data.
Theory of operation
===================
@@ -129,11 +98,6 @@ per-block basis. This allows for a lightweight hash computation on first read
into the page cache. Block hashes are stored linearly, aligned to the nearest
block size.
If forward error correction (FEC) support is enabled any recovery of
corrupted data will be verified using the cryptographic hash of the
corresponding data. This is why combining error correction with
integrity checking is essential.
Hash Tree
---------

View File

@@ -50,7 +50,6 @@
@top_srcdir@/lib/misc/lvm-file.h
@top_srcdir@/lib/misc/lvm-flock.h
@top_srcdir@/lib/misc/lvm-globals.h
@top_srcdir@/lib/misc/lvm-maths.h
@top_srcdir@/lib/misc/lvm-percent.h
@top_srcdir@/lib/misc/lvm-signal.h
@top_srcdir@/lib/misc/lvm-string.h
@@ -59,7 +58,6 @@
@top_srcdir@/lib/misc/util.h
@top_srcdir@/lib/mm/memlock.h
@top_srcdir@/lib/mm/xlate.h
@top_srcdir@/lib/notify/lvmnotify.h
@top_srcdir@/lib/properties/prop_common.h
@top_srcdir@/lib/report/properties.h
@top_srcdir@/lib/report/report.h

View File

@@ -264,15 +264,9 @@
/* Define to 1 if you have the <limits.h> header file. */
#undef HAVE_LIMITS_H
/* Define to 1 if you have the <linux/fiemap.h> header file. */
#undef HAVE_LINUX_FIEMAP_H
/* Define to 1 if you have the <linux/fs.h> header file. */
#undef HAVE_LINUX_FS_H
/* Define to 1 if you have the <linux/magic.h> header file. */
#undef HAVE_LINUX_MAGIC_H
/* Define to 1 if you have the <locale.h> header file. */
#undef HAVE_LOCALE_H
@@ -341,9 +335,6 @@
/* Define to 1 if the system has the type `ptrdiff_t'. */
#undef HAVE_PTRDIFF_T
/* Define to 1 if the compiler has the `__builtin_clz` builtin. */
#undef HAVE___BUILTIN_CLZ
/* Define to 1 if you have the <readline/history.h> header file. */
#undef HAVE_READLINE_HISTORY_H
@@ -640,9 +631,6 @@
/* The path to 'modprobe', if available. */
#undef MODPROBE_CMD
/* Define to 1 to include code that uses dbus notification. */
#undef NOTIFYDBUS_SUPPORT
/* Define to 1 to enable O_DIRECT support. */
#undef O_DIRECT_SUPPORT

View File

@@ -76,7 +76,6 @@ SOURCES =\
filters/filter-partitioned.c \
filters/filter-type.c \
filters/filter-usable.c \
filters/filter-internal.c \
format_text/archive.c \
format_text/archiver.c \
format_text/export.c \
@@ -112,13 +111,11 @@ SOURCES =\
misc/lvm-file.c \
misc/lvm-flock.c \
misc/lvm-globals.c \
misc/lvm-maths.c \
misc/lvm-signal.c \
misc/lvm-string.c \
misc/lvm-wrappers.c \
misc/lvm-percent.c \
mm/memlock.c \
notify/lvmnotify.c \
properties/prop_common.c \
report/properties.c \
report/report.c \
@@ -218,7 +215,6 @@ ifeq ($(MAKECMDGOALS),distclean)
format_pool \
snapshot \
mirror \
notify \
raid \
replicator \
thin \

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004-2016 Red Hat, Inc. All rights reserved.
* Copyright (C) 2004-2013 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
@@ -253,9 +253,8 @@ int lv_status(struct cmd_context *cmd, const struct lv_segment *lv_seg,
int lv_cache_status(const struct logical_volume *cache_lv,
struct lv_status_cache **status)
{
return 0;
}
int lv_check_not_in_use(const struct logical_volume *lv, int error_if_used)
int lv_check_not_in_use(const struct logical_volume *lv)
{
return 0;
}
@@ -288,6 +287,18 @@ int lv_raid_message(const struct logical_volume *lv, const char *msg)
{
return 0;
}
int lv_cache_block_info(struct logical_volume *lv,
uint32_t *chunk_size, uint64_t *dirty_count,
uint64_t *used_count, uint64_t *total_count)
{
return 0;
}
int lv_cache_policy_info(struct logical_volume *lv,
const char **policy_name, int *policy_argc,
const char ***policy_argv)
{
return 0;
}
int lv_thin_pool_percent(const struct logical_volume *lv, int metadata,
dm_percent_t *percent)
{
@@ -358,10 +369,6 @@ int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv)
{
return 1;
}
int lv_deactivate_any_missing_subdevs(const struct logical_volume *lv)
{
return 1;
}
int pv_uses_vg(struct physical_volume *pv,
struct volume_group *vg)
{
@@ -374,11 +381,6 @@ void activation_exit(void)
{
}
int raid4_is_supported(struct cmd_context *cmd, const struct segment_type *segtype)
{
return 1;
}
int lv_is_active(const struct logical_volume *lv)
{
return 0;
@@ -601,24 +603,7 @@ int module_present(struct cmd_context *cmd, const char *target_name)
#ifdef MODPROBE_CMD
char module[128];
const char *argv[] = { MODPROBE_CMD, module, NULL };
#endif
struct stat st;
char path[PATH_MAX];
int i = dm_snprintf(path, (sizeof(path) - 1), "%smodule/dm_%s",
dm_sysfs_dir(), target_name);
if (i > 0) {
while (path[--i] != '/') /* stop on dm_ */
if (path[i] == '-')
path[i] = '_'; /* replace '-' with '_' */
if ((lstat(path, &st) == 0) && S_ISDIR(st.st_mode)) {
log_debug_activation("Module directory %s exists.", path);
return 1;
}
}
#ifdef MODPROBE_CMD
if (dm_snprintf(module, sizeof(module), "dm-%s", target_name) < 0) {
log_error("module_present module name too long: %s",
target_name);
@@ -630,39 +615,27 @@ int module_present(struct cmd_context *cmd, const char *target_name)
return ret;
}
int target_present_version(struct cmd_context *cmd, const char *target_name,
int use_modprobe,
uint32_t *maj, uint32_t *min, uint32_t *patchlevel)
int target_present(struct cmd_context *cmd, const char *target_name,
int use_modprobe)
{
if (!activation()) {
log_error(INTERNAL_ERROR "Target present version called when activation is disabled.");
uint32_t maj, min, patchlevel;
if (!activation())
return 0;
}
#ifdef MODPROBE_CMD
if (use_modprobe) {
if (target_version(target_name, maj, min, patchlevel))
if (target_version(target_name, &maj, &min, &patchlevel))
return 1;
if (!module_present(cmd, target_name))
return_0;
}
#endif
return target_version(target_name, maj, min, patchlevel);
return target_version(target_name, &maj, &min, &patchlevel);
}
int target_present(struct cmd_context *cmd, const char *target_name,
int use_modprobe)
{
uint32_t maj, min, patchlevel;
return target_present_version(cmd, target_name, use_modprobe,
&maj, &min, &patchlevel);
}
/*
* When '*info' is NULL, returns 1 only when LV is active.
* When '*info' != NULL, returns 1 when info structure is populated.
*/
static int _lv_info(struct cmd_context *cmd, const struct logical_volume *lv,
int use_layer, struct lvinfo *info,
const struct lv_segment *seg,
@@ -687,18 +660,16 @@ static int _lv_info(struct cmd_context *cmd, const struct logical_volume *lv,
/* New thin-pool has no layer, but -tpool suffix needs to be queried */
if (!use_layer && lv_is_new_thin_pool(lv)) {
/* Check if there isn't existing old thin pool mapping in the table */
if (!dev_manager_info(cmd, lv, NULL, 0, 0, &dminfo, NULL, NULL))
if (!dev_manager_info(cmd->mem, lv, NULL, 0, 0, &dminfo, NULL, NULL))
return_0;
if (!dminfo.exists)
use_layer = 1;
}
if (seg_status) {
/* TODO: for now it's mess with seg_status */
if (seg_status)
seg_status->seg = seg;
}
if (!dev_manager_info(cmd, lv,
if (!dev_manager_info(cmd->mem, lv,
(use_layer) ? lv_layer(lv) : NULL,
with_open_count, with_read_ahead,
&dminfo, (info) ? &info->read_ahead : NULL,
@@ -749,103 +720,50 @@ int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s, int use_layer,
}
/*
* Returns 1 if lv_with_info_and_seg_status info structure populated,
* Returns 1 if lv_seg_status structure populated,
* else 0 on failure or if device not active locally.
*
* When seg_status parsing had troubles it will set type to SEG_STATUS_UNKNOWN.
*
* Using usually one ioctl to obtain info and status.
* More complex segment do collect info from one device,
* but status from another device.
*
* TODO: further improve with more statuses (i.e. snapshot's origin/merge)
*/
int lv_info_with_seg_status(struct cmd_context *cmd,
const struct lv_segment *lv_seg,
struct lv_with_info_and_seg_status *status,
int with_open_count, int with_read_ahead)
int lv_status(struct cmd_context *cmd, const struct lv_segment *lv_seg,
int use_layer, struct lv_seg_status *lv_seg_status)
{
const struct logical_volume *olv, *lv = status->lv = lv_seg->lv;
if (!activation())
return 0;
if (lv_is_used_cache_pool(lv)) {
/* INFO is not set as cache-pool cannot be active.
* STATUS is collected from cache LV */
lv_seg = get_only_segment_using_this_lv(lv);
(void) _lv_info(cmd, lv_seg->lv, 1, NULL, lv_seg, &status->seg_status, 0, 0);
return 1;
}
return _lv_info(cmd, lv_seg->lv, use_layer, NULL, lv_seg, lv_seg_status, 0, 0);
}
if (lv_is_thin_pool(lv)) {
/* Always collect status for '-tpool' */
if (_lv_info(cmd, lv, 1, &status->info, lv_seg, &status->seg_status, 0, 0) &&
(status->seg_status.type == SEG_STATUS_THIN_POOL)) {
/* There is -tpool device, but query 'active' state of 'fake' thin-pool */
if (!_lv_info(cmd, lv, 0, NULL, NULL, NULL, 0, 0) &&
!status->seg_status.thin_pool->needs_check)
status->info.exists = 0; /* So pool LV is not active */
}
return 1;
} else if (lv_is_external_origin(lv)) {
if (!_lv_info(cmd, lv, 0, &status->info, NULL, NULL,
with_open_count, with_read_ahead))
return_0;
/*
* Returns 1 if lv_with_info_and_seg_status structure populated,
* else 0 on failure or if device not active locally.
*
* This is the same as calling lv_info and lv_status,
* but* it's done in one go with one ioctl if possible! ]
*/
int lv_info_with_seg_status(struct cmd_context *cmd, const struct logical_volume *lv,
const struct lv_segment *lv_seg, int use_layer,
struct lv_with_info_and_seg_status *status,
int with_open_count, int with_read_ahead)
{
if (!activation())
return 0;
(void) _lv_info(cmd, lv, 1, NULL, lv_seg, &status->seg_status, 0, 0);
return 1;
} else if (lv_is_origin(lv)) {
/* Query segment status for 'layered' (-real) device most of the time,
* only for merging snapshot, query its progress.
* TODO: single LV may need couple status to be exposed at once....
* but this needs more logical background
*/
/* Show INFO for actual origin and grab status for merging origin */
if (!_lv_info(cmd, lv, 0, &status->info, lv_seg,
lv_is_merging_origin(lv) ? &status->seg_status : NULL,
with_open_count, with_read_ahead))
return_0;
if (lv == lv_seg->lv)
return _lv_info(cmd, lv, use_layer, &status->info, lv_seg, &status->seg_status,
with_open_count, with_read_ahead);
if (status->info.exists &&
(status->seg_status.type != SEG_STATUS_SNAPSHOT)) /* Not merging */
/* Grab STATUS from layered -real */
(void) _lv_info(cmd, lv, 1, NULL, lv_seg, &status->seg_status, 0, 0);
return 1;
} else if (lv_is_cow(lv)) {
if (lv_is_merging_cow(lv)) {
olv = origin_from_cow(lv);
if (!_lv_info(cmd, olv, 0, &status->info, first_seg(olv), &status->seg_status,
with_open_count, with_read_ahead))
return_0;
if (status->seg_status.type == SEG_STATUS_SNAPSHOT) {
log_debug_activation("Snapshot merge is in progress, querying status of %s instead.",
display_lvname(lv));
/*
* When merge is in progress, query merging origin LV instead.
* COW volume is already mapped as error target in this case.
*/
status->lv = olv;
return 1;
}
/* Merge not yet started, still a snapshot... */
}
/* Hadle fictional lvm2 snapshot and query snapshotX volume */
lv_seg = find_snapshot(lv);
}
return _lv_info(cmd, lv, 0, &status->info, lv_seg, &status->seg_status,
with_open_count, with_read_ahead);
/*
* If the info is requested for an LV and segment
* status for segment that belong to another LV,
* we need to acquire info and status separately!
*/
return _lv_info(cmd, lv, use_layer, &status->info, NULL, NULL, with_open_count, with_read_ahead) &&
_lv_info(cmd, lv_seg->lv, use_layer, NULL, lv_seg, &status->seg_status, 0, 0);
}
#define OPEN_COUNT_CHECK_RETRIES 25
#define OPEN_COUNT_CHECK_USLEEP_DELAY 200000
/* Only report error if error_if_used is set */
int lv_check_not_in_use(const struct logical_volume *lv, int error_if_used)
int lv_check_not_in_use(const struct logical_volume *lv)
{
struct lvinfo info;
unsigned int open_count_check_retries;
@@ -856,22 +774,14 @@ int lv_check_not_in_use(const struct logical_volume *lv, int error_if_used)
/* If sysfs is not used, use open_count information only. */
if (dm_sysfs_dir()) {
if (dm_device_has_holders(info.major, info.minor)) {
if (error_if_used)
log_error("Logical volume %s is used by another device.",
display_lvname(lv));
else
log_debug_activation("Logical volume %s is used by another device.",
display_lvname(lv));
log_error("Logical volume %s is used by another device.",
display_lvname(lv));
return 0;
}
if (dm_device_has_mounted_fs(info.major, info.minor)) {
if (error_if_used)
log_error("Logical volume %s contains a filesystem in use.",
display_lvname(lv));
else
log_debug_activation("Logical volume %s contains a filesystem in use.",
display_lvname(lv));
log_error("Logical volume %s contains a filesystem in use.",
display_lvname(lv));
return 0;
}
}
@@ -879,10 +789,8 @@ int lv_check_not_in_use(const struct logical_volume *lv, int error_if_used)
open_count_check_retries = retry_deactivation() ? OPEN_COUNT_CHECK_RETRIES : 1;
while (info.open_count > 0 && open_count_check_retries--) {
if (!open_count_check_retries) {
if (error_if_used)
log_error("Logical volume %s in use.", display_lvname(lv));
else
log_debug_activation("Logical volume %s in use.", display_lvname(lv));
log_error("Logical volume %s in use.",
display_lvname(lv));
return 0;
}
@@ -1159,29 +1067,19 @@ int lv_cache_status(const struct logical_volume *cache_lv,
struct dev_manager *dm;
struct lv_segment *cache_seg;
if (lv_is_cache_pool(cache_lv)) {
if (dm_list_empty(&cache_lv->segs_using_this_lv) ||
!(cache_seg = get_only_segment_using_this_lv(cache_lv))) {
log_error(INTERNAL_ERROR "Cannot check status for unused cache pool %s.",
display_lvname(cache_lv));
return 0;
}
if (lv_is_cache_pool(cache_lv) && !dm_list_empty(&cache_lv->segs_using_this_lv)) {
if (!(cache_seg = get_only_segment_using_this_lv(cache_lv)))
return_0;
cache_lv = cache_seg->lv;
}
if (lv_is_pending_delete(cache_lv)) {
log_error("Cannot check status for deleted cache volume %s.",
display_lvname(cache_lv));
if (lv_is_pending_delete(cache_lv))
return 0;
}
if (!lv_info(cache_lv->vg->cmd, cache_lv, 1, NULL, 0, 0)) {
log_error("Cannot check status for locally inactive cache volume %s.",
display_lvname(cache_lv));
if (!lv_info(cache_lv->vg->cmd, cache_lv, 0, NULL, 0, 0))
return 0;
}
log_debug_activation("Checking status for cache volume %s.",
log_debug_activation("Checking cache status for LV %s.",
display_lvname(cache_lv));
if (!(dm = dev_manager_create(cache_lv->vg->cmd, cache_lv->vg->name, 1)))
@@ -1262,13 +1160,13 @@ int lv_thin_pool_transaction_id(const struct logical_volume *lv,
if (!lv_info(lv->vg->cmd, lv, 1, NULL, 0, 0))
return 0;
log_debug_activation("Checking thin-pool transaction id for LV %s.",
log_debug_activation("Checking thin-pool percent for LV %s.",
display_lvname(lv));
if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name, 1)))
return_0;
if (!(r = dev_manager_thin_pool_status(dm, lv, &status, 0)))
if (!(r = dev_manager_thin_pool_status(dm, lv, &status, 1)))
stack;
else
*transaction_id = status->transaction_id;
@@ -1305,10 +1203,8 @@ static int _lv_active(struct cmd_context *cmd, const struct logical_volume *lv)
struct lvinfo info;
if (!lv_info(cmd, lv, 0, &info, 0, 0)) {
log_debug("Cannot determine activation status of %s%s.",
display_lvname(lv),
activation() ? "" : " (no device driver)");
return 0;
stack;
return -1;
}
return info.exists;
@@ -1433,7 +1329,7 @@ int lvs_in_vg_opened(const struct volume_group *vg)
if (lv_is_visible(lvl->lv))
count += (_lv_open_count(vg->cmd, lvl->lv) > 0);
log_debug_activation("Counted %d open LVs in VG %s.", count, vg->name);
log_debug_activation("Counted %d open LVs in VG %s", count, vg->name);
return count;
}
@@ -1495,9 +1391,9 @@ static int _lv_is_active(const struct logical_volume *lv,
* Old users of this function will never be affected by this,
* since they are only concerned about active vs. not active.
* New users of this function who specifically ask for 'exclusive'
* will be given a warning message.
* will be given an error message.
*/
log_warn("WARNING: Unable to determine exclusivity of %s.", display_lvname(lv));
log_error("Unable to determine exclusivity of %s.", display_lvname(lv));
e = 0;
@@ -1528,26 +1424,6 @@ out:
return r || l;
}
/*
* Check if "raid4" @segtype is supported by kernel.
*
* if segment type is not raid4, return 1.
*/
int raid4_is_supported(struct cmd_context *cmd, const struct segment_type *segtype)
{
unsigned attrs;
if (segtype_is_raid4(segtype) &&
(!segtype->ops->target_present ||
!segtype->ops->target_present(cmd, NULL, &attrs) ||
!(attrs & RAID_FEATURE_RAID4))) {
log_error("RAID module does not support RAID4.");
return 0;
}
return 1;
}
int lv_is_active(const struct logical_volume *lv)
{
return _lv_is_active(lv, NULL, NULL, NULL);
@@ -1607,7 +1483,7 @@ static struct dm_event_handler *_create_dm_event_handler(struct cmd_context *cmd
if (dm_event_handler_set_dmeventd_path(dmevh, find_config_tree_str(cmd, dmeventd_executable_CFG, NULL)))
goto_bad;
if (dso && dm_event_handler_set_dso(dmevh, dso))
if (dm_event_handler_set_dso(dmevh, dso))
goto_bad;
if (dm_event_handler_set_uuid(dmevh, dmuuid))
@@ -1651,39 +1527,6 @@ static char *_build_target_uuid(struct cmd_context *cmd, const struct logical_vo
return build_dm_uuid(cmd->mem, lv, layer);
}
static int _device_registered_with_dmeventd(struct cmd_context *cmd, const struct logical_volume *lv, int *pending, const char **dso)
{
char *uuid;
enum dm_event_mask evmask = 0;
struct dm_event_handler *dmevh;
*pending = 0;
if (!(uuid = _build_target_uuid(cmd, lv)))
return_0;
if (!(dmevh = _create_dm_event_handler(cmd, uuid, NULL, 0, DM_EVENT_ALL_ERRORS)))
return_0;
if (dm_event_get_registered_device(dmevh, 0)) {
dm_event_handler_destroy(dmevh);
return 0;
}
evmask = dm_event_handler_get_event_mask(dmevh);
if (evmask & DM_EVENT_REGISTRATION_PENDING) {
*pending = 1;
evmask &= ~DM_EVENT_REGISTRATION_PENDING;
}
if (dso && (*dso = dm_event_handler_get_dso(dmevh)) && !(*dso = dm_pool_strdup(cmd->mem, *dso)))
log_error("Failed to duplicate dso name.");
dm_event_handler_destroy(dmevh);
return evmask;
}
int target_registered_with_dmeventd(struct cmd_context *cmd, const char *dso,
const struct logical_volume *lv, int *pending)
{
@@ -1742,7 +1585,7 @@ int target_register_events(struct cmd_context *cmd, const char *dso, const struc
if (!r)
return_0;
log_very_verbose("%s %s for events", set ? "Monitored" : "Unmonitored", uuid);
log_info("%s %s for events", set ? "Monitored" : "Unmonitored", uuid);
return 1;
}
@@ -1766,8 +1609,6 @@ int monitor_dev_for_events(struct cmd_context *cmd, const struct logical_volume
uint32_t s;
static const struct lv_activate_opts zlaopts = { 0 };
struct lvinfo info;
const char *dso = NULL;
int new_unmonitor;
if (!laopts)
laopts = &zlaopts;
@@ -1782,23 +1623,6 @@ int monitor_dev_for_events(struct cmd_context *cmd, const struct logical_volume
if (monitor && !dmeventd_monitor_mode())
return 1;
/*
* Activation of unused cache-pool activates metadata device as
* a public LV for clearing purpose.
* FIXME:
* As VG lock is held across whole operation unmonitored volume
* is usually OK since dmeventd couldn't do anything.
* However in case command would have crashed, such LV is
* left unmonitored and may potentially require dmeventd.
*/
if ((lv_is_cache_pool_data(lv) || lv_is_cache_pool_metadata(lv)) &&
!lv_is_used_cache_pool((find_pool_seg(first_seg(lv))->lv))) {
log_debug_activation("Skipping %smonitor of %s.%s",
(monitor) ? "" : "un", display_lvname(lv),
(monitor) ? " Cache pool activation for clearing only." : "");
return 1;
}
/*
* Allow to unmonitor thin pool via explicit pool unmonitor
* or unmonitor before the last thin pool user deactivation
@@ -1833,8 +1657,7 @@ int monitor_dev_for_events(struct cmd_context *cmd, const struct logical_volume
/*
* In case this LV is a snapshot origin, we instead monitor
* each of its respective snapshots. The origin itself may
* also need to be monitored if it is a mirror, for example,
* so fall through to process it afterwards.
* also need to be monitored if it is a mirror, for example.
*/
if (!laopts->origin_only && lv_is_origin(lv))
dm_list_iterate_safe(snh, snht, &lv->snapshot_segs)
@@ -1893,58 +1716,42 @@ int monitor_dev_for_events(struct cmd_context *cmd, const struct logical_volume
!seg->segtype->ops->target_monitored) /* doesn't support registration */
continue;
if (!monitor)
/* When unmonitoring, obtain existing dso being used. */
monitored = _device_registered_with_dmeventd(cmd, seg_is_snapshot(seg) ? seg->cow : seg->lv, &pending, &dso);
else
monitored = seg->segtype->ops->target_monitored(seg, &pending);
monitored = seg->segtype->ops->target_monitored(seg, &pending);
/* FIXME: We should really try again if pending */
monitored = (pending) ? 0 : monitored;
monitor_fn = NULL;
new_unmonitor = 0;
if (monitor) {
if (monitored)
log_verbose("%s already monitored.", display_lvname(lv));
else if (seg->segtype->ops->target_monitor_events) {
log_verbose("Monitoring %s%s", display_lvname(lv), test_mode() ? " [Test mode: skipping this]" : "");
else if (seg->segtype->ops->target_monitor_events)
monitor_fn = seg->segtype->ops->target_monitor_events;
}
} else {
if (!monitored)
log_verbose("%s already not monitored.", display_lvname(lv));
else if (dso && *dso) {
/*
* Divert unmonitor away from code that depends on the new segment
* type instead of the existing one if it's changing.
*/
log_verbose("Not monitoring %s with %s%s", display_lvname(lv), dso, test_mode() ? " [Test mode: skipping this]" : "");
new_unmonitor = 1;
}
else if (seg->segtype->ops->target_unmonitor_events)
monitor_fn = seg->segtype->ops->target_unmonitor_events;
}
/* Do [un]monitor */
if (!monitor_fn)
continue;
log_verbose("%sonitoring %s%s", monitor ? "M" : "Not m", display_lvname(lv),
test_mode() ? " [Test mode: skipping this]" : "");
/* FIXME Test mode should really continue a bit further. */
if (test_mode())
continue;
if (new_unmonitor) {
if (!target_register_events(cmd, dso, seg_is_snapshot(seg) ? seg->cow : lv, 0, 0, 10)) {
log_error("%s: segment unmonitoring failed.",
display_lvname(lv));
return 0;
}
} else if (monitor_fn) {
/* FIXME specify events */
if (!monitor_fn(seg, 0)) {
log_error("%s: %s segment monitoring function failed.",
display_lvname(lv), lvseg_name(seg));
return 0;
}
} else
continue;
/* FIXME specify events */
if (!monitor_fn(seg, 0)) {
log_error("%s: %s segment monitoring function failed.",
display_lvname(lv), seg->segtype->name);
return 0;
}
/* Check [un]monitor results */
/* Try a couple times if pending, but not forever... */
@@ -2020,7 +1827,7 @@ static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s,
const struct logical_volume *lv_pre_to_free = NULL;
struct logical_volume *lv_pre_tmp;
struct seg_list *sl;
struct lv_segment *snap_seg;
struct lv_segment *snap_seg;
struct lvinfo info;
int r = 0, lockfs = 0, flush_required = 0;
struct detached_lv_data detached;
@@ -2126,16 +1933,6 @@ static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s,
}
}
/* Flush is ATM required for the tested cases
* NOTE: Mirror repair requires noflush for proper repair!
* TODO: Relax this limiting condition further */
if (!flush_required &&
(lv_is_pvmove(lv) ||
(!lv_is_mirror(lv) && !lv_is_thin_pool(lv) && !lv_is_thin_volume(lv)))) {
log_debug("Requiring flush for LV %s.", display_lvname(lv));
flush_required = 1;
}
if (!monitor_dev_for_events(cmd, lv, laopts, 0))
/* FIXME Consider aborting here */
stack;
@@ -2256,7 +2053,6 @@ static int _lv_resume(struct cmd_context *cmd, const char *lvid_s,
}
laopts->read_only = _passes_readonly_filter(cmd, lv);
laopts->resuming = 1;
if (!_lv_activate_lv(lv, laopts))
goto_out;
@@ -2311,7 +2107,7 @@ static int _lv_has_open_snapshots(const struct logical_volume *lv)
int r = 0;
dm_list_iterate_items_gen(snap_seg, &lv->snapshot_segs, origin_list)
if (!lv_check_not_in_use(snap_seg->cow, 1))
if (!lv_check_not_in_use(snap_seg->cow))
r++;
if (r)
@@ -2365,7 +2161,7 @@ int lv_deactivate(struct cmd_context *cmd, const char *lvid_s, const struct logi
if (lv_is_visible(lv) || lv_is_virtual_origin(lv) ||
lv_is_merging_thin_snapshot(lv)) {
if (!lv_check_not_in_use(lv, 1))
if (!lv_check_not_in_use(lv))
goto_out;
if (lv_is_origin(lv) && _lv_has_open_snapshots(lv))
@@ -2447,7 +2243,7 @@ static int _lv_activate(struct cmd_context *cmd, const char *lvid_s,
goto out;
}
if ((!lv->vg->cmd->partial_activation) && lv_is_partial(lv)) {
if ((!lv->vg->cmd->partial_activation) && (lv->status & PARTIAL_LV)) {
if (!lv_is_raid_type(lv) || !partial_raid_lv_supports_degraded_activation(lv)) {
log_error("Refusing activation of partial LV %s. "
"Use '--activationmode partial' to override.",
@@ -2503,7 +2299,7 @@ static int _lv_activate(struct cmd_context *cmd, const char *lvid_s,
if (info.exists && !info.suspended && info.live_table &&
(info.read_only == read_only_lv(lv, laopts))) {
r = 1;
log_debug_activation("LV %s is already active.", display_lvname(lv));
log_debug_activation("Volume is already active.");
goto out;
}
@@ -2577,77 +2373,6 @@ int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv)
return r;
}
/* Remove any existing, closed mapped device by @name */
static int _remove_dm_dev_by_name(const char *name)
{
int r = 0;
struct dm_task *dmt;
struct dm_info info;
if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
return_0;
/* Check, if the device exists. */
if (dm_task_set_name(dmt, name) && dm_task_run(dmt) && dm_task_get_info(dmt, &info)) {
dm_task_destroy(dmt);
/* Ignore non-existing or open dm devices */
if (!info.exists || info.open_count)
return 1;
if (!(dmt = dm_task_create(DM_DEVICE_REMOVE)))
return_0;
if (dm_task_set_name(dmt, name))
r = dm_task_run(dmt);
}
dm_task_destroy(dmt);
return r;
}
/* Work all segments of @lv removing any existing, closed "*-missing_N_0" sub devices. */
static int _lv_remove_any_missing_subdevs(struct logical_volume *lv)
{
if (lv) {
uint32_t seg_no = 0;
char name[257];
struct lv_segment *seg;
dm_list_iterate_items(seg, &lv->segments) {
if (seg->area_count != 1)
return_0;
if (dm_snprintf(name, sizeof(name), "%s-%s-missing_%u_0", seg->lv->vg->name, seg->lv->name, seg_no) < 0)
return 0;
if (!_remove_dm_dev_by_name(name))
return 0;
seg_no++;
}
}
return 1;
}
/* Remove any "*-missing_*" sub devices added by the activation layer for an rmate/rimage missing PV mapping */
int lv_deactivate_any_missing_subdevs(const struct logical_volume *lv)
{
uint32_t s;
struct lv_segment *seg = first_seg(lv);
for (s = 0; s < seg->area_count; s++) {
if (seg_type(seg, s) == AREA_LV &&
!_lv_remove_any_missing_subdevs(seg_lv(seg, s)))
return 0;
if (seg->meta_areas && seg_metatype(seg, s) == AREA_LV &&
!_lv_remove_any_missing_subdevs(seg_metalv(seg, s)))
return 0;
}
return 1;
}
/*
* Does PV use VG somewhere in its construction?
* Returns 1 on failure.

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004-2016 Red Hat, Inc. All rights reserved.
* Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
@@ -54,12 +54,11 @@ struct lv_seg_status {
};
struct lv_with_info_and_seg_status {
const struct logical_volume *lv; /* input */
int info_ok;
const struct logical_volume *lv; /* output */
struct lvinfo info; /* output */
int seg_part_of_lv; /* output */
struct lv_seg_status seg_status; /* output, see lv_seg_status */
/* TODO: add extra status for snapshot origin */
struct lv_seg_status seg_status; /* input/output, see lv_seg_status */
};
struct lv_activate_opts {
@@ -82,7 +81,6 @@ struct lv_activate_opts {
* set of flags to avoid any scanning in udev. These udev
* flags are persistent in udev db for any spurious event
* that follows. */
unsigned resuming; /* Set when resuming after a suspend. */
};
void set_activation(int activation, int silent);
@@ -93,14 +91,10 @@ int library_version(char *version, size_t size);
int lvm1_present(struct cmd_context *cmd);
int module_present(struct cmd_context *cmd, const char *target_name);
int target_present_version(struct cmd_context *cmd, const char *target_name,
int use_modprobe, uint32_t *maj,
uint32_t *min, uint32_t *patchlevel);
int target_present(struct cmd_context *cmd, const char *target_name,
int use_modprobe);
int target_version(const char *target_name, uint32_t *maj,
uint32_t *min, uint32_t *patchlevel);
int raid4_is_supported(struct cmd_context *cmd, const struct segment_type *segtype);
int lvm_dm_prefix_check(int major, int minor, const char *prefix);
int list_segment_modules(struct dm_pool *mem, const struct lv_segment *seg,
struct dm_list *modules);
@@ -124,8 +118,6 @@ int lv_deactivate(struct cmd_context *cmd, const char *lvid_s, const struct logi
int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv);
int lv_deactivate_any_missing_subdevs(const struct logical_volume *lv);
/*
* Returns 1 if info structure has been populated, else 0 on failure.
* When lvinfo* is NULL, it returns 1 if the device is locally active, 0 otherwise.
@@ -135,6 +127,13 @@ int lv_info(struct cmd_context *cmd, const struct logical_volume *lv, int use_la
int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s, int use_layer,
struct lvinfo *info, int with_open_count, int with_read_ahead);
/*
* Returns 1 if lv_seg_status structure has been populated,
* else 0 on failure or if device not active locally.
*/
int lv_status(struct cmd_context *cmd, const struct lv_segment *lv_seg,
int use_layer, struct lv_seg_status *lv_seg_status);
/*
* Returns 1 if lv_info_and_seg_status structure has been populated,
* else 0 on failure or if device not active locally.
@@ -142,12 +141,12 @@ int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s, int use_layer,
* lv_info_with_seg_status is the same as calling lv_info and then lv_status,
* but this fn tries to do that with one ioctl if possible.
*/
int lv_info_with_seg_status(struct cmd_context *cmd,
const struct lv_segment *lv_seg,
int lv_info_with_seg_status(struct cmd_context *cmd, const struct logical_volume *lv,
const struct lv_segment *lv_seg, int use_layer,
struct lv_with_info_and_seg_status *status,
int with_open_count, int with_read_ahead);
int lv_check_not_in_use(const struct logical_volume *lv, int error_if_used);
int lv_check_not_in_use(const struct logical_volume *lv);
/*
* Returns 1 if activate_lv has been set: 1 = activate; 0 = don't.
@@ -240,28 +239,4 @@ int device_is_usable(struct device *dev, struct dev_usable_check_params check);
*/
void fs_unlock(void);
#define TARGET_NAME_CACHE "cache"
#define TARGET_NAME_ERROR "error"
#define TARGET_NAME_ERROR_OLD "erro" /* Truncated in older kernels */
#define TARGET_NAME_LINEAR "linear"
#define TARGET_NAME_MIRROR "mirror"
#define TARGET_NAME_RAID "raid"
#define TARGET_NAME_SNAPSHOT "snapshot"
#define TARGET_NAME_SNAPSHOT_MERGE "snapshot-merge"
#define TARGET_NAME_SNAPSHOT_ORIGIN "snapshot-origin"
#define TARGET_NAME_STRIPED "striped"
#define TARGET_NAME_THIN "thin"
#define TARGET_NAME_THIN_POOL "thin-pool"
#define TARGET_NAME_ZERO "zero"
#define MODULE_NAME_CLUSTERED_MIRROR "clog"
#define MODULE_NAME_CACHE TARGET_NAME_CACHE
#define MODULE_NAME_ERROR TARGET_NAME_ERROR
#define MODULE_NAME_LOG_CLUSTERED "log-clustered"
#define MODULE_NAME_LOG_USERSPACE "log-userspace"
#define MODULE_NAME_MIRROR TARGET_NAME_MIRROR
#define MODULE_NAME_SNAPSHOT TARGET_NAME_SNAPSHOT
#define MODULE_NAME_RAID TARGET_NAME_RAID
#define MODULE_NAME_ZERO TARGET_NAME_ZERO
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -45,12 +45,11 @@ void dev_manager_exit(void);
* (eg, an origin is created before its snapshot, but is not
* unsuspended until the snapshot is also created.)
*/
int dev_manager_info(struct cmd_context *cmd, const struct logical_volume *lv,
int dev_manager_info(struct dm_pool *mem, const struct logical_volume *lv,
const char *layer,
int with_open_count, int with_read_ahead,
struct dm_info *dminfo, uint32_t *read_ahead,
struct lv_seg_status *seg_status);
int dev_manager_snapshot_percent(struct dev_manager *dm,
const struct logical_volume *lv,
dm_percent_t *percent);
@@ -69,7 +68,7 @@ int dev_manager_cache_status(struct dev_manager *dm,
int dev_manager_thin_pool_status(struct dev_manager *dm,
const struct logical_volume *lv,
struct dm_status_thin_pool **status,
int flush);
int noflush);
int dev_manager_thin_pool_percent(struct dev_manager *dm,
const struct logical_volume *lv,
int metadata, dm_percent_t *percent);

950
lib/cache/lvmcache.c vendored

File diff suppressed because it is too large Load Diff

18
lib/cache/lvmcache.h vendored
View File

@@ -102,16 +102,15 @@ int lvmcache_vginfo_holders_dec_and_test_for_zero(struct lvmcache_vginfo *vginfo
struct lvmcache_vginfo *lvmcache_vginfo_from_vgname(const char *vgname,
const char *vgid);
struct lvmcache_vginfo *lvmcache_vginfo_from_vgid(const char *vgid);
struct lvmcache_info *lvmcache_info_from_pvid(const char *pvid, struct device *dev, int valid_only);
struct lvmcache_info *lvmcache_info_from_pvid(const char *pvid, int valid_only);
const char *lvmcache_vgname_from_vgid(struct dm_pool *mem, const char *vgid);
const char *lvmcache_vgid_from_vgname(struct cmd_context *cmd, const char *vgname);
struct device *lvmcache_device_from_pvid(struct cmd_context *cmd, const struct id *pvid,
unsigned *scan_done_once, uint64_t *label_sector);
const char *lvmcache_pvid_from_devname(struct cmd_context *cmd,
const char *devname);
const char *dev_name);
char *lvmcache_vgname_from_pvid(struct cmd_context *cmd, const char *pvid);
const char *lvmcache_vgname_from_info(struct lvmcache_info *info);
const struct format_type *lvmcache_fmt_from_info(struct lvmcache_info *info);
int lvmcache_vgs_locked(void);
int lvmcache_vgname_is_locked(const char *vgname);
@@ -194,11 +193,12 @@ unsigned lvmcache_mda_count(struct lvmcache_info *info);
int lvmcache_vgid_is_cached(const char *vgid);
uint64_t lvmcache_smallest_mda_size(struct lvmcache_info *info);
void lvmcache_replace_dev(struct cmd_context *cmd, struct physical_volume *pv,
struct device *dev);
int lvmcache_found_duplicate_pvs(void);
int lvmcache_get_unused_duplicate_devs(struct cmd_context *cmd, struct dm_list *head);
int vg_has_duplicate_pvs(struct volume_group *vg);
void lvmcache_set_preferred_duplicates(const char *vgid);
int lvmcache_contains_lock_type_sanlock(struct cmd_context *cmd);
@@ -209,10 +209,4 @@ int lvmcache_vg_is_foreign(struct cmd_context *cmd, const char *vgname, const ch
void lvmcache_lock_ordering(int enable);
int lvmcache_dev_is_unchosen_duplicate(struct device *dev);
void lvmcache_remove_unchosen_duplicate(struct device *dev);
int lvmcache_pvid_in_unchosen_duplicates(const char *pvid);
#endif

1816
lib/cache/lvmetad.c vendored

File diff suppressed because it is too large Load Diff

103
lib/cache/lvmetad.h vendored
View File

@@ -28,35 +28,54 @@ typedef int (*activation_handler) (struct cmd_context *cmd,
enum activation_change activate);
#ifdef LVMETAD_SUPPORT
/*
* Sets up a global handle for our process.
*/
void lvmetad_init(struct cmd_context *);
/*
* lvmetad_connect: connect to lvmetad
* lvmetad_disconnect: disconnect from lvmetad
* lvmetad_make_unused: disconnect from lvmetad and refresh cmd filter
* lvmetad_used: check if lvmetad is being used (i.e. is connected)
* Override the use of lvmetad for retrieving scan results and metadata.
*/
int lvmetad_connect(struct cmd_context *cmd);
void lvmetad_disconnect(void);
void lvmetad_make_unused(struct cmd_context *cmd);
int lvmetad_used(void);
void lvmetad_set_active(struct cmd_context *, int);
/*
* Configure the socket that lvmetad_init will use to connect to the daemon.
*/
void lvmetad_set_socket(const char *);
/*
* Check whether lvmetad is used.
*/
int lvmetad_used(void);
/*
* Check if lvmetad socket is present (either the one set by lvmetad_set_socket
* or the default one if not set).
* or the default one if not set). For example, this may be used before calling
* lvmetad_active() check that does connect to the socket - this would produce
* various connection errors if the socket is not present.
*/
int lvmetad_socket_present(void);
/*
* Check if lvmetad pidfile is present, indicating that the lvmetad
* process is running or not.
* Check whether lvmetad is active (where active means both that it is running
* and that we have a working connection with it). It opens new connection
* with lvmetad in the process when lvmetad is supposed to be used and the
* connection is not open yet.
*/
int lvmetad_pidfile_present(void);
int lvmetad_active(void);
/*
* Connect to lvmetad unless the connection is already open or lvmetad is
* not configured to be used. If we fail to connect, print a warning.
*/
void lvmetad_connect_or_warn(void);
/*
* Drop connection to lvmetad. A subsequent lvmetad_connect_or_warn or
* lvmetad_active will re-establish the connection (possibly at a
* different socket path).
*/
void lvmetad_disconnect(void);
/*
* Set the "lvmetad validity token" (currently only consists of the lvmetad
@@ -78,16 +97,14 @@ void lvmetad_release_token(void);
* lvmetad_vg_commit. The request is validated immediately and lvmetad_vg_commit
* only constitutes a pointer update.
*/
int lvmetad_vg_update_pending(struct volume_group *vg);
int lvmetad_vg_update_finish(struct volume_group *vg);
int lvmetad_vg_update(struct volume_group *vg);
/*
* Inform lvmetad that a VG has been removed. This is not entirely safe, but is
* only needed during vgremove, which does not wipe PV labels and therefore
* cannot mark the PVs as gone.
*/
int lvmetad_vg_remove_pending(struct volume_group *vg);
int lvmetad_vg_remove_finish(struct volume_group *vg);
int lvmetad_vg_remove(struct volume_group *vg);
/*
* Notify lvmetad that a PV has been found. It is not an error if the PV is
@@ -97,17 +114,15 @@ int lvmetad_vg_remove_finish(struct volume_group *vg);
* number on the cached and on the discovered PV match but the metadata content
* does not.
*/
int lvmetad_pv_found(struct cmd_context *cmd, const struct id *pvid, struct device *dev,
int lvmetad_pv_found(const struct id *pvid, struct device *dev,
const struct format_type *fmt, uint64_t label_sector,
struct volume_group *vg,
struct dm_list *found_vgnames,
struct dm_list *changed_vgnames);
struct volume_group *vg, activation_handler handler);
/*
* Inform the daemon that the device no longer exists.
*/
int lvmetad_pv_gone(dev_t devno, const char *pv_name);
int lvmetad_pv_gone_by_dev(struct device *dev);
int lvmetad_pv_gone(dev_t devno, const char *pv_name, activation_handler handler);
int lvmetad_pv_gone_by_dev(struct device *dev, activation_handler handler);
/*
* Request a list of all PVs available to lvmetad. If requested, this will also
@@ -146,55 +161,45 @@ struct volume_group *lvmetad_vg_lookup(struct cmd_context *cmd,
* Scan a single device and update lvmetad with the result(s).
*/
int lvmetad_pvscan_single(struct cmd_context *cmd, struct device *dev,
struct dm_list *found_vgnames,
struct dm_list *changed_vgnames);
activation_handler handler, int ignore_obsolete);
int lvmetad_pvscan_all_devs(struct cmd_context *cmd, int do_wait);
int lvmetad_pvscan_all_devs(struct cmd_context *cmd, activation_handler handler);
int lvmetad_pvscan_foreign_vgs(struct cmd_context *cmd, activation_handler handler);
int lvmetad_vg_clear_outdated_pvs(struct volume_group *vg);
void lvmetad_validate_global_cache(struct cmd_context *cmd, int force);
int lvmetad_token_matches(struct cmd_context *cmd);
int lvmetad_vg_is_foreign(struct cmd_context *cmd, const char *vgname, const char *vgid);
int lvmetad_is_disabled(struct cmd_context *cmd, const char **reason);
void lvmetad_set_disabled(struct cmd_context *cmd, const char *reason);
void lvmetad_clear_disabled(struct cmd_context *cmd);
# else /* LVMETAD_SUPPORT */
# define lvmetad_init(cmd) do { } while (0)
# define lvmetad_disconnect() do { } while (0)
# define lvmetad_connect(cmd) (0)
# define lvmetad_make_unused(cmd) do { } while (0)
# define lvmetad_used() (0)
# define lvmetad_set_active(cmd, a) do { } while (0)
# define lvmetad_set_socket(a) do { } while (0)
# define lvmetad_used() (0)
# define lvmetad_socket_present() (0)
# define lvmetad_pidfile_present() (0)
# define lvmetad_active() (0)
# define lvmetad_connect_or_warn() do { } while (0)
# define lvmetad_set_token(a) do { } while (0)
# define lvmetad_release_token() do { } while (0)
# define lvmetad_vg_update(vg) (1)
# define lvmetad_vg_update_pending(vg) (1)
# define lvmetad_vg_update_finish(vg) (1)
# define lvmetad_vg_remove_pending(vg) (1)
# define lvmetad_vg_remove_finish(vg) (1)
# define lvmetad_pv_found(cmd, pvid, dev, fmt, label_sector, vg, found_vgnames, changed_vgnames) (1)
# define lvmetad_pv_gone(devno, pv_name) (1)
# define lvmetad_pv_gone_by_dev(dev) (1)
# define lvmetad_vg_remove(vg) (1)
# define lvmetad_pv_found(pvid, dev, fmt, label_sector, vg, handler) (1)
# define lvmetad_pv_gone(devno, pv_name, handler) (1)
# define lvmetad_pv_gone_by_dev(dev, handler) (1)
# define lvmetad_pv_list_to_lvmcache(cmd) (1)
# define lvmetad_pv_lookup(cmd, pvid, found) (0)
# define lvmetad_pv_lookup_by_dev(cmd, dev, found) (0)
# define lvmetad_vg_list_to_lvmcache(cmd) (1)
# define lvmetad_get_vgnameids(cmd, vgnameids) do { } while (0)
# define lvmetad_vg_lookup(cmd, vgname, vgid) (NULL)
# define lvmetad_pvscan_single(cmd, dev, found_vgnames, changed_vgnames) (0)
# define lvmetad_pvscan_all_devs(cmd, do_wait) (0)
# define lvmetad_vg_clear_outdated_pvs(vg) do { } while (0)
# define lvmetad_pvscan_single(cmd, dev, handler, ignore_obsolete) (0)
# define lvmetad_pvscan_all_devs(cmd, handler) (0)
# define lvmetad_pvscan_foreign_vgs(cmd, handler) (0)
# define lvmetad_vg_clear_outdated_pvs(vg) (1)
# define lvmetad_validate_global_cache(cmd, force) do { } while (0)
# define lvmetad_vg_is_foreign(cmd, vgname, vgid) (0)
# define lvmetad_token_matches(cmd) (1)
# define lvmetad_is_disabled(cmd, reason) (0)
# define lvmetad_set_disabled(cmd, reason) do { } while (0)
# define lvmetad_clear_disabled(cmd) do { } while (0)
# endif /* LVMETAD_SUPPORT */

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2013-2016 Red Hat, Inc. All rights reserved.
* Copyright (C) 2013-2014 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
@@ -26,8 +26,6 @@
#include "defaults.h"
static const char _cache_module[] = "cache";
#define CACHE_POLICY_WHEN_MISSING "mq"
#define CACHE_MODE_WHEN_MISSING CACHE_MODE_WRITETHROUGH
/* TODO: using static field here, maybe should be a part of segment_type */
static unsigned _feature_mask;
@@ -43,21 +41,24 @@ static unsigned _feature_mask;
*
* Needs both segments cache and cache_pool to be loaded.
*/
static void _fix_missing_defaults(struct lv_segment *cpool_seg)
static int _fix_missing_defaults(struct lv_segment *cpool_seg)
{
if (!cpool_seg->policy_name) {
cpool_seg->policy_name = CACHE_POLICY_WHEN_MISSING;
log_verbose("Cache pool %s is missing cache policy, using %s.",
display_lvname(cpool_seg->lv),
cpool_seg->policy_name = "mq";
log_verbose("Cache is missing cache policy, using %s.",
cpool_seg->policy_name);
}
if (cpool_seg->cache_mode == CACHE_MODE_UNDEFINED) {
cpool_seg->cache_mode = CACHE_MODE_WHEN_MISSING;
log_verbose("Cache pool %s is missing cache mode, using %s.",
display_lvname(cpool_seg->lv),
if (!cache_mode_is_set(cpool_seg)) {
if (!cache_set_mode(cpool_seg, "writethrough")) {
log_error(INTERNAL_ERROR "Failed to writethrough cache mode.");
return 0;
}
log_verbose("Cache is missing cache mode, using %s.",
get_cache_mode_name(cpool_seg));
}
return 1;
}
static int _cache_pool_text_import(struct lv_segment *seg,
@@ -96,7 +97,7 @@ static int _cache_pool_text_import(struct lv_segment *seg,
if (dm_config_has_node(sn, "cache_mode")) {
if (!(str = dm_config_find_str(sn, "cache_mode", NULL)))
return SEG_LOG_ERROR("cache_mode must be a string in");
if (!set_cache_mode(&seg->cache_mode, str))
if (!cache_set_mode(seg, str))
return SEG_LOG_ERROR("Unknown cache_mode in");
}
@@ -140,9 +141,9 @@ static int _cache_pool_text_import(struct lv_segment *seg,
if (!attach_pool_metadata_lv(seg, meta_lv))
return_0;
/* when cache pool is used, we require policy and mode to be defined */
if (!dm_list_empty(&seg->lv->segs_using_this_lv))
_fix_missing_defaults(seg);
if (!dm_list_empty(&seg->lv->segs_using_this_lv) &&
!_fix_missing_defaults(seg))
return_0;
return 1;
}
@@ -169,7 +170,7 @@ static int _cache_pool_text_export(const struct lv_segment *seg,
* but not worth to break backward compatibility, by shifting
* content to cache segment
*/
if (seg->cache_mode != CACHE_MODE_UNDEFINED) {
if (cache_mode_is_set(seg)) {
if (!(cache_mode = get_cache_mode_name(seg)))
return_0;
outf(f, "cache_mode = \"%s\"", cache_mode);
@@ -207,16 +208,11 @@ static int _target_present(struct cmd_context *cmd,
uint32_t maj;
uint32_t min;
unsigned cache_feature;
unsigned cache_alias;
const char feature[12];
const char module[12]; /* check dm-%s */
const char *aliasing;
} _features[] = {
/* Assumption: cache >=1.9 always aliases MQ policy */
{ 1, 9, CACHE_FEATURE_POLICY_SMQ, CACHE_FEATURE_POLICY_MQ, "policy_smq", "cache-smq",
" and aliases cache-mq" },
{ 1, 8, CACHE_FEATURE_POLICY_SMQ, 0, "policy_smq", "cache-smq" },
{ 1, 3, CACHE_FEATURE_POLICY_MQ, 0, "policy_mq", "cache-mq" },
{ 1, 3, CACHE_FEATURE_POLICY_MQ, "policy_mq", "cache-mq" },
{ 1, 8, CACHE_FEATURE_POLICY_SMQ, "policy_smq", "cache-smq" },
};
static const char _lvmconf[] = "global/cache_disabled_features";
static unsigned _attrs = 0;
@@ -234,8 +230,10 @@ static int _target_present(struct cmd_context *cmd,
if (!_cache_checked) {
_cache_checked = 1;
if (!(_cache_present = target_present_version(cmd, TARGET_NAME_CACHE, 1,
&maj, &min, &patchlevel)))
if (!(_cache_present = target_present(cmd, "cache", 1)))
return 0;
if (!target_version("cache", &maj, &min, &patchlevel))
return_0;
if ((maj < 1) ||
@@ -247,17 +245,13 @@ static int _target_present(struct cmd_context *cmd,
return 0;
}
for (i = 0; i < DM_ARRAY_SIZE(_features); ++i) {
if (_attrs & _features[i].cache_feature)
continue; /* already present */
if (((maj > _features[i].maj) ||
(maj == _features[i].maj && min >= _features[i].min)) &&
module_present(cmd, _features[i].module)) {
log_debug_activation("Cache policy %s is available%s.",
_features[i].module,
_features[i].aliasing ? : "");
_attrs |= (_features[i].cache_feature | _features[i].cache_alias);
} else if (!_features[i].cache_alias)
(!_features[i].module[0] || module_present(cmd, _features[i].module)))
_attrs |= _features[i].cache_feature;
else
log_very_verbose("Target %s does not support %s.",
_cache_module, _features[i].feature);
}
@@ -300,7 +294,7 @@ static int _modules_needed(struct dm_pool *mem,
const struct lv_segment *seg __attribute__((unused)),
struct dm_list *modules)
{
if (!str_list_add(mem, modules, MODULE_NAME_CACHE)) {
if (!str_list_add(mem, modules, "cache")) {
log_error("String list allocation failed for cache module.");
return 0;
}
@@ -354,12 +348,12 @@ static int _cache_text_import(struct lv_segment *seg,
seg->lv->status |= strstr(seg->lv->name, "_corig") ? LV_PENDING_DELETE : 0;
if (!attach_pool_lv(seg, pool_lv, NULL, NULL, NULL))
if (!attach_pool_lv(seg, pool_lv, NULL, NULL))
return_0;
/* load order is unknown, could be cache origin or pool LV, so check for both */
if (!dm_list_empty(&pool_lv->segments))
_fix_missing_defaults(first_seg(pool_lv));
if (!dm_list_empty(&pool_lv->segments) &&
!_fix_missing_defaults(first_seg(pool_lv)))
return_0;
return 1;
}
@@ -398,7 +392,6 @@ static int _cache_add_target_line(struct dev_manager *dm,
{
struct lv_segment *cache_pool_seg;
char *metadata_uuid, *data_uuid, *origin_uuid;
uint64_t feature_flags = 0;
if (!seg->pool_lv || !seg_is_cache(seg)) {
log_error(INTERNAL_ERROR "Passed segment is not cache.");
@@ -406,25 +399,6 @@ static int _cache_add_target_line(struct dev_manager *dm,
}
cache_pool_seg = first_seg(seg->pool_lv);
if (seg->cleaner_policy)
/* With cleaner policy always pass writethrough */
feature_flags |= DM_CACHE_FEATURE_WRITETHROUGH;
else
switch (cache_pool_seg->cache_mode) {
default:
log_error(INTERNAL_ERROR "LV %s has unknown cache mode %d.",
display_lvname(seg->lv), cache_pool_seg->cache_mode);
/* Fall through */
case CACHE_MODE_WRITETHROUGH:
feature_flags |= DM_CACHE_FEATURE_WRITETHROUGH;
break;
case CACHE_MODE_WRITEBACK:
feature_flags |= DM_CACHE_FEATURE_WRITEBACK;
break;
case CACHE_MODE_PASSTHROUGH:
feature_flags |= DM_CACHE_FEATURE_PASSTHROUGH;
break;
}
if (!(metadata_uuid = build_dm_uuid(mem, cache_pool_seg->metadata_lv, NULL)))
return_0;
@@ -436,7 +410,7 @@ static int _cache_add_target_line(struct dev_manager *dm,
return_0;
if (!dm_tree_node_add_cache_target(node, len,
feature_flags,
cache_pool_seg->feature_flags,
metadata_uuid,
data_uuid,
origin_uuid,

View File

@@ -192,9 +192,6 @@ static int _get_env_vars(struct cmd_context *cmd)
}
}
if (strcmp((getenv("LVM_RUN_BY_DMEVENTD") ? : "0"), "1") == 0)
init_run_by_dmeventd(cmd);
return 1;
}
@@ -281,8 +278,6 @@ static int _parse_debug_classes(struct cmd_context *cmd)
debug_classes |= LOG_CLASS_LOCKING;
else if (!strcasecmp(cv->v.str, "lvmpolld"))
debug_classes |= LOG_CLASS_LVMPOLLD;
else if (!strcasecmp(cv->v.str, "dbus"))
debug_classes |= LOG_CLASS_DBUS;
else
log_verbose("Unrecognised value for log/debug_classes: %s", cv->v.str);
}
@@ -368,7 +363,7 @@ static void _init_logging(struct cmd_context *cmd)
/* Tell device-mapper about our logging */
#ifdef DEVMAPPER_SUPPORT
if (!dm_log_is_non_default())
dm_log_with_errno_init(print_log_libdm);
dm_log_with_errno_init(print_log);
#endif
reset_log_duplicated();
reset_lvm_errno(1);
@@ -643,8 +638,8 @@ static int _process_config(struct cmd_context *cmd)
if (!strcmp(cmd->stripe_filler, "/dev/ioerror") &&
stat(cmd->stripe_filler, &st))
cmd->stripe_filler = "error";
else if (strcmp(cmd->stripe_filler, "error") &&
strcmp(cmd->stripe_filler, "zero")) {
if (strcmp(cmd->stripe_filler, "error")) {
if (stat(cmd->stripe_filler, &st)) {
log_warn("WARNING: activation/missing_stripe_filler = \"%s\" "
"is invalid,", cmd->stripe_filler);
@@ -680,9 +675,6 @@ static int _process_config(struct cmd_context *cmd)
if (!process_profilable_config(cmd))
return_0;
if (find_config_tree_bool(cmd, report_two_word_unknown_device_CFG, NULL))
init_unknown_device_name("unknown device");
init_detect_internal_vg_cache_corruption
(find_config_tree_bool(cmd, global_detect_internal_vg_cache_corruption_CFG, NULL));
@@ -953,9 +945,6 @@ static void _destroy_config(struct cmd_context *cmd)
* they will get loaded again automatically.
*/
dm_list_iterate_items_safe(profile, tmp_profile, &cmd->profile_params->profiles) {
if (cmd->is_interactive && (profile == cmd->profile_params->shell_profile))
continue;
config_destroy(profile->cft);
profile->cft = NULL;
dm_list_move(&cmd->profile_params->profiles_to_load, &profile->list);
@@ -1000,7 +989,7 @@ static int _init_dev_cache(struct cmd_context *cmd)
if (!(cn = find_config_tree_array(cmd, devices_scan_CFG, NULL))) {
log_error(INTERNAL_ERROR "Unable to find configuration for devices/scan.");
return 0;
return_0;
}
for (cv = cn->v; cv; cv = cv->next) {
@@ -1059,7 +1048,7 @@ static int _init_dev_cache(struct cmd_context *cmd)
return 1;
}
#define MAX_FILTERS 9
#define MAX_FILTERS 8
static struct dev_filter *_init_lvmetad_filter_chain(struct cmd_context *cmd)
{
@@ -1084,13 +1073,6 @@ static struct dev_filter *_init_lvmetad_filter_chain(struct cmd_context *cmd)
nr_filt++;
}
/* internal filter used by command processing. */
if (!(filters[nr_filt] = internal_filter_create())) {
log_error("Failed to create internal device filter");
goto bad;
}
nr_filt++;
/* global regex filter. Optional. */
if ((cn = find_config_tree_node(cmd, devices_global_filter_CFG, NULL))) {
if (!(filters[nr_filt] = regex_filter_create(cn->v))) {
@@ -1172,7 +1154,7 @@ bad:
* If lvmetad is used, there are three filter chains:
*
* - cmd->lvmetad_filter - the lvmetad filter chain used when scanning devs for lvmetad update:
* sysfs filter -> internal filter -> global regex filter -> type filter ->
* sysfs filter -> global regex filter -> type filter ->
* usable device filter(FILTER_MODE_PRE_LVMETAD) ->
* mpath component filter -> partitioned filter ->
* md component filter -> fw raid filter
@@ -1186,7 +1168,7 @@ bad:
* If lvmetad is not used, there's just one filter chain:
*
* - cmd->filter == cmd->full_filter:
* persistent filter -> sysfs filter -> internal filter -> global regex filter ->
* persistent filter -> sysfs filter -> global regex filter ->
* regex_filter -> type filter -> usable device filter(FILTER_MODE_NO_LVMETAD) ->
* mpath component filter -> partitioned filter -> md component filter -> fw raid filter
*
@@ -1656,24 +1638,35 @@ static void _init_globals(struct cmd_context *cmd)
}
/*
* init_connections();
* _init_lvmetad();
* lvmetad_disconnect(); (close previous connection)
* lvmetad_set_socket(); (set path from config)
* lvmetad_set_token(); (set token from filter config)
* if (find_config(use_lvmetad))
* lvmetad_connect();
*
* If lvmetad_connect() is successful, lvmetad_used() will
* return 1.
*
* If the config has use_lvmetad=0, then lvmetad_connect()
* will not be called, and lvmetad_used() will return 0.
*
* Other code should use lvmetad_used() to check if the
* command is using lvmetad.
*
* Close and reopen stream on file descriptor fd.
*/
static int _reopen_stream(FILE *stream, int fd, const char *mode, const char *name, FILE **new_stream)
{
int fd_copy, new_fd;
if ((fd_copy = dup(fd)) < 0) {
log_sys_error("dup", name);
return 0;
}
if (fclose(stream))
log_sys_error("fclose", name);
if ((new_fd = dup2(fd_copy, fd)) < 0)
log_sys_error("dup2", name);
else if (new_fd != fd)
log_error("dup2(%d, %d) returned %d", fd_copy, fd, new_fd);
if (close(fd_copy) < 0)
log_sys_error("close", name);
if (!(*new_stream = fdopen(fd, mode))) {
log_sys_error("fdopen", name);
return 0;
}
return 1;
}
static int _init_lvmetad(struct cmd_context *cmd)
{
@@ -1697,29 +1690,13 @@ static int _init_lvmetad(struct cmd_context *cmd)
if (find_config_tree_int(cmd, global_locking_type_CFG, NULL) == 3 &&
find_config_tree_bool(cmd, global_use_lvmetad_CFG, NULL)) {
log_warn("WARNING: Not using lvmetad because locking_type is 3 (clustered).");
return 1;
}
if (!find_config_tree_bool(cmd, global_use_lvmetad_CFG, NULL)) {
if (lvmetad_pidfile_present()) {
log_warn("WARNING: Not using lvmetad because config setting use_lvmetad=0.");
log_warn("WARNING: To avoid corruption, rescan devices to make changes visible (pvscan --cache).");
}
return 1;
}
if (!lvmetad_connect(cmd)) {
log_warn("WARNING: Failed to connect to lvmetad. Falling back to device scanning.");
return 1;
}
if (!lvmetad_used()) {
/* This should never happen. */
log_error(INTERNAL_ERROR "lvmetad setup incorrect");
return 0;
}
log_warn("WARNING: configuration setting use_lvmetad overridden to 0 due to locking_type 3. "
"Clustered environment not supported by lvmetad yet.");
lvmetad_set_active(NULL, 0);
} else
lvmetad_set_active(NULL, find_config_tree_bool(cmd, global_use_lvmetad_CFG, NULL));
lvmetad_init(cmd);
return 1;
}
@@ -1758,75 +1735,6 @@ bad:
return 0;
}
int init_run_by_dmeventd(struct cmd_context *cmd)
{
init_dmeventd_monitor(DMEVENTD_MONITOR_IGNORE);
init_ignore_suspended_devices(1);
init_disable_dmeventd_monitoring(1); /* Lock settings */
return 0;
}
void destroy_config_context(struct cmd_context *cmd)
{
_destroy_config(cmd);
if (cmd->mem)
dm_pool_destroy(cmd->mem);
if (cmd->libmem)
dm_pool_destroy(cmd->libmem);
dm_free(cmd);
}
/*
* A "config context" is a very light weight toolcontext that
* is only used for reading config settings from lvm.conf.
*/
struct cmd_context *create_config_context(void)
{
struct cmd_context *cmd;
if (!(cmd = dm_zalloc(sizeof(*cmd))))
goto_out;
strcpy(cmd->system_dir, DEFAULT_SYS_DIR);
if (!_get_env_vars(cmd))
goto_out;
if (!(cmd->libmem = dm_pool_create("library", 4 * 1024)))
goto_out;
dm_list_init(&cmd->config_files);
dm_list_init(&cmd->tags);
if (!_init_lvm_conf(cmd))
goto_out;
if (!_init_hostname(cmd))
goto_out;
if (!_init_tags(cmd, cmd->cft))
goto_out;
/* Load lvmlocal.conf */
if (*cmd->system_dir && !_load_config_file(cmd, "", 1))
goto_out;
if (!_init_tag_configs(cmd))
goto_out;
if (!(cmd->cft = _merge_config_files(cmd, cmd->cft)))
goto_out;
return cmd;
out:
if (cmd)
destroy_config_context(cmd);
return NULL;
}
/* Entry point */
struct cmd_context *create_toolcontext(unsigned is_long_lived,
const char *system_dir,
@@ -1836,6 +1744,7 @@ struct cmd_context *create_toolcontext(unsigned is_long_lived,
unsigned set_filters)
{
struct cmd_context *cmd;
FILE *new_stream;
int flags;
#ifdef M_MMAP_MAX
@@ -1885,8 +1794,9 @@ struct cmd_context *create_toolcontext(unsigned is_long_lived,
if (is_valid_fd(STDIN_FILENO) &&
((flags = fcntl(STDIN_FILENO, F_GETFL)) > 0) &&
(flags & O_ACCMODE) != O_WRONLY) {
if (!reopen_standard_stream(&stdin, "r"))
if (!_reopen_stream(stdin, STDIN_FILENO, "r", "stdin", &new_stream))
goto_out;
stdin = new_stream;
if (setvbuf(stdin, cmd->linebuffer, _IOLBF, linebuffer_size)) {
log_sys_error("setvbuf", "");
goto out;
@@ -1896,8 +1806,9 @@ struct cmd_context *create_toolcontext(unsigned is_long_lived,
if (is_valid_fd(STDOUT_FILENO) &&
((flags = fcntl(STDOUT_FILENO, F_GETFL)) > 0) &&
(flags & O_ACCMODE) != O_RDONLY) {
if (!reopen_standard_stream(&stdout, "w"))
if (!_reopen_stream(stdout, STDOUT_FILENO, "w", "stdout", &new_stream))
goto_out;
stdout = new_stream;
if (setvbuf(stdout, cmd->linebuffer + linebuffer_size,
_IOLBF, linebuffer_size)) {
log_sys_error("setvbuf", "");
@@ -1909,6 +1820,7 @@ struct cmd_context *create_toolcontext(unsigned is_long_lived,
/* Without buffering, must not use stdin/stdout */
init_silent(1);
#endif
/*
* Environment variable LVM_SYSTEM_DIR overrides this below.
*/
@@ -1981,8 +1893,6 @@ struct cmd_context *create_toolcontext(unsigned is_long_lived,
if (!init_lvmcache_orphans(cmd))
goto_out;
dm_list_init(&cmd->unused_duplicate_devs);
if (!_init_segtypes(cmd))
goto_out;
@@ -1994,7 +1904,7 @@ struct cmd_context *create_toolcontext(unsigned is_long_lived,
_init_globals(cmd);
if (set_connections && !init_connections(cmd))
goto_out;
return_0;
if (set_filters && !init_filters(cmd, 1))
goto_out;
@@ -2224,6 +2134,7 @@ int refresh_toolcontext(struct cmd_context *cmd)
void destroy_toolcontext(struct cmd_context *cmd)
{
struct dm_config_tree *cft_cmdline;
FILE *new_stream;
int flags;
if (cmd->dump_filter && cmd->filter && cmd->filter->dump &&
@@ -2259,18 +2170,20 @@ void destroy_toolcontext(struct cmd_context *cmd)
if (is_valid_fd(STDIN_FILENO) &&
((flags = fcntl(STDIN_FILENO, F_GETFL)) > 0) &&
(flags & O_ACCMODE) != O_WRONLY) {
if (reopen_standard_stream(&stdin, "r"))
if (_reopen_stream(stdin, STDIN_FILENO, "r", "stdin", &new_stream)) {
stdin = new_stream;
setlinebuf(stdin);
else
} else
cmd->linebuffer = NULL; /* Leave buffer in place (deliberate leak) */
}
if (is_valid_fd(STDOUT_FILENO) &&
((flags = fcntl(STDOUT_FILENO, F_GETFL)) > 0) &&
(flags & O_ACCMODE) != O_RDONLY) {
if (reopen_standard_stream(&stdout, "w"))
if (_reopen_stream(stdout, STDOUT_FILENO, "w", "stdout", &new_stream)) {
stdout = new_stream;
setlinebuf(stdout);
else
} else
cmd->linebuffer = NULL; /* Leave buffer in place (deliberate leak) */
}

View File

@@ -66,15 +66,6 @@ struct cmd_context_initialized_parts {
unsigned connections:1;
};
struct cmd_report {
int log_only;
dm_report_group_type_t report_group_type;
struct dm_report_group *report_group;
struct dm_report *log_rh;
const char *log_name;
log_report_t saved_log_report_state;
};
/* FIXME Split into tool & library contexts */
/* command-instance-related variables needed by library */
struct cmd_context {
@@ -88,20 +79,11 @@ struct cmd_context {
* Command line and arguments.
*/
const char *cmd_line;
const char *name; /* needed before cmd->command is set */
struct command_name *cname;
struct command *command;
char **argv;
struct arg_values *opt_arg_values;
struct arg_values *arg_values;
struct dm_list arg_value_groups;
/*
* Position args remaining after command name
* and --options are removed from original argc/argv.
*/
int position_argc;
char **position_argv;
/*
* Format handlers.
*/
@@ -131,7 +113,6 @@ struct cmd_context {
* Switches.
*/
unsigned is_long_lived:1; /* optimises persistent_filter handling */
unsigned is_interactive:1;
unsigned check_pv_dev_sizes:1;
unsigned handles_missing_pvs:1;
unsigned handles_unknown_segments:1;
@@ -147,8 +128,6 @@ struct cmd_context {
unsigned threaded:1; /* set if running within a thread e.g. clvmd */
unsigned independent_metadata_areas:1; /* active formats have MDAs outside PVs */
unsigned unknown_system_id:1;
unsigned include_historical_lvs:1; /* also process/report/display historical LVs */
unsigned record_historical_lvs:1; /* record historical LVs */
unsigned include_foreign_vgs:1; /* report/display cmds can reveal foreign VGs */
unsigned include_shared_vgs:1; /* report/display cmds can reveal lockd VGs */
unsigned include_active_foreign_vgs:1; /* cmd should process foreign VGs with active LVs */
@@ -160,9 +139,6 @@ struct cmd_context {
unsigned lockd_vg_rescan:1;
unsigned lockd_vg_default_sh:1;
unsigned lockd_vg_enforce_sh:1;
unsigned vg_notify:1;
unsigned lv_notify:1;
unsigned pv_notify:1;
/*
* Filtering.
@@ -203,11 +179,6 @@ struct cmd_context {
char dev_dir[PATH_MAX];
char proc_dir[PATH_MAX];
/*
* Reporting.
*/
struct cmd_report cmd_report;
/*
* Buffers.
*/
@@ -221,7 +192,6 @@ struct cmd_context {
const char *report_list_item_separator;
const char *time_format;
unsigned rand_seed;
struct dm_list unused_duplicate_devs; /* save preferences between lvmcache instances */
};
/*
@@ -242,15 +212,6 @@ int config_files_changed(struct cmd_context *cmd);
int init_lvmcache_orphans(struct cmd_context *cmd);
int init_filters(struct cmd_context *cmd, unsigned load_persistent_cache);
int init_connections(struct cmd_context *cmd);
int init_run_by_dmeventd(struct cmd_context *cmd);
/*
* A config context is a very light weight cmd struct that
* is only used for reading config settings from lvm.conf,
* which are at cmd->cft.
*/
struct cmd_context *create_config_context(void);
void destroy_config_context(struct cmd_context *cmd);
struct format_type *get_format_by_name(struct cmd_context *cmd, const char *format);

View File

@@ -385,13 +385,6 @@ int override_config_tree_from_string(struct cmd_context *cmd,
return 0;
}
if (cmd->is_interactive &&
!config_force_check(cmd, CONFIG_STRING, cft_new)) {
log_error("Ignoring invalid configuration string.");
dm_config_destroy(cft_new);
return 0;
}
if (!(cs = dm_pool_zalloc(cft_new->mem, sizeof(struct config_source)))) {
log_error("Failed to allocate config source.");
dm_config_destroy(cft_new);
@@ -496,7 +489,7 @@ int override_config_tree_from_profile(struct cmd_context *cmd,
int config_file_read_fd(struct dm_config_tree *cft, struct device *dev,
off_t offset, size_t size, off_t offset2, size_t size2,
checksum_fn_t checksum_fn, uint32_t checksum,
int checksum_only, int no_dup_node_check)
int checksum_only)
{
char *fb, *fe;
int r = 0;
@@ -547,13 +540,8 @@ int config_file_read_fd(struct dm_config_tree *cft, struct device *dev,
if (!checksum_only) {
fe = fb + size + size2;
if (no_dup_node_check) {
if (!dm_config_parse_without_dup_node_check(cft, fb, fe))
goto_out;
} else {
if (!dm_config_parse(cft, fb, fe))
goto_out;
}
if (!dm_config_parse(cft, fb, fe))
goto_out;
}
r = 1;
@@ -601,7 +589,7 @@ int config_file_read(struct dm_config_tree *cft)
}
r = config_file_read_fd(cft, cf->dev, 0, (size_t) info.st_size, 0, 0,
(checksum_fn_t) NULL, 0, 0, 0);
(checksum_fn_t) NULL, 0, 0);
if (!cf->keep_open) {
if (!dev_close(cf->dev))
@@ -996,20 +984,6 @@ static int _config_def_check_node_is_profilable(struct cft_check_handle *handle,
return 1;
}
static int _config_def_check_node_is_allowed(struct cft_check_handle *handle,
const char *rp, struct dm_config_node *cn,
const cfg_def_item_t *def)
{
if (handle->disallowed_flags & def->flags) {
log_warn_suppress(handle->suppress_messages,
"Configuration %s \"%s\" is not allowed here.",
cn->v ? "option" : "section", rp);
return 0;
}
return 1;
}
static int _config_def_check_node(struct cft_check_handle *handle,
const char *vp, char *pvp, char *rp, char *prp,
size_t buf_size, struct dm_config_node *cn)
@@ -1060,9 +1034,6 @@ static int _config_def_check_node(struct cft_check_handle *handle,
!_config_def_check_node_is_profilable(handle, rp, cn, def))
return_0;
if (!_config_def_check_node_is_allowed(handle, rp, cn, def))
return_0;
handle->status[def->id] |= CFG_VALID;
return 1;
}
@@ -2142,7 +2113,7 @@ bad:
return NULL;
}
int config_force_check(struct cmd_context *cmd, config_source_t source, struct dm_config_tree *cft)
static int _check_profile(struct cmd_context *cmd, struct profile *profile)
{
struct cft_check_handle *handle;
int r;
@@ -2153,19 +2124,13 @@ int config_force_check(struct cmd_context *cmd, config_source_t source, struct d
}
handle->cmd = cmd;
handle->cft = cft;
handle->source = source;
handle->cft = profile->cft;
handle->source = profile->source;
/* the check is compulsory - allow only profilable items in a profile config! */
handle->force_check = 1;
/* provide warning messages only if config/checks=1 */
handle->suppress_messages = !find_config_tree_bool(cmd, config_checks_CFG, NULL);
/*
* Some settings can't be changed if we're running commands interactively
* within lvm shell so check for them in case we're in this interactive mode.
*/
if (cmd->is_interactive)
handle->disallowed_flags |= CFG_DISALLOW_INTERACTIVE;
r = config_def_check(handle);
dm_pool_free(cmd->libmem, handle);
@@ -2287,7 +2252,7 @@ int load_profile(struct cmd_context *cmd, struct profile *profile) {
* messages to be suppressed, but the check itself is always done
* for profiles!
*/
if (!config_force_check(cmd, profile->source, profile->cft)) {
if (!_check_profile(cmd, profile)) {
log_error("Ignoring invalid %s %s.",
_config_source_names[profile->source], profile->name);
config_destroy(profile->cft);
@@ -2466,25 +2431,3 @@ int get_default_allocation_cache_pool_chunk_size_CFG(struct cmd_context *cmd, st
{
return DEFAULT_CACHE_POOL_CHUNK_SIZE * 2;
}
uint64_t get_default_allocation_cache_pool_max_chunks_CFG(struct cmd_context *cmd, struct profile *profile)
{
static int _warn_max_chunks = 0;
/*
* TODO: In future may depend on the cache target version,
* newer targets may scale better.
*/
uint64_t default_max_chunks = DEFAULT_CACHE_POOL_MAX_CHUNKS;
uint64_t max_chunks = find_config_tree_int(cmd, allocation_cache_pool_max_chunks_CFG, profile);
if (!max_chunks)
max_chunks = default_max_chunks;
else if (max_chunks > default_max_chunks)
/* Still warn the user when the value is tweaked above recommended level */
/* Maybe drop to log_verbose... */
log_warn_suppress(_warn_max_chunks++, "WARNING: Configured cache_pool_max_chunks value "
FMTu64 " is higher then recommended " FMTu64 ".",
max_chunks, default_max_chunks);
return max_chunks;
}

View File

@@ -48,7 +48,6 @@ struct profile_params {
struct profile *global_metadata_profile; /* profile (as given by --metadataprofile cmd arg) that overrides any other VG/LV-based profile */
struct dm_list profiles_to_load; /* list of profiles which are only added, but still need to be loaded for any use */
struct dm_list profiles; /* list of profiles which are loaded already and which are ready for use */
struct profile *shell_profile; /* master profile used in interactive/shell mode */
};
#define CFG_PATH_MAX_LEN 128
@@ -99,34 +98,31 @@ typedef union {
/* whether the configuration item name is variable */
#define CFG_NAME_VARIABLE 0x0001
#define CFG_NAME_VARIABLE 0x001
/* whether empty value is allowed */
#define CFG_ALLOW_EMPTY 0x0002
#define CFG_ALLOW_EMPTY 0x002
/* whether the configuration item is for advanced use only */
#define CFG_ADVANCED 0x0004
#define CFG_ADVANCED 0x004
/* whether the configuration item is not officially supported */
#define CFG_UNSUPPORTED 0x0008
#define CFG_UNSUPPORTED 0x008
/* whether the configuration item is customizable by a profile */
#define CFG_PROFILABLE 0x0010
/* whether the configuration item is customizable by a profile
* and whether it can be attached to VG/LV metadata at the same time
#define CFG_PROFILABLE 0x010
/* whether the configuration item is customizable by a profile */
/* and whether it can be attached to VG/LV metadata at the same time
* The CFG_PROFILABLE_METADATA flag incorporates CFG_PROFILABLE flag!!! */
#define CFG_PROFILABLE_METADATA 0x0030
#define CFG_PROFILABLE_METADATA 0x030
/* whether the default value is undefned */
#define CFG_DEFAULT_UNDEFINED 0x0040
#define CFG_DEFAULT_UNDEFINED 0x040
/* whether the default value is commented out on output */
#define CFG_DEFAULT_COMMENTED 0x0080
#define CFG_DEFAULT_COMMENTED 0x080
/* whether the default value is calculated during run time */
#define CFG_DEFAULT_RUN_TIME 0x0100
#define CFG_DEFAULT_RUN_TIME 0x100
/* whether the configuration setting is disabled (and hence defaults always used) */
#define CFG_DISABLED 0x0200
#define CFG_DISABLED 0x200
/* whether to print integers in octal form (prefixed by "0") */
#define CFG_FORMAT_INT_OCTAL 0x0400
#define CFG_FORMAT_INT_OCTAL 0x400
/* whether to disable checks for the whole config section subtree */
#define CFG_SECTION_NO_CHECK 0x0800
/* whether to disallow a possibility to override configuration
* setting for commands run interactively (e.g. in lvm shell) */
#define CFG_DISALLOW_INTERACTIVE 0x1000
#define CFG_SECTION_NO_CHECK 0x800
/* configuration definition item structure */
typedef struct cfg_def_item {
@@ -216,15 +212,11 @@ struct cft_check_handle {
unsigned check_diff:1; /* check if the value used differs from default one */
unsigned ignoreadvanced:1; /* do not include advnced configs */
unsigned ignoreunsupported:1; /* do not include unsupported configs */
uint16_t disallowed_flags; /* set of disallowed flags */
uint8_t status[CFG_COUNT]; /* flags for each configuration item - the result of the check */
};
int config_def_get_path(char *buf, size_t buf_size, int id);
/* Checks config using given handle - the handle may be reused. */
int config_def_check(struct cft_check_handle *handle);
/* Forces config check and automatically creates a new handle inside with defaults and discards the handle after the check. */
int config_force_check(struct cmd_context *cmd, config_source_t source, struct dm_config_tree *cft);
int override_config_tree_from_string(struct cmd_context *cmd, const char *config_settings);
int override_config_tree_from_profile(struct cmd_context *cmd, struct profile *profile);
@@ -239,7 +231,7 @@ struct dm_config_tree *config_open(config_source_t source, const char *filename,
int config_file_read_fd(struct dm_config_tree *cft, struct device *dev,
off_t offset, size_t size, off_t offset2, size_t size2,
checksum_fn_t checksum_fn, uint32_t checksum,
int skip_parse, int no_dup_node_check);
int skip_parse);
int config_file_read(struct dm_config_tree *cft);
struct dm_config_tree *config_file_open_and_read(const char *config_file, config_source_t source,
struct cmd_context *cmd);
@@ -307,6 +299,5 @@ int get_default_allocation_cache_pool_chunk_size_CFG(struct cmd_context *cmd, st
#define get_default_unconfigured_allocation_cache_pool_chunk_size_CFG NULL
const char *get_default_allocation_cache_policy_CFG(struct cmd_context *cmd, struct profile *profile);
#define get_default_unconfigured_allocation_cache_policy_CFG NULL
uint64_t get_default_allocation_cache_pool_max_chunks_CFG(struct cmd_context *cmd, struct profile *profile);
#endif

View File

@@ -23,11 +23,6 @@
* - define a configuration array of one or more types:
* cfg_array(id, name, parent, flags, types, default_value, since_version, unconfigured_default_value, deprecated_since_version, deprecation_comment, comment)
*
* - define a configuration setting where the default value is evaluated in runtime
* cfg_runtime(id, name, parent, flags, type, since_version, deprecated_since_version, deprecation_comment, comment)
* (for each cfg_runtime, you need to define 'get_default_<name>(struct cmd_context *cmd, struct profile *profile)' function
* to get the default value in runtime - usually, these functions are placed in config.[ch] file)
*
*
* If default value can't be assigned statically because it depends on some
* run-time checks or if it depends on other settings already defined,
@@ -57,7 +52,6 @@
* CFG_DISABLED - configuration is disabled (defaults always used)
* CFG_FORMAT_INT_OCTAL - print integer number in octal form (also prefixed by "0")
* CFG_SECTION_NO_CHECK - do not check content of the section at all - use with care!!!
* CFG_DISALLOW_INTERACTIVE - disallow configuration node for use in interactive environment (e.g. cmds run in lvm shell)
*
* type: Allowed type for the value of simple configuation setting, one of:
* CFG_TYPE_BOOL
@@ -130,7 +124,7 @@ cfg_section(devices_CFG_SECTION, "devices", root_CFG_SECTION, 0, vsn(1, 0, 0), 0
cfg_section(allocation_CFG_SECTION, "allocation", root_CFG_SECTION, CFG_PROFILABLE, vsn(2, 2, 77), 0, NULL,
"How LVM selects space and applies properties to LVs.\n")
cfg_section(log_CFG_SECTION, "log", root_CFG_SECTION, CFG_PROFILABLE, vsn(1, 0, 0), 0, NULL,
cfg_section(log_CFG_SECTION, "log", root_CFG_SECTION, 0, vsn(1, 0, 0), 0, NULL,
"How LVM log information is reported.\n")
cfg_section(backup_CFG_SECTION, "backup", root_CFG_SECTION, 0, vsn(1, 0, 0), 0, NULL,
@@ -172,7 +166,7 @@ cfg(config_checks_CFG, "checks", config_CFG_SECTION, 0, CFG_TYPE_BOOL, 1, vsn(2,
cfg(config_abort_on_errors_CFG, "abort_on_errors", config_CFG_SECTION, 0, CFG_TYPE_BOOL, 0, vsn(2,2,99), NULL, 0, NULL,
"Abort the LVM process if a configuration mismatch is found.\n")
cfg_runtime(config_profile_dir_CFG, "profile_dir", config_CFG_SECTION, CFG_DISALLOW_INTERACTIVE, CFG_TYPE_STRING, vsn(2, 2, 99), 0, NULL,
cfg_runtime(config_profile_dir_CFG, "profile_dir", config_CFG_SECTION, 0, CFG_TYPE_STRING, vsn(2, 2, 99), 0, NULL,
"Directory where LVM looks for configuration profiles.\n")
cfg(devices_dir_CFG, "dir", devices_CFG_SECTION, CFG_ADVANCED, CFG_TYPE_STRING, DEFAULT_DEV_DIR, vsn(1, 0, 0), NULL, 0, NULL,
@@ -401,18 +395,6 @@ cfg(devices_issue_discards_CFG, "issue_discards", devices_CFG_SECTION, 0, CFG_TY
"generally do. If enabled, discards will only be issued if both the\n"
"storage and kernel provide support.\n")
cfg(devices_allow_changes_with_duplicate_pvs_CFG, "allow_changes_with_duplicate_pvs", devices_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_ALLOW_CHANGES_WITH_DUPLICATE_PVS, vsn(2, 2, 153), NULL, 0, NULL,
"Allow VG modification while a PV appears on multiple devices.\n"
"When a PV appears on multiple devices, LVM attempts to choose the\n"
"best device to use for the PV. If the devices represent the same\n"
"underlying storage, the choice has minimal consequence. If the\n"
"devices represent different underlying storage, the wrong choice\n"
"can result in data loss if the VG is modified. Disabling this\n"
"setting is the safest option because it prevents modifying a VG\n"
"or activating LVs in it while a PV appears on multiple devices.\n"
"Enabling this setting allows the VG to be used as usual even with\n"
"uncertain devices.\n")
cfg_array(allocation_cling_tag_list_CFG, "cling_tag_list", allocation_CFG_SECTION, CFG_DEFAULT_UNDEFINED, CFG_TYPE_STRING, NULL, vsn(2, 2, 77), NULL, 0, NULL,
"Advise LVM which PVs to use when searching for new space.\n"
"When searching for free space to extend an LV, the 'cling' allocation\n"
@@ -467,12 +449,6 @@ cfg(allocation_mirror_logs_require_separate_pvs_CFG, "mirror_logs_require_separa
"Mirror logs and images will always use different PVs.\n"
"The default setting changed in version 2.02.85.\n")
cfg(allocation_raid_stripe_all_devices_CFG, "raid_stripe_all_devices", allocation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_ALLOCATION_STRIPE_ALL_DEVICES, vsn(2, 2, 162), NULL, 0, NULL,
"Stripe across all PVs when RAID stripes are not specified.\n"
"If enabled, all PVs in the VG or on the command line are used for raid0/4/5/6/10\n"
"when the command does not specify the number of stripes to use.\n"
"This was the default behaviour until release 2.02.162.\n")
cfg(allocation_cache_pool_metadata_require_separate_pvs_CFG, "cache_pool_metadata_require_separate_pvs", allocation_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_CACHE_POOL_METADATA_REQUIRE_SEPARATE_PVS, vsn(2, 2, 106), NULL, 0, NULL,
"Cache pool metadata and data will always use different PVs.\n")
@@ -516,11 +492,6 @@ cfg_runtime(allocation_cache_pool_chunk_size_CFG, "cache_pool_chunk_size", alloc
"on the smaller end of the spectrum. Supported values range from\n"
"32KiB to 1GiB in multiples of 32.\n")
cfg(allocation_cache_pool_max_chunks_CFG, "cache_pool_max_chunks", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_UNDEFINED, CFG_TYPE_INT, 0, vsn(2, 2, 165), NULL, 0, NULL,
"The maximum number of chunks in a cache pool.\n"
"For cache target v1.9 the recommended maximumm is 1000000 chunks.\n"
"Using cache pool with more chunks may degrade cache performance.\n")
cfg(allocation_thin_pool_metadata_require_separate_pvs_CFG, "thin_pool_metadata_require_separate_pvs", allocation_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_THIN_POOL_METADATA_REQUIRE_SEPARATE_PVS, vsn(2, 2, 89), NULL, 0, NULL,
"Thin pool metdata and data will always use different PVs.\n")
@@ -564,47 +535,6 @@ cfg_runtime(allocation_thin_pool_chunk_size_CFG, "thin_pool_chunk_size", allocat
cfg(allocation_physical_extent_size_CFG, "physical_extent_size", allocation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_EXTENT_SIZE, vsn(2, 2, 112), NULL, 0, NULL,
"Default physical extent size in KiB to use for new VGs.\n")
cfg(log_report_command_log_CFG, "report_command_log", log_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED | CFG_DISALLOW_INTERACTIVE, CFG_TYPE_BOOL, DEFAULT_COMMAND_LOG_REPORT, vsn(2, 2, 158), NULL, 0, NULL,
"Enable or disable LVM log reporting.\n"
"If enabled, LVM will collect a log of operations, messages,\n"
"per-object return codes with object identification and associated\n"
"error numbers (errnos) during LVM command processing. Then the\n"
"log is either reported solely or in addition to any existing\n"
"reports, depending on LVM command used. If it is a reporting command\n"
"(e.g. pvs, vgs, lvs, lvm fullreport), then the log is reported in\n"
"addition to any existing reports. Otherwise, there's only log report\n"
"on output. For all applicable LVM commands, you can request that\n"
"the output has only log report by using --logonly command line\n"
"option. Use log/command_log_cols and log/command_log_sort settings\n"
"to define fields to display and sort fields for the log report.\n"
"You can also use log/command_log_selection to define selection\n"
"criteria used each time the log is reported.\n")
cfg(log_command_log_sort_CFG, "command_log_sort", log_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED | CFG_DISALLOW_INTERACTIVE, CFG_TYPE_STRING, DEFAULT_COMMAND_LOG_SORT, vsn(2, 2, 158), NULL, 0, NULL,
"List of columns to sort by when reporting command log.\n"
"See <lvm command> --logonly --configreport log -o help\n"
"for the list of possible fields.\n")
cfg(log_command_log_cols_CFG, "command_log_cols", log_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED | CFG_DISALLOW_INTERACTIVE, CFG_TYPE_STRING, DEFAULT_COMMAND_LOG_COLS, vsn(2, 2, 158), NULL, 0, NULL,
"List of columns to report when reporting command log.\n"
"See <lvm command> --logonly --configreport log -o help\n"
"for the list of possible fields.\n")
cfg(log_command_log_selection_CFG, "command_log_selection", log_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED | CFG_DISALLOW_INTERACTIVE, CFG_TYPE_STRING, DEFAULT_COMMAND_LOG_SELECTION, vsn(2, 2, 158), NULL, 0, NULL,
"Selection criteria used when reporting command log.\n"
"You can define selection criteria that are applied each\n"
"time log is reported. This way, it is possible to control the\n"
"amount of log that is displayed on output and you can select\n"
"only parts of the log that are important for you. To define\n"
"selection criteria, use fields from log report. See also\n"
"<lvm command> --logonly --configreport log -S help for the\n"
"list of possible fields and selection operators. You can also\n"
"define selection criteria for log report on command line directly\n"
"using <lvm command> --configreport log -S <selection criteria>\n"
"which has precedence over log/command_log_selection setting.\n"
"For more information about selection criteria in general, see\n"
"lvm(8) man page.\n")
cfg(log_verbose_CFG, "verbose", log_CFG_SECTION, 0, CFG_TYPE_INT, DEFAULT_VERBOSE, vsn(1, 0, 0), NULL, 0, NULL,
"Controls the messages sent to stdout or stderr.\n")
@@ -651,7 +581,7 @@ cfg(log_activation_CFG, "activation", log_CFG_SECTION, 0, CFG_TYPE_BOOL, 0, vsn(
cfg(log_activate_file_CFG, "activate_file", log_CFG_SECTION, CFG_DEFAULT_UNDEFINED | CFG_UNSUPPORTED, CFG_TYPE_STRING, NULL, vsn(1, 0, 0), NULL, 0, NULL, NULL)
cfg_array(log_debug_classes_CFG, "debug_classes", log_CFG_SECTION, CFG_ALLOW_EMPTY, CFG_TYPE_STRING, "#Smemory#Sdevices#Sactivation#Sallocation#Slvmetad#Smetadata#Scache#Slocking#Slvmpolld#Sdbus", vsn(2, 2, 99), NULL, 0, NULL,
cfg_array(log_debug_classes_CFG, "debug_classes", log_CFG_SECTION, CFG_ALLOW_EMPTY, CFG_TYPE_STRING, "#Smemory#Sdevices#Sactivation#Sallocation#Slvmetad#Smetadata#Scache#Slocking#Slvmpolld", vsn(2, 2, 99), NULL, 0, NULL,
"Select log messages by class.\n"
"Some debugging messages are assigned to a class and only appear in\n"
"debug output if the class is listed here. Classes currently\n"
@@ -924,20 +854,12 @@ cfg(global_use_lvmetad_CFG, "use_lvmetad", global_CFG_SECTION, 0, CFG_TYPE_BOOL,
"scanning from the LVM system entirely, including lvmetad, use\n"
"devices/global_filter.\n")
cfg(global_lvmetad_update_wait_time_CFG, "lvmetad_update_wait_time", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_LVMETAD_UPDATE_WAIT_TIME, vsn(2, 2, 151), NULL, 0, NULL,
"The number of seconds a command will wait for lvmetad update to finish.\n"
"After waiting for this period, a command will not use lvmetad, and\n"
"will revert to disk scanning.\n")
cfg(global_use_lvmlockd_CFG, "use_lvmlockd", global_CFG_SECTION, 0, CFG_TYPE_BOOL, 0, vsn(2, 2, 124), NULL, 0, NULL,
"Use lvmlockd for locking among hosts using LVM on shared storage.\n"
"Applicable only if LVM is compiled with lockd support in which\n"
"case there is also lvmlockd(8) man page available for more\n"
"information.\n")
"See lvmlockd(8) for more information.\n")
cfg(global_lvmlockd_lock_retries_CFG, "lvmlockd_lock_retries", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_LVMLOCKD_LOCK_RETRIES, vsn(2, 2, 125), NULL, 0, NULL,
"Retry lvmlockd lock requests this many times.\n"
"Applicable only if LVM is compiled with lockd support\n")
"Retry lvmlockd lock requests this many times.\n")
cfg(global_sanlock_lv_extend_CFG, "sanlock_lv_extend", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_SANLOCK_LV_EXTEND_MB, vsn(2, 2, 124), NULL, 0, NULL,
"Size in MiB to extend the internal LV holding sanlock locks.\n"
@@ -945,8 +867,7 @@ cfg(global_sanlock_lv_extend_CFG, "sanlock_lv_extend", global_CFG_SECTION, CFG_D
"LVs have been created, the internal LV needs to be extended. lvcreate\n"
"will automatically extend the internal LV when needed by the amount\n"
"specified here. Setting this to 0 disables the automatic extension\n"
"and can cause lvcreate to fail. Applicable only if LVM is compiled\n"
"with lockd support\n")
"and can cause lvcreate to fail.\n")
cfg(global_thin_check_executable_CFG, "thin_check_executable", global_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, THIN_CHECK_CMD, vsn(2, 2, 94), "@THIN_CHECK_CMD@", 0, NULL,
"The full path to the thin_check command.\n"
@@ -1072,13 +993,7 @@ cfg(global_use_lvmpolld_CFG, "use_lvmpolld", global_CFG_SECTION, 0, CFG_TYPE_BOO
"manage the progress of ongoing operations. lvmpolld can be used as\n"
"a native systemd service, which allows it to be started on demand,\n"
"and to use its own control group. When this option is disabled, LVM\n"
"commands will supervise long running operations by forking themselves.\n"
"Applicable only if LVM is compiled with lvmpolld support.\n")
cfg(global_notify_dbus_CFG, "notify_dbus", global_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_NOTIFY_DBUS, vsn(2, 2, 145), NULL, 0, NULL,
"Enable D-Bus notification from LVM commands.\n"
"When enabled, an LVM command that changes PVs, changes VG metadata,\n"
"or changes the activation state of an LV will send a notification.\n")
"commands will supervise long running operations by forking themselves.\n")
cfg(activation_udev_sync_CFG, "udev_sync", activation_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_UDEV_SYNC, vsn(2, 2, 51), NULL, 0, NULL,
"Use udev notifications to synchronize udev and LVM.\n"
@@ -1111,8 +1026,7 @@ cfg(activation_retry_deactivation_CFG, "retry_deactivation", activation_CFG_SECT
cfg(activation_missing_stripe_filler_CFG, "missing_stripe_filler", activation_CFG_SECTION, CFG_ADVANCED, CFG_TYPE_STRING, DEFAULT_STRIPE_FILLER, vsn(1, 0, 0), NULL, 0, NULL,
"Method to fill missing stripes when activating an incomplete LV.\n"
"Using 'error' will make inaccessible parts of the device return I/O\n"
"errors on access. Using 'zero' will return success (and zero) on I/O\n"
"You can instead use a device path, in which case,\n"
"errors on access. You can instead use a device path, in which case,\n"
"that device will be used in place of missing stripes. Using anything\n"
"other than 'error' with mirrored or snapshotted volumes is likely to\n"
"result in data corruption.\n")
@@ -1446,18 +1360,6 @@ cfg(metadata_check_pv_device_sizes_CFG, "check_pv_device_sizes", metadata_CFG_SE
"less than corresponding PV size. You should not disable this unless\n"
"you are absolutely sure about what you are doing!\n")
cfg(metadata_record_lvs_history_CFG, "record_lvs_history", metadata_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_RECORD_LVS_HISTORY, vsn(2, 2, 145), NULL, 0, NULL,
"When enabled, LVM keeps history records about removed LVs in\n"
"metadata. The information that is recorded in metadata for\n"
"historical LVs is reduced when compared to original\n"
"information kept in metadata for live LVs. Currently, this\n"
"feature is supported for thin and thin snapshot LVs only.\n")
cfg(metadata_lvs_history_retention_time_CFG, "lvs_history_retention_time", metadata_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_LVS_HISTORY_RETENTION_TIME, vsn(2, 2, 145), NULL, 0, NULL,
"Retention time in seconds after which a record about individual\n"
"historical logical volume is automatically destroyed.\n"
"A value of 0 disables this feature.\n")
cfg(metadata_pvmetadatacopies_CFG, "pvmetadatacopies", metadata_CFG_SECTION, CFG_ADVANCED | CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_PVMETADATACOPIES, vsn(1, 0, 0), NULL, 0, NULL,
"Number of copies of metadata to store on each PV.\n"
"The --pvmetadatacopies option overrides this setting.\n"
@@ -1521,20 +1423,6 @@ cfg(disk_area_start_sector_CFG, "start_sector", disk_area_CFG_SUBSECTION, CFG_UN
cfg(disk_area_size_CFG, "size", disk_area_CFG_SUBSECTION, CFG_UNSUPPORTED | CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, 0, vsn(1, 0, 0), NULL, 0, NULL, NULL)
cfg(disk_area_id_CFG, "id", disk_area_CFG_SUBSECTION, CFG_UNSUPPORTED | CFG_DEFAULT_UNDEFINED, CFG_TYPE_STRING, NULL, vsn(1, 0, 0), NULL, 0, NULL, NULL)
cfg(report_output_format_CFG, "output_format", report_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED | CFG_DISALLOW_INTERACTIVE, CFG_TYPE_STRING, DEFAULT_REP_OUTPUT_FORMAT, vsn(2, 2, 158), NULL, 0, NULL,
"Format of LVM command's report output.\n"
"If there is more than one report per command, then the format\n"
"is applied for all reports. You can also change output format\n"
"directly on command line using --reportformat option which\n"
"has precedence over log/output_format setting.\n"
"Accepted values:\n"
" basic\n"
" Original format with columns and rows. If there is more than\n"
" one report per command, each report is prefixed with report's\n"
" name for identification.\n"
" json\n"
" JSON format.\n")
cfg(report_compact_output_CFG, "compact_output", report_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_REP_COMPACT_OUTPUT, vsn(2, 2, 115), NULL, 0, NULL,
"Do not print empty values for all report fields.\n"
"If enabled, all fields that don't have a value set for any of the\n"
@@ -1577,7 +1465,7 @@ cfg(report_prefixes_CFG, "prefixes", report_CFG_SECTION, CFG_PROFILABLE | CFG_DE
cfg(report_quoted_CFG, "quoted", report_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_REP_QUOTED, vsn(2, 2, 39), NULL, 0, NULL,
"Quote field values when using field name prefixes.\n")
cfg(report_columns_as_rows_CFG, "columns_as_rows", report_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_REP_COLUMNS_AS_ROWS, vsn(1, 0, 0), NULL, 0, NULL,
cfg(report_colums_as_rows_CFG, "colums_as_rows", report_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_REP_COLUMNS_AS_ROWS, vsn(1, 0, 0), NULL, 0, NULL,
"Output each column as a row.\n"
"If set, this also implies report/prefixes=1.\n")
@@ -1791,53 +1679,9 @@ cfg(report_pvsegs_cols_verbose_CFG, "pvsegs_cols_verbose", report_CFG_SECTION, C
"List of columns to sort by when reporting 'pvs --segments' command in verbose mode.\n"
"See 'pvs --segments -o help' for the list of possible fields.\n")
cfg(report_vgs_cols_full_CFG, "vgs_cols_full", report_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_VGS_COLS_FULL, vsn(2, 2, 158), NULL, 0, NULL,
"List of columns to report for lvm fullreport's 'vgs' subreport.\n"
"See 'vgs -o help' for the list of possible fields.\n")
cfg(report_pvs_cols_full_CFG, "pvs_cols_full", report_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_PVS_COLS_FULL, vsn(2, 2, 158), NULL, 0, NULL,
"List of columns to report for lvm fullreport's 'vgs' subreport.\n"
"See 'pvs -o help' for the list of possible fields.\n")
cfg(report_lvs_cols_full_CFG, "lvs_cols_full", report_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_LVS_COLS_FULL, vsn(2, 2, 158), NULL, 0, NULL,
"List of columns to report for lvm fullreport's 'lvs' subreport.\n"
"See 'lvs -o help' for the list of possible fields.\n")
cfg(report_pvsegs_cols_full_CFG, "pvsegs_cols_full", report_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_PVSEGS_COLS_FULL, vsn(2, 2, 158), NULL, 0, NULL,
"List of columns to report for lvm fullreport's 'pvseg' subreport.\n"
"See 'pvs --segments -o help' for the list of possible fields.\n")
cfg(report_segs_cols_full_CFG, "segs_cols_full", report_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_SEGS_COLS_FULL, vsn(2, 2, 158), NULL, 0, NULL,
"List of columns to report for lvm fullreport's 'seg' subreport.\n"
"See 'lvs --segments -o help' for the list of possible fields.\n")
cfg(report_vgs_sort_full_CFG, "vgs_sort_full", report_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_VGS_SORT_FULL, vsn(2, 2, 158), NULL, 0, NULL,
"List of columns to sort by when reporting lvm fullreport's 'vgs' subreport.\n"
"See 'vgs -o help' for the list of possible fields.\n")
cfg(report_pvs_sort_full_CFG, "pvs_sort_full", report_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_PVS_SORT_FULL, vsn(2, 2, 158), NULL, 0, NULL,
"List of columns to sort by when reporting lvm fullreport's 'vgs' subreport.\n"
"See 'pvs -o help' for the list of possible fields.\n")
cfg(report_lvs_sort_full_CFG, "lvs_sort_full", report_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_LVS_SORT_FULL, vsn(2, 2, 158), NULL, 0, NULL,
"List of columns to sort by when reporting lvm fullreport's 'lvs' subreport.\n"
"See 'lvs -o help' for the list of possible fields.\n")
cfg(report_pvsegs_sort_full_CFG, "pvsegs_sort_full", report_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_PVSEGS_SORT_FULL, vsn(2, 2, 158), NULL, 0, NULL,
"List of columns to sort by when reporting for lvm fullreport's 'pvseg' subreport.\n"
"See 'pvs --segments -o help' for the list of possible fields.\n")
cfg(report_segs_sort_full_CFG, "segs_sort_full", report_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_SEGS_SORT_FULL, vsn(2, 2, 158), NULL, 0, NULL,
"List of columns to sort by when reporting lvm fullreport's 'seg' subreport.\n"
"See 'lvs --segments -o help' for the list of possible fields.\n")
cfg(report_mark_hidden_devices_CFG, "mark_hidden_devices", report_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, 1, vsn(2, 2, 140), NULL, 0, NULL,
"Use brackets [] to mark hidden devices.\n")
cfg(report_two_word_unknown_device_CFG, "two_word_unknown_device", report_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, 0, vsn(2, 2, 146), NULL, 0, NULL,
"Use the two words 'unknown device' in place of '[unknown]'.\n"
"This is displayed when the device for a PV is not known.\n")
cfg(dmeventd_mirror_library_CFG, "mirror_library", dmeventd_CFG_SECTION, 0, CFG_TYPE_STRING, DEFAULT_DMEVENTD_MIRROR_LIB, vsn(1, 2, 3), NULL, 0, NULL,
"The library dmeventd uses when monitoring a mirror device.\n"
"libdevmapper-event-lvm2mirror.so attempts to recover from\n"
@@ -1859,12 +1703,6 @@ cfg(dmeventd_thin_library_CFG, "thin_library", dmeventd_CFG_SECTION, 0, CFG_TYPE
"and emits a warning through syslog when the usage exceeds 80%. The\n"
"warning is repeated when 85%, 90% and 95% of the pool is filled.\n")
cfg(dmeventd_thin_command_CFG, "thin_command", dmeventd_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_DMEVENTD_THIN_COMMAND, vsn(2, 2, 169), NULL, 0, NULL,
"The plugin runs command with each 5% increment when thin-pool data volume\n"
"or metadata volume gets above 50%.\n"
"Command which starts with 'lvm ' prefix is internal lvm command.\n"
"You can write your own handler to customise behaviour in more details.\n")
cfg(dmeventd_executable_CFG, "executable", dmeventd_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_DMEVENTD_PATH, vsn(2, 2, 73), "@DMEVENTD_PATH@", 0, NULL,
"The full path to the dmeventd binary.\n")
@@ -1920,7 +1758,6 @@ cfg_array(local_extra_system_ids_CFG, "extra_system_ids", local_CFG_SECTION, CFG
cfg(local_host_id_CFG, "host_id", local_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, 0, vsn(2, 2, 124), NULL, 0, NULL,
"The lvmlockd sanlock host_id.\n"
"This must be unique among all hosts, and must be between 1 and 2000.\n"
"Applicable only if LVM is compiled with lockd support\n")
"This must be unique among all hosts, and must be between 1 and 2000.\n")
cfg(CFG_COUNT, NULL, root_CFG_SECTION, 0, CFG_TYPE_INT, 0, vsn(0, 0, 0), NULL, 0, NULL, NULL)

View File

@@ -45,7 +45,6 @@
#define DEFAULT_DATA_ALIGNMENT_DETECTION 1
#define DEFAULT_ISSUE_DISCARDS 0
#define DEFAULT_PV_MIN_SIZE_KB 2048
#define DEFAULT_ALLOW_CHANGES_WITH_DUPLICATE_PVS 0
#define DEFAULT_LOCKING_LIB "liblvm2clusterlock.so"
#define DEFAULT_ERROR_WHEN_FULL 0
@@ -53,12 +52,10 @@
#define DEFAULT_FALLBACK_TO_CLUSTERED_LOCKING 1
#define DEFAULT_WAIT_FOR_LOCKS 1
#define DEFAULT_LVMLOCKD_LOCK_RETRIES 3
#define DEFAULT_LVMETAD_UPDATE_WAIT_TIME 10
#define DEFAULT_PRIORITISE_WRITE_LOCKS 1
#define DEFAULT_USE_MLOCKALL 0
#define DEFAULT_METADATA_READ_ONLY 0
#define DEFAULT_LVDISPLAY_SHOWS_FULL_DEVICE_PATH 0
#define DEFAULT_UNKNOWN_DEVICE_NAME "[unknown]"
#define DEFAULT_SANLOCK_LV_EXTEND_MB 256
@@ -66,14 +63,7 @@
#define DEFAULT_MIRROR_LOG_FAULT_POLICY "allocate"
#define DEFAULT_MIRROR_IMAGE_FAULT_POLICY "remove"
#define DEFAULT_MIRROR_MAX_IMAGES 8 /* limited by kernel DM_KCOPYD_MAX_REGIONS */
/* Limited by kernel failed devices bitfield in superblock (raid4/5/6 MD max 253) */
/*
* FIXME: Increase these to 64 and further to the MD maximum
* once the SubLVs split and name shift got enhanced
*/
#define DEFAULT_RAID1_MAX_IMAGES 10
#define DEFAULT_RAID_MAX_IMAGES 64
#define DEFAULT_ALLOCATION_STRIPE_ALL_DEVICES 0 /* Don't stripe across all devices if not -i/--stripes given */
#define DEFAULT_RAID_MAX_IMAGES 8
#define DEFAULT_RAID_FAULT_POLICY "warn"
@@ -81,7 +71,6 @@
#define DEFAULT_DMEVENTD_MIRROR_LIB "libdevmapper-event-lvm2mirror.so"
#define DEFAULT_DMEVENTD_SNAPSHOT_LIB "libdevmapper-event-lvm2snapshot.so"
#define DEFAULT_DMEVENTD_THIN_LIB "libdevmapper-event-lvm2thin.so"
#define DEFAULT_DMEVENTD_THIN_COMMAND "lvm lvextend --use-policies"
#define DEFAULT_DMEVENTD_MONITOR 1
#define DEFAULT_BACKGROUND_POLLING 1
@@ -128,7 +117,6 @@
#define DEFAULT_CACHE_REPAIR_OPTIONS_CONFIG "#S" DEFAULT_CACHE_REPAIR_OPTION1
#define DEFAULT_CACHE_POOL_METADATA_REQUIRE_SEPARATE_PVS 0
#define DEFAULT_CACHE_POOL_CHUNK_SIZE 64 /* KB */
#define DEFAULT_CACHE_POOL_MAX_CHUNKS 1000000
#define DEFAULT_CACHE_POOL_MIN_METADATA_SIZE 2048 /* KB */
#define DEFAULT_CACHE_POOL_MAX_METADATA_SIZE (16 * 1024 * 1024) /* KB */
#define DEFAULT_CACHE_POLICY "mq"
@@ -139,8 +127,6 @@
#define DEFAULT_FORMAT "lvm2"
#define DEFAULT_STRIPESIZE 64 /* KB */
#define DEFAULT_RECORD_LVS_HISTORY 0
#define DEFAULT_LVS_HISTORY_RETENTION_TIME 0
#define DEFAULT_PVMETADATAIGNORE 0
#define DEFAULT_PVMETADATASIZE 255
#define DEFAULT_PVMETADATACOPIES 1
@@ -149,7 +135,6 @@
#define DEFAULT_READ_AHEAD "auto"
#define DEFAULT_UDEV_RULES 1
#define DEFAULT_UDEV_SYNC 1
#define DEFAULT_NOTIFY_DBUS 1
#define DEFAULT_VERIFY_UDEV_OPERATIONS 0
#define DEFAULT_RETRY_DEACTIVATION 1
#define DEFAULT_ACTIVATION_CHECKS 0
@@ -169,7 +154,6 @@
# define DEFAULT_LOG_FACILITY LOG_USER
#endif
#define DEFAULT_COMMAND_LOG_REPORT 0
#define DEFAULT_SYSLOG 1
#define DEFAULT_VERBOSE 0
#define DEFAULT_SILENT 0
@@ -177,7 +161,7 @@
#define DEFAULT_INDENT 1
#define DEFAULT_ABORT_ON_INTERNAL_ERRORS 0
#define DEFAULT_DETECT_INTERNAL_VG_CACHE_CORRUPTION 0
#define DEFAULT_UNITS "r"
#define DEFAULT_UNITS "h"
#define DEFAULT_SUFFIX 1
#define DEFAULT_HOSTTAGS 0
@@ -217,18 +201,14 @@
#define DEFAULT_REP_LIST_ITEM_SEPARATOR ","
#define DEFAULT_TIME_FORMAT "%Y-%m-%d %T %z"
#define DEFAULT_REP_OUTPUT_FORMAT "basic"
#define DEFAULT_COMPACT_OUTPUT_COLS ""
#define DEFAULT_COMMAND_LOG_SELECTION "!(log_type=status && message=success)"
#define DEFAULT_LVS_COLS "lv_name,vg_name,lv_attr,lv_size,pool_lv,origin,data_percent,metadata_percent,move_pv,mirror_log,copy_percent,convert_lv"
#define DEFAULT_VGS_COLS "vg_name,pv_count,lv_count,snap_count,vg_attr,vg_size,vg_free"
#define DEFAULT_PVS_COLS "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free"
#define DEFAULT_SEGS_COLS "lv_name,vg_name,lv_attr,stripes,segtype,seg_size"
#define DEFAULT_PVSEGS_COLS "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,pvseg_start,pvseg_size"
#define DEFAULT_DEVTYPES_COLS "devtype_name,devtype_max_partitions,devtype_description"
#define DEFAULT_COMMAND_LOG_COLS "log_seq_num,log_type,log_context,log_object_type,log_object_name,log_object_id,log_object_group,log_object_group_id,log_message,log_errno,log_ret_code"
#define DEFAULT_LVS_COLS_VERB "lv_name,vg_name,seg_count,lv_attr,lv_size,lv_major,lv_minor,lv_kernel_major,lv_kernel_minor,pool_lv,origin,data_percent,metadata_percent,move_pv,copy_percent,mirror_log,convert_lv,lv_uuid,lv_profile"
#define DEFAULT_VGS_COLS_VERB "vg_name,vg_attr,vg_extent_size,pv_count,lv_count,snap_count,vg_size,vg_free,vg_uuid,vg_profile"
@@ -237,25 +217,12 @@
#define DEFAULT_PVSEGS_COLS_VERB "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,pvseg_start,pvseg_size,lv_name,seg_start_pe,segtype,seg_pe_ranges"
#define DEFAULT_DEVTYPES_COLS_VERB "devtype_name,devtype_max_partitions,devtype_description"
#define DEFAULT_VGS_COLS_FULL "vg_all"
#define DEFAULT_PVS_COLS_FULL "pv_all"
#define DEFAULT_LVS_COLS_FULL "lv_all"
#define DEFAULT_PVSEGS_COLS_FULL "pvseg_all,pv_uuid,lv_uuid"
#define DEFAULT_SEGS_COLS_FULL "seg_all,lv_uuid"
#define DEFAULT_LVS_SORT "vg_name,lv_name"
#define DEFAULT_VGS_SORT "vg_name"
#define DEFAULT_PVS_SORT "pv_name"
#define DEFAULT_SEGS_SORT "vg_name,lv_name,seg_start"
#define DEFAULT_PVSEGS_SORT "pv_name,pvseg_start"
#define DEFAULT_DEVTYPES_SORT "devtype_name"
#define DEFAULT_COMMAND_LOG_SORT "log_seq_num"
#define DEFAULT_VGS_SORT_FULL "vg_name"
#define DEFAULT_PVS_SORT_FULL "pv_name"
#define DEFAULT_LVS_SORT_FULL "vg_name,lv_name"
#define DEFAULT_PVSEGS_SORT_FULL "pv_uuid,pvseg_start"
#define DEFAULT_SEGS_SORT_FULL "lv_uuid,seg_start"
#define DEFAULT_MIRROR_DEVICE_FAULT_POLICY "remove"
#define DEFAULT_MIRROR_LOG_FAULT_POLICY "allocate"
@@ -264,4 +231,6 @@
#define DEFAULT_THIN_POOL_AUTOEXTEND_THRESHOLD 100
#define DEFAULT_THIN_POOL_AUTOEXTEND_PERCENT 20
#define DEFAULT_CY_LOCK_TYPE "sanlock"
#endif /* _LVM_DEFAULTS_H */

View File

@@ -92,15 +92,7 @@ void str_list_del(struct dm_list *sll, const char *str)
dm_list_iterate_safe(slh, slht, sll)
if (!strcmp(str, dm_list_item(slh, struct dm_str_list)->str))
dm_list_del(slh);
}
void str_list_wipe(struct dm_list *sll)
{
struct dm_list *slh, *slht;
dm_list_iterate_safe(slh, slht, sll)
dm_list_del(slh);
dm_list_del(slh);
}
int str_list_dup(struct dm_pool *mem, struct dm_list *sllnew,
@@ -126,8 +118,8 @@ int str_list_match_item(const struct dm_list *sll, const char *str)
struct dm_str_list *sl;
dm_list_iterate_items(sl, sll)
if (!strcmp(str, sl->str))
return 1;
if (!strcmp(str, sl->str))
return 1;
return 0;
}
@@ -161,8 +153,8 @@ int str_list_lists_equal(const struct dm_list *sll, const struct dm_list *sll2)
return 0;
dm_list_iterate_items(sl, sll)
if (!str_list_match_item(sll2, sl->str))
return 0;
if (!str_list_match_item(sll2, sl->str))
return 0;
return 1;
}

View File

@@ -25,7 +25,6 @@ int str_list_add_list(struct dm_pool *mem, struct dm_list *sll, struct dm_list *
int str_list_add_no_dup_check(struct dm_pool *mem, struct dm_list *sll, const char *str);
int str_list_add_h_no_dup_check(struct dm_pool *mem, struct dm_list *sll, const char *str);
void str_list_del(struct dm_list *sll, const char *str);
void str_list_wipe(struct dm_list *sll);
int str_list_match_item(const struct dm_list *sll, const char *str);
int str_list_match_list(const struct dm_list *sll, const struct dm_list *sll2, const char **tag_matched);
int str_list_lists_equal(const struct dm_list *sll, const struct dm_list *sll2);

View File

@@ -17,8 +17,6 @@
#include "btree.h"
#include "config.h"
#include "toolcontext.h"
#include "dm-ioctl.h" /* for DM_UUID_LEN */
#include "lvm-string.h" /* for LVM's UUID_PREFIX */
#ifdef UDEV_SYNC_SUPPORT
#include <libudev.h>
@@ -40,9 +38,6 @@ struct dir_list {
static struct {
struct dm_pool *mem;
struct dm_hash_table *names;
struct dm_hash_table *vgid_index;
struct dm_hash_table *lvid_index;
struct btree *sysfs_only_devices; /* see comments in _get_device_for_sysfs_dev_name_using_devno */
struct btree *devices;
struct dm_regex *preferred_names_matcher;
const char *dev_dir;
@@ -363,312 +358,6 @@ static int _add_alias(struct device *dev, const char *path)
return 1;
}
static int _get_sysfs_value(const char *path, char *buf, size_t buf_size, int error_if_no_value)
{
FILE *fp;
size_t len;
int r = 0;
if (!(fp = fopen(path, "r"))) {
log_sys_error("fopen", path);
return 0;
}
if (!fgets(buf, buf_size, fp)) {
log_sys_error("fgets", path);
goto out;
}
if ((len = strlen(buf)) && buf[len - 1] == '\n')
buf[--len] = '\0';
if (!len && error_if_no_value)
log_error("_get_sysfs_value: %s: no value", path);
else
r = 1;
out:
if (fclose(fp))
log_sys_error("fclose", path);
return r;
}
static int _get_dm_uuid_from_sysfs(char *buf, size_t buf_size, int major, int minor)
{
char path[PATH_MAX];
if (dm_snprintf(path, sizeof(path), "%sdev/block/%d:%d/dm/uuid", dm_sysfs_dir(), major, minor) < 0) {
log_error("%d:%d: dm_snprintf failed for path to sysfs dm directory.", major, minor);
return 0;
}
return _get_sysfs_value(path, buf, buf_size, 0);
}
static struct dm_list *_get_or_add_list_by_index_key(struct dm_hash_table *idx, const char *key)
{
struct dm_list *list;
if ((list = dm_hash_lookup(idx, key)))
return list;
if (!(list = _zalloc(sizeof(*list)))) {
log_error("%s: failed to allocate device list for device cache index.", key);
return NULL;
}
dm_list_init(list);
if (!dm_hash_insert(idx, key, list)) {
log_error("%s: failed to insert device list to device cache index.", key);
return NULL;
}
return list;
}
static struct device *_insert_sysfs_dev(dev_t devno, const char *devname)
{
static struct device _fake_dev = { .flags = DEV_USED_FOR_LV };
struct stat stat0;
char path[PATH_MAX];
char *path_copy;
struct device *dev;
if (dm_snprintf(path, sizeof(path), "%s%s", _cache.dev_dir, devname) < 0) {
log_error("_insert_sysfs_dev: %s: dm_snprintf failed", devname);
return NULL;
}
if (lstat(path, &stat0) < 0) {
/* When device node does not exist return fake entry.
* This may happen when i.e. lvm2 device dir != /dev */
log_debug("%s: Not available device node", path);
return &_fake_dev;
}
if (!(dev = _dev_create(devno)))
return_NULL;
if (!(path_copy = dm_pool_strdup(_cache.mem, path))) {
log_error("_insert_sysfs_dev: %s: dm_pool_strdup failed", devname);
return NULL;
}
if (!_add_alias(dev, path_copy)) {
log_error("Couldn't add alias to dev cache.");
_free(dev);
return NULL;
}
if (!btree_insert(_cache.sysfs_only_devices, (uint32_t) devno, dev)) {
log_error("Couldn't add device to binary tree of sysfs-only devices in dev cache.");
_free(dev);
return NULL;
}
return dev;
}
static struct device *_get_device_for_sysfs_dev_name_using_devno(const char *devname)
{
char path[PATH_MAX];
char buf[PATH_MAX];
int major, minor;
dev_t devno;
struct device *dev;
if (dm_snprintf(path, sizeof(path), "%sblock/%s/dev", dm_sysfs_dir(), devname) < 0) {
log_error("_get_device_for_sysfs_dev_name_using_devno: %s: dm_snprintf failed", devname);
return NULL;
}
if (!_get_sysfs_value(path, buf, sizeof(buf), 1))
return_NULL;
if (sscanf(buf, "%d:%d", &major, &minor) != 2) {
log_error("_get_device_for_sysfs_dev_name_using_devno: %s: failed to get major and minor number", devname);
return NULL;
}
devno = MKDEV((dev_t)major, (dev_t)minor);
if (!(dev = (struct device *) btree_lookup(_cache.devices, (uint32_t) devno))) {
/*
* If we get here, it means the device is referenced in sysfs, but it's not yet in /dev.
* This may happen in some rare cases right after LVs get created - we sync with udev
* (or alternatively we create /dev content ourselves) while VG lock is held. However,
* dev scan is done without VG lock so devices may already be in sysfs, but /dev may
* not be updated yet if we call LVM command right after LV creation. This is not a
* problem with devtmpfs as there's at least kernel name for device in /dev as soon
* as the sysfs item exists, but we still support environments without devtmpfs or
* where different directory for dev nodes is used (e.g. our test suite). So track
* such devices in _cache.sysfs_only_devices hash for the vgid/lvid check to work still.
*/
if (!(dev = (struct device *) btree_lookup(_cache.sysfs_only_devices, (uint32_t) devno)) &&
!(dev = _insert_sysfs_dev(devno, devname)))
return_NULL;
}
return dev;
}
#define NOT_LVM_UUID "-"
static int _get_vgid_and_lvid_for_dev(struct device *dev)
{
static size_t lvm_prefix_len = sizeof(UUID_PREFIX) - 1;
static size_t lvm_uuid_len = sizeof(UUID_PREFIX) - 1 + 2 * ID_LEN;
char uuid[DM_UUID_LEN];
size_t uuid_len;
if (!_get_dm_uuid_from_sysfs(uuid, sizeof(uuid), (int) MAJOR(dev->dev), (int) MINOR(dev->dev)))
return_0;
uuid_len = strlen(uuid);
/*
* UUID for LV is either "LVM-<vg_uuid><lv_uuid>" or "LVM-<vg_uuid><lv_uuid>-<suffix>",
* where vg_uuid and lv_uuid has length of ID_LEN and suffix len is not restricted
* (only restricted by whole DM UUID max len).
*/
if (((uuid_len == lvm_uuid_len) ||
((uuid_len > lvm_uuid_len) && (uuid[lvm_uuid_len] == '-'))) &&
!strncmp(uuid, UUID_PREFIX, lvm_prefix_len)) {
/* Separate VGID and LVID part from DM UUID. */
if (!(dev->vgid = dm_pool_strndup(_cache.mem, uuid + lvm_prefix_len, ID_LEN)) ||
!(dev->lvid = dm_pool_strndup(_cache.mem, uuid + lvm_prefix_len + ID_LEN, ID_LEN)))
return_0;
} else
dev->vgid = dev->lvid = NOT_LVM_UUID;
return 1;
}
static int _index_dev_by_vgid_and_lvid(struct device *dev)
{
const char *devname = dev_name(dev);
char devpath[PATH_MAX];
char path[PATH_MAX];
DIR *d;
struct dirent *dirent;
struct device *holder_dev;
struct dm_list *vgid_list, *lvid_list;
struct device_list *dl_vgid, *dl_lvid;
int r = 0;
if (dev->flags & DEV_USED_FOR_LV)
/* already indexed */
return 1;
/* Get holders for device. */
if (dm_snprintf(path, sizeof(path), "%sdev/block/%d:%d/holders/", dm_sysfs_dir(), (int) MAJOR(dev->dev), (int) MINOR(dev->dev)) < 0) {
log_error("%s: dm_snprintf failed for path to holders directory.", devname);
return 0;
}
if (!(d = opendir(path))) {
if (errno == ENOENT) {
log_debug("%s: path does not exist, skipping", path);
return 1;
}
log_sys_error("opendir", path);
return 0;
}
/* Iterate over device's holders and look for LVs. */
while ((dirent = readdir(d))) {
if (!strcmp(".", dirent->d_name) ||
!strcmp("..", dirent->d_name))
continue;
if (dm_snprintf(devpath, sizeof(devpath), "%s%s", _cache.dev_dir, dirent->d_name) == -1) {
log_error("%s: dm_snprintf failed for holder %s device path.", devname, dirent->d_name);
goto out;
}
if (!(holder_dev = (struct device *) dm_hash_lookup(_cache.names, devpath))) {
/*
* Cope with situation where canonical /<dev_dir>/<dirent->d_name>
* does not exist, but some other node name or symlink exists in
* non-standard environments - someone renaming the nodes or using
* mknod with different dev names than actual kernel names.
* This looks up struct device by major:minor pair which we get
* by looking at /sys/block/<dirent->d_name>/dev sysfs attribute.
*/
if (!(holder_dev = _get_device_for_sysfs_dev_name_using_devno(dirent->d_name))) {
log_error("%s: failed to find associated device structure for holder %s.", devname, devpath);
goto out;
}
}
/* We're only interested in a holder which is a DM device. */
if (!dm_is_dm_major(MAJOR(holder_dev->dev)))
continue;
/*
* And if it's a DM device, we're only interested in a holder which is an LVM device.
* Get the VG UUID and LV UUID if we don't have that already.
*/
if (!holder_dev->vgid && !_get_vgid_and_lvid_for_dev(holder_dev))
goto_out;
if (*holder_dev->vgid == *NOT_LVM_UUID)
continue;
/*
* Do not add internal LV devices to index.
* If a device is internal, the holder has the same VG UUID as the device.
*/
if (dm_is_dm_major(MAJOR(dev->dev))) {
if (!dev->vgid && !_get_vgid_and_lvid_for_dev(dev))
goto_out;
if (*dev->vgid != *NOT_LVM_UUID && !strcmp(holder_dev->vgid, dev->vgid))
continue;
}
if (!(vgid_list = _get_or_add_list_by_index_key(_cache.vgid_index, holder_dev->vgid)) ||
!(lvid_list = _get_or_add_list_by_index_key(_cache.lvid_index, holder_dev->lvid)))
goto_out;
/* Create dev list items for the holder device. */
if (!(dl_vgid = _zalloc(sizeof(*dl_vgid))) ||
!(dl_lvid = _zalloc(sizeof(*dl_lvid)))) {
log_error("%s: failed to allocate dev list item.", devname);
goto out;
}
dl_vgid->dev = dl_lvid->dev = dev;
/* Add dev list item to VGID device list if it's not there already. */
if (!(dev->flags & DEV_USED_FOR_LV))
dm_list_add(vgid_list, &dl_vgid->list);
/* Add dev list item to LVID device list. */
dm_list_add(lvid_list, &dl_lvid->list);
/* Mark device as used == also indexed in dev cache by VGID and LVID. */
dev->flags |= DEV_USED_FOR_LV;
}
r = 1;
out:
if (closedir(d))
log_sys_error("closedir", path);
return r;
}
struct dm_list *dev_cache_get_dev_list_for_vgid(const char *vgid)
{
return dm_hash_lookup(_cache.vgid_index, vgid);
}
struct dm_list *dev_cache_get_dev_list_for_lvid(const char *lvid)
{
return dm_hash_lookup(_cache.lvid_index, lvid);
}
/*
* Either creates a new dev, or adds an alias to
* an existing dev.
@@ -689,15 +378,14 @@ static int _insert_dev(const char *path, dev_t d)
}
/* is this device already registered ? */
if (!(dev = (struct device *) btree_lookup(_cache.devices, (uint32_t) d))) {
if (!(dev = (struct device *) btree_lookup(_cache.sysfs_only_devices, (uint32_t) d))) {
/* create new device */
if (loopfile) {
if (!(dev = dev_create_file(path, NULL, NULL, 0)))
return_0;
} else if (!(dev = _dev_create(d)))
if (!(dev = (struct device *) btree_lookup(_cache.devices,
(uint32_t) d))) {
/* create new device */
if (loopfile) {
if (!(dev = dev_create_file(path, NULL, NULL, 0)))
return_0;
}
} else if (!(dev = _dev_create(d)))
return_0;
if (!(btree_insert(_cache.devices, (uint32_t) d, dev))) {
log_error("Couldn't insert device into binary tree.");
@@ -805,108 +493,6 @@ static int _insert_file(const char *path)
return 1;
}
static int _dev_cache_iterate_devs_for_index(void)
{
struct btree_iter *iter = btree_first(_cache.devices);
struct device *dev;
int r = 1;
while (iter) {
dev = btree_get_data(iter);
if (!_index_dev_by_vgid_and_lvid(dev))
r = 0;
iter = btree_next(iter);
}
return r;
}
static int _dev_cache_iterate_sysfs_for_index(const char *path)
{
char devname[PATH_MAX];
DIR *d;
struct dirent *dirent;
int major, minor;
dev_t devno;
struct device *dev;
int partial_failure = 0;
int r = 0;
if (!(d = opendir(path))) {
log_sys_error("opendir", path);
return 0;
}
while ((dirent = readdir(d))) {
if (!strcmp(".", dirent->d_name) ||
!strcmp("..", dirent->d_name))
continue;
if (sscanf(dirent->d_name, "%d:%d", &major, &minor) != 2) {
log_error("_dev_cache_iterate_sysfs_for_index: %s: failed "
"to get major and minor number", dirent->d_name);
partial_failure = 1;
continue;
}
devno = MKDEV((dev_t)major, (dev_t)minor);
if (!(dev = (struct device *) btree_lookup(_cache.devices, (uint32_t) devno)) &&
!(dev = (struct device *) btree_lookup(_cache.sysfs_only_devices, (uint32_t) devno))) {
if (!dm_device_get_name(major, minor, 1, devname, sizeof(devname)) ||
!(dev = _insert_sysfs_dev(devno, devname))) {
partial_failure = 1;
continue;
}
}
if (!_index_dev_by_vgid_and_lvid(dev))
partial_failure = 1;
}
r = !partial_failure;
if (closedir(d))
log_sys_error("closedir", path);
return r;
}
int dev_cache_index_devs(void)
{
static int sysfs_has_dev_block = -1;
char path[PATH_MAX];
if (dm_snprintf(path, sizeof(path), "%sdev/block", dm_sysfs_dir()) < 0) {
log_error("dev_cache_index_devs: dm_snprintf failed.");
return 0;
}
/* Skip indexing if /sys/dev/block is not available.*/
if (sysfs_has_dev_block == -1) {
struct stat info;
if (stat(path, &info) == 0)
sysfs_has_dev_block = 1;
else {
if (errno == ENOENT) {
sysfs_has_dev_block = 0;
return 1;
} else {
log_sys_error("stat", path);
return 0;
}
}
} else if (!sysfs_has_dev_block)
return 1;
if (obtain_device_list_from_udev() &&
udev_get_library_context())
return _dev_cache_iterate_devs_for_index(); /* with udev */
return _dev_cache_iterate_sysfs_for_index(path);
}
#ifdef UDEV_SYNC_SUPPORT
static int _device_in_udev_db(const dev_t d)
@@ -1077,8 +663,6 @@ static void _full_scan(int dev_scan)
_insert_dirs(&_cache.dirs);
(void) dev_cache_index_devs();
dm_list_iterate_items(dl, &_cache.files)
_insert_file(dl->dir);
@@ -1167,9 +751,7 @@ int dev_cache_init(struct cmd_context *cmd)
if (!(_cache.mem = dm_pool_create("dev_cache", 10 * 1024)))
return_0;
if (!(_cache.names = dm_hash_create(128)) ||
!(_cache.vgid_index = dm_hash_create(32)) ||
!(_cache.lvid_index = dm_hash_create(32))) {
if (!(_cache.names = dm_hash_create(128))) {
dm_pool_destroy(_cache.mem);
_cache.mem = 0;
return_0;
@@ -1180,11 +762,6 @@ int dev_cache_init(struct cmd_context *cmd)
goto bad;
}
if (!(_cache.sysfs_only_devices = btree_create(_cache.mem))) {
log_error("Couldn't create binary tree for sysfs-only devices in dev cache.");
goto bad;
}
if (!(_cache.dev_dir = _strdup(cmd->dev_dir))) {
log_error("strdup dev_dir failed.");
goto bad;
@@ -1248,12 +825,6 @@ int dev_cache_exit(void)
if (_cache.names)
dm_hash_destroy(_cache.names);
if (_cache.vgid_index)
dm_hash_destroy(_cache.vgid_index);
if (_cache.lvid_index)
dm_hash_destroy(_cache.lvid_index);
memset(&_cache, 0, sizeof(_cache));
return (!num_open);
@@ -1537,5 +1108,5 @@ int dev_fd(struct device *dev)
const char *dev_name(const struct device *dev)
{
return (dev && dev->aliases.n) ? dm_list_item(dev->aliases.n, struct dm_str_list)->str :
unknown_device_name();
"unknown device";
}

View File

@@ -31,10 +31,6 @@ struct dev_filter {
unsigned use_count;
};
int dev_cache_index_devs(void);
struct dm_list *dev_cache_get_dev_list_for_vgid(const char *vgid);
struct dm_list *dev_cache_get_dev_list_for_lvid(const char *lvid);
/*
* The global device cache.
*/

View File

@@ -36,9 +36,6 @@
#define DEV_EXT_UDEV_DEVTYPE "DEVTYPE"
#define DEV_EXT_UDEV_DEVTYPE_DISK "disk"
/* the list of symlinks associated with device node */
#define DEV_EXT_UDEV_DEVLINKS "DEVLINKS"
/*
* DEV_EXT_UDEV_MPATH_DEVICE_PATH is set by multipath in udev db
* with value either 0 or 1. The same functionality as

View File

@@ -494,22 +494,11 @@ int dev_open_flags(struct device *dev, int flags, int direct, int quiet)
#ifdef O_NOATIME
/* Don't update atime on device inodes */
if (!(dev->flags & DEV_REGULAR) && !(dev->flags & DEV_NOT_O_NOATIME))
if (!(dev->flags & DEV_REGULAR))
flags |= O_NOATIME;
#endif
if ((dev->fd = open(name, flags, 0777)) < 0) {
#ifdef O_NOATIME
if ((errno == EPERM) && (flags & O_NOATIME)) {
flags &= ~O_NOATIME;
dev->flags |= DEV_NOT_O_NOATIME;
if ((dev->fd = open(name, flags, 0777)) >= 0) {
log_debug_devs("%s: Not using O_NOATIME", name);
goto opened;
}
}
#endif
#ifdef O_DIRECT_SUPPORT
if (direct && !(dev->flags & DEV_O_DIRECT_TESTED)) {
flags &= ~O_DIRECT;
@@ -524,8 +513,6 @@ int dev_open_flags(struct device *dev, int flags, int direct, int quiet)
log_sys_debug("open", name);
else
log_sys_error("open", name);
dev->flags |= DEV_OPEN_FAILURE;
return 0;
}
@@ -569,7 +556,6 @@ int dev_open_flags(struct device *dev, int flags, int direct, int quiet)
dev->flags & DEV_OPENED_EXCL ? " O_EXCL" : "",
dev->flags & DEV_O_DIRECT ? " O_DIRECT" : "");
dev->flags &= ~DEV_OPEN_FAILURE;
return 1;
}

View File

@@ -38,8 +38,8 @@ static int _dev_has_md_magic(struct device *dev, uint64_t sb_offset)
/* Version 1 is little endian; version 0.90.0 is machine endian */
if (dev_read(dev, sb_offset, sizeof(uint32_t), &md_magic) &&
((md_magic == MD_SB_MAGIC) ||
((MD_SB_MAGIC != xlate32(MD_SB_MAGIC)) && (md_magic == xlate32(MD_SB_MAGIC)))))
((md_magic == xlate32(MD_SB_MAGIC)) ||
(md_magic == MD_SB_MAGIC)))
return 1;
return 0;

View File

@@ -125,13 +125,6 @@ struct dev_types *create_dev_types(const char *proc_dir,
if (!strncmp("emcpower", line + i, 8) && isspace(*(line + i + 8)))
dt->emcpower_major = line_maj;
/* Look for Veritas Dynamic Multipathing */
if (!strncmp("VxDMP", line + i, 5) && isspace(*(line + i + 5)))
dt->vxdmp_major = line_maj;
if (!strncmp("loop", line + i, 4) && isspace(*(line + i + 4)))
dt->loop_major = line_maj;
if (!strncmp("power2", line + i, 6) && isspace(*(line + i + 6)))
dt->power2_major = line_maj;
@@ -222,9 +215,6 @@ int dev_subsystem_part_major(struct dev_types *dt, struct device *dev)
if (MAJOR(dev->dev) == dt->power2_major)
return 1;
if (MAJOR(dev->dev) == dt->vxdmp_major)
return 1;
if ((MAJOR(dev->dev) == dt->blkext_major) &&
dev_get_primary_dev(dt, dev, &primary_dev) &&
(MAJOR(primary_dev) == dt->md_major))
@@ -253,15 +243,9 @@ const char *dev_subsystem_name(struct dev_types *dt, struct device *dev)
if (MAJOR(dev->dev) == dt->power2_major)
return "POWER2";
if (MAJOR(dev->dev) == dt->vxdmp_major)
return "VXDMP";
if (MAJOR(dev->dev) == dt->blkext_major)
return "BLKEXT";
if (MAJOR(dev->dev) == dt->loop_major)
return "LOOP";
return "";
}
@@ -281,38 +265,6 @@ int major_is_scsi_device(struct dev_types *dt, int major)
return (dt->dev_type_array[major].flags & PARTITION_SCSI_DEVICE) ? 1 : 0;
}
static int _loop_is_with_partscan(struct device *dev)
{
FILE *fp;
int partscan = 0;
char path[PATH_MAX];
char buffer[64];
if (dm_snprintf(path, sizeof(path), "%sdev/block/%d:%d/loop/partscan",
dm_sysfs_dir(),
(int) MAJOR(dev->dev),
(int) MINOR(dev->dev)) < 0) {
log_warn("Sysfs path for partscan is too long.");
return 0;
}
if (!(fp = fopen(path, "r")))
return 0; /* not there -> no partscan */
if (!fgets(buffer, sizeof(buffer), fp)) {
log_warn("Failed to read %s.", path);
} else if (sscanf(buffer, "%d", &partscan) != 1) {
log_warn("Failed to parse %s '%s'.", path, buffer);
partscan = 0;
}
if (fclose(fp))
log_sys_debug("fclose", path);
return partscan;
}
/* See linux/genhd.h and fs/partitions/msdos */
#define PART_MAGIC 0xAA55
#define PART_MAGIC_OFFSET UINT64_C(0x1FE)
@@ -342,11 +294,6 @@ static int _is_partitionable(struct dev_types *dt, struct device *dev)
if (MAJOR(dev->dev) == dt->md_major)
return 1;
/* All loop devices are partitionable via blkext (as of 3.2) */
if ((MAJOR(dev->dev) == dt->loop_major) &&
_loop_is_with_partscan(dev))
return 1;
if ((parts <= 1) || (MINOR(dev->dev) % parts))
return 0;
@@ -906,12 +853,6 @@ static unsigned long _dev_topology_attribute(struct dev_types *dt,
result = value >> SECTOR_SHIFT;
if (!result && value) {
log_warn("WARNING: Device %s: %s is %lu and is unexpectedly less than sector.",
dev_name(dev), attribute, value);
result = 1;
}
out_close:
if (fclose(fp))
log_sys_debug("fclose", path);
@@ -986,100 +927,3 @@ int dev_is_rotational(struct dev_types *dt, struct device *dev)
return 1;
}
#endif
#ifdef UDEV_SYNC_SUPPORT
/*
* Udev daemon usually has 30s timeout to process each event by default.
* But still, that value can be changed in udev configuration and we
* don't have libudev API to read the actual timeout value used.
*/
/* FIXME: Is this long enough to wait for udev db to get initialized?
*
* Take also into consideration that this check is done for each
* device that is scanned so we don't want to wait for a long time
* if there's something wrong with udev, e.g. timeouts! With current
* libudev API, we can't recognize whether the event processing has
* not finished yet and it's still being processed or whether it has
* failed already due to timeout in udev - in both cases the
* udev_device_get_is_initialized returns 0.
*/
#define UDEV_DEV_IS_MPATH_COMPONENT_ITERATION_COUNT 100
#define UDEV_DEV_IS_MPATH_COMPONENT_USLEEP 100000
int udev_dev_is_mpath_component(struct device *dev)
{
struct udev *udev_context = udev_get_library_context();
struct udev_device *udev_device = NULL;
const char *value;
int initialized = 0;
unsigned i = 0;
int ret = 0;
if (!udev_context) {
log_warn("WARNING: No udev context available to check if device %s is multipath component.", dev_name(dev));
return 0;
}
while (1) {
if (i >= UDEV_DEV_IS_MPATH_COMPONENT_ITERATION_COUNT)
break;
if (udev_device)
udev_device_unref(udev_device);
if (!(udev_device = udev_device_new_from_devnum(udev_context, 'b', dev->dev))) {
log_warn("WARNING: Failed to get udev device handler for device %s.", dev_name(dev));
return 0;
}
#ifdef HAVE_LIBUDEV_UDEV_DEVICE_GET_IS_INITIALIZED
if ((initialized = udev_device_get_is_initialized(udev_device)))
break;
#else
if ((initialized = (udev_device_get_property_value(udev_device, DEV_EXT_UDEV_DEVLINKS) != NULL)))
break;
#endif
log_debug("Device %s not initialized in udev database (%u/%u, %u microseconds).", dev_name(dev),
i + 1, UDEV_DEV_IS_MPATH_COMPONENT_ITERATION_COUNT,
i * UDEV_DEV_IS_MPATH_COMPONENT_USLEEP);
usleep(UDEV_DEV_IS_MPATH_COMPONENT_USLEEP);
i++;
}
if (!initialized) {
log_warn("WARNING: Device %s not initialized in udev database even after waiting %u microseconds.",
dev_name(dev), i * UDEV_DEV_IS_MPATH_COMPONENT_USLEEP);
goto out;
}
value = udev_device_get_property_value(udev_device, DEV_EXT_UDEV_BLKID_TYPE);
if (value && !strcmp(value, DEV_EXT_UDEV_BLKID_TYPE_MPATH)) {
log_debug("Device %s is multipath component based on blkid variable in udev db (%s=\"%s\").",
dev_name(dev), DEV_EXT_UDEV_BLKID_TYPE, value);
ret = 1;
goto out;
}
value = udev_device_get_property_value(udev_device, DEV_EXT_UDEV_MPATH_DEVICE_PATH);
if (value && !strcmp(value, "1")) {
log_debug("Device %s is multipath component based on multipath variable in udev db (%s=\"%s\").",
dev_name(dev), DEV_EXT_UDEV_MPATH_DEVICE_PATH, value);
ret = 1;
goto out;
}
out:
udev_device_unref(udev_device);
return ret;
}
#else
int udev_dev_is_mpath_component(struct device *dev)
{
return 0;
}
#endif

View File

@@ -21,7 +21,9 @@
#define NUMBER_OF_MAJORS 4096
#ifdef __linux__
# include "kdev_t.h"
# define MAJOR(dev) ((dev & 0xfff00) >> 8)
# define MINOR(dev) ((dev & 0xff) | ((dev >> 12) & 0xfff00))
# define MKDEV(ma,mi) ((mi & 0xff) | (ma << 8) | ((mi & ~0xff) << 12))
#else
# define MAJOR(x) major((x))
# define MINOR(x) minor((x))
@@ -41,10 +43,8 @@ struct dev_types {
int drbd_major;
int device_mapper_major;
int emcpower_major;
int vxdmp_major;
int power2_major;
int dasd_major;
int loop_major;
struct dev_type_def dev_type_array[NUMBER_OF_MAJORS];
};
@@ -60,7 +60,6 @@ int dev_is_md(struct device *dev, uint64_t *sb);
int dev_is_swap(struct device *dev, uint64_t *signature);
int dev_is_luks(struct device *dev, uint64_t *signature);
int dasd_is_cdl_formatted(struct device *dev);
int udev_dev_is_mpath_component(struct device *dev);
/* Signature wiping. */
#define TYPE_LVM1_MEMBER 0x001

View File

@@ -63,6 +63,5 @@ static const dev_known_type_t _dev_known_types[] = {
{"bcache", 1, "bcache block device cache"},
{"nvme", 64, "NVM Express"},
{"zvol", 16, "ZFS Zvols"},
{"VxDMP", 16, "Veritas Dynamic Multipathing"},
{"", 0, ""}
};

View File

@@ -27,10 +27,6 @@
#define DEV_OPENED_EXCL 0x00000010 /* Opened EXCL */
#define DEV_O_DIRECT 0x00000020 /* Use O_DIRECT */
#define DEV_O_DIRECT_TESTED 0x00000040 /* DEV_O_DIRECT is reliable */
#define DEV_OPEN_FAILURE 0x00000080 /* Has last open failed? */
#define DEV_USED_FOR_LV 0x00000100 /* Is device used for an LV */
#define DEV_ASSUMED_FOR_LV 0x00000200 /* Is device assumed for an LV */
#define DEV_NOT_O_NOATIME 0x00000400 /* Don't use O_NOATIME */
/*
* Support for external device info.
@@ -72,10 +68,7 @@ struct device {
struct dm_list open_list;
struct dev_ext ext;
const char *vgid; /* if device is an LV */
const char *lvid; /* if device is an LV */
char pvid[ID_LEN + 1]; /* if device is a PV */
char pvid[ID_LEN + 1];
char _padding[7];
};

View File

@@ -121,29 +121,19 @@ const char *get_percent_string(percent_type_t def)
return _percent_types[def];
}
static const char *_lv_name(const struct logical_volume *lv)
{
/* Never try to display names of the internal snapshot structures. */
if (lv_is_snapshot(lv))
return find_cow(lv)->name;
return lv->name;
}
const char *display_lvname(const struct logical_volume *lv)
{
char *name;
const char *lv_name = _lv_name(lv);
int r;
if ((lv->vg->cmd->display_lvname_idx + NAME_LEN) >= sizeof((lv->vg->cmd->display_buffer)))
lv->vg->cmd->display_lvname_idx = 0;
name = lv->vg->cmd->display_buffer + lv->vg->cmd->display_lvname_idx;
r = dm_snprintf(name, NAME_LEN, "%s/%s", lv->vg->name, lv_name);
r = dm_snprintf(name, NAME_LEN, "%s/%s", lv->vg->name, lv->name);
if (r < 0) {
log_error("Full LV name \"%s/%s\" is too long.", lv->vg->name, lv_name);
log_error("Full LV name \"%s/%s\" is too long.", lv->vg->name, lv->name);
return NULL;
}
@@ -342,34 +332,6 @@ void lvdisplay_colons(const struct logical_volume *lv)
inkernel ? info.major : -1, inkernel ? info.minor : -1);
}
static int _lvdisplay_historical_full(struct cmd_context *cmd,
const struct logical_volume *lv)
{
char uuid[64] __attribute__((aligned(8)));
int lvm1compat = find_config_tree_bool(cmd, global_lvdisplay_shows_full_device_path_CFG, NULL);
struct historical_logical_volume *hlv = lv->this_glv->historical;
if (!id_write_format(&hlv->lvid.id[1], uuid, sizeof(uuid)))
return_0;
log_print("--- Historical Logical volume ---");
if (lvm1compat)
/* /dev/vgname/lvname doen't actually exist for historical devices */
log_print("LV Name %s%s/%s",
hlv->vg->cmd->dev_dir, hlv->vg->name, hlv->name);
else
log_print("LV Name %s%s", HISTORICAL_LV_PREFIX, hlv->name);
log_print("VG Name %s", hlv->vg->name);
log_print("LV UUID %s", uuid);
log_print("LV Creation time %s", lv_creation_time_dup(cmd->mem, lv, 1));
log_print("LV Removal time %s", lv_removal_time_dup(cmd->mem, lv, 1));
log_print(" ");
return 1;
}
int lvdisplay_full(struct cmd_context *cmd,
const struct logical_volume *lv,
void *handle __attribute__((unused)))
@@ -387,9 +349,6 @@ int lvdisplay_full(struct cmd_context *cmd,
int thin_active = 0;
dm_percent_t thin_percent;
if (lv_is_historical(lv))
return _lvdisplay_historical_full(cmd, lv);
if (!id_write_format(&lv->lvid.id[1], uuid, sizeof(uuid)))
return_0;
@@ -424,7 +383,7 @@ int lvdisplay_full(struct cmd_context *cmd,
log_print("LV UUID %s", uuid);
log_print("LV Write Access %s", access_str);
log_print("LV Creation host, time %s, %s",
lv_host_dup(cmd->mem, lv), lv_creation_time_dup(cmd->mem, lv, 1));
lv_host_dup(cmd->mem, lv), lv_time_dup(cmd->mem, lv, 1));
if (lv_is_origin(lv)) {
log_print("LV snapshot status source of");
@@ -831,102 +790,50 @@ void display_name_error(name_error_t name_error)
* Prompt for y or n from stdin.
* Defaults to 'no' in silent mode.
* All callers should support --yes and/or --force to override this.
*
* Accepted are either _yes[] or _no[] strings or just their outset.
* When running without 'tty' stdin is printed to stderr.
* 'Yes' is accepted ONLY with '\n'.
*/
char yes_no_prompt(const char *prompt, ...)
{
/* Lowercase Yes/No strings */
static const char _yes[] = "yes";
static const char _no[] = "no";
const char *answer = NULL;
int c = silent_mode() ? EOF : 0;
int i = 0, ret = 0, sig = 0;
char buf[12];
int c = 0, ret = 0, cb = 0;
va_list ap;
sigint_allow();
for (;;) {
if (!ret) {
/* Show prompt */
do {
if (c == '\n' || !c) {
va_start(ap, prompt);
vfprintf(stderr, prompt, ap);
va_end(ap);
fflush(stderr);
if (c == EOF)
if (silent_mode()) {
fputc('n', stderr);
ret = 'n';
break;
i = 0;
answer = NULL;
}
ret = 0;
}
nextchar:
if ((sig = sigint_caught()))
break; /* Check if already interrupted before getchar() */
if ((c = getchar()) == EOF) {
/* SIGNAL or no chars on stdin (missing '\n') or ^D */
if (!i)
break; /* Just shown prompt,-> print [n]\n */
goto invalid; /* Note: c holds EOF */
ret = 'n'; /* SIGINT */
cb = 1;
break;
}
if ((i < (sizeof(buf) - 4)) && isprint(c))
buf[i++] = c;
c = tolower(c);
if ((ret > 0) && (c == answer[0]))
answer++; /* Matching, next char */
else if (c == '\n') {
if (feof(stdin))
fputc('\n', stderr);
if (ret > 0)
break; /* Answered */
invalid:
if (i >= (sizeof(buf) - 4)) {
/* '...' for missing input */
i = sizeof(buf) - 1;
buf[i - 1] = buf[i - 2] = buf[i - 3] = '.';
}
buf[i] = 0;
log_warn("WARNING: Invalid input '%s'.", buf);
ret = 0; /* Otherwise refresh prompt */
} else if (!ret && (c == _yes[0])) {
ret = 'y';
answer = _yes + 1; /* Expecting 'Yes' */
} else if (!ret && (c == _no[0])) {
ret = 'n';
answer = _no + 1; /* Expecting 'No' */
} else if (!ret && isspace(c)) {
/* Ignore any whitespace before */
--i;
goto nextchar;
} else if ((ret > 0) && isspace(c)) {
/* Ignore any whitespace after */
while (*answer)
answer++; /* jump to end-of-word */
} else
ret = -1; /* Read till '\n' and refresh */
}
if ((c == 'y') || (c == 'n')) {
/* If both 'y' and 'n' given, begin again. */
if (ret && c != ret)
ret = -1;
else
ret = c;
}
} while (ret < 1 || c != '\n');
sigint_restore();
/* For other then Yes answer check there is really no interrupt */
if (sig || sigint_caught()) {
stack;
ret = 'n';
} else if (c == EOF) {
fputs("[n]\n", stderr);
ret = 'n';
} else
/* Not knowing if it's terminal, makes this hard.... */
log_verbose("Accepted input: [%c]", ret);
if (cb && !sigint_caught())
fputc(ret, stderr);
if (c != '\n')
fputc('\n', stderr);
return ret;
}

View File

@@ -55,8 +55,8 @@ static int _errseg_target_present(struct cmd_context *cmd,
/* Reported truncated in older kernels */
if (!_errseg_checked) {
_errseg_checked = 1;
_errseg_present = target_present(cmd, TARGET_NAME_ERROR, 0) ||
target_present(cmd, TARGET_NAME_ERROR_OLD, 0);
_errseg_present = target_present(cmd, "error", 0) ||
target_present(cmd, "erro", 0);
}
return _errseg_present;
@@ -66,7 +66,7 @@ static int _errseg_modules_needed(struct dm_pool *mem,
const struct lv_segment *seg __attribute__((unused)),
struct dm_list *modules)
{
if (!str_list_add(mem, modules, MODULE_NAME_ERROR)) {
if (!str_list_add(mem, modules, "error")) {
log_error("error module string list allocation failed");
return 0;
}

View File

@@ -1,81 +0,0 @@
/*
* Copyright (C) 2006 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
*/
#include "lib.h"
#include "filter.h"
static DM_LIST_INIT(_allow_devs);
int internal_filter_allow(struct dm_pool *mem, struct device *dev)
{
struct device_list *devl;
if (!(devl = dm_pool_alloc(mem, sizeof(*devl)))) {
log_error("device_list element allocation failed");
return 0;
}
devl->dev = dev;
dm_list_add(&_allow_devs, &devl->list);
return 1;
}
void internal_filter_clear(void)
{
dm_list_init(&_allow_devs);
}
static int _passes_internal(struct dev_filter *f __attribute__((unused)),
struct device *dev)
{
struct device_list *devl;
if (!internal_filtering())
return 1;
dm_list_iterate_items(devl, &_allow_devs) {
if (devl->dev == dev)
return 1;
}
log_debug_devs("%s: Skipping for internal filtering.", dev_name(dev));
return 0;
}
static void _destroy(struct dev_filter *f)
{
if (f->use_count)
log_error(INTERNAL_ERROR "Destroying internal filter while in use %u times.", f->use_count);
dm_free(f);
}
struct dev_filter *internal_filter_create(void)
{
struct dev_filter *f;
if (!(f = dm_zalloc(sizeof(*f)))) {
log_error("md filter allocation failed");
return NULL;
}
f->passes_filter = _passes_internal;
f->destroy = _destroy;
f->use_count = 0;
log_debug_devs("internal filter initialised.");
return f;
}

View File

@@ -129,8 +129,6 @@ int persistent_filter_load(struct dev_filter *f, struct dm_config_tree **cft_out
if (dm_hash_get_num_entries(pf->devices)) {
/* We populated dev_cache ourselves */
dev_cache_scan(0);
if (!dev_cache_index_devs())
stack;
r = 1;
}

View File

@@ -40,7 +40,7 @@ static int _extract_pattern(struct dm_pool *mem, const char *pat,
break;
default:
log_error("Pattern must begin with 'a' or 'r'.");
log_info("pattern must begin with 'a' or 'r'");
return 0;
}
pat++;
@@ -77,7 +77,7 @@ static int _extract_pattern(struct dm_pool *mem, const char *pat,
*/
ptr = r + strlen(r) - 1;
if (*ptr != sep) {
log_error("Invalid separator at end of regex.");
log_info("invalid separator at end of regex");
return 0;
}
*ptr = '\0';

Some files were not shown because too many files have changed in this diff Show More