mirror of
				git://sourceware.org/git/lvm2.git
				synced 2025-11-03 08:23:48 +03:00 
			
		
		
		
	Compare commits
	
		
			1 Commits
		
	
	
		
			dev-dct-cm
			...
			dev-mcsont
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					b51b031157 | 
@@ -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)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1 +1 @@
 | 
			
		||||
1.02.138-git (2016-11-30)
 | 
			
		||||
1.02.117-git (2016-02-15)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										395
									
								
								WHATS_NEW
									
									
									
									
									
								
							
							
						
						
									
										395
									
								
								WHATS_NEW
									
									
									
									
									
								
							@@ -1,398 +1,5 @@
 | 
			
		||||
Version 2.02.169 - 
 | 
			
		||||
Version 2.02.143 -
 | 
			
		||||
=====================================
 | 
			
		||||
  Add extra memory page when limiting pthread stack size in clvmd.
 | 
			
		||||
  Support striped/raid0* <-> raid10_near conversions
 | 
			
		||||
  Support shrinking of RaidLvs
 | 
			
		||||
  Support region size changes on existing RaidLVs
 | 
			
		||||
  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.
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										152
									
								
								WHATS_NEW_DM
									
									
									
									
									
								
							
							
						
						
									
										152
									
								
								WHATS_NEW_DM
									
									
									
									
									
								
							@@ -1,153 +1,5 @@
 | 
			
		||||
Version 1.02.138 - 
 | 
			
		||||
Version 1.02.117 - 
 | 
			
		||||
=====================================
 | 
			
		||||
  Add extra memory page when limiting pthread stack size in dmeventd.
 | 
			
		||||
  Avoids immediate resume when preloaded device is smaller.
 | 
			
		||||
  Do not suppress kernel key description in dmsetup table output.
 | 
			
		||||
  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
 | 
			
		||||
=====================================
 | 
			
		||||
@@ -210,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.
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										171
									
								
								acinclude.m4
									
									
									
									
									
								
							
							
						
						
									
										171
									
								
								acinclude.m4
									
									
									
									
									
								
							@@ -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
									
									
								
							
							
						
						
									
										1
									
								
								aclocal.m4
									
									
									
									
										vendored
									
									
								
							@@ -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])
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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,15 +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.
 | 
			
		||||
	# User handler is specified with the full path starting with '/'.
 | 
			
		||||
	# 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.
 | 
			
		||||
 
 | 
			
		||||
@@ -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"
 | 
			
		||||
}
 | 
			
		||||
@@ -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
									
									
								
							
							
						
						
									
										211
									
								
								configure
									
									
									
									
										vendored
									
									
								
							@@ -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" ;;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										58
									
								
								configure.in
									
									
									
									
									
								
							
							
						
						
									
										58
									
								
								configure.in
									
									
									
									
									
								
							@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -517,7 +517,7 @@ int main(int argc, char *argv[])
 | 
			
		||||
	/* Initialise the LVM thread variables */
 | 
			
		||||
	dm_list_init(&lvm_cmd_head);
 | 
			
		||||
	if (pthread_attr_init(&stack_attr) ||
 | 
			
		||||
	    pthread_attr_setstacksize(&stack_attr, STACK_SIZE + getpagesize())) {
 | 
			
		||||
	    pthread_attr_setstacksize(&stack_attr, STACK_SIZE)) {
 | 
			
		||||
		log_sys_error("pthread_attr_init", "");
 | 
			
		||||
		exit(1);
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -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)",
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -468,7 +453,7 @@ static int _pthread_create_smallstack(pthread_t *t, void *(*fun)(void *), void *
 | 
			
		||||
	/*
 | 
			
		||||
	 * We use a smaller stack since it gets preallocated in its entirety
 | 
			
		||||
	 */
 | 
			
		||||
	pthread_attr_setstacksize(&attr, THREAD_STACK_SIZE + getpagesize());
 | 
			
		||||
	pthread_attr_setstacksize(&attr, THREAD_STACK_SIZE);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * If no-one will be waiting, we need to detach.
 | 
			
		||||
@@ -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)
 | 
			
		||||
 
 | 
			
		||||
@@ -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 */
 | 
			
		||||
 
 | 
			
		||||
@@ -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)))
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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,
 | 
			
		||||
 
 | 
			
		||||
@@ -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.",
 | 
			
		||||
 
 | 
			
		||||
@@ -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.
 | 
			
		||||
 *
 | 
			
		||||
@@ -18,6 +18,7 @@
 | 
			
		||||
 | 
			
		||||
#include <sys/wait.h>
 | 
			
		||||
#include <stdarg.h>
 | 
			
		||||
#include <pthread.h>
 | 
			
		||||
 | 
			
		||||
/* TODO - move this mountinfo code into library to be reusable */
 | 
			
		||||
#ifdef __linux__
 | 
			
		||||
@@ -29,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. */
 | 
			
		||||
@@ -39,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[3];
 | 
			
		||||
	char *cmd_str;
 | 
			
		||||
	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[0])
 | 
			
		||||
		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,
 | 
			
		||||
@@ -163,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;
 | 
			
		||||
@@ -170,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, ¶ms);
 | 
			
		||||
@@ -223,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;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -237,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);
 | 
			
		||||
@@ -306,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,
 | 
			
		||||
@@ -352,54 +360,27 @@ int register_device(const char *device,
 | 
			
		||||
		    void **user)
 | 
			
		||||
{
 | 
			
		||||
	struct dso_state *state;
 | 
			
		||||
	char *str;
 | 
			
		||||
	char cmd_str[PATH_MAX + 128 + 2]; /* cmd ' ' vg/lv \0 */
 | 
			
		||||
 | 
			
		||||
	if (!dmeventd_lvm2_init_with_pool("thin_pool_state", state))
 | 
			
		||||
		goto_bad;
 | 
			
		||||
 | 
			
		||||
	if (!dmeventd_lvm2_command(state->mem, cmd_str, sizeof(cmd_str),
 | 
			
		||||
				   "_dmeventd_thin_command", device)) {
 | 
			
		||||
	if (!dmeventd_lvm2_command(state->mem, state->cmd_str,
 | 
			
		||||
				   sizeof(state->cmd_str),
 | 
			
		||||
				   "lvextend --use-policies",
 | 
			
		||||
				   device)) {
 | 
			
		||||
		dmeventd_lvm2_exit_with_pool(state);
 | 
			
		||||
		goto_bad;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (strncmp(cmd_str, "lvm ", 4) == 0) {
 | 
			
		||||
		if (!(state->cmd_str = dm_pool_strdup(state->mem, cmd_str + 4))) {
 | 
			
		||||
			log_error("Failed to copy lvm command.");
 | 
			
		||||
			goto bad;
 | 
			
		||||
		}
 | 
			
		||||
	} else if (cmd_str[0] == '/') {
 | 
			
		||||
		if (!(state->cmd_str = dm_pool_strdup(state->mem, cmd_str))) {
 | 
			
		||||
			log_error("Failed to copy thin command.");
 | 
			
		||||
			goto bad;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* Find last space before 'vg/lv' */
 | 
			
		||||
		if (!(str = strrchr(state->cmd_str, ' ')))
 | 
			
		||||
			goto inval;
 | 
			
		||||
 | 
			
		||||
		if (!(state->argv[0] = dm_pool_strndup(state->mem, state->cmd_str,
 | 
			
		||||
						       str - state->cmd_str))) {
 | 
			
		||||
			log_error("Failed to copy command.");
 | 
			
		||||
			goto bad;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		state->argv[1] = str + 1;  /* 1 argument - vg/lv */
 | 
			
		||||
		_init_thread_signals(state);
 | 
			
		||||
	} else /* Unuspported command format */
 | 
			
		||||
		goto inval;
 | 
			
		||||
 | 
			
		||||
	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;
 | 
			
		||||
inval:
 | 
			
		||||
	log_error("Invalid command for monitoring: %s.", cmd_str);
 | 
			
		||||
bad:
 | 
			
		||||
	log_error("Failed to monitor thin pool %s.", device);
 | 
			
		||||
	log_error("Failed to monitor thin %s.", device);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
@@ -411,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;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1
									
								
								daemons/lvmdbusd/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								daemons/lvmdbusd/.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -1 +0,0 @@
 | 
			
		||||
path.py
 | 
			
		||||
@@ -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)
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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))
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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):
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
 
 | 
			
		||||
@@ -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()
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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())
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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,
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										45
									
								
								daemons/lvmdbusd/refresh.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								daemons/lvmdbusd/refresh.py
									
									
									
									
									
										Normal 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
 | 
			
		||||
@@ -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)
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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()
 | 
			
		||||
 
 | 
			
		||||
@@ -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):
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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
											
										
									
								
							@@ -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, };
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
@@ -19,12 +19,10 @@
 | 
			
		||||
 | 
			
		||||
#define MIN_ARGV_SIZE  8
 | 
			
		||||
 | 
			
		||||
static const char *const polling_ops[] = {
 | 
			
		||||
	[PVMOVE] = LVMPD_REQ_PVMOVE,
 | 
			
		||||
	[CONVERT] = LVMPD_REQ_CONVERT,
 | 
			
		||||
	[MERGE] = LVMPD_REQ_MERGE,
 | 
			
		||||
	[MERGE_THIN] = LVMPD_REQ_MERGE_THIN
 | 
			
		||||
};
 | 
			
		||||
static const char *const const polling_ops[] = { [PVMOVE] = LVMPD_REQ_PVMOVE,
 | 
			
		||||
						 [CONVERT] = LVMPD_REQ_CONVERT,
 | 
			
		||||
						 [MERGE] = LVMPD_REQ_MERGE,
 | 
			
		||||
						 [MERGE_THIN] = LVMPD_REQ_MERGE_THIN };
 | 
			
		||||
 | 
			
		||||
const char *polling_op(enum poll_type type)
 | 
			
		||||
{
 | 
			
		||||
@@ -33,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 *));
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
-------
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
--------
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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.
 | 
			
		||||
 
 | 
			
		||||
@@ -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>
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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>
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
---------
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,14 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.  
 | 
			
		||||
 * Copyright (C) 2004-2017 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
 | 
			
		||||
 */
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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 \
 | 
			
		||||
 
 | 
			
		||||
@@ -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.
 | 
			
		||||
 
 | 
			
		||||
@@ -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
											
										
									
								
							@@ -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
									
									
								
							
							
						
						
									
										950
									
								
								lib/cache/lvmcache.c
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										18
									
								
								lib/cache/lvmcache.h
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										18
									
								
								lib/cache/lvmcache.h
									
									
									
									
										vendored
									
									
								
							@@ -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
									
									
								
							
							
						
						
									
										1816
									
								
								lib/cache/lvmetad.c
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										103
									
								
								lib/cache/lvmetad.h
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										103
									
								
								lib/cache/lvmetad.h
									
									
									
									
										vendored
									
									
								
							@@ -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 */
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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,
 | 
			
		||||
 
 | 
			
		||||
@@ -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) */
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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")
 | 
			
		||||
@@ -1221,15 +1135,14 @@ cfg_array(activation_read_only_volume_list_CFG, "read_only_volume_list", activat
 | 
			
		||||
	"read_only_volume_list = [ \"vg1\", \"vg2/lvol1\", \"@tag1\", \"@*\" ]\n"
 | 
			
		||||
	"#\n")
 | 
			
		||||
 | 
			
		||||
 cfg(activation_mirror_region_size_CFG, "mirror_region_size", activation_CFG_SECTION, 0, CFG_TYPE_INT, DEFAULT_RAID_REGION_SIZE, vsn(1, 0, 0), NULL, vsn(2, 2, 99),
 | 
			
		||||
cfg(activation_mirror_region_size_CFG, "mirror_region_size", activation_CFG_SECTION, 0, CFG_TYPE_INT, DEFAULT_RAID_REGION_SIZE, vsn(1, 0, 0), NULL, vsn(2, 2, 99),
 | 
			
		||||
	"This has been replaced by the activation/raid_region_size setting.\n",
 | 
			
		||||
	"Size in KiB of each raid or mirror synchronization region.\n")
 | 
			
		||||
        "Size in KiB of each copy operation when mirroring.\n")
 | 
			
		||||
 | 
			
		||||
cfg(activation_raid_region_size_CFG, "raid_region_size", activation_CFG_SECTION, 0, CFG_TYPE_INT, DEFAULT_RAID_REGION_SIZE, vsn(2, 2, 99), NULL, 0, NULL,
 | 
			
		||||
	"Size in KiB of each raid or mirror synchronization region.\n"
 | 
			
		||||
	"The clean/dirty state of data is tracked for each region.\n"
 | 
			
		||||
	"The value is rounded down to a power of two if necessary, and\n"
 | 
			
		||||
	"is ignored if it is not a multiple of the machine memory page size.\n")
 | 
			
		||||
	"For raid or mirror segment types, this is the amount of data that is\n"
 | 
			
		||||
	"copied at once when initializing, or moved at once by pvmove.\n")
 | 
			
		||||
 | 
			
		||||
cfg(activation_error_when_full_CFG, "error_when_full", activation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_ERROR_WHEN_FULL, vsn(2, 2, 115), NULL, 0, NULL,
 | 
			
		||||
	"Return errors if a thin pool runs out of space.\n"
 | 
			
		||||
@@ -1447,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"
 | 
			
		||||
@@ -1522,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"
 | 
			
		||||
@@ -1578,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")
 | 
			
		||||
 | 
			
		||||
@@ -1792,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"
 | 
			
		||||
@@ -1860,14 +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"
 | 
			
		||||
	"User handler is specified with the full path starting with '/'.\n")
 | 
			
		||||
	/* TODO: systemd service handler */
 | 
			
		||||
 | 
			
		||||
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")
 | 
			
		||||
 | 
			
		||||
@@ -1923,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)
 | 
			
		||||
 
 | 
			
		||||
@@ -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 */
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
@@ -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";
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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.
 | 
			
		||||
 */
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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, ""}
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -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];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user